summaryrefslogtreecommitdiff
path: root/components/drivers
diff options
context:
space:
mode:
authorGuEe-GUI <[email protected]>2026-03-01 13:06:32 +0800
committerRbb666 <[email protected]>2026-06-15 10:00:57 +0800
commit8517f2d086924f66fcb867f7a84ff2855f9926bd (patch)
treef78dfea50b184d616c6b092496cb703238eaaff2 /components/drivers
parent79e7d919094ebf213d43f3ce84f643a44020d229 (diff)
[dm][virtio] support virtio dm
1. version for v1.2 2. support packed queue 1. support MMIO/PCI over bus 2. new virtio queue api with dma/cpu sync 3. update for virtio device drivers: - net - block - console - input - gpu 4. new virtio device drivers: - 9p - crypto - rng - scmi - scsi Signed-off-by: GuEe-GUI <[email protected]>
Diffstat (limited to 'components/drivers')
-rw-r--r--components/drivers/include/drivers/virtio.h282
-rw-r--r--components/drivers/include/drivers/virtq.h198
-rw-r--r--components/drivers/include/rtdevice.h5
-rw-r--r--components/drivers/virtio/Kconfig118
-rw-r--r--components/drivers/virtio/SConscript52
-rw-r--r--components/drivers/virtio/virtio-9p.c188
-rw-r--r--components/drivers/virtio/virtio-blk.c332
-rw-r--r--components/drivers/virtio/virtio-console.c732
-rw-r--r--components/drivers/virtio/virtio-crypto.c666
-rw-r--r--components/drivers/virtio/virtio-gpu.c1021
-rw-r--r--components/drivers/virtio/virtio-input.c300
-rw-r--r--components/drivers/virtio/virtio-net.c423
-rw-r--r--components/drivers/virtio/virtio-rng.c191
-rw-r--r--components/drivers/virtio/virtio-scmi.c293
-rw-r--r--components/drivers/virtio/virtio-scsi.c322
-rw-r--r--components/drivers/virtio/virtio.c560
-rw-r--r--components/drivers/virtio/virtio.h155
-rw-r--r--components/drivers/virtio/virtio_blk.c254
-rw-r--r--components/drivers/virtio/virtio_blk.h105
-rw-r--r--components/drivers/virtio/virtio_config/virtio-9p.h26
-rw-r--r--components/drivers/virtio/virtio_config/virtio-blk.h129
-rw-r--r--components/drivers/virtio/virtio_config/virtio-console.h63
-rw-r--r--components/drivers/virtio/virtio_config/virtio-crypto.h527
-rw-r--r--components/drivers/virtio/virtio_config/virtio-gpu.h499
-rw-r--r--components/drivers/virtio/virtio_config/virtio-input.h68
-rw-r--r--components/drivers/virtio/virtio_config/virtio-net.h (renamed from components/drivers/virtio/virtio_net.h)59
-rw-r--r--components/drivers/virtio/virtio_config/virtio-scmi.h35
-rw-r--r--components/drivers/virtio/virtio_config/virtio-scsi.h163
-rw-r--r--components/drivers/virtio/virtio_console.c778
-rw-r--r--components/drivers/virtio/virtio_console.h97
-rw-r--r--components/drivers/virtio/virtio_gpu.c935
-rw-r--r--components/drivers/virtio/virtio_gpu.h412
-rw-r--r--components/drivers/virtio/virtio_ids.h77
-rw-r--r--components/drivers/virtio/virtio_input.c449
-rw-r--r--components/drivers/virtio/virtio_input.h145
-rw-r--r--components/drivers/virtio/virtio_input_event_codes.h932
-rw-r--r--components/drivers/virtio/virtio_internal.h112
-rw-r--r--components/drivers/virtio/virtio_mmio.c652
-rw-r--r--components/drivers/virtio/virtio_mmio.h67
-rw-r--r--components/drivers/virtio/virtio_net.c267
-rw-r--r--components/drivers/virtio/virtio_pci.c942
-rw-r--r--components/drivers/virtio/virtio_queue.c1219
-rw-r--r--components/drivers/virtio/virtio_queue.h97
43 files changed, 9833 insertions, 5114 deletions
diff --git a/components/drivers/include/drivers/virtio.h b/components/drivers/include/drivers/virtio.h
new file mode 100644
index 0000000000..e38aed5793
--- /dev/null
+++ b/components/drivers/include/drivers/virtio.h
@@ -0,0 +1,282 @@
+/*
+ * Copyright (c) 2006-2023, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date Author Notes
+ * 2021-9-16 GuEe-GUI the first version
+ * 2021-11-11 GuEe-GUI modify to virtio common interface
+ * 2023-02-25 GuEe-GUI support DM
+ */
+
+#ifndef __VIRTIO_H__
+#define __VIRTIO_H__
+
+#include <mm_page.h>
+
+#include <drivers/core/dm.h>
+#include <drivers/core/driver.h>
+#include <drivers/byteorder.h>
+
+#include "../../virtio/virtio_ids.h"
+
+#define VIRTIO_STATUS_ACKNOWLEDGE RT_BIT(0)
+#define VIRTIO_STATUS_DRIVER RT_BIT(1)
+#define VIRTIO_STATUS_DRIVER_OK RT_BIT(2)
+#define VIRTIO_STATUS_FEATURES_OK RT_BIT(3)
+#define VIRTIO_STATUS_NEEDS_RESET RT_BIT(6)
+#define VIRTIO_STATUS_FAILED RT_BIT(7)
+
+#define VIRTIO_F_NOTIFY_ON_EMPTY 24
+#define VIRTIO_F_ANY_LAYOUT 27
+#define VIRTIO_F_RING_INDIRECT_DESC 28
+#define VIRTIO_F_RING_EVENT_IDX 29
+#define VIRTIO_F_VERSION_1 32
+#define VIRTIO_F_ACCESS_PLATFORM 33
+#define VIRTIO_F_RING_PACKED 34
+#define VIRTIO_F_IN_ORDER 35
+#define VIRTIO_F_ORDER_PLATFORM 36
+#define VIRTIO_F_SR_IOV 37
+#define VIRTIO_F_NOTIFICATION_DATA 38
+#define VIRTIO_F_NOTIF_CONFIG_DATA 39
+#define VIRTIO_F_RING_RESET 40
+
+#define VIRTIO_TRANSPORT_F_START VIRTIO_F_RING_INDIRECT_DESC
+#define VIRTIO_TRANSPORT_F_END VIRTIO_F_RING_RESET
+
+struct rt_virtio_device_id
+{
+#define VIRTIO_DEVICE_ANY_ID 0xffffffff
+ rt_uint32_t device;
+ rt_uint32_t vendor;
+};
+
+struct rt_virtqueue;
+struct rt_virtio_transport;
+
+typedef rt_bool_t (*rt_virtqueue_notifier)(struct rt_virtqueue *vq);
+typedef void (*rt_virtqueue_callback)(struct rt_virtqueue *vq);
+
+struct rt_virtio_device
+{
+ struct rt_device parent;
+
+ int idx;
+ struct rt_virtio_device_id id;
+
+ rt_uint64_t features;
+ const struct rt_virtio_transport *trans;
+
+ rt_list_t vq_node;
+ struct rt_spinlock vq_lock;
+
+ rt_bool_t dma_dispatch;
+ void *priv;
+};
+
+struct virtqueue_split;
+struct virtqueue_packed;
+
+struct rt_virtqueue_formula
+{
+ void *page;
+};
+
+struct rt_virtqueue
+{
+ rt_list_t list;
+ rt_list_t user_list;
+
+ const char *name;
+ rt_uint32_t index;
+ rt_uint32_t num_max;
+ rt_uint32_t num_free;
+
+ rt_virtqueue_callback callback;
+
+ union
+ {
+ struct virtqueue_split *vq_split;
+ struct virtqueue_packed *vq_packed;
+ };
+ rt_bool_t packed_ring;
+
+ rt_virtqueue_notifier notify;
+
+ rt_bool_t event;
+ rt_bool_t event_triggered;
+ rt_uint32_t free_head;
+ rt_uint32_t num_added;
+ rt_uint16_t last_used_idx;
+
+ struct rt_virtio_device *vdev;
+ struct rt_virtqueue_formula formula;
+};
+
+struct rt_virtio_shm_region
+{
+ rt_uint8_t id;
+
+ rt_uint64_t base;
+ rt_uint64_t size;
+};
+
+#define RT_VIRTQUEUE_CTL_IRQ_AFFINITY 0
+#define RT_VIRTQUEUE_CTL_READ_SHM_REGION 1
+
+struct rt_virtio_transport
+{
+ rt_err_t (*get_status)(struct rt_virtio_device *vdev, rt_uint8_t *out_status);
+ rt_err_t (*set_status)(struct rt_virtio_device *vdev, rt_uint8_t status);
+ rt_err_t (*get_features)(struct rt_virtio_device *vdev, rt_uint64_t *out_features);
+ rt_err_t (*set_features)(struct rt_virtio_device *vdev);
+ rt_err_t (*get_config)(struct rt_virtio_device *vdev, rt_uint32_t offset, void *dst, int length);
+ rt_err_t (*set_config)(struct rt_virtio_device *vdev, rt_uint32_t offset, const void *src, int length);
+ rt_err_t (*install_vqs)(struct rt_virtio_device *vdev, int vqs_nr,
+ struct rt_virtqueue *vqs[], const char *names[], rt_virtqueue_callback cbs[]);
+ rt_err_t (*release_vqs)(struct rt_virtio_device *vdev);
+ rt_err_t (*control_vqs)(struct rt_virtio_device *vdev, rt_uint32_t cfg, void *data);
+ rt_err_t (*generation)(struct rt_virtio_device *vdev, rt_uint32_t *out_counter);
+ rt_err_t (*reset)(struct rt_virtio_device *vdev);
+};
+
+struct rt_virtio_driver
+{
+ struct rt_driver parent;
+
+ const struct rt_virtio_device_id *ids;
+
+ rt_uint64_t features;
+
+ rt_err_t (*probe)(struct rt_virtio_device *vdev);
+ rt_err_t (*remove)(struct rt_virtio_device *vdev);
+ void (*config_changed)(struct rt_virtio_device *vdev);
+};
+
+struct rt_virtqueue *rt_virtqueue_create(struct rt_virtio_device *vdev,
+ const char *name, int index, int num, rt_uint32_t align,
+ rt_virtqueue_notifier notify, rt_virtqueue_callback callback,
+ struct rt_virtqueue_formula *formula);
+
+rt_err_t rt_virtqueue_delete(struct rt_virtio_device *vdev, struct rt_virtqueue *vq);
+
+rt_err_t rt_virtqueue_add_outbuf(struct rt_virtqueue *vq, void *dma_buf, rt_size_t size);
+rt_err_t rt_virtqueue_add_inbuf(struct rt_virtqueue *vq, void *dma_buf, rt_size_t size);
+
+rt_bool_t rt_virtqueue_prepare(struct rt_virtqueue *vq, rt_uint32_t nr);
+void rt_virtqueue_wait_prepare(struct rt_virtqueue *vq, rt_uint32_t nr);
+rt_uint32_t rt_virtqueue_next_buf_index(struct rt_virtqueue *vq);
+
+rt_bool_t rt_virtqueue_submit(struct rt_virtqueue *vq);
+rt_bool_t rt_virtqueue_notify(struct rt_virtqueue *vq);
+rt_bool_t rt_virtqueue_kick(struct rt_virtqueue *vq);
+
+void rt_virtqueue_isr(int irq, struct rt_virtqueue *vq);
+rt_bool_t rt_virtqueue_poll(struct rt_virtqueue *vq, rt_uint32_t last_used_idx);
+
+void rt_virtqueue_disable_callback(struct rt_virtqueue *vq);
+rt_bool_t rt_virtqueue_enable_callback(struct rt_virtqueue *vq,
+ rt_uint32_t *out_last_used_idx);
+
+void *rt_virtqueue_read_buf(struct rt_virtqueue *vq, rt_size_t *out_len);
+
+rt_size_t rt_virtqueue_get_virtq_size(struct rt_virtqueue *vq);
+rt_ubase_t rt_virtqueue_get_desc_addr(struct rt_virtqueue *vq);
+rt_ubase_t rt_virtqueue_get_avail_addr(struct rt_virtqueue *vq);
+rt_ubase_t rt_virtqueue_get_used_addr(struct rt_virtqueue *vq);
+
+void rt_virtio_device_ready(struct rt_virtio_device *vdev);
+void rt_virtio_device_reset(struct rt_virtio_device *vdev);
+void rt_virtio_device_config_changed(struct rt_virtio_device *vdev);
+
+void rt_virtio_add_status(struct rt_virtio_device *vdev, rt_uint32_t status);
+
+rt_bool_t rt_virtio_has_status(struct rt_virtio_device *vdev, rt_uint8_t status_bit);
+rt_bool_t rt_virtio_has_feature(struct rt_virtio_device *vdev, rt_uint32_t feature_bit);
+
+rt_err_t rt_virtio_get_config(struct rt_virtio_device *vdev,
+ rt_uint32_t offset, void *dst, int length);
+rt_err_t rt_virtio_set_config(struct rt_virtio_device *vdev,
+ rt_uint32_t offset, const void *src, int length);
+
+rt_inline void rt_virtio_read_bytes(struct rt_virtio_device *vdev,
+ rt_uint32_t offset, void *buf, rt_uint32_t bytes_size, rt_uint32_t count)
+{
+ rt_uint32_t old, gen;
+
+ if (vdev->trans->generation)
+ {
+ vdev->trans->generation(vdev, &gen);
+ }
+ else
+ {
+ gen = 0;
+ }
+
+ do {
+ old = gen;
+
+ for (int i = 0; i < count; ++i)
+ {
+ vdev->trans->get_config(vdev,
+ offset + bytes_size * i, buf + i * bytes_size, bytes_size);
+ }
+
+ if (vdev->trans->generation)
+ {
+ vdev->trans->generation(vdev, &gen);
+ }
+ else
+ {
+ gen = 0;
+ }
+ } while (gen != old);
+}
+
+#define rt_virtio_le_to_cpu(value) \
+ (sizeof(value) == 4 ? rt_le32_to_cpu(value) : \
+ (sizeof(value) == 2 ? rt_le16_to_cpu(value) : \
+ (sizeof(value) == 1 ? value : rt_le64_to_cpu(value))))
+
+#define rt_virtio_cpu_to_le(value) \
+ (sizeof(value) == 4 ? rt_cpu_to_le32(value) : \
+ (sizeof(value) == 2 ? rt_cpu_to_le16(value) : \
+ (sizeof(value) == 1 ? value : rt_cpu_to_le64(value))))
+
+#define rt_virtio_read_config(vdev, type, member, out_value) \
+do { \
+ typeof(((type *)0)->member) tmp; \
+ rt_uint32_t offset = (rt_ubase_t)&((type *)0)->member; \
+ switch (sizeof(tmp)) \
+ { \
+ case 1: case 2: case 4: \
+ rt_virtio_get_config(vdev, offset, &tmp, sizeof(tmp)); \
+ break; \
+ default: \
+ rt_virtio_read_bytes(vdev, offset, &tmp, sizeof(tmp), 1); \
+ break; \
+ } \
+ *(out_value) = rt_virtio_le_to_cpu(tmp); \
+} while (0)
+
+#define rt_virtio_write_config(vdev, type, member, value) \
+do { \
+ typeof(((type *)0)->member) tmp = rt_virtio_cpu_to_le(value); \
+ rt_uint32_t offset = (rt_ubase_t)&((type *)0)->member; \
+ rt_virtio_set_config(vdev, offset, &tmp, sizeof(tmp)); \
+} while (0)
+
+rt_err_t rt_virtio_virtqueue_install(struct rt_virtio_device *vdev, int vqs_nr,
+ struct rt_virtqueue *vqs[], const char *names[], rt_virtqueue_callback cbs[]);
+rt_err_t rt_virtio_virtqueue_release(struct rt_virtio_device *vdev);
+rt_err_t rt_virtio_virtqueue_control(struct rt_virtio_device *vdev, rt_uint32_t cfg, void *data);
+
+const char *rt_virtio_device_id_name(struct rt_virtio_device *vdev);
+
+rt_err_t rt_virtio_driver_register(struct rt_virtio_driver *vdrv);
+rt_err_t rt_virtio_device_register(struct rt_virtio_device *vdev);
+
+#define RT_VIRTIO_DRIVER_EXPORT(driver) RT_DRIVER_EXPORT(driver, virtio, BUILIN)
+
+#endif /* __VIRTIO_H__ */
diff --git a/components/drivers/include/drivers/virtq.h b/components/drivers/include/drivers/virtq.h
new file mode 100644
index 0000000000..fa18ee82e3
--- /dev/null
+++ b/components/drivers/include/drivers/virtq.h
@@ -0,0 +1,198 @@
+/*
+ * Copyright (c) 2006-2023, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date Author Notes
+ * 2021-11-11 GuEe-GUI the first version
+ * 2023-02-25 GuEe-GUI support packed
+ */
+
+#ifndef __VIRTQ_H__
+#define __VIRTQ_H__
+
+#include <drivers/misc.h>
+#include <drivers/byteorder.h>
+
+#define VIRTQ_DESC_F_NEXT RT_BIT(0) /* This marks a buffer as continuing via the next field. */
+#define VIRTQ_DESC_F_WRITE RT_BIT(1) /* This marks a buffer as write-only (otherwise read-only). */
+#define VIRTQ_DESC_F_INDIRECT RT_BIT(3) /* This means the buffer contains a list of buffer descriptors. */
+#define VIRTQ_DESC_F_AVAIL RT_BIT(7)
+#define VIRTQ_DESC_F_USED RT_BIT(15)
+
+/*
+ * The device uses this in used->flags to advise the driver: don't kick me
+ * when you add a buffer. It's unreliable, so it's simply an optimization.
+ */
+#define VIRTQ_USED_F_NO_NOTIFY 1
+
+/*
+ * The driver uses this in avail->flags to advise the device: don't
+ * interrupt me when you consume a buffer. It's unreliable, so it's
+ * simply an optimization.
+ */
+#define VIRTQ_AVAIL_F_NO_INTERRUPT 1
+
+/* Virtqueue descriptors: 16 bytes. These can chain together via "next". */
+struct virtq_desc
+{
+ rt_uint64_t addr; /* Address (guest-physical). */
+ rt_uint32_t len; /* Length. */
+ rt_uint16_t flags; /* The flags as indicated above. */
+ rt_uint16_t next; /* We chain unused descriptors via this, too */
+};
+
+struct virtq_avail
+{
+ rt_uint16_t flags; /* Notifications */
+ rt_uint16_t idx; /* Where the driver would put the next descriptor entry in the ring (modulo the queue size) */
+ rt_uint16_t ring[];
+
+ /*
+ * Only if VIRTIO_F_RING_EVENT_IDX
+ * rt_uint16_t used_event;
+ */
+};
+
+struct virtq_used_elem
+{
+ rt_uint32_t id; /* Index of start of used descriptor chain. */
+ rt_uint32_t len; /* Total length of the descriptor chain which was written to. */
+};
+
+struct virtq_used
+{
+ rt_uint16_t flags;
+ rt_uint16_t idx;
+ struct virtq_used_elem ring[];
+
+ /*
+ * Only if VIRTIO_F_RING_EVENT_IDX
+ * rt_uint16_t avail_event;
+ */
+};
+
+/* Enable events in packed ring. */
+#define VIRTQ_PACKED_EVENT_FLAG_ENABLE 0x0
+/* Disable events in packed ring. */
+#define VIRTQ_PACKED_EVENT_FLAG_DISABLE 0x1
+/*
+ * Enable events for a specific descriptor in packed ring.
+ * (as specified by Descriptor Ring Change Event Offset/Wrap Counter).
+ * Only valid if VIRTIO_F_RING_EVENT_IDX has been negotiated.
+ */
+#define VIRTQ_PACKED_EVENT_FLAG_DESC 0x2
+
+/* Offset bit shift in event suppression structure of packed ring. */
+#define VIRTQ_PACKED_EVENT_OFF 0
+/* Wrap counter bit shift in event suppression structure of packed ring. */
+#define VIRTQ_PACKED_EVENT_WRAP_CTR 15
+
+struct virtq_packed_desc
+{
+ rt_le64_t addr; /* Buffer Address. */
+ rt_le32_t len; /* Buffer Length. */
+ rt_le16_t id; /* Buffer ID (always at the last desc). */
+ rt_le16_t flags; /* The flags depending on descriptor type. */
+ /*
+ * For avail desc:
+ * When wrap counter is 1 => VIRTQ_DESC_F_AVAIL | ~VIRTQ_DESC_F_USED
+ * When wrap counter is 0 => ~VIRTQ_DESC_F_AVAIL | VIRTQ_DESC_F_USED
+ *
+ * For used desc:
+ * When wrap counter is 1 => VIRTQ_DESC_F_AVAIL | VIRTQ_DESC_F_USED
+ * When wrap counter is 0 => ~VIRTQ_DESC_F_AVAIL | ~VIRTQ_DESC_F_USED
+ */
+};
+
+struct virtq_packed_desc_event
+{
+ rt_le16_t off_wrap; /* Descriptor ring change event offset/wrap counter. */
+ rt_le16_t flags; /* Descriptor ring change event flags. */
+};
+
+struct virtq
+{
+ rt_uint32_t num;
+ rt_uint32_t align;
+
+ union
+ {
+ struct virtq_desc *desc;
+ struct virtq_packed_desc *desc_packed;
+ };
+ union
+ {
+ struct virtq_avail *avail;
+ struct virtq_packed_desc_event *driver_event;
+ };
+ union
+ {
+ struct virtq_used *used;
+ struct virtq_packed_desc_event *device_event;
+ };
+};
+
+rt_inline void virtq_init(struct virtq *virtq, rt_uint32_t num,
+ void *pages, rt_ubase_t align)
+{
+ /* Only split */
+ virtq->num = num;
+ virtq->align = align;
+
+ virtq->desc = (struct virtq_desc *)pages;
+ virtq->avail = (struct virtq_avail *)&virtq->desc[num];
+ /* Keep sizeof(used_event) */
+ virtq->used = (struct virtq_used *)RT_ALIGN((rt_ubase_t)&virtq->avail->ring[num] + sizeof(rt_uint16_t), align);
+}
+
+rt_inline rt_size_t virtq_size(struct virtq *virtq, rt_uint32_t try_num, rt_uint32_t try_align)
+{
+ /* Only split */
+ rt_uint32_t align;
+ rt_size_t size, num;
+
+ if (virtq)
+ {
+ num = virtq->num;
+ align = virtq->align;
+ }
+ else
+ {
+ num = try_num;
+ align = try_align;
+ }
+
+ size = sizeof(struct virtq_desc) * num;
+ size += sizeof(struct virtq_avail) + sizeof(rt_uint16_t) * num;
+ /* Keep sizeof(used_event) */
+ size += sizeof(rt_uint16_t);
+ size = RT_ALIGN(size, align);
+ size += sizeof(struct virtq_used) + sizeof(struct virtq_used_elem) * num;
+ /* Keep sizeof(avail_event) */
+ size += sizeof(rt_uint16_t);
+
+ return size;
+}
+
+rt_inline rt_bool_t virtq_need_event(rt_uint16_t event_idx,
+ rt_uint16_t new_idx, rt_uint16_t old_idx)
+{
+ return (rt_uint16_t)(new_idx - event_idx - 1) < (rt_uint16_t)(new_idx - old_idx);
+}
+
+/* Get location of event indices (only with VIRTIO_F_EVENT_IDX) */
+rt_inline rt_uint16_t *virtq_used_event(struct virtq *virtq)
+{
+ /* For backwards compat, used event index is at *end* of avail ring. */
+ return &virtq->avail->ring[virtq->num];
+}
+
+rt_inline rt_uint16_t *virtq_avail_event(struct virtq *virtq)
+{
+ /* For backwards compat, avail event index is at *end* of used ring. */
+ return (rt_uint16_t *)&virtq->used->ring[virtq->num];
+}
+
+#endif /* __VIRTQ_H__ */
diff --git a/components/drivers/include/rtdevice.h b/components/drivers/include/rtdevice.h
index 3d5aa23c44..0c83137087 100644
--- a/components/drivers/include/rtdevice.h
+++ b/components/drivers/include/rtdevice.h
@@ -156,6 +156,11 @@ extern "C" {
#ifdef RT_USING_NVMEM
#include "drivers/nvmem.h"
#endif /* RT_USING_NVMEM */
+
+#ifdef RT_USING_VIRTIO
+#include "drivers/virtio.h"
+#include "drivers/virtq.h"
+#endif
#endif /* RT_USING_DM */
#ifdef RT_USING_REGULATOR
diff --git a/components/drivers/virtio/Kconfig b/components/drivers/virtio/Kconfig
index 8298ff75be..5d974c886d 100644
--- a/components/drivers/virtio/Kconfig
+++ b/components/drivers/virtio/Kconfig
@@ -1,43 +1,99 @@
menuconfig RT_USING_VIRTIO
bool "Using VirtIO device drivers"
+ depends on RT_USING_DM
+ depends on RT_USING_DMA
default n
- if RT_USING_VIRTIO
- choice RT_USING_VIRTIO_VERSION
- prompt "VirtIO Version"
- default RT_USING_VIRTIO10
+config RT_VIRTIO_TRANSPORT_MMIO
+ bool "Using VirtIO MMIO transport"
+ depends on RT_USING_VIRTIO
+ depends on RT_USING_OFW
+ default y
- config RT_USING_VIRTIO10
- bool "VirtIO v1.0"
- endchoice
+config RT_VIRTIO_TRANSPORT_PCI
+ bool "Using VirtIO PCI transport"
+ depends on RT_USING_VIRTIO
+ depends on RT_USING_PCI
+ default y
+ help
+ We not support the version of 0.95 in PCI. The minimum version >= 1.0
- config RT_USING_VIRTIO_MMIO_ALIGN
- bool "Using VirtIO MMIO alignment"
- default y
+config RT_VIRTIO_NET
+ bool "VirtIO Net"
+ depends on RT_USING_VIRTIO
+ depends on RT_USING_ETHERNET
+ default y
- config RT_USING_VIRTIO_BLK
- bool "Using VirtIO BLK"
- default y
+config RT_VIRTIO_BLK
+ bool "VirtIO BLK"
+ depends on RT_USING_VIRTIO
+ depends on RT_USING_BLK
+ default y
- config RT_USING_VIRTIO_NET
- bool "Using VirtIO NET"
- default y
+config RT_VIRTIO_CONSOLE
+ bool "VirtIO Console"
+ depends on RT_USING_VIRTIO
+ depends on RT_USING_SERIAL
+ select RT_USING_DEVICE_IPC
+ select RT_USING_SYSTEM_WORKQUEUE
+ default y
- menuconfig RT_USING_VIRTIO_CONSOLE
- bool "Using VirtIO Console"
- default y
+config RT_VIRTIO_RNG
+ bool "VirtIO RNG"
+ depends on RT_USING_VIRTIO
+ depends on RT_USING_HWCRYPTO
+ depends on RT_HWCRYPTO_USING_RNG
+ default y
- if RT_USING_VIRTIO_CONSOLE
- config RT_USING_VIRTIO_CONSOLE_PORT_MAX_NR
- int "Max number of port in VirtIO Console"
- default 4
- endif
+config RT_VIRTIO_SCSI
+ bool "VirtIO SCSI"
+ depends on RT_USING_VIRTIO
+ depends on RT_SCSI_SD || RT_SCSI_CDROM
+ default y
- config RT_USING_VIRTIO_GPU
- bool "Using VirtIO GPU"
- default y
+config RT_VIRTIO_9P
+ bool "VirtIO 9P"
+ depends on RT_USING_VIRTIO
+ select RT_USING_DFS_9PFS
+ default y
- config RT_USING_VIRTIO_INPUT
- bool "Using VirtIO Input"
- default y
- endif
+config RT_VIRTIO_RPROC_SERIAL
+ bool "VirtIO Remoteproc Serial Link"
+ depends on RT_USING_VIRTIO
+ select RT_VIRTIO_CONSOLE
+ default y
+
+config RT_VIRTIO_GPU
+ bool "VirtIO GPU"
+ depends on RT_USING_VIRTIO
+ default y
+
+config RT_VIRTIO_INPUT
+ bool "VirtIO Input"
+ depends on RT_USING_VIRTIO
+ depends on RT_USING_INPUT
+ depends on RT_INPUT_TOUCHSCREEN
+ default y
+
+config RT_VIRTIO_CRYPTO
+ bool "VirtIO Crypto"
+ depends on RT_USING_VIRTIO
+ depends on RT_USING_HWCRYPTO
+ depends on RT_HWCRYPTO_USING_AES
+ depends on RT_HWCRYPTO_USING_AES_ECB
+ depends on RT_HWCRYPTO_USING_AES_CBC
+ depends on RT_HWCRYPTO_USING_AES_CTR
+ depends on RT_HWCRYPTO_USING_DES
+ depends on RT_HWCRYPTO_USING_DES_ECB
+ depends on RT_HWCRYPTO_USING_DES_CBC
+ depends on RT_HWCRYPTO_USING_3DES
+ depends on RT_HWCRYPTO_USING_3DES_ECB
+ depends on RT_HWCRYPTO_USING_3DES_CBC
+ depends on RT_HWCRYPTO_USING_RC4
+ default y
+
+config RT_VIRTIO_SCMI
+ bool "VirtIO SCMI"
+ depends on RT_USING_VIRTIO
+ depends on RT_FIRMWARE_ARM_SCMI
+ default y
diff --git a/components/drivers/virtio/SConscript b/components/drivers/virtio/SConscript
index d38ec0e356..a5d3817f0d 100644
--- a/components/drivers/virtio/SConscript
+++ b/components/drivers/virtio/SConscript
@@ -1,11 +1,51 @@
-# RT-Thread building script for component
-
from building import *
-cwd = GetCurrentDir()
-src = Glob('*.c')
-CPPPATH = [cwd]
+group = []
+
+if not GetDepend(['RT_USING_VIRTIO']):
+ Return('group')
+
+cwd = GetCurrentDir()
+CPPPATH = [cwd + '/../include']
+
+src = ['virtio.c', 'virtio_queue.c']
+
+if GetDepend(['RT_VIRTIO_TRANSPORT_MMIO']):
+ src += ['virtio_mmio.c']
+
+if GetDepend(['RT_VIRTIO_TRANSPORT_PCI']):
+ src += ['virtio_pci.c']
+
+if GetDepend(['RT_VIRTIO_NET']):
+ src += ['virtio-net.c']
+
+if GetDepend(['RT_VIRTIO_BLK']):
+ src += ['virtio-blk.c']
+
+if GetDepend(['RT_VIRTIO_CONSOLE']) or GetDepend(['RT_VIRTIO_RPROC_SERIAL']):
+ src += ['virtio-console.c']
+
+if GetDepend(['RT_VIRTIO_RNG']):
+ src += ['virtio-rng.c']
+
+if GetDepend(['RT_VIRTIO_SCSI']):
+ src += ['virtio-scsi.c']
+
+if GetDepend(['RT_VIRTIO_9P']):
+ src += ['virtio-9p.c']
+
+if GetDepend(['RT_VIRTIO_GPU']):
+ src += ['virtio-gpu.c']
+
+if GetDepend(['RT_VIRTIO_INPUT']):
+ src += ['virtio-input.c']
+
+if GetDepend(['RT_VIRTIO_CRYPTO']):
+ src += ['virtio-crypto.c']
+
+if GetDepend(['RT_VIRTIO_SCMI']):
+ src += ['virtio-scmi.c']
-group = DefineGroup('DeviceDrivers', src, depend = ['RT_USING_VIRTIO'], CPPPATH = CPPPATH)
+group = DefineGroup('DeviceDrivers', src, depend = [''], CPPPATH = CPPPATH)
Return('group')
diff --git a/components/drivers/virtio/virtio-9p.c b/components/drivers/virtio/virtio-9p.c
new file mode 100644
index 0000000000..67ef8ca3e8
--- /dev/null
+++ b/components/drivers/virtio/virtio-9p.c
@@ -0,0 +1,188 @@
+/*
+ * 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.9p"
+#define DBG_LVL DBG_INFO
+#include <rtdbg.h>
+
+#include <dfs_9pfs.h>
+#include "virtio_config/virtio-9p.h"
+
+struct virtio_9p
+{
+ struct p9_protocol parent;
+ struct rt_virtio_device *vdev;
+
+ char *tag;
+ struct rt_virtqueue *vqs[1];
+ struct rt_completion done;
+ struct rt_spinlock lock;
+};
+
+static rt_err_t virtio_9p_transport(struct p9_protocol *p9p,
+ rt_uint8_t *tx_data, rt_uint32_t tx_size,
+ rt_uint8_t *rx_data, rt_uint32_t *ref_rx_size)
+{
+ rt_err_t err;
+ rt_ubase_t level;
+ struct rt_virtqueue *vq;
+ struct virtio_9p *v9p = rt_container_of(p9p, struct virtio_9p, parent);
+
+ vq = v9p->vqs[0];
+ rt_virtqueue_wait_prepare(vq, 2);
+
+ level = rt_spin_lock_irqsave(&v9p->lock);
+
+ rt_virtqueue_add_outbuf(vq, tx_data, tx_size);
+ rt_virtqueue_add_inbuf(vq, rx_data, *ref_rx_size);
+
+ rt_virtqueue_kick(vq);
+
+ rt_spin_unlock_irqrestore(&v9p->lock, level);
+
+ if (!(err = rt_completion_wait(&v9p->done, rt_tick_from_millisecond(1000))))
+ {
+ *ref_rx_size = rt_min_t(rt_uint32_t,
+ *ref_rx_size, rt_le32_to_cpu(*(rt_uint32_t*)(&rx_data[0])));
+ }
+
+ return err;
+}
+
+static void virtio_9p_done(struct rt_virtqueue *vq)
+{
+ rt_ubase_t level;
+ struct virtio_9p *v9p = vq->vdev->priv;
+
+ level = rt_spin_lock_irqsave(&v9p->lock);
+
+ rt_virtqueue_read_buf(vq, RT_NULL);
+ rt_completion_done(&v9p->done);
+
+ rt_spin_unlock_irqrestore(&v9p->lock, level);
+}
+
+static rt_err_t virtio_9p_vq_init(struct virtio_9p *v9p)
+{
+ const char *names[] =
+ {
+ "req",
+ };
+ rt_virtqueue_callback cbs[] =
+ {
+ &virtio_9p_done,
+ };
+
+ return rt_virtio_virtqueue_install(v9p->vdev, RT_ARRAY_SIZE(v9p->vqs),
+ v9p->vqs, names, cbs);
+}
+
+static void virtio_9p_vq_finit(struct virtio_9p *v9p)
+{
+ if (v9p->vqs[0])
+ {
+ rt_virtio_virtqueue_release(v9p->vdev);
+ }
+ if (v9p->tag)
+ {
+ rt_free(v9p->tag);
+ }
+
+ rt_free(v9p);
+}
+
+static rt_err_t virtio_9p_probe(struct rt_virtio_device *vdev)
+{
+ rt_err_t err;
+ rt_uint16_t tag_len = 0;
+ struct virtio_9p *v9p = rt_calloc(1, sizeof(*v9p));
+
+ if (!v9p)
+ {
+ return -RT_ENOMEM;
+ }
+
+ vdev->priv = v9p;
+ v9p->vdev = vdev;
+ vdev->parent.user_data = v9p;
+
+ if ((err = virtio_9p_vq_init(v9p)))
+ {
+ goto _fail;
+ }
+
+ if (rt_virtio_has_feature(vdev, VIRTIO_9P_F_MOUNT_TAG))
+ {
+ rt_virtio_read_config(vdev, struct virtio_9p_config, tag_len, &tag_len);
+ }
+
+ v9p->tag = rt_malloc(tag_len + 1);
+
+ if (!v9p->tag)
+ {
+ err = -RT_EINVAL;
+ goto _fail;
+ }
+
+ rt_virtio_read_bytes(vdev, rt_offsetof(struct virtio_9p_config, tag),
+ v9p->tag, 1, tag_len);
+ v9p->tag[tag_len] = '\0';
+
+ rt_completion_init(&v9p->done);
+ rt_spin_lock_init(&v9p->lock);
+
+ v9p->parent.name = "virtio";
+ v9p->parent.tag = v9p->tag;
+ v9p->parent.transport = &virtio_9p_transport;
+ if ((err = dfs_9pfs_add_tag(&v9p->parent)))
+ {
+ goto _fail;
+ }
+
+ return RT_EOK;
+
+_fail:
+ virtio_9p_vq_finit(v9p);
+
+ return err;
+}
+
+static rt_err_t virtio_9p_remove(struct rt_virtio_device *vdev)
+{
+ struct virtio_9p *v9p = vdev->parent.user_data;
+
+ dfs_9pfs_del_tag(&v9p->parent);
+
+ virtio_9p_vq_finit(v9p);
+
+ return RT_EOK;
+}
+
+static const struct rt_virtio_device_id virtio_9p_ids[] =
+{
+ { VIRTIO_DEVICE_ID_9P, VIRTIO_DEVICE_ANY_ID },
+ { /* sentinel */ }
+};
+
+static struct rt_virtio_driver virtio_9p_driver =
+{
+ .ids = virtio_9p_ids,
+ .features =
+ RT_BIT(VIRTIO_9P_F_MOUNT_TAG)
+ | RT_BIT(VIRTIO_F_ANY_LAYOUT),
+
+ .probe = virtio_9p_probe,
+ .remove = virtio_9p_remove,
+};
+RT_VIRTIO_DRIVER_EXPORT(virtio_9p_driver);
diff --git a/components/drivers/virtio/virtio-blk.c b/components/drivers/virtio/virtio-blk.c
new file mode 100644
index 0000000000..32267ad0e0
--- /dev/null
+++ b/components/drivers/virtio/virtio-blk.c
@@ -0,0 +1,332 @@
+/*
+ * Copyright (c) 2006-2023, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date Author Notes
+ * 2021-9-16 GuEe-GUI the first version
+ * 2021-11-11 GuEe-GUI using virtio common interface
+ * 2023-02-25 GuEe-GUI using virtio dm
+ */
+
+#include <rthw.h>
+#include <rtthread.h>
+#include <rtdevice.h>
+
+#define DBG_TAG "virtio.dev.blk"
+#define DBG_LVL DBG_INFO
+#include <rtdbg.h>
+
+#include "../block/blk_dev.h"
+#include "virtio_internal.h"
+#include "virtio_config/virtio-blk.h"
+
+struct virtio_blk
+{
+ struct rt_blk_disk parent;
+ struct rt_virtio_device *vdev;
+
+ int vblk_id;
+ rt_le32_t blk_size;
+
+ int vqs_nr;
+ struct rt_virtqueue *vqs[RT_CPUS_NR];
+ struct rt_spinlock *lock;
+ struct rt_completion *done;
+};
+
+#define raw_to_virtio_blk(raw) rt_container_of(raw, struct virtio_blk, parent)
+
+static struct rt_dm_ida virtio_blk_ida = RT_DM_IDA_INIT(CUSTOM);
+static struct rt_dm_ida vd_ida = RT_DM_IDA_INIT(VIRTUAL_BLOCK);
+
+static rt_err_t virtio_blk_request(struct virtio_blk *vblk,
+ rt_off_t sector, void *buffer, rt_size_t sector_count, int type)
+{
+ rt_base_t level;
+ rt_uint8_t status;
+ struct rt_virtqueue *vq;
+ struct virtio_blk_req req;
+ struct rt_virtio_device *vdev = vblk->vdev;
+
+ vq = vblk->vqs[rt_hw_cpu_id() % vblk->vqs_nr];
+ if (type == VIRTIO_BLK_T_OUT || type == VIRTIO_BLK_T_IN)
+ {
+ rt_virtqueue_wait_prepare(vq, 3);
+ }
+ else
+ {
+ rt_virtqueue_wait_prepare(vq, 2);
+ }
+
+ level = rt_spin_lock_irqsave(&vblk->lock[vq->index]);
+
+ req.type = cpu_to_virtio32(vdev, type);
+ req.ioprio = cpu_to_virtio32(vdev, blk_request_ioprio());
+ req.sector = cpu_to_virtio64(vdev, sector * (vblk->blk_size / 512));
+ rt_virtqueue_add_outbuf(vq, &req, sizeof(req));
+
+ if (type == VIRTIO_BLK_T_OUT)
+ {
+ rt_virtqueue_add_outbuf(vq, buffer, sector_count * vblk->blk_size);
+ }
+ else if (type == VIRTIO_BLK_T_IN)
+ {
+ rt_virtqueue_add_inbuf(vq, buffer, sector_count * vblk->blk_size);
+ }
+
+ status = RT_UINT8_MAX;
+ rt_virtqueue_add_inbuf(vq, &status, sizeof(status));
+
+ rt_virtqueue_kick(vq);
+
+ rt_spin_unlock_irqrestore(&vblk->lock[vq->index], level);
+
+ rt_completion_wait(&vblk->done[vq->index], RT_WAITING_FOREVER);
+
+ switch (status)
+ {
+ case VIRTIO_BLK_S_OK:
+ return RT_EOK;
+
+ case VIRTIO_BLK_S_UNSUPP:
+ return -RT_ENOSYS;
+
+ case VIRTIO_BLK_S_ZONE_OPEN_RESOURCE:
+ return 1;
+
+ case VIRTIO_BLK_S_ZONE_ACTIVE_RESOURCE:
+ return 2;
+
+ case VIRTIO_BLK_S_IOERR:
+ case VIRTIO_BLK_S_ZONE_UNALIGNED_WP:
+ default:
+ return -RT_EIO;
+ }
+}
+
+static rt_ssize_t virtio_blk_read(struct rt_blk_disk *disk, rt_off_t sector,
+ void *buffer, rt_size_t sector_count)
+{
+ rt_ssize_t res;
+ struct virtio_blk *vblk = raw_to_virtio_blk(disk);
+
+ res = virtio_blk_request(vblk, sector, buffer, sector_count, VIRTIO_BLK_T_IN);
+
+ return res >= 0 ? sector_count : res;
+}
+
+static rt_ssize_t virtio_blk_write(struct rt_blk_disk *disk, rt_off_t sector,
+ const void *buffer, rt_size_t sector_count)
+{
+ rt_ssize_t res;
+ struct virtio_blk *vblk = raw_to_virtio_blk(disk);
+
+ res = virtio_blk_request(vblk, sector, (void *)buffer, sector_count, VIRTIO_BLK_T_OUT);
+
+ return res >= 0 ? sector_count : res;
+}
+
+static rt_err_t virtio_blk_getgeome(struct rt_blk_disk *disk,
+ struct rt_device_blk_geometry *geometry)
+{
+ rt_le64_t capacity;
+ struct virtio_blk *vblk = raw_to_virtio_blk(disk);
+
+ rt_virtio_read_config(vblk->vdev, struct virtio_blk_config, capacity, &capacity);
+
+ geometry->bytes_per_sector = 512;
+ geometry->block_size = vblk->blk_size;
+ geometry->sector_count = rt_le64_to_cpu(capacity);
+
+ return RT_EOK;
+}
+
+static rt_err_t virtio_blk_sync(struct rt_blk_disk *disk)
+{
+ struct virtio_blk *vblk = raw_to_virtio_blk(disk);
+
+ return virtio_blk_request(vblk, 0, RT_NULL, 0, VIRTIO_BLK_T_FLUSH);
+}
+
+static rt_err_t virtio_blk_erase(struct rt_blk_disk *disk)
+{
+ struct virtio_blk *vblk = raw_to_virtio_blk(disk);
+
+ return virtio_blk_request(vblk, 0, RT_NULL, 0, VIRTIO_BLK_T_SECURE_ERASE);
+}
+
+static rt_err_t virtio_blk_autorefresh(struct rt_blk_disk *disk, rt_bool_t is_auto)
+{
+ rt_uint8_t writeback = !is_auto;
+ struct virtio_blk *vblk = raw_to_virtio_blk(disk);
+
+ /*
+ * 0: write through
+ * 1: write back
+ */
+ rt_virtio_write_config(vblk->vdev, struct virtio_blk_config, writeback, writeback);
+
+ return RT_EOK;
+}
+
+static const struct rt_blk_disk_ops virtio_blk_ops =
+{
+ .read = virtio_blk_read,
+ .write = virtio_blk_write,
+ .getgeome = virtio_blk_getgeome,
+ .sync = virtio_blk_sync,
+ .erase = virtio_blk_erase,
+ .autorefresh = virtio_blk_autorefresh,
+};
+
+static void virtio_blk_done(struct rt_virtqueue *vq)
+{
+ rt_ubase_t level;
+ struct virtio_blk *vblk = vq->vdev->priv;
+
+ level = rt_spin_lock_irqsave(&vblk->lock[vq->index]);
+
+ rt_virtqueue_read_buf(vq, RT_NULL);
+ rt_completion_done(&vblk->done[vq->index]);
+
+ rt_spin_unlock_irqrestore(&vblk->lock[vq->index], level);
+}
+
+static rt_err_t virtio_blk_vq_init(struct virtio_blk *vblk)
+{
+ rt_uint16_t vqs_nr = 1;
+ const char *names[RT_ARRAY_SIZE(vblk->vqs)];
+ rt_virtqueue_callback cbs[RT_ARRAY_SIZE(vblk->vqs)];
+ struct rt_virtio_device *vdev = vblk->vdev;
+
+ if (rt_virtio_has_feature(vdev, VIRTIO_BLK_F_MQ))
+ {
+ rt_virtio_read_config(vdev, struct virtio_blk_config, num_queues, &vqs_nr);
+ }
+
+ if (!(vblk->lock = rt_malloc(sizeof(vblk->lock[0]) * vqs_nr)))
+ {
+ return -RT_ENOMEM;
+ }
+
+ if (!(vblk->done = rt_malloc(sizeof(vblk->done[0]) * vqs_nr)))
+ {
+ return -RT_ENOMEM;
+ }
+
+ for (int i = 0; i < vqs_nr; ++i)
+ {
+ names[i] = "req";
+ cbs[i] = &virtio_blk_done;
+
+ rt_spin_lock_init(&vblk->lock[i]);
+ rt_completion_init(&vblk->done[i]);
+ }
+
+ vblk->vqs_nr = vqs_nr;
+ return rt_virtio_virtqueue_install(vdev, vqs_nr, vblk->vqs, names, cbs);
+}
+
+static void virtio_blk_vq_finit(struct virtio_blk *vblk)
+{
+ if (vblk->vqs[0])
+ {
+ rt_virtio_virtqueue_release(vblk->vdev);
+ }
+ if (vblk->lock)
+ {
+ rt_free(vblk->lock);
+ }
+ if (vblk->done)
+ {
+ rt_free(vblk->done);
+ }
+}
+
+static rt_err_t virtio_blk_probe(struct rt_virtio_device *vdev)
+{
+ rt_err_t err;
+ struct virtio_blk *vblk = rt_calloc(1, sizeof(*vblk));
+
+ if (!vblk)
+ {
+ return -RT_ENOMEM;
+ }
+
+ if ((vblk->vblk_id = rt_dm_ida_alloc(&virtio_blk_ida)) < 0)
+ {
+ return -RT_EFULL;
+ }
+
+ vdev->priv = vblk;
+ vblk->vdev = vdev;
+ vdev->parent.user_data = vblk;
+ vblk->parent.ida = &vd_ida;
+ vblk->parent.parallel_io = RT_TRUE;
+ vblk->parent.ops = &virtio_blk_ops;
+ vblk->parent.max_partitions = RT_BLK_PARTITION_MAX;
+
+ if ((err = virtio_blk_vq_init(vblk)))
+ {
+ goto _fail;
+ }
+
+ rt_virtio_read_config(vdev, struct virtio_blk_config, blk_size, &vblk->blk_size);
+
+ rt_dm_dev_set_name(&vblk->parent.parent, "vd%c%c", letter_name(vblk->vblk_id));
+
+ if ((err = rt_hw_blk_disk_register(&vblk->parent)))
+ {
+ goto _fail;
+ }
+
+ return RT_EOK;
+
+_fail:
+ rt_dm_ida_free(&virtio_blk_ida, vblk->vblk_id);
+ virtio_blk_vq_finit(vblk);
+ rt_free(vblk);
+
+ return err;
+}
+
+static rt_err_t virtio_blk_remove(struct rt_virtio_device *vdev)
+{
+ struct virtio_blk *vblk = vdev->parent.user_data;
+
+ rt_hw_blk_disk_unregister(&vblk->parent);
+ rt_dm_ida_free(&virtio_blk_ida, vblk->vblk_id);
+
+ virtio_blk_vq_finit(vblk);
+ rt_free(vblk);
+
+ return RT_EOK;
+}
+
+static const struct rt_virtio_device_id virtio_blk_ids[] =
+{
+ { VIRTIO_DEVICE_ID_BLOCK, VIRTIO_DEVICE_ANY_ID },
+ { /* sentinel */ }
+};
+
+static struct rt_virtio_driver virtio_blk_driver =
+{
+ .ids = virtio_blk_ids,
+ .features =
+ RT_BIT(VIRTIO_BLK_F_SIZE_MAX)
+ | RT_BIT(VIRTIO_BLK_F_GEOMETRY)
+ | RT_BIT(VIRTIO_BLK_F_BLK_SIZE)
+ | RT_BIT(VIRTIO_BLK_F_FLUSH)
+ | RT_BIT(VIRTIO_BLK_F_TOPOLOGY)
+ | RT_BIT(VIRTIO_BLK_F_CONFIG_WCE)
+ | RT_BIT(VIRTIO_BLK_F_MQ)
+ | RT_BIT(VIRTIO_BLK_F_DISCARD)
+ | RT_BIT(VIRTIO_BLK_F_WRITE_ZEROES)
+ | RT_BIT(VIRTIO_BLK_F_SECURE_ERASE),
+
+ .probe = virtio_blk_probe,
+ .remove = virtio_blk_remove,
+};
+RT_VIRTIO_DRIVER_EXPORT(virtio_blk_driver);
diff --git a/components/drivers/virtio/virtio-console.c b/components/drivers/virtio/virtio-console.c
new file mode 100644
index 0000000000..b49391409e
--- /dev/null
+++ b/components/drivers/virtio/virtio-console.c
@@ -0,0 +1,732 @@
+/*
+ * Copyright (c) 2006-2023, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date Author Notes
+ * 2021-11-11 GuEe-GUI the first version
+ * 2023-02-25 GuEe-GUI using virtio dm
+ */
+
+#include <rthw.h>
+#include <rtthread.h>
+#include <rtdevice.h>
+
+#define DBG_TAG "virtio.dev.console"
+#define DBG_LVL DBG_INFO
+#include <rtdbg.h>
+
+#include <cpuport.h>
+
+#include "virtio_internal.h"
+#include "virtio_config/virtio-console.h"
+
+#define QUEUE_PORT_RX 0
+#define QUEUE_PORT_TX 1
+#define QUEUE_CTRL_RX 2
+#define QUEUE_CTRL_TX 3
+
+struct virtio_console;
+
+struct console_port
+{
+ struct rt_serial_device parent;
+ char name[64];
+
+ char *stream;
+ char *rx_stream;
+ char *tx_stream;
+ rt_bool_t irq_enabled;
+ rt_bool_t host_connected;
+ struct rt_spinlock lock;
+ struct virtio_console *vconsole;
+
+ struct rt_virtqueue *rx_vq;
+ struct rt_virtqueue *tx_vq;
+};
+
+#define raw_to_console_port(raw) rt_container_of(raw, struct console_port, parent)
+
+struct virtio_console
+{
+ struct rt_virtio_device *vdev;
+
+ rt_uint32_t uid;
+ rt_size_t stream_rx_size;
+ rt_size_t stream_tx_size;
+
+ struct rt_spinlock lock;
+ struct rt_virtqueue *ctrl_rx_vq;
+ struct rt_virtqueue *ctrl_tx_vq;
+
+ rt_size_t ctrl_packet_size;
+ struct virtio_console_control_ext *ctrl_packet;
+
+ struct rt_work ctrl_work;
+ struct rt_work config_work;
+
+ rt_size_t max_port_nr;
+ struct rt_virtqueue **vqs;
+ struct console_port *ports;
+};
+
+static struct rt_dm_ida virtio_console_ida = RT_DM_IDA_INIT(CUSTOM);
+
+rt_inline rt_bool_t console_multiport(struct virtio_console *vconsole)
+{
+ return rt_virtio_has_feature(vconsole->vdev, VIRTIO_CONSOLE_F_MULTIPORT);
+}
+
+static rt_ssize_t console_send_ctrl_msg(struct virtio_console *vconsole,
+ rt_uint32_t port_id, rt_uint16_t event, rt_uint16_t value)
+{
+ struct rt_virtqueue *vq;
+ struct virtio_console_control ctrl_packet;
+
+ if (!vconsole || vconsole->max_port_nr <= 1)
+ {
+ return RT_EOK;
+ }
+
+ vq = vconsole->ctrl_tx_vq;
+ rt_spin_lock(&vconsole->lock);
+
+ ctrl_packet.id = cpu_to_virtio32(vconsole->vdev, port_id);
+ ctrl_packet.event = cpu_to_virtio16(vconsole->vdev, event);
+ ctrl_packet.value = cpu_to_virtio16(vconsole->vdev, value);
+
+ rt_virtqueue_add_outbuf(vq, &ctrl_packet, sizeof(ctrl_packet));
+ rt_virtqueue_kick(vq);
+
+ while (!rt_virtqueue_read_buf(vq, RT_NULL))
+ {
+ rt_hw_cpu_relax();
+ }
+
+ rt_spin_unlock(&vconsole->lock);
+
+ return RT_EOK;
+}
+
+static void console_emergency_write(struct virtio_console *vconsole,
+ rt_uint32_t emerg_wr)
+{
+ rt_virtio_write_config(vconsole->vdev, struct virtio_console_config,
+ emerg_wr, emerg_wr);
+}
+
+static rt_err_t console_port_configure(struct rt_serial_device *serial,
+ struct serial_configure *cfg)
+{
+ return RT_EOK;
+}
+
+static rt_err_t console_port_control(struct rt_serial_device *serial, int cmd, void *arg)
+{
+ struct console_port *port = raw_to_console_port(serial);
+
+ switch (cmd)
+ {
+ case RT_DEVICE_CTRL_CLR_INT:
+ port->irq_enabled = RT_FALSE;
+ break;
+
+ case RT_DEVICE_CTRL_SET_INT:
+ port->irq_enabled = RT_TRUE;
+ break;
+ }
+
+ return RT_EOK;
+}
+
+static int console_port_putc(struct rt_serial_device *serial, char c)
+{
+ rt_base_t level;
+ char *tx_stream;
+ struct rt_virtqueue *vq;
+ struct console_port *port = raw_to_console_port(serial);
+
+ if (!port->host_connected)
+ {
+ if (rt_virtio_has_feature(port->vconsole->vdev, VIRTIO_CONSOLE_F_EMERG_WRITE))
+ {
+ console_emergency_write(port->vconsole, c);
+
+ if (port->parent.parent.open_flag & RT_DEVICE_FLAG_INT_TX)
+ {
+ rt_hw_serial_isr(&port->parent, RT_SERIAL_EVENT_TX_DONE);
+ }
+ }
+
+ return 1;
+ }
+
+ vq = port->tx_vq;
+ rt_virtqueue_wait_prepare(vq, 1);
+
+ level = rt_spin_lock_irqsave(&port->lock);
+
+ tx_stream = &port->tx_stream[rt_virtqueue_next_buf_index(vq)];
+ *tx_stream = c;
+ rt_virtqueue_add_outbuf(vq, tx_stream, sizeof(*tx_stream));
+ rt_virtqueue_kick(vq);
+
+ if (port->parent.parent.open_flag & ~RT_DEVICE_FLAG_INT_TX)
+ {
+ while (!rt_virtqueue_read_buf(vq, RT_NULL))
+ {
+ rt_hw_cpu_relax();
+ }
+ }
+
+ rt_spin_unlock_irqrestore(&port->lock, level);
+
+ return 1;
+}
+
+static int console_port_getc(struct rt_serial_device *serial)
+{
+ rt_base_t level;
+ int ch = -1;
+ char *rx_stream;
+ struct rt_virtqueue *vq;
+ struct console_port *port = raw_to_console_port(serial);
+
+ level = rt_spin_lock_irqsave(&port->lock);
+
+ vq = port->rx_vq;
+ if ((rx_stream = rt_virtqueue_read_buf(vq, RT_NULL)))
+ {
+ ch = *rx_stream;
+
+ rt_virtqueue_add_inbuf(vq, rx_stream, sizeof(char));
+
+ rt_virtqueue_kick(vq);
+ }
+
+ rt_spin_unlock_irqrestore(&port->lock, level);
+
+ return ch;
+}
+
+static const struct rt_uart_ops console_port_ops =
+{
+ .configure = console_port_configure,
+ .control = console_port_control,
+ .putc = console_port_putc,
+ .getc = console_port_getc,
+};
+
+static rt_err_t console_port_add(struct virtio_console *vconsole,
+ struct console_port *port)
+{
+ char *stream;
+ const char *name;
+ rt_uint32_t id = port - vconsole->ports;
+
+ rt_memset(port, 0, sizeof(*port));
+
+ if (!(stream = rt_malloc(sizeof(char) * (vconsole->stream_rx_size + vconsole->stream_tx_size))))
+ {
+ return -RT_ENOMEM;
+ }
+
+ port->stream = stream;
+ port->tx_stream = stream;
+ port->rx_stream = stream + vconsole->stream_tx_size;
+ port->vconsole = vconsole;
+ rt_spin_lock_init(&port->lock);
+
+ if (!port->rx_vq || !port->tx_vq)
+ {
+ if (id != 0)
+ {
+ port->rx_vq = vconsole->vqs[4 + (id - 1) * 2 + QUEUE_PORT_RX];
+ port->tx_vq = vconsole->vqs[4 + (id - 1) * 2 + QUEUE_PORT_TX];
+ }
+ else
+ {
+ port->rx_vq = vconsole->vqs[QUEUE_PORT_RX];
+ port->tx_vq = vconsole->vqs[QUEUE_PORT_TX];
+ }
+
+ for (int idx = 0; idx < vconsole->stream_rx_size; ++idx)
+ {
+ rt_virtqueue_add_inbuf(port->rx_vq, &port->rx_stream[idx], sizeof(char));
+
+ rt_virtqueue_submit(port->rx_vq);
+ }
+
+ rt_virtqueue_notify(port->rx_vq);
+ }
+
+ console_send_ctrl_msg(vconsole, VIRTIO_CONSOLE_BAD_ID,
+ VIRTIO_CONSOLE_DEVICE_READY, 1);
+
+ if (!console_multiport(port->vconsole))
+ {
+ port->host_connected = RT_TRUE;
+ }
+
+ port->parent.ops = &console_port_ops;
+ port->parent.config = (struct serial_configure)RT_SERIAL_CONFIG_DEFAULT;
+ rt_dm_dev_set_name(&port->parent.parent, "vport%up%u", vconsole->uid, id);
+ name = rt_dm_dev_get_name(&port->parent.parent);
+
+ return rt_hw_serial_register(&port->parent, name,
+ RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_REMOVABLE |
+ RT_DEVICE_FLAG_INT_TX | RT_DEVICE_FLAG_INT_RX, vconsole);
+}
+
+static void console_port_remove(struct console_port *port, rt_bool_t sync)
+{
+ rt_uint32_t port_id;
+
+ if (!port->vconsole)
+ {
+ return;
+ }
+
+ /* Make sure pending buffer is empty */
+ while (rt_virtqueue_read_buf(port->tx_vq, RT_NULL) ||
+ rt_virtqueue_read_buf(port->rx_vq, RT_NULL))
+ {
+ rt_thread_yield();
+ }
+
+ port_id = port - port->vconsole->ports;
+
+ if (sync && port_id != 0)
+ {
+ console_send_ctrl_msg(port->vconsole, port_id, VIRTIO_CONSOLE_PORT_OPEN, 0);
+ }
+
+ rt_device_unregister(&port->parent.parent);
+
+ rt_free(port->stream);
+ port->vconsole = RT_NULL;
+}
+
+static struct console_port *console_find_port_by_vq(struct virtio_console *vconsole,
+ struct rt_virtqueue *vq)
+{
+ for (int i = 0; i < vconsole->max_port_nr; ++i)
+ {
+ struct console_port *port = &vconsole->ports[i];
+
+ if (port->tx_vq == vq || port->rx_vq == vq)
+ {
+ return port;
+ }
+ }
+
+ return RT_NULL;
+}
+
+static struct console_port *console_find_port_by_id(struct virtio_console *vconsole,
+ rt_uint32_t id)
+{
+ return id < vconsole->max_port_nr ? &vconsole->ports[id] : RT_NULL;
+}
+
+static void console_resize(struct virtio_console *vconsole,
+ rt_uint16_t cols, rt_uint16_t rows)
+{
+ LOG_D("%s: [cols, rows] resize [%u, %u]",
+ rt_dm_dev_get_name(&vconsole->vdev.parent), cols, rows);
+
+ /* Port to TTY */
+}
+
+static void console_ctrl_work(struct rt_work *work, void *work_data)
+{
+ rt_uint32_t port_id;
+ struct console_port *port;
+ struct virtio_console_control *ctrl_packet;
+ struct virtio_console_control_ext *ctrl_packet_ext;
+ struct virtio_console *vconsole = work_data;
+ struct rt_virtio_device *vdev = vconsole->vdev;
+
+_next_ctrl:
+ if (!(ctrl_packet_ext = rt_virtqueue_read_buf(vconsole->ctrl_rx_vq, RT_NULL)))
+ {
+ return;
+ }
+
+ ctrl_packet = &ctrl_packet_ext->ctrl;
+ port = console_find_port_by_id(vconsole, virtio32_to_cpu(vdev, ctrl_packet->id));
+ port_id = virtio32_to_cpu(vdev, ctrl_packet->id);
+
+ if (!port->vconsole &&
+ cpu_to_virtio16(vdev, ctrl_packet->event) != VIRTIO_CONSOLE_PORT_ADD)
+ {
+ LOG_D("%s: Port%d in control is invalid", rt_dm_dev_get_name(&vdev->parent),
+ port_id);
+
+ goto _prepare_next_ctrl;
+ }
+
+ switch (virtio16_to_cpu(vdev, ctrl_packet->event))
+ {
+ case VIRTIO_CONSOLE_PORT_ADD:
+ if (port->vconsole)
+ {
+ LOG_D("%s: Port%u already added", rt_dm_dev_get_name(&vdev->parent),
+ port_id);
+
+ console_send_ctrl_msg(vconsole, port_id, VIRTIO_CONSOLE_PORT_READY, 1);
+ break;
+ }
+ if (port_id >= vconsole->max_port_nr)
+ {
+ LOG_W("%s: Port%u is out of %u max supported",
+ rt_dm_dev_get_name(&vdev->parent), port_id, vconsole->max_port_nr);
+ break;
+ }
+ console_port_add(vconsole, port);
+ break;
+
+ case VIRTIO_CONSOLE_PORT_REMOVE:
+ console_port_remove(port, RT_FALSE);
+ break;
+
+ case VIRTIO_CONSOLE_CONSOLE_PORT:
+ console_send_ctrl_msg(vconsole, port_id, VIRTIO_CONSOLE_PORT_OPEN, 1);
+ break;
+
+ case VIRTIO_CONSOLE_RESIZE:
+ console_resize(vconsole,
+ virtio16_to_cpu(vdev, ctrl_packet_ext->resize.cols),
+ virtio16_to_cpu(vdev, ctrl_packet_ext->resize.rows));
+ break;
+
+ case VIRTIO_CONSOLE_PORT_OPEN:
+ port->host_connected = !!virtio16_to_cpu(vdev, ctrl_packet->value);
+ console_send_ctrl_msg(vconsole, port_id, VIRTIO_CONSOLE_PORT_OPEN, 1);
+ break;
+
+ case VIRTIO_CONSOLE_PORT_NAME:
+ rt_strncpy(port->name, (const char *)ctrl_packet_ext->data, sizeof(port->name));
+ break;
+
+ default:
+ break;
+ }
+
+_prepare_next_ctrl:
+ rt_virtqueue_add_inbuf(vconsole->ctrl_rx_vq,
+ ctrl_packet_ext, sizeof(*ctrl_packet_ext));
+
+ rt_virtqueue_kick(vconsole->ctrl_rx_vq);
+
+ goto _next_ctrl;
+}
+
+static void console_config_work(struct rt_work *work, void *work_data)
+{
+ rt_uint16_t cols, rows;
+ struct virtio_console *vconsole = work_data;
+ struct rt_virtio_device *vdev = vconsole->vdev;
+
+ rt_virtio_read_config(vdev, struct virtio_console_config, cols, &cols);
+ rt_virtio_read_config(vdev, struct virtio_console_config, rows, &rows);
+
+ console_resize(vconsole, cols, rows);
+}
+
+static void virtio_console_rx_done(struct rt_virtqueue *vq)
+{
+ struct virtio_console *vconsole = vq->vdev->priv;
+ struct console_port *port = console_find_port_by_vq(vconsole, vq);
+
+ if (!port)
+ {
+ return;
+ }
+
+ if (port->irq_enabled)
+ {
+ rt_hw_serial_isr(&port->parent, RT_SERIAL_EVENT_RX_IND);
+ }
+ else
+ {
+ /* Give up */
+ console_port_getc(&port->parent);
+ }
+}
+
+static void virtio_console_tx_done(struct rt_virtqueue *vq)
+{
+ struct virtio_console *vconsole = vq->vdev->priv;
+ struct console_port *port = console_find_port_by_vq(vconsole, vq);
+
+ if (!port)
+ {
+ return;
+ }
+
+ if (port->parent.parent.open_flag & RT_DEVICE_FLAG_INT_TX)
+ {
+ if (rt_virtqueue_read_buf(vq, RT_NULL))
+ {
+ rt_hw_serial_isr(&port->parent, RT_SERIAL_EVENT_TX_DONE);
+ }
+ }
+}
+
+static void virtio_console_ctrl_done(struct rt_virtqueue *vq)
+{
+ struct virtio_console *vconsole = vq->vdev->priv;
+
+ rt_work_submit(&vconsole->ctrl_work, 0);
+}
+
+static void virtio_console_config_changed(struct rt_virtio_device *vdev)
+{
+ struct virtio_console *vconsole = vdev->priv;
+
+ if (!console_multiport(vconsole))
+ {
+ rt_work_submit(&vconsole->config_work, 0);
+ }
+}
+
+static rt_err_t virtio_console_vq_init(struct virtio_console *vconsole)
+{
+ rt_err_t err;
+ const char **names;
+ rt_size_t vqs_nr = 2;
+ rt_virtqueue_callback *cbs;
+
+ if (vconsole->max_port_nr > 1)
+ {
+ vqs_nr = 2 * vconsole->max_port_nr + 2;
+ }
+
+ vconsole->vqs = rt_calloc(vqs_nr, sizeof(*vconsole->vqs));
+
+ if (!vconsole->vqs)
+ {
+ return -RT_ENOMEM;
+ }
+
+ if (!(names = rt_malloc(sizeof(*names) * vqs_nr)))
+ {
+ return -RT_ENOMEM;
+ }
+
+ if (!(cbs = rt_malloc(sizeof(*cbs) * vqs_nr)))
+ {
+ rt_free(names);
+
+ return -RT_ENOMEM;
+ }
+
+ names[QUEUE_PORT_RX] = "ch-rx";
+ names[QUEUE_PORT_TX] = "ch-tx";
+ cbs[QUEUE_PORT_RX] = &virtio_console_rx_done;
+ cbs[QUEUE_PORT_TX] = &virtio_console_tx_done;
+
+ if (vqs_nr > 2)
+ {
+ names[QUEUE_CTRL_RX] = "ctl-rx";
+ names[QUEUE_CTRL_TX] = "ctl-tx";
+ cbs[QUEUE_CTRL_RX] = &virtio_console_ctrl_done;
+ cbs[QUEUE_CTRL_TX] = RT_NULL;
+ }
+
+ for (int i = 4; i < vqs_nr; i += 2)
+ {
+ names[i + QUEUE_PORT_RX] = "ch-rx";
+ names[i + QUEUE_PORT_TX] = "ch-tx";
+ cbs[i + QUEUE_PORT_RX] = &virtio_console_rx_done;
+ cbs[i + QUEUE_PORT_TX] = &virtio_console_tx_done;
+ }
+
+ if ((err = rt_virtio_virtqueue_install(vconsole->vdev, vqs_nr,
+ vconsole->vqs, names, cbs)))
+ {
+ goto _out_free;
+ }
+
+ vconsole->stream_rx_size = rt_virtqueue_get_virtq_size(vconsole->vqs[QUEUE_PORT_RX]);
+ vconsole->stream_tx_size = rt_virtqueue_get_virtq_size(vconsole->vqs[QUEUE_PORT_TX]);
+
+ if (vqs_nr > 2)
+ {
+ struct rt_virtqueue *ctrl_rx_vq, *ctrl_tx_vq;
+
+ ctrl_rx_vq = vconsole->vqs[QUEUE_CTRL_RX];
+ ctrl_tx_vq = vconsole->vqs[QUEUE_CTRL_TX];
+
+ vconsole->ctrl_packet_size = rt_virtqueue_get_virtq_size(ctrl_rx_vq);
+ vconsole->ctrl_packet = rt_malloc(sizeof(*vconsole->ctrl_packet) *
+ vconsole->ctrl_packet_size);
+
+ if (!vconsole->ctrl_packet)
+ {
+ goto _out_free;
+ }
+
+ for (int idx = 0; idx < vconsole->ctrl_packet_size; ++idx)
+ {
+ rt_virtqueue_add_inbuf(ctrl_rx_vq, &vconsole->ctrl_packet[idx],
+ sizeof(vconsole->ctrl_packet[idx]));
+
+ rt_virtqueue_submit(ctrl_rx_vq);
+ }
+
+ rt_virtqueue_notify(ctrl_rx_vq);
+
+ vconsole->ctrl_rx_vq = ctrl_rx_vq;
+ vconsole->ctrl_tx_vq = ctrl_tx_vq;
+
+ rt_virtqueue_disable_callback(ctrl_tx_vq);
+ }
+
+_out_free:
+ rt_free(names);
+ rt_free(cbs);
+
+ return err;
+}
+
+static void virtio_console_vq_finit(struct virtio_console *vconsole)
+{
+ if (vconsole->ports)
+ {
+ rt_free(vconsole->ports);
+ }
+
+ if (vconsole->vqs)
+ {
+ if (vconsole->vqs[0])
+ {
+ rt_virtio_virtqueue_release(vconsole->vdev);
+ }
+
+ rt_free(vconsole->vqs);
+ }
+
+ if (vconsole->ctrl_packet)
+ {
+ rt_free(vconsole->ctrl_packet);
+ }
+}
+
+static rt_err_t virtio_console_probe(struct rt_virtio_device *vdev)
+{
+ rt_err_t err;
+ struct virtio_console *vconsole = rt_calloc(1, sizeof(*vconsole));
+
+ if (!vconsole)
+ {
+ return -RT_ENOMEM;
+ }
+
+ vdev->priv = vconsole;
+ vconsole->vdev = vdev;
+ vdev->parent.user_data = vconsole;
+
+ rt_virtio_read_config(vdev, struct virtio_console_config,
+ max_nr_ports, &vconsole->max_port_nr);
+ vconsole->max_port_nr = rt_max_t(rt_size_t, 1, vconsole->max_port_nr);
+
+ vconsole->ports = rt_malloc(sizeof(*vconsole->ports) * vconsole->max_port_nr);
+
+ if (!vconsole->ports)
+ {
+ err = -RT_ENOMEM;
+ goto _fail;
+ }
+
+ if ((err = virtio_console_vq_init(vconsole)))
+ {
+ goto _fail;
+ }
+
+ if ((vconsole->uid = rt_dm_ida_alloc(&virtio_console_ida)) < 0)
+ {
+ return -RT_EFULL;
+ }
+
+ if (vconsole->ctrl_rx_vq && vconsole->ctrl_tx_vq)
+ {
+ rt_work_init(&vconsole->ctrl_work, console_ctrl_work, vconsole);
+ }
+
+ rt_work_init(&vconsole->config_work, console_config_work, vconsole);
+
+ for (int i = 0; i < vconsole->max_port_nr; ++i)
+ {
+ vconsole->ports[i].vconsole = RT_NULL;
+ }
+
+ if ((err = console_port_add(vconsole, &vconsole->ports[0])))
+ {
+ goto _fail;
+ }
+
+ return RT_EOK;
+
+_fail:
+ rt_dm_ida_free(&virtio_console_ida, vconsole->uid);
+ virtio_console_vq_finit(vconsole);
+ rt_free(vconsole);
+
+ return err;
+}
+
+static rt_err_t virtio_console_remove(struct rt_virtio_device *vdev)
+{
+ struct virtio_console *vconsole = vdev->parent.user_data;
+
+ for (int i = 0; i < vconsole->max_port_nr; ++i)
+ {
+ console_port_remove(&vconsole->ports[i], RT_TRUE);
+ }
+
+ rt_dm_ida_free(&virtio_console_ida, vconsole->uid);
+
+ virtio_console_vq_finit(vconsole);
+ rt_free(vconsole);
+
+ return RT_EOK;
+}
+
+static const struct rt_virtio_device_id virtio_console_ids[] =
+{
+ { VIRTIO_DEVICE_ID_CONSOLE, VIRTIO_DEVICE_ANY_ID },
+ { /* sentinel */ }
+};
+
+static struct rt_virtio_driver virtio_console_driver =
+{
+ .ids = virtio_console_ids,
+ .features =
+ RT_BIT(VIRTIO_CONSOLE_F_SIZE)
+ | RT_BIT(VIRTIO_CONSOLE_F_MULTIPORT)
+ | RT_BIT(VIRTIO_CONSOLE_F_EMERG_WRITE),
+
+ .probe = virtio_console_probe,
+ .remove = virtio_console_remove,
+ .config_changed = virtio_console_config_changed,
+};
+RT_VIRTIO_DRIVER_EXPORT(virtio_console_driver);
+
+static const struct rt_virtio_device_id virtio_rproc_serial_ids[] =
+{
+#ifdef RT_VIRTIO_RPROC_SERIAL
+ { VIRTIO_DEVICE_ID_RPROC_SERIAL, VIRTIO_DEVICE_ANY_ID },
+#endif
+ { /* sentinel */ }
+};
+
+static struct rt_virtio_driver virtio_rproc_serial_driver =
+{
+ .ids = virtio_rproc_serial_ids,
+ .probe = virtio_console_probe,
+ .remove = virtio_console_remove,
+};
+RT_VIRTIO_DRIVER_EXPORT(virtio_rproc_serial_driver);
diff --git a/components/drivers/virtio/virtio-crypto.c b/components/drivers/virtio/virtio-crypto.c
new file mode 100644
index 0000000000..1f4d80abdf
--- /dev/null
+++ b/components/drivers/virtio/virtio-crypto.c
@@ -0,0 +1,666 @@
+/*
+ * 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.crypto"
+#define DBG_LVL DBG_INFO
+#include <rtdbg.h>
+
+#include "virtio_config/virtio-crypto.h"
+
+struct virtio_crypto_symmetric_contex
+{
+ rt_uint64_t session_id;
+ struct rt_virtqueue *data_vq;
+};
+
+struct virtio_crypto
+{
+ struct rt_hwcrypto_device parent;
+ struct rt_virtio_device *vdev;
+
+ rt_uint32_t status;
+ rt_uint32_t services;
+ rt_uint32_t max_data_queues;
+ rt_uint64_t max_req_size;
+ rt_uint64_t max_cipher_key_len;
+ rt_uint64_t max_auth_key_len;
+
+ struct rt_virtqueue **vqs;
+ struct rt_virtqueue *ctrl_vq;
+ struct rt_completion *data_done;
+ struct rt_completion ctrl_done;
+ struct rt_spinlock *data_lock;
+ struct rt_spinlock ctrl_lock;
+};
+
+#define raw_to_virtio_crypto(raw) rt_container_of((raw)->parent.device, struct virtio_crypto, parent)
+
+rt_inline struct rt_virtqueue *virtio_crypto_data_vq(struct virtio_crypto *vcrypto)
+{
+ return vcrypto->vqs[rt_hw_cpu_id() % vcrypto->max_data_queues];
+}
+
+static rt_err_t virtio_crypto_symmetric_create_session(
+ struct hwcrypto_symmetric *symmetric_ctx, rt_bool_t encrypt)
+{
+ rt_ubase_t level;
+ struct rt_virtqueue *ctrl_vq, *data_vq;
+ struct virtio_crypto_op_ctrl_req ctrl;
+ struct virtio_crypto_session_input input;
+ struct virtio_crypto_sym_create_session_req *sym_create_session;
+ struct virtio_crypto *vcrypto = raw_to_virtio_crypto(symmetric_ctx);
+ struct virtio_crypto_symmetric_contex *vctx = symmetric_ctx->parent.contex;
+
+ ctrl_vq = vcrypto->ctrl_vq;
+ data_vq = virtio_crypto_data_vq(vcrypto);
+
+ /* Pad ctrl header */
+ ctrl.header.opcode = rt_cpu_to_le32(VIRTIO_CRYPTO_CIPHER_CREATE_SESSION);
+ switch (symmetric_ctx->parent.type & HWCRYPTO_MAIN_TYPE_MASK)
+ {
+ case HWCRYPTO_TYPE_AES:
+ switch (symmetric_ctx->parent.type)
+ {
+ case HWCRYPTO_TYPE_AES_ECB:
+ ctrl.header.algo = rt_cpu_to_le32(VIRTIO_CRYPTO_CIPHER_AES_ECB);
+ break;
+
+ case HWCRYPTO_TYPE_AES_CBC:
+ ctrl.header.algo = rt_cpu_to_le32(VIRTIO_CRYPTO_CIPHER_AES_CBC);
+ break;
+
+ case HWCRYPTO_TYPE_AES_CTR:
+ ctrl.header.algo = rt_cpu_to_le32(VIRTIO_CRYPTO_CIPHER_AES_CTR);
+ break;
+
+ default:
+ return -RT_ENOSYS;
+ }
+ break;
+
+ case HWCRYPTO_TYPE_DES:
+ switch (symmetric_ctx->parent.type)
+ {
+ case HWCRYPTO_TYPE_DES_ECB:
+ ctrl.header.algo = rt_cpu_to_le32(VIRTIO_CRYPTO_CIPHER_DES_ECB);
+ break;
+
+ case HWCRYPTO_TYPE_DES_CBC:
+ ctrl.header.algo = rt_cpu_to_le32(VIRTIO_CRYPTO_CIPHER_DES_CBC);
+ break;
+
+ default:
+ return -RT_ENOSYS;
+ }
+ break;
+
+ case HWCRYPTO_TYPE_3DES:
+ switch (symmetric_ctx->parent.type)
+ {
+ case HWCRYPTO_TYPE_3DES_ECB:
+ ctrl.header.algo = rt_cpu_to_le32(VIRTIO_CRYPTO_CIPHER_3DES_ECB);
+ break;
+
+ case HWCRYPTO_TYPE_3DES_CBC:
+ ctrl.header.algo = rt_cpu_to_le32(VIRTIO_CRYPTO_CIPHER_3DES_CBC);
+ break;
+
+ default:
+ return -RT_ENOSYS;
+ }
+ break;
+
+ case HWCRYPTO_TYPE_RC4:
+ ctrl.header.algo = rt_cpu_to_le32(VIRTIO_CRYPTO_CIPHER_ARC4);
+ break;
+ }
+ ctrl.header.queue_id = data_vq->index;
+
+ input.status = rt_cpu_to_le32(VIRTIO_CRYPTO_ERR);
+
+ /* Pad cipher's parameters */
+ sym_create_session = &ctrl.sym_create_session;
+ sym_create_session->op_type = rt_cpu_to_le32(VIRTIO_CRYPTO_SYM_OP_CIPHER);
+ sym_create_session->cipher.para.algo = ctrl.header.algo;
+ sym_create_session->cipher.para.keylen = rt_cpu_to_le32(symmetric_ctx->key_bitlen / 8);
+ sym_create_session->cipher.para.op = rt_cpu_to_le32(encrypt ?
+ VIRTIO_CRYPTO_OP_ENCRYPT : VIRTIO_CRYPTO_OP_DECRYPT);
+
+ rt_virtqueue_wait_prepare(ctrl_vq, 3);
+
+ level = rt_spin_lock_irqsave(&vcrypto->ctrl_lock);
+
+ rt_virtqueue_add_outbuf(ctrl_vq, &ctrl, sizeof(ctrl));
+ rt_virtqueue_add_outbuf(ctrl_vq, symmetric_ctx->key, symmetric_ctx->key_bitlen / 8);
+ rt_virtqueue_add_inbuf(ctrl_vq, &input, sizeof(input));
+
+ rt_virtqueue_kick(ctrl_vq);
+
+ rt_spin_unlock_irqrestore(&vcrypto->ctrl_lock, level);
+
+ rt_completion_wait(&vcrypto->ctrl_done, RT_WAITING_FOREVER);
+
+ switch (input.status)
+ {
+ case VIRTIO_CRYPTO_OK:
+ break;
+
+ case VIRTIO_CRYPTO_INVSESS:
+ RT_ASSERT(0);
+ case VIRTIO_CRYPTO_ERR:
+ case VIRTIO_CRYPTO_KEY_REJECTED:
+ return -RT_ERROR;
+
+ case VIRTIO_CRYPTO_BADMSG:
+ return -RT_EINVAL;
+
+ case VIRTIO_CRYPTO_NOTSUPP:
+ return -RT_ENOSYS;
+
+ case VIRTIO_CRYPTO_NOSPC:
+ return -RT_EEMPTY;
+ }
+
+ vctx->session_id = input.session_id;
+ vctx->data_vq = data_vq;
+
+ return RT_EOK;
+}
+
+static void virtio_crypto_symmetric_destroy_session(
+ struct hwcrypto_symmetric *symmetric_ctx)
+{
+ rt_ubase_t level;
+ struct rt_virtqueue *ctrl_vq;
+ struct virtio_crypto_inhdr inhdr;
+ struct virtio_crypto_op_ctrl_req ctrl;
+ struct virtio_crypto_destroy_session_req *destroy_session;
+ struct virtio_crypto *vcrypto = raw_to_virtio_crypto(symmetric_ctx);
+ struct virtio_crypto_symmetric_contex *vctx = symmetric_ctx->parent.contex;
+
+ ctrl_vq = vcrypto->ctrl_vq;
+ inhdr.status = VIRTIO_CRYPTO_ERR;
+
+ /* Pad ctrl header */
+ ctrl.header.opcode = rt_cpu_to_le32(VIRTIO_CRYPTO_CIPHER_DESTROY_SESSION);
+ ctrl.header.queue_id = vctx->data_vq->index;
+
+ destroy_session = &ctrl.destroy_session;
+ destroy_session->session_id = rt_cpu_to_le64(vctx->session_id);
+
+ rt_virtqueue_wait_prepare(ctrl_vq, 2);
+
+ level = rt_spin_lock_irqsave(&vcrypto->ctrl_lock);
+
+ rt_virtqueue_add_outbuf(ctrl_vq, &ctrl, sizeof(ctrl));
+ rt_virtqueue_add_inbuf(ctrl_vq, &inhdr.status, sizeof(inhdr.status));
+
+ rt_virtqueue_kick(ctrl_vq);
+
+ rt_spin_unlock_irqrestore(&vcrypto->ctrl_lock, level);
+
+ rt_completion_wait(&vcrypto->ctrl_done, RT_WAITING_FOREVER);
+
+ if (inhdr.status != VIRTIO_CRYPTO_OK)
+ {
+ LOG_E("%s fail status = %d", __func__, inhdr.status);
+ }
+}
+
+static rt_err_t virtio_crypto_symmetric_crypt(
+ struct hwcrypto_symmetric *symmetric_ctx,
+ struct hwcrypto_symmetric_info *symmetric_info)
+{
+ rt_err_t err;
+ rt_ubase_t level;
+ struct rt_virtqueue *data_vq;
+ struct virtio_crypto_inhdr inhdr;
+ struct virtio_crypto_op_data_req data;
+ struct virtio_crypto *vcrypto = raw_to_virtio_crypto(symmetric_ctx);
+ struct virtio_crypto_symmetric_contex *vctx = symmetric_ctx->parent.contex;
+
+ if (!(vcrypto->status & VIRTIO_CRYPTO_S_HW_READY))
+ {
+ LOG_D("%s: to %s %s is not ready",
+ rt_dm_dev_get_name(&vcrypto->parent.parent), "symmetric", "crypt");
+
+ return -RT_EIO;
+ }
+
+ if (symmetric_info->mode == HWCRYPTO_MODE_ENCRYPT)
+ {
+ err = virtio_crypto_symmetric_create_session(symmetric_ctx, RT_TRUE);
+ }
+ else if (symmetric_info->mode == HWCRYPTO_MODE_DECRYPT)
+ {
+ err = virtio_crypto_symmetric_create_session(symmetric_ctx, RT_FALSE);
+ }
+ else
+ {
+ err = -RT_ENOSYS;
+ }
+
+ if (err)
+ {
+ return err;
+ }
+
+ vctx = symmetric_ctx->parent.contex;
+ data_vq = vctx->data_vq;
+
+ data.header.session_id = rt_cpu_to_le64(vctx->session_id);
+ if (symmetric_info->mode == HWCRYPTO_MODE_ENCRYPT)
+ {
+ data.header.opcode = rt_cpu_to_le32(VIRTIO_CRYPTO_CIPHER_ENCRYPT);
+ }
+ else if (symmetric_info->mode == HWCRYPTO_MODE_DECRYPT)
+ {
+ data.header.opcode = rt_cpu_to_le32(VIRTIO_CRYPTO_CIPHER_DECRYPT);
+ }
+
+ if (!symmetric_ctx->iv_len)
+ {
+ symmetric_ctx->iv_len = sizeof(symmetric_ctx->iv);
+ rt_memset(symmetric_ctx->iv, 0, symmetric_ctx->iv_len);
+ }
+
+ data.sym_req.op_type = rt_cpu_to_le32(VIRTIO_CRYPTO_SYM_OP_CIPHER);
+ data.sym_req.cipher.para.iv_len = rt_cpu_to_le32(symmetric_ctx->iv_len);
+ data.sym_req.cipher.para.src_data_len = rt_cpu_to_le32(symmetric_info->length);
+ data.sym_req.cipher.para.dst_data_len = rt_cpu_to_le32(symmetric_info->length);
+
+ inhdr.status = VIRTIO_CRYPTO_ERR;
+
+ rt_virtqueue_wait_prepare(data_vq, 5);
+
+ level = rt_spin_lock_irqsave(&vcrypto->data_lock[data_vq->index]);
+
+ /* Outhdr */
+ rt_virtqueue_add_outbuf(data_vq, &data, sizeof(data));
+
+ rt_virtqueue_add_outbuf(data_vq,
+ &symmetric_ctx->iv[symmetric_ctx->iv_off], symmetric_ctx->iv_len);
+
+ /* Source data */
+ rt_virtqueue_add_outbuf(data_vq, (void *)symmetric_info->in, symmetric_info->length);
+
+ /* Destination data */
+ rt_virtqueue_add_inbuf(data_vq, symmetric_info->out, symmetric_info->length);
+
+ rt_virtqueue_add_inbuf(data_vq, &inhdr.status, sizeof(inhdr.status));
+
+ rt_virtqueue_kick(data_vq);
+
+ rt_spin_unlock_irqrestore(&vcrypto->data_lock[data_vq->index], level);
+
+ rt_completion_wait(&vcrypto->data_done[data_vq->index], RT_WAITING_FOREVER);
+
+ switch (inhdr.status)
+ {
+ case VIRTIO_CRYPTO_OK:
+ err = RT_EOK;
+ break;
+
+ case VIRTIO_CRYPTO_INVSESS:
+ err = -RT_EINVAL;
+ break;
+
+ case VIRTIO_CRYPTO_ERR:
+ case VIRTIO_CRYPTO_KEY_REJECTED:
+ err = -RT_ERROR;
+ break;
+
+ case VIRTIO_CRYPTO_BADMSG:
+ err = -RT_EINVAL;
+ break;
+
+ case VIRTIO_CRYPTO_NOTSUPP:
+ err = -RT_ENOSYS;
+ break;
+
+ case VIRTIO_CRYPTO_NOSPC:
+ err = -RT_EEMPTY;
+ break;
+ }
+
+ virtio_crypto_symmetric_destroy_session(symmetric_ctx);
+
+ return err;
+}
+
+static const struct hwcrypto_symmetric_ops virtio_crypto_symmetric_ops =
+{
+ .crypt = virtio_crypto_symmetric_crypt,
+};
+
+static rt_err_t virtio_crypto_create(struct rt_hwcrypto_ctx *ctx)
+{
+ struct hwcrypto_symmetric *crypto_symmetric;
+
+ switch (ctx->type & HWCRYPTO_MAIN_TYPE_MASK)
+ {
+ case HWCRYPTO_TYPE_AES:
+ case HWCRYPTO_TYPE_DES:
+ case HWCRYPTO_TYPE_3DES:
+ case HWCRYPTO_TYPE_RC4:
+ ctx->contex = rt_calloc(1, sizeof(struct virtio_crypto_symmetric_contex));
+
+ if (!ctx->contex)
+ {
+ return -RT_ENOMEM;
+ }
+
+ crypto_symmetric = rt_container_of(ctx, struct hwcrypto_symmetric, parent);
+ crypto_symmetric->ops = &virtio_crypto_symmetric_ops;
+ break;
+
+ default:
+ return -RT_ENOSYS;
+ }
+
+ return RT_EOK;
+}
+
+static void virtio_crypto_destroy(struct rt_hwcrypto_ctx *ctx)
+{
+ if (!ctx->contex)
+ {
+ return;
+ }
+
+ switch (ctx->type & HWCRYPTO_MAIN_TYPE_MASK)
+ {
+ case HWCRYPTO_TYPE_AES:
+ case HWCRYPTO_TYPE_DES:
+ case HWCRYPTO_TYPE_3DES:
+ case HWCRYPTO_TYPE_RC4:
+ rt_free(ctx->contex);
+ break;
+ }
+}
+
+static rt_err_t virtio_crypto_copy(struct rt_hwcrypto_ctx *des,
+ const struct rt_hwcrypto_ctx *src)
+{
+ rt_err_t err = RT_EOK;
+
+ switch (src->type & HWCRYPTO_MAIN_TYPE_MASK)
+ {
+ case HWCRYPTO_TYPE_AES:
+ case HWCRYPTO_TYPE_DES:
+ case HWCRYPTO_TYPE_3DES:
+ case HWCRYPTO_TYPE_RC4:
+ break;
+
+ default:
+ err = -RT_ENOSYS;
+ break;
+ }
+
+ return err;
+}
+
+static void virtio_crypto_reset(struct rt_hwcrypto_ctx *ctx)
+{
+}
+
+static const struct rt_hwcrypto_ops virtio_crypto_ops =
+{
+ .create = virtio_crypto_create,
+ .destroy = virtio_crypto_destroy,
+ .copy = virtio_crypto_copy,
+ .reset = virtio_crypto_reset,
+};
+
+static void virtio_crypto_data_done(struct rt_virtqueue *vq)
+{
+ rt_ubase_t level;
+ struct virtio_crypto *vcrypto = vq->vdev->priv;
+
+ level = rt_spin_lock_irqsave(&vcrypto->data_lock[vq->index]);
+
+ rt_virtqueue_read_buf(vq, RT_NULL);
+ rt_completion_done(&vcrypto->data_done[vq->index]);
+
+ rt_spin_unlock_irqrestore(&vcrypto->data_lock[vq->index], level);
+}
+
+static void virtio_crypto_ctrl_done(struct rt_virtqueue *vq)
+{
+ rt_ubase_t level;
+ struct virtio_crypto *vcrypto = vq->vdev->priv;
+
+ level = rt_spin_lock_irqsave(&vcrypto->ctrl_lock);
+
+ rt_virtqueue_read_buf(vq, RT_NULL);
+ rt_completion_done(&vcrypto->ctrl_done);
+
+ rt_spin_unlock_irqrestore(&vcrypto->ctrl_lock, level);
+}
+
+static void virtio_crypto_config_changed(struct rt_virtio_device *vdev)
+{
+ rt_uint32_t status;
+ struct virtio_crypto *vcrypto = vdev->parent.user_data;
+
+ rt_virtio_read_config(vdev, struct virtio_crypto_config, status, &status);
+
+ if (status & (~VIRTIO_CRYPTO_S_HW_READY))
+ {
+ LOG_E("%s: Unknown status bits = 0x%x",
+ rt_dm_dev_get_name(&vdev->parent), status);
+
+ RT_ASSERT(0);
+ return;
+ }
+
+ if (vcrypto->status != status)
+ {
+ /* Change status */
+ vcrypto->status = status;
+ }
+}
+
+static rt_err_t virtio_crypto_vq_init(struct virtio_crypto *vcrypto)
+{
+ rt_err_t err;
+ rt_size_t vqs_nr;
+ const char **names = RT_NULL;
+ rt_virtqueue_callback *cbs = RT_NULL;
+
+ vqs_nr = vcrypto->max_data_queues + 1;
+
+ vcrypto->vqs = rt_calloc(vqs_nr, sizeof(*vcrypto->vqs));
+
+ if (!vcrypto->vqs)
+ {
+ return -RT_ENOMEM;
+ }
+
+ if (!(names = rt_malloc(sizeof(*names) * vqs_nr)))
+ {
+ return -RT_ENOMEM;
+ }
+
+ if (!(cbs = rt_malloc(sizeof(*cbs) * vqs_nr)))
+ {
+ err = -RT_ENOMEM;
+ goto _out_free;
+ }
+
+ vcrypto->data_lock = rt_malloc(sizeof(vcrypto->data_lock[0]) *
+ vcrypto->max_data_queues);
+
+ if (!vcrypto->data_lock)
+ {
+ err = -RT_ENOMEM;
+ goto _out_free;
+ }
+
+ vcrypto->data_done = rt_malloc(sizeof(vcrypto->data_done[0]) *
+ vcrypto->max_data_queues);
+
+ if (!vcrypto->data_done)
+ {
+ err = -RT_ENOMEM;
+ goto _out_free;
+ }
+
+ for (int i = 0; i < vcrypto->max_data_queues; ++i)
+ {
+ names[i] = "data";
+ cbs[i] = &virtio_crypto_data_done;
+
+ rt_spin_lock_init(&vcrypto->data_lock[i]);
+ rt_completion_init(&vcrypto->data_done[i]);
+ }
+
+ names[vqs_nr - 1] = "ctrl";
+ cbs[vqs_nr - 1] = &virtio_crypto_ctrl_done;
+
+ if ((err = rt_virtio_virtqueue_install(vcrypto->vdev, vqs_nr,
+ vcrypto->vqs, names, cbs)))
+ {
+ goto _out_free;
+ }
+
+ vcrypto->ctrl_vq = vcrypto->vqs[vcrypto->max_data_queues];
+
+_out_free:
+ if (names)
+ {
+ rt_free(names);
+ }
+ if (cbs)
+ {
+ rt_free(cbs);
+ }
+
+ return err;
+}
+
+static void virtio_crypto_vq_finit(struct virtio_crypto *vcrypto)
+{
+ if (vcrypto->vqs)
+ {
+ if (vcrypto->vqs[0])
+ {
+ rt_virtio_virtqueue_release(vcrypto->vdev);
+ }
+
+ rt_free(vcrypto->vqs);
+ }
+
+ if (vcrypto->data_lock)
+ {
+ rt_free(vcrypto->data_lock);
+ }
+
+ if (vcrypto->data_done)
+ {
+ rt_free(vcrypto->data_done);
+ }
+}
+
+static rt_err_t virtio_crypto_probe(struct rt_virtio_device *vdev)
+{
+ rt_err_t err;
+ struct virtio_crypto *vcrypto = rt_calloc(1, sizeof(*vcrypto));
+
+ if (!vcrypto)
+ {
+ return -RT_ENOMEM;
+ }
+
+ vdev->priv = vcrypto;
+ vcrypto->vdev = vdev;
+ vdev->parent.user_data = vcrypto;
+
+ rt_virtio_read_config(vdev, struct virtio_crypto_config, max_dataqueues,
+ &vcrypto->max_data_queues);
+
+ if (vcrypto->max_data_queues > RT_CPUS_NR)
+ {
+ vcrypto->max_data_queues = RT_CPUS_NR;
+ }
+ else
+ {
+ vcrypto->max_data_queues = 1;
+ }
+
+ rt_virtio_read_config(vdev, struct virtio_crypto_config, crypto_services,
+ &vcrypto->services);
+ rt_virtio_read_config(vdev, struct virtio_crypto_config, max_size,
+ &vcrypto->max_req_size);
+ rt_virtio_read_config(vdev, struct virtio_crypto_config, max_cipher_key_len,
+ &vcrypto->max_cipher_key_len);
+ rt_virtio_read_config(vdev, struct virtio_crypto_config, max_auth_key_len,
+ &vcrypto->max_auth_key_len);
+
+ if ((err = virtio_crypto_vq_init(vcrypto)))
+ {
+ goto _fail;
+ }
+
+ rt_spin_lock_init(&vcrypto->ctrl_lock);
+ rt_completion_init(&vcrypto->ctrl_done);
+
+ vcrypto->parent.ops = &virtio_crypto_ops;
+ vcrypto->parent.id = ((rt_uint64_t)vdev->id.vendor << 32) | vdev->id.device;
+
+ virtio_crypto_config_changed(vdev);
+
+ if ((err = rt_hwcrypto_register(&vcrypto->parent, RT_HWCRYPTO_DEFAULT_NAME)))
+ {
+ goto _fail;
+ }
+
+ return RT_EOK;
+
+_fail:
+ virtio_crypto_vq_finit(vcrypto);
+ rt_free(vcrypto);
+
+ return err;
+}
+
+static rt_err_t virtio_crypto_remove(struct rt_virtio_device *vdev)
+{
+ struct virtio_crypto *vcrypto = vdev->parent.user_data;
+
+ rt_device_unregister(&vcrypto->parent.parent);
+
+ virtio_crypto_vq_finit(vcrypto);
+ rt_free(vcrypto);
+
+ return RT_EOK;
+}
+
+static const struct rt_virtio_device_id virtio_crypto_ids[] =
+{
+ { VIRTIO_DEVICE_ID_CRYPTO, VIRTIO_DEVICE_ANY_ID },
+ { /* sentinel */ }
+};
+
+static struct rt_virtio_driver virtio_crypto_driver =
+{
+ .ids = virtio_crypto_ids,
+ .features =
+ RT_BIT(VIRTIO_F_ANY_LAYOUT),
+
+ .probe = virtio_crypto_probe,
+ .remove = virtio_crypto_remove,
+ .config_changed = virtio_crypto_config_changed,
+};
+RT_VIRTIO_DRIVER_EXPORT(virtio_crypto_driver);
diff --git a/components/drivers/virtio/virtio-gpu.c b/components/drivers/virtio/virtio-gpu.c
new file mode 100644
index 0000000000..e090730f49
--- /dev/null
+++ b/components/drivers/virtio/virtio-gpu.c
@@ -0,0 +1,1021 @@
+/*
+ * Copyright (c) 2006-2023, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date Author Notes
+ * 2021-11-11 GuEe-GUI the first version
+ * 2023-02-25 GuEe-GUI using virtio dm
+ */
+
+#include <rthw.h>
+#include <rtthread.h>
+#include <rtdevice.h>
+
+#define DBG_TAG "virtio.dev.gpu"
+#define DBG_LVL DBG_INFO
+#include <rtdbg.h>
+
+#include <mmu.h>
+#include <cpuport.h>
+#include "virtio_internal.h"
+#include "virtio_config/virtio-gpu.h"
+
+#define CTRL_QUEUE 0
+#define CURSOR_QUEUE 1
+
+struct virtio_gpu
+{
+ struct rt_graphic_device parent;
+ struct rt_virtio_device *vdev;
+
+ struct rt_virtqueue *vqs[2];
+
+ rt_bool_t vsync;
+ rt_uint32_t width;
+ rt_uint32_t height;
+ rt_uint32_t pmode_id;
+ rt_uint32_t num_scanouts;
+ rt_uint32_t resource_id;
+#define PRIMARY_PLANE_RESOURCE_ID 1
+#define CURSOR_PLANE_RESOURCE_ID 2
+
+ struct rt_work event_work;
+ struct rt_completion done;
+
+#define CURSOR_WIDTH 64
+#define CURSOR_HEIGHT 64
+ rt_uint8_t *cursor;
+};
+
+#define raw_to_virtio_gpu(raw) rt_container_of(raw, struct virtio_gpu, parent)
+
+static void virtio_gpu_ctrl_send_command(struct virtio_gpu *vgpu,
+ const void *cmd, rt_size_t cmd_len, void *res, rt_size_t res_len)
+{
+ struct rt_virtqueue *vq;
+
+ vq = vgpu->vqs[CTRL_QUEUE];
+
+ rt_virtqueue_wait_prepare(vq, 2);
+
+ rt_virtqueue_add_outbuf(vq, (void *)cmd, cmd_len);
+ rt_virtqueue_add_inbuf(vq, res, res_len);
+
+ rt_virtqueue_kick(vq);
+
+ while (!rt_virtqueue_read_buf(vq, RT_NULL))
+ {
+ rt_hw_cpu_relax();
+ }
+}
+
+static void virtio_gpu_cursor_send_command(struct virtio_gpu *vgpu,
+ const void *cmd, rt_size_t cmd_len)
+{
+ struct rt_virtqueue *vq;
+
+ vq = vgpu->vqs[CURSOR_QUEUE];
+
+ rt_virtqueue_wait_prepare(vq, 1);
+
+ rt_virtqueue_add_outbuf(vq, (void *)cmd, cmd_len);
+
+ rt_virtqueue_kick(vq);
+
+ while (!rt_virtqueue_read_buf(vq, RT_NULL))
+ {
+ rt_hw_cpu_relax();
+ }
+}
+
+static rt_uint32_t virtio_gpu_next_resource_id(struct virtio_gpu *vgpu)
+{
+ rt_uint32_t last_resource_id = vgpu->resource_id++;
+
+ while (last_resource_id != vgpu->resource_id)
+ {
+ if (vgpu->resource_id &&
+ vgpu->resource_id == PRIMARY_PLANE_RESOURCE_ID &&
+ vgpu->resource_id == CURSOR_PLANE_RESOURCE_ID)
+ {
+ return vgpu->resource_id;
+ }
+
+ ++vgpu->resource_id;
+ }
+
+ return 0;
+}
+
+static rt_err_t virtio_gpu_create_2d_resource(struct virtio_gpu *vgpu,
+ enum virtio_gpu_formats format, rt_uint32_t resource_id,
+ rt_uint32_t width, rt_uint32_t height)
+{
+ struct virtio_gpu_ctrl_hdr res;
+ struct virtio_gpu_resource_create_2d req;
+
+ req.hdr.type = rt_cpu_to_le32(VIRTIO_GPU_CMD_RESOURCE_CREATE_2D);
+ req.resource_id = rt_cpu_to_le32(resource_id);
+ req.format = rt_cpu_to_le32(format);
+ req.width = rt_cpu_to_le32(width);
+ req.height = rt_cpu_to_le32(height);
+
+ virtio_gpu_ctrl_send_command(vgpu, &req, sizeof(req), &res, sizeof(res));
+
+ return res.type == rt_cpu_to_le32(VIRTIO_GPU_RESP_OK_NODATA) ? RT_EOK : -RT_ERROR;
+}
+
+static rt_err_t virtio_gpu_unref_resource(struct virtio_gpu *vgpu,
+ rt_uint32_t resource_id)
+{
+ struct virtio_gpu_ctrl_hdr res;
+ struct virtio_gpu_resource_unref req;
+
+ rt_memset(&req, 0, sizeof(req));
+
+ req.hdr.type = rt_cpu_to_le32(VIRTIO_GPU_CMD_RESOURCE_UNREF);
+ req.resource_id = rt_cpu_to_le32(resource_id);
+
+ virtio_gpu_ctrl_send_command(vgpu, &req, sizeof(req), &res, sizeof(res));
+
+ return res.type == rt_cpu_to_le32(VIRTIO_GPU_RESP_OK_NODATA) ? RT_EOK : -RT_ERROR;
+}
+
+static rt_err_t virtio_gpu_attach_backing_resource(struct virtio_gpu *vgpu,
+ rt_uint32_t resource_id, void *buffer, rt_size_t size)
+{
+ struct virtio_gpu_ctrl_hdr res;
+ struct
+ {
+ struct virtio_gpu_resource_attach_backing req;
+ struct virtio_gpu_mem_entry mem;
+ } req;
+
+ rt_memset(&req, 0, sizeof(req));
+
+ req.req.hdr.type = rt_cpu_to_le32(VIRTIO_GPU_CMD_RESOURCE_ATTACH_BACKING);
+ req.req.resource_id = rt_cpu_to_le32(resource_id);
+ req.req.nr_entries = rt_cpu_to_le32(1);
+
+ req.mem.addr = rt_cpu_to_le64((rt_ubase_t)rt_kmem_v2p(buffer));
+ req.mem.length = rt_cpu_to_le32(size);
+
+ virtio_gpu_ctrl_send_command(vgpu, &req, sizeof(req), &res, sizeof(res));
+
+ return res.type == rt_cpu_to_le32(VIRTIO_GPU_RESP_OK_NODATA) ? RT_EOK : -RT_ERROR;
+}
+
+static rt_err_t virtio_gpu_detach_backing_resource(struct virtio_gpu *vgpu,
+ rt_uint32_t resource_id)
+{
+ struct virtio_gpu_ctrl_hdr res;
+ struct virtio_gpu_resource_detach_backing req;
+
+ rt_memset(&req, 0, sizeof(req));
+
+ req.hdr.type = rt_cpu_to_le32(VIRTIO_GPU_CMD_RESOURCE_DETACH_BACKING);
+ req.resource_id = rt_cpu_to_le32(resource_id);
+
+ virtio_gpu_ctrl_send_command(vgpu, &req, sizeof(req), &res, sizeof(res));
+
+ return res.type == rt_cpu_to_le32(VIRTIO_GPU_RESP_OK_NODATA) ? RT_EOK : -RT_ERROR;
+}
+
+static rt_err_t virtio_gpu_set_scanout(struct virtio_gpu *vgpu,
+ rt_uint32_t scanout_id, rt_uint32_t resource_id,
+ rt_uint32_t width, rt_uint32_t height)
+{
+ struct virtio_gpu_ctrl_hdr res;
+ struct virtio_gpu_set_scanout req;
+
+ rt_memset(&req, 0, sizeof(req));
+
+ req.hdr.type = rt_cpu_to_le32(VIRTIO_GPU_CMD_SET_SCANOUT);
+ req.r.width = rt_cpu_to_le32(width);
+ req.r.height = rt_cpu_to_le32(height);
+ req.scanout_id = rt_cpu_to_le32(scanout_id);
+ req.resource_id = rt_cpu_to_le32(resource_id);
+
+ virtio_gpu_ctrl_send_command(vgpu, &req, sizeof(req), &res, sizeof(res));
+
+ return res.type == rt_cpu_to_le32(VIRTIO_GPU_RESP_OK_NODATA) ? RT_EOK : -RT_ERROR;
+}
+
+static rt_err_t virtio_gpu_flush_resource(struct virtio_gpu *vgpu,
+ rt_uint32_t resource_id,
+ rt_uint32_t x, rt_uint32_t y, rt_uint32_t width, rt_uint32_t height)
+{
+ struct virtio_gpu_ctrl_hdr res;
+ struct virtio_gpu_resource_flush req;
+
+ rt_memset(&req, 0, sizeof(req));
+
+ req.hdr.type = rt_cpu_to_le32(VIRTIO_GPU_CMD_RESOURCE_FLUSH);
+ req.r.x = rt_cpu_to_le32(x);
+ req.r.y = rt_cpu_to_le32(y);
+ req.r.width = rt_cpu_to_le32(width);
+ req.r.height = rt_cpu_to_le32(height);
+ req.resource_id = rt_cpu_to_le32(resource_id);
+
+ virtio_gpu_ctrl_send_command(vgpu, &req, sizeof(req), &res, sizeof(res));
+
+ return res.type == rt_cpu_to_le32(VIRTIO_GPU_RESP_OK_NODATA) ? RT_EOK : -RT_ERROR;
+}
+
+static rt_err_t virtio_gpu_transfer_to_host_2d(struct virtio_gpu *vgpu,
+ rt_uint32_t resource_id,
+ rt_uint32_t x, rt_uint32_t y, rt_uint32_t width, rt_uint32_t height,
+ rt_uint64_t offset)
+{
+ struct virtio_gpu_ctrl_hdr res;
+ struct virtio_gpu_transfer_to_host_2d req;
+
+ rt_memset(&req, 0, sizeof(req));
+
+ req.hdr.type = rt_cpu_to_le32(VIRTIO_GPU_CMD_TRANSFER_TO_HOST_2D);
+ req.r.x = rt_cpu_to_le32(x);
+ req.r.y = rt_cpu_to_le32(y);
+ req.r.width = rt_cpu_to_le32(width);
+ req.r.height = rt_cpu_to_le32(height);
+ req.offset = rt_cpu_to_le64(offset);
+ req.resource_id = rt_cpu_to_le32(resource_id);
+
+ virtio_gpu_ctrl_send_command(vgpu, &req, sizeof(req), &res, sizeof(res));
+
+ return res.type == rt_cpu_to_le32(VIRTIO_GPU_RESP_OK_NODATA) ? RT_EOK : -RT_ERROR;
+}
+
+static rt_err_t virtio_gpu_update_cursor(struct virtio_gpu *vgpu,
+ rt_uint32_t scanout_id, rt_uint32_t resource_id,
+ rt_uint32_t hot_x, rt_uint32_t hot_y)
+{
+ struct virtio_gpu_update_cursor req;
+
+ rt_memset(&req, 0, sizeof(req));
+
+ req.hdr.type = rt_cpu_to_le32(VIRTIO_GPU_CMD_UPDATE_CURSOR);
+ req.pos.scanout_id = rt_cpu_to_le32(scanout_id);
+ req.resource_id = rt_cpu_to_le32(resource_id);
+ req.hot_x = rt_cpu_to_le32(hot_x);
+ req.hot_y = rt_cpu_to_le32(hot_y);
+
+ virtio_gpu_cursor_send_command(vgpu, &req, sizeof(req));
+
+ return RT_EOK;
+}
+
+static rt_err_t virtio_gpu_cursor_move(struct virtio_gpu *vgpu,
+ rt_uint32_t scanout_id, rt_uint32_t resource_id,
+ rt_uint32_t x, rt_uint32_t y)
+{
+ struct virtio_gpu_update_cursor req;
+
+ rt_memset(&req, 0, sizeof(req));
+
+ req.hdr.type = rt_cpu_to_le32(VIRTIO_GPU_CMD_MOVE_CURSOR);
+ req.pos.scanout_id = rt_cpu_to_le32(scanout_id);
+ req.pos.x = rt_cpu_to_le32(x);
+ req.pos.y = rt_cpu_to_le32(y);
+ req.resource_id = rt_cpu_to_le32(resource_id);
+
+ virtio_gpu_cursor_send_command(vgpu, &req, sizeof(req));
+
+ return RT_EOK;
+}
+
+static rt_err_t virtio_gpu_get_edid(struct virtio_gpu *vgpu)
+{
+ rt_err_t err;
+ struct virtio_gpu_cmd_get_edid req;
+ struct virtio_gpu_resp_edid *res = rt_malloc(sizeof(*res));
+
+ if (!res)
+ {
+ return -RT_ENOMEM;
+ }
+
+ rt_memset(&req, 0, sizeof(req));
+ req.hdr.type = rt_cpu_to_le32(VIRTIO_GPU_CMD_GET_EDID);
+ req.scanout = rt_cpu_to_le32(vgpu->pmode_id);
+
+ virtio_gpu_ctrl_send_command(vgpu, &req, sizeof(req), res, sizeof(*res));
+
+ if (res->hdr.type == rt_cpu_to_le32(VIRTIO_GPU_RESP_OK_EDID))
+ {
+ rt_memcpy(&vgpu->parent.edid, res->edid,
+ rt_min_t(rt_size_t, sizeof(vgpu->parent.edid), res->size));
+ err = RT_EOK;
+ }
+ else
+ {
+ err = -RT_EIO;
+ }
+
+ rt_free(res);
+
+ return err;
+}
+
+static rt_err_t virtio_gpu_get_display_info(struct virtio_gpu *vgpu)
+{
+ struct virtio_gpu_ctrl_hdr req;
+ struct virtio_gpu_resp_display_info info;
+
+ rt_memset(&req, 0, sizeof(req));
+ req.type = rt_cpu_to_le32(VIRTIO_GPU_CMD_GET_DISPLAY_INFO);
+
+ virtio_gpu_ctrl_send_command(vgpu, &req, sizeof(req), &info, sizeof(info));
+
+ if (info.hdr.type != rt_cpu_to_le32(VIRTIO_GPU_RESP_OK_DISPLAY_INFO))
+ {
+ return -RT_EIO;
+ }
+
+ for (int i = 0; i < vgpu->num_scanouts; ++i)
+ {
+ if (info.pmodes[i].enabled)
+ {
+ struct virtio_gpu_display_one *pmode = &info.pmodes[i];
+
+ vgpu->pmode_id = i;
+ vgpu->width = pmode->r.width;
+ vgpu->height = pmode->r.height;
+ break;
+ }
+ }
+
+ return RT_EOK;
+}
+
+static rt_err_t virtio_gpu_resize(struct virtio_gpu *vgpu)
+{
+ rt_err_t err = RT_EOK;
+
+ if (rt_virtio_has_feature(vgpu->vdev, VIRTIO_GPU_F_EDID))
+ {
+ err = virtio_gpu_get_edid(vgpu);
+ }
+
+ if (!err)
+ {
+ err = virtio_gpu_get_display_info(vgpu);
+ }
+
+ return err;
+}
+
+static enum virtio_gpu_formats virtio_gpu_raw_modes[] =
+{
+ VIRTIO_GPU_FORMAT_B8G8R8A8_UNORM,
+ VIRTIO_GPU_FORMAT_R8G8B8A8_UNORM,
+};
+
+static rt_uint32_t virtio_gpu_modes[] =
+{
+ RTGRAPHIC_PIXEL_FORMAT_ARGB888,
+ RTGRAPHIC_PIXEL_FORMAT_ABGR888,
+};
+
+typedef char __assert_virtio_gpu_modes[-(RT_ARRAY_SIZE(virtio_gpu_raw_modes) % RT_ARRAY_SIZE(virtio_gpu_modes))];
+
+static enum virtio_gpu_formats virtio_gpu_mode(rt_uint32_t mode)
+{
+ for (int i = 0; i < RT_ARRAY_SIZE(virtio_gpu_modes); ++i)
+ {
+ if (virtio_gpu_modes[i] == mode)
+ {
+ return virtio_gpu_raw_modes[i];
+ }
+ }
+
+ LOG_E("BUG of the graphic framework");
+ RT_ASSERT(0);
+ return -1;
+}
+
+static rt_err_t virtio_gpu_cursor_plane_fb_update(struct rt_graphic_plane *plane,
+ struct rt_device_rect_info *rect)
+{
+ rt_err_t err;
+ rt_uint32_t resource_id;
+ struct virtio_gpu *vgpu = raw_to_virtio_gpu(plane->graphic);
+
+ if (!rect->width && !rect->height)
+ {
+ return RT_EOK;
+ }
+
+ if (rect->width > CURSOR_WIDTH || rect->height > CURSOR_HEIGHT)
+ {
+ return -RT_EINVAL;
+ }
+
+ resource_id = CURSOR_PLANE_RESOURCE_ID;
+
+ err = virtio_gpu_transfer_to_host_2d(vgpu, resource_id,
+ rect->x, rect->y, rect->width, rect->height, 0);
+
+ if (!err)
+ {
+ err = virtio_gpu_flush_resource(vgpu, resource_id,
+ rect->x, rect->y, rect->width, rect->height);
+ }
+
+ virtio_gpu_update_cursor(vgpu, vgpu->pmode_id, resource_id, rect->x, rect->y);
+ virtio_gpu_cursor_move(vgpu, vgpu->pmode_id, resource_id, rect->x, rect->y);
+
+ return err;
+}
+
+static rt_err_t virtio_gpu_cursor_plane_fb_remap(struct rt_graphic_plane *plane,
+ rt_uint32_t mode, struct rt_device_rect_info *rect)
+{
+ rt_err_t err;
+ rt_uint32_t framebuffer_len, bits_per_pixel, line_length, resource_id;
+ struct virtio_gpu *vgpu = raw_to_virtio_gpu(plane->graphic);
+
+ if (rect->width > CURSOR_WIDTH || rect->height > CURSOR_HEIGHT)
+ {
+ return -RT_EINVAL;
+ }
+
+ resource_id = CURSOR_PLANE_RESOURCE_ID;
+
+ err = virtio_gpu_create_2d_resource(vgpu, virtio_gpu_mode(mode),
+ resource_id, rect->width, rect->height);
+
+ if (err)
+ {
+ return err;
+ }
+
+ bits_per_pixel = rt_graphic_mode_bpp(mode);
+ line_length = rect->width * (bits_per_pixel / 8);
+
+ framebuffer_len = line_length * rect->height;
+
+ err = virtio_gpu_attach_backing_resource(vgpu, resource_id, vgpu->cursor, framebuffer_len);
+
+ if (err)
+ {
+ goto _unref_resource;
+ }
+
+ plane->line_length = line_length;
+ plane->bits_per_pixel = bits_per_pixel;
+
+ plane->framebuffer = vgpu->cursor;
+ plane->screen_len = framebuffer_len;
+ plane->framebuffer_len = framebuffer_len;
+
+ return RT_EOK;
+
+_unref_resource:
+ virtio_gpu_unref_resource(vgpu, resource_id);
+
+ return err;
+}
+
+static rt_err_t virtio_gpu_cursor_plane_fb_cleanup(struct rt_graphic_plane *plane)
+{
+ rt_uint32_t resource_id;
+ struct virtio_gpu *vgpu = raw_to_virtio_gpu(plane->graphic);
+
+ if (!plane->framebuffer)
+ {
+ return RT_EOK;
+ }
+
+ resource_id = CURSOR_PLANE_RESOURCE_ID;
+
+ virtio_gpu_detach_backing_resource(vgpu, resource_id);
+ virtio_gpu_unref_resource(vgpu, resource_id);
+
+ plane->framebuffer = RT_NULL;
+
+ return RT_EOK;
+}
+
+static const struct rt_graphic_plane_ops virtio_gpu_cursor_plane_ops =
+{
+ .update = virtio_gpu_cursor_plane_fb_update,
+ .fb_remap = virtio_gpu_cursor_plane_fb_remap,
+ .fb_cleanup = virtio_gpu_cursor_plane_fb_cleanup,
+};
+
+static rt_err_t virtio_gpu_primary_plane_fb_update(struct rt_graphic_plane *plane,
+ struct rt_device_rect_info *rect)
+{
+ rt_err_t err;
+ rt_uint32_t resource_id;
+ struct virtio_gpu *vgpu = raw_to_virtio_gpu(plane->graphic);
+
+ vgpu->vsync = RT_FALSE;
+ resource_id = PRIMARY_PLANE_RESOURCE_ID;
+
+ err = virtio_gpu_transfer_to_host_2d(vgpu, resource_id,
+ rect->x, rect->y, rect->width, rect->height, 0);
+
+ if (!err)
+ {
+ err = virtio_gpu_flush_resource(vgpu, resource_id,
+ rect->x, rect->y, rect->width, rect->height);
+ }
+ vgpu->vsync = RT_TRUE;
+
+ return err;
+}
+
+static rt_err_t virtio_gpu_primary_plane_fb_remap(struct rt_graphic_plane *plane,
+ rt_uint32_t mode, struct rt_device_rect_info *rect)
+{
+ rt_err_t err;
+ void *framebuffer;
+ rt_uint32_t framebuffer_len, bits_per_pixel, line_length, resource_id;
+ struct virtio_gpu *vgpu = raw_to_virtio_gpu(plane->graphic);
+
+ resource_id = PRIMARY_PLANE_RESOURCE_ID;
+ err = virtio_gpu_create_2d_resource(vgpu, virtio_gpu_mode(mode),
+ resource_id, rect->width, rect->height);
+
+ if (err)
+ {
+ return err;
+ }
+
+ bits_per_pixel = rt_graphic_mode_bpp(mode);
+ line_length = rect->width * (bits_per_pixel / 8);
+
+ framebuffer_len = line_length * rect->height;
+ framebuffer = rt_malloc_align(framebuffer_len, ARCH_PAGE_SIZE);
+
+ if (!framebuffer)
+ {
+ err = -RT_ENOMEM;
+ goto _unref_resource;
+ }
+
+ err = virtio_gpu_attach_backing_resource(vgpu, resource_id, framebuffer, framebuffer_len);
+
+ if (err)
+ {
+ goto _free_framebuffer;
+ }
+
+ err = virtio_gpu_set_scanout(vgpu, vgpu->pmode_id, resource_id,
+ rect->width, rect->height);
+
+ if (err)
+ {
+ goto _detach_backing;
+ }
+
+ plane->line_length = line_length;
+ plane->bits_per_pixel = bits_per_pixel;
+
+ plane->framebuffer = framebuffer;
+ plane->screen_len = framebuffer_len;
+ plane->framebuffer_len = framebuffer_len;
+
+ return RT_EOK;
+
+_detach_backing:
+ virtio_gpu_detach_backing_resource(vgpu, resource_id);
+
+_free_framebuffer:
+ rt_free_align(framebuffer);
+
+_unref_resource:
+ virtio_gpu_unref_resource(vgpu, resource_id);
+
+ return err;
+}
+
+static rt_err_t virtio_gpu_primary_plane_fb_cleanup(struct rt_graphic_plane *plane)
+{
+ rt_uint32_t resource_id;
+ struct virtio_gpu *vgpu = raw_to_virtio_gpu(plane->graphic);
+
+ if (!plane->framebuffer)
+ {
+ return RT_EOK;
+ }
+
+ resource_id = PRIMARY_PLANE_RESOURCE_ID;
+
+ virtio_gpu_detach_backing_resource(vgpu, resource_id);
+ virtio_gpu_unref_resource(vgpu, resource_id);
+ rt_free_align(plane->framebuffer);
+
+ plane->framebuffer = RT_NULL;
+
+ return RT_EOK;
+}
+
+static const struct rt_graphic_plane_ops virtio_gpu_primary_plane_ops =
+{
+ .update = virtio_gpu_primary_plane_fb_update,
+ .fb_remap = virtio_gpu_primary_plane_fb_remap,
+ .fb_cleanup = virtio_gpu_primary_plane_fb_cleanup,
+};
+
+static rt_err_t virtio_gpu_dpms_switch(struct rt_graphic_device *gdev, rt_uint32_t dpms)
+{
+ rt_uint32_t update_ms = 0;
+ struct virtio_gpu *vgpu = raw_to_virtio_gpu(gdev);
+
+ if (dpms == RT_GRAPHIC_DPMS_ON)
+ {
+ update_ms = RT_GRAPHIC_UPDATE_MS;
+ }
+
+ rt_graphic_device_update_auto(&vgpu->parent, update_ms);
+
+ return RT_EOK;
+}
+
+static rt_err_t virtio_gpu_wait_vsync(struct rt_graphic_device *gdev)
+{
+ struct virtio_gpu *vgpu = raw_to_virtio_gpu(gdev);
+
+ while (!vgpu->vsync)
+ {
+ rt_hw_cpu_relax();
+ }
+
+ return RT_EOK;
+}
+
+static rt_err_t virtio_gpu_virgl_control(struct rt_graphic_device *gdev, int cmd, void *args)
+{
+ rt_err_t err;
+ struct virtio_gpu *vgpu = raw_to_virtio_gpu(gdev);
+
+ switch (cmd)
+ {
+ case VIRTIO_GPU_CMD_GET_CAPSET_INFO:
+ {
+ struct virtio_gpu_get_capset_info req;
+ struct virtio_gpu_resp_capset_info *res = args;
+
+ rt_memcpy(&req, args, sizeof(req));
+
+ virtio_gpu_ctrl_send_command(vgpu, &req, sizeof(req), res, sizeof(*res));
+
+ err = res->hdr.type == rt_cpu_to_le32(VIRTIO_GPU_RESP_OK_CAPSET_INFO) ? RT_EOK : -RT_ERROR;
+ break;
+ }
+
+ case VIRTIO_GPU_CMD_GET_CAPSET:
+ {
+ struct virtio_gpu_get_capset req;
+ struct virtio_gpu_resp_capset *res = args;
+
+ rt_memcpy(&req, args, sizeof(req));
+
+ virtio_gpu_ctrl_send_command(vgpu, &req, sizeof(req), res, sizeof(*res));
+
+ err = res->hdr.type == rt_cpu_to_le32(VIRTIO_GPU_RESP_OK_CAPSET) ? RT_EOK : -RT_ERROR;
+ break;
+ }
+
+ case VIRTIO_GPU_CMD_CTX_CREATE:
+ {
+ struct virtio_gpu_ctrl_hdr res;
+ struct virtio_gpu_ctx_create *req = args;
+
+ virtio_gpu_ctrl_send_command(vgpu, req, sizeof(*req), &res, sizeof(res));
+
+ rt_memcpy(args, &res, sizeof(res));
+ err = res.type == rt_cpu_to_le32(VIRTIO_GPU_RESP_OK_NODATA) ? RT_EOK : -RT_ERROR;
+ break;
+ }
+
+ case VIRTIO_GPU_CMD_CTX_DESTROY:
+ {
+ struct virtio_gpu_ctrl_hdr res;
+ struct virtio_gpu_ctx_destroy *req = args;
+
+ virtio_gpu_ctrl_send_command(vgpu, req, sizeof(*req), &res, sizeof(res));
+
+ rt_memcpy(args, &res, sizeof(res));
+ err = res.type == rt_cpu_to_le32(VIRTIO_GPU_RESP_OK_NODATA) ? RT_EOK : -RT_ERROR;
+ break;
+ }
+
+ case VIRTIO_GPU_CMD_CTX_ATTACH_RESOURCE:
+ {
+ struct virtio_gpu_ctrl_hdr res;
+ struct virtio_gpu_ctx_resource *req = args;
+
+ virtio_gpu_ctrl_send_command(vgpu, req, sizeof(*req), &res, sizeof(res));
+
+ rt_memcpy(args, &res, sizeof(res));
+ err = res.type == rt_cpu_to_le32(VIRTIO_GPU_RESP_OK_NODATA) ? RT_EOK : -RT_ERROR;
+ break;
+ }
+
+ case VIRTIO_GPU_CMD_CTX_DETACH_RESOURCE:
+ {
+ struct virtio_gpu_ctrl_hdr res;
+ struct virtio_gpu_ctx_resource *req = args;
+
+ virtio_gpu_ctrl_send_command(vgpu, req, sizeof(*req), &res, sizeof(res));
+
+ rt_memcpy(args, &res, sizeof(res));
+ err = res.type == rt_cpu_to_le32(VIRTIO_GPU_RESP_OK_NODATA) ? RT_EOK : -RT_ERROR;
+ break;
+ }
+
+ case VIRTIO_GPU_CMD_RESOURCE_CREATE_3D:
+ {
+ struct virtio_gpu_ctrl_hdr res;
+ struct virtio_gpu_resource_create_3d *req = args;
+
+ /*
+ * Create a new resource id instead of user's. Because the
+ * `virtio_gpu_resource_create_3d` is base on the `virtio_gpu_ctrl_hdr`,
+ * user should pick the resource_id by res after request.
+ */
+ req->resource_id = virtio_gpu_next_resource_id(vgpu);
+
+ virtio_gpu_ctrl_send_command(vgpu, req, sizeof(*req), &res, sizeof(res));
+
+ rt_memcpy(args, &res, sizeof(res));
+ err = res.type == rt_cpu_to_le32(VIRTIO_GPU_RESP_OK_NODATA) ? RT_EOK : -RT_ERROR;
+ break;
+ }
+
+ case VIRTIO_GPU_CMD_TRANSFER_TO_HOST_3D:
+ {
+ struct virtio_gpu_ctrl_hdr res;
+ struct virtio_gpu_transfer_host_3d *req = args;
+
+ virtio_gpu_ctrl_send_command(vgpu, req, sizeof(*req), &res, sizeof(res));
+
+ rt_memcpy(args, &res, sizeof(res));
+ err = res.type == rt_cpu_to_le32(VIRTIO_GPU_RESP_OK_NODATA) ? RT_EOK : -RT_ERROR;
+ break;
+ }
+
+ case VIRTIO_GPU_CMD_TRANSFER_FROM_HOST_3D:
+ {
+ struct virtio_gpu_ctrl_hdr res;
+ struct virtio_gpu_transfer_host_3d *req = args;
+
+ virtio_gpu_ctrl_send_command(vgpu, req, sizeof(*req), &res, sizeof(res));
+
+ rt_memcpy(args, &res, sizeof(res));
+ err = res.type == rt_cpu_to_le32(VIRTIO_GPU_RESP_OK_NODATA) ? RT_EOK : -RT_ERROR;
+ break;
+ }
+
+ case VIRTIO_GPU_CMD_SUBMIT_3D:
+ {
+ struct virtio_gpu_ctrl_hdr res;
+ struct virtio_gpu_cmd_submit *req = args;
+
+ virtio_gpu_ctrl_send_command(vgpu, req, req->size, &res, sizeof(res));
+
+ rt_memcpy(args, &res, sizeof(res));
+ err = res.type == rt_cpu_to_le32(VIRTIO_GPU_RESP_OK_NODATA) ? RT_EOK : -RT_ERROR;
+ break;
+ }
+
+ default:
+ err = -RT_ENOSYS;
+ break;
+ }
+
+ return err;
+}
+
+static const struct rt_graphic_device_ops virtio_gpu_virgl_ops =
+{
+ .dpms_switch = virtio_gpu_dpms_switch,
+ .wait_vsync = virtio_gpu_wait_vsync,
+ .control = virtio_gpu_virgl_control,
+};
+
+static const struct rt_graphic_device_ops virtio_gpu_ops =
+{
+ .dpms_switch = virtio_gpu_dpms_switch,
+ .wait_vsync = virtio_gpu_wait_vsync,
+};
+
+static void virtio_gpu_event_work(struct rt_work *work, void *work_data)
+{
+ rt_uint32_t events_read, events_clear = 0;
+ struct virtio_gpu *vgpu = work_data;
+ struct rt_virtio_device *vdev = vgpu->vdev;
+
+ rt_virtio_read_config(vdev, struct virtio_gpu_config, events_read, &events_read);
+
+ if (events_read & VIRTIO_GPU_EVENT_DISPLAY)
+ {
+ rt_graphic_device_enter(&vgpu->parent);
+ virtio_gpu_resize(vgpu);
+ rt_graphic_device_leave(&vgpu->parent);
+
+ rt_graphic_device_hotplug_event(&vgpu->parent);
+
+ events_clear |= VIRTIO_GPU_EVENT_DISPLAY;
+ }
+
+ rt_virtio_write_config(vdev, struct virtio_gpu_config, events_clear, events_clear);
+}
+
+static void virtio_gpu_config_changed(struct rt_virtio_device *vdev)
+{
+ struct virtio_gpu *vgpu = vdev->priv;
+
+ rt_work_submit(&vgpu->event_work, 0);
+}
+
+static rt_err_t virtio_gpu_vq_init(struct virtio_gpu *vgpu)
+{
+ const char *names[] =
+ {
+ "ctrl",
+ "cursor"
+ };
+ rt_virtqueue_callback cbs[] =
+ {
+ RT_NULL, /* Just poll */
+ RT_NULL, /* Just poll */
+ };
+
+ return rt_virtio_virtqueue_install(vgpu->vdev,
+ RT_ARRAY_SIZE(names), vgpu->vqs, names, cbs);
+}
+
+static void virtio_gpu_vq_finit(struct virtio_gpu *vgpu)
+{
+ if (vgpu->vqs[0])
+ {
+ rt_virtio_virtqueue_release(vgpu->vdev);
+ }
+}
+
+static void virtio_gpu_unregister(struct virtio_gpu *vgpu)
+{
+ if (rt_virtio_has_feature(vgpu->vdev, VIRTIO_GPU_F_EDID))
+ {
+ rt_graphic_device_unregister(&vgpu->parent);
+ }
+ else
+ {
+ rt_graphic_device_simple_unregister(&vgpu->parent);
+ }
+}
+
+static rt_err_t virtio_gpu_probe(struct rt_virtio_device *vdev)
+{
+ rt_err_t err;
+ struct rt_graphic_plane *primary_plane, *cursor_plane;
+ struct virtio_gpu *vgpu = rt_calloc(1, sizeof(*vgpu));
+
+ if (!vgpu)
+ {
+ return -RT_ENOMEM;
+ }
+
+ vdev->priv = vgpu;
+ vgpu->vdev = vdev;
+
+ vgpu->cursor = rt_malloc_align(
+ CURSOR_WIDTH * CURSOR_HEIGHT * sizeof(rt_uint32_t), ARCH_PAGE_SIZE);
+
+ if (!vgpu->cursor)
+ {
+ err = -RT_ENOMEM;
+ goto _fail;
+ }
+
+ if ((err = virtio_gpu_vq_init(vgpu)))
+ {
+ goto _fail;
+ }
+
+ vgpu->vsync = RT_TRUE;
+
+ rt_virtio_read_config(vdev, struct virtio_gpu_config, num_scanouts, &vgpu->num_scanouts);
+
+ rt_work_init(&vgpu->event_work, virtio_gpu_event_work, vgpu);
+
+ virtio_gpu_resize(vgpu);
+
+ if (rt_virtio_has_feature(vdev, VIRTIO_GPU_F_VIRGL))
+ {
+ vgpu->parent.ops = &virtio_gpu_virgl_ops;
+ }
+ else
+ {
+ vgpu->parent.ops = &virtio_gpu_ops;
+ }
+
+ if (rt_virtio_has_feature(vdev, VIRTIO_GPU_F_EDID))
+ {
+ primary_plane = rt_graphic_device_alloc_plane(&vgpu->parent, 0,
+ &virtio_gpu_primary_plane_ops,
+ virtio_gpu_modes, RT_ARRAY_SIZE(virtio_gpu_modes),
+ RT_GRAPHIC_PLANE_TYPE_PRIMARY);
+
+ if (!primary_plane)
+ {
+ err = -RT_EIO;
+ goto _fail;
+ }
+
+ if ((err = rt_graphic_device_add_plane(&vgpu->parent, primary_plane)))
+ {
+ goto _free_primary_plane;
+ }
+
+ err = rt_graphic_device_register(&vgpu->parent);
+ }
+ else
+ {
+ err = rt_graphic_device_simple_register(&vgpu->parent,
+ vgpu->width, vgpu->height, 0, &virtio_gpu_primary_plane_ops,
+ virtio_gpu_modes, RT_ARRAY_SIZE(virtio_gpu_modes));
+ }
+
+ if (err)
+ {
+ goto _fail;
+ }
+
+ cursor_plane = rt_graphic_device_alloc_plane(&vgpu->parent, 0,
+ &virtio_gpu_cursor_plane_ops,
+ virtio_gpu_modes, RT_ARRAY_SIZE(virtio_gpu_modes),
+ RT_GRAPHIC_PLANE_TYPE_CURSOR);
+
+ if (!cursor_plane)
+ {
+ err = -RT_EIO;
+ goto _fail;
+ }
+
+ if ((err = rt_graphic_device_add_plane(&vgpu->parent, cursor_plane)))
+ {
+ goto _free_cursor_plane;
+ }
+
+ cursor_plane->width = CURSOR_WIDTH;
+ cursor_plane->height = CURSOR_HEIGHT;
+
+ return RT_EOK;
+
+_free_cursor_plane:
+ virtio_gpu_unregister(vgpu);
+ rt_graphic_device_free_plane(cursor_plane);
+
+_free_primary_plane:
+ rt_graphic_device_free_plane(primary_plane);
+
+_fail:
+ virtio_gpu_vq_finit(vgpu);
+
+ if (vgpu->cursor)
+ {
+ rt_free_align(vgpu->cursor);
+ }
+ rt_free(vgpu);
+
+ return err;
+}
+
+static rt_err_t virtio_gpu_remove(struct rt_virtio_device *vdev)
+{
+ struct virtio_gpu *vgpu = vdev->parent.user_data;
+
+ virtio_gpu_unregister(vgpu);
+ virtio_gpu_vq_finit(vgpu);
+ rt_free_align(vgpu->cursor);
+ rt_free(vgpu);
+
+ return RT_EOK;
+}
+
+static const struct rt_virtio_device_id virtio_gpu_ids[] =
+{
+ { VIRTIO_DEVICE_ID_GPU, VIRTIO_DEVICE_ANY_ID },
+ { /* sentinel */ }
+};
+
+static struct rt_virtio_driver virtio_gpu_driver =
+{
+ .ids = virtio_gpu_ids,
+ .features =
+ RT_BIT(VIRTIO_GPU_F_VIRGL)
+ | RT_BIT(VIRTIO_GPU_F_EDID)
+ | RT_BIT(VIRTIO_F_ANY_LAYOUT),
+
+ .probe = virtio_gpu_probe,
+ .remove = virtio_gpu_remove,
+ .config_changed = virtio_gpu_config_changed,
+};
+RT_VIRTIO_DRIVER_EXPORT(virtio_gpu_driver);
diff --git a/components/drivers/virtio/virtio-input.c b/components/drivers/virtio/virtio-input.c
new file mode 100644
index 0000000000..1b705b17d5
--- /dev/null
+++ b/components/drivers/virtio/virtio-input.c
@@ -0,0 +1,300 @@
+/*
+ * Copyright (c) 2006-2023, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date Author Notes
+ * 2021-11-11 GuEe-GUI the first version
+ */
+
+#include <rthw.h>
+#include <rtthread.h>
+#include <rtdevice.h>
+
+#define DBG_TAG "virtio.dev.input"
+#define DBG_LVL DBG_INFO
+#include <rtdbg.h>
+
+#include "virtio_config/virtio-input.h"
+
+#define QUEUE_EVENTS 0
+#define QUEUE_STATUS 1
+
+struct virtio_input
+{
+ struct rt_input_device parent;
+ struct rt_virtio_device *vdev;
+
+ struct rt_virtqueue *vqs[2];
+
+ rt_size_t events_nr;
+ struct rt_spinlock lock;
+ struct virtio_input_event *events;
+};
+
+#define raw_to_virtio_input(raw) rt_container_of(raw, struct virtio_input, parent)
+
+static rt_err_t virtio_input_trigger(struct rt_input_device *idev,
+ rt_uint16_t type, rt_uint16_t code, rt_int32_t value)
+{
+ struct rt_virtqueue *vq;
+ struct virtio_input_event status;
+ struct virtio_input *vinput = raw_to_virtio_input(idev);
+
+ vq = vinput->vqs[QUEUE_STATUS];
+
+ rt_virtqueue_wait_prepare(vq, 1);
+
+ rt_spin_lock(&vinput->lock);
+
+ status.type = rt_cpu_to_le16(type);
+ status.code = rt_cpu_to_le16(code);
+ status.value = rt_cpu_to_le32(value);
+ rt_virtqueue_add_outbuf(vq, &status, sizeof(status));
+
+ rt_virtqueue_kick(vq);
+
+ while (!rt_virtqueue_read_buf(vq, RT_NULL))
+ {
+ rt_hw_cpu_relax();
+ }
+
+ rt_spin_unlock(&vinput->lock);
+
+ return RT_EOK;
+}
+
+static void virtio_input_events_done(struct rt_virtqueue *vq)
+{
+ rt_ubase_t level;
+ struct virtio_input_event *event;
+ struct virtio_input *vinput = vq->vdev->priv;
+
+ level = rt_spin_lock_irqsave(&vinput->lock);
+
+ while ((event = rt_virtqueue_read_buf(vq, RT_NULL)))
+ {
+ rt_input_event(&vinput->parent,
+ rt_le16_to_cpu(event->type),
+ rt_le16_to_cpu(event->code),
+ rt_le32_to_cpu(event->value));
+
+ LOG_D("%s: Event (type: %d, code: %d, value: %d)",
+ rt_dm_dev_get_name(&vinput->parent),
+ rt_le16_to_cpu(event->type),
+ rt_le16_to_cpu(event->code),
+ rt_le32_to_cpu(event->value));
+
+ rt_virtqueue_add_inbuf(vq, event, sizeof(*event));
+
+ rt_virtqueue_kick(vq);
+ }
+
+ rt_spin_unlock_irqrestore(&vinput->lock, level);
+}
+
+static void virtio_input_status_done(struct rt_virtqueue *vq)
+{
+}
+
+static rt_uint8_t virtio_input_cfg_select(struct virtio_input *vinput,
+ rt_uint8_t select, rt_uint8_t subsel)
+{
+ rt_uint8_t size = 0;
+ struct rt_virtio_device *vdev = vinput->vdev;
+
+ rt_virtio_write_config(vdev, struct virtio_input_config, select, select);
+ rt_virtio_write_config(vdev, struct virtio_input_config, subsel, subsel);
+ rt_virtio_read_config(vdev, struct virtio_input_config, size, &size);
+
+ return size;
+}
+
+static void virtio_input_cfg_bits(struct virtio_input *vinput,
+ rt_uint8_t select, rt_uint8_t subsel, rt_bitmap_t *map, rt_size_t bitcount)
+{
+ rt_uint8_t size = virtio_input_cfg_select(vinput, select, subsel);
+
+ if (!size)
+ {
+ return;
+ }
+
+ bitcount = rt_min_t(rt_size_t, bitcount, size * RT_BITS_PER_BYTE);
+
+ rt_virtio_read_bytes(vinput->vdev,
+ rt_offsetof(struct virtio_input_config, bitmap), map, 1, size);
+
+ rt_bitmap_set_bit(vinput->parent.cap, subsel);
+}
+
+static void virtio_input_cfg_abs(struct virtio_input *vinput, int abs)
+{
+ rt_uint32_t min, max, res, fuzz, flat;
+ struct rt_virtio_device *vdev = vinput->vdev;
+
+ virtio_input_cfg_select(vinput, VIRTIO_INPUT_CFG_ABS_INFO, abs);
+ rt_virtio_read_config(vdev, struct virtio_input_config, abs.min, &min);
+ rt_virtio_read_config(vdev, struct virtio_input_config, abs.max, &max);
+ rt_virtio_read_config(vdev, struct virtio_input_config, abs.res, &res);
+ rt_virtio_read_config(vdev, struct virtio_input_config, abs.fuzz, &fuzz);
+ rt_virtio_read_config(vdev, struct virtio_input_config, abs.flat, &flat);
+
+ rt_input_set_capability(&vinput->parent, EV_ABS, abs);
+ rt_input_set_absinfo(&vinput->parent, abs, min, max, fuzz, flat);
+ vinput->parent.absinfo->resolution = res;
+}
+
+static rt_err_t virtio_input_vq_init(struct virtio_input *vinput)
+{
+ rt_err_t err;
+ const char *names[] =
+ {
+ "events",
+ "status"
+ };
+ rt_virtqueue_callback cbs[] =
+ {
+ &virtio_input_events_done,
+ &virtio_input_status_done,
+ };
+ struct rt_virtqueue *vq;
+
+ err = rt_virtio_virtqueue_install(vinput->vdev,
+ RT_ARRAY_SIZE(names), vinput->vqs, names, cbs);
+
+ if (err)
+ {
+ return err;
+ }
+
+ vinput->events_nr = rt_virtqueue_get_virtq_size(vinput->vqs[QUEUE_EVENTS]);
+
+ vinput->events = rt_malloc(sizeof(*vinput->events) * vinput->events_nr);
+
+ if (!vinput->events)
+ {
+ return -RT_ENOMEM;
+ }
+
+ vq = vinput->vqs[QUEUE_EVENTS];
+
+ for (int i = 0; i < vinput->events_nr; ++i)
+ {
+ rt_virtqueue_add_inbuf(vq, &vinput->events[i], sizeof(*vinput->events));
+
+ rt_virtqueue_submit(vq);
+ }
+
+ rt_virtqueue_notify(vq);
+
+ return RT_EOK;
+}
+
+static void virtio_input_vq_finit(struct virtio_input *vinput)
+{
+ if (vinput->vqs[0])
+ {
+ rt_virtio_virtqueue_release(vinput->vdev);
+ }
+
+ if (vinput->events)
+ {
+ rt_free(vinput->events);
+ }
+}
+
+static rt_err_t virtio_input_probe(struct rt_virtio_device *vdev)
+{
+ rt_err_t err;
+ struct virtio_input *vinput = rt_calloc(1, sizeof(*vinput));
+
+ if (!vinput)
+ {
+ return -RT_ENOMEM;
+ }
+
+ vdev->priv = vinput;
+ vinput->vdev = vdev;
+ vdev->parent.user_data = vinput;
+
+ if ((err = virtio_input_vq_init(vinput)) < 0)
+ {
+ goto _fail;
+ }
+
+ rt_spin_lock_init(&vinput->lock);
+
+ virtio_input_cfg_bits(vinput, VIRTIO_INPUT_CFG_EV_BITS, EV_KEY,
+ vinput->parent.key_map, KEY_CNT);
+ virtio_input_cfg_bits(vinput, VIRTIO_INPUT_CFG_EV_BITS, EV_REL,
+ vinput->parent.rel_map, REL_CNT);
+ virtio_input_cfg_bits(vinput, VIRTIO_INPUT_CFG_EV_BITS, EV_ABS,
+ vinput->parent.abs_map, ABS_CNT);
+
+ if (rt_bitmap_test_bit(vinput->parent.cap, EV_ABS))
+ {
+ for (int abs = 0; abs < ABS_CNT; ++abs)
+ {
+ if (!rt_bitmap_test_bit(vinput->parent.abs_map, abs))
+ {
+ continue;
+ }
+
+ virtio_input_cfg_abs(vinput, abs);
+ }
+
+ if (rt_bitmap_test_bit(vinput->parent.abs_map, ABS_MT_SLOT))
+ {
+ int nslots = vinput->parent.absinfo[ABS_MT_SLOT].maximum + 1;
+
+ if ((err = rt_input_setup_touch(&vinput->parent, nslots, RT_NULL)))
+ {
+ goto _fail;
+ }
+ }
+ }
+
+ vinput->parent.trigger = &virtio_input_trigger;
+
+ if ((err = rt_input_device_register(&vinput->parent)))
+ {
+ goto _fail;
+ }
+
+ return RT_EOK;
+
+_fail:
+ virtio_input_vq_finit(vinput);
+ rt_input_remove_config(&vinput->parent);
+ rt_free(vinput);
+
+ return err;
+}
+
+static rt_err_t virtio_input_remove(struct rt_virtio_device *vdev)
+{
+ struct virtio_input *vinput = vdev->parent.user_data;
+
+ rt_input_device_unregister(&vinput->parent);
+
+ virtio_input_vq_finit(vinput);
+ rt_free(vinput);
+
+ return RT_EOK;
+}
+
+static const struct rt_virtio_device_id virtio_input_ids[] =
+{
+ { VIRTIO_DEVICE_ID_INPUT, VIRTIO_DEVICE_ANY_ID },
+ { /* sentinel */ }
+};
+
+static struct rt_virtio_driver virtio_input_driver =
+{
+ .ids = virtio_input_ids,
+ .probe = virtio_input_probe,
+ .remove = virtio_input_remove,
+};
+RT_VIRTIO_DRIVER_EXPORT(virtio_input_driver);
diff --git a/components/drivers/virtio/virtio-net.c b/components/drivers/virtio/virtio-net.c
new file mode 100644
index 0000000000..e2e1b559a6
--- /dev/null
+++ b/components/drivers/virtio/virtio-net.c
@@ -0,0 +1,423 @@
+/*
+ * Copyright (c) 2006-2023, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date Author Notes
+ * 2021-11-11 GuEe-GUI the first version
+ * 2023-02-25 GuEe-GUI using virtio dm
+ */
+
+#include <rthw.h>
+#include <rtthread.h>
+#include <rtdevice.h>
+
+#define DBG_TAG "virtio.dev.net"
+#define DBG_LVL DBG_INFO
+#include <rtdbg.h>
+
+#include <mm_aspace.h>
+#include <netif/ethernetif.h>
+
+#include "virtio_config/virtio-net.h"
+
+#define QUEUE_RX(n) (n)
+#define QUEUE_TX(n) ((n) + 1)
+
+rt_packed(struct net_packet
+{
+ struct virtio_net_hdr hdr;
+
+ rt_uint8_t mss[VIRTIO_NET_MSS];
+});
+
+struct virtio_net
+{
+ struct eth_device parent;
+ struct rt_virtio_device *vdev;
+
+ rt_uint16_t status;
+
+ int max_pairs;
+ int request_num;
+ void (*virtqueue_add_net_packet)(struct rt_virtqueue *, struct net_packet *, rt_size_t);
+ struct rt_virtqueue *vqs[RT_CPUS_NR * 2];
+
+ rt_list_t rx_vq_nodes;
+ struct rt_spinlock rx_lock;
+
+ struct net_packet *tx_packet;
+ struct net_packet *rx_packet;
+};
+
+#define raw_to_virtio_net(raw) \
+ rt_container_of(rt_container_of(raw, struct eth_device, parent), struct virtio_net, parent)
+
+static void virtqueue_add_net_packet_split(struct rt_virtqueue *vq,
+ struct net_packet *packet, rt_size_t len)
+{
+ rt_virtqueue_add_outbuf(vq, packet, sizeof(packet->hdr) + len);
+}
+
+static void virtqueue_add_net_packet_packed(struct rt_virtqueue *vq,
+ struct net_packet *packet, rt_size_t len)
+{
+ rt_virtqueue_add_outbuf(vq, &packet->hdr, sizeof(packet->hdr));
+ rt_virtqueue_add_outbuf(vq, &packet->mss, len);
+}
+
+static rt_err_t virtio_net_tx(rt_device_t dev, struct pbuf *p)
+{
+ struct rt_virtqueue *vq;
+ struct net_packet *packet;
+ struct virtio_net *vnet = raw_to_virtio_net(dev);
+
+ vq = vnet->vqs[QUEUE_TX(rt_hw_cpu_id() % vnet->max_pairs)];
+ rt_virtqueue_wait_prepare(vq, vnet->request_num);
+
+ packet = &vnet->tx_packet[vq->index * rt_virtqueue_next_buf_index(vq)];
+ packet->hdr.flags = 0;
+ packet->hdr.gso_type = 0;
+ packet->hdr.hdr_len = 0;
+ packet->hdr.gso_size = 0;
+ packet->hdr.csum_start = 0;
+ packet->hdr.csum_offset = 0;
+ packet->hdr.num_buffers = 0;
+
+ RT_ASSERT(p->tot_len <= sizeof(packet->mss));
+
+ pbuf_copy_partial(p, &packet->mss, p->tot_len, 0);
+
+ vnet->virtqueue_add_net_packet(vq, packet, p->tot_len);
+
+ rt_virtqueue_kick(vq);
+
+ return RT_EOK;
+}
+
+static struct pbuf *virtio_net_rx(rt_device_t dev)
+{
+ rt_size_t size;
+ rt_ubase_t level;
+ struct pbuf *p = RT_NULL;
+ struct net_packet *packet;
+ struct rt_virtqueue *vq;
+ struct virtio_net *vnet = raw_to_virtio_net(dev);
+
+ level = rt_spin_lock_irqsave(&vnet->rx_lock);
+
+ rt_list_for_each_entry(vq, &vnet->rx_vq_nodes, user_list)
+ {
+ packet = rt_virtqueue_read_buf(vq, &size);
+
+ if (!packet)
+ {
+ rt_list_remove(&vq->user_list);
+ break;
+ }
+ size -= sizeof(packet->hdr);
+
+ rt_spin_unlock_irqrestore(&vnet->rx_lock, level);
+
+ p = pbuf_alloc(PBUF_RAW, size, PBUF_RAM);
+
+ if (!p)
+ {
+ return RT_NULL;
+ }
+
+ rt_memcpy(p->payload, &packet->mss, size);
+
+ level = rt_spin_lock_irqsave(&vnet->rx_lock);
+
+ if (!rt_virtqueue_poll(vq, packet - vnet->rx_packet))
+ {
+ rt_list_remove(&vq->user_list);
+ }
+
+ rt_virtqueue_add_inbuf(vq, packet, sizeof(*packet));
+
+ rt_virtqueue_kick(vq);
+
+ break;
+ }
+
+ rt_spin_unlock_irqrestore(&vnet->rx_lock, level);
+
+ return p;
+}
+
+static rt_err_t virtio_net_control(rt_device_t dev, int cmd, void *args)
+{
+ rt_err_t err = RT_EOK;
+ rt_uint8_t *mac;
+ struct virtio_net *vnet = raw_to_virtio_net(dev);
+
+ switch (cmd)
+ {
+ case NIOCTL_GADDR:
+ mac = args;
+
+ if (!mac)
+ {
+ err = -RT_EINVAL;
+ break;
+ }
+
+ for (int i = 0; i < 6; ++i)
+ {
+ rt_virtio_read_config(vnet->vdev, struct virtio_net_config, mac[i], &mac[i]);
+ }
+ break;
+
+ default:
+ err = -RT_EINVAL;
+ break;
+ }
+
+ return err;
+}
+
+#ifdef RT_USING_DEVICE_OPS
+const static struct rt_device_ops virtio_net_ops =
+{
+ .control = virtio_net_control,
+};
+#endif
+
+static void virtio_net_rx_done(struct rt_virtqueue *vq)
+{
+ rt_ubase_t level;
+ struct virtio_net *vnet = vq->vdev->priv;
+
+ level = rt_spin_lock_irqsave(&vnet->rx_lock);
+
+ rt_list_insert_before(&vnet->rx_vq_nodes, &vq->user_list);
+
+ rt_spin_unlock_irqrestore(&vnet->rx_lock, level);
+
+ eth_device_ready(&vnet->parent);
+}
+
+static void virtio_net_tx_done(struct rt_virtqueue *vq)
+{
+ rt_virtqueue_read_buf(vq, RT_NULL);
+}
+
+static void virtio_net_config_changed(struct rt_virtio_device *vdev)
+{
+ rt_uint16_t status;
+ rt_bool_t link_up;
+ struct virtio_net *vnet = vdev->priv;
+
+ if (!rt_virtio_has_feature(vdev, VIRTIO_NET_F_STATUS))
+ {
+ return;
+ }
+
+ rt_virtio_read_config(vdev, struct virtio_net_config, status, &status);
+
+ /* Remove other status bit */
+ status &= VIRTIO_NET_S_LINK_UP;
+
+ if (vnet->status == status)
+ {
+ /* Status no change */
+ return;
+ }
+
+ link_up = !!((vnet->status = status) & VIRTIO_NET_S_LINK_UP);
+
+ LOG_D("%s linkchange to %s", rt_dm_dev_get_name(&vdev->parent), link_up ? "up" : "down");
+
+ eth_device_linkchange(&vnet->parent, link_up);
+}
+
+static rt_err_t virtio_net_vq_init(struct virtio_net *vnet)
+{
+ rt_err_t err;
+ rt_size_t vqs_nr = 2, qsize;
+ const char *names[RT_ARRAY_SIZE(vnet->vqs)];
+ rt_virtqueue_callback cbs[RT_ARRAY_SIZE(vnet->vqs)];
+ struct rt_virtio_device *vdev = vnet->vdev;
+
+ if (rt_virtio_has_feature(vdev, VIRTIO_NET_F_MQ) ||
+ rt_virtio_has_feature(vdev, VIRTIO_NET_F_RSS))
+ {
+ rt_virtio_read_config(vdev, struct virtio_net_config, max_virtqueue_pairs, &vqs_nr);
+ vqs_nr *= 2;
+ }
+
+ for (int i = 0; i < vqs_nr; i += 2)
+ {
+ int rx = QUEUE_RX(i), tx = QUEUE_TX(i);
+
+ names[rx] = "rx";
+ names[tx] = "tx";
+
+ cbs[rx] = &virtio_net_rx_done;
+ cbs[tx] = &virtio_net_tx_done;
+ }
+
+ vnet->max_pairs = vqs_nr / 2;
+ err = rt_virtio_virtqueue_install(vdev, vqs_nr, vnet->vqs, names, cbs);
+
+ if (err)
+ {
+ return err;
+ }
+
+ qsize = rt_virtqueue_get_virtq_size(vnet->vqs[QUEUE_TX(0)]);
+
+ if (!(vnet->tx_packet = rt_malloc(sizeof(vnet->tx_packet[0]) * vqs_nr * qsize)))
+ {
+ return -RT_ENOMEM;
+ }
+
+ qsize = rt_virtqueue_get_virtq_size(vnet->vqs[QUEUE_RX(0)]);
+
+ if (!(vnet->rx_packet = rt_malloc(sizeof(vnet->rx_packet[0]) * vqs_nr * qsize)))
+ {
+ return -RT_ENOMEM;
+ }
+
+ for (int i = 0; i < vqs_nr; i += 2)
+ {
+ int rx = QUEUE_RX(i);
+ struct net_packet *packet;
+ struct rt_virtqueue *vq = vnet->vqs[rx];
+
+ packet = &vnet->rx_packet[rx * qsize];
+
+ for (int idx = 0; idx < qsize; ++idx, ++packet)
+ {
+ rt_virtqueue_add_inbuf(vq, packet, sizeof(*packet));
+
+ rt_virtqueue_submit(vq);
+ }
+
+ rt_virtqueue_notify(vq);
+ }
+
+ return RT_EOK;
+}
+
+static void virtio_net_vq_finit(struct virtio_net *vnet)
+{
+ if (vnet->vqs[0])
+ {
+ rt_virtio_virtqueue_release(vnet->vdev);
+ }
+ if (vnet->tx_packet)
+ {
+ rt_free(vnet->tx_packet);
+ }
+ if (vnet->rx_packet)
+ {
+ rt_free(vnet->rx_packet);
+ }
+}
+
+static rt_err_t virtio_net_probe(struct rt_virtio_device *vdev)
+{
+ rt_err_t err = RT_EOK;
+ struct virtio_net *vnet = rt_calloc(1, sizeof(*vnet));
+
+ if (!vnet)
+ {
+ return -RT_ENOMEM;
+ }
+
+ vdev->priv = vnet;
+ vnet->vdev = vdev;
+ vdev->parent.user_data = vnet;
+#ifdef RT_USING_DEVICE_OPS
+ vnet->parent.parent.ops = &virtio_net_ops;
+#else
+ vnet->parent.parent.control = virtio_net_control;
+#endif
+ vnet->parent.eth_tx = virtio_net_tx;
+ vnet->parent.eth_rx = virtio_net_rx;
+
+ if (rt_virtio_has_feature(vdev, VIRTIO_F_RING_PACKED))
+ {
+ vnet->request_num = 2;
+ vnet->virtqueue_add_net_packet = &virtqueue_add_net_packet_packed;
+ }
+ else
+ {
+ vnet->request_num = 1;
+ vnet->virtqueue_add_net_packet = &virtqueue_add_net_packet_split;
+ }
+
+ if ((err = virtio_net_vq_init(vnet)))
+ {
+ goto _fail;
+ }
+
+ rt_list_init(&vnet->rx_vq_nodes);
+ rt_spin_lock_init(&vnet->rx_lock);
+
+ if ((err = rt_dm_dev_set_name_auto(&vnet->parent.parent, "e")) < 0)
+ {
+ goto _fail;
+ }
+
+ if ((err = eth_device_init(&vnet->parent, rt_dm_dev_get_name(&vnet->parent.parent))))
+ {
+ goto _fail;
+ }
+
+ eth_device_linkchange(&vnet->parent, RT_TRUE);
+
+ return RT_EOK;
+
+_fail:
+ virtio_net_vq_finit(vnet);
+ rt_free(vnet);
+
+ return err;
+}
+
+static rt_err_t virtio_net_remove(struct rt_virtio_device *vdev)
+{
+ struct virtio_net *vnet = vdev->parent.user_data;
+
+ eth_device_linkchange(&vnet->parent, RT_FALSE);
+ eth_device_deinit(&vnet->parent);
+
+ virtio_net_vq_finit(vnet);
+ rt_free(vnet);
+
+ return RT_EOK;
+}
+
+static const struct rt_virtio_device_id virtio_net_ids[] =
+{
+ { VIRTIO_DEVICE_ID_NET, VIRTIO_DEVICE_ANY_ID },
+ { /* sentinel */ }
+};
+
+static struct rt_virtio_driver virtio_net_driver =
+{
+ .ids = virtio_net_ids,
+ .features =
+ RT_BIT(VIRTIO_NET_F_MTU)
+ | RT_BIT(VIRTIO_NET_F_MAC)
+ | RT_BIT(VIRTIO_NET_F_MRG_RXBUF)
+ | RT_BIT(VIRTIO_NET_F_STATUS)
+ | RT_BIT(VIRTIO_NET_F_CTRL_RX)
+ | RT_BIT(VIRTIO_NET_F_CTRL_VLAN)
+ | RT_BIT(VIRTIO_NET_F_CTRL_RX_EXTRA)
+ | RT_BIT(VIRTIO_NET_F_GUEST_ANNOUNCE)
+ | RT_BIT(VIRTIO_NET_F_MQ)
+ | RT_BIT(VIRTIO_NET_F_CTRL_MAC_ADDR)
+ | RT_BIT(VIRTIO_NET_F_SPEED_DUPLEX)
+ | RT_BIT(VIRTIO_F_ANY_LAYOUT),
+
+ .probe = virtio_net_probe,
+ .remove = virtio_net_remove,
+ .config_changed = virtio_net_config_changed,
+};
+RT_VIRTIO_DRIVER_EXPORT(virtio_net_driver);
diff --git a/components/drivers/virtio/virtio-rng.c b/components/drivers/virtio/virtio-rng.c
new file mode 100644
index 0000000000..99d2781960
--- /dev/null
+++ b/components/drivers/virtio/virtio-rng.c
@@ -0,0 +1,191 @@
+/*
+ * 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.rng"
+#define DBG_LVL DBG_INFO
+#include <rtdbg.h>
+
+#include <cpuport.h>
+
+struct virtio_rng
+{
+ struct rt_hwcrypto_device parent;
+ struct rt_virtio_device *vdev;
+
+ struct rt_virtqueue *vqs[1];
+ struct rt_spinlock lock;
+};
+
+static rt_uint32_t virtio_rng_rand(struct hwcrypto_rng *ctx)
+{
+ rt_uint32_t rand;
+ struct rt_virtqueue *vq;
+ struct virtio_rng *vrng = rt_container_of(ctx->parent.device, struct virtio_rng, parent);
+
+ vq = vrng->vqs[0];
+ rt_virtqueue_wait_prepare(vq, 1);
+
+ rt_spin_lock(&vrng->lock);
+
+ rt_virtqueue_add_inbuf(vq, &rand, sizeof(rand));
+ rt_virtqueue_kick(vq);
+
+ while (!rt_virtqueue_read_buf(vq, RT_NULL))
+ {
+ rt_hw_cpu_relax();
+ }
+
+ rt_spin_unlock(&vrng->lock);
+
+ return rand;
+}
+
+static const struct hwcrypto_rng_ops rng_ops =
+{
+ .update = virtio_rng_rand,
+};
+
+static rt_err_t virtio_rng_create(struct rt_hwcrypto_ctx *ctx)
+{
+ if ((ctx->type & HWCRYPTO_MAIN_TYPE_MASK) == HWCRYPTO_TYPE_RNG)
+ {
+ struct hwcrypto_rng *rng;
+
+ ctx->contex = RT_NULL;
+
+ rng = rt_container_of(ctx, struct hwcrypto_rng, parent);
+ rng->ops = &rng_ops;
+
+ return RT_EOK;
+ }
+
+ return -RT_ENOSYS;
+}
+
+static void virtio_rng_destroy(struct rt_hwcrypto_ctx *ctx)
+{
+}
+
+static rt_err_t virtio_rng_copy(struct rt_hwcrypto_ctx *des,
+ const struct rt_hwcrypto_ctx *src)
+{
+ if ((src->type & HWCRYPTO_MAIN_TYPE_MASK) == HWCRYPTO_TYPE_RNG)
+ {
+ return RT_EOK;
+ }
+
+ return -RT_ENOSYS;
+}
+
+static void virtio_rng_reset(struct rt_hwcrypto_ctx *ctx)
+{
+}
+
+static const struct rt_hwcrypto_ops virtio_rng_ops =
+{
+ .create = virtio_rng_create,
+ .destroy = virtio_rng_destroy,
+ .copy = virtio_rng_copy,
+ .reset = virtio_rng_reset,
+};
+
+static void virtio_rng_done(struct rt_virtqueue *vq)
+{
+}
+
+static rt_err_t virtio_rng_vq_init(struct virtio_rng *vrng)
+{
+ const char *names[] =
+ {
+ "req",
+ };
+ rt_virtqueue_callback cbs[] =
+ {
+ &virtio_rng_done,
+ };
+
+ return rt_virtio_virtqueue_install(vrng->vdev, RT_ARRAY_SIZE(vrng->vqs),
+ vrng->vqs, names, cbs);
+}
+
+static void virtio_rng_vq_finit(struct virtio_rng *vrng)
+{
+ if (vrng->vqs[0])
+ {
+ rt_virtio_virtqueue_release(vrng->vdev);
+ }
+}
+
+static rt_err_t virtio_rng_probe(struct rt_virtio_device *vdev)
+{
+ rt_err_t err;
+ struct virtio_rng *vrng = rt_calloc(1, sizeof(*vrng));
+
+ if (!vrng)
+ {
+ return -RT_ENOMEM;
+ }
+
+ vdev->priv = vrng;
+ vrng->vdev = vdev;
+ vdev->parent.user_data = vrng;
+
+ if ((err = virtio_rng_vq_init(vrng)))
+ {
+ goto _fail;
+ }
+
+ rt_spin_lock_init(&vrng->lock);
+ vrng->parent.ops = &virtio_rng_ops;
+ vrng->parent.id = vdev->id.vendor;
+
+ if ((err = rt_hwcrypto_register(&vrng->parent, "hwrng")))
+ {
+ goto _fail;
+ }
+
+ return RT_EOK;
+
+_fail:
+ virtio_rng_vq_finit(vrng);
+ rt_free(vrng);
+
+ return err;
+}
+
+static rt_err_t virtio_rng_remove(struct rt_virtio_device *vdev)
+{
+ struct virtio_rng *vrng = vdev->parent.user_data;
+
+ rt_device_unregister(&vrng->parent.parent);
+
+ virtio_rng_vq_finit(vrng);
+ rt_free(vrng);
+
+ return RT_EOK;
+}
+
+static const struct rt_virtio_device_id virtio_rng_ids[] =
+{
+ { VIRTIO_DEVICE_ID_RNG, VIRTIO_DEVICE_ANY_ID },
+ { /* sentinel */ }
+};
+
+static struct rt_virtio_driver virtio_rng_driver =
+{
+ .ids = virtio_rng_ids,
+ .probe = virtio_rng_probe,
+ .remove = virtio_rng_remove,
+};
+RT_VIRTIO_DRIVER_EXPORT(virtio_rng_driver);
diff --git a/components/drivers/virtio/virtio-scmi.c b/components/drivers/virtio/virtio-scmi.c
new file mode 100644
index 0000000000..92343e4f7e
--- /dev/null
+++ b/components/drivers/virtio/virtio-scmi.c
@@ -0,0 +1,293 @@
+/*
+ * 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.scmi"
+#define DBG_LVL DBG_INFO
+#include <rtdbg.h>
+
+#include "virtio_internal.h"
+#include "virtio_config/virtio-scmi.h"
+#include "../firmware/arm_scmi/agent.h"
+
+#define QUEUE_CMDQ 0
+#define QUEUE_EVENTQ 1
+
+struct virtio_scmi_event_msg_ext
+{
+ rt_list_t list;
+
+ struct rt_scmi_device *sdev;
+ rt_scmi_msg_callback rx_callback;
+
+ rt_size_t msg_size;
+ struct virtio_scmi_event_msg event_msg;
+};
+
+struct virtio_scmi
+{
+ struct rt_virtio_device *vdev;
+
+ rt_list_t event_nodes;
+ struct rt_work event_work;
+
+ struct rt_virtqueue *vqs[2];
+ struct rt_completion done;
+ struct rt_spinlock lock;
+};
+
+static struct virtio_scmi *system_virtio_scmi = RT_NULL;
+
+static rt_err_t scmi_agent_virtio_setup(struct scmi_agent *agent,
+ struct rt_device *dev)
+{
+ RT_ASSERT(system_virtio_scmi != RT_NULL);
+
+ agent->priv = system_virtio_scmi;
+
+ return RT_EOK;
+}
+
+static rt_err_t scmi_agent_virtio_process_msg(struct scmi_agent *agent,
+ struct rt_scmi_msg *msg)
+{
+ rt_base_t level;
+ struct rt_virtqueue *vq;
+ struct virtio_scmi *vscmi = agent->priv;
+
+ if (!msg->rx_callback ||
+ !rt_virtio_has_feature(vscmi->vdev, VIRTIO_SCMI_F_P2A_CHANNELS))
+ {
+ void *buffer;
+ rt_size_t request_size, response_size;
+ struct virtio_scmi_request *request;
+ struct virtio_scmi_response *response;
+
+ request_size = sizeof(*request) + msg->in_msg_size;
+ response_size = sizeof(*response) + msg->out_msg_size;
+ buffer = rt_malloc(request_size + response_size);
+
+ if (!buffer)
+ {
+ return -RT_ENOMEM;
+ }
+
+ request = buffer;
+ response = buffer + request_size;
+
+ request->hdr = cpu_to_virtio32(vscmi->vdev, scmi_header(
+ msg->message_id, 0, msg->sdev->protocol_id, 0));
+ rt_memcpy(request->params, msg->in_msg, msg->in_msg_size);
+
+ vq = vscmi->vqs[QUEUE_CMDQ];
+ rt_virtqueue_wait_prepare(vq, 2);
+
+ level = rt_spin_lock_irqsave(&vscmi->lock);
+
+ rt_virtqueue_add_outbuf(vq, request, request_size);
+ rt_virtqueue_add_inbuf(vq, response, response_size);
+ rt_virtqueue_kick(vq);
+
+ rt_spin_unlock_irqrestore(&vscmi->lock, level);
+
+ rt_completion_wait(&vscmi->done, RT_WAITING_FOREVER);
+
+ if (msg->out_msg)
+ {
+ if (request->hdr != response->hdr)
+ {
+ LOG_W("WTF? request header(%x) != response header(%x)",
+ rt_le32_to_cpu(request->hdr), rt_le32_to_cpu(response->hdr));
+ }
+
+ rt_memcpy(msg->out_msg, response->ret_values, msg->out_msg_size);
+ }
+
+ /* Fixup for device */
+ if (msg->rx_callback)
+ {
+ msg->rx_callback(msg->sdev, response->ret_values, msg->out_msg_size);
+ }
+
+ rt_free(buffer);
+ }
+ else
+ {
+ struct virtio_scmi_event_msg_ext *msge = rt_malloc(sizeof(*msge) +
+ rt_max(msg->in_msg_size, msg->out_msg_size));
+
+ if (!msge)
+ {
+ return -RT_ENOMEM;
+ }
+
+ msge->sdev = msg->sdev;
+ msge->rx_callback = msg->rx_callback;
+ msge->msg_size = msg->out_msg_size;
+ msge->event_msg.hdr = cpu_to_virtio32(vscmi->vdev, scmi_header(
+ msg->message_id, 0, msg->sdev->protocol_id, 0));
+ rt_memcpy(msge->event_msg.payload, msg->in_msg, msg->in_msg_size);
+
+ vq = vscmi->vqs[QUEUE_EVENTQ];
+ rt_virtqueue_wait_prepare(vq, 1);
+
+ level = rt_spin_lock_irqsave(&vscmi->lock);
+
+ rt_virtqueue_add_outbuf(vq, &msge->event_msg,
+ sizeof(msge->event_msg) + msg->in_msg_size);
+ rt_virtqueue_kick(vq);
+
+ rt_spin_unlock_irqrestore(&vscmi->lock, level);
+ }
+
+ return RT_EOK;
+}
+
+struct scmi_agent_ops scmi_agent_virtio_ops =
+{
+ .name = "virtio",
+ .setup = scmi_agent_virtio_setup,
+ .process_msg = scmi_agent_virtio_process_msg,
+};
+
+static void virtio_scmi_work(struct rt_work *work, void *work_data)
+{
+ rt_ubase_t level;
+ struct virtio_scmi *vscmi = work_data;
+ struct virtio_scmi_event_msg_ext *msge, *msge_next;
+
+ level = rt_spin_lock_irqsave(&vscmi->lock);
+
+ rt_list_for_each_entry_safe(msge, msge_next, &vscmi->event_nodes, list)
+ {
+ rt_list_remove(&msge->list);
+
+ rt_spin_unlock_irqrestore(&vscmi->lock, level);
+
+ msge->rx_callback(msge->sdev, msge->event_msg.payload, msge->msg_size);
+ rt_free(msge);
+
+ level = rt_spin_lock_irqsave(&vscmi->lock);
+ }
+
+ rt_spin_unlock_irqrestore(&vscmi->lock, level);
+}
+
+static void virtio_scmi_cmd_done(struct rt_virtqueue *vq)
+{
+ rt_ubase_t level;
+ struct virtio_scmi *vscmi = vq->vdev->priv;
+
+ level = rt_spin_lock_irqsave(&vscmi->lock);
+
+ rt_virtqueue_read_buf(vq, RT_NULL);
+ rt_completion_done(&vscmi->done);
+
+ rt_spin_unlock_irqrestore(&vscmi->lock, level);
+}
+
+static void virtio_scmi_event_done(struct rt_virtqueue *vq)
+{
+ rt_ubase_t level;
+ void *raw_buffer;
+ struct virtio_scmi *vscmi = vq->vdev->priv;
+
+ level = rt_spin_lock_irqsave(&vscmi->lock);
+
+ if ((raw_buffer = rt_virtqueue_read_buf(vq, RT_NULL)))
+ {
+ struct virtio_scmi_event_msg_ext *msge;
+
+ msge = rt_container_of(raw_buffer, struct virtio_scmi_event_msg_ext, event_msg);
+
+ rt_list_init(&msge->list);
+ rt_list_insert_before(&vscmi->event_nodes, &msge->list);
+
+ rt_work_submit(&vscmi->event_work, 0);
+ }
+
+ rt_spin_unlock_irqrestore(&vscmi->lock, level);
+}
+
+static rt_err_t virtio_scmi_vq_init(struct virtio_scmi *vscmi)
+{
+ rt_size_t vqs_nr;
+ const char *names[] =
+ {
+ "cmd",
+ "event"
+ };
+ rt_virtqueue_callback cbs[] =
+ {
+ &virtio_scmi_cmd_done,
+ &virtio_scmi_event_done,
+ };
+
+ vqs_nr = rt_virtio_has_feature(vscmi->vdev, VIRTIO_SCMI_F_P2A_CHANNELS) ?
+ RT_ARRAY_SIZE(names) : 1;
+
+ return rt_virtio_virtqueue_install(vscmi->vdev, vqs_nr, vscmi->vqs, names, cbs);
+}
+
+static rt_err_t virtio_scmi_probe(struct rt_virtio_device *vdev)
+{
+ rt_err_t err;
+ struct virtio_scmi *vscmi = rt_calloc(1, sizeof(*vscmi));
+
+ if (!vscmi)
+ {
+ return -RT_ENOMEM;
+ }
+
+ vdev->priv = vscmi;
+ vscmi->vdev = vdev;
+ vdev->parent.user_data = vscmi;
+
+ if ((err = virtio_scmi_vq_init(vscmi)) < 0)
+ {
+ rt_free(vscmi);
+
+ return err;
+ }
+
+ if (rt_virtio_has_feature(vscmi->vdev, VIRTIO_SCMI_F_P2A_CHANNELS))
+ {
+ rt_list_init(&vscmi->event_nodes);
+ rt_work_init(&vscmi->event_work, virtio_scmi_work, vscmi);
+ }
+
+ rt_spin_lock_init(&vscmi->lock);
+ rt_completion_init(&vscmi->done);
+
+ system_virtio_scmi = vscmi;
+
+ return RT_EOK;
+}
+
+static const struct rt_virtio_device_id virtio_scmi_ids[] =
+{
+ { VIRTIO_DEVICE_ID_SCMI, VIRTIO_DEVICE_ANY_ID },
+ { /* sentinel */ }
+};
+
+static struct rt_virtio_driver virtio_scmi_driver =
+{
+ .ids = virtio_scmi_ids,
+ .features =
+ RT_BIT(VIRTIO_SCMI_F_P2A_CHANNELS)
+ | RT_BIT(VIRTIO_SCMI_F_SHARED_MEMORY)
+ | RT_BIT(VIRTIO_F_ANY_LAYOUT),
+
+ .probe = virtio_scmi_probe,
+};
+RT_VIRTIO_DRIVER_EXPORT(virtio_scmi_driver);
diff --git a/components/drivers/virtio/virtio-scsi.c b/components/drivers/virtio/virtio-scsi.c
new file mode 100644
index 0000000000..7080f1fd16
--- /dev/null
+++ b/components/drivers/virtio/virtio-scsi.c
@@ -0,0 +1,322 @@
+/*
+ * 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.scsi"
+#define DBG_LVL DBG_INFO
+#include <rtdbg.h>
+
+#include "virtio_config/virtio-scsi.h"
+#include "virtio_internal.h"
+
+#define QUEUE_CONTROL 0
+#define QUEUE_EVENT 1
+#define QUEUE_REQUEST 2
+
+struct virtio_scsi
+{
+ struct rt_scsi_host parent;
+ struct rt_virtio_device *vdev;
+
+ struct rt_virtqueue *vqs[3];
+ struct rt_completion done;
+ struct rt_spinlock lock;
+
+ rt_uint16_t max_target;
+ rt_uint32_t max_lun;
+ struct rt_work hotplug_work;
+};
+
+static void virtio_scsi_init_cmd_req(struct virtio_scsi *vscsi,
+ struct rt_scsi_device *sdev, struct rt_scsi_cmd *cmd,
+ struct virtio_scsi_cmd_req *req)
+{
+ req->lun[0] = 1;
+ req->lun[1] = sdev->id;
+ req->lun[2] = (sdev->lun >> 8) | 0x40;
+ req->lun[3] = sdev->lun & 0xff;
+ req->tag = cpu_to_virtio64(vscsi->vdev, (rt_ubase_t)cmd);
+ req->task_attr = VIRTIO_SCSI_S_SIMPLE;
+ req->prio = 0;
+ req->crn = 0;
+}
+
+static rt_err_t virtio_scsi_transfer(struct rt_scsi_device *sdev,
+ struct rt_scsi_cmd *cmd)
+{
+ rt_ubase_t level;
+ struct rt_virtqueue *vq;
+ struct virtio_scsi_cmd_req req;
+ struct virtio_scsi_cmd_resp resp;
+ struct virtio_scsi *vscsi = rt_container_of(sdev->host, struct virtio_scsi, parent);
+
+ virtio_scsi_init_cmd_req(vscsi, sdev, cmd, &req);
+
+ RT_ASSERT(cmd->op_size < sizeof(req.cdb));
+ rt_memcpy(&req.cdb, &cmd->op, cmd->op_size);
+
+ vq = vscsi->vqs[QUEUE_REQUEST];
+ if (!cmd->data.ptr || !cmd->data.size)
+ {
+ rt_virtqueue_wait_prepare(vq, 2);
+ }
+ else
+ {
+ rt_virtqueue_wait_prepare(vq, 3);
+ }
+
+ level = rt_spin_lock_irqsave(&vscsi->lock);
+
+ rt_virtqueue_add_outbuf(vq, &req, sizeof(req));
+
+ if (!cmd->data.ptr || !cmd->data.size)
+ {
+ rt_virtqueue_add_inbuf(vq, &resp, sizeof(resp));
+ }
+ else if (!rt_scsi_cmd_is_write(cmd))
+ {
+ rt_virtqueue_add_inbuf(vq, &resp, sizeof(resp));
+ rt_virtqueue_add_inbuf(vq, cmd->data.ptr, cmd->data.size);
+ }
+ else
+ {
+ rt_virtqueue_add_outbuf(vq, cmd->data.ptr, cmd->data.size);
+ rt_virtqueue_add_inbuf(vq, &resp, sizeof(resp));
+ }
+
+ rt_virtqueue_kick(vq);
+
+ rt_spin_unlock_irqrestore(&vscsi->lock, level);
+
+ rt_completion_wait(&vscsi->done, RT_WAITING_FOREVER);
+
+ switch (resp.response)
+ {
+ case VIRTIO_SCSI_S_OK:
+ if (resp.sense_len)
+ {
+ rt_memcpy(&cmd->data.request_sense, &resp.sense,
+ rt_min_t(rt_uint32_t,
+ virtio32_to_cpu(vscsi->vdev, resp.sense_len),
+ VIRTIO_SCSI_SENSE_SIZE));
+ }
+ return RT_EOK;
+
+ case VIRTIO_SCSI_S_OVERRUN:
+ LOG_E("%s resp = %s", rt_dm_dev_get_name(sdev->host->dev), "OVERRUN");
+ return -RT_ERROR;
+
+ case VIRTIO_SCSI_S_ABORTED:
+ LOG_E("%s resp = %s", rt_dm_dev_get_name(sdev->host->dev), "ABORTED");
+ return -RT_EIO;
+
+ case VIRTIO_SCSI_S_BAD_TARGET:
+ LOG_E("%s resp = %s", rt_dm_dev_get_name(sdev->host->dev), "BAD_TARGET");
+ return -RT_EINVAL;
+
+ case VIRTIO_SCSI_S_RESET:
+ LOG_E("%s resp = %s", rt_dm_dev_get_name(sdev->host->dev), "RESET");
+ return -RT_EIO;
+
+ case VIRTIO_SCSI_S_BUSY:
+ LOG_E("%s resp = %s", rt_dm_dev_get_name(sdev->host->dev), "BUSY");
+ return -RT_EBUSY;
+
+ case VIRTIO_SCSI_S_TRANSPORT_FAILURE:
+ LOG_E("%s resp = %s", rt_dm_dev_get_name(sdev->host->dev), "TRANSPORT_FAILURE");
+ return -RT_EIO;
+
+ case VIRTIO_SCSI_S_TARGET_FAILURE:
+ LOG_E("%s resp = %s", rt_dm_dev_get_name(sdev->host->dev), "TARGET_FAILURE");
+ return -RT_EIO;
+
+ case VIRTIO_SCSI_S_NEXUS_FAILURE:
+ LOG_E("%s resp = %s", rt_dm_dev_get_name(sdev->host->dev), "NEXUS_FAILURE");
+ return -RT_EIO;
+
+ case VIRTIO_SCSI_S_FAILURE:
+ LOG_E("%s resp = %s", rt_dm_dev_get_name(sdev->host->dev), "FAILURE");
+ return -RT_EIO;
+
+ case VIRTIO_SCSI_S_FUNCTION_SUCCEEDED:
+ return RT_EOK;
+
+ case VIRTIO_SCSI_S_FUNCTION_REJECTED:
+ LOG_E("%s resp = %s", rt_dm_dev_get_name(sdev->host->dev), "FUNCTION_REJECTED");
+ return -RT_EINVAL;
+
+ case VIRTIO_SCSI_S_INCORRECT_LUN:
+ LOG_E("%s resp = %s", rt_dm_dev_get_name(sdev->host->dev), "INCORRECT_LUN");
+ return -RT_EINVAL;
+
+ default:
+ LOG_E("%s resp = UNKNOWN(%d)", rt_dm_dev_get_name(sdev->host->dev), resp.response);
+ return -RT_EIO;
+ }
+}
+
+static struct rt_scsi_ops virtio_scsi_ops =
+{
+ .transfer = virtio_scsi_transfer,
+};
+
+static void virtio_scsi_hotplug_work(struct rt_work *work, void *work_data)
+{
+ struct virtio_scsi *vscsi = work_data;
+
+ if (!rt_scsi_host_unregister(&vscsi->parent))
+ {
+ vscsi->parent.max_id = vscsi->max_target;
+ vscsi->parent.max_lun = vscsi->max_lun;
+
+ rt_scsi_host_register(&vscsi->parent);
+ }
+}
+
+static void virtio_scsi_request_done(struct rt_virtqueue *vq)
+{
+ rt_ubase_t level;
+ struct virtio_scsi *vscsi = vq->vdev->priv;
+
+ level = rt_spin_lock_irqsave(&vscsi->lock);
+
+ rt_virtqueue_read_buf(vq, RT_NULL);
+ rt_completion_done(&vscsi->done);
+
+ rt_spin_unlock_irqrestore(&vscsi->lock, level);
+}
+
+static void virtio_scsi_config_changed(struct rt_virtio_device *vdev)
+{
+ struct virtio_scsi *vscsi = vdev->priv;
+
+ rt_virtio_read_config(vdev, struct virtio_scsi_config,
+ max_target, &vscsi->max_target);
+ rt_virtio_read_config(vdev, struct virtio_scsi_config,
+ max_lun, &vscsi->max_lun);
+
+ if (vscsi->parent.max_id != vscsi->max_target ||
+ vscsi->parent.max_lun != vscsi->max_lun)
+ {
+ rt_work_submit(&vscsi->hotplug_work, 0);
+ }
+}
+
+static rt_err_t virtio_scsi_vq_init(struct virtio_scsi *vscsi)
+{
+ const char *names[] =
+ {
+ RT_NULL, /* ctrl */
+ RT_NULL, /* event */
+ "req",
+ };
+ rt_virtqueue_callback cbs[] =
+ {
+ RT_NULL,
+ RT_NULL,
+ &virtio_scsi_request_done,
+ };
+
+ return rt_virtio_virtqueue_install(vscsi->vdev, RT_ARRAY_SIZE(vscsi->vqs),
+ vscsi->vqs, names, cbs);
+}
+
+static void virtio_scsi_vq_finit(struct virtio_scsi *vscsi)
+{
+ if (vscsi->vqs[0])
+ {
+ rt_virtio_virtqueue_release(vscsi->vdev);
+ }
+}
+
+static rt_err_t virtio_scsi_probe(struct rt_virtio_device *vdev)
+{
+ rt_err_t err;
+ rt_uint32_t cdb_size;
+ struct virtio_scsi *vscsi = rt_calloc(1, sizeof(*vscsi));
+
+ if (!vscsi)
+ {
+ return -RT_ENOMEM;
+ }
+
+ vdev->priv = vscsi;
+ vscsi->vdev = vdev;
+ vdev->parent.user_data = vscsi;
+ vscsi->parent.dev = &vdev->parent;
+ vscsi->parent.ops = &virtio_scsi_ops;
+
+ rt_virtio_read_config(vdev, struct virtio_scsi_config,
+ max_target, &vscsi->max_target);
+ rt_virtio_read_config(vdev, struct virtio_scsi_config,
+ max_lun, &vscsi->max_lun);
+
+ vscsi->parent.max_id = vscsi->max_target;
+ vscsi->parent.max_lun = vscsi->max_lun;
+
+ if ((err = virtio_scsi_vq_init(vscsi)))
+ {
+ goto _fail;
+ }
+
+ cdb_size = RT_ALIGN(sizeof(((struct rt_scsi_cmd *)RT_NULL)->op), 32);
+ rt_virtio_write_config(vdev, struct virtio_scsi_config, cdb_size, cdb_size);
+
+ rt_completion_init(&vscsi->done);
+ rt_spin_lock_init(&vscsi->lock);
+
+ rt_work_init(&vscsi->hotplug_work, virtio_scsi_hotplug_work, vscsi);
+
+ if ((err = rt_scsi_host_register(&vscsi->parent)))
+ {
+ goto _fail;
+ }
+
+ return RT_EOK;
+
+_fail:
+ virtio_scsi_vq_finit(vscsi);
+ rt_free(vscsi);
+
+ return err;
+}
+
+static rt_err_t virtio_scsi_remove(struct rt_virtio_device *vdev)
+{
+ struct virtio_scsi *vscsi = vdev->parent.user_data;
+
+ rt_scsi_host_unregister(&vscsi->parent);
+
+ virtio_scsi_vq_finit(vscsi);
+ rt_free(vscsi);
+
+ return RT_EOK;
+}
+
+static const struct rt_virtio_device_id virtio_scsi_ids[] =
+{
+ { VIRTIO_DEVICE_ID_SCSI, VIRTIO_DEVICE_ANY_ID },
+ { /* sentinel */ }
+};
+
+static struct rt_virtio_driver virtio_scsi_driver =
+{
+ .ids = virtio_scsi_ids,
+ .features =
+ RT_BIT(VIRTIO_F_ANY_LAYOUT),
+
+ .probe = virtio_scsi_probe,
+ .remove = virtio_scsi_remove,
+ .config_changed = virtio_scsi_config_changed,
+};
+RT_VIRTIO_DRIVER_EXPORT(virtio_scsi_driver);
diff --git a/components/drivers/virtio/virtio.c b/components/drivers/virtio/virtio.c
index a7937dfaee..083922eaf4 100644
--- a/components/drivers/virtio/virtio.c
+++ b/components/drivers/virtio/virtio.c
@@ -6,468 +6,356 @@
* Change Logs:
* Date Author Notes
* 2021-11-11 GuEe-GUI the first version
- * 2023-10-12 fangjianzhou support SDL2
+ * 2023-04-13 ErikChan add virtio bus
*/
+#include <rtatomic.h>
#include <rtthread.h>
-#include <cpuport.h>
-#include <virtio.h>
+#define DBG_TAG "rtdm.virtio"
+#define DBG_LVL DBG_INFO
+#include <rtdbg.h>
-rt_inline void _virtio_dev_check(struct virtio_device *dev)
-{
- RT_ASSERT(dev != RT_NULL);
- RT_ASSERT(dev->mmio_config != RT_NULL);
-}
+#include <cpuport.h>
-void virtio_reset_device(struct virtio_device *dev)
+#include <drivers/virtio.h>
+#include <drivers/core/bus.h>
+
+void rt_virtio_device_ready(struct rt_virtio_device *vdev)
{
- _virtio_dev_check(dev);
+ rt_uint8_t status;
- dev->mmio_config->status = 0;
-}
+ RT_ASSERT(vdev != RT_NULL);
+ RT_ASSERT(vdev->trans != RT_NULL);
-void virtio_status_acknowledge_driver(struct virtio_device *dev)
-{
- _virtio_dev_check(dev);
+ if (!vdev->trans->get_status(vdev, &status))
+ {
+ if (status & VIRTIO_STATUS_DRIVER_OK)
+ {
+ LOG_W("%s device driver is OK yet");
+ }
- dev->mmio_config->status |= VIRTIO_STATUS_ACKNOWLEDGE | VIRTIO_STATUS_DRIVER;
+ vdev->trans->set_status(vdev, status | VIRTIO_STATUS_DRIVER_OK);
+ }
}
-void virtio_status_driver_ok(struct virtio_device *dev)
+void rt_virtio_device_reset(struct rt_virtio_device *vdev)
{
- _virtio_dev_check(dev);
+ RT_ASSERT(vdev != RT_NULL);
+ RT_ASSERT(vdev->trans != RT_NULL);
- dev->mmio_config->status |= VIRTIO_STATUS_FEATURES_OK | VIRTIO_STATUS_DRIVER_OK;
+ vdev->trans->reset(vdev);
}
-void virtio_interrupt_ack(struct virtio_device *dev)
+void rt_virtio_device_config_changed(struct rt_virtio_device *vdev)
{
- rt_uint32_t status;
+ struct rt_virtio_driver *vdrv;
- _virtio_dev_check(dev);
+ RT_ASSERT(vdev != RT_NULL);
+ RT_ASSERT(vdev->parent.drv != RT_NULL);
- status = dev->mmio_config->interrupt_status;
+ vdrv = rt_container_of(vdev->parent.drv, struct rt_virtio_driver, parent);
- if (status != 0)
+ if (vdrv->config_changed)
{
- dev->mmio_config->interrupt_ack = status;
+ vdrv->config_changed(vdev);
}
}
-rt_bool_t virtio_has_feature(struct virtio_device *dev, rt_uint32_t feature_bit)
+void rt_virtio_add_status(struct rt_virtio_device *vdev, rt_uint32_t status)
{
- _virtio_dev_check(dev);
+ rt_uint8_t cur_status;
+
+ RT_ASSERT(vdev != RT_NULL);
+ RT_ASSERT(vdev->trans != RT_NULL);
- return !!(dev->mmio_config->device_features & (1UL << feature_bit));
+ if (!vdev->trans->get_status(vdev, &cur_status))
+ {
+ vdev->trans->set_status(vdev, cur_status | status);
+ }
}
-rt_err_t virtio_queues_alloc(struct virtio_device *dev, rt_size_t queues_num)
+rt_bool_t rt_virtio_has_status(struct rt_virtio_device *vdev, rt_uint8_t status_bit)
{
- _virtio_dev_check(dev);
+ rt_uint8_t status;
- dev->queues = rt_malloc(sizeof(struct virtq) * queues_num);
+ RT_ASSERT(vdev != RT_NULL);
+ RT_ASSERT(vdev->trans != RT_NULL);
- if (dev->queues != RT_NULL)
+ if (!vdev->trans->get_status(vdev, &status))
{
- dev->queues_num = queues_num;
-
- return RT_EOK;
+ return (status & RT_BIT(status_bit)) != 0;
}
- return -RT_ENOMEM;
+ return RT_FALSE;
}
-void virtio_queues_free(struct virtio_device *dev)
+rt_bool_t rt_virtio_has_feature(struct rt_virtio_device *vdev, rt_uint32_t feature_bit)
{
- if (dev->queues != RT_NULL)
- {
- dev->queues_num = 0;
- rt_free(dev->queues);
- }
+ RT_ASSERT(vdev != RT_NULL);
+
+ return (vdev->features & RT_BIT(feature_bit)) != 0;
}
-rt_err_t virtio_queue_init(struct virtio_device *dev, rt_uint32_t queue_index, rt_size_t ring_size)
+rt_err_t rt_virtio_get_config(struct rt_virtio_device *vdev, rt_uint32_t offset, void *dst, int length)
{
- int i;
- void *pages;
- rt_size_t pages_total_size;
- struct virtq *queue;
+ RT_ASSERT(vdev != RT_NULL);
+ RT_ASSERT(vdev->trans != RT_NULL);
- _virtio_dev_check(dev);
+ return vdev->trans->get_config(vdev, offset, dst, length);
+}
- RT_ASSERT(queue_index < dev->queues_num);
- /* ring_size is power of 2 */
- RT_ASSERT(ring_size > 0);
- RT_ASSERT(((ring_size - 1) & ring_size) == 0);
+rt_err_t rt_virtio_set_config(struct rt_virtio_device *vdev, rt_uint32_t offset, const void *src, int length)
+{
+ RT_ASSERT(vdev != RT_NULL);
+ RT_ASSERT(vdev->trans != RT_NULL);
- /* Select the queue first, then read queue_num_max */
- dev->mmio_config->queue_sel = queue_index;
- RT_ASSERT(dev->mmio_config->queue_num_max > 0);
- RT_ASSERT(ring_size <= dev->mmio_config->queue_num_max);
+ return vdev->trans->set_config(vdev, offset, src, length);
+}
- queue = &dev->queues[queue_index];
- pages_total_size = VIRTIO_PAGE_ALIGN(
- VIRTQ_DESC_TOTAL_SIZE(ring_size) + VIRTQ_AVAIL_TOTAL_SIZE(ring_size)) + VIRTQ_USED_TOTAL_SIZE(ring_size);
+rt_err_t rt_virtio_virtqueue_install(struct rt_virtio_device *vdev, int vqs_nr,
+ struct rt_virtqueue *vqs[], const char *names[], rt_virtqueue_callback cbs[])
+{
+ RT_ASSERT(vdev != RT_NULL);
+ RT_ASSERT(vdev->trans != RT_NULL);
+ RT_ASSERT(vqs_nr >= 0);
+ RT_ASSERT(vqs != RT_NULL);
+ RT_ASSERT(names != RT_NULL);
+ RT_ASSERT(cbs != RT_NULL);
- pages = rt_malloc_align(pages_total_size, VIRTIO_PAGE_SIZE);
+ return vdev->trans->install_vqs(vdev, vqs_nr, vqs, names, cbs);
+}
- if (pages == RT_NULL)
- {
- return -RT_ENOMEM;
- }
+rt_err_t rt_virtio_virtqueue_release(struct rt_virtio_device *vdev)
+{
+ RT_ASSERT(vdev != RT_NULL);
+ RT_ASSERT(vdev->trans != RT_NULL);
- queue->free = rt_malloc(sizeof(rt_bool_t) * ring_size);
+ return vdev->trans->release_vqs(vdev);
+}
- if (queue->free == RT_NULL)
- {
- rt_free_align(pages);
- return -RT_ENOMEM;
- }
+rt_err_t rt_virtio_virtqueue_control(struct rt_virtio_device *vdev, rt_uint32_t cfg, void *data)
+{
+ RT_ASSERT(vdev != RT_NULL);
+ RT_ASSERT(vdev->trans != RT_NULL);
- rt_memset(pages, 0, pages_total_size);
+ return vdev->trans->control_vqs(vdev, cfg, data);
+}
- dev->mmio_config->guest_page_size = VIRTIO_PAGE_SIZE;
- dev->mmio_config->queue_num = ring_size;
- dev->mmio_config->queue_align = VIRTIO_PAGE_SIZE;
- dev->mmio_config->queue_pfn = VIRTIO_VA2PA(pages) >> VIRTIO_PAGE_SHIFT;
+static const char *const virtio_device_id_name[] =
+{
+ [VIRTIO_DEVICE_ID_INVALID] = "invalid",
+ [VIRTIO_DEVICE_ID_NET] = "net",
+ [VIRTIO_DEVICE_ID_BLOCK] = "blk",
+ [VIRTIO_DEVICE_ID_CONSOLE] = "console",
+ [VIRTIO_DEVICE_ID_RNG] = "rng",
+ [VIRTIO_DEVICE_ID_RPMSG] = "rpmsg",
+ [VIRTIO_DEVICE_ID_SCSI] = "scsi",
+ [VIRTIO_DEVICE_ID_9P] = "9p",
+ [VIRTIO_DEVICE_ID_RPROC_SERIAL] = "rproc-serial",
+ [VIRTIO_DEVICE_ID_GPU] = "gpu",
+ [VIRTIO_DEVICE_ID_INPUT] = "input",
+ [VIRTIO_DEVICE_ID_CRYPTO] = "crypto",
+ [VIRTIO_DEVICE_ID_IOMMU] = "iommu",
+ [VIRTIO_DEVICE_ID_AUDIO] = "sound",
+ [VIRTIO_DEVICE_ID_SCMI] = "scmi",
- queue->num = ring_size;
- queue->desc = (struct virtq_desc *)((rt_ubase_t)pages);
- queue->avail = (struct virtq_avail *)(((rt_ubase_t)pages) + VIRTQ_DESC_TOTAL_SIZE(ring_size));
- queue->used = (struct virtq_used *)VIRTIO_PAGE_ALIGN(
- (rt_ubase_t)&queue->avail->ring[ring_size] + VIRTQ_AVAIL_RES_SIZE);
+ [VIRTIO_DEVICE_ID_MAX] = RT_NULL,
+};
- queue->used_idx = 0;
+const char *rt_virtio_device_id_name(struct rt_virtio_device *vdev)
+{
+ int device;
+ const char *name = RT_NULL;
- /* All descriptors start out unused */
- for (i = 0; i < ring_size; ++i)
- {
- queue->free[i] = RT_TRUE;
- }
+ RT_ASSERT(vdev != RT_NULL);
- queue->free_count = ring_size;
+ device = vdev->id.device;
- return RT_EOK;
-}
+ if (device < RT_ARRAY_SIZE(virtio_device_id_name))
+ {
+ name = virtio_device_id_name[device];
-void virtio_queue_destroy(struct virtio_device *dev, rt_uint32_t queue_index)
-{
- struct virtq *queue;
+ if (!name)
+ {
+ name = "nosys";
+ }
- _virtio_dev_check(dev);
+ return name;
+ }
- RT_ASSERT(queue_index < dev->queues_num);
+ return name;
+}
- /* Select the queue first, then read queue_num_max */
- dev->mmio_config->queue_sel = queue_index;
- RT_ASSERT(dev->mmio_config->queue_num_max > 0);
+static struct rt_bus virtio_bus;
- queue = &dev->queues[queue_index];
+rt_err_t rt_virtio_driver_register(struct rt_virtio_driver *vdrv)
+{
+ const struct rt_virtio_device_id *id;
- RT_ASSERT(queue->num > 0);
+ RT_ASSERT(vdrv != RT_NULL);
- rt_free(queue->free);
- rt_free_align((void *)queue->desc);
+ id = vdrv->ids;
+ while (id->device && (id + 1)->device)
+ {
+ ++id;
+ }
- dev->mmio_config->queue_pfn = RT_NULL;
+ vdrv->parent.bus = &virtio_bus;
+#if RT_NAME_MAX > 0
+ rt_strcpy(vdrv->parent.parent.name, virtio_device_id_name[id->device]);
+#else
+ vdrv->parent.parent.name = virtio_device_id_name[id->device];
+#endif
- queue->num = 0;
- queue->desc = RT_NULL;
- queue->avail = RT_NULL;
- queue->used = RT_NULL;
+ return rt_driver_register(&vdrv->parent);
}
-void virtio_queue_notify(struct virtio_device *dev, rt_uint32_t queue_index)
+static struct rt_dm_ida virtio_ida = RT_DM_IDA_INIT(CUSTOM);
+
+rt_err_t rt_virtio_device_register(struct rt_virtio_device *vdev)
{
- _virtio_dev_check(dev);
+ RT_ASSERT(vdev != RT_NULL);
+ RT_ASSERT(vdev->trans != RT_NULL);
- dev->mmio_config->queue_notify = queue_index;
-}
+ if ((vdev->idx = rt_dm_ida_alloc(&virtio_ida)) < 0)
+ {
+ return -RT_EFULL;
+ }
-void virtio_submit_chain(struct virtio_device *dev, rt_uint32_t queue_index, rt_uint16_t desc_index)
-{
- rt_size_t ring_size;
- struct virtq *queue;
+ rt_dm_dev_set_name(&vdev->parent, "virtio%u-%s", vdev->idx,
+ virtio_device_id_name[vdev->id.device]);
- _virtio_dev_check(dev);
+ rt_list_init(&vdev->vq_node);
- queue = &dev->queues[queue_index];
- ring_size = queue->num;
+ rt_spin_lock_init(&vdev->vq_lock);
- /* Tell the device the first index in our chain of descriptors */
- queue->avail->ring[queue->avail->idx % ring_size] = desc_index;
- rt_hw_dsb();
+ rt_virtio_device_reset(vdev);
+ rt_virtio_add_status(vdev, VIRTIO_STATUS_ACKNOWLEDGE);
- /* Tell the device another avail ring entry is available */
- queue->avail->idx++;
- rt_hw_dsb();
+ return rt_bus_add_device(&virtio_bus, &vdev->parent);
}
-rt_uint16_t virtio_alloc_desc(struct virtio_device *dev, rt_uint32_t queue_index)
+static rt_bool_t virtio_match(rt_driver_t drv, rt_device_t dev)
{
- int i;
- struct virtq *queue;
+ const struct rt_virtio_device_id *id;
+ struct rt_virtio_driver *vdrv = rt_container_of(drv, struct rt_virtio_driver, parent);
+ struct rt_virtio_device *vdev = rt_container_of(dev, struct rt_virtio_device, parent);
- _virtio_dev_check(dev);
-
- RT_ASSERT(queue_index < dev->queues_num);
-
- queue = &dev->queues[queue_index];
-
- if (queue->free_count > 0)
+ for (id = vdrv->ids; id->device; ++id)
{
- rt_size_t ring_size = queue->num;
-
- for (i = 0; i < ring_size; ++i)
+ if (id->device != vdev->id.device && id->device != VIRTIO_DEVICE_ANY_ID)
{
- if (queue->free[i])
- {
- queue->free[i] = RT_FALSE;
- queue->free_count--;
+ continue;
+ }
- return (rt_uint16_t)i;
- }
+ if (id->vendor == VIRTIO_DEVICE_ANY_ID || id->vendor == vdev->id.vendor)
+ {
+ return RT_TRUE;
}
}
- return VIRTQ_INVALID_DESC_ID;
+ return RT_FALSE;
}
-void virtio_free_desc(struct virtio_device *dev, rt_uint32_t queue_index, rt_uint16_t desc_index)
+static rt_err_t virtio_probe(rt_device_t dev)
{
- struct virtq *queue;
-
- _virtio_dev_check(dev);
+ rt_err_t err;
+ rt_uint8_t status;
+ rt_uint64_t device_features, driver_features;
+ struct rt_virtio_driver *vdrv = rt_container_of(dev->drv, struct rt_virtio_driver, parent);
+ struct rt_virtio_device *vdev = rt_container_of(dev, struct rt_virtio_device, parent);
- queue = &dev->queues[queue_index];
+ rt_virtio_add_status(vdev, VIRTIO_STATUS_DRIVER);
- RT_ASSERT(queue_index < dev->queues_num);
- RT_ASSERT(!queue->free[desc_index]);
+ vdev->trans->get_features(vdev, &device_features);
- queue->desc[desc_index].addr = 0;
- queue->desc[desc_index].len = 0;
- queue->desc[desc_index].flags = 0;
- queue->desc[desc_index].next = 0;
+ driver_features = vdrv->features;
- queue->free[desc_index] = RT_TRUE;
-
- queue->free_count++;
-}
+ for (int i = VIRTIO_TRANSPORT_F_START; i <= VIRTIO_TRANSPORT_F_END; ++i)
+ {
+ rt_uint64_t flag = RT_BIT_ULL(i);
-rt_err_t virtio_alloc_desc_chain(struct virtio_device *dev, rt_uint32_t queue_index, rt_size_t count,
- rt_uint16_t *indexs)
-{
- int i, j;
+ if (device_features & flag)
+ {
+ driver_features |= flag;
+ }
+ }
- _virtio_dev_check(dev);
+ vdev->features = driver_features & device_features;
- RT_ASSERT(indexs != RT_NULL);
+ err = vdev->trans->set_features(vdev);
- if (dev->queues[queue_index].free_count < count)
+ if (err)
{
- return -RT_ERROR;
+ goto _err;
}
- for (i = 0; i < count; ++i)
+ if (rt_virtio_has_feature(vdev, VIRTIO_F_VERSION_1))
{
- indexs[i] = virtio_alloc_desc(dev, queue_index);
+ rt_virtio_add_status(vdev, VIRTIO_STATUS_FEATURES_OK);
+ vdev->trans->get_status(vdev, &status);
- if (indexs[i] == VIRTQ_INVALID_DESC_ID)
+ if (!(status & VIRTIO_STATUS_FEATURES_OK))
{
- for (j = 0; j < i; ++j)
- {
- virtio_free_desc(dev, queue_index, indexs[j]);
- }
+ LOG_E("%s device refuses features: %x", rt_dm_dev_get_name(dev), status);
- return -RT_ERROR;
+ err = -RT_EIO;
+ goto _err;
}
}
- return RT_EOK;
-}
-
-void virtio_free_desc_chain(struct virtio_device *dev, rt_uint32_t queue_index, rt_uint16_t desc_index)
-{
- rt_uint16_t flags, next;
- struct virtq_desc *desc;
-
- _virtio_dev_check(dev);
+ err = vdrv->probe(vdev);
- desc = &dev->queues[queue_index].desc[0];
-
- for (;;)
+ if (err)
{
- flags = desc[desc_index].flags;
- next = desc[desc_index].next;
-
- virtio_free_desc(dev, queue_index, desc_index);
-
- if (flags & VIRTQ_DESC_F_NEXT)
- {
- desc_index = next;
- }
- else
- {
- break;
- }
+ goto _err;
}
-}
-
-void virtio_fill_desc(struct virtio_device *dev, rt_uint32_t queue_index, rt_uint16_t desc_index,
- rt_uint64_t addr, rt_uint32_t len, rt_uint16_t flags, rt_uint16_t next)
-{
- struct virtq_desc *desc;
-
- _virtio_dev_check(dev);
- desc = &dev->queues[queue_index].desc[desc_index];
+ vdev->trans->get_status(vdev, &status);
- desc->addr = addr;
- desc->len = len;
- desc->flags = flags;
- desc->next = next;
-}
-
-#ifdef RT_USING_SMART
-#ifdef RT_USING_VIRTIO_GPU
+ if (!(status & VIRTIO_STATUS_DRIVER_OK))
+ {
+ rt_virtio_device_ready(vdev);
+ }
-#include <virtio_gpu.h>
-#include "drivers/lcd.h"
-#include <dfs_file.h>
-#include <lwp_user_mm.h>
+ return RT_EOK;
-static struct rt_device_graphic_info _graphic_info;
-static struct rt_device_rect_info _rect_info;
-static struct rt_device _fb = {};
-static rt_device_t _gpu_dev = RT_NULL;
+_err:
+ rt_virtio_add_status(vdev, VIRTIO_STATUS_FAILED);
-static rt_err_t fb_open(rt_device_t dev, rt_uint16_t oflag)
-{
- return RT_EOK;
+ return err;
}
-static rt_err_t fb_close(rt_device_t dev)
+static rt_err_t virtio_remove(rt_device_t dev)
{
- return RT_EOK;
-}
+ struct rt_virtio_driver *vdrv = rt_container_of(dev->drv, struct rt_virtio_driver, parent);
+ struct rt_virtio_device *vdev = rt_container_of(dev, struct rt_virtio_device, parent);
-static rt_err_t fb_control(rt_device_t dev, int cmd, void *args)
-{
- switch(cmd)
+ if (vdrv && vdrv->remove)
{
- case FBIOPAN_DISPLAY:
- {
- rt_hw_cpu_dcache_clean(_graphic_info.framebuffer, _graphic_info.smem_len);
- rt_device_control(_gpu_dev, RTGRAPHIC_CTRL_RECT_UPDATE, &_rect_info);
- break;
- }
- case FBIOGET_FSCREENINFO:
- {
- struct fb_fix_screeninfo *info = (struct fb_fix_screeninfo *)args;
- strncpy(info->id, "lcd", sizeof(info->id));
- info->smem_len = _graphic_info.smem_len;
- break;
- }
- case FBIOGET_VSCREENINFO:
- {
- struct fb_var_screeninfo *info = (struct fb_var_screeninfo *)args;
- info->bits_per_pixel = _graphic_info.bits_per_pixel;
- info->xres = _graphic_info.width;
- info->yres = _graphic_info.height;
- info->yres_virtual = _graphic_info.height;
- info->xres_virtual = _graphic_info.width;
- info->transp.offset = 24;
- info->transp.length = 8;
- info->red.offset = 0;
- info->red.length = 8;
- info->green.offset = 8;
- info->green.length = 8;
- info->blue.offset = 16;
- info->blue.length = 8;
- break;
- }
- case RT_FIOMMAP2:
- {
- struct dfs_mmap2_args *mmap2 = (struct dfs_mmap2_args *)args;
+ vdrv->remove(vdev);
+ }
- if(mmap2)
- {
- mmap2->ret = lwp_map_user_phy(lwp_self(), RT_NULL, rt_kmem_v2p(_graphic_info.framebuffer), mmap2->length, 1);
- }
- else
- {
- return -EIO;
- }
+ rt_virtio_add_status(vdev, VIRTIO_STATUS_ACKNOWLEDGE);
- break;
- }
- default:
- break;
- }
+ rt_dm_ida_free(&virtio_ida, vdev->idx);
return RT_EOK;
}
-#ifdef RT_USING_DEVICE_OPS
-const static struct rt_device_ops fb_ops =
+static struct rt_bus virtio_bus =
{
- RT_NULL,
- fb_open,
- fb_close,
- RT_NULL,
- RT_NULL,
- fb_control
+ .name = "virtio",
+ .match = virtio_match,
+ .probe = virtio_probe,
+ .remove = virtio_remove,
};
-#endif
-static int fb_init()
+static int virtio_bus_init(void)
{
- _gpu_dev = rt_device_find("virtio-gpu0");
-
- if(_gpu_dev == RT_NULL)
- {
- return -RT_ERROR;
- }
-
- if(_gpu_dev != RT_NULL && rt_device_open(_gpu_dev, 0) == RT_EOK)
- {
- rt_memset(&_graphic_info, 0, sizeof(_graphic_info));
- rt_memset(&_rect_info, 0, sizeof(_rect_info));
- rt_device_control(_gpu_dev, VIRTIO_DEVICE_CTRL_GPU_SET_PRIMARY, RT_NULL);
- rt_device_control(_gpu_dev, VIRTIO_DEVICE_CTRL_GPU_CREATE_2D, (void *)RTGRAPHIC_PIXEL_FORMAT_RGB888);
- rt_device_control(_gpu_dev, RTGRAPHIC_CTRL_GET_INFO, &_graphic_info);
- _rect_info.x = 0;
- _rect_info.y = 0;
- _rect_info.width = _graphic_info.width;
- _rect_info.height = _graphic_info.height;
- memset(_graphic_info.framebuffer, 0xff, _graphic_info.smem_len);
- rt_device_control(_gpu_dev, RTGRAPHIC_CTRL_RECT_UPDATE, &_rect_info);
- }
-
- if(rt_device_find("fb0") != RT_NULL)
- {
- rt_kprintf("a device named fb0 already exists\n");
- return -RT_ERROR;
- }
+ rt_bus_register(&virtio_bus);
- _fb.type = RT_Device_Class_Miscellaneous;
-
-#ifdef RT_USING_DEVICE_OPS
- _fb.ops = &fb_ops;
-#else
- _fb.init = RT_NULL;
- _fb.open = fb_open;
- _fb.close = fb_close;
- _fb.read = RT_NULL;
- _fb.write = RT_NULL;
- _fb.control = fb_control;
- _fb.user_data = RT_NULL;
-#endif
-
- rt_device_register(&_fb, "fb0", RT_DEVICE_FLAG_RDWR);
- return RT_EOK;
+ return 0;
}
-INIT_COMPONENT_EXPORT(fb_init);
-#endif
-#endif
+INIT_CORE_EXPORT(virtio_bus_init);
diff --git a/components/drivers/virtio/virtio.h b/components/drivers/virtio/virtio.h
deleted file mode 100644
index 3807585d82..0000000000
--- a/components/drivers/virtio/virtio.h
+++ /dev/null
@@ -1,155 +0,0 @@
-/*
- * Copyright (c) 2006-2023, RT-Thread Development Team
- *
- * SPDX-License-Identifier: Apache-2.0
- *
- * Change Logs:
- * Date Author Notes
- * 2021-9-16 GuEe-GUI the first version
- * 2021-11-11 GuEe-GUI modify to virtio common interface
- */
-
-#ifndef __VIRTIO_H__
-#define __VIRTIO_H__
-
-#include <rthw.h>
-#include <rtdef.h>
-
-#ifdef RT_USING_SMART
-#include <mmu.h>
-#include <ioremap.h>
-#endif
-
-#if RT_NAME_MAX < 16
-#error "Please set RT_NAME_MAX to at lest 16"
-#endif
-
-#ifdef RT_USING_VIRTIO10
-#define RT_USING_VIRTIO_VERSION 0x1
-#endif
-
-#include <virtio_mmio.h>
-#include <virtio_queue.h>
-
-#define VIRTIO_MAGIC_VALUE 0x74726976 /* "virt" */
-
-#define VIRTIO_STATUS_ACKNOWLEDGE (1 << 0)
-#define VIRTIO_STATUS_DRIVER (1 << 1)
-#define VIRTIO_STATUS_DRIVER_OK (1 << 2)
-#define VIRTIO_STATUS_FEATURES_OK (1 << 3)
-#define VIRTIO_STATUS_NEEDS_RESET (1 << 6)
-#define VIRTIO_STATUS_FAILED (1 << 7)
-
-#define VIRTIO_F_NOTIFY_ON_EMPTY 24
-#define VIRTIO_F_ANY_LAYOUT 27
-#define VIRTIO_F_RING_INDIRECT_DESC 28
-#define VIRTIO_F_RING_EVENT_IDX 29
-#define VIRTIO_F_VERSION_1 32
-#define VIRTIO_F_RING_PACKED 34
-
-#ifdef RT_USING_SMART
-#define VIRTIO_VA2PA(vaddr) ((rt_ubase_t)rt_kmem_v2p(vaddr))
-#define VIRTIO_PA2VA(paddr) ((rt_ubase_t)rt_ioremap((void *)paddr, ARCH_PAGE_SIZE))
-#else
-#define VIRTIO_VA2PA(vaddr) ((rt_ubase_t)vaddr)
-#define VIRTIO_PA2VA(paddr) ((rt_ubase_t)paddr)
-#endif /* RT_USING_SMART */
-#define VIRTIO_PAGE_SHIFT 12
-#define VIRTIO_PAGE_SIZE (1 << VIRTIO_PAGE_SHIFT)
-#define VIRTIO_PAGE_ALIGN(addr) (RT_ALIGN(addr, VIRTIO_PAGE_SIZE))
-
-enum
-{
- /* virtio 1.0 */
- VIRTIO_DEVICE_ID_INVALID = 0, /* Invalid device */
- VIRTIO_DEVICE_ID_NET = 1, /* Net */
- VIRTIO_DEVICE_ID_BLOCK = 2, /* Block */
- VIRTIO_DEVICE_ID_CONSOLE = 3, /* Console */
- VIRTIO_DEVICE_ID_RNG = 4, /* Rng */
- VIRTIO_DEVICE_ID_BALLOON = 5, /* Balloon */
- VIRTIO_DEVICE_ID_IOMEM = 6, /* IO memory */
- VIRTIO_DEVICE_ID_RPMSG = 7, /* Remote processor messaging */
- VIRTIO_DEVICE_ID_SCSI = 8, /* SCSI */
- VIRTIO_DEVICE_ID_9P = 9, /* 9p console */
- VIRTIO_DEVICE_ID_MAC80211_WLAN = 10, /* Mac80211 wlan */
- VIRTIO_DEVICE_ID_RPROC_SERIAL = 11, /* Remoteproc serial link */
- VIRTIO_DEVICE_ID_CAIF = 12, /* CAIF */
- VIRTIO_DEVICE_ID_MEM_BALLOON = 13, /* Memory balloon */
- VIRTIO_DEVICE_ID_GPU = 16, /* GPU */
- VIRTIO_DEVICE_ID_TIME = 17, /* Timer/clock device */
- VIRTIO_DEVICE_ID_INPUT = 18, /* Input */
- /* virtio 1.1 */
- VIRTIO_DEVICE_ID_SOCKET = 19, /* Socket device */
- VIRTIO_DEVICE_ID_CRYPTO = 20, /* Crypto device */
- VIRTIO_DEVICE_ID_SIG_DIS_MOD = 21, /* Signal Distribution Module */
- VIRTIO_DEVICE_ID_PSTORE = 22, /* Pstore device */
- VIRTIO_DEVICE_ID_IOMMU = 23, /* IOMMU device */
- VIRTIO_DEVICE_ID_MEM = 24, /* Memory device */
- /* virtio 1.2 */
- VIRTIO_DEVICE_ID_AUDIO = 25, /* Audio device */
- VIRTIO_DEVICE_ID_FS = 26, /* File system device */
- VIRTIO_DEVICE_ID_PMEM = 27, /* PMEM device */
- VIRTIO_DEVICE_ID_RPMB = 28, /* RPMB device */
- VIRTIO_DEVICE_ID_MAC80211_HWSIM = 29, /* Mac80211 hwsim wireless simulation device */
- VIRTIO_DEVICE_ID_VIDEO_ENCODER = 30, /* Video encoder device */
- VIRTIO_DEVICE_ID_VIDEO_DECODER = 31, /* Video decoder device */
- VIRTIO_DEVICE_ID_SCMI = 32, /* SCMI device */
- VIRTIO_DEVICE_ID_NITRO_SEC_MOD = 33, /* NitroSecureModule */
- VIRTIO_DEVICE_ID_I2C_ADAPTER = 34, /* I2C adapter */
- VIRTIO_DEVICE_ID_WATCHDOG = 35, /* Watchdog */
- VIRTIO_DEVICE_ID_CAN = 36, /* CAN device */
- VIRTIO_DEVICE_ID_DMABUF = 37, /* Virtio dmabuf */
- VIRTIO_DEVICE_ID_PARAM_SERV = 38, /* Parameter Server */
- VIRTIO_DEVICE_ID_AUDIO_POLICY = 39, /* Audio policy device */
- VIRTIO_DEVICE_ID_BT = 40, /* Bluetooth device */
- VIRTIO_DEVICE_ID_GPIO = 41, /* GPIO device */
- VIRTIO_DEVICE_ID_RDMA = 42, /* RDMA device */
-
- VIRTIO_DEVICE_TYPE_SIZE
-};
-
-struct virtio_device
-{
- rt_uint32_t irq;
-
- struct virtq *queues;
- rt_size_t queues_num;
-
- union
- {
- rt_ubase_t *mmio_base;
- struct virtio_mmio_config *mmio_config;
- };
-
-#ifdef RT_USING_SMP
- struct rt_spinlock spinlock;
-#endif
-
- void *priv;
-};
-
-typedef rt_err_t (*virtio_device_init_handler)(rt_ubase_t *mmio_base, rt_uint32_t irq);
-
-void virtio_reset_device(struct virtio_device *dev);
-void virtio_status_acknowledge_driver(struct virtio_device *dev);
-void virtio_status_driver_ok(struct virtio_device *dev);
-void virtio_interrupt_ack(struct virtio_device *dev);
-rt_bool_t virtio_has_feature(struct virtio_device *dev, rt_uint32_t feature_bit);
-
-rt_err_t virtio_queues_alloc(struct virtio_device *dev, rt_size_t queues_num);
-void virtio_queues_free(struct virtio_device *dev);
-rt_err_t virtio_queue_init(struct virtio_device *dev, rt_uint32_t queue_index, rt_size_t ring_size);
-void virtio_queue_destroy(struct virtio_device *dev, rt_uint32_t queue_index);
-void virtio_queue_notify(struct virtio_device *dev, rt_uint32_t queue_index);
-
-void virtio_submit_chain(struct virtio_device *dev, rt_uint32_t queue_index, rt_uint16_t desc_index);
-
-rt_uint16_t virtio_alloc_desc(struct virtio_device *dev, rt_uint32_t queue_index);
-void virtio_free_desc(struct virtio_device *dev, rt_uint32_t queue_index, rt_uint16_t desc_index);
-rt_err_t virtio_alloc_desc_chain(struct virtio_device *dev, rt_uint32_t queue_index, rt_size_t count,
- rt_uint16_t *indexs);
-void virtio_free_desc_chain(struct virtio_device *dev, rt_uint32_t queue_index, rt_uint16_t desc_index);
-void virtio_fill_desc(struct virtio_device *dev, rt_uint32_t queue_index, rt_uint16_t desc_index,
- rt_uint64_t addr, rt_uint32_t len, rt_uint16_t flags, rt_uint16_t next);
-
-#endif /* __VIRTIO_H__ */
diff --git a/components/drivers/virtio/virtio_blk.c b/components/drivers/virtio/virtio_blk.c
deleted file mode 100644
index 4161e5907b..0000000000
--- a/components/drivers/virtio/virtio_blk.c
+++ /dev/null
@@ -1,254 +0,0 @@
-/*
- * Copyright (c) 2006-2023, RT-Thread Development Team
- *
- * SPDX-License-Identifier: Apache-2.0
- *
- * Change Logs:
- * Date Author Notes
- * 2021-9-16 GuEe-GUI the first version
- * 2021-11-11 GuEe-GUI using virtio common interface
- */
-
-#include <rthw.h>
-#include <rtthread.h>
-#include <cpuport.h>
-#include <rtdevice.h>
-
-#ifdef RT_USING_VIRTIO_BLK
-
-#include <virtio_blk.h>
-
-static void virtio_blk_rw(struct virtio_blk_device *virtio_blk_dev, rt_off_t pos, void *buffer, rt_size_t count,
- int flags)
-{
- rt_uint16_t idx[3];
- rt_size_t size = count * virtio_blk_dev->config->blk_size;
- struct virtio_device *virtio_dev = &virtio_blk_dev->virtio_dev;
-
-#ifdef RT_USING_SMP
- rt_base_t level = rt_spin_lock_irqsave(&virtio_dev->spinlock);
-#endif
-
- /* Allocate 3 descriptors */
- while (virtio_alloc_desc_chain(virtio_dev, 0, 3, idx))
- {
-#ifdef RT_USING_SMP
- rt_spin_unlock_irqrestore(&virtio_dev->spinlock, level);
-#endif
- rt_thread_yield();
-
-#ifdef RT_USING_SMP
- level = rt_spin_lock_irqsave(&virtio_dev->spinlock);
-#endif
- }
-
- virtio_blk_dev->info[idx[0]].status = 0xff;
- virtio_blk_dev->info[idx[0]].valid = RT_TRUE;
- virtio_blk_dev->info[idx[0]].req.type = flags;
- virtio_blk_dev->info[idx[0]].req.ioprio = 0;
- virtio_blk_dev->info[idx[0]].req.sector = pos * (virtio_blk_dev->config->blk_size / 512);
-
- flags = flags == VIRTIO_BLK_T_OUT ? 0 : VIRTQ_DESC_F_WRITE;
-
- virtio_fill_desc(virtio_dev, VIRTIO_BLK_QUEUE, idx[0],
- VIRTIO_VA2PA(&virtio_blk_dev->info[idx[0]].req), sizeof(struct virtio_blk_req), VIRTQ_DESC_F_NEXT, idx[1]);
-
- virtio_fill_desc(virtio_dev, VIRTIO_BLK_QUEUE, idx[1],
- VIRTIO_VA2PA(buffer), size, flags | VIRTQ_DESC_F_NEXT, idx[2]);
-
- virtio_fill_desc(virtio_dev, VIRTIO_BLK_QUEUE, idx[2],
- VIRTIO_VA2PA(&virtio_blk_dev->info[idx[0]].status), sizeof(rt_uint8_t), VIRTQ_DESC_F_WRITE, 0);
-
- virtio_submit_chain(virtio_dev, VIRTIO_BLK_QUEUE, idx[0]);
-
- virtio_queue_notify(virtio_dev, VIRTIO_BLK_QUEUE);
-
- /* Wait for virtio_blk_isr() to done */
- while (virtio_blk_dev->info[idx[0]].valid)
- {
-#ifdef RT_USING_SMP
- rt_spin_unlock_irqrestore(&virtio_dev->spinlock, level);
-#endif
- rt_thread_yield();
-
-#ifdef RT_USING_SMP
- level = rt_spin_lock_irqsave(&virtio_dev->spinlock);
-#endif
- }
-
- virtio_free_desc_chain(virtio_dev, VIRTIO_BLK_QUEUE, idx[0]);
-
-#ifdef RT_USING_SMP
- rt_spin_unlock_irqrestore(&virtio_dev->spinlock, level);
-#endif
-}
-
-static rt_ssize_t virtio_blk_read(rt_device_t dev, rt_off_t pos, void *buffer, rt_size_t count)
-{
- virtio_blk_rw((struct virtio_blk_device *)dev, pos, buffer, count, VIRTIO_BLK_T_IN);
-
- return count;
-}
-
-static rt_ssize_t virtio_blk_write(rt_device_t dev, rt_off_t pos, const void *buffer, rt_size_t count)
-{
- virtio_blk_rw((struct virtio_blk_device *)dev, pos, (void *)buffer, count, VIRTIO_BLK_T_OUT);
-
- return count;
-}
-
-static rt_err_t virtio_blk_control(rt_device_t dev, int cmd, void *args)
-{
- rt_err_t status = RT_EOK;
- struct virtio_blk_device *virtio_blk_dev = (struct virtio_blk_device *)dev;
-
- switch (cmd)
- {
- case RT_DEVICE_CTRL_BLK_GETGEOME:
- {
- struct rt_device_blk_geometry *geometry = (struct rt_device_blk_geometry *)args;
-
- if (geometry == RT_NULL)
- {
- status = -RT_ERROR;
- break;
- }
-
- geometry->bytes_per_sector = VIRTIO_BLK_BYTES_PER_SECTOR;
- geometry->block_size = virtio_blk_dev->config->blk_size;
- geometry->sector_count = virtio_blk_dev->config->capacity;
- }
- break;
- default:
- status = -RT_EINVAL;
- break;
- }
-
- return status;
-}
-
-#ifdef RT_USING_DEVICE_OPS
-const static struct rt_device_ops virtio_blk_ops =
-{
- RT_NULL,
- RT_NULL,
- RT_NULL,
- virtio_blk_read,
- virtio_blk_write,
- virtio_blk_control
-};
-#endif
-
-static void virtio_blk_isr(int irqno, void *param)
-{
- rt_uint32_t id;
- struct virtio_blk_device *virtio_blk_dev = (struct virtio_blk_device *)param;
- struct virtio_device *virtio_dev = &virtio_blk_dev->virtio_dev;
- struct virtq *queue = &virtio_dev->queues[VIRTIO_BLK_QUEUE];
-
-#ifdef RT_USING_SMP
- rt_base_t level = rt_spin_lock_irqsave(&virtio_dev->spinlock);
-#endif
-
- virtio_interrupt_ack(virtio_dev);
- rt_hw_dsb();
-
- /* The device increments disk.used->idx when it adds an entry to the used ring */
- while (queue->used_idx != queue->used->idx)
- {
- rt_hw_dsb();
- id = queue->used->ring[queue->used_idx % queue->num].id;
-
- RT_ASSERT(virtio_blk_dev->info[id].status == 0);
-
- /* Done with buffer */
- virtio_blk_dev->info[id].valid = RT_FALSE;
-
- queue->used_idx++;
- }
-
-#ifdef RT_USING_SMP
- rt_spin_unlock_irqrestore(&virtio_dev->spinlock, level);
-#endif
-}
-
-rt_err_t rt_virtio_blk_init(rt_ubase_t *mmio_base, rt_uint32_t irq)
-{
- static int dev_no = 0;
- char dev_name[RT_NAME_MAX];
- struct virtio_device *virtio_dev;
- struct virtio_blk_device *virtio_blk_dev;
-
- virtio_blk_dev = rt_malloc(sizeof(struct virtio_blk_device));
-
- if (virtio_blk_dev == RT_NULL)
- {
- return -RT_ENOMEM;
- }
-
- virtio_dev = &virtio_blk_dev->virtio_dev;
- virtio_dev->irq = irq;
- virtio_dev->mmio_base = mmio_base;
-
- virtio_blk_dev->config = (struct virtio_blk_config *)virtio_dev->mmio_config->config;
-
-#ifdef RT_USING_SMP
- rt_spin_lock_init(&virtio_dev->spinlock);
-#endif
-
- virtio_reset_device(virtio_dev);
- virtio_status_acknowledge_driver(virtio_dev);
-
- /* Negotiate features */
- virtio_dev->mmio_config->driver_features = virtio_dev->mmio_config->device_features & ~(
- (1 << VIRTIO_BLK_F_RO) |
- (1 << VIRTIO_BLK_F_MQ) |
- (1 << VIRTIO_BLK_F_SCSI) |
- (1 << VIRTIO_BLK_F_CONFIG_WCE) |
- (1 << VIRTIO_F_ANY_LAYOUT) |
- (1 << VIRTIO_F_RING_EVENT_IDX) |
- (1 << VIRTIO_F_RING_INDIRECT_DESC));
-
- /* Tell device that feature negotiation is complete and we're completely ready */
- virtio_status_driver_ok(virtio_dev);
-
- if (virtio_queues_alloc(virtio_dev, 1) != RT_EOK)
- {
- goto _alloc_fail;
- }
-
- /* Initialize queue 0 */
- if (virtio_queue_init(virtio_dev, 0, VIRTIO_BLK_QUEUE_RING_SIZE) != RT_EOK)
- {
- goto _alloc_fail;
- }
-
- virtio_blk_dev->parent.type = RT_Device_Class_Block;
-#ifdef RT_USING_DEVICE_OPS
- virtio_blk_dev->parent.ops = &virtio_blk_ops;
-#else
- virtio_blk_dev->parent.init = RT_NULL;
- virtio_blk_dev->parent.open = RT_NULL;
- virtio_blk_dev->parent.close = RT_NULL;
- virtio_blk_dev->parent.read = virtio_blk_read;
- virtio_blk_dev->parent.write = virtio_blk_write;
- virtio_blk_dev->parent.control = virtio_blk_control;
-#endif
-
- rt_snprintf(dev_name, RT_NAME_MAX, "virtio-blk%d", dev_no++);
-
- rt_hw_interrupt_install(irq, virtio_blk_isr, virtio_blk_dev, dev_name);
- rt_hw_interrupt_umask(irq);
-
- return rt_device_register((rt_device_t)virtio_blk_dev, dev_name, RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_REMOVABLE);
-
-_alloc_fail:
-
- if (virtio_blk_dev != RT_NULL)
- {
- virtio_queues_free(virtio_dev);
- rt_free(virtio_blk_dev);
- }
- return -RT_ENOMEM;
-}
-#endif /* RT_USING_VIRTIO_BLK */
diff --git a/components/drivers/virtio/virtio_blk.h b/components/drivers/virtio/virtio_blk.h
deleted file mode 100644
index 21ac7a1c85..0000000000
--- a/components/drivers/virtio/virtio_blk.h
+++ /dev/null
@@ -1,105 +0,0 @@
-/*
- * Copyright (c) 2006-2023, RT-Thread Development Team
- *
- * SPDX-License-Identifier: Apache-2.0
- *
- * Change Logs:
- * Date Author Notes
- * 2021-9-16 GuEe-GUI the first version
- * 2021-11-11 GuEe-GUI using virtio common interface
- */
-
-#ifndef __VIRTIO_BLK_H__
-#define __VIRTIO_BLK_H__
-
-#include <rtdef.h>
-
-#include <virtio.h>
-
-#define VIRTIO_BLK_QUEUE 0
-#define VIRTIO_BLK_BYTES_PER_SECTOR 512
-#define VIRTIO_BLK_QUEUE_RING_SIZE 4
-
-#define VIRTIO_BLK_F_RO 5 /* Disk is read-only */
-#define VIRTIO_BLK_F_SCSI 7 /* Supports scsi command passthru */
-#define VIRTIO_BLK_F_CONFIG_WCE 11 /* Writeback mode available in config */
-#define VIRTIO_BLK_F_MQ 12 /* Support more than one vq */
-
-#define VIRTIO_BLK_T_IN 0 /* Read the blk */
-#define VIRTIO_BLK_T_OUT 1 /* Write the blk */
-#define VIRTIO_BLK_T_SCSI_CMD 2
-#define VIRTIO_BLK_T_SCSI_CMD_OUT 3
-#define VIRTIO_BLK_T_FLUSH 4
-#define VIRTIO_BLK_T_FLUSH_OUT 5
-
-struct virtio_blk_req
-{
- rt_uint32_t type;
- rt_uint32_t ioprio;
- rt_uint64_t sector;
-};
-
-struct virtio_blk_config
-{
- rt_uint64_t capacity; /* The capacity (in 512-byte sectors). */
- rt_uint32_t size_max; /* The maximum segment size (if VIRTIO_BLK_F_SIZE_MAX) */
- rt_uint32_t seg_max; /* The maximum number of segments (if VIRTIO_BLK_F_SEG_MAX) */
-
- /* Geometry of the device (if VIRTIO_BLK_F_GEOMETRY) */
- struct virtio_blk_geometry
- {
- rt_uint16_t cylinders;
- rt_uint8_t heads;
- rt_uint8_t sectors;
- } geometry;
-
- rt_uint32_t blk_size; /* Block size of device (if VIRTIO_BLK_F_BLK_SIZE) */
-
- struct virtio_blk_topology
- {
- /* # Of logical blocks per physical block (log2) */
- rt_uint8_t physical_block_exp;
- /* Offset of first aligned logical block */
- rt_uint8_t alignment_offset;
- /* Suggested minimum I/O size in blocks */
- rt_uint16_t min_io_size;
- /* Optimal (suggested maximum) I/O size in blocks */
- rt_uint32_t opt_io_size;
- } topology;
-
- rt_uint8_t writeback;
- rt_uint8_t unused0;
- rt_uint16_t num_queues;
- rt_uint32_t max_discard_sectors;
- rt_uint32_t max_discard_seg;
- rt_uint32_t discard_sector_alignment;
- rt_uint32_t max_write_zeroes_sectors;
- rt_uint32_t max_write_zeroes_seg;
- rt_uint8_t write_zeroes_may_unmap;
- rt_uint8_t unused1[3];
- rt_uint32_t max_secure_erase_sectors;
- rt_uint32_t max_secure_erase_seg;
- rt_uint32_t secure_erase_sector_alignment;
-} __attribute__((packed));
-
-struct virtio_blk_device
-{
- struct rt_device parent;
-
- struct virtio_device virtio_dev;
-
- struct virtio_blk_config *config;
-
- struct
- {
- rt_bool_t valid;
- rt_uint8_t status;
-
- struct virtio_blk_req req;
-
- } info[VIRTIO_BLK_QUEUE_RING_SIZE];
-};
-
-rt_err_t rt_virtio_blk_init(rt_ubase_t *mmio_base, rt_uint32_t irq);
-
-#endif /* __VIRTIO_BLK_H__ */
diff --git a/components/drivers/virtio/virtio_config/virtio-9p.h b/components/drivers/virtio/virtio_config/virtio-9p.h
new file mode 100644
index 0000000000..be870d9984
--- /dev/null
+++ b/components/drivers/virtio/virtio_config/virtio-9p.h
@@ -0,0 +1,26 @@
+/*
+ * 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_9P_H__
+#define __VIRTIO_9P_H__
+
+#include <drivers/core/dm.h>
+
+#define VIRTIO_9P_F_MOUNT_TAG 0
+
+rt_packed(struct virtio_9p_config
+{
+ /* length of the tag name */
+ rt_le16_t tag_len;
+ /* non-NULL terminated tag name */
+ rt_uint8_t tag[];
+});
+
+#endif /* __VIRTIO_9P_H__ */
diff --git a/components/drivers/virtio/virtio_config/virtio-blk.h b/components/drivers/virtio/virtio_config/virtio-blk.h
new file mode 100644
index 0000000000..045aa78087
--- /dev/null
+++ b/components/drivers/virtio/virtio_config/virtio-blk.h
@@ -0,0 +1,129 @@
+/*
+ * Copyright (c) 2006-2023, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date Author Notes
+ * 2021-9-16 GuEe-GUI the first version
+ * 2021-11-11 GuEe-GUI using virtio common interface
+ * 2023-02-25 GuEe-GUI using virtio dm
+ */
+
+#ifndef __VIRTIO_BLK_H__
+#define __VIRTIO_BLK_H__
+
+#include <drivers/core/dm.h>
+
+#define VIRTIO_BLK_F_SIZE_MAX 1 /* Indicates maximum segment size */
+#define VIRTIO_BLK_F_SEG_MAX 2 /* Indicates maximum # of segments */
+#define VIRTIO_BLK_F_GEOMETRY 4 /* Legacy geometry available */
+#define VIRTIO_BLK_F_RO 5 /* Disk is read-only */
+#define VIRTIO_BLK_F_BLK_SIZE 6 /* Block size of disk is available*/
+#define VIRTIO_BLK_F_SCSI 7 /* Supports scsi command passthru */
+#define VIRTIO_BLK_F_FLUSH 9 /* Flush command supported */
+#define VIRTIO_BLK_F_TOPOLOGY 10 /* Topology information is available */
+#define VIRTIO_BLK_F_CONFIG_WCE 11 /* Writeback mode available in config */
+#define VIRTIO_BLK_F_MQ 12 /* Support more than one vq */
+#define VIRTIO_BLK_F_DISCARD 13 /* DISCARD is supported */
+#define VIRTIO_BLK_F_WRITE_ZEROES 14 /* WRITE ZEROES is supported */
+#define VIRTIO_BLK_F_SECURE_ERASE 16 /* Secure Erase is supported */
+
+#define VIRTIO_BLK_T_IN 0 /* Read the blk */
+#define VIRTIO_BLK_T_OUT 1 /* Write the blk */
+#define VIRTIO_BLK_T_SCSI_CMD 2
+#define VIRTIO_BLK_T_SCSI_CMD_OUT 3
+#define VIRTIO_BLK_T_FLUSH 4
+#define VIRTIO_BLK_T_FLUSH_OUT 5
+#define VIRTIO_BLK_T_GET_ID 8 /* Get device ID command */
+#define VIRTIO_BLK_T_DISCARD 11 /* Discard command */
+#define VIRTIO_BLK_T_WRITE_ZEROES 13 /* Write zeroes command */
+#define VIRTIO_BLK_T_SECURE_ERASE 14 /* Secure erase command */
+#define VIRTIO_BLK_T_ZONE_APPEND 15 /* Zone append command */
+#define VIRTIO_BLK_T_ZONE_REPORT 16 /* Report zones command */
+#define VIRTIO_BLK_T_ZONE_OPEN 18 /* Open zone command */
+#define VIRTIO_BLK_T_ZONE_CLOSE 20 /* Close zone command */
+#define VIRTIO_BLK_T_ZONE_FINISH 22 /* Finish zone command */
+#define VIRTIO_BLK_T_ZONE_RESET 24 /* Reset zone command */
+#define VIRTIO_BLK_T_ZONE_RESET_ALL 26 /* Reset All zones command */
+
+struct virtio_blk_req
+{
+ rt_le32_t type;
+ rt_le32_t ioprio;
+ rt_le64_t sector;
+
+#define VIRTIO_BLK_S_OK 0
+#define VIRTIO_BLK_S_IOERR 1
+#define VIRTIO_BLK_S_UNSUPP 2
+#define VIRTIO_BLK_S_ZONE_INVALID_CMD 3
+#define VIRTIO_BLK_S_ZONE_UNALIGNED_WP 4
+#define VIRTIO_BLK_S_ZONE_OPEN_RESOURCE 5
+#define VIRTIO_BLK_S_ZONE_ACTIVE_RESOURCE 6
+ /*
+ * next:
+ * rt_uint8_t data[];
+ * rt_uint8_t status;
+ */
+};
+
+struct virtio_blk_discard_write_zeroes
+{
+ rt_le64_t sector;
+ rt_le32_t num_sectors;
+
+ /*
+ * unmap:1
+ * reserved:31
+ */
+ rt_le32_t flags;
+};
+
+rt_packed(struct virtio_blk_config
+{
+ /* The capacity (in 512-byte sectors). */
+ rt_le64_t capacity;
+ /* The maximum segment size (if VIRTIO_BLK_F_SIZE_MAX) */
+ rt_le32_t size_max;
+ /* The maximum number of segments (if VIRTIO_BLK_F_SEG_MAX) */
+ rt_le32_t seg_max;
+
+ /* Geometry of the device (if VIRTIO_BLK_F_GEOMETRY) */
+ struct virtio_blk_geometry
+ {
+ rt_le16_t cylinders;
+ rt_uint8_t heads;
+ rt_uint8_t sectors;
+ } geometry;
+
+ /* Block size of device (if VIRTIO_BLK_F_BLK_SIZE) */
+ rt_le32_t blk_size;
+
+ struct virtio_blk_topology
+ {
+ /* # Of logical blocks per physical block (log2) */
+ rt_uint8_t physical_block_exp;
+ /* Offset of first aligned logical block */
+ rt_uint8_t alignment_offset;
+ /* Suggested minimum I/O size in blocks */
+ rt_le16_t min_io_size;
+ /* Optimal (suggested maximum) I/O size in blocks */
+ rt_le32_t opt_io_size;
+ } topology;
+
+ rt_uint8_t writeback;
+ rt_uint8_t unused0;
+ rt_uint16_t num_queues;
+ rt_le32_t max_discard_sectors;
+ rt_le32_t max_discard_seg;
+ rt_le32_t discard_sector_alignment;
+ rt_le32_t max_write_zeroes_sectors;
+ rt_le32_t max_write_zeroes_seg;
+ rt_uint8_t write_zeroes_may_unmap;
+ rt_uint8_t unused1[3];
+ rt_le32_t max_secure_erase_sectors;
+ rt_le32_t max_secure_erase_seg;
+ rt_le32_t secure_erase_sector_alignment;
+});
+
+#endif /* __VIRTIO_BLK_H__ */
diff --git a/components/drivers/virtio/virtio_config/virtio-console.h b/components/drivers/virtio/virtio_config/virtio-console.h
new file mode 100644
index 0000000000..cf51ab41a4
--- /dev/null
+++ b/components/drivers/virtio/virtio_config/virtio-console.h
@@ -0,0 +1,63 @@
+/*
+ * Copyright (c) 2006-2023, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date Author Notes
+ * 2021-11-11 GuEe-GUI the first version
+ * 2023-02-25 GuEe-GUI using virtio dm
+ */
+
+#ifndef __VIRTIO_CONSOLE_H__
+#define __VIRTIO_CONSOLE_H__
+
+#include <drivers/core/dm.h>
+
+#define VIRTIO_CONSOLE_F_SIZE 0 /* Does host provide console size? */
+#define VIRTIO_CONSOLE_F_MULTIPORT 1 /* Does host provide multiple ports? */
+#define VIRTIO_CONSOLE_F_EMERG_WRITE 2 /* Does host support emergency write? */
+
+rt_packed(struct virtio_console_config
+{
+ rt_le16_t cols;
+ rt_le16_t rows;
+ rt_le32_t max_nr_ports;
+ rt_le32_t emerg_wr;
+});
+
+rt_packed(struct virtio_console_resize
+{
+ rt_le16_t cols;
+ rt_le16_t rows;
+});
+
+rt_packed(struct virtio_console_control
+{
+#define VIRTIO_CONSOLE_BAD_ID (~(rt_uint32_t)0)
+ rt_le32_t id; /* Port number */
+
+#define VIRTIO_CONSOLE_DEVICE_READY 0
+#define VIRTIO_CONSOLE_PORT_ADD 1
+#define VIRTIO_CONSOLE_PORT_REMOVE 2
+#define VIRTIO_CONSOLE_PORT_READY 3
+#define VIRTIO_CONSOLE_CONSOLE_PORT 4
+#define VIRTIO_CONSOLE_RESIZE 5
+#define VIRTIO_CONSOLE_PORT_OPEN 6
+#define VIRTIO_CONSOLE_PORT_NAME 7
+ rt_le16_t event; /* The kind of control event */
+ rt_le16_t value; /* Extra information for the event */
+});
+
+rt_packed(struct virtio_console_control_ext
+{
+ struct virtio_console_control ctrl;
+
+ union
+ {
+ struct virtio_console_resize resize;
+ rt_uint8_t data[64];
+ };
+});
+
+#endif /* __VIRTIO_CONSOLE_H__ */
diff --git a/components/drivers/virtio/virtio_config/virtio-crypto.h b/components/drivers/virtio/virtio_config/virtio-crypto.h
new file mode 100644
index 0000000000..49df7ef96c
--- /dev/null
+++ b/components/drivers/virtio/virtio_config/virtio-crypto.h
@@ -0,0 +1,527 @@
+/*
+ * 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_CRYPTO_H__
+#define __VIRTIO_CRYPTO_H__
+
+#include <drivers/core/dm.h>
+
+#define VIRTIO_CRYPTO_SERVICE_CIPHER 0
+#define VIRTIO_CRYPTO_SERVICE_HASH 1
+#define VIRTIO_CRYPTO_SERVICE_MAC 2
+#define VIRTIO_CRYPTO_SERVICE_AEAD 3
+#define VIRTIO_CRYPTO_SERVICE_AKCIPHER 4
+
+#define VIRTIO_CRYPTO_OPCODE(service, op) (((VIRTIO_CRYPTO_SERVICE_##service) << 8) | (op))
+
+struct virtio_crypto_ctrl_header
+{
+#define VIRTIO_CRYPTO_CIPHER_CREATE_SESSION VIRTIO_CRYPTO_OPCODE(CIPHER, 0x02)
+#define VIRTIO_CRYPTO_CIPHER_DESTROY_SESSION VIRTIO_CRYPTO_OPCODE(CIPHER, 0x03)
+#define VIRTIO_CRYPTO_HASH_CREATE_SESSION VIRTIO_CRYPTO_OPCODE(HASH, 0x02)
+#define VIRTIO_CRYPTO_HASH_DESTROY_SESSION VIRTIO_CRYPTO_OPCODE(HASH, 0x03)
+#define VIRTIO_CRYPTO_MAC_CREATE_SESSION VIRTIO_CRYPTO_OPCODE(MAC, 0x02)
+#define VIRTIO_CRYPTO_MAC_DESTROY_SESSION VIRTIO_CRYPTO_OPCODE(MAC, 0x03)
+#define VIRTIO_CRYPTO_AEAD_CREATE_SESSION VIRTIO_CRYPTO_OPCODE(AEAD, 0x02)
+#define VIRTIO_CRYPTO_AEAD_DESTROY_SESSION VIRTIO_CRYPTO_OPCODE(AEAD, 0x03)
+#define VIRTIO_CRYPTO_AKCIPHER_CREATE_SESSION VIRTIO_CRYPTO_OPCODE(AKCIPHER, 0x04)
+#define VIRTIO_CRYPTO_AKCIPHER_DESTROY_SESSION VIRTIO_CRYPTO_OPCODE(AKCIPHER, 0x05)
+ rt_le32_t opcode;
+ rt_le32_t algo;
+ rt_le32_t flag;
+ /* data virtqueue id */
+ rt_le32_t queue_id;
+};
+
+struct virtio_crypto_cipher_session_para
+{
+#define VIRTIO_CRYPTO_NO_CIPHER 0
+#define VIRTIO_CRYPTO_CIPHER_ARC4 1
+#define VIRTIO_CRYPTO_CIPHER_AES_ECB 2
+#define VIRTIO_CRYPTO_CIPHER_AES_CBC 3
+#define VIRTIO_CRYPTO_CIPHER_AES_CTR 4
+#define VIRTIO_CRYPTO_CIPHER_DES_ECB 5
+#define VIRTIO_CRYPTO_CIPHER_DES_CBC 6
+#define VIRTIO_CRYPTO_CIPHER_3DES_ECB 7
+#define VIRTIO_CRYPTO_CIPHER_3DES_CBC 8
+#define VIRTIO_CRYPTO_CIPHER_3DES_CTR 9
+#define VIRTIO_CRYPTO_CIPHER_KASUMI_F8 10
+#define VIRTIO_CRYPTO_CIPHER_SNOW3G_UEA2 11
+#define VIRTIO_CRYPTO_CIPHER_AES_F8 12
+#define VIRTIO_CRYPTO_CIPHER_AES_XTS 13
+#define VIRTIO_CRYPTO_CIPHER_ZUC_EEA3 14
+ rt_le32_t algo;
+ /* length of key */
+ rt_le32_t keylen;
+
+#define VIRTIO_CRYPTO_OP_ENCRYPT 1
+#define VIRTIO_CRYPTO_OP_DECRYPT 2
+ /* encrypt or decrypt */
+ rt_le32_t op;
+ rt_le32_t padding;
+};
+
+struct virtio_crypto_session_input
+{
+ /* Device-writable part */
+ rt_le64_t session_id;
+ rt_le32_t status;
+ rt_le32_t padding;
+};
+
+struct virtio_crypto_cipher_session_req
+{
+ struct virtio_crypto_cipher_session_para para;
+ rt_uint8_t padding[32];
+};
+
+struct virtio_crypto_hash_session_para
+{
+#define VIRTIO_CRYPTO_NO_HASH 0
+#define VIRTIO_CRYPTO_HASH_MD5 1
+#define VIRTIO_CRYPTO_HASH_SHA1 2
+#define VIRTIO_CRYPTO_HASH_SHA_224 3
+#define VIRTIO_CRYPTO_HASH_SHA_256 4
+#define VIRTIO_CRYPTO_HASH_SHA_384 5
+#define VIRTIO_CRYPTO_HASH_SHA_512 6
+#define VIRTIO_CRYPTO_HASH_SHA3_224 7
+#define VIRTIO_CRYPTO_HASH_SHA3_256 8
+#define VIRTIO_CRYPTO_HASH_SHA3_384 9
+#define VIRTIO_CRYPTO_HASH_SHA3_512 10
+#define VIRTIO_CRYPTO_HASH_SHA3_SHAKE128 11
+#define VIRTIO_CRYPTO_HASH_SHA3_SHAKE256 12
+ rt_le32_t algo;
+ /* hash result length */
+ rt_le32_t hash_result_len;
+ rt_uint8_t padding[8];
+};
+
+struct virtio_crypto_hash_create_session_req
+{
+ struct virtio_crypto_hash_session_para para;
+ rt_uint8_t padding[40];
+};
+
+struct virtio_crypto_mac_session_para
+{
+#define VIRTIO_CRYPTO_NO_MAC 0
+#define VIRTIO_CRYPTO_MAC_HMAC_MD5 1
+#define VIRTIO_CRYPTO_MAC_HMAC_SHA1 2
+#define VIRTIO_CRYPTO_MAC_HMAC_SHA_224 3
+#define VIRTIO_CRYPTO_MAC_HMAC_SHA_256 4
+#define VIRTIO_CRYPTO_MAC_HMAC_SHA_384 5
+#define VIRTIO_CRYPTO_MAC_HMAC_SHA_512 6
+#define VIRTIO_CRYPTO_MAC_CMAC_3DES 25
+#define VIRTIO_CRYPTO_MAC_CMAC_AES 26
+#define VIRTIO_CRYPTO_MAC_KASUMI_F9 27
+#define VIRTIO_CRYPTO_MAC_SNOW3G_UIA2 28
+#define VIRTIO_CRYPTO_MAC_GMAC_AES 41
+#define VIRTIO_CRYPTO_MAC_GMAC_TWOFISH 42
+#define VIRTIO_CRYPTO_MAC_CBCMAC_AES 49
+#define VIRTIO_CRYPTO_MAC_CBCMAC_KASUMI_F9 50
+#define VIRTIO_CRYPTO_MAC_XCBC_AES 53
+ rt_le32_t algo;
+ /* hash result length */
+ rt_le32_t hash_result_len;
+ /* length of authenticated key */
+ rt_le32_t auth_key_len;
+ rt_le32_t padding;
+};
+
+struct virtio_crypto_mac_create_session_req
+{
+ struct virtio_crypto_mac_session_para para;
+ rt_uint8_t padding[40];
+};
+
+struct virtio_crypto_aead_session_para
+{
+#define VIRTIO_CRYPTO_NO_AEAD 0
+#define VIRTIO_CRYPTO_AEAD_GCM 1
+#define VIRTIO_CRYPTO_AEAD_CCM 2
+#define VIRTIO_CRYPTO_AEAD_CHACHA20_POLY1305 3
+ rt_le32_t algo;
+ /* length of key */
+ rt_le32_t key_len;
+ /* hash result length */
+ rt_le32_t hash_result_len;
+ /* length of the additional authenticated data (AAD) in bytes */
+ rt_le32_t aad_len;
+ /* encrypt or decrypt, See above VIRTIO_CRYPTO_OP_* */
+ rt_le32_t op;
+ rt_le32_t padding;
+};
+
+struct virtio_crypto_aead_create_session_req
+{
+ struct virtio_crypto_aead_session_para para;
+ rt_uint8_t padding[32];
+};
+
+struct virtio_crypto_rsa_session_para
+{
+#define VIRTIO_CRYPTO_RSA_RAW_PADDING 0
+#define VIRTIO_CRYPTO_RSA_PKCS1_PADDING 1
+ rt_le32_t padding_algo;
+
+#define VIRTIO_CRYPTO_RSA_NO_HASH 0
+#define VIRTIO_CRYPTO_RSA_MD2 1
+#define VIRTIO_CRYPTO_RSA_MD3 2
+#define VIRTIO_CRYPTO_RSA_MD4 3
+#define VIRTIO_CRYPTO_RSA_MD5 4
+#define VIRTIO_CRYPTO_RSA_SHA1 5
+#define VIRTIO_CRYPTO_RSA_SHA256 6
+#define VIRTIO_CRYPTO_RSA_SHA384 7
+#define VIRTIO_CRYPTO_RSA_SHA512 8
+#define VIRTIO_CRYPTO_RSA_SHA224 9
+ rt_le32_t hash_algo;
+};
+
+struct virtio_crypto_ecdsa_session_para
+{
+#define VIRTIO_CRYPTO_CURVE_UNKNOWN 0
+#define VIRTIO_CRYPTO_CURVE_NIST_P192 1
+#define VIRTIO_CRYPTO_CURVE_NIST_P224 2
+#define VIRTIO_CRYPTO_CURVE_NIST_P256 3
+#define VIRTIO_CRYPTO_CURVE_NIST_P384 4
+#define VIRTIO_CRYPTO_CURVE_NIST_P521 5
+ rt_le32_t curve_id;
+ rt_le32_t padding;
+};
+
+struct virtio_crypto_akcipher_session_para
+{
+#define VIRTIO_CRYPTO_NO_AKCIPHER 0
+#define VIRTIO_CRYPTO_AKCIPHER_RSA 1
+#define VIRTIO_CRYPTO_AKCIPHER_DSA 2
+#define VIRTIO_CRYPTO_AKCIPHER_ECDSA 3
+ rt_le32_t algo;
+
+#define VIRTIO_CRYPTO_AKCIPHER_KEY_TYPE_PUBLIC 1
+#define VIRTIO_CRYPTO_AKCIPHER_KEY_TYPE_PRIVATE 2
+ rt_le32_t keytype;
+ rt_le32_t keylen;
+
+ union
+ {
+ struct virtio_crypto_rsa_session_para rsa;
+ struct virtio_crypto_ecdsa_session_para ecdsa;
+ };
+};
+
+struct virtio_crypto_akcipher_create_session_req
+{
+ struct virtio_crypto_akcipher_session_para para;
+ rt_uint8_t padding[36];
+};
+
+struct virtio_crypto_alg_chain_session_para
+{
+#define VIRTIO_CRYPTO_SYM_ALG_CHAIN_ORDER_HASH_THEN_CIPHER 1
+#define VIRTIO_CRYPTO_SYM_ALG_CHAIN_ORDER_CIPHER_THEN_HASH 2
+ rt_le32_t alg_chain_order;
+/* Plain hash */
+#define VIRTIO_CRYPTO_SYM_HASH_MODE_PLAIN 1
+/* Authenticated hash (mac) */
+#define VIRTIO_CRYPTO_SYM_HASH_MODE_AUTH 2
+/* Nested hash */
+#define VIRTIO_CRYPTO_SYM_HASH_MODE_NESTED 3
+ rt_le32_t hash_mode;
+ struct virtio_crypto_cipher_session_para cipher_param;
+ union
+ {
+ struct virtio_crypto_hash_session_para hash_param;
+ struct virtio_crypto_mac_session_para mac_param;
+ rt_uint8_t padding_union[16];
+ };
+ /* length of the additional authenticated data (AAD) in bytes */
+ rt_le32_t aad_len;
+ rt_le32_t padding;
+};
+
+struct virtio_crypto_alg_chain_session_req
+{
+ struct virtio_crypto_alg_chain_session_para para;
+};
+
+struct virtio_crypto_sym_create_session_req
+{
+ union
+ {
+ struct virtio_crypto_cipher_session_req cipher;
+ struct virtio_crypto_alg_chain_session_req chain;
+ rt_uint8_t padding_union[48];
+ };
+
+ /* Device-readable part */
+
+/* No operation */
+#define VIRTIO_CRYPTO_SYM_OP_NONE 0
+/* Cipher only operation on the data */
+#define VIRTIO_CRYPTO_SYM_OP_CIPHER 1
+/*
+ * Chain any cipher with any hash or mac operation. The order
+ * depends on the value of alg_chain_order param
+ */
+#define VIRTIO_CRYPTO_SYM_OP_ALGORITHM_CHAINING 2
+ rt_le32_t op_type;
+ rt_le32_t padding;
+};
+
+struct virtio_crypto_destroy_session_req
+{
+ /* Device-readable part */
+ rt_le64_t session_id;
+ rt_uint8_t padding[48];
+};
+
+/* The request of the control virtqueue's packet */
+struct virtio_crypto_op_ctrl_req
+{
+ struct virtio_crypto_ctrl_header header;
+
+ union
+ {
+ struct virtio_crypto_sym_create_session_req sym_create_session;
+ struct virtio_crypto_hash_create_session_req hash_create_session;
+ struct virtio_crypto_mac_create_session_req mac_create_session;
+ struct virtio_crypto_aead_create_session_req aead_create_session;
+ struct virtio_crypto_akcipher_create_session_req akcipher_create_session;
+ struct virtio_crypto_destroy_session_req destroy_session;
+ rt_uint8_t padding[56];
+ };
+};
+
+struct virtio_crypto_op_header
+{
+#define VIRTIO_CRYPTO_CIPHER_ENCRYPT VIRTIO_CRYPTO_OPCODE(CIPHER, 0x00)
+#define VIRTIO_CRYPTO_CIPHER_DECRYPT VIRTIO_CRYPTO_OPCODE(CIPHER, 0x01)
+#define VIRTIO_CRYPTO_HASH VIRTIO_CRYPTO_OPCODE(HASH, 0x00)
+#define VIRTIO_CRYPTO_MAC VIRTIO_CRYPTO_OPCODE(MAC, 0x00)
+#define VIRTIO_CRYPTO_AEAD_ENCRYPT VIRTIO_CRYPTO_OPCODE(AEAD, 0x00)
+#define VIRTIO_CRYPTO_AEAD_DECRYPT VIRTIO_CRYPTO_OPCODE(AEAD, 0x01)
+#define VIRTIO_CRYPTO_AKCIPHER_ENCRYPT VIRTIO_CRYPTO_OPCODE(AKCIPHER, 0x00)
+#define VIRTIO_CRYPTO_AKCIPHER_DECRYPT VIRTIO_CRYPTO_OPCODE(AKCIPHER, 0x01)
+#define VIRTIO_CRYPTO_AKCIPHER_SIGN VIRTIO_CRYPTO_OPCODE(AKCIPHER, 0x02)
+#define VIRTIO_CRYPTO_AKCIPHER_VERIFY VIRTIO_CRYPTO_OPCODE(AKCIPHER, 0x03)
+ rt_le32_t opcode;
+ /* algo should be service-specific algorithms */
+ rt_le32_t algo;
+ /* session_id should be service-specific algorithms */
+ rt_le64_t session_id;
+ /* control flag to control the request */
+ rt_le32_t flag;
+ rt_le32_t padding;
+};
+
+struct virtio_crypto_cipher_para
+{
+ /*
+ * Byte Length of valid IV/Counter
+ *
+ * For block ciphers in CBC or F8 mode, or for Kasumi in F8 mode, or for
+ * SNOW3G in UEA2 mode, this is the length of the IV (which
+ * must be the same as the block length of the cipher).
+ * For block ciphers in CTR mode, this is the length of the counter
+ * (which must be the same as the block length of the cipher).
+ * For AES-XTS, this is the 128bit tweak, i, from IEEE Std 1619-2007.
+ *
+ * The IV/Counter will be updated after every partial cryptographic
+ * operation.
+ */
+ rt_le32_t iv_len;
+ /* length of source data */
+ rt_le32_t src_data_len;
+ /* length of dst data */
+ rt_le32_t dst_data_len;
+ rt_le32_t padding;
+};
+
+struct virtio_crypto_hash_para
+{
+ /* length of source data */
+ rt_le32_t src_data_len;
+ /* hash result length */
+ rt_le32_t hash_result_len;
+};
+
+struct virtio_crypto_mac_para
+{
+ struct virtio_crypto_hash_para hash;
+};
+
+struct virtio_crypto_aead_para
+{
+ /*
+ * Byte Length of valid IV data pointed to by the below iv_addr
+ * parameter.
+ *
+ * For GCM mode, this is either 12 (for 96-bit IVs) or 16, in which
+ * case iv_addr points to J0.
+ * For CCM mode, this is the length of the nonce, which can be in the
+ * range 7 to 13 inclusive.
+ */
+ rt_le32_t iv_len;
+ /* length of additional auth data */
+ rt_le32_t aad_len;
+ /* length of source data */
+ rt_le32_t src_data_len;
+ /* length of dst data */
+ rt_le32_t dst_data_len;
+};
+
+struct virtio_crypto_cipher_data_req
+{
+ /* Device-readable part */
+ struct virtio_crypto_cipher_para para;
+ rt_uint8_t padding[24];
+};
+
+struct virtio_crypto_hash_data_req
+{
+ /* Device-readable part */
+ struct virtio_crypto_hash_para para;
+ rt_uint8_t padding[40];
+};
+
+struct virtio_crypto_mac_data_req
+{
+ /* Device-readable part */
+ struct virtio_crypto_mac_para para;
+ rt_uint8_t padding[40];
+};
+
+struct virtio_crypto_alg_chain_data_para
+{
+ rt_le32_t iv_len;
+ /* Length of source data */
+ rt_le32_t src_data_len;
+ /* Length of destination data */
+ rt_le32_t dst_data_len;
+ /* Starting point for cipher processing in source data */
+ rt_le32_t cipher_start_src_offset;
+ /* Length of the source data that the cipher will be computed on */
+ rt_le32_t len_to_cipher;
+ /* Starting point for hash processing in source data */
+ rt_le32_t hash_start_src_offset;
+ /* Length of the source data that the hash will be computed on */
+ rt_le32_t len_to_hash;
+ /* Length of the additional auth data */
+ rt_le32_t aad_len;
+ /* Length of the hash result */
+ rt_le32_t hash_result_len;
+ rt_le32_t reserved;
+};
+
+struct virtio_crypto_alg_chain_data_req
+{
+ /* Device-readable part */
+ struct virtio_crypto_alg_chain_data_para para;
+};
+
+struct virtio_crypto_sym_data_req
+{
+ union
+ {
+ struct virtio_crypto_cipher_data_req cipher;
+ struct virtio_crypto_alg_chain_data_req chain;
+ rt_uint8_t padding_union[40];
+ };
+
+ /* See above VIRTIO_CRYPTO_SYM_OP_* */
+ rt_le32_t op_type;
+ rt_le32_t padding;
+};
+
+struct virtio_crypto_aead_data_req
+{
+ /* Device-readable part */
+ struct virtio_crypto_aead_para para;
+ rt_uint8_t padding[32];
+};
+
+struct virtio_crypto_akcipher_para
+{
+ rt_le32_t src_data_len;
+ rt_le32_t dst_data_len;
+};
+
+struct virtio_crypto_akcipher_data_req
+{
+ struct virtio_crypto_akcipher_para para;
+ rt_uint8_t padding[40];
+};
+
+/* The request of the data virtqueue's packet */
+struct virtio_crypto_op_data_req
+{
+ struct virtio_crypto_op_header header;
+
+ union
+ {
+ struct virtio_crypto_sym_data_req sym_req;
+ struct virtio_crypto_hash_data_req hash_req;
+ struct virtio_crypto_mac_data_req mac_req;
+ struct virtio_crypto_aead_data_req aead_req;
+ struct virtio_crypto_akcipher_data_req akcipher_req;
+ rt_uint8_t padding[48];
+ };
+};
+
+#define VIRTIO_CRYPTO_OK 0
+#define VIRTIO_CRYPTO_ERR 1
+#define VIRTIO_CRYPTO_BADMSG 2
+#define VIRTIO_CRYPTO_NOTSUPP 3
+#define VIRTIO_CRYPTO_INVSESS 4 /* Invalid session id */
+#define VIRTIO_CRYPTO_NOSPC 5 /* no free session ID */
+#define VIRTIO_CRYPTO_KEY_REJECTED 6 /* Signature verification failed */
+
+/* The accelerator hardware is ready */
+#define VIRTIO_CRYPTO_S_HW_READY (1 << 0)
+
+struct virtio_crypto_config
+{
+ /* See VIRTIO_CRYPTO_OP_* above */
+ rt_le32_t status;
+
+ /*
+ * Maximum number of data queue
+ */
+ rt_le32_t max_dataqueues;
+
+ /*
+ * Specifies the services mask which the device support,
+ * see VIRTIO_CRYPTO_SERVICE_* above
+ */
+ rt_le32_t crypto_services;
+
+ /* Detailed algorithms mask */
+ rt_le32_t cipher_algo_l;
+ rt_le32_t cipher_algo_h;
+ rt_le32_t hash_algo;
+ rt_le32_t mac_algo_l;
+ rt_le32_t mac_algo_h;
+ rt_le32_t aead_algo;
+ /* Maximum length of cipher key */
+ rt_le32_t max_cipher_key_len;
+ /* Maximum length of authenticated key */
+ rt_le32_t max_auth_key_len;
+ rt_le32_t akcipher_algo;
+ /* Maximum size of each crypto request's content */
+ rt_le64_t max_size;
+};
+
+struct virtio_crypto_inhdr
+{
+ /* See VIRTIO_CRYPTO_* above */
+ rt_uint8_t status;
+};
+
+#endif /* __VIRTIO_CRYPTO_H__ */
diff --git a/components/drivers/virtio/virtio_config/virtio-gpu.h b/components/drivers/virtio/virtio_config/virtio-gpu.h
new file mode 100644
index 0000000000..20e2ca6d2e
--- /dev/null
+++ b/components/drivers/virtio/virtio_config/virtio-gpu.h
@@ -0,0 +1,499 @@
+/*
+ * Copyright (c) 2006-2023, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date Author Notes
+ * 2021-11-11 GuEe-GUI the first version
+ * 2023-02-25 GuEe-GUI using virtio dm
+ */
+
+#ifndef __VIRTIO_GPU_H__
+#define __VIRTIO_GPU_H__
+
+#include <drivers/core/dm.h>
+
+#define VIRTIO_GPU_F_VIRGL 0 /* VIRTIO_GPU_CMD_CTX_*, VIRTIO_GPU_CMD_*_3D */
+#define VIRTIO_GPU_F_EDID 1 /* VIRTIO_GPU_CMD_GET_EDID */
+#define VIRTIO_GPU_F_RESOURCE_UUID 2 /* VIRTIO_GPU_CMD_RESOURCE_ASSIGN_UUID */
+#define VIRTIO_GPU_F_RESOURCE_BLOB 3 /* VIRTIO_GPU_CMD_RESOURCE_CREATE_BLOB */
+#define VIRTIO_GPU_F_CONTEXT_INIT 4 /* VIRTIO_GPU_CMD_CREATE_CONTEXT with context_init and multiple timelines */
+
+enum virtio_gpu_ctrl_type
+{
+ VIRTIO_GPU_UNDEFINED = 0,
+
+ /* 2d commands */
+ VIRTIO_GPU_CMD_GET_DISPLAY_INFO = 0x0100,
+ VIRTIO_GPU_CMD_RESOURCE_CREATE_2D,
+ VIRTIO_GPU_CMD_RESOURCE_UNREF,
+ VIRTIO_GPU_CMD_SET_SCANOUT,
+ VIRTIO_GPU_CMD_RESOURCE_FLUSH,
+ VIRTIO_GPU_CMD_TRANSFER_TO_HOST_2D,
+ VIRTIO_GPU_CMD_RESOURCE_ATTACH_BACKING,
+ VIRTIO_GPU_CMD_RESOURCE_DETACH_BACKING,
+ VIRTIO_GPU_CMD_GET_CAPSET_INFO,
+ VIRTIO_GPU_CMD_GET_CAPSET,
+ VIRTIO_GPU_CMD_GET_EDID,
+ VIRTIO_GPU_CMD_RESOURCE_ASSIGN_UUID,
+ VIRTIO_GPU_CMD_RESOURCE_CREATE_BLOB,
+ VIRTIO_GPU_CMD_SET_SCANOUT_BLOB,
+
+ /* 3d commands */
+ VIRTIO_GPU_CMD_CTX_CREATE = 0x0200,
+ VIRTIO_GPU_CMD_CTX_DESTROY,
+ VIRTIO_GPU_CMD_CTX_ATTACH_RESOURCE,
+ VIRTIO_GPU_CMD_CTX_DETACH_RESOURCE,
+ VIRTIO_GPU_CMD_RESOURCE_CREATE_3D,
+ VIRTIO_GPU_CMD_TRANSFER_TO_HOST_3D,
+ VIRTIO_GPU_CMD_TRANSFER_FROM_HOST_3D,
+ VIRTIO_GPU_CMD_SUBMIT_3D,
+ VIRTIO_GPU_CMD_RESOURCE_MAP_BLOB,
+ VIRTIO_GPU_CMD_RESOURCE_UNMAP_BLOB,
+
+ /* cursor commands */
+ VIRTIO_GPU_CMD_UPDATE_CURSOR = 0x0300,
+ VIRTIO_GPU_CMD_MOVE_CURSOR,
+
+ /* success responses */
+ VIRTIO_GPU_RESP_OK_NODATA = 0x1100,
+ VIRTIO_GPU_RESP_OK_DISPLAY_INFO,
+ VIRTIO_GPU_RESP_OK_CAPSET_INFO,
+ VIRTIO_GPU_RESP_OK_CAPSET,
+ VIRTIO_GPU_RESP_OK_EDID,
+ VIRTIO_GPU_RESP_OK_RESOURCE_UUID,
+ VIRTIO_GPU_RESP_OK_MAP_INFO,
+
+ /* error responses */
+ VIRTIO_GPU_RESP_ERR_UNSPEC = 0x1200,
+ VIRTIO_GPU_RESP_ERR_OUT_OF_MEMORY,
+ VIRTIO_GPU_RESP_ERR_INVALID_SCANOUT_ID,
+ VIRTIO_GPU_RESP_ERR_INVALID_RESOURCE_ID,
+ VIRTIO_GPU_RESP_ERR_INVALID_CONTEXT_ID,
+ VIRTIO_GPU_RESP_ERR_INVALID_PARAMETER,
+};
+
+enum virtio_gpu_shm_id
+{
+ VIRTIO_GPU_SHM_ID_UNDEFINED = 0,
+ /*
+ * VIRTIO_GPU_CMD_RESOURCE_MAP_BLOB
+ * VIRTIO_GPU_CMD_RESOURCE_UNMAP_BLOB
+ */
+ VIRTIO_GPU_SHM_ID_HOST_VISIBLE = 1
+};
+
+#define VIRTIO_GPU_FLAG_FENCE (1 << 0)
+/*
+ * If the following flag is set, then ring_idx contains the index
+ * of the command ring that needs to used when creating the fence
+ */
+#define VIRTIO_GPU_FLAG_INFO_RING_IDX (1 << 1)
+
+struct virtio_gpu_ctrl_hdr
+{
+ /*
+ * specifies the type of the driver request (VIRTIO_GPU_CMD_*) or
+ * device response (VIRTIO_GPU_RESP_*).
+ */
+ rt_le32_t type;
+ /*
+ * request / response flags.
+ */
+ rt_le32_t flags;
+ /*
+ * If the driver sets the VIRTIO_GPU_FLAG_FENCE bit
+ * in the request flags field the device MUST:
+ * set VIRTIO_GPU_FLAG_FENCE bit in the response,
+ * copy the content of the fence_id field from the request to the response,
+ * and send the response only after command processing is complete.
+ */
+ rt_le64_t fence_id;
+ /*
+ * Rendering context (used in 3D mode only).
+ */
+ rt_le32_t ctx_id;
+ /*
+ * If VIRTIO_GPU_F_CONTEXT_INIT is supported,
+ * then the driver MAY set VIRTIO_GPU_FLAG_INFO_RING_IDX bit
+ * in the request flags. In that case:
+ * ring_idx indicates the value of a context-specific ring index.
+ * The minimum value is 0 and maximum value is 63 (inclusive).
+ * If VIRTIO_GPU_FLAG_FENCE is set, fence_id acts as a sequence number
+ * on the synchronization timeline defined by ctx_idx and the ring index.
+ * If VIRTIO_GPU_FLAG_FENCE is set and when the command associated
+ * with fence_id is complete, the device MUST send a response for
+ * all outstanding commands with a sequence number less than or
+ * equal to fence_id on the same synchronization timeline.
+ */
+ rt_uint8_t ring_idx;
+ rt_uint8_t padding[3];
+};
+
+/* data passed in the cursor vq */
+
+struct virtio_gpu_cursor_pos
+{
+ rt_le32_t scanout_id;
+ rt_le32_t x;
+ rt_le32_t y;
+ rt_le32_t padding;
+};
+
+/* VIRTIO_GPU_CMD_UPDATE_CURSOR, VIRTIO_GPU_CMD_MOVE_CURSOR */
+struct virtio_gpu_update_cursor
+{
+ struct virtio_gpu_ctrl_hdr hdr;
+ struct virtio_gpu_cursor_pos pos; /* update & move */
+ rt_le32_t resource_id; /* update only */
+ rt_le32_t hot_x; /* update only */
+ rt_le32_t hot_y; /* update only */
+ rt_le32_t padding;
+};
+
+/* data passed in the control vq, 2d related */
+
+struct virtio_gpu_rect
+{
+ rt_le32_t x;
+ rt_le32_t y;
+ rt_le32_t width;
+ rt_le32_t height;
+};
+
+/* VIRTIO_GPU_CMD_RESOURCE_UNREF */
+struct virtio_gpu_resource_unref
+{
+ struct virtio_gpu_ctrl_hdr hdr;
+ rt_le32_t resource_id;
+ rt_le32_t padding;
+};
+
+/* VIRTIO_GPU_CMD_RESOURCE_CREATE_2D: create a 2d resource with a format */
+struct virtio_gpu_resource_create_2d
+{
+ struct virtio_gpu_ctrl_hdr hdr;
+ rt_le32_t resource_id;
+ rt_le32_t format;
+ rt_le32_t width;
+ rt_le32_t height;
+};
+
+/* VIRTIO_GPU_CMD_SET_SCANOUT */
+struct virtio_gpu_set_scanout
+{
+ struct virtio_gpu_ctrl_hdr hdr;
+ struct virtio_gpu_rect r;
+ rt_le32_t scanout_id;
+ rt_le32_t resource_id;
+};
+
+/* VIRTIO_GPU_CMD_RESOURCE_FLUSH */
+struct virtio_gpu_resource_flush
+{
+ struct virtio_gpu_ctrl_hdr hdr;
+ struct virtio_gpu_rect r;
+ rt_le32_t resource_id;
+ rt_le32_t padding;
+};
+
+/* VIRTIO_GPU_CMD_TRANSFER_TO_HOST_2D: simple transfer to_host */
+struct virtio_gpu_transfer_to_host_2d
+{
+ struct virtio_gpu_ctrl_hdr hdr;
+ struct virtio_gpu_rect r;
+ rt_le64_t offset;
+ rt_le32_t resource_id;
+ rt_le32_t padding;
+};
+
+struct virtio_gpu_mem_entry
+{
+ rt_le64_t addr;
+ rt_le32_t length;
+ rt_le32_t padding;
+};
+
+/* VIRTIO_GPU_CMD_RESOURCE_ATTACH_BACKING */
+struct virtio_gpu_resource_attach_backing
+{
+ struct virtio_gpu_ctrl_hdr hdr;
+ rt_le32_t resource_id;
+ rt_le32_t nr_entries;
+};
+
+/* VIRTIO_GPU_CMD_RESOURCE_DETACH_BACKING */
+struct virtio_gpu_resource_detach_backing
+{
+ struct virtio_gpu_ctrl_hdr hdr;
+ rt_le32_t resource_id;
+ rt_le32_t padding;
+};
+
+/* VIRTIO_GPU_RESP_OK_DISPLAY_INFO */
+#define VIRTIO_GPU_MAX_SCANOUTS 16
+struct virtio_gpu_resp_display_info
+{
+ struct virtio_gpu_ctrl_hdr hdr;
+ struct virtio_gpu_display_one
+ {
+ struct virtio_gpu_rect r;
+ rt_le32_t enabled;
+ rt_le32_t flags;
+ } pmodes[VIRTIO_GPU_MAX_SCANOUTS];
+};
+
+/* data passed in the control vq, 3d related */
+
+struct virtio_gpu_box
+{
+ rt_le32_t x, y, z;
+ rt_le32_t w, h, d;
+};
+
+/* VIRTIO_GPU_CMD_TRANSFER_TO_HOST_3D, VIRTIO_GPU_CMD_TRANSFER_FROM_HOST_3D */
+struct virtio_gpu_transfer_host_3d
+{
+ struct virtio_gpu_ctrl_hdr hdr;
+ struct virtio_gpu_box box;
+ rt_le64_t offset;
+ rt_le32_t resource_id;
+ rt_le32_t level;
+ rt_le32_t stride;
+ rt_le32_t layer_stride;
+};
+
+/* VIRTIO_GPU_CMD_RESOURCE_CREATE_3D */
+#define VIRTIO_GPU_RESOURCE_FLAG_Y_0_TOP (1 << 0)
+struct virtio_gpu_resource_create_3d
+{
+ struct virtio_gpu_ctrl_hdr hdr;
+ rt_le32_t resource_id;
+ rt_le32_t target;
+ rt_le32_t format;
+ rt_le32_t bind;
+ rt_le32_t width;
+ rt_le32_t height;
+ rt_le32_t depth;
+ rt_le32_t array_size;
+ rt_le32_t last_level;
+ rt_le32_t nr_samples;
+ rt_le32_t flags;
+ rt_le32_t padding;
+};
+
+/* VIRTIO_GPU_CMD_CTX_CREATE */
+#define VIRTIO_GPU_CONTEXT_INIT_CAPSET_ID_MASK 0x000000ff
+struct virtio_gpu_ctx_create
+{
+ struct virtio_gpu_ctrl_hdr hdr;
+ rt_le32_t nlen;
+ rt_le32_t context_init;
+ char debug_name[64];
+};
+
+/* VIRTIO_GPU_CMD_CTX_DESTROY */
+struct virtio_gpu_ctx_destroy
+{
+ struct virtio_gpu_ctrl_hdr hdr;
+};
+
+/* VIRTIO_GPU_CMD_CTX_ATTACH_RESOURCE, VIRTIO_GPU_CMD_CTX_DETACH_RESOURCE */
+struct virtio_gpu_ctx_resource
+{
+ struct virtio_gpu_ctrl_hdr hdr;
+ rt_le32_t resource_id;
+ rt_le32_t padding;
+};
+
+/* VIRTIO_GPU_CMD_SUBMIT_3D */
+struct virtio_gpu_cmd_submit
+{
+ struct virtio_gpu_ctrl_hdr hdr;
+ rt_le32_t size;
+ rt_le32_t padding;
+};
+
+#define VIRTIO_GPU_CAPSET_VIRGL 1
+#define VIRTIO_GPU_CAPSET_VIRGL2 2
+#define VIRTIO_GPU_CAPSET_GFXSTREAM 3
+#define VIRTIO_GPU_CAPSET_VENUS 4
+#define VIRTIO_GPU_CAPSET_CROSS_DOMAIN 5
+
+/* VIRTIO_GPU_CMD_GET_CAPSET_INFO */
+struct virtio_gpu_get_capset_info
+{
+ struct virtio_gpu_ctrl_hdr hdr;
+ rt_le32_t capset_index;
+ rt_le32_t padding;
+};
+
+/* VIRTIO_GPU_RESP_OK_CAPSET_INFO */
+struct virtio_gpu_resp_capset_info
+{
+ struct virtio_gpu_ctrl_hdr hdr;
+ rt_le32_t capset_id;
+ rt_le32_t capset_max_version;
+ rt_le32_t capset_max_size;
+ rt_le32_t padding;
+};
+
+/* VIRTIO_GPU_CMD_GET_CAPSET */
+struct virtio_gpu_get_capset
+{
+ struct virtio_gpu_ctrl_hdr hdr;
+ rt_le32_t capset_id;
+ rt_le32_t capset_version;
+};
+
+/* VIRTIO_GPU_RESP_OK_CAPSET */
+struct virtio_gpu_resp_capset
+{
+ struct virtio_gpu_ctrl_hdr hdr;
+ rt_uint8_t capset_data[];
+};
+
+/* VIRTIO_GPU_CMD_GET_EDID */
+struct virtio_gpu_cmd_get_edid
+{
+ struct virtio_gpu_ctrl_hdr hdr;
+ rt_le32_t scanout;
+ rt_le32_t padding;
+};
+
+/* VIRTIO_GPU_RESP_OK_EDID */
+struct virtio_gpu_resp_edid
+{
+ struct virtio_gpu_ctrl_hdr hdr;
+ rt_le32_t size;
+ rt_le32_t padding;
+ rt_uint8_t edid[1024];
+};
+
+#define VIRTIO_GPU_EVENT_DISPLAY (1 << 0)
+
+struct virtio_gpu_config
+{
+ /*
+ * signals pending events to the driver.
+ * The driver MUST NOT write to this field.
+ */
+ rt_le32_t events_read;
+ /*
+ * clears pending events in the device.
+ * Writing a '1' into a bit will clear the corresponding bit in events_read,
+ * mimicking write-to-clear behavior.
+ */
+ rt_le32_t events_clear;
+ /*
+ * specifies the maximum number of scanouts supported by the device.
+ * Minimum value is 1, maximum value is 16.
+ */
+ rt_le32_t num_scanouts;
+ /*
+ * specifies the maximum number of capability sets supported by the device.
+ * The minimum value is zero.
+ */
+ rt_le32_t num_capsets;
+};
+
+/* simple formats for fbcon/X use */
+enum virtio_gpu_formats
+{
+ VIRTIO_GPU_FORMAT_B8G8R8A8_UNORM = 1,
+ VIRTIO_GPU_FORMAT_B8G8R8X8_UNORM = 2,
+ VIRTIO_GPU_FORMAT_A8R8G8B8_UNORM = 3,
+ VIRTIO_GPU_FORMAT_X8R8G8B8_UNORM = 4,
+
+ VIRTIO_GPU_FORMAT_R8G8B8A8_UNORM = 67,
+ VIRTIO_GPU_FORMAT_X8B8G8R8_UNORM = 68,
+
+ VIRTIO_GPU_FORMAT_A8B8G8R8_UNORM = 121,
+ VIRTIO_GPU_FORMAT_R8G8B8X8_UNORM = 134,
+};
+
+/* VIRTIO_GPU_CMD_RESOURCE_ASSIGN_UUID */
+struct virtio_gpu_resource_assign_uuid
+{
+ struct virtio_gpu_ctrl_hdr hdr;
+ rt_le32_t resource_id;
+ rt_le32_t padding;
+};
+
+/* VIRTIO_GPU_RESP_OK_RESOURCE_UUID */
+struct virtio_gpu_resp_resource_uuid
+{
+ struct virtio_gpu_ctrl_hdr hdr;
+ rt_uint8_t uuid[16];
+};
+
+/* VIRTIO_GPU_CMD_RESOURCE_CREATE_BLOB */
+struct virtio_gpu_resource_create_blob
+{
+ struct virtio_gpu_ctrl_hdr hdr;
+ rt_le32_t resource_id;
+#define VIRTIO_GPU_BLOB_MEM_GUEST 0x0001
+#define VIRTIO_GPU_BLOB_MEM_HOST3D 0x0002
+#define VIRTIO_GPU_BLOB_MEM_HOST3D_GUEST 0x0003
+
+#define VIRTIO_GPU_BLOB_FLAG_USE_MAPPABLE 0x0001
+#define VIRTIO_GPU_BLOB_FLAG_USE_SHAREABLE 0x0002
+#define VIRTIO_GPU_BLOB_FLAG_USE_CROSS_DEVICE 0x0004
+ /* zero is invalid blob mem */
+ rt_le32_t blob_mem;
+ rt_le32_t blob_flags;
+ rt_le32_t nr_entries;
+ rt_le64_t blob_id;
+ rt_le64_t size;
+ /*
+ * sizeof(nr_entries * virtio_gpu_mem_entry) bytes follow
+ */
+};
+
+/* VIRTIO_GPU_CMD_SET_SCANOUT_BLOB */
+struct virtio_gpu_set_scanout_blob
+{
+ struct virtio_gpu_ctrl_hdr hdr;
+ struct virtio_gpu_rect r;
+ rt_le32_t scanout_id;
+ rt_le32_t resource_id;
+ rt_le32_t width;
+ rt_le32_t height;
+ rt_le32_t format;
+ rt_le32_t padding;
+ rt_le32_t strides[4];
+ rt_le32_t offsets[4];
+};
+
+/* VIRTIO_GPU_CMD_RESOURCE_MAP_BLOB */
+struct virtio_gpu_resource_map_blob
+{
+ struct virtio_gpu_ctrl_hdr hdr;
+ rt_le32_t resource_id;
+ rt_le32_t padding;
+ rt_le64_t offset;
+};
+
+/* VIRTIO_GPU_RESP_OK_MAP_INFO */
+#define VIRTIO_GPU_MAP_CACHE_MASK 0x0f
+#define VIRTIO_GPU_MAP_CACHE_NONE 0x00
+#define VIRTIO_GPU_MAP_CACHE_CACHED 0x01
+#define VIRTIO_GPU_MAP_CACHE_UNCACHED 0x02
+#define VIRTIO_GPU_MAP_CACHE_WC 0x03
+struct virtio_gpu_resp_map_info
+{
+ struct virtio_gpu_ctrl_hdr hdr;
+ rt_uint32_t map_info;
+ rt_uint32_t padding;
+};
+
+/* VIRTIO_GPU_CMD_RESOURCE_UNMAP_BLOB */
+struct virtio_gpu_resource_unmap_blob
+{
+ struct virtio_gpu_ctrl_hdr hdr;
+ rt_le32_t resource_id;
+ rt_le32_t padding;
+};
+
+#endif /* __VIRTIO_GPU_H__ */
diff --git a/components/drivers/virtio/virtio_config/virtio-input.h b/components/drivers/virtio/virtio_config/virtio-input.h
new file mode 100644
index 0000000000..62c7c9953a
--- /dev/null
+++ b/components/drivers/virtio/virtio_config/virtio-input.h
@@ -0,0 +1,68 @@
+/*
+ * Copyright (c) 2006-2023, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date Author Notes
+ * 2021-11-11 GuEe-GUI the first version
+ * 2023-02-25 GuEe-GUI using virtio dm
+ */
+
+#ifndef __VIRTIO_INPUT_H__
+#define __VIRTIO_INPUT_H__
+
+#include <drivers/core/dm.h>
+
+enum virtio_input_config_select
+{
+ VIRTIO_INPUT_CFG_UNSET = 0x00,
+ VIRTIO_INPUT_CFG_ID_NAME = 0x01,
+ VIRTIO_INPUT_CFG_ID_SERIAL = 0x02,
+ VIRTIO_INPUT_CFG_ID_DEVIDS = 0x03,
+ VIRTIO_INPUT_CFG_PROP_BITS = 0x10,
+ VIRTIO_INPUT_CFG_EV_BITS = 0x11,
+ VIRTIO_INPUT_CFG_ABS_INFO = 0x12,
+};
+
+struct virtio_input_absinfo
+{
+ rt_le32_t min; /* Minimum value for the axis */
+ rt_le32_t max; /* Maximum value for the axis */
+ rt_le32_t fuzz; /* Fuzz value that is used to filter noise from the event stream */
+ rt_le32_t flat; /* Within this value will be discarded by joydev interface and reported as 0 instead */
+ rt_le32_t res; /* Resolution for the values reported for the axis */
+};
+
+struct virtio_input_devids
+{
+ rt_le16_t bustype;
+ rt_le16_t vendor;
+ rt_le16_t product;
+ rt_le16_t version;
+};
+
+rt_packed(struct virtio_input_config
+{
+ rt_uint8_t select;
+ rt_uint8_t subsel;
+ rt_uint8_t size;
+ rt_uint8_t reserved[5];
+
+ union
+ {
+ char string[128];
+ rt_uint8_t bitmap[128];
+ struct virtio_input_absinfo abs;
+ struct virtio_input_devids ids;
+ };
+});
+
+struct virtio_input_event
+{
+ rt_le16_t type;
+ rt_le16_t code;
+ rt_le32_t value;
+};
+
+#endif /* __VIRTIO_INPUT_H__ */
diff --git a/components/drivers/virtio/virtio_net.h b/components/drivers/virtio/virtio_config/virtio-net.h
index 4bc57cb05b..1c5d0a2932 100644
--- a/components/drivers/virtio/virtio_net.h
+++ b/components/drivers/virtio/virtio_config/virtio-net.h
@@ -6,22 +6,13 @@
* Change Logs:
* Date Author Notes
* 2021-11-11 GuEe-GUI the first version
+ * 2023-02-25 GuEe-GUI using virtio dm
*/
#ifndef __VIRTIO_NET_H__
#define __VIRTIO_NET_H__
-#ifdef RT_USING_VIRTIO_NET
-
-#include <rtdef.h>
-#include <netif/ethernetif.h>
-
-#include <virtio.h>
-
-#define VIRTIO_NET_QUEUE_RX 0
-#define VIRTIO_NET_QUEUE_TX 1
-#define VIRTIO_NET_RTX_QUEUE_SIZE 16
-#define VIRTIO_NET_RTX_BUF_SIZE 2048
+#include <drivers/core/dm.h>
#define VIRTIO_NET_F_CSUM 0 /* Host handles pkts w/ partial csum */
#define VIRTIO_NET_F_GUEST_CSUM 1 /* Guest handles pkts w/ partial csum */
@@ -52,37 +43,32 @@
#define VIRTIO_NET_F_STANDBY 62 /* Act as standby for another device with the same MAC */
#define VIRTIO_NET_F_SPEED_DUPLEX 63 /* Device set linkspeed and duplex */
-#define VIRTIO_NET_S_LINK_UP (1 << 0)
-#define VIRTIO_NET_S_ANNOUNCE (1 << 1)
-
+rt_packed(struct virtio_net_hdr
+{
#define VIRTIO_NET_HDR_F_NEEDS_CSUM 1
#define VIRTIO_NET_HDR_F_DATA_VALID 2
#define VIRTIO_NET_HDR_F_RSC_INFO 4
-
+ rt_uint8_t flags;
#define VIRTIO_NET_HDR_GSO_NONE 0
#define VIRTIO_NET_HDR_GSO_TCPV4 1
#define VIRTIO_NET_HDR_GSO_UDP 3
#define VIRTIO_NET_HDR_GSO_TCPV6 4
#define VIRTIO_NET_HDR_GSO_ECN 0x80
-
-struct virtio_net_hdr
-{
- rt_uint8_t flags;
rt_uint8_t gso_type;
rt_uint16_t hdr_len;
rt_uint16_t gso_size;
rt_uint16_t csum_start;
rt_uint16_t csum_offset;
rt_uint16_t num_buffers;
-} __attribute__ ((packed));
+});
-#define VIRTIO_NET_MSS 1514
-#define VIRTIO_NET_HDR_SIZE (sizeof(struct virtio_net_hdr))
-#define VIRTIO_NET_PAYLOAD_MAX_SIZE (VIRTIO_NET_HDR_SIZE + VIRTIO_NET_MSS)
+#define VIRTIO_NET_MSS 1514
-struct virtio_net_config
+rt_packed(struct virtio_net_config
{
rt_uint8_t mac[6];
+#define VIRTIO_NET_S_LINK_UP (1 << 0)
+#define VIRTIO_NET_S_ANNOUNCE (1 << 1)
rt_uint16_t status;
rt_uint16_t max_virtqueue_pairs;
rt_uint16_t mtu;
@@ -91,29 +77,6 @@ struct virtio_net_config
rt_uint8_t rss_max_key_size;
rt_uint16_t rss_max_indirection_table_length;
rt_uint32_t supported_hash_types;
-} __attribute__((packed));
-
-struct virtio_net_device
-{
- struct eth_device parent;
-
- struct virtio_device virtio_dev;
-
- struct virtio_net_config *config;
-
- struct
- {
- /* Transmit hdr */
- struct virtio_net_hdr hdr;
- /* Transmit buffer */
- rt_uint8_t tx_buffer[VIRTIO_NET_PAYLOAD_MAX_SIZE];
- /* Receive buffer */
- rt_uint8_t rx_buffer[VIRTIO_NET_PAYLOAD_MAX_SIZE];
- } info[VIRTIO_NET_RTX_QUEUE_SIZE];
-};
-
-rt_err_t rt_virtio_net_init(rt_ubase_t *mmio_base, rt_uint32_t irq);
-
-#endif /* RT_USING_VIRTIO_NET */
+});
#endif /* __VIRTIO_NET_H__ */
diff --git a/components/drivers/virtio/virtio_config/virtio-scmi.h b/components/drivers/virtio/virtio_config/virtio-scmi.h
new file mode 100644
index 0000000000..bd08006716
--- /dev/null
+++ b/components/drivers/virtio/virtio_config/virtio-scmi.h
@@ -0,0 +1,35 @@
+/*
+ * 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_SCMI_H__
+#define __VIRTIO_SCMI_H__
+
+#define VIRTIO_SCMI_F_P2A_CHANNELS 0 /* Device implements some SCMI notifications, or delayed responses. */
+#define VIRTIO_SCMI_F_SHARED_MEMORY 1 /* Device implements any SCMI statistics shared memory region */
+
+rt_packed(struct virtio_scmi_request
+{
+ rt_le32_t hdr;
+ rt_uint8_t params[];
+});
+
+rt_packed(struct virtio_scmi_response
+{
+ rt_le32_t hdr;
+ rt_uint8_t ret_values[];
+});
+
+rt_packed(struct virtio_scmi_event_msg
+{
+ rt_le32_t hdr;
+ rt_uint8_t payload[];
+});
+
+#endif /* __VIRTIO_SCMI_H__ */
diff --git a/components/drivers/virtio/virtio_config/virtio-scsi.h b/components/drivers/virtio/virtio_config/virtio-scsi.h
new file mode 100644
index 0000000000..f0e5320adc
--- /dev/null
+++ b/components/drivers/virtio/virtio_config/virtio-scsi.h
@@ -0,0 +1,163 @@
+/*
+ * 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_SCSI_H__
+#define __VIRTIO_SCSI_H__
+
+#include <drivers/core/dm.h>
+
+#define VIRTIO_SCSI_CDB_DEFAULT_SIZE 32
+#define VIRTIO_SCSI_SENSE_DEFAULT_SIZE 96
+
+#ifndef VIRTIO_SCSI_CDB_SIZE
+#define VIRTIO_SCSI_CDB_SIZE VIRTIO_SCSI_CDB_DEFAULT_SIZE
+#endif
+#ifndef VIRTIO_SCSI_SENSE_SIZE
+#define VIRTIO_SCSI_SENSE_SIZE VIRTIO_SCSI_SENSE_DEFAULT_SIZE
+#endif
+
+/* SCSI command request, followed by data-out */
+rt_packed(struct virtio_scsi_cmd_req
+{
+ rt_uint8_t lun[8]; /* Logical Unit Number */
+ rt_le64_t tag; /* Command identifier */
+ rt_uint8_t task_attr; /* Task attribute */
+ rt_uint8_t prio; /* SAM command priority field */
+ rt_uint8_t crn;
+ rt_uint8_t cdb[VIRTIO_SCSI_CDB_SIZE];
+});
+
+/* SCSI command request, followed by protection information */
+rt_packed(struct virtio_scsi_cmd_req_pi
+{
+ rt_uint8_t lun[8]; /* Logical Unit Number */
+ rt_le64_t tag; /* Command identifier */
+ rt_uint8_t task_attr; /* Task attribute */
+ rt_uint8_t prio; /* SAM command priority field */
+ rt_uint8_t crn;
+ rt_le32_t pi_bytesout; /* DataOUT PI Number of bytes */
+ rt_le32_t pi_bytesin; /* DataIN PI Number of bytes */
+ rt_uint8_t cdb[VIRTIO_SCSI_CDB_SIZE];
+});
+
+/* Response, followed by sense data and data-in */
+rt_packed(struct virtio_scsi_cmd_resp
+{
+ rt_le32_t sense_len; /* Sense data length */
+ rt_le32_t resid; /* Residual bytes in data buffer */
+ rt_le16_t status_qualifier; /* Status qualifier */
+ rt_uint8_t status; /* Command completion status */
+ rt_uint8_t response; /* Response values */
+ rt_uint8_t sense[VIRTIO_SCSI_SENSE_SIZE];
+});
+
+/* Task Management Request */
+rt_packed(struct virtio_scsi_ctrl_tmf_req
+{
+ rt_le32_t type;
+ rt_le32_t subtype;
+ rt_uint8_t lun[8];
+ rt_le64_t tag;
+});
+
+rt_packed(struct virtio_scsi_ctrl_tmf_resp
+{
+ rt_uint8_t response;
+});
+
+/* Asynchronous notification query/subscription */
+rt_packed(struct virtio_scsi_ctrl_an_req
+{
+ rt_le32_t type;
+ rt_uint8_t lun[8];
+ rt_le32_t event_requested;
+});
+
+rt_packed(struct virtio_scsi_ctrl_an_resp
+{
+ rt_le32_t event_actual;
+ rt_uint8_t response;
+});
+
+rt_packed(struct virtio_scsi_event
+{
+ rt_le32_t event;
+ rt_uint8_t lun[8];
+ rt_le32_t reason;
+});
+
+rt_packed(struct virtio_scsi_config
+{
+ rt_le32_t num_queues;
+ rt_le32_t seg_max;
+ rt_le32_t max_sectors;
+ rt_le32_t cmd_per_lun;
+ rt_le32_t event_info_size;
+ rt_le32_t sense_size;
+ rt_le32_t cdb_size;
+ rt_le16_t max_channel;
+ rt_le16_t max_target;
+ rt_le32_t max_lun;
+});
+
+/* Feature Bits */
+#define VIRTIO_SCSI_F_INOUT 0
+#define VIRTIO_SCSI_F_HOTPLUG 1
+#define VIRTIO_SCSI_F_CHANGE 2
+#define VIRTIO_SCSI_F_T10_PI 3
+
+/* Response codes */
+#define VIRTIO_SCSI_S_OK 0
+#define VIRTIO_SCSI_S_OVERRUN 1
+#define VIRTIO_SCSI_S_ABORTED 2
+#define VIRTIO_SCSI_S_BAD_TARGET 3
+#define VIRTIO_SCSI_S_RESET 4
+#define VIRTIO_SCSI_S_BUSY 5
+#define VIRTIO_SCSI_S_TRANSPORT_FAILURE 6
+#define VIRTIO_SCSI_S_TARGET_FAILURE 7
+#define VIRTIO_SCSI_S_NEXUS_FAILURE 8
+#define VIRTIO_SCSI_S_FAILURE 9
+#define VIRTIO_SCSI_S_FUNCTION_SUCCEEDED 10
+#define VIRTIO_SCSI_S_FUNCTION_REJECTED 11
+#define VIRTIO_SCSI_S_INCORRECT_LUN 12
+
+/* Controlq type codes */
+#define VIRTIO_SCSI_T_TMF 0
+#define VIRTIO_SCSI_T_AN_QUERY 1
+#define VIRTIO_SCSI_T_AN_SUBSCRIBE 2
+
+/* Valid TMF subtypes */
+#define VIRTIO_SCSI_T_TMF_ABORT_TASK 0
+#define VIRTIO_SCSI_T_TMF_ABORT_TASK_SET 1
+#define VIRTIO_SCSI_T_TMF_CLEAR_ACA 2
+#define VIRTIO_SCSI_T_TMF_CLEAR_TASK_SET 3
+#define VIRTIO_SCSI_T_TMF_I_T_NEXUS_RESET 4
+#define VIRTIO_SCSI_T_TMF_LOGICAL_UNIT_RESET 5
+#define VIRTIO_SCSI_T_TMF_QUERY_TASK 6
+#define VIRTIO_SCSI_T_TMF_QUERY_TASK_SET 7
+
+/* Events */
+#define VIRTIO_SCSI_T_EVENTS_MISSED 0x80000000
+#define VIRTIO_SCSI_T_NO_EVENT 0
+#define VIRTIO_SCSI_T_TRANSPORT_RESET 1
+#define VIRTIO_SCSI_T_ASYNC_NOTIFY 2
+#define VIRTIO_SCSI_T_PARAM_CHANGE 3
+
+/* Reasons of transport reset event */
+#define VIRTIO_SCSI_EVT_RESET_HARD 0
+#define VIRTIO_SCSI_EVT_RESET_RESCAN 1
+#define VIRTIO_SCSI_EVT_RESET_REMOVED 2
+
+#define VIRTIO_SCSI_S_SIMPLE 0
+#define VIRTIO_SCSI_S_ORDERED 1
+#define VIRTIO_SCSI_S_HEAD 2
+#define VIRTIO_SCSI_S_ACA 3
+
+#endif /* __VIRTIO_SCSI_H__ */
diff --git a/components/drivers/virtio/virtio_console.c b/components/drivers/virtio/virtio_console.c
deleted file mode 100644
index 7ad171cec3..0000000000
--- a/components/drivers/virtio/virtio_console.c
+++ /dev/null
@@ -1,778 +0,0 @@
-/*
- * Copyright (c) 2006-2023, RT-Thread Development Team
- *
- * SPDX-License-Identifier: Apache-2.0
- *
- * Change Logs:
- * Date Author Notes
- * 2021-11-11 GuEe-GUI the first version
- */
-
-#include <rthw.h>
-#include <rtthread.h>
-#include <cpuport.h>
-
-#ifdef RT_USING_VIRTIO_CONSOLE
-
-#include <virtio_console.h>
-
-struct port_device
-{
- struct rt_device parent;
-
- rt_list_t node;
- rt_uint32_t port_id;
- rt_bool_t rx_notify;
- rt_bool_t need_destroy;
-
- struct virtio_console_device *console;
-
- struct virtq *queue_rx, *queue_tx;
- rt_uint32_t queue_rx_index, queue_tx_index;
-
-#ifdef RT_USING_SMP
- struct rt_spinlock spinlock_rx, spinlock_tx;
-#endif
-
- struct rt_device_notify rx_notify_helper;
-
- struct
- {
- char rx_char, tx_char;
- } info[VIRTIO_CONSOLE_QUEUE_SIZE];
-};
-
-static void virtio_console_send_ctrl(struct virtio_console_device *virtio_console_dev,
- struct virtio_console_control *ctrl)
-{
- rt_uint16_t id;
- struct virtio_device *virtio_dev = &virtio_console_dev->virtio_dev;
- struct virtq *queue_ctrl_tx;
-
-#ifdef RT_USING_SMP
- rt_base_t level = rt_spin_lock_irqsave(&virtio_dev->spinlock);
-#endif
-
- queue_ctrl_tx = &virtio_dev->queues[VIRTIO_CONSOLE_QUEUE_CTRL_TX];
-
- id = queue_ctrl_tx->avail->idx % queue_ctrl_tx->num;
-
- rt_memcpy(&virtio_console_dev->info[id].tx_ctrl, ctrl, sizeof(struct virtio_console_control));
-
- virtio_free_desc(virtio_dev, VIRTIO_CONSOLE_QUEUE_CTRL_TX, id);
-
- virtio_fill_desc(virtio_dev, VIRTIO_CONSOLE_QUEUE_CTRL_TX, id,
- virtio_console_dev->info[id].tx_ctrl_paddr, sizeof(struct virtio_console_control), 0, 0);
-
- virtio_submit_chain(virtio_dev, VIRTIO_CONSOLE_QUEUE_CTRL_TX, id);
-
- virtio_queue_notify(virtio_dev, VIRTIO_CONSOLE_QUEUE_CTRL_TX);
-
- virtio_alloc_desc(virtio_dev, VIRTIO_CONSOLE_QUEUE_CTRL_TX);
-
-#ifdef RT_USING_SMP
- rt_spin_unlock_irqrestore(&virtio_dev->spinlock, level);
-#endif
-}
-
-static rt_err_t virtio_console_port_init(rt_device_t dev);
-static rt_err_t virtio_console_port_open(rt_device_t dev, rt_uint16_t oflag);
-static rt_err_t virtio_console_port_close(rt_device_t dev);
-static rt_ssize_t virtio_console_port_read(rt_device_t dev, rt_off_t pos, void *buffer, rt_size_t size);
-static rt_ssize_t virtio_console_port_write(rt_device_t dev, rt_off_t pos, const void *buffer, rt_size_t size);
-static rt_err_t virtio_console_port_control(rt_device_t dev, int cmd, void *args);
-
-#ifdef RT_USING_DEVICE_OPS
-const static struct rt_device_ops virtio_console_port_ops =
-{
- virtio_console_port_init,
- virtio_console_port_open,
- virtio_console_port_close,
- virtio_console_port_read,
- virtio_console_port_write,
- virtio_console_port_control
-};
-#endif
-
-static rt_err_t virtio_console_port_create(struct virtio_console_device *virtio_console_dev)
-{
- rt_uint32_t port_id;
- char dev_name[RT_NAME_MAX];
- struct port_device *port_dev, *prev_port_dev = RT_NULL;
- struct virtio_device *virtio_dev = &virtio_console_dev->virtio_dev;
-
- if (virtio_console_dev->port_nr > 0 && !virtio_has_feature(virtio_dev, VIRTIO_CONSOLE_F_MULTIPORT))
- {
- return -RT_ENOSYS;
- }
-
- if (virtio_console_dev->port_nr >= virtio_console_dev->max_port_nr)
- {
- return -RT_EFULL;
- }
-
- port_id = 0;
-
- /* The port device list is always ordered, so just find next number for id */
- rt_list_for_each_entry(port_dev, &virtio_console_dev->port_head, node)
- {
- if (port_dev->port_id != port_id)
- {
- break;
- }
- ++port_id;
- prev_port_dev = port_dev;
- }
-
- port_dev = rt_malloc(sizeof(struct port_device));
-
- if (port_dev == RT_NULL)
- {
- return -RT_ENOMEM;
- }
-
- port_dev->parent.type = RT_Device_Class_Char;
-#ifdef RT_USING_DEVICE_OPS
- port_dev->parent.ops = &virtio_console_port_ops;
-#else
- port_dev->parent.init = virtio_console_port_init;
- port_dev->parent.open = virtio_console_port_open;
- port_dev->parent.close = virtio_console_port_close;
- port_dev->parent.read = virtio_console_port_read;
- port_dev->parent.write = virtio_console_port_write;
- port_dev->parent.control = virtio_console_port_control;
-#endif
-
- port_dev->parent.rx_indicate = RT_NULL;
- port_dev->parent.tx_complete = RT_NULL;
-
- rt_list_init(&port_dev->node);
- port_dev->port_id = port_id;
- port_dev->need_destroy = RT_FALSE;
- port_dev->rx_notify = RT_TRUE;
- port_dev->console = virtio_console_dev;
- port_dev->queue_rx_index = VIRTIO_CONSOLE_PORT_QUEUE_INDEX(port_dev->port_id, VIRTIO_CONSOLE_QUEUE_DATA_RX);
- port_dev->queue_tx_index = VIRTIO_CONSOLE_PORT_QUEUE_INDEX(port_dev->port_id, VIRTIO_CONSOLE_QUEUE_DATA_TX);
- port_dev->queue_rx = &virtio_dev->queues[port_dev->queue_rx_index];
- port_dev->queue_tx = &virtio_dev->queues[port_dev->queue_tx_index];
-
-#ifdef RT_USING_SMP
- rt_spin_lock_init(&port_dev->spinlock_rx);
- rt_spin_lock_init(&port_dev->spinlock_tx);
-#endif
-
- rt_snprintf(dev_name, RT_NAME_MAX, "vport%dp%d", virtio_console_dev->console_id, port_id);
-
- if (rt_device_register((rt_device_t)port_dev, dev_name, RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_INT_RX) != RT_EOK)
- {
- rt_free(port_dev);
-
- return -RT_ERROR;
- }
-
- if (prev_port_dev != RT_NULL)
- {
- rt_list_insert_after(&prev_port_dev->node, &port_dev->node);
- }
- else
- {
- /* Port0 */
- rt_list_insert_after(&virtio_console_dev->port_head, &port_dev->node);
- }
-
- virtio_console_dev->port_nr++;
-
- return RT_EOK;
-}
-
-static void virtio_console_port_destroy(struct virtio_console_device *virtio_console_dev,
- struct port_device *port_dev)
-{
- struct virtio_console_control set_ctrl;
-
- set_ctrl.id = port_dev->port_id;
- set_ctrl.event = VIRTIO_CONSOLE_PORT_OPEN;
- set_ctrl.value = 0;
-
- virtio_console_send_ctrl(virtio_console_dev, &set_ctrl);
-
- virtio_console_dev->port_nr--;
-
- rt_list_remove(&port_dev->node);
-
- rt_device_unregister((rt_device_t)port_dev);
-
- rt_free(port_dev);
-}
-
-static rt_err_t virtio_console_port_init(rt_device_t dev)
-{
- rt_uint16_t id;
- rt_uint16_t idx[VIRTIO_CONSOLE_QUEUE_SIZE];
- rt_uint16_t rx_queue_index, tx_queue_index;
- struct port_device *port_dev = (struct port_device *)dev;
- struct virtio_console_device *virtio_console_dev = port_dev->console;
- struct virtio_device *virtio_dev = &virtio_console_dev->virtio_dev;
- struct virtq *queue_rx, *queue_tx;
-
- rx_queue_index = VIRTIO_CONSOLE_PORT_QUEUE_INDEX(port_dev->port_id, VIRTIO_CONSOLE_QUEUE_DATA_RX);
- tx_queue_index = VIRTIO_CONSOLE_PORT_QUEUE_INDEX(port_dev->port_id, VIRTIO_CONSOLE_QUEUE_DATA_TX);
-
- queue_rx = &virtio_dev->queues[rx_queue_index];
- queue_tx = &virtio_dev->queues[tx_queue_index];
-
- virtio_alloc_desc_chain(virtio_dev, rx_queue_index, queue_rx->num, idx);
- virtio_alloc_desc_chain(virtio_dev, tx_queue_index, queue_tx->num, idx);
-
- for (id = 0; id < queue_rx->num; ++id)
- {
- void *addr = &port_dev->info[id].rx_char;
-
- virtio_fill_desc(virtio_dev, rx_queue_index, id,
- VIRTIO_VA2PA(addr), sizeof(char), VIRTQ_DESC_F_WRITE, 0);
-
- queue_rx->avail->ring[id] = id;
- }
- rt_hw_dsb();
-
- queue_rx->avail->flags = 0;
- queue_rx->avail->idx = queue_rx->num;
-
- queue_rx->used_idx = queue_rx->used->idx;
-
- queue_tx->avail->flags = VIRTQ_AVAIL_F_NO_INTERRUPT;
- queue_tx->avail->idx = 0;
-
- virtio_queue_notify(virtio_dev, rx_queue_index);
-
- if (virtio_has_feature(virtio_dev, VIRTIO_CONSOLE_F_MULTIPORT))
- {
- struct virtio_console_control set_ctrl;
-
- set_ctrl.id = VIRTIO_CONSOLE_PORT_BAD_ID;
- set_ctrl.event = VIRTIO_CONSOLE_DEVICE_READY;
- set_ctrl.value = 1;
-
- virtio_console_send_ctrl(virtio_console_dev, &set_ctrl);
- }
-
- return RT_EOK;
-}
-
-static rt_err_t virtio_console_port_open(rt_device_t dev, rt_uint16_t oflag)
-{
- struct port_device *port_dev = (struct port_device *)dev;
-
- if (port_dev->port_id == 0 && virtio_has_feature(&port_dev->console->virtio_dev, VIRTIO_CONSOLE_F_MULTIPORT))
- {
- /* Port0 is reserve in multiport */
- return -RT_ERROR;
- }
-
- port_dev->rx_notify = RT_TRUE;
-
- return RT_EOK;
-}
-
-static rt_err_t virtio_console_port_close(rt_device_t dev)
-{
- struct port_device *port_dev = (struct port_device *)dev;
-
- if (port_dev->need_destroy)
- {
- virtio_console_port_destroy(port_dev->console, port_dev);
-
- /*
- * We released the device memory in virtio_console_port_destroy,
- * rt_device_close has not finished yet, make the return value
- * to empty so that rt_device_close will not access the device memory.
- */
- return -RT_EEMPTY;
- }
-
- port_dev->rx_notify = RT_FALSE;
-
- return RT_EOK;
-}
-
-static rt_ssize_t virtio_console_port_read(rt_device_t dev, rt_off_t pos, void *buffer, rt_size_t size)
-{
- rt_off_t i = 0;
- rt_uint16_t id;
- rt_uint32_t len;
- struct port_device *port_dev = (struct port_device *)dev;
- struct virtio_device *virtio_dev = &port_dev->console->virtio_dev;
- rt_uint32_t queue_rx_index = port_dev->queue_rx_index;
- struct virtq *queue_rx = port_dev->queue_rx;
-
-#ifdef RT_USING_SMP
- rt_base_t level = rt_spin_lock_irqsave(&port_dev->spinlock_rx);
-#endif
-
- while (i < size)
- {
- if (queue_rx->used_idx == queue_rx->used->idx)
- {
- break;
- }
- rt_hw_dsb();
-
- id = queue_rx->used->ring[queue_rx->used_idx % queue_rx->num].id;
- len = queue_rx->used->ring[queue_rx->used_idx % queue_rx->num].len;
-
- if (len > sizeof(char))
- {
- rt_kprintf("%s: Receive buffer's size = %u is too big!\n", port_dev->parent.parent.name, len);
- len = sizeof(char);
- }
-
- *((char *)buffer + i) = port_dev->info[id].rx_char;
-
- queue_rx->used_idx++;
-
- virtio_submit_chain(virtio_dev, queue_rx_index, id);
-
- virtio_queue_notify(virtio_dev, queue_rx_index);
-
- i += len;
- }
-
-#ifdef RT_USING_SMP
- rt_spin_unlock_irqrestore(&port_dev->spinlock_rx, level);
-#endif
-
- size = i;
-
- return size;
-}
-
-static rt_ssize_t virtio_console_port_write(rt_device_t dev, rt_off_t pos, const void *buffer, rt_size_t size)
-{
- char ch = 0;
- rt_off_t i = 0;
- rt_uint16_t id;
- struct port_device *port_dev = (struct port_device *)dev;
- struct virtio_device *virtio_dev = &port_dev->console->virtio_dev;
- rt_uint32_t queue_tx_index = port_dev->queue_tx_index;
- struct virtq *queue_tx = port_dev->queue_tx;
-
-#ifdef RT_USING_SMP
- rt_base_t level = rt_spin_lock_irqsave(&port_dev->spinlock_tx);
-#endif
-
- while (i < size || ch == '\r')
- {
- id = queue_tx->avail->idx % queue_tx->num;
-
- /* Keep the way until 'new line' are unified */
- if (ch != '\r')
- {
- ch = *((const char *)buffer + i);
- }
- else
- {
- i -= sizeof(char);
- }
-
- port_dev->info[id].tx_char = ch;
-
- ch = (ch == '\n' ? '\r' : 0);
-
- virtio_free_desc(virtio_dev, queue_tx_index, id);
-
- virtio_fill_desc(virtio_dev, queue_tx_index, id,
- VIRTIO_VA2PA(&port_dev->info[id].tx_char), sizeof(char), 0, 0);
-
- virtio_submit_chain(virtio_dev, queue_tx_index, id);
-
- virtio_queue_notify(virtio_dev, queue_tx_index);
-
- virtio_alloc_desc(virtio_dev, queue_tx_index);
-
- i += sizeof(char);
- }
-
-#ifdef RT_USING_SMP
- rt_spin_unlock_irqrestore(&port_dev->spinlock_tx, level);
-#endif
-
- return size;
-}
-
-static rt_err_t virtio_console_port_control(rt_device_t dev, int cmd, void *args)
-{
- rt_err_t status = RT_EOK;
- struct port_device *port_dev = (struct port_device *)dev;
-
- switch (cmd)
- {
- case RT_DEVICE_CTRL_NOTIFY_SET:
- if (args == RT_NULL)
- {
- status = -RT_ERROR;
- break;
- }
- rt_memcpy(&port_dev->rx_notify_helper, args, sizeof(port_dev->rx_notify_helper));
- break;
- case RT_DEVICE_CTRL_CLR_INT:
- /* Disable RX */
- port_dev->rx_notify = RT_FALSE;
- break;
- case RT_DEVICE_CTRL_SET_INT:
- /* Enable RX */
- port_dev->rx_notify = RT_TRUE;
- break;
- case VIRTIO_DEVICE_CTRL_CONSOLE_PORT_DESTROY:
- {
- port_dev->need_destroy = RT_TRUE;
- port_dev->rx_notify = RT_FALSE;
- }
- break;
- default:
- status = -RT_EINVAL;
- break;
- }
-
- return status;
-}
-
-static rt_err_t virtio_console_init(rt_device_t dev)
-{
- struct virtio_console_device *virtio_console_dev = (struct virtio_console_device *)dev;
- struct virtio_device *virtio_dev = &virtio_console_dev->virtio_dev;
-
- if (virtio_has_feature(virtio_dev, VIRTIO_CONSOLE_F_MULTIPORT))
- {
- rt_uint16_t id;
- rt_uint16_t idx[VIRTIO_CONSOLE_QUEUE_SIZE];
- struct virtq *queue_ctrl_rx, *queue_ctrl_tx;
-
- queue_ctrl_rx = &virtio_dev->queues[VIRTIO_CONSOLE_QUEUE_CTRL_RX];
- queue_ctrl_tx = &virtio_dev->queues[VIRTIO_CONSOLE_QUEUE_CTRL_TX];
-
- virtio_alloc_desc_chain(virtio_dev, VIRTIO_CONSOLE_QUEUE_CTRL_RX, queue_ctrl_rx->num, idx);
- virtio_alloc_desc_chain(virtio_dev, VIRTIO_CONSOLE_QUEUE_CTRL_TX, queue_ctrl_tx->num, idx);
-
- for (id = 0; id < queue_ctrl_rx->num; ++id)
- {
- void *addr = &virtio_console_dev->info[id].rx_ctrl;
-
- virtio_fill_desc(virtio_dev, VIRTIO_CONSOLE_QUEUE_CTRL_RX, id,
- VIRTIO_VA2PA(addr), sizeof(struct virtio_console_control), VIRTQ_DESC_F_WRITE, 0);
-
- queue_ctrl_rx->avail->ring[id] = id;
- }
- rt_hw_dsb();
-
- for (id = 0; id < queue_ctrl_tx->num; ++id)
- {
- virtio_console_dev->info[id].tx_ctrl_paddr = VIRTIO_VA2PA(&virtio_console_dev->info[id].tx_ctrl);
- }
-
- queue_ctrl_rx->avail->flags = 0;
- queue_ctrl_rx->avail->idx = queue_ctrl_rx->num;
-
- queue_ctrl_rx->used_idx = queue_ctrl_rx->used->idx;
-
- queue_ctrl_tx->avail->flags = VIRTQ_AVAIL_F_NO_INTERRUPT;
- queue_ctrl_tx->avail->idx = 0;
-
- virtio_queue_notify(virtio_dev, VIRTIO_CONSOLE_QUEUE_CTRL_RX);
- }
-
- return virtio_console_port_create(virtio_console_dev);
-}
-
-static rt_err_t virtio_console_control(rt_device_t dev, int cmd, void *args)
-{
- rt_err_t status = RT_EOK;
- struct virtio_console_device *virtio_console_dev = (struct virtio_console_device *)dev;
-
- switch (cmd)
- {
- case VIRTIO_DEVICE_CTRL_CONSOLE_PORT_CREATE:
- status = virtio_console_port_create(virtio_console_dev);
- break;
- default:
- status = -RT_EINVAL;
- break;
- }
-
- return status;
-}
-
-#ifdef RT_USING_DEVICE_OPS
-const static struct rt_device_ops virtio_console_ops =
-{
- virtio_console_init,
- RT_NULL,
- RT_NULL,
- RT_NULL,
- RT_NULL,
- virtio_console_control
-};
-#endif
-
-static void virtio_console_isr(int irqno, void *param)
-{
- rt_uint32_t id;
- rt_uint32_t len;
- struct port_device *port_dev;
- struct virtio_console_device *virtio_console_dev = (struct virtio_console_device *)param;
- struct virtio_device *virtio_dev = &virtio_console_dev->virtio_dev;
- const char *dev_name = virtio_console_dev->parent.parent.name;
-
-#ifdef RT_USING_SMP
- rt_base_t level = rt_spin_lock_irqsave(&virtio_dev->spinlock);
-#endif
-
- virtio_interrupt_ack(virtio_dev);
- rt_hw_dsb();
-
- do {
- struct virtq *queue_rx;
- struct virtio_console_control *ctrl, set_ctrl;
-
- if (!virtio_has_feature(virtio_dev, VIRTIO_CONSOLE_F_MULTIPORT))
- {
- break;
- }
-
- queue_rx = &virtio_dev->queues[VIRTIO_CONSOLE_QUEUE_CTRL_RX];
-
- if (queue_rx->used_idx == queue_rx->used->idx)
- {
- break;
- }
- rt_hw_dsb();
-
- id = queue_rx->used->ring[queue_rx->used_idx % queue_rx->num].id;
- len = queue_rx->used->ring[queue_rx->used_idx % queue_rx->num].len;
-
- queue_rx->used_idx++;
-
- if (len != sizeof(struct virtio_console_control))
- {
- rt_kprintf("%s: Invalid ctrl!\n", dev_name);
- break;
- }
-
- ctrl = &virtio_console_dev->info[id].rx_ctrl;
-
- switch (ctrl->event)
- {
- case VIRTIO_CONSOLE_PORT_ADD:
- {
- set_ctrl.id = ctrl->id;
- set_ctrl.event = VIRTIO_CONSOLE_PORT_READY;
- set_ctrl.value = 1;
-
- #ifdef RT_USING_SMP
- rt_spin_unlock_irqrestore(&virtio_dev->spinlock, level);
- #endif
-
- virtio_console_send_ctrl(virtio_console_dev, &set_ctrl);
-
- #ifdef RT_USING_SMP
- level = rt_spin_lock_irqsave(&virtio_dev->spinlock);
- #endif
- }
- break;
- case VIRTIO_CONSOLE_PORT_REMOVE:
- break;
- case VIRTIO_CONSOLE_RESIZE:
- break;
- case VIRTIO_CONSOLE_PORT_OPEN:
- {
- set_ctrl.id = ctrl->id;
- set_ctrl.event = VIRTIO_CONSOLE_PORT_OPEN;
- set_ctrl.value = 1;
-
- #ifdef RT_USING_SMP
- rt_spin_unlock_irqrestore(&virtio_dev->spinlock, level);
- #endif
-
- virtio_console_send_ctrl(virtio_console_dev, &set_ctrl);
-
- #ifdef RT_USING_SMP
- level = rt_spin_lock_irqsave(&virtio_dev->spinlock);
- #endif
- }
- break;
- case VIRTIO_CONSOLE_PORT_NAME:
- break;
- default:
- rt_kprintf("%s: Unsupport ctrl[id: %d, event: %d, value: %d]!\n",
- dev_name, ctrl->id, ctrl->event, ctrl->value);
- break;
- }
-
- } while (0);
-
-#ifdef RT_USING_SMP
- rt_spin_unlock_irqrestore(&virtio_dev->spinlock, level);
-#endif
-
- rt_list_for_each_entry(port_dev, &virtio_console_dev->port_head, node)
- {
- rt_uint32_t queue_rx_index = port_dev->queue_rx_index;
- struct virtq *queue_rx = port_dev->queue_rx;
-
-#ifdef RT_USING_SMP
- rt_base_t level = rt_spin_lock_irqsave(&port_dev->spinlock_rx);
-#endif
-
- if (queue_rx->used_idx != queue_rx->used->idx)
- {
- rt_hw_dsb();
-
- id = queue_rx->used->ring[queue_rx->used_idx % queue_rx->num].id;
- len = queue_rx->used->ring[queue_rx->used_idx % queue_rx->num].len;
-
- if (port_dev->rx_notify)
- {
- #ifdef RT_USING_SMP
- rt_spin_unlock_irqrestore(&port_dev->spinlock_rx, level);
- #endif
- /* Will call virtio_console_port_read to inc used_idx */
-
- if (port_dev->parent.rx_indicate != RT_NULL)
- {
- port_dev->parent.rx_indicate(&port_dev->parent, len);
- }
-
- if (port_dev->rx_notify_helper.notify != RT_NULL)
- {
- port_dev->rx_notify_helper.notify(port_dev->rx_notify_helper.dev);
- }
-
- #ifdef RT_USING_SMP
- level = rt_spin_lock_irqsave(&port_dev->spinlock_rx);
- #endif
- }
- else
- {
- queue_rx->used_idx++;
-
- virtio_submit_chain(virtio_dev, queue_rx_index, id);
-
- virtio_queue_notify(virtio_dev, queue_rx_index);
- }
- }
-
-#ifdef RT_USING_SMP
- rt_spin_unlock_irqrestore(&port_dev->spinlock_rx, level);
-#endif
- }
-}
-
-rt_err_t rt_virtio_console_init(rt_ubase_t *mmio_base, rt_uint32_t irq)
-{
- int i;
- rt_size_t queues_num;
- static int dev_no = 0;
- char dev_name[RT_NAME_MAX];
- struct virtio_device *virtio_dev;
- struct virtio_console_device *virtio_console_dev;
-
- RT_ASSERT(RT_USING_VIRTIO_CONSOLE_PORT_MAX_NR > 0);
-
- virtio_console_dev = rt_malloc(sizeof(struct virtio_console_device));
-
- if (virtio_console_dev == RT_NULL)
- {
- goto _alloc_fail;
- }
-
- virtio_dev = &virtio_console_dev->virtio_dev;
- virtio_dev->irq = irq;
- virtio_dev->mmio_base = mmio_base;
-
- virtio_console_dev->config = (struct virtio_console_config *)virtio_dev->mmio_config->config;
-
-#ifdef RT_USING_SMP
- rt_spin_lock_init(&virtio_dev->spinlock);
-#endif
-
- virtio_reset_device(virtio_dev);
- virtio_status_acknowledge_driver(virtio_dev);
-
- virtio_dev->mmio_config->driver_features = virtio_dev->mmio_config->device_features & ~(
- (1 << VIRTIO_F_RING_EVENT_IDX) |
- (1 << VIRTIO_F_RING_INDIRECT_DESC));
-
- virtio_status_driver_ok(virtio_dev);
-
- if (!virtio_has_feature(virtio_dev, VIRTIO_CONSOLE_F_MULTIPORT))
- {
- virtio_console_dev->max_port_nr = 1;
- queues_num = 2;
- }
- else
- {
- if (virtio_console_dev->config->max_nr_ports > RT_USING_VIRTIO_CONSOLE_PORT_MAX_NR)
- {
- virtio_console_dev->max_port_nr = RT_USING_VIRTIO_CONSOLE_PORT_MAX_NR;
- virtio_console_dev->config->max_nr_ports = virtio_console_dev->max_port_nr;
- }
- else
- {
- virtio_console_dev->max_port_nr = virtio_console_dev->config->max_nr_ports;
- }
-
- queues_num = VIRTIO_CONSOLE_PORT_QUEUE_INDEX(virtio_console_dev->max_port_nr, VIRTIO_CONSOLE_QUEUE_DATA_RX);
- }
-
- if (virtio_queues_alloc(virtio_dev, queues_num) != RT_EOK)
- {
- goto _alloc_fail;
- }
-
- for (i = 0; i < virtio_dev->queues_num; ++i)
- {
- if (virtio_queue_init(virtio_dev, i, VIRTIO_CONSOLE_QUEUE_SIZE) != RT_EOK)
- {
- for (; i >= 0; --i)
- {
- virtio_queue_destroy(virtio_dev, i);
- }
- goto _alloc_fail;
- }
- }
-
- virtio_console_dev->parent.type = RT_Device_Class_Char;
-#ifdef RT_USING_DEVICE_OPS
- virtio_console_dev->parent.ops = &virtio_console_ops;
-#else
- virtio_console_dev->parent.init = virtio_console_init;
- virtio_console_dev->parent.open = RT_NULL;
- virtio_console_dev->parent.close = RT_NULL;
- virtio_console_dev->parent.read = RT_NULL;
- virtio_console_dev->parent.write = RT_NULL;
- virtio_console_dev->parent.control = virtio_console_control;
-#endif
-
- virtio_console_dev->parent.rx_indicate = RT_NULL;
- virtio_console_dev->parent.tx_complete = RT_NULL;
-
- virtio_console_dev->console_id = dev_no;
- virtio_console_dev->port_nr = 0;
- rt_list_init(&virtio_console_dev->port_head);
-
- rt_snprintf(dev_name, RT_NAME_MAX, "virtio-console%d", dev_no++);
-
- rt_hw_interrupt_install(irq, virtio_console_isr, virtio_console_dev, dev_name);
- rt_hw_interrupt_umask(irq);
-
- return rt_device_register((rt_device_t)virtio_console_dev, dev_name, RT_DEVICE_FLAG_RDWR | RT_DEVICE_FLAG_INT_RX);
-
-_alloc_fail:
-
- if (virtio_console_dev != RT_NULL)
- {
- virtio_queues_free(virtio_dev);
- rt_free(virtio_console_dev);
- }
- return -RT_ENOMEM;
-}
-#endif /* RT_USING_VIRTIO_CONSOLE */
diff --git a/components/drivers/virtio/virtio_console.h b/components/drivers/virtio/virtio_console.h
deleted file mode 100644
index 542a187e7c..0000000000
--- a/components/drivers/virtio/virtio_console.h
+++ /dev/null
@@ -1,97 +0,0 @@
-/*
- * Copyright (c) 2006-2023, RT-Thread Development Team
- *
- * SPDX-License-Identifier: Apache-2.0
- *
- * Change Logs:
- * Date Author Notes
- * 2021-11-11 GuEe-GUI the first version
- */
-
-#ifndef __VIRTIO_CONSOLE_H__
-#define __VIRTIO_CONSOLE_H__
-
-#include <rtdef.h>
-
-#include <virtio.h>
-
-#ifndef RT_USING_VIRTIO_CONSOLE_PORT_MAX_NR
-#define RT_USING_VIRTIO_CONSOLE_PORT_MAX_NR 4
-#endif
-
-#define VIRTIO_CONSOLE_QUEUE_DATA_RX 0
-#define VIRTIO_CONSOLE_QUEUE_DATA_TX 1
-#define VIRTIO_CONSOLE_QUEUE_CTRL_RX 2
-#define VIRTIO_CONSOLE_QUEUE_CTRL_TX 3
-#define VIRTIO_CONSOLE_QUEUE_SIZE 64
-
-/* Every port has data rx & tx, and port0 has ctrl rx & tx in multiport */
-#define VIRTIO_CONSOLE_PORT_QUEUE_INDEX(id, queue) ((id) * 2 + (!!(id)) * 2 + (queue))
-
-#define VIRTIO_CONSOLE_PORT_BAD_ID (~(rt_uint32_t)0)
-
-#define VIRTIO_CONSOLE_F_SIZE 0 /* Does host provide console size? */
-#define VIRTIO_CONSOLE_F_MULTIPORT 1 /* Does host provide multiple ports? */
-#define VIRTIO_CONSOLE_F_EMERG_WRITE 2 /* Does host support emergency write? */
-
-struct virtio_console_config
-{
- rt_uint16_t cols;
- rt_uint16_t rows;
- rt_uint32_t max_nr_ports;
- rt_uint32_t emerg_wr;
-} __attribute__((packed));
-
-struct virtio_console_control
-{
- rt_uint32_t id; /* Port number */
- rt_uint16_t event; /* The kind of control event */
- rt_uint16_t value; /* Extra information for the event */
-};
-
-enum virtio_console_control_event
-{
- VIRTIO_CONSOLE_DEVICE_READY = 0,
- VIRTIO_CONSOLE_PORT_ADD,
- VIRTIO_CONSOLE_PORT_REMOVE,
- VIRTIO_CONSOLE_PORT_READY,
- VIRTIO_CONSOLE_CONSOLE_PORT,
- VIRTIO_CONSOLE_RESIZE,
- VIRTIO_CONSOLE_PORT_OPEN,
- VIRTIO_CONSOLE_PORT_NAME,
-};
-
-struct virtio_console_resize
-{
- rt_uint16_t cols;
- rt_uint16_t rows;
-};
-
-struct virtio_console_device
-{
- struct rt_device parent;
-
- struct virtio_device virtio_dev;
-
- rt_uint32_t console_id;
- rt_size_t port_nr;
- rt_size_t max_port_nr;
- rt_list_t port_head;
- struct virtio_console_config *config;
-
- struct
- {
- rt_ubase_t tx_ctrl_paddr;
- struct virtio_console_control rx_ctrl, tx_ctrl;
- } info[VIRTIO_CONSOLE_QUEUE_SIZE];
-};
-
-rt_err_t rt_virtio_console_init(rt_ubase_t *mmio_base, rt_uint32_t irq);
-
-enum
-{
- VIRTIO_DEVICE_CTRL_CONSOLE_PORT_CREATE = 0x20,
- VIRTIO_DEVICE_CTRL_CONSOLE_PORT_DESTROY,
-};
-
-#endif /* __VIRTIO_CONSOLE_H__ */
diff --git a/components/drivers/virtio/virtio_gpu.c b/components/drivers/virtio/virtio_gpu.c
deleted file mode 100644
index fa8981e56c..0000000000
--- a/components/drivers/virtio/virtio_gpu.c
+++ /dev/null
@@ -1,935 +0,0 @@
-/*
- * Copyright (c) 2006-2023, RT-Thread Development Team
- *
- * SPDX-License-Identifier: Apache-2.0
- *
- * Change Logs:
- * Date Author Notes
- * 2021-11-11 GuEe-GUI the first version
- */
-
-#include <rthw.h>
-#include <rtthread.h>
-#include <cpuport.h>
-#include <rtdevice.h>
-
-#ifdef RT_USING_VIRTIO_GPU
-
-#include <virtio_gpu.h>
-
-static struct virtio_gpu_device *_primary_virtio_gpu_dev = RT_NULL;
-
-static rt_ubase_t _pixel_format_convert(rt_ubase_t format, rt_bool_t to_virtio_gpu_format)
-{
- rt_ubase_t ret = 0;
-
- if (to_virtio_gpu_format)
- {
- switch (format)
- {
- case RTGRAPHIC_PIXEL_FORMAT_RGB888:
- ret = VIRTIO_GPU_FORMAT_R8G8B8X8_UNORM;
- break;
- case RTGRAPHIC_PIXEL_FORMAT_ARGB888:
- ret = VIRTIO_GPU_FORMAT_A8R8G8B8_UNORM;
- break;
- case RTGRAPHIC_PIXEL_FORMAT_ABGR888:
- ret = VIRTIO_GPU_FORMAT_A8B8G8R8_UNORM;
- break;
- default:
- break;
- }
- }
- else
- {
- switch (format)
- {
- case VIRTIO_GPU_FORMAT_R8G8B8X8_UNORM:
- ret = RTGRAPHIC_PIXEL_FORMAT_RGB888;
- break;
- case VIRTIO_GPU_FORMAT_A8R8G8B8_UNORM:
- ret = RTGRAPHIC_PIXEL_FORMAT_ARGB888;
- break;
- case VIRTIO_GPU_FORMAT_A8B8G8R8_UNORM:
- ret = RTGRAPHIC_PIXEL_FORMAT_ABGR888;
- break;
- default:
- break;
- }
- }
-
- return ret;
-}
-
-static void virtio_gpu_ctrl_send_command(struct virtio_gpu_device *virtio_gpu_dev,
- const void *cmd, rt_size_t cmd_len, void *res, rt_size_t res_len)
-{
- rt_uint16_t idx[2];
- void *addr = &virtio_gpu_dev->gpu_request;
- void *ret_res = ((rt_uint8_t *)addr + cmd_len);
- struct virtio_device *virtio_dev = &virtio_gpu_dev->virtio_dev;
-
-#ifdef RT_USING_SMP
- rt_base_t level = rt_spin_lock_irqsave(&virtio_dev->spinlock);
-#endif
-
- while (virtio_alloc_desc_chain(virtio_dev, VIRTIO_GPU_QUEUE_CTRL, 2, idx))
- {
-#ifdef RT_USING_SMP
- rt_spin_unlock_irqrestore(&virtio_dev->spinlock, level);
-#endif
- rt_thread_yield();
-
-#ifdef RT_USING_SMP
- level = rt_spin_lock_irqsave(&virtio_dev->spinlock);
-#endif
- }
-
- rt_memcpy(&virtio_gpu_dev->gpu_request, cmd, cmd_len);
-
- virtio_fill_desc(virtio_dev, VIRTIO_GPU_QUEUE_CTRL, idx[0],
- VIRTIO_VA2PA(addr), cmd_len, VIRTQ_DESC_F_NEXT, idx[1]);
-
- virtio_fill_desc(virtio_dev, VIRTIO_GPU_QUEUE_CTRL, idx[1],
- VIRTIO_VA2PA(addr) + cmd_len, res_len, VIRTQ_DESC_F_WRITE, 0);
-
- rt_memset(ret_res, 0, res_len);
-
- virtio_gpu_dev->info[idx[0]].ctrl_valid = RT_TRUE;
-
- virtio_submit_chain(virtio_dev, VIRTIO_GPU_QUEUE_CTRL, idx[0]);
-
- virtio_queue_notify(virtio_dev, VIRTIO_GPU_QUEUE_CTRL);
-
- while (virtio_gpu_dev->info[idx[0]].ctrl_valid)
- {
-#ifdef RT_USING_SMP
- rt_spin_unlock_irqrestore(&virtio_dev->spinlock, level);
-#endif
- rt_thread_yield();
-
-#ifdef RT_USING_SMP
- level = rt_spin_lock_irqsave(&virtio_dev->spinlock);
-#endif
- }
-
- virtio_free_desc_chain(virtio_dev, VIRTIO_GPU_QUEUE_CTRL, idx[0]);
-
- rt_memcpy(res, ret_res, res_len);
-
-#ifdef RT_USING_SMP
- rt_spin_unlock_irqrestore(&virtio_dev->spinlock, level);
-#endif
-}
-
-static void virtio_gpu_cursor_send_command(struct virtio_gpu_device *virtio_gpu_dev,
- const void *cmd, rt_size_t cmd_len)
-{
- rt_uint16_t id;
- void *addr;
- struct virtio_device *virtio_dev = &virtio_gpu_dev->virtio_dev;
-
-#ifdef RT_USING_SMP
- rt_base_t level = rt_spin_lock_irqsave(&virtio_dev->spinlock);
-#endif
-
- while ((id = virtio_alloc_desc(virtio_dev, VIRTIO_GPU_QUEUE_CURSOR)) == VIRTQ_INVALID_DESC_ID)
- {
-#ifdef RT_USING_SMP
- rt_spin_unlock_irqrestore(&virtio_dev->spinlock, level);
-#endif
- rt_thread_yield();
-
-#ifdef RT_USING_SMP
- level = rt_spin_lock_irqsave(&virtio_dev->spinlock);
-#endif
- }
-
- addr = &virtio_gpu_dev->info[id].cursor_cmd;
- virtio_gpu_dev->info[id].cursor_valid = RT_TRUE;
-
- rt_memcpy(addr, cmd, cmd_len);
-
- virtio_fill_desc(virtio_dev, VIRTIO_GPU_QUEUE_CURSOR, id, VIRTIO_VA2PA(addr), cmd_len, 0, 0);
-
- virtio_submit_chain(virtio_dev, VIRTIO_GPU_QUEUE_CURSOR, id);
-
- virtio_queue_notify(virtio_dev, VIRTIO_GPU_QUEUE_CURSOR);
-
- while (virtio_gpu_dev->info[id].cursor_valid)
- {
-#ifdef RT_USING_SMP
- rt_spin_unlock_irqrestore(&virtio_dev->spinlock, level);
-#endif
- rt_thread_yield();
-
-#ifdef RT_USING_SMP
- level = rt_spin_lock_irqsave(&virtio_dev->spinlock);
-#endif
- }
-
- virtio_free_desc(virtio_dev, VIRTIO_GPU_QUEUE_CURSOR, id);
-
-#ifdef RT_USING_SMP
- rt_spin_unlock_irqrestore(&virtio_dev->spinlock, level);
-#endif
-}
-
-static rt_err_t virtio_gpu_create_2d_resource(struct virtio_gpu_device *virtio_gpu_dev, enum virtio_gpu_formats format,
- rt_uint32_t *resource_id, rt_uint32_t width, rt_uint32_t height)
-{
- struct virtio_gpu_ctrl_hdr res;
- struct virtio_gpu_resource_create_2d req;
-
- *resource_id = ++virtio_gpu_dev->next_resource_id;
-
- req.hdr.type = VIRTIO_GPU_CMD_RESOURCE_CREATE_2D;
- req.resource_id = *resource_id;
- req.format = format;
- req.width = width;
- req.height = height;
-
- virtio_gpu_ctrl_send_command(virtio_gpu_dev, &req, sizeof(req), &res, sizeof(res));
-
- if (res.type == VIRTIO_GPU_RESP_OK_NODATA)
- {
- return RT_EOK;
- }
-
- return -RT_ERROR;
-}
-
-static rt_err_t virtio_gpu_unref_resource(struct virtio_gpu_device *virtio_gpu_dev, rt_uint32_t resource_id)
-{
- struct virtio_gpu_ctrl_hdr res;
- struct virtio_gpu_resource_unref req;
-
- rt_memset(&req, 0, sizeof(req));
-
- req.hdr.type = VIRTIO_GPU_CMD_RESOURCE_UNREF;
- req.resource_id = resource_id;
-
- virtio_gpu_ctrl_send_command(virtio_gpu_dev, &req, sizeof(req), &res, sizeof(res));
-
- if (res.type == VIRTIO_GPU_RESP_OK_NODATA)
- {
- return RT_EOK;
- }
-
- return -RT_ERROR;
-}
-
-static rt_err_t virtio_gpu_attach_backing_resource(struct virtio_gpu_device *virtio_gpu_dev, rt_uint32_t resource_id,
- void *buffer, rt_size_t size)
-{
- struct virtio_gpu_ctrl_hdr res;
- struct
- {
- struct virtio_gpu_resource_attach_backing req;
- struct virtio_gpu_mem_entry mem;
- } req;
-
- rt_memset(&req, 0, sizeof(req));
-
- req.req.hdr.type = VIRTIO_GPU_CMD_RESOURCE_ATTACH_BACKING;
- req.req.resource_id = resource_id;
- req.req.nr_entries = 1;
-
- req.mem.addr = VIRTIO_VA2PA(buffer);
- req.mem.length = size;
-
- virtio_gpu_ctrl_send_command(virtio_gpu_dev, &req, sizeof(req), &res, sizeof(res));
-
- if (res.type == VIRTIO_GPU_RESP_OK_NODATA)
- {
- return RT_EOK;
- }
-
- return -RT_ERROR;
-}
-
-static rt_err_t virtio_gpu_set_scanout(struct virtio_gpu_device *virtio_gpu_dev, rt_uint32_t scanout_id,
- rt_uint32_t resource_id, rt_uint32_t width, rt_uint32_t height)
-{
- struct virtio_gpu_ctrl_hdr res;
- struct virtio_gpu_set_scanout req;
-
- rt_memset(&req, 0, sizeof(req));
-
- req.hdr.type = VIRTIO_GPU_CMD_SET_SCANOUT;
- req.r.x = 0;
- req.r.y = 0;
- req.r.width = width;
- req.r.height = height;
- req.scanout_id = scanout_id;
- req.resource_id = resource_id;
-
- virtio_gpu_ctrl_send_command(virtio_gpu_dev, &req, sizeof(req), &res, sizeof(res));
-
- if (res.type == VIRTIO_GPU_RESP_OK_NODATA)
- {
- return RT_EOK;
- }
-
- return -RT_ERROR;
-}
-
-static rt_err_t virtio_gpu_flush_resource(struct virtio_gpu_device *virtio_gpu_dev, rt_uint32_t resource_id,
- rt_uint32_t x, rt_uint32_t y, rt_uint32_t width, rt_uint32_t height)
-{
- struct virtio_gpu_ctrl_hdr res;
- struct virtio_gpu_resource_flush req;
-
- rt_memset(&req, 0, sizeof(req));
-
- req.hdr.type = VIRTIO_GPU_CMD_RESOURCE_FLUSH;
- req.r.x = x;
- req.r.y = y;
- req.r.width = width;
- req.r.height = height;
- req.resource_id = resource_id;
-
- virtio_gpu_ctrl_send_command(virtio_gpu_dev, &req, sizeof(req), &res, sizeof(res));
-
- if (res.type == VIRTIO_GPU_RESP_OK_NODATA)
- {
- return RT_EOK;
- }
-
- return -RT_ERROR;
-}
-
-static rt_err_t virtio_gpu_transfer_to_host_2d(struct virtio_gpu_device *virtio_gpu_dev, rt_uint32_t resource_id,
- rt_uint32_t x, rt_uint32_t y, rt_uint32_t width, rt_uint32_t height, rt_uint32_t offset)
-{
- struct virtio_gpu_ctrl_hdr res;
- struct virtio_gpu_transfer_to_host_2d req;
-
- rt_memset(&req, 0, sizeof(req));
-
- req.hdr.type = VIRTIO_GPU_CMD_TRANSFER_TO_HOST_2D;
- req.r.x = x;
- req.r.y = y;
- req.r.width = width;
- req.r.height = height;
- req.offset = offset;
- req.resource_id = resource_id;
-
- virtio_gpu_ctrl_send_command(virtio_gpu_dev, &req, sizeof(req), &res, sizeof(res));
-
- if (res.type == VIRTIO_GPU_RESP_OK_NODATA)
- {
- return RT_EOK;
- }
-
- return -RT_ERROR;
-}
-
-static rt_err_t virtio_gpu_gfx_flush_2d(struct virtio_gpu_device *virtio_gpu_dev, rt_uint32_t resource_id,
- rt_uint32_t x, rt_uint32_t y, rt_uint32_t width, rt_uint32_t height)
-{
- rt_err_t status = virtio_gpu_transfer_to_host_2d(virtio_gpu_dev, resource_id, x, y, width, height, 0);
-
- if (status == RT_EOK)
- {
- status = virtio_gpu_flush_resource(virtio_gpu_dev, resource_id, x, y, width, height);
- }
-
- return status;
-}
-
-static rt_err_t virtio_gpu_update_cursor(struct virtio_gpu_device *virtio_gpu_dev, rt_uint32_t scanout_id,
- rt_uint32_t resource_id, rt_uint32_t hot_x, rt_uint32_t hot_y)
-{
- struct virtio_gpu_update_cursor req;
-
- rt_memset(&req, 0, sizeof(req));
-
- req.hdr.type = VIRTIO_GPU_CMD_UPDATE_CURSOR;
- req.pos.scanout_id = scanout_id;
- req.resource_id = resource_id;
- req.hot_x = hot_x;
- req.hot_y = hot_y;
-
- virtio_gpu_cursor_send_command(virtio_gpu_dev, &req, sizeof(req));
-
- return RT_EOK;
-}
-
-static rt_err_t virtio_gpu_cursor_move(struct virtio_gpu_device *virtio_gpu_dev, rt_uint32_t scanout_id,
- rt_uint32_t resource_id, rt_uint32_t x, rt_uint32_t y)
-{
- struct virtio_gpu_update_cursor req;
-
- rt_memset(&req, 0, sizeof(req));
-
- req.hdr.type = VIRTIO_GPU_CMD_MOVE_CURSOR;
- req.pos.scanout_id = scanout_id;
- req.pos.x = x;
- req.pos.y = y;
- req.resource_id = resource_id;
-
- virtio_gpu_cursor_send_command(virtio_gpu_dev, &req, sizeof(req));
-
- return RT_EOK;
-}
-
-static rt_err_t virtio_gpu_cursor_set_img(struct virtio_gpu_device *virtio_gpu_dev, void *img)
-{
- rt_err_t status;
-
- rt_memcpy(virtio_gpu_dev->cursor_img, img, VIRTIO_GPU_CURSOR_IMG_SIZE);
-
- status = virtio_gpu_attach_backing_resource(virtio_gpu_dev,
- virtio_gpu_dev->cursor_resource_id, virtio_gpu_dev->cursor_img, VIRTIO_GPU_CURSOR_IMG_SIZE);
-
- if (status != RT_EOK)
- {
- return status;
- }
-
- status = virtio_gpu_transfer_to_host_2d(virtio_gpu_dev, virtio_gpu_dev->cursor_resource_id,
- 0, 0, VIRTIO_GPU_CURSOR_WIDTH, VIRTIO_GPU_CURSOR_HEIGHT, 0);
-
- return status;
-}
-
-static rt_err_t virtio_gpu_get_display_info(struct virtio_gpu_device *virtio_gpu_dev)
-{
- int i;
- struct virtio_gpu_ctrl_hdr req;
- struct virtio_gpu_resp_display_info info;
-
- rt_memset(&req, 0, sizeof(req));
- req.type = VIRTIO_GPU_CMD_GET_DISPLAY_INFO;
-
- virtio_gpu_ctrl_send_command(virtio_gpu_dev, &req, sizeof(req), &info, sizeof(info));
-
- if (info.hdr.type != VIRTIO_GPU_RESP_OK_DISPLAY_INFO)
- {
- return -RT_ERROR;
- }
-
- for (i = 0; i < VIRTIO_GPU_MAX_SCANOUTS; ++i)
- {
- if (info.pmodes[i].enabled)
- {
- if (virtio_gpu_dev->pmode_id == VIRTIO_GPU_INVALID_PMODE_ID)
- {
- rt_memcpy(&virtio_gpu_dev->pmode, &info.pmodes[i], sizeof(virtio_gpu_dev->pmode));
- virtio_gpu_dev->pmode_id = i;
- }
- }
- }
-
- return RT_EOK;
-}
-
-static rt_err_t virtio_gpu_init(rt_device_t dev)
-{
- rt_err_t status;
- struct virtio_gpu_device *virtio_gpu_dev = (struct virtio_gpu_device *)dev;
- struct virtio_device *virtio_dev = &virtio_gpu_dev->virtio_dev;
- struct virtq *queue_ctrl, *queue_cursor;
-
- queue_ctrl = &virtio_dev->queues[VIRTIO_GPU_QUEUE_CTRL];
- queue_cursor = &virtio_dev->queues[VIRTIO_GPU_QUEUE_CURSOR];
-
- queue_ctrl->avail->flags = 0;
- queue_cursor->avail->flags = 0;
-
- status = virtio_gpu_get_display_info(virtio_gpu_dev);
-
- if (virtio_gpu_dev->pmode_id != VIRTIO_GPU_INVALID_PMODE_ID && _primary_virtio_gpu_dev == RT_NULL)
- {
- /* This device is ready */
- _primary_virtio_gpu_dev = virtio_gpu_dev;
- }
-
- return status;
-}
-
-static rt_ssize_t virtio_gpu_read(rt_device_t dev, rt_off_t pos, void *buffer, rt_size_t size)
-{
- struct virtio_gpu_device *virtio_gpu_dev = (struct virtio_gpu_device *)dev;
-
- if (virtio_gpu_dev->framebuffer == RT_NULL || pos + size >= virtio_gpu_dev->smem_len)
- {
- return 0;
- }
-
- rt_mutex_take(&virtio_gpu_dev->rw_mutex, RT_WAITING_FOREVER);
-
- rt_memcpy(buffer, (rt_uint8_t *)virtio_gpu_dev->framebuffer + pos, size);
-
- rt_mutex_release(&virtio_gpu_dev->rw_mutex);
-
- return size;
-}
-
-static rt_ssize_t virtio_gpu_write(rt_device_t dev, rt_off_t pos, const void *buffer, rt_size_t size)
-{
- struct virtio_gpu_device *virtio_gpu_dev = (struct virtio_gpu_device *)dev;
-
- if (virtio_gpu_dev->framebuffer == RT_NULL || pos + size >= virtio_gpu_dev->smem_len)
- {
- return 0;
- }
-
- rt_mutex_take(&virtio_gpu_dev->rw_mutex, RT_WAITING_FOREVER);
-
- rt_memcpy((rt_uint8_t *)virtio_gpu_dev->framebuffer + pos, buffer, size);
-
- rt_mutex_release(&virtio_gpu_dev->rw_mutex);
-
- return size;
-}
-
-static rt_err_t virtio_gpu_control(rt_device_t dev, int cmd, void *args)
-{
- rt_err_t status = RT_EOK;
- struct virtio_gpu_device *virtio_gpu_dev = (struct virtio_gpu_device *)dev;
-
- switch (cmd)
- {
- case VIRTIO_DEVICE_CTRL_GPU_SET_PRIMARY:
-
- _primary_virtio_gpu_dev = virtio_gpu_dev;
-
- return status;
- }
-
- if (args == RT_NULL)
- {
- return -RT_ERROR;
- }
-
- switch (cmd)
- {
- case RTGRAPHIC_CTRL_RECT_UPDATE:
- {
- struct rt_device_rect_info *info = (struct rt_device_rect_info *)args;
-
- if (virtio_gpu_dev->pmode_id == VIRTIO_GPU_INVALID_PMODE_ID)
- {
- status = -RT_ERROR;
- break;
- }
-
- status = virtio_gpu_gfx_flush_2d(virtio_gpu_dev, virtio_gpu_dev->display_resource_id,
- info->x, info->y, info->width, info->height);
- }
- break;
- case RTGRAPHIC_CTRL_GET_INFO:
- {
- struct rt_device_graphic_info *info = (struct rt_device_graphic_info *)args;
-
- info->pixel_format = _pixel_format_convert((rt_ubase_t)args, RT_FALSE);
- info->bits_per_pixel = VIRTIO_GPU_FORMAT_BPP;
- info->pitch = virtio_gpu_dev->pmode.r.width * VIRTIO_GPU_FORMAT_PIXEL;
- info->width = virtio_gpu_dev->pmode.r.width;
- info->height = virtio_gpu_dev->pmode.r.height;
- info->framebuffer = virtio_gpu_dev->framebuffer;
- info->smem_len = virtio_gpu_dev->smem_len;
- }
- break;
- case VIRTIO_DEVICE_CTRL_GPU_CREATE_2D:
-
- virtio_gpu_dev->format = _pixel_format_convert((rt_ubase_t)args, RT_TRUE);
-
- if (virtio_gpu_dev->format == 0 || virtio_gpu_dev->pmode_id == VIRTIO_GPU_INVALID_PMODE_ID)
- {
- status = -RT_ERROR;
- break;
- }
-
- status = virtio_gpu_create_2d_resource(virtio_gpu_dev, virtio_gpu_dev->format,
- &virtio_gpu_dev->display_resource_id, virtio_gpu_dev->pmode.r.width, virtio_gpu_dev->pmode.r.height);
-
- if (status != RT_EOK)
- {
- break;
- }
-
- virtio_gpu_dev->smem_len =
- virtio_gpu_dev->pmode.r.width * virtio_gpu_dev->pmode.r.height * VIRTIO_GPU_FORMAT_PIXEL;
- virtio_gpu_dev->smem_len = RT_ALIGN(virtio_gpu_dev->smem_len, VIRTIO_PAGE_SIZE);
- virtio_gpu_dev->framebuffer = rt_malloc_align(virtio_gpu_dev->smem_len, VIRTIO_PAGE_SIZE);
-
- if (virtio_gpu_dev->framebuffer == RT_NULL)
- {
- virtio_gpu_unref_resource(virtio_gpu_dev, virtio_gpu_dev->display_resource_id);
-
- status = -RT_ENOMEM;
- break;
- }
-
- status = virtio_gpu_attach_backing_resource(virtio_gpu_dev,
- virtio_gpu_dev->display_resource_id, virtio_gpu_dev->framebuffer, virtio_gpu_dev->smem_len);
-
- if (status != RT_EOK)
- {
- break;
- }
-
- status = virtio_gpu_set_scanout(virtio_gpu_dev, virtio_gpu_dev->pmode_id, virtio_gpu_dev->display_resource_id,
- virtio_gpu_dev->pmode.r.width, virtio_gpu_dev->pmode.r.height);
-
- break;
- case VIRTIO_DEVICE_CTRL_CURSOR_SETUP:
-
- if (virtio_gpu_dev->pmode_id == VIRTIO_GPU_INVALID_PMODE_ID)
- {
- status = -RT_ERROR;
- break;
- }
-
- rt_mutex_take(&virtio_gpu_dev->ops_mutex, RT_WAITING_FOREVER);
-
- status = virtio_gpu_create_2d_resource(virtio_gpu_dev, virtio_gpu_dev->format,
- &virtio_gpu_dev->cursor_resource_id, VIRTIO_GPU_CURSOR_WIDTH, VIRTIO_GPU_CURSOR_HEIGHT);
-
- if (status != RT_EOK)
- {
- goto _cursor_setup_end;
- }
-
- status = virtio_gpu_cursor_set_img(virtio_gpu_dev, args);
-
- if (status != RT_EOK)
- {
- goto _cursor_setup_end;
- }
-
- virtio_gpu_dev->cursor_x = 0;
- virtio_gpu_dev->cursor_y = 0;
-
- status = virtio_gpu_update_cursor(virtio_gpu_dev, virtio_gpu_dev->pmode_id, virtio_gpu_dev->cursor_resource_id,
- virtio_gpu_dev->cursor_x, virtio_gpu_dev->cursor_y);
-
- if (status == RT_EOK)
- {
- virtio_gpu_dev->cursor_enable = RT_TRUE;
- }
-
-_cursor_setup_end:
- rt_mutex_release(&virtio_gpu_dev->ops_mutex);
-
- break;
- case VIRTIO_DEVICE_CTRL_CURSOR_SET_IMG:
-
- if (virtio_gpu_dev->pmode_id == VIRTIO_GPU_INVALID_PMODE_ID || !virtio_gpu_dev->cursor_enable)
- {
- status = -RT_ERROR;
- break;
- }
-
- rt_mutex_take(&virtio_gpu_dev->ops_mutex, RT_WAITING_FOREVER);
-
- status = virtio_gpu_cursor_set_img(virtio_gpu_dev, args);
-
- if (status != RT_EOK)
- {
- goto _cursor_set_img_end;
- }
-
- status = virtio_gpu_update_cursor(virtio_gpu_dev, virtio_gpu_dev->pmode_id, virtio_gpu_dev->cursor_resource_id,
- virtio_gpu_dev->cursor_x, virtio_gpu_dev->cursor_y);
-
-_cursor_set_img_end:
- rt_mutex_release(&virtio_gpu_dev->ops_mutex);
-
- break;
- case VIRTIO_DEVICE_CTRL_CURSOR_MOVE:
-
- if (virtio_gpu_dev->pmode_id == VIRTIO_GPU_INVALID_PMODE_ID || !virtio_gpu_dev->cursor_enable)
- {
- status = -RT_ERROR;
- break;
- }
-
- rt_mutex_take(&virtio_gpu_dev->ops_mutex, RT_WAITING_FOREVER);
-
- virtio_gpu_dev->cursor_x = ((rt_uint32_t *)args)[0];
- virtio_gpu_dev->cursor_y = ((rt_uint32_t *)args)[1];
-
- status = virtio_gpu_cursor_move(virtio_gpu_dev, virtio_gpu_dev->pmode_id, virtio_gpu_dev->cursor_resource_id,
- virtio_gpu_dev->cursor_x, virtio_gpu_dev->cursor_y);
-
- rt_mutex_release(&virtio_gpu_dev->ops_mutex);
-
- break;
- default:
- status = -RT_EINVAL;
- break;
- }
-
- return status;
-}
-
-#ifdef RT_USING_DEVICE_OPS
-const static struct rt_device_ops virtio_gpu_ops =
-{
- virtio_gpu_init,
- RT_NULL,
- RT_NULL,
- virtio_gpu_read,
- virtio_gpu_write,
- virtio_gpu_control
-};
-#endif
-
-static void virtio_gpu_set_pixel(const char *pixel, int x, int y)
-{
- rt_uint8_t *fb;
- struct virtio_gpu_device *virtio_gpu_dev = _primary_virtio_gpu_dev;
-
- if (virtio_gpu_dev == RT_NULL || virtio_gpu_dev->pmode_id == VIRTIO_GPU_INVALID_PMODE_ID)
- {
- return;
- }
-
- fb = (rt_uint8_t *)virtio_gpu_dev->framebuffer;
- fb += (y * virtio_gpu_dev->pmode.r.width + x) * VIRTIO_GPU_FORMAT_PIXEL;
- *((rt_uint32_t *)fb) = *((rt_uint32_t *)pixel);
-}
-
-static void virtio_gpu_get_pixel(char *pixel, int x, int y)
-{
- rt_uint8_t *fb;
- struct virtio_gpu_device *virtio_gpu_dev = _primary_virtio_gpu_dev;
-
- if (virtio_gpu_dev == RT_NULL || virtio_gpu_dev->pmode_id == VIRTIO_GPU_INVALID_PMODE_ID)
- {
- return;
- }
-
- fb = (rt_uint8_t *)virtio_gpu_dev->framebuffer;
- *((rt_uint32_t *)pixel) = *(fb + (y * virtio_gpu_dev->pmode.r.width + x) * VIRTIO_GPU_FORMAT_PIXEL);
-}
-
-static void virtio_gpu_draw_hline(const char *pixel, int x1, int x2, int y)
-{
- int i;
- rt_uint8_t *fb;
- rt_uint32_t color = *((rt_uint32_t *)pixel);
- struct virtio_gpu_device *virtio_gpu_dev = _primary_virtio_gpu_dev;
-
- if (virtio_gpu_dev == RT_NULL || virtio_gpu_dev->pmode_id == VIRTIO_GPU_INVALID_PMODE_ID ||
- x1 < 0 || x2 < 0 || y < 0)
- {
- return;
- }
-
- if (x1 > x2)
- {
- x1 ^= x2;
- x2 ^= x1;
- x1 ^= x2;
- }
-
- fb = (rt_uint8_t *)virtio_gpu_dev->framebuffer;
- fb += (y * virtio_gpu_dev->pmode.r.width + x1) * VIRTIO_GPU_FORMAT_PIXEL;
-
- for (i = x1; i < x2; ++i)
- {
- *((rt_uint32_t *)fb) = color;
-
- fb += VIRTIO_GPU_FORMAT_PIXEL;
- }
-}
-
-static void virtio_gpu_draw_vline(const char *pixel, int x, int y1, int y2)
-{
- int i;
- rt_uint8_t *fb;
- rt_uint16_t pitch;
- rt_uint32_t color = *((rt_uint32_t *)pixel);
- struct virtio_gpu_device *virtio_gpu_dev = _primary_virtio_gpu_dev;
-
- if (virtio_gpu_dev == RT_NULL || virtio_gpu_dev->pmode_id == VIRTIO_GPU_INVALID_PMODE_ID ||
- x < 0 || y1 < 0 || y2 < 0)
- {
- return;
- }
-
- if (y1 > y2)
- {
- y1 ^= y2;
- y2 ^= y1;
- y1 ^= y2;
- }
-
- fb = (rt_uint8_t *)virtio_gpu_dev->framebuffer;
- fb += (y1 * virtio_gpu_dev->pmode.r.width + x) * VIRTIO_GPU_FORMAT_PIXEL;
-
- pitch = virtio_gpu_dev->pmode.r.width * VIRTIO_GPU_FORMAT_PIXEL;
-
- for (i = y1; i < y2; ++i)
- {
- *((rt_uint32_t *)fb) = color;
-
- fb += pitch;
- }
-}
-
-static void virtio_gpu_blit_line(const char *pixel, int x, int y, rt_size_t size)
-{
- int i;
- rt_uint8_t *fb;
- rt_uint32_t *colors = (rt_uint32_t *)pixel;
- struct virtio_gpu_device *virtio_gpu_dev = _primary_virtio_gpu_dev;
-
- if (virtio_gpu_dev == RT_NULL || virtio_gpu_dev->pmode_id == VIRTIO_GPU_INVALID_PMODE_ID || x < 0 || y < 0)
- {
- return;
- }
-
- fb = (rt_uint8_t *)virtio_gpu_dev->framebuffer;
- fb += (y * virtio_gpu_dev->pmode.r.width + x) * VIRTIO_GPU_FORMAT_PIXEL;
-
- for (i = 0; i < size; ++i)
- {
- *((rt_uint32_t *)fb) = *colors++;
- fb += VIRTIO_GPU_FORMAT_PIXEL;
- }
-}
-
-static struct rt_device_graphic_ops virtio_gpu_graphic_ops =
-{
- virtio_gpu_set_pixel,
- virtio_gpu_get_pixel,
- virtio_gpu_draw_hline,
- virtio_gpu_draw_vline,
- virtio_gpu_blit_line
-};
-
-static void virtio_gpu_isr(int irqno, void *param)
-{
- rt_uint16_t id;
- struct virtio_gpu_device *virtio_gpu_dev = (struct virtio_gpu_device *)param;
- struct virtio_device *virtio_dev = &virtio_gpu_dev->virtio_dev;
- struct virtq *queue_ctrl = &virtio_dev->queues[VIRTIO_GPU_QUEUE_CTRL];
- struct virtq *queue_cursor = &virtio_dev->queues[VIRTIO_GPU_QUEUE_CURSOR];
-
-#ifdef RT_USING_SMP
- rt_base_t level = rt_spin_lock_irqsave(&virtio_dev->spinlock);
-#endif
-
- virtio_interrupt_ack(virtio_dev);
- rt_hw_dsb();
-
- while (queue_ctrl->used_idx != queue_ctrl->used->idx)
- {
- rt_hw_dsb();
- id = queue_ctrl->used->ring[queue_ctrl->used_idx % queue_ctrl->num].id;
-
- virtio_gpu_dev->info[id].ctrl_valid = RT_FALSE;
-
- queue_ctrl->used_idx++;
- }
-
- while (queue_cursor->used_idx != queue_cursor->used->idx)
- {
- rt_hw_dsb();
- id = queue_cursor->used->ring[queue_cursor->used_idx % queue_cursor->num].id;
-
- virtio_gpu_dev->info[id].cursor_valid = RT_FALSE;
-
- queue_cursor->used_idx++;
- }
-
-#ifdef RT_USING_SMP
- rt_spin_unlock_irqrestore(&virtio_dev->spinlock, level);
-#endif
-}
-
-rt_err_t rt_virtio_gpu_init(rt_ubase_t *mmio_base, rt_uint32_t irq)
-{
- static int dev_no = 0;
- char dev_name[RT_NAME_MAX];
- struct virtio_device *virtio_dev;
- struct virtio_gpu_device *virtio_gpu_dev;
-
- virtio_gpu_dev = rt_malloc(sizeof(struct virtio_gpu_device));
-
- if (virtio_gpu_dev == RT_NULL)
- {
- goto _alloc_fail;
- }
-
- virtio_dev = &virtio_gpu_dev->virtio_dev;
- virtio_dev->irq = irq;
- virtio_dev->mmio_base = mmio_base;
-
- virtio_gpu_dev->pmode_id = VIRTIO_GPU_INVALID_PMODE_ID;
- virtio_gpu_dev->display_resource_id = 0;
- virtio_gpu_dev->cursor_resource_id = 0;
- virtio_gpu_dev->next_resource_id = 0;
- virtio_gpu_dev->framebuffer = RT_NULL;
- virtio_gpu_dev->smem_len = 0;
- virtio_gpu_dev->cursor_enable = RT_FALSE;
-
-#ifdef RT_USING_SMP
- rt_spin_lock_init(&virtio_dev->spinlock);
-#endif
-
- virtio_reset_device(virtio_dev);
- virtio_status_acknowledge_driver(virtio_dev);
-
- virtio_dev->mmio_config->driver_features = virtio_dev->mmio_config->device_features & ~(
- (1 << VIRTIO_F_RING_EVENT_IDX) |
- (1 << VIRTIO_F_RING_INDIRECT_DESC));
-
- virtio_status_driver_ok(virtio_dev);
-
- if (virtio_queues_alloc(virtio_dev, 2) != RT_EOK)
- {
- goto _alloc_fail;
- }
-
- if (virtio_queue_init(virtio_dev, VIRTIO_GPU_QUEUE_CTRL, VIRTIO_GPU_QUEUE_SIZE) != RT_EOK)
- {
- goto _alloc_fail;
- }
-
- if (virtio_queue_init(virtio_dev, VIRTIO_GPU_QUEUE_CURSOR, VIRTIO_GPU_QUEUE_SIZE) != RT_EOK)
- {
- virtio_queue_destroy(virtio_dev, VIRTIO_GPU_QUEUE_CTRL);
-
- goto _alloc_fail;
- }
-
- virtio_gpu_dev->parent.type = RT_Device_Class_Graphic;
-#ifdef RT_USING_DEVICE_OPS
- virtio_gpu_dev->parent.ops = &virtio_gpu_ops;
-#else
- virtio_gpu_dev->parent.init = virtio_gpu_init;
- virtio_gpu_dev->parent.open = RT_NULL;
- virtio_gpu_dev->parent.close = RT_NULL;
- virtio_gpu_dev->parent.read = virtio_gpu_read;
- virtio_gpu_dev->parent.write = virtio_gpu_write;
- virtio_gpu_dev->parent.control = virtio_gpu_control;
-#endif
- virtio_gpu_dev->parent.user_data = &virtio_gpu_graphic_ops;
-
- rt_snprintf(dev_name, RT_NAME_MAX, "virtio-gpu%d", dev_no++);
-
- rt_mutex_init(&virtio_gpu_dev->rw_mutex, dev_name, RT_IPC_FLAG_PRIO);
- rt_mutex_init(&virtio_gpu_dev->ops_mutex, dev_name, RT_IPC_FLAG_PRIO);
-
- rt_hw_interrupt_install(irq, virtio_gpu_isr, virtio_gpu_dev, dev_name);
- rt_hw_interrupt_umask(irq);
-
- return rt_device_register((rt_device_t)virtio_gpu_dev, dev_name, RT_DEVICE_FLAG_RDWR);
-
-_alloc_fail:
-
- if (virtio_gpu_dev != RT_NULL)
- {
- virtio_queues_free(virtio_dev);
- rt_free(virtio_gpu_dev);
- }
- return -RT_ENOMEM;
-}
-#endif /* RT_USING_VIRTIO_GPU */
diff --git a/components/drivers/virtio/virtio_gpu.h b/components/drivers/virtio/virtio_gpu.h
deleted file mode 100644
index 6f894ebacf..0000000000
--- a/components/drivers/virtio/virtio_gpu.h
+++ /dev/null
@@ -1,412 +0,0 @@
-/*
- * Copyright (c) 2006-2023, RT-Thread Development Team
- *
- * SPDX-License-Identifier: Apache-2.0
- *
- * Change Logs:
- * Date Author Notes
- * 2021-11-11 GuEe-GUI the first version
- */
-
-#ifndef __VIRTIO_GPU_H__
-#define __VIRTIO_GPU_H__
-
-#include <rtdef.h>
-
-#include <virtio.h>
-
-#define VIRTIO_GPU_QUEUE_CTRL 0
-#define VIRTIO_GPU_QUEUE_CURSOR 1
-#define VIRTIO_GPU_QUEUE_SIZE 32
-
-#define VIRTIO_GPU_F_VIRGL 0 /* VIRTIO_GPU_CMD_CTX_*, VIRTIO_GPU_CMD_*_3D */
-#define VIRTIO_GPU_F_EDID 1 /* VIRTIO_GPU_CMD_GET_EDID */
-#define VIRTIO_GPU_F_RESOURCE_UUID 2 /* VIRTIO_GPU_CMD_RESOURCE_ASSIGN_UUID */
-#define VIRTIO_GPU_F_RESOURCE_BLOB 3 /* VIRTIO_GPU_CMD_RESOURCE_CREATE_BLOB */
-#define VIRTIO_GPU_F_CONTEXT_INIT 4 /* VIRTIO_GPU_CMD_CREATE_CONTEXT with context_init and multiple timelines */
-
-#define VIRTIO_GPU_EVENT_DISPLAY (1 << 0)
-
-#define VIRTIO_GPU_FORMAT_BPP 32
-#define VIRTIO_GPU_FORMAT_PIXEL 4
-#define VIRTIO_GPU_CURSOR_WIDTH 64
-#define VIRTIO_GPU_CURSOR_HEIGHT 64
-#define VIRTIO_GPU_CURSOR_IMG_SIZE (VIRTIO_GPU_CURSOR_WIDTH * VIRTIO_GPU_CURSOR_HEIGHT * VIRTIO_GPU_FORMAT_PIXEL)
-#define VIRTIO_GPU_INVALID_PMODE_ID RT_UINT32_MAX
-
-/* GPU control */
-
-struct virtio_gpu_config
-{
- rt_uint32_t events_read;
- rt_uint32_t events_clear;
- rt_uint32_t num_scanouts; /* 1 ~ 16 */
- rt_uint32_t reserved;
-};
-
-enum virtio_gpu_ctrl_type
-{
- VIRTIO_GPU_UNDEFINED = 0,
-
- /* 2d commands */
- VIRTIO_GPU_CMD_GET_DISPLAY_INFO = 0x0100,
- VIRTIO_GPU_CMD_RESOURCE_CREATE_2D,
- VIRTIO_GPU_CMD_RESOURCE_UNREF,
- VIRTIO_GPU_CMD_SET_SCANOUT,
- VIRTIO_GPU_CMD_RESOURCE_FLUSH,
- VIRTIO_GPU_CMD_TRANSFER_TO_HOST_2D,
- VIRTIO_GPU_CMD_RESOURCE_ATTACH_BACKING,
- VIRTIO_GPU_CMD_RESOURCE_DETACH_BACKING,
- VIRTIO_GPU_CMD_GET_CAPSET_INFO,
- VIRTIO_GPU_CMD_GET_CAPSET,
- VIRTIO_GPU_CMD_GET_EDID,
- VIRTIO_GPU_CMD_RESOURCE_ASSIGN_UUID,
- VIRTIO_GPU_CMD_RESOURCE_CREATE_BLOB,
- VIRTIO_GPU_CMD_SET_SCANOUT_BLOB,
-
- /* 3d commands */
- VIRTIO_GPU_CMD_CTX_CREATE = 0x0200,
- VIRTIO_GPU_CMD_CTX_DESTROY,
- VIRTIO_GPU_CMD_CTX_ATTACH_RESOURCE,
- VIRTIO_GPU_CMD_CTX_DETACH_RESOURCE,
- VIRTIO_GPU_CMD_RESOURCE_CREATE_3D,
- VIRTIO_GPU_CMD_TRANSFER_TO_HOST_3D,
- VIRTIO_GPU_CMD_TRANSFER_FROM_HOST_3D,
- VIRTIO_GPU_CMD_SUBMIT_3D,
- VIRTIO_GPU_CMD_RESOURCE_MAP_BLOB,
- VIRTIO_GPU_CMD_RESOURCE_UNMAP_BLOB,
-
- /* cursor commands */
- VIRTIO_GPU_CMD_UPDATE_CURSOR = 0x0300,
- VIRTIO_GPU_CMD_MOVE_CURSOR,
-
- /* success responses */
- VIRTIO_GPU_RESP_OK_NODATA = 0x1100,
- VIRTIO_GPU_RESP_OK_DISPLAY_INFO,
- VIRTIO_GPU_RESP_OK_CAPSET_INFO,
- VIRTIO_GPU_RESP_OK_CAPSET,
- VIRTIO_GPU_RESP_OK_EDID,
- VIRTIO_GPU_RESP_OK_RESOURCE_UUID,
- VIRTIO_GPU_RESP_OK_MAP_INFO,
-
- /* error responses */
- VIRTIO_GPU_RESP_ERR_UNSPEC = 0x1200,
- VIRTIO_GPU_RESP_ERR_OUT_OF_MEMORY,
- VIRTIO_GPU_RESP_ERR_INVALID_SCANOUT_ID,
- VIRTIO_GPU_RESP_ERR_INVALID_RESOURCE_ID,
- VIRTIO_GPU_RESP_ERR_INVALID_CONTEXT_ID,
- VIRTIO_GPU_RESP_ERR_INVALID_PARAMETER,
-};
-
-#define VIRTIO_GPU_FLAG_FENCE (1 << 0)
-
-struct virtio_gpu_ctrl_hdr
-{
- rt_uint32_t type;
- rt_uint32_t flags;
- rt_uint64_t fence_id;
- rt_uint32_t ctx_id;
- rt_uint8_t ring_idx;
- rt_uint8_t padding[3];
-};
-
-#define VIRTIO_GPU_MAX_SCANOUTS 16
-
-struct virtio_gpu_rect
-{
- rt_uint32_t x;
- rt_uint32_t y;
- rt_uint32_t width;
- rt_uint32_t height;
-};
-
-struct virtio_gpu_resp_display_info
-{
- struct virtio_gpu_ctrl_hdr hdr;
- struct virtio_gpu_display_one
- {
- struct virtio_gpu_rect r;
- rt_uint32_t enabled;
- rt_uint32_t flags;
- } pmodes[VIRTIO_GPU_MAX_SCANOUTS];
-};
-
-struct virtio_gpu_get_edid
-{
- struct virtio_gpu_ctrl_hdr hdr;
- rt_uint32_t scanout;
- rt_uint32_t padding;
-};
-
-struct virtio_gpu_resp_edid
-{
- struct virtio_gpu_ctrl_hdr hdr;
- rt_uint32_t size;
- rt_uint32_t padding;
- rt_uint8_t edid[1024];
-};
-
-enum virtio_gpu_formats
-{
- VIRTIO_GPU_FORMAT_B8G8R8A8_UNORM = 1,
- VIRTIO_GPU_FORMAT_B8G8R8X8_UNORM = 2,
- VIRTIO_GPU_FORMAT_A8R8G8B8_UNORM = 3,
- VIRTIO_GPU_FORMAT_X8R8G8B8_UNORM = 4,
-
- VIRTIO_GPU_FORMAT_R8G8B8A8_UNORM = 67,
- VIRTIO_GPU_FORMAT_X8B8G8R8_UNORM = 68,
-
- VIRTIO_GPU_FORMAT_A8B8G8R8_UNORM = 121,
- VIRTIO_GPU_FORMAT_R8G8B8X8_UNORM = 134,
-};
-
-struct virtio_gpu_resource_create_2d
-{
- struct virtio_gpu_ctrl_hdr hdr;
- rt_uint32_t resource_id;
- rt_uint32_t format;
- rt_uint32_t width;
- rt_uint32_t height;
-};
-
-struct virtio_gpu_resource_unref
-{
- struct virtio_gpu_ctrl_hdr hdr;
- rt_uint32_t resource_id;
- rt_uint32_t padding;
-};
-
-struct virtio_gpu_set_scanout
-{
- struct virtio_gpu_ctrl_hdr hdr;
- struct virtio_gpu_rect r;
- rt_uint32_t scanout_id;
- rt_uint32_t resource_id;
-};
-
-struct virtio_gpu_resource_flush
-{
- struct virtio_gpu_ctrl_hdr hdr;
- struct virtio_gpu_rect r;
- rt_uint32_t resource_id;
- rt_uint32_t padding;
-};
-
-struct virtio_gpu_transfer_to_host_2d
-{
- struct virtio_gpu_ctrl_hdr hdr;
- struct virtio_gpu_rect r;
- rt_uint64_t offset;
- rt_uint32_t resource_id;
- rt_uint32_t padding;
-};
-
-struct virtio_gpu_resource_attach_backing
-{
- struct virtio_gpu_ctrl_hdr hdr;
- rt_uint32_t resource_id;
- rt_uint32_t nr_entries;
-};
-
-struct virtio_gpu_mem_entry
-{
- rt_uint64_t addr;
- rt_uint32_t length;
- rt_uint32_t padding;
-};
-
-struct virtio_gpu_resource_detach_backing
-{
- struct virtio_gpu_ctrl_hdr hdr;
- rt_uint32_t resource_id;
- rt_uint32_t padding;
-};
-
-struct virtio_gpu_get_capset_info
-{
- struct virtio_gpu_ctrl_hdr hdr;
- rt_uint32_t capset_index;
- rt_uint32_t padding;
-};
-
-#define VIRTIO_GPU_CAPSET_VIRGL 1
-#define VIRTIO_GPU_CAPSET_VIRGL2 2
-#define VIRTIO_GPU_CAPSET_GFXSTREAM 3
-#define VIRTIO_GPU_CAPSET_VENUS 4
-#define VIRTIO_GPU_CAPSET_CROSS_DOMAIN 5
-
-struct virtio_gpu_resp_capset_info
-{
- struct virtio_gpu_ctrl_hdr hdr;
- rt_uint32_t capset_id;
- rt_uint32_t capset_max_version;
- rt_uint32_t capset_max_size;
- rt_uint32_t padding;
-};
-
-struct virtio_gpu_get_capset
-{
- struct virtio_gpu_ctrl_hdr hdr;
- rt_uint32_t capset_id;
- rt_uint32_t capset_version;
-};
-
-struct virtio_gpu_resp_capset
-{
- struct virtio_gpu_ctrl_hdr hdr;
- rt_uint8_t capset_data[];
-};
-
-struct virtio_gpu_resource_assign_uuid
-{
- struct virtio_gpu_ctrl_hdr hdr;
- rt_uint32_t resource_id;
- rt_uint32_t padding;
-};
-
-struct virtio_gpu_resp_resource_uuid
-{
- struct virtio_gpu_ctrl_hdr hdr;
- rt_uint8_t uuid[16];
-};
-
-#define VIRTIO_GPU_BLOB_MEM_GUEST 0x0001
-#define VIRTIO_GPU_BLOB_MEM_HOST3D 0x0002
-#define VIRTIO_GPU_BLOB_MEM_HOST3D_GUEST 0x0003
-
-#define VIRTIO_GPU_BLOB_FLAG_USE_MAPPABLE 0x0001
-#define VIRTIO_GPU_BLOB_FLAG_USE_SHAREABLE 0x0002
-#define VIRTIO_GPU_BLOB_FLAG_USE_CROSS_DEVICE 0x0004
-
-struct virtio_gpu_resource_create_blob
-{
- struct virtio_gpu_ctrl_hdr hdr;
- rt_uint32_t resource_id;
- rt_uint32_t blob_mem;
- rt_uint32_t blob_flags;
- rt_uint32_t nr_entries;
- rt_uint64_t blob_id;
- rt_uint64_t size;
-};
-
-struct virtio_gpu_set_scanout_blob
-{
- struct virtio_gpu_ctrl_hdr hdr;
- struct virtio_gpu_rect r;
- rt_uint32_t scanout_id;
- rt_uint32_t resource_id;
- rt_uint32_t width;
- rt_uint32_t height;
- rt_uint32_t format;
- rt_uint32_t padding;
- rt_uint32_t strides[4];
- rt_uint32_t offsets[4];
-};
-
-#define VIRTIO_GPU_CONTEXT_INIT_CAPSET_ID_MASK 0x000000ff
-struct virtio_gpu_ctx_create
-{
- struct virtio_gpu_ctrl_hdr hdr;
- rt_uint32_t nlen;
- rt_uint32_t context_init;
- char debug_name[64];
-};
-
-struct virtio_gpu_resource_map_blob
-{
- struct virtio_gpu_ctrl_hdr hdr;
- rt_uint32_t resource_id;
- rt_uint32_t padding;
- rt_uint64_t offset;
-};
-
-#define VIRTIO_GPU_MAP_CACHE_MASK 0x0f
-#define VIRTIO_GPU_MAP_CACHE_NONE 0x00
-#define VIRTIO_GPU_MAP_CACHE_CACHED 0x01
-#define VIRTIO_GPU_MAP_CACHE_UNCACHED 0x02
-#define VIRTIO_GPU_MAP_CACHE_WC 0x03
-
-struct virtio_gpu_resp_map_info
-{
- struct virtio_gpu_ctrl_hdr hdr;
- rt_uint32_t map_info;
- rt_uint32_t padding;
-};
-
-struct virtio_gpu_resource_unmap_blob
-{
- struct virtio_gpu_ctrl_hdr hdr;
- rt_uint32_t resource_id;
- rt_uint32_t padding;
-};
-
-/* GPU cursor */
-
-struct virtio_gpu_cursor_pos
-{
- rt_uint32_t scanout_id;
- rt_uint32_t x;
- rt_uint32_t y;
- rt_uint32_t padding;
-};
-
-struct virtio_gpu_update_cursor
-{
- struct virtio_gpu_ctrl_hdr hdr;
- struct virtio_gpu_cursor_pos pos;
- rt_uint32_t resource_id;
- rt_uint32_t hot_x;
- rt_uint32_t hot_y;
- rt_uint32_t padding;
-};
-
-struct virtio_gpu_device
-{
- struct rt_device parent;
-
- struct virtio_device virtio_dev;
-
- /* Current display's info */
- struct virtio_gpu_display_one pmode;
- enum virtio_gpu_formats format;
- rt_uint32_t pmode_id;
- rt_uint32_t cursor_x, cursor_y;
- rt_uint32_t display_resource_id;
- rt_uint32_t cursor_resource_id;
- rt_uint32_t next_resource_id;
-
- /* Display framebuffer */
- struct rt_mutex rw_mutex;
- void *framebuffer;
- rt_uint32_t smem_len;
-
- /* Cursor image info */
- rt_bool_t cursor_enable;
- struct rt_mutex ops_mutex;
- rt_uint8_t cursor_img[VIRTIO_GPU_CURSOR_IMG_SIZE];
-
- /* GPU request info */
- struct virtio_gpu_resp_display_info gpu_request;
-
- struct
- {
- rt_bool_t ctrl_valid;
- rt_bool_t cursor_valid;
-
- struct virtio_gpu_update_cursor cursor_cmd;
- } info[VIRTIO_GPU_QUEUE_SIZE];
-};
-
-rt_err_t rt_virtio_gpu_init(rt_ubase_t *mmio_base, rt_uint32_t irq);
-
-enum
-{
- VIRTIO_DEVICE_CTRL_GPU_SET_PRIMARY = 0x20,
- VIRTIO_DEVICE_CTRL_GPU_CREATE_2D,
-
- VIRTIO_DEVICE_CTRL_CURSOR_SETUP,
- VIRTIO_DEVICE_CTRL_CURSOR_SET_IMG,
- VIRTIO_DEVICE_CTRL_CURSOR_MOVE,
-};
-
-#endif /* __VIRTIO_GPU_H__ */
diff --git a/components/drivers/virtio/virtio_ids.h b/components/drivers/virtio/virtio_ids.h
new file mode 100644
index 0000000000..f3452e4f6d
--- /dev/null
+++ b/components/drivers/virtio/virtio_ids.h
@@ -0,0 +1,77 @@
+/*
+ * Copyright (c) 2006-2023, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ */
+
+#ifndef __VIRTIO_IDS_H__
+#define __VIRTIO_IDS_H__
+
+enum
+{
+ /* virtio 1.0 */
+ VIRTIO_DEVICE_ID_INVALID = 0, /* Invalid device */
+ VIRTIO_DEVICE_ID_NET = 1, /* Net */
+ VIRTIO_DEVICE_ID_BLOCK = 2, /* Block */
+ VIRTIO_DEVICE_ID_CONSOLE = 3, /* Console */
+ VIRTIO_DEVICE_ID_RNG = 4, /* Rng */
+ VIRTIO_DEVICE_ID_BALLOON = 5, /* Balloon */
+ VIRTIO_DEVICE_ID_IOMEM = 6, /* IO memory */
+ VIRTIO_DEVICE_ID_RPMSG = 7, /* Remote processor messaging */
+ VIRTIO_DEVICE_ID_SCSI = 8, /* SCSI */
+ VIRTIO_DEVICE_ID_9P = 9, /* 9p console */
+ VIRTIO_DEVICE_ID_MAC80211_WLAN = 10, /* Mac80211 wlan */
+ VIRTIO_DEVICE_ID_RPROC_SERIAL = 11, /* Remoteproc serial link */
+ VIRTIO_DEVICE_ID_CAIF = 12, /* CAIF */
+ VIRTIO_DEVICE_ID_MEM_BALLOON = 13, /* Memory balloon */
+ VIRTIO_DEVICE_ID_GPU = 16, /* GPU */
+ VIRTIO_DEVICE_ID_TIME = 17, /* Timer/clock device */
+ VIRTIO_DEVICE_ID_INPUT = 18, /* Input */
+ /* virtio 1.1 */
+ VIRTIO_DEVICE_ID_SOCKET = 19, /* Socket device */
+ VIRTIO_DEVICE_ID_CRYPTO = 20, /* Crypto device */
+ VIRTIO_DEVICE_ID_SIG_DIS_MOD = 21, /* Signal Distribution Module */
+ VIRTIO_DEVICE_ID_PSTORE = 22, /* Pstore device */
+ VIRTIO_DEVICE_ID_IOMMU = 23, /* IOMMU device */
+ VIRTIO_DEVICE_ID_MEM = 24, /* Memory device */
+ /* virtio 1.2 */
+ VIRTIO_DEVICE_ID_AUDIO = 25, /* Audio device */
+ VIRTIO_DEVICE_ID_FS = 26, /* File system device */
+ VIRTIO_DEVICE_ID_PMEM = 27, /* PMEM device */
+ VIRTIO_DEVICE_ID_RPMB = 28, /* Replay protected memory block device */
+ VIRTIO_DEVICE_ID_MAC80211_HWSIM = 29, /* Mac80211 hwsim wireless simulation device */
+ VIRTIO_DEVICE_ID_VIDEO_ENCODER = 30, /* Video encoder device */
+ VIRTIO_DEVICE_ID_VIDEO_DECODER = 31, /* Video decoder device */
+ VIRTIO_DEVICE_ID_SCMI = 32, /* SCMI device */
+ VIRTIO_DEVICE_ID_NITRO_SEC_MOD = 33, /* NitroSecureModule */
+ VIRTIO_DEVICE_ID_I2C_ADAPTER = 34, /* I2C adapter */
+ VIRTIO_DEVICE_ID_WATCHDOG = 35, /* Watchdog */
+ VIRTIO_DEVICE_ID_CAN = 36, /* CAN device */
+ VIRTIO_DEVICE_ID_DMABUF = 37, /* Virtio dmabuf */
+ VIRTIO_DEVICE_ID_PARAM_SERV = 38, /* Parameter Server */
+ VIRTIO_DEVICE_ID_AUDIO_POLICY = 39, /* Audio policy device */
+ VIRTIO_DEVICE_ID_BT = 40, /* Bluetooth device */
+ VIRTIO_DEVICE_ID_GPIO = 41, /* GPIO device */
+ VIRTIO_DEVICE_ID_RDMA = 42, /* RDMA device */
+ /* virtio 1.3 */
+ VIRTIO_DEVICE_ID_CAMERA = 43, /* Camera device */
+ VIRTIO_DEVICE_ID_ISM = 44, /* Internal shared memory device */
+ VIRTIO_DEVICE_ID_SPI_MASTER = 45, /* SPI master */
+
+ VIRTIO_DEVICE_ID_MAX
+};
+
+enum
+{
+ VIRTIO_PCI_SUBSYSTEM_DEVICE_ID_NET = 0x1000, /* Network card */
+ VIRTIO_PCI_SUBSYSTEM_DEVICE_ID_BLOCK = 0x1001, /* Block device */
+ VIRTIO_PCI_SUBSYSTEM_DEVICE_ID_BALLOON = 0x1002, /* Memory ballooning (traditional) */
+ VIRTIO_PCI_SUBSYSTEM_DEVICE_ID_CONSOLE = 0x1003, /* Console */
+ VIRTIO_PCI_SUBSYSTEM_DEVICE_ID_SCSI = 0x1004, /* SCSI host */
+ VIRTIO_PCI_SUBSYSTEM_DEVICE_ID_RNG = 0x1005, /* Entropy source */
+ VIRTIO_PCI_SUBSYSTEM_DEVICE_ID_9P = 0x1009, /* 9P transport */
+
+ VIRTIO_PCI_SUBSYSTEM_DEVICE_ID_MAX
+};
+
+#endif /* __VIRTIO_IDS_H__ */
diff --git a/components/drivers/virtio/virtio_input.c b/components/drivers/virtio/virtio_input.c
deleted file mode 100644
index 564b32bcaf..0000000000
--- a/components/drivers/virtio/virtio_input.c
+++ /dev/null
@@ -1,449 +0,0 @@
-/*
- * Copyright (c) 2006-2023, RT-Thread Development Team
- *
- * SPDX-License-Identifier: Apache-2.0
- *
- * Change Logs:
- * Date Author Notes
- * 2021-11-11 GuEe-GUI the first version
- */
-
-#include <rthw.h>
-#include <rtthread.h>
-#include <cpuport.h>
-
-#ifdef RT_USING_VIRTIO_INPUT
-
-#include <virtio_input.h>
-
-static void _set_bit(rt_uint32_t nr, volatile rt_ubase_t *addr)
-{
- rt_ubase_t mask = BIT_MASK(nr);
- rt_ubase_t *p = ((rt_ubase_t *)addr) + BIT_WORD(nr);
-
- *p |= mask;
-}
-
-static rt_ssize_t virtio_input_cfg_select(struct virtio_input_device *virtio_input_dev,
- rt_uint8_t select, rt_uint8_t subsel)
-{
- struct virtio_input_config *config = virtio_input_dev->config;
-
- rt_hw_dsb();
- config->select = select;
- config->subsel = subsel;
- rt_hw_dsb();
-
- return config->size;
-}
-
-static void virtio_input_cfg_bits(struct virtio_input_device *virtio_input_dev,
- rt_uint8_t select, rt_uint8_t subsel, rt_ubase_t *bits, rt_uint32_t bitcount)
-{
- int i;
- rt_uint32_t bit;
- rt_uint8_t bytes;
- rt_uint8_t *virtio_bits;
- void *config_base = virtio_input_dev->config;
- rt_off_t offset = (rt_size_t)&((struct virtio_input_config *)0)->bitmap;
-
- bytes = virtio_input_cfg_select(virtio_input_dev, select, subsel);
-
- if (bytes == 0)
- {
- return;
- }
-
- if (bitcount > bytes * 8)
- {
- bitcount = bytes * 8;
- }
-
- /*
- * Bitmap in virtio config space is a simple stream of bytes,
- * with the first byte carrying bits 0-7, second bits 8-15 and
- * so on.
- */
- virtio_bits = rt_malloc(bytes);
-
- if (virtio_bits == RT_NULL)
- {
- return;
- }
-
- for (i = 0; i < bytes; ++i)
- {
- void *buffer = (void *)virtio_bits + i;
-
- if (virtio_input_dev->virtio_dev.mmio_config->version == 1)
- {
- HWREG8(config_base + offset + i) = *((rt_uint8_t *)buffer);
- }
- else
- {
- rt_memcpy(config_base + offset + i, buffer, sizeof(rt_uint8_t));
- }
- }
-
- for (bit = 0; bit < bitcount; ++bit)
- {
- if (virtio_bits[bit / 8] & (1 << (bit % 8)))
- {
- _set_bit(bit, bits);
- }
- }
-
- rt_free(virtio_bits);
-
- if (select == VIRTIO_INPUT_CFG_EV_BITS)
- {
- _set_bit(subsel, virtio_input_dev->ev_bit);
- }
-}
-
-static rt_err_t virtio_input_init(rt_device_t dev)
-{
- int i;
- rt_uint16_t idx[VIRTIO_INPUT_QUEUE_MAX_SIZE];
- struct virtio_input_device *virtio_input_dev = (struct virtio_input_device *)dev;
- struct virtio_device *virtio_dev = &virtio_input_dev->virtio_dev;
- struct virtq *queue_event, *queue_status;
-
- virtio_input_cfg_bits(virtio_input_dev, VIRTIO_INPUT_CFG_EV_BITS, EV_KEY, virtio_input_dev->key_bit, KEY_CNT);
- virtio_input_cfg_bits(virtio_input_dev, VIRTIO_INPUT_CFG_EV_BITS, EV_REL, virtio_input_dev->rel_bit, REL_CNT);
- virtio_input_cfg_bits(virtio_input_dev, VIRTIO_INPUT_CFG_EV_BITS, EV_ABS, virtio_input_dev->abs_bit, ABS_CNT);
-
- queue_event = &virtio_dev->queues[VIRTIO_INPUT_QUEUE_EVENT];
- queue_status = &virtio_dev->queues[VIRTIO_INPUT_QUEUE_STATUS];
-
- virtio_alloc_desc_chain(virtio_dev, VIRTIO_INPUT_QUEUE_EVENT, queue_event->num, idx);
- virtio_alloc_desc_chain(virtio_dev, VIRTIO_INPUT_QUEUE_STATUS, queue_status->num, idx);
-
- for (i = 0; i < queue_event->num; ++i)
- {
- rt_uint16_t id = i;
- void *addr = &virtio_input_dev->recv_events[i];
-
- virtio_fill_desc(virtio_dev, VIRTIO_INPUT_QUEUE_EVENT, id,
- VIRTIO_VA2PA(addr), sizeof(struct virtio_input_event), VIRTQ_DESC_F_WRITE, 0);
-
- virtio_submit_chain(virtio_dev, VIRTIO_INPUT_QUEUE_EVENT, id);
- }
- rt_hw_dsb();
-
- queue_event->avail->flags = 0;
- queue_status->avail->flags = VIRTQ_AVAIL_F_NO_INTERRUPT;
-
- virtio_queue_notify(virtio_dev, VIRTIO_INPUT_QUEUE_EVENT);
-
- return RT_EOK;
-}
-
-static rt_ssize_t virtio_input_read(rt_device_t dev, rt_off_t pos, void *buffer, rt_size_t size)
-{
- struct virtio_input_device *virtio_input_dev = (struct virtio_input_device *)dev;
-
- if (buffer == RT_NULL || pos + size >= virtio_input_dev->virtio_dev.queues[VIRTIO_INPUT_QUEUE_EVENT].num)
- {
- return 0;
- }
-
- rt_mutex_take(&virtio_input_dev->rw_mutex, RT_WAITING_FOREVER);
-
- rt_memcpy(buffer, &virtio_input_dev->bcst_events[pos], size);
-
- rt_mutex_release(&virtio_input_dev->rw_mutex);
-
- return size;
-}
-
-static rt_ssize_t virtio_input_write(rt_device_t dev, rt_off_t pos, const void *buffer, rt_size_t size)
-{
- struct virtio_input_device *virtio_input_dev = (struct virtio_input_device *)dev;
-
- if (buffer == RT_NULL || pos + size >= virtio_input_dev->virtio_dev.queues[VIRTIO_INPUT_QUEUE_EVENT].num)
- {
- return 0;
- }
-
- rt_mutex_take(&virtio_input_dev->rw_mutex, RT_WAITING_FOREVER);
-
- rt_memcpy(&virtio_input_dev->bcst_events[pos], buffer, size);
-
- rt_mutex_release(&virtio_input_dev->rw_mutex);
-
- return size;
-}
-
-static rt_err_t virtio_input_control(rt_device_t dev, int cmd, void *args)
-{
- rt_err_t status = RT_EOK;
- struct virtio_input_device *virtio_input_dev = (struct virtio_input_device *)dev;
- struct virtio_device *virtio_dev = &virtio_input_dev->virtio_dev;
- struct virtio_input_config *config = virtio_input_dev->config;
-
- if (args == RT_NULL)
- {
- return -RT_ERROR;
- }
-
- switch (cmd)
- {
- case VIRTIO_DEVICE_CTRL_INPUT_GET_TYPE:
-
- *(enum virtio_input_type *)args = virtio_input_dev->type;
-
- break;
- case VIRTIO_DEVICE_CTRL_INPUT_BIND_BSCT_HANDLER:
-
- virtio_input_dev->bsct_handler = args;
-
- break;
- case VIRTIO_DEVICE_CTRL_INPUT_GET_ABS_X_INFO:
-
- virtio_input_cfg_select(virtio_input_dev, VIRTIO_INPUT_CFG_ABS_INFO, VIRTIO_INPUT_ABS_AXIS_X);
- rt_memcpy(args, config, sizeof(struct virtio_input_config));
-
- break;
- case VIRTIO_DEVICE_CTRL_INPUT_GET_ABS_Y_INFO:
-
- virtio_input_cfg_select(virtio_input_dev, VIRTIO_INPUT_CFG_ABS_INFO, VIRTIO_INPUT_ABS_AXIS_Y);
- rt_memcpy(args, config, sizeof(struct virtio_input_config));
-
- break;
- case VIRTIO_DEVICE_CTRL_INPUT_SET_STATUS:
- {
- rt_uint16_t id;
- void *addr;
- struct virtq *queue_status = &virtio_dev->queues[VIRTIO_INPUT_QUEUE_STATUS];
-
-#ifdef RT_USING_SMP
- rt_base_t level = rt_spin_lock_irqsave(&virtio_dev->spinlock);
-#endif
- id = queue_status->avail->idx % queue_status->num;
- addr = &virtio_input_dev->xmit_events[id];
-
- rt_memcpy(addr, args, sizeof(struct virtio_input_event));
-
- virtio_free_desc(virtio_dev, VIRTIO_INPUT_QUEUE_STATUS, id);
-
- virtio_fill_desc(virtio_dev, VIRTIO_INPUT_QUEUE_STATUS, id,
- VIRTIO_VA2PA(addr), sizeof(struct virtio_input_event), 0, 0);
-
- virtio_submit_chain(virtio_dev, VIRTIO_INPUT_QUEUE_STATUS, id);
-
- virtio_queue_notify(virtio_dev, VIRTIO_INPUT_QUEUE_STATUS);
-
- virtio_alloc_desc(virtio_dev, VIRTIO_INPUT_QUEUE_STATUS);
-
-#ifdef RT_USING_SMP
- rt_spin_unlock_irqrestore(&virtio_dev->spinlock, level);
-#endif
- }
- break;
- case VIRTIO_DEVICE_CTRL_INPUT_GET_EV_BIT:
-
- rt_memcpy(args, virtio_input_dev->ev_bit, sizeof(virtio_input_dev->ev_bit));
-
- break;
- case VIRTIO_DEVICE_CTRL_INPUT_GET_KEY_BIT:
-
- rt_memcpy(args, virtio_input_dev->key_bit, sizeof(virtio_input_dev->key_bit));
-
- break;
- case VIRTIO_DEVICE_CTRL_INPUT_GET_REL_BIT:
-
- rt_memcpy(args, virtio_input_dev->rel_bit, sizeof(virtio_input_dev->rel_bit));
-
- break;
- case VIRTIO_DEVICE_CTRL_INPUT_GET_ABS_BIT:
-
- rt_memcpy(args, virtio_input_dev->abs_bit, sizeof(virtio_input_dev->abs_bit));
-
- break;
- default:
- status = -RT_EINVAL;
- break;
- }
-
- return status;
-}
-
-#ifdef RT_USING_DEVICE_OPS
-const static struct rt_device_ops virtio_input_ops =
-{
- virtio_input_init,
- RT_NULL,
- RT_NULL,
- virtio_input_read,
- virtio_input_write,
- virtio_input_control
-};
-#endif
-
-static void virtio_input_isr(int irqno, void *param)
-{
- struct virtio_input_device *virtio_input_dev = (struct virtio_input_device *)param;
- struct virtio_device *virtio_dev = &virtio_input_dev->virtio_dev;
- struct virtq *event_queue = &virtio_dev->queues[VIRTIO_INPUT_QUEUE_EVENT];
- const char *dev_name = virtio_input_dev->parent.parent.name;
-
-#ifdef RT_USING_SMP
- rt_base_t level = rt_spin_lock_irqsave(&virtio_dev->spinlock);
-#endif
-
- virtio_interrupt_ack(virtio_dev);
- rt_hw_dsb();
-
- while (event_queue->used_idx != event_queue->used->idx)
- {
- rt_uint16_t id = event_queue->used->ring[event_queue->used_idx % event_queue->num].id;
- rt_uint32_t len = event_queue->used->ring[event_queue->used_idx % event_queue->num].len;
-
- if (len == sizeof(struct virtio_input_event))
- {
- struct virtio_input_event *recv_events = &virtio_input_dev->recv_events[id];
- struct virtio_input_event *bcst_events = &virtio_input_dev->bcst_events[id];
-
- if (recv_events->type >= EV_SYN && recv_events->type <= EV_ABS)
- {
- bcst_events->type = recv_events->type;
- bcst_events->code = recv_events->code;
- bcst_events->value = recv_events->value;
-
- if (virtio_input_dev->bsct_handler != RT_NULL)
- {
- virtio_input_dev->bsct_handler(*bcst_events);
- }
- }
- else
- {
- rt_kprintf("%s: Unsupport event[type: %02x, code: %02x, value: %08x]!\n",
- dev_name, recv_events->type, recv_events->code, recv_events->value);
- }
- }
- else
- {
- rt_kprintf("%s: Invalid event!\n", dev_name);
- }
-
- event_queue->used_idx++;
-
- virtio_submit_chain(virtio_dev, VIRTIO_INPUT_QUEUE_EVENT, id);
-
- virtio_queue_notify(virtio_dev, VIRTIO_INPUT_QUEUE_EVENT);
- }
-
-#ifdef RT_USING_SMP
- rt_spin_unlock_irqrestore(&virtio_dev->spinlock, level);
-#endif
-}
-
-rt_err_t rt_virtio_input_init(rt_ubase_t *mmio_base, rt_uint32_t irq)
-{
- rt_uint32_t flag;
- static int dev_no = 0;
- char dev_name[RT_NAME_MAX];
- struct virtio_device *virtio_dev;
- struct virtio_input_device *virtio_input_dev;
-
- virtio_input_dev = rt_malloc(sizeof(struct virtio_input_device));
-
- if (virtio_input_dev == RT_NULL)
- {
- goto _alloc_fail;
- }
-
- virtio_dev = &virtio_input_dev->virtio_dev;
- virtio_dev->irq = irq;
- virtio_dev->mmio_base = mmio_base;
-
- virtio_input_dev->config = (struct virtio_input_config *)virtio_dev->mmio_config->config;
- virtio_input_dev->bsct_handler = RT_NULL;
-
-#ifdef RT_USING_SMP
- rt_spin_lock_init(&virtio_dev->spinlock);
-#endif
-
- virtio_reset_device(virtio_dev);
- virtio_status_acknowledge_driver(virtio_dev);
-
- virtio_dev->mmio_config->driver_features = virtio_dev->mmio_config->device_features & ~(
- (1 << VIRTIO_F_RING_EVENT_IDX) |
- (1 << VIRTIO_F_RING_INDIRECT_DESC));
-
- virtio_status_driver_ok(virtio_dev);
-
- if (virtio_queues_alloc(virtio_dev, 2) != RT_EOK)
- {
- goto _alloc_fail;
- }
-
- if (virtio_queue_init(virtio_dev, VIRTIO_INPUT_QUEUE_EVENT, VIRTIO_INPUT_EVENT_QUEUE_SIZE) != RT_EOK)
- {
- goto _alloc_fail;
- }
-
- if (virtio_queue_init(virtio_dev, VIRTIO_INPUT_QUEUE_STATUS, VIRTIO_INPUT_STATUS_QUEUE_SIZE) != RT_EOK)
- {
- virtio_queue_destroy(virtio_dev, VIRTIO_INPUT_QUEUE_EVENT);
-
- goto _alloc_fail;
- }
-
- virtio_input_cfg_select(virtio_input_dev, VIRTIO_INPUT_CFG_ID_DEVIDS, 0);
-
- if (virtio_input_dev->config->ids.product == EV_ABS)
- {
- virtio_input_dev->type = VIRTIO_INPUT_TYPE_TABLET;
-
- virtio_input_dev->parent.type = RT_Device_Class_Touch;
-
- flag = RT_DEVICE_FLAG_STANDALONE | RT_DEVICE_FLAG_INT_RX;
- }
- else
- {
- if (virtio_input_dev->config->ids.product == EV_KEY)
- {
- virtio_input_dev->type = VIRTIO_INPUT_TYPE_KEYBOARD;
- }
- else
- {
- virtio_input_dev->type = VIRTIO_INPUT_TYPE_MOUSE;
- }
-
- /* Replace it to "KeyBoard" or "Mouse" if support in the future */
- virtio_input_dev->parent.type = RT_Device_Class_Miscellaneous;
-
- flag = RT_DEVICE_FLAG_RDWR;
- }
-#ifdef RT_USING_DEVICE_OPS
- virtio_input_dev->parent.ops = &virtio_input_ops;
-#else
- virtio_input_dev->parent.init = virtio_input_init;
- virtio_input_dev->parent.open = RT_NULL;
- virtio_input_dev->parent.close = RT_NULL;
- virtio_input_dev->parent.read = virtio_input_read;
- virtio_input_dev->parent.write = virtio_input_write;
- virtio_input_dev->parent.control = virtio_input_control;
-#endif
-
- rt_snprintf(dev_name, RT_NAME_MAX, "virtio-input%d", dev_no++);
-
- rt_mutex_init(&virtio_input_dev->rw_mutex, dev_name, RT_IPC_FLAG_PRIO);
-
- rt_hw_interrupt_install(irq, virtio_input_isr, virtio_input_dev, dev_name);
- rt_hw_interrupt_umask(irq);
-
- return rt_device_register((rt_device_t)virtio_input_dev, dev_name, flag);
-
-_alloc_fail:
-
- if (virtio_input_dev != RT_NULL)
- {
- virtio_queues_free(virtio_dev);
- rt_free(virtio_input_dev);
- }
- return -RT_ENOMEM;
-}
-#endif /* RT_USING_VIRTIO_INPUT */
diff --git a/components/drivers/virtio/virtio_input.h b/components/drivers/virtio/virtio_input.h
deleted file mode 100644
index 700088e19e..0000000000
--- a/components/drivers/virtio/virtio_input.h
+++ /dev/null
@@ -1,145 +0,0 @@
-/*
- * Copyright (c) 2006-2023, RT-Thread Development Team
- *
- * SPDX-License-Identifier: Apache-2.0
- *
- * Change Logs:
- * Date Author Notes
- * 2021-11-11 GuEe-GUI the first version
- */
-
-#ifndef __VIRTIO_INPUT_H__
-#define __VIRTIO_INPUT_H__
-
-#include <rtdef.h>
-
-#include <virtio.h>
-#include <virtio_input_event_codes.h>
-
-#define VIRTIO_INPUT_QUEUE_EVENT 0
-#define VIRTIO_INPUT_QUEUE_STATUS 1
-#define VIRTIO_INPUT_EVENT_QUEUE_SIZE 64
-#define VIRTIO_INPUT_STATUS_QUEUE_SIZE 8
-#define VIRTIO_INPUT_QUEUE_MAX_SIZE (VIRTIO_INPUT_EVENT_QUEUE_SIZE > VIRTIO_INPUT_STATUS_QUEUE_SIZE ? \
- VIRTIO_INPUT_EVENT_QUEUE_SIZE : VIRTIO_INPUT_STATUS_QUEUE_SIZE)
-
-#define VIRTIO_INPUT_ABS_AXIS_X 0
-#define VIRTIO_INPUT_ABS_AXIS_Y 1
-
-enum virtio_input_type
-{
- VIRTIO_INPUT_TYPE_KEYBOARD,
- VIRTIO_INPUT_TYPE_MOUSE,
- VIRTIO_INPUT_TYPE_TABLET,
-
- VIRTIO_INPUT_TYPE_SIZE,
-};
-
-enum virtio_input_config_select
-{
- VIRTIO_INPUT_CFG_UNSET = 0x00,
- VIRTIO_INPUT_CFG_ID_NAME = 0x01,
- VIRTIO_INPUT_CFG_ID_SERIAL = 0x02,
- VIRTIO_INPUT_CFG_ID_DEVIDS = 0x03,
- VIRTIO_INPUT_CFG_PROP_BITS = 0x10,
- VIRTIO_INPUT_CFG_EV_BITS = 0x11,
- VIRTIO_INPUT_CFG_ABS_INFO = 0x12,
-};
-
-struct virtio_input_absinfo
-{
- rt_uint32_t min; /* Minimum value for the axis */
- rt_uint32_t max; /* Maximum value for the axis */
- rt_uint32_t fuzz; /* Fuzz value that is used to filter noise from the event stream */
- rt_uint32_t flat; /* Within this value will be discarded by joydev interface and reported as 0 instead */
- rt_uint32_t res; /* Resolution for the values reported for the axis */
-};
-
-struct virtio_input_devids
-{
- rt_uint16_t bustype;
- rt_uint16_t vendor;
- rt_uint16_t product;
- rt_uint16_t version;
-};
-
-struct virtio_input_config
-{
- rt_uint8_t select;
- rt_uint8_t subsel;
- rt_uint8_t size;
- rt_uint8_t reserved[5];
-
- union
- {
- char string[128];
- rt_uint8_t bitmap[128];
- struct virtio_input_absinfo abs;
- struct virtio_input_devids ids;
- };
-} __attribute__((packed));
-
-struct virtio_input_event
-{
- rt_uint16_t type;
- rt_uint16_t code;
- rt_uint32_t value;
-};
-
-#ifdef ARCH_CPU_64BIT
-#define BITS_PER_LONG 64
-#else
-#define BITS_PER_LONG 32
-#endif
-#define BIT_MASK(nr) (1UL << ((nr) % BITS_PER_LONG))
-#define BIT_WORD(nr) ((nr) / BITS_PER_LONG)
-#define DIV_ROUND_UP(n, d) (((n) + (d) - 1) / (d))
-
-#define BITS_PER_BYTE 8
-#define BITS_PER_TYPE(type) (sizeof(type) * BITS_PER_BYTE)
-#define BITS_TO_BYTES(nr) DIV_ROUND_UP(nr, BITS_PER_TYPE(char))
-#define BITS_TO_LONGS(nr) DIV_ROUND_UP(nr, BITS_PER_TYPE(long))
-
-struct virtio_input_device
-{
- struct rt_device parent;
-
- struct virtio_device virtio_dev;
-
- rt_ubase_t ev_bit[BITS_TO_LONGS(EV_CNT)];
- rt_ubase_t key_bit[BITS_TO_LONGS(KEY_CNT)];
- rt_ubase_t rel_bit[BITS_TO_LONGS(REL_CNT)];
- rt_ubase_t abs_bit[BITS_TO_LONGS(ABS_CNT)];
-
- enum virtio_input_type type;
- struct virtio_input_config *config;
-
- /* Broadcast events */
- struct rt_mutex rw_mutex;
- void (*bsct_handler)(struct virtio_input_event event);
- struct virtio_input_event bcst_events[VIRTIO_INPUT_EVENT_QUEUE_SIZE];
-
- /* Receive events */
- struct virtio_input_event recv_events[VIRTIO_INPUT_EVENT_QUEUE_SIZE];
-
- /* Transmit status */
- struct virtio_input_event xmit_events[VIRTIO_INPUT_STATUS_QUEUE_SIZE];
-};
-
-enum
-{
- VIRTIO_DEVICE_CTRL_INPUT_GET_TYPE = 0x20,
- VIRTIO_DEVICE_CTRL_INPUT_BIND_BSCT_HANDLER,
- VIRTIO_DEVICE_CTRL_INPUT_GET_ABS_X_INFO,
- VIRTIO_DEVICE_CTRL_INPUT_GET_ABS_Y_INFO,
- VIRTIO_DEVICE_CTRL_INPUT_SET_STATUS,
-
- VIRTIO_DEVICE_CTRL_INPUT_GET_EV_BIT,
- VIRTIO_DEVICE_CTRL_INPUT_GET_KEY_BIT,
- VIRTIO_DEVICE_CTRL_INPUT_GET_REL_BIT,
- VIRTIO_DEVICE_CTRL_INPUT_GET_ABS_BIT,
-};
-
-rt_err_t rt_virtio_input_init(rt_ubase_t *mmio_base, rt_uint32_t irq);
-
-#endif /* __VIRTIO_INPUT_H__ */
diff --git a/components/drivers/virtio/virtio_input_event_codes.h b/components/drivers/virtio/virtio_input_event_codes.h
deleted file mode 100644
index 3e8d6d00f9..0000000000
--- a/components/drivers/virtio/virtio_input_event_codes.h
+++ /dev/null
@@ -1,932 +0,0 @@
-/*
- * Copyright (c) 2006-2023, RT-Thread Development Team
- *
- * SPDX-License-Identifier: Apache-2.0
- *
- * Change Logs:
- * Date Author Notes
- * 2021-11-11 GuEe-GUI the first version
- */
-
-#ifndef __VIRTIO_INPUT_EVENT_CODES__
-#define __VIRTIO_INPUT_EVENT_CODES__
-
-/* Device properties and quirks */
-#define INPUT_PROP_POINTER 0x00 /* Needs a pointer */
-#define INPUT_PROP_DIRECT 0x01 /* Direct input devices */
-#define INPUT_PROP_BUTTONPAD 0x02 /* Has button(s) under pad */
-#define INPUT_PROP_SEMI_MT 0x03 /* Touch rectangle only */
-#define INPUT_PROP_TOPBUTTONPAD 0x04 /* Softbuttons at top of pad */
-#define INPUT_PROP_POINTING_STICK 0x05 /* Is a pointing stick */
-#define INPUT_PROP_ACCELEROMETER 0x06 /* Has accelerometer */
-
-#define INPUT_PROP_MAX 0x1f
-#define INPUT_PROP_CNT (INPUT_PROP_MAX + 1)
-
-/* Event types */
-#define EV_SYN 0x00 /* Synchronization events */
-#define EV_KEY 0x01 /* Keys and buttons type */
-#define EV_REL 0x02 /* Relative axes events */
-#define EV_ABS 0x03 /* Absolute axes events */
-#define EV_MSC 0x04 /* Misc events */
-#define EV_SW 0x05 /* Switch events */
-#define EV_LED 0x11 /* LEDs events */
-#define EV_SND 0x12 /* Sounds events */
-#define EV_REP 0x14 /* Repeat events */
-#define EV_FF 0x15 /* Force feedback events */
-#define EV_PWR 0x16 /* Power management events */
-#define EV_FF_STATUS 0x17 /* Force feedback state */
-#define EV_MAX 0x1f /* Maximum number of events */
-#define EV_CNT (EV_MAX + 1)/* Event count */
-
-/* Synchronization events.*/
-#define SYN_REPORT 0
-#define SYN_CONFIG 1
-#define SYN_MT_REPORT 2
-#define SYN_DROPPED 3
-#define SYN_MAX 0xf
-#define SYN_CNT (SYN_MAX + 1)
-
-/*
- * Keys and buttons
- *
- * Most of the keys/buttons are modeled after USB HUT 1.12
- * (see http://www.usb.org/developers/hidpage).
- * Abbreviations in the comments:
- * AC - Application Control
- * AL - Application Launch Button
- * SC - System Control
- */
-#define KEY_RESERVED 0
-#define KEY_ESC 1
-#define KEY_1 2
-#define KEY_2 3
-#define KEY_3 4
-#define KEY_4 5
-#define KEY_5 6
-#define KEY_6 7
-#define KEY_7 8
-#define KEY_8 9
-#define KEY_9 10
-#define KEY_0 11
-#define KEY_MINUS 12
-#define KEY_EQUAL 13
-#define KEY_BACKSPACE 14
-#define KEY_TAB 15
-#define KEY_Q 16
-#define KEY_W 17
-#define KEY_E 18
-#define KEY_R 19
-#define KEY_T 20
-#define KEY_Y 21
-#define KEY_U 22
-#define KEY_I 23
-#define KEY_O 24
-#define KEY_P 25
-#define KEY_LEFTBRACE 26
-#define KEY_RIGHTBRACE 27
-#define KEY_ENTER 28
-#define KEY_LEFTCTRL 29
-#define KEY_A 30
-#define KEY_S 31
-#define KEY_D 32
-#define KEY_F 33
-#define KEY_G 34
-#define KEY_H 35
-#define KEY_J 36
-#define KEY_K 37
-#define KEY_L 38
-#define KEY_SEMICOLON 39
-#define KEY_APOSTROPHE 40
-#define KEY_GRAVE 41
-#define KEY_LEFTSHIFT 42
-#define KEY_BACKSLASH 43
-#define KEY_Z 44
-#define KEY_X 45
-#define KEY_C 46
-#define KEY_V 47
-#define KEY_B 48
-#define KEY_N 49
-#define KEY_M 50
-#define KEY_COMMA 51
-#define KEY_DOT 52
-#define KEY_SLASH 53
-#define KEY_RIGHTSHIFT 54
-#define KEY_KPASTERISK 55
-#define KEY_LEFTALT 56
-#define KEY_SPACE 57
-#define KEY_CAPSLOCK 58
-#define KEY_F1 59
-#define KEY_F2 60
-#define KEY_F3 61
-#define KEY_F4 62
-#define KEY_F5 63
-#define KEY_F6 64
-#define KEY_F7 65
-#define KEY_F8 66
-#define KEY_F9 67
-#define KEY_F10 68
-#define KEY_NUMLOCK 69
-#define KEY_SCROLLLOCK 70
-#define KEY_KP7 71
-#define KEY_KP8 72
-#define KEY_KP9 73
-#define KEY_KPMINUS 74
-#define KEY_KP4 75
-#define KEY_KP5 76
-#define KEY_KP6 77
-#define KEY_KPPLUS 78
-#define KEY_KP1 79
-#define KEY_KP2 80
-#define KEY_KP3 81
-#define KEY_KP0 82
-#define KEY_KPDOT 83
-
-#define KEY_ZENKAKUHANKAKU 85
-#define KEY_102ND 86
-#define KEY_F11 87
-#define KEY_F12 88
-#define KEY_RO 89
-#define KEY_KATAKANA 90
-#define KEY_HIRAGANA 91
-#define KEY_HENKAN 92
-#define KEY_KATAKANAHIRAGANA 93
-#define KEY_MUHENKAN 94
-#define KEY_KPJPCOMMA 95
-#define KEY_KPENTER 96
-#define KEY_RIGHTCTRL 97
-#define KEY_KPSLASH 98
-#define KEY_SYSRQ 99
-#define KEY_RIGHTALT 100
-#define KEY_LINEFEED 101
-#define KEY_HOME 102
-#define KEY_UP 103
-#define KEY_PAGEUP 104
-#define KEY_LEFT 105
-#define KEY_RIGHT 106
-#define KEY_END 107
-#define KEY_DOWN 108
-#define KEY_PAGEDOWN 109
-#define KEY_INSERT 110
-#define KEY_DELETE 111
-#define KEY_MACRO 112
-#define KEY_MUTE 113
-#define KEY_VOLUMEDOWN 114
-#define KEY_VOLUMEUP 115
-#define KEY_POWER 116 /* SC System Power Down */
-#define KEY_KPEQUAL 117
-#define KEY_KPPLUSMINUS 118
-#define KEY_PAUSE 119
-#define KEY_SCALE 120 /* AL Compiz Scale (Expose) */
-
-#define KEY_KPCOMMA 121
-#define KEY_HANGEUL 122
-#define KEY_HANGUEL KEY_HANGEUL
-#define KEY_HANJA 123
-#define KEY_YEN 124
-#define KEY_LEFTMETA 125
-#define KEY_RIGHTMETA 126
-#define KEY_COMPOSE 127
-
-#define KEY_STOP 128 /* AC Stop */
-#define KEY_AGAIN 129
-#define KEY_PROPS 130 /* AC Properties */
-#define KEY_UNDO 131 /* AC Undo */
-#define KEY_FRONT 132
-#define KEY_COPY 133 /* AC Copy */
-#define KEY_OPEN 134 /* AC Open */
-#define KEY_PASTE 135 /* AC Paste */
-#define KEY_FIND 136 /* AC Search */
-#define KEY_CUT 137 /* AC Cut */
-#define KEY_HELP 138 /* AL Integrated Help Center */
-#define KEY_MENU 139 /* Menu (show menu) */
-#define KEY_CALC 140 /* AL Calculator */
-#define KEY_SETUP 141
-#define KEY_SLEEP 142 /* SC System Sleep */
-#define KEY_WAKEUP 143 /* System Wake Up */
-#define KEY_FILE 144 /* AL Local Machine Browser */
-#define KEY_SENDFILE 145
-#define KEY_DELETEFILE 146
-#define KEY_XFER 147
-#define KEY_PROG1 148
-#define KEY_PROG2 149
-#define KEY_WWW 150 /* AL Internet Browser */
-#define KEY_MSDOS 151
-#define KEY_COFFEE 152 /* AL Terminal Lock/Screensaver */
-#define KEY_SCREENLOCK KEY_COFFEE
-#define KEY_ROTATE_DISPLAY 153 /* Display orientation for e.g. tablets */
-#define KEY_DIRECTION KEY_ROTATE_DISPLAY
-#define KEY_CYCLEWINDOWS 154
-#define KEY_MAIL 155
-#define KEY_BOOKMARKS 156 /* AC Bookmarks */
-#define KEY_COMPUTER 157
-#define KEY_BACK 158 /* AC Back */
-#define KEY_FORWARD 159 /* AC Forward */
-#define KEY_CLOSECD 160
-#define KEY_EJECTCD 161
-#define KEY_EJECTCLOSECD 162
-#define KEY_NEXTSONG 163
-#define KEY_PLAYPAUSE 164
-#define KEY_PREVIOUSSONG 165
-#define KEY_STOPCD 166
-#define KEY_RECORD 167
-#define KEY_REWIND 168
-#define KEY_PHONE 169 /* Media Select Telephone */
-#define KEY_ISO 170
-#define KEY_CONFIG 171 /* AL Consumer Control Configuration */
-#define KEY_HOMEPAGE 172 /* AC Home */
-#define KEY_REFRESH 173 /* AC Refresh */
-#define KEY_EXIT 174 /* AC Exit */
-#define KEY_MOVE 175
-#define KEY_EDIT 176
-#define KEY_SCROLLUP 177
-#define KEY_SCROLLDOWN 178
-#define KEY_KPLEFTPAREN 179
-#define KEY_KPRIGHTPAREN 180
-#define KEY_NEW 181 /* AC New */
-#define KEY_REDO 182 /* AC Redo/Repeat */
-
-#define KEY_F13 183
-#define KEY_F14 184
-#define KEY_F15 185
-#define KEY_F16 186
-#define KEY_F17 187
-#define KEY_F18 188
-#define KEY_F19 189
-#define KEY_F20 190
-#define KEY_F21 191
-#define KEY_F22 192
-#define KEY_F23 193
-#define KEY_F24 194
-
-#define KEY_PLAYCD 200
-#define KEY_PAUSECD 201
-#define KEY_PROG3 202
-#define KEY_PROG4 203
-#define KEY_ALL_APPLICATIONS 204 /* AC Desktop Show All Applications */
-#define KEY_DASHBOARD KEY_ALL_APPLICATIONS
-#define KEY_SUSPEND 205
-#define KEY_CLOSE 206 /* AC Close */
-#define KEY_PLAY 207
-#define KEY_FASTFORWARD 208
-#define KEY_BASSBOOST 209
-#define KEY_PRINT 210 /* AC Print */
-#define KEY_HP 211
-#define KEY_CAMERA 212
-#define KEY_SOUND 213
-#define KEY_QUESTION 214
-#define KEY_EMAIL 215
-#define KEY_CHAT 216
-#define KEY_SEARCH 217
-#define KEY_CONNECT 218
-#define KEY_FINANCE 219 /* AL Checkbook/Finance */
-#define KEY_SPORT 220
-#define KEY_SHOP 221
-#define KEY_ALTERASE 222
-#define KEY_CANCEL 223 /* AC Cancel */
-#define KEY_BRIGHTNESSDOWN 224
-#define KEY_BRIGHTNESSUP 225
-#define KEY_MEDIA 226
-
-#define KEY_SWITCHVIDEOMODE 227 /* Cycle between available video outputs (Monitor/LCD/TV-out/etc) */
-#define KEY_KBDILLUMTOGGLE 228
-#define KEY_KBDILLUMDOWN 229
-#define KEY_KBDILLUMUP 230
-
-#define KEY_SEND 231 /* AC Send */
-#define KEY_REPLY 232 /* AC Reply */
-#define KEY_FORWARDMAIL 233 /* AC Forward Msg */
-#define KEY_SAVE 234 /* AC Save */
-#define KEY_DOCUMENTS 235
-
-#define KEY_BATTERY 236
-
-#define KEY_BLUETOOTH 237
-#define KEY_WLAN 238
-#define KEY_UWB 239
-
-#define KEY_UNKNOWN 240
-
-#define KEY_VIDEO_NEXT 241 /* Drive next video source */
-#define KEY_VIDEO_PREV 242 /* Drive previous video source */
-#define KEY_BRIGHTNESS_CYCLE 243 /* Brightness up, after max is min */
-#define KEY_BRIGHTNESS_AUTO 244 /* Set Auto Brightness: manual brightness control is off, rely on ambient */
-#define KEY_BRIGHTNESS_ZERO KEY_BRIGHTNESS_AUTO
-#define KEY_DISPLAY_OFF 245 /* Display device to off state */
-
-#define KEY_WWAN 246 /* Wireless WAN (LTE, UMTS, GSM, etc.) */
-#define KEY_WIMAX KEY_WWAN
-#define KEY_RFKILL 247 /* Key that controls all radios */
-
-#define KEY_MICMUTE 248 /* Mute / unmute the microphone */
-
-/* Code 255 is reserved for special needs of AT keyboard driver */
-#define BTN_MISC 0x100
-#define BTN_0 0x100
-#define BTN_1 0x101
-#define BTN_2 0x102
-#define BTN_3 0x103
-#define BTN_4 0x104
-#define BTN_5 0x105
-#define BTN_6 0x106
-#define BTN_7 0x107
-#define BTN_8 0x108
-#define BTN_9 0x109
-
-#define BTN_MOUSE 0x110
-#define BTN_LEFT 0x110
-#define BTN_RIGHT 0x111
-#define BTN_MIDDLE 0x112
-#define BTN_SIDE 0x113
-#define BTN_EXTRA 0x114
-#define BTN_FORWARD 0x115
-#define BTN_BACK 0x116
-#define BTN_TASK 0x117
-
-#define BTN_JOYSTICK 0x120
-#define BTN_TRIGGER 0x120
-#define BTN_THUMB 0x121
-#define BTN_THUMB2 0x122
-#define BTN_TOP 0x123
-#define BTN_TOP2 0x124
-#define BTN_PINKIE 0x125
-#define BTN_BASE 0x126
-#define BTN_BASE2 0x127
-#define BTN_BASE3 0x128
-#define BTN_BASE4 0x129
-#define BTN_BASE5 0x12a
-#define BTN_BASE6 0x12b
-#define BTN_DEAD 0x12f
-
-#define BTN_GAMEPAD 0x130
-#define BTN_SOUTH 0x130
-#define BTN_A BTN_SOUTH
-#define BTN_EAST 0x131
-#define BTN_B BTN_EAST
-#define BTN_C 0x132
-#define BTN_NORTH 0x133
-#define BTN_X BTN_NORTH
-#define BTN_WEST 0x134
-#define BTN_Y BTN_WEST
-#define BTN_Z 0x135
-#define BTN_TL 0x136
-#define BTN_TR 0x137
-#define BTN_TL2 0x138
-#define BTN_TR2 0x139
-#define BTN_SELECT 0x13a
-#define BTN_START 0x13b
-#define BTN_MODE 0x13c
-#define BTN_THUMBL 0x13d
-#define BTN_THUMBR 0x13e
-
-#define BTN_DIGI 0x140
-#define BTN_TOOL_PEN 0x140
-#define BTN_TOOL_RUBBER 0x141
-#define BTN_TOOL_BRUSH 0x142
-#define BTN_TOOL_PENCIL 0x143
-#define BTN_TOOL_AIRBRUSH 0x144
-#define BTN_TOOL_FINGER 0x145
-#define BTN_TOOL_MOUSE 0x146
-#define BTN_TOOL_LENS 0x147
-#define BTN_TOOL_QUINTTAP 0x148 /* Five fingers on trackpad */
-#define BTN_STYLUS3 0x149
-#define BTN_TOUCH 0x14a
-#define BTN_STYLUS 0x14b
-#define BTN_STYLUS2 0x14c
-#define BTN_TOOL_DOUBLETAP 0x14d
-#define BTN_TOOL_TRIPLETAP 0x14e
-#define BTN_TOOL_QUADTAP 0x14f /* Four fingers on trackpad */
-
-#define BTN_WHEEL 0x150
-#define BTN_GEAR_DOWN 0x150
-#define BTN_GEAR_UP 0x151
-
-#define KEY_OK 0x160
-#define KEY_SELECT 0x161
-#define KEY_GOTO 0x162
-#define KEY_CLEAR 0x163
-#define KEY_POWER2 0x164
-#define KEY_OPTION 0x165
-#define KEY_INFO 0x166 /* AL OEM Features/Tips/Tutorial */
-#define KEY_TIME 0x167
-#define KEY_VENDOR 0x168
-#define KEY_ARCHIVE 0x169
-#define KEY_PROGRAM 0x16a /* Media Select Program Guide */
-#define KEY_CHANNEL 0x16b
-#define KEY_FAVORITES 0x16c
-#define KEY_EPG 0x16d
-#define KEY_PVR 0x16e /* Media Select Home */
-#define KEY_MHP 0x16f
-#define KEY_LANGUAGE 0x170
-#define KEY_TITLE 0x171
-#define KEY_SUBTITLE 0x172
-#define KEY_ANGLE 0x173
-#define KEY_FULL_SCREEN 0x174 /* AC View Toggle */
-#define KEY_ZOOM KEY_FULL_SCREEN
-#define KEY_MODE 0x175
-#define KEY_KEYBOARD 0x176
-#define KEY_ASPECT_RATIO 0x177 /* HUTRR37: Aspect */
-#define KEY_SCREEN KEY_ASPECT_RATIO
-#define KEY_PC 0x178 /* Media Select Computer */
-#define KEY_TV 0x179 /* Media Select TV */
-#define KEY_TV2 0x17a /* Media Select Cable */
-#define KEY_VCR 0x17b /* Media Select VCR */
-#define KEY_VCR2 0x17c /* VCR Plus */
-#define KEY_SAT 0x17d /* Media Select Satellite */
-#define KEY_SAT2 0x17e
-#define KEY_CD 0x17f /* Media Select CD */
-#define KEY_TAPE 0x180 /* Media Select Tape */
-#define KEY_RADIO 0x181
-#define KEY_TUNER 0x182 /* Media Select Tuner */
-#define KEY_PLAYER 0x183
-#define KEY_TEXT 0x184
-#define KEY_DVD 0x185 /* Media Select DVD */
-#define KEY_AUX 0x186
-#define KEY_MP3 0x187
-#define KEY_AUDIO 0x188 /* AL Audio Browser */
-#define KEY_VIDEO 0x189 /* AL Movie Browser */
-#define KEY_DIRECTORY 0x18a
-#define KEY_LIST 0x18b
-#define KEY_MEMO 0x18c /* Media Select Messages */
-#define KEY_CALENDAR 0x18d
-#define KEY_RED 0x18e
-#define KEY_GREEN 0x18f
-#define KEY_YELLOW 0x190
-#define KEY_BLUE 0x191
-#define KEY_CHANNELUP 0x192 /* Channel Increment */
-#define KEY_CHANNELDOWN 0x193 /* Channel Decrement */
-#define KEY_FIRST 0x194
-#define KEY_LAST 0x195 /* Recall Last */
-#define KEY_AB 0x196
-#define KEY_NEXT 0x197
-#define KEY_RESTART 0x198
-#define KEY_SLOW 0x199
-#define KEY_SHUFFLE 0x19a
-#define KEY_BREAK 0x19b
-#define KEY_PREVIOUS 0x19c
-#define KEY_DIGITS 0x19d
-#define KEY_TEEN 0x19e
-#define KEY_TWEN 0x19f
-#define KEY_VIDEOPHONE 0x1a0 /* Media Select Video Phone */
-#define KEY_GAMES 0x1a1 /* Media Select Games */
-#define KEY_ZOOMIN 0x1a2 /* AC Zoom In */
-#define KEY_ZOOMOUT 0x1a3 /* AC Zoom Out */
-#define KEY_ZOOMRESET 0x1a4 /* AC Zoom */
-#define KEY_WORDPROCESSOR 0x1a5 /* AL Word Processor */
-#define KEY_EDITOR 0x1a6 /* AL Text Editor */
-#define KEY_SPREADSHEET 0x1a7 /* AL Spreadsheet */
-#define KEY_GRAPHICSEDITOR 0x1a8 /* AL Graphics Editor */
-#define KEY_PRESENTATION 0x1a9 /* AL Presentation App */
-#define KEY_DATABASE 0x1aa /* AL Database App */
-#define KEY_NEWS 0x1ab /* AL Newsreader */
-#define KEY_VOICEMAIL 0x1ac /* AL Voicemail */
-#define KEY_ADDRESSBOOK 0x1ad /* AL Contacts/Address Book */
-#define KEY_MESSENGER 0x1ae /* AL Instant Messaging */
-#define KEY_DISPLAYTOGGLE 0x1af /* Turn display (LCD) on and off */
-#define KEY_BRIGHTNESS_TOGGLE KEY_DISPLAYTOGGLE
-#define KEY_SPELLCHECK 0x1b0 /* AL Spell Check */
-#define KEY_LOGOFF 0x1b1 /* AL Logoff */
-
-#define KEY_DOLLAR 0x1b2
-#define KEY_EURO 0x1b3
-
-#define KEY_FRAMEBACK 0x1b4 /* Consumer - transport controls */
-#define KEY_FRAMEFORWARD 0x1b5
-#define KEY_CONTEXT_MENU 0x1b6 /* GenDesc - system context menu */
-#define KEY_MEDIA_REPEAT 0x1b7 /* Consumer - transport control */
-#define KEY_10CHANNELSUP 0x1b8 /* 10 channels up (10+) */
-#define KEY_10CHANNELSDOWN 0x1b9 /* 10 channels down (10-) */
-#define KEY_IMAGES 0x1ba /* AL Image Browser */
-#define KEY_NOTIFICATION_CENTER 0x1bc /* Show/hide the notification center */
-#define KEY_PICKUP_PHONE 0x1bd /* Answer incoming call */
-#define KEY_HANGUP_PHONE 0x1be /* Decline incoming call */
-
-#define KEY_DEL_EOL 0x1c0
-#define KEY_DEL_EOS 0x1c1
-#define KEY_INS_LINE 0x1c2
-#define KEY_DEL_LINE 0x1c3
-
-#define KEY_FN 0x1d0
-#define KEY_FN_ESC 0x1d1
-#define KEY_FN_F1 0x1d2
-#define KEY_FN_F2 0x1d3
-#define KEY_FN_F3 0x1d4
-#define KEY_FN_F4 0x1d5
-#define KEY_FN_F5 0x1d6
-#define KEY_FN_F6 0x1d7
-#define KEY_FN_F7 0x1d8
-#define KEY_FN_F8 0x1d9
-#define KEY_FN_F9 0x1da
-#define KEY_FN_F10 0x1db
-#define KEY_FN_F11 0x1dc
-#define KEY_FN_F12 0x1dd
-#define KEY_FN_1 0x1de
-#define KEY_FN_2 0x1df
-#define KEY_FN_D 0x1e0
-#define KEY_FN_E 0x1e1
-#define KEY_FN_F 0x1e2
-#define KEY_FN_S 0x1e3
-#define KEY_FN_B 0x1e4
-#define KEY_FN_RIGHT_SHIFT 0x1e5
-
-#define KEY_BRL_DOT1 0x1f1
-#define KEY_BRL_DOT2 0x1f2
-#define KEY_BRL_DOT3 0x1f3
-#define KEY_BRL_DOT4 0x1f4
-#define KEY_BRL_DOT5 0x1f5
-#define KEY_BRL_DOT6 0x1f6
-#define KEY_BRL_DOT7 0x1f7
-#define KEY_BRL_DOT8 0x1f8
-#define KEY_BRL_DOT9 0x1f9
-#define KEY_BRL_DOT10 0x1fa
-
-#define KEY_NUMERIC_0 0x200 /* Used by phones, remote controls, and other keypads */
-#define KEY_NUMERIC_1 0x201
-#define KEY_NUMERIC_2 0x202
-#define KEY_NUMERIC_3 0x203
-#define KEY_NUMERIC_4 0x204
-#define KEY_NUMERIC_5 0x205
-#define KEY_NUMERIC_6 0x206
-#define KEY_NUMERIC_7 0x207
-#define KEY_NUMERIC_8 0x208
-#define KEY_NUMERIC_9 0x209
-#define KEY_NUMERIC_STAR 0x20a
-#define KEY_NUMERIC_POUND 0x20b
-#define KEY_NUMERIC_A 0x20c /* Phone key A - HUT Telephony 0xb9 */
-#define KEY_NUMERIC_B 0x20d
-#define KEY_NUMERIC_C 0x20e
-#define KEY_NUMERIC_D 0x20f
-
-#define KEY_CAMERA_FOCUS 0x210
-#define KEY_WPS_BUTTON 0x211 /* WiFi Protected Setup key */
-
-#define KEY_TOUCHPAD_TOGGLE 0x212 /* Request switch touchpad on or off */
-#define KEY_TOUCHPAD_ON 0x213
-#define KEY_TOUCHPAD_OFF 0x214
-
-#define KEY_CAMERA_ZOOMIN 0x215
-#define KEY_CAMERA_ZOOMOUT 0x216
-#define KEY_CAMERA_UP 0x217
-#define KEY_CAMERA_DOWN 0x218
-#define KEY_CAMERA_LEFT 0x219
-#define KEY_CAMERA_RIGHT 0x21a
-
-#define KEY_ATTENDANT_ON 0x21b
-#define KEY_ATTENDANT_OFF 0x21c
-#define KEY_ATTENDANT_TOGGLE 0x21d /* Attendant call on or off */
-#define KEY_LIGHTS_TOGGLE 0x21e /* Reading light on or off */
-
-#define BTN_DPAD_UP 0x220
-#define BTN_DPAD_DOWN 0x221
-#define BTN_DPAD_LEFT 0x222
-#define BTN_DPAD_RIGHT 0x223
-
-#define KEY_ALS_TOGGLE 0x230 /* Ambient light sensor */
-#define KEY_ROTATE_LOCK_TOGGLE 0x231 /* Display rotation lock */
-
-#define KEY_BUTTONCONFIG 0x240 /* AL Button Configuration */
-#define KEY_TASKMANAGER 0x241 /* AL Task/Project Manager */
-#define KEY_JOURNAL 0x242 /* AL Log/Journal/Timecard */
-#define KEY_CONTROLPANEL 0x243 /* AL Control Panel */
-#define KEY_APPSELECT 0x244 /* AL Select Task/Application */
-#define KEY_SCREENSAVER 0x245 /* AL Screen Saver */
-#define KEY_VOICECOMMAND 0x246 /* Listening Voice Command */
-#define KEY_ASSISTANT 0x247 /* AL Context-aware desktop assistant */
-#define KEY_KBD_LAYOUT_NEXT 0x248 /* AC Next Keyboard Layout Select */
-#define KEY_EMOJI_PICKER 0x249 /* Show/hide emoji picker (HUTRR101) */
-#define KEY_DICTATE 0x24a /* Start or Stop Voice Dictation Session (HUTRR99) */
-
-#define KEY_BRIGHTNESS_MIN 0x250 /* Set Brightness to Minimum */
-#define KEY_BRIGHTNESS_MAX 0x251 /* Set Brightness to Maximum */
-
-#define KEY_KBDINPUTASSIST_PREV 0x260
-#define KEY_KBDINPUTASSIST_NEXT 0x261
-#define KEY_KBDINPUTASSIST_PREVGROUP 0x262
-#define KEY_KBDINPUTASSIST_NEXTGROUP 0x263
-#define KEY_KBDINPUTASSIST_ACCEPT 0x264
-#define KEY_KBDINPUTASSIST_CANCEL 0x265
-
-/* Diagonal movement keys */
-#define KEY_RIGHT_UP 0x266
-#define KEY_RIGHT_DOWN 0x267
-#define KEY_LEFT_UP 0x268
-#define KEY_LEFT_DOWN 0x269
-
-#define KEY_ROOT_MENU 0x26a /* Show Device's Root Menu */
-/* Show Top Menu of the Media (e.g. DVD) */
-#define KEY_MEDIA_TOP_MENU 0x26b
-#define KEY_NUMERIC_11 0x26c
-#define KEY_NUMERIC_12 0x26d
-/*
- * Toggle Audio Description: refers to an audio service that helps blind and
- * visually impaired consumers understand the action in a program. Note: in
- * some countries this is referred to as "Video Description".
- */
-#define KEY_AUDIO_DESC 0x26e
-#define KEY_3D_MODE 0x26f
-#define KEY_NEXT_FAVORITE 0x270
-#define KEY_STOP_RECORD 0x271
-#define KEY_PAUSE_RECORD 0x272
-#define KEY_VOD 0x273 /* Video on Demand */
-#define KEY_UNMUTE 0x274
-#define KEY_FASTREVERSE 0x275
-#define KEY_SLOWREVERSE 0x276
-/*
- * Control a data application associated with the currently viewed channel,
- * e.g. teletext or data broadcast application (MHEG, MHP, HbbTV, etc.)
- */
-#define KEY_DATA 0x277
-#define KEY_ONSCREEN_KEYBOARD 0x278
-/* Electronic privacy screen control */
-#define KEY_PRIVACY_SCREEN_TOGGLE 0x279
-
-/* Select an area of screen to be copied */
-#define KEY_SELECTIVE_SCREENSHOT 0x27a
-
-/* Move the focus to the next or previous user controllable element within a UI container */
-#define KEY_NEXT_ELEMENT 0x27b
-#define KEY_PREVIOUS_ELEMENT 0x27c
-
-/* Toggle Autopilot engagement */
-#define KEY_AUTOPILOT_ENGAGE_TOGGLE 0x27d
-
-/* Shortcut Keys */
-#define KEY_MARK_WAYPOINT 0x27e
-#define KEY_SOS 0x27f
-#define KEY_NAV_CHART 0x280
-#define KEY_FISHING_CHART 0x281
-#define KEY_SINGLE_RANGE_RADAR 0x282
-#define KEY_DUAL_RANGE_RADAR 0x283
-#define KEY_RADAR_OVERLAY 0x284
-#define KEY_TRADITIONAL_SONAR 0x285
-#define KEY_CLEARVU_SONAR 0x286
-#define KEY_SIDEVU_SONAR 0x287
-#define KEY_NAV_INFO 0x288
-#define KEY_BRIGHTNESS_MENU 0x289
-
-/*
- * Some keyboards have keys which do not have a defined meaning, these keys
- * are intended to be programmed / bound to macros by the user. For most
- * keyboards with these macro-keys the key-sequence to inject, or action to
- * take, is all handled by software on the host side. So from the kernel's
- * point of view these are just normal keys.
- *
- * The KEY_MACRO# codes below are intended for such keys, which may be labeled
- * e.g. G1-G18, or S1 - S30. The KEY_MACRO# codes MUST NOT be used for keys
- * where the marking on the key does indicate a defined meaning / purpose.
- *
- * The KEY_MACRO# codes MUST also NOT be used as fallback for when no existing
- * KEY_FOO define matches the marking / purpose. In this case a new KEY_FOO
- * define MUST be added.
- */
-#define KEY_MACRO1 0x290
-#define KEY_MACRO2 0x291
-#define KEY_MACRO3 0x292
-#define KEY_MACRO4 0x293
-#define KEY_MACRO5 0x294
-#define KEY_MACRO6 0x295
-#define KEY_MACRO7 0x296
-#define KEY_MACRO8 0x297
-#define KEY_MACRO9 0x298
-#define KEY_MACRO10 0x299
-#define KEY_MACRO11 0x29a
-#define KEY_MACRO12 0x29b
-#define KEY_MACRO13 0x29c
-#define KEY_MACRO14 0x29d
-#define KEY_MACRO15 0x29e
-#define KEY_MACRO16 0x29f
-#define KEY_MACRO17 0x2a0
-#define KEY_MACRO18 0x2a1
-#define KEY_MACRO19 0x2a2
-#define KEY_MACRO20 0x2a3
-#define KEY_MACRO21 0x2a4
-#define KEY_MACRO22 0x2a5
-#define KEY_MACRO23 0x2a6
-#define KEY_MACRO24 0x2a7
-#define KEY_MACRO25 0x2a8
-#define KEY_MACRO26 0x2a9
-#define KEY_MACRO27 0x2aa
-#define KEY_MACRO28 0x2ab
-#define KEY_MACRO29 0x2ac
-#define KEY_MACRO30 0x2ad
-
-/*
- * Some keyboards with the macro-keys described above have some extra keys
- * for controlling the host-side software responsible for the macro handling:
- * -A macro recording start/stop key. Note that not all keyboards which emit
- * KEY_MACRO_RECORD_START will also emit KEY_MACRO_RECORD_STOP if
- * KEY_MACRO_RECORD_STOP is not advertised, then KEY_MACRO_RECORD_START
- * should be interpreted as a recording start/stop toggle;
- * -Keys for switching between different macro (pre)sets, either a key for
- * cycling through the configured presets or keys to directly select a preset.
- */
-#define KEY_MACRO_RECORD_START 0x2b0
-#define KEY_MACRO_RECORD_STOP 0x2b1
-#define KEY_MACRO_PRESET_CYCLE 0x2b2
-#define KEY_MACRO_PRESET1 0x2b3
-#define KEY_MACRO_PRESET2 0x2b4
-#define KEY_MACRO_PRESET3 0x2b5
-
-/*
- * Some keyboards have a buildin LCD panel where the contents are controlled
- * by the host. Often these have a number of keys directly below the LCD
- * intended for controlling a menu shown on the LCD. These keys often don't
- * have any labeling so we just name them KEY_KBD_LCD_MENU#
- */
-#define KEY_KBD_LCD_MENU1 0x2b8
-#define KEY_KBD_LCD_MENU2 0x2b9
-#define KEY_KBD_LCD_MENU3 0x2ba
-#define KEY_KBD_LCD_MENU4 0x2bb
-#define KEY_KBD_LCD_MENU5 0x2bc
-
-#define BTN_TRIGGER_HAPPY 0x2c0
-#define BTN_TRIGGER_HAPPY1 0x2c0
-#define BTN_TRIGGER_HAPPY2 0x2c1
-#define BTN_TRIGGER_HAPPY3 0x2c2
-#define BTN_TRIGGER_HAPPY4 0x2c3
-#define BTN_TRIGGER_HAPPY5 0x2c4
-#define BTN_TRIGGER_HAPPY6 0x2c5
-#define BTN_TRIGGER_HAPPY7 0x2c6
-#define BTN_TRIGGER_HAPPY8 0x2c7
-#define BTN_TRIGGER_HAPPY9 0x2c8
-#define BTN_TRIGGER_HAPPY10 0x2c9
-#define BTN_TRIGGER_HAPPY11 0x2ca
-#define BTN_TRIGGER_HAPPY12 0x2cb
-#define BTN_TRIGGER_HAPPY13 0x2cc
-#define BTN_TRIGGER_HAPPY14 0x2cd
-#define BTN_TRIGGER_HAPPY15 0x2ce
-#define BTN_TRIGGER_HAPPY16 0x2cf
-#define BTN_TRIGGER_HAPPY17 0x2d0
-#define BTN_TRIGGER_HAPPY18 0x2d1
-#define BTN_TRIGGER_HAPPY19 0x2d2
-#define BTN_TRIGGER_HAPPY20 0x2d3
-#define BTN_TRIGGER_HAPPY21 0x2d4
-#define BTN_TRIGGER_HAPPY22 0x2d5
-#define BTN_TRIGGER_HAPPY23 0x2d6
-#define BTN_TRIGGER_HAPPY24 0x2d7
-#define BTN_TRIGGER_HAPPY25 0x2d8
-#define BTN_TRIGGER_HAPPY26 0x2d9
-#define BTN_TRIGGER_HAPPY27 0x2da
-#define BTN_TRIGGER_HAPPY28 0x2db
-#define BTN_TRIGGER_HAPPY29 0x2dc
-#define BTN_TRIGGER_HAPPY30 0x2dd
-#define BTN_TRIGGER_HAPPY31 0x2de
-#define BTN_TRIGGER_HAPPY32 0x2df
-#define BTN_TRIGGER_HAPPY33 0x2e0
-#define BTN_TRIGGER_HAPPY34 0x2e1
-#define BTN_TRIGGER_HAPPY35 0x2e2
-#define BTN_TRIGGER_HAPPY36 0x2e3
-#define BTN_TRIGGER_HAPPY37 0x2e4
-#define BTN_TRIGGER_HAPPY38 0x2e5
-#define BTN_TRIGGER_HAPPY39 0x2e6
-#define BTN_TRIGGER_HAPPY40 0x2e7
-
-/* We avoid low common keys in module aliases so they don't get huge. */
-#define KEY_MIN_INTERESTING KEY_MUTE
-#define KEY_MAX 0x2ff
-#define KEY_CNT (KEY_MAX + 1)
-
-/* Relative axes */
-#define REL_X 0x00
-#define REL_Y 0x01
-#define REL_Z 0x02
-#define REL_RX 0x03
-#define REL_RY 0x04
-#define REL_RZ 0x05
-#define REL_HWHEEL 0x06
-#define REL_DIAL 0x07
-#define REL_WHEEL 0x08
-#define REL_MISC 0x09
-/*
- * 0x0a is reserved and should not be used in input drivers.
- * It was used by HID as REL_MISC + 1 and userspace needs to detect if
- * the next REL_* event is correct or is just REL_MISC + n.
- * We define here REL_RESERVED so userspace can rely on it and detect
- * the situation described above.
- */
-#define REL_RESERVED 0x0a
-#define REL_WHEEL_HI_RES 0x0b
-#define REL_HWHEEL_HI_RES 0x0c
-#define REL_MAX 0x0f
-#define REL_CNT (REL_MAX + 1)
-
-/* Absolute axes */
-#define ABS_X 0x00
-#define ABS_Y 0x01
-#define ABS_Z 0x02
-#define ABS_RX 0x03
-#define ABS_RY 0x04
-#define ABS_RZ 0x05
-#define ABS_THROTTLE 0x06
-#define ABS_RUDDER 0x07
-#define ABS_WHEEL 0x08
-#define ABS_GAS 0x09
-#define ABS_BRAKE 0x0a
-#define ABS_HAT0X 0x10
-#define ABS_HAT0Y 0x11
-#define ABS_HAT1X 0x12
-#define ABS_HAT1Y 0x13
-#define ABS_HAT2X 0x14
-#define ABS_HAT2Y 0x15
-#define ABS_HAT3X 0x16
-#define ABS_HAT3Y 0x17
-#define ABS_PRESSURE 0x18
-#define ABS_DISTANCE 0x19
-#define ABS_TILT_X 0x1a
-#define ABS_TILT_Y 0x1b
-#define ABS_TOOL_WIDTH 0x1c
-
-#define ABS_VOLUME 0x20
-
-#define ABS_MISC 0x28
-
-/*
- * 0x2e is reserved and should not be used in input drivers.
- * It was used by HID as ABS_MISC + 6 and userspace needs to detect if
- * the next ABS_* event is correct or is just ABS_MISC + n.
- * We define here ABS_RESERVED so userspace can rely on it and detect
- * the situation described above.
- */
-#define ABS_RESERVED 0x2e
-
-#define ABS_MT_SLOT 0x2f /* MT slot being modified */
-#define ABS_MT_TOUCH_MAJOR 0x30 /* Major axis of touching ellipse */
-#define ABS_MT_TOUCH_MINOR 0x31 /* Minor axis (omit if circular) */
-#define ABS_MT_WIDTH_MAJOR 0x32 /* Major axis of approaching ellipse */
-#define ABS_MT_WIDTH_MINOR 0x33 /* Minor axis (omit if circular) */
-#define ABS_MT_ORIENTATION 0x34 /* Ellipse orientation */
-#define ABS_MT_POSITION_X 0x35 /* Center X touch position */
-#define ABS_MT_POSITION_Y 0x36 /* Center Y touch position */
-#define ABS_MT_TOOL_TYPE 0x37 /* Type of touching device */
-#define ABS_MT_BLOB_ID 0x38 /* Group a set of packets as a blob */
-#define ABS_MT_TRACKING_ID 0x39 /* Unique ID of initiated contact */
-#define ABS_MT_PRESSURE 0x3a /* Pressure on contact area */
-#define ABS_MT_DISTANCE 0x3b /* Contact hover distance */
-#define ABS_MT_TOOL_X 0x3c /* Center X tool position */
-#define ABS_MT_TOOL_Y 0x3d /* Center Y tool position */
-
-
-#define ABS_MAX 0x3f
-#define ABS_CNT (ABS_MAX + 1)
-
-/* Switch events */
-#define SW_LID 0x00 /* Set = lid shut */
-#define SW_TABLET_MODE 0x01 /* Set = tablet mode */
-#define SW_HEADPHONE_INSERT 0x02 /* Set = inserted */
-#define SW_RFKILL_ALL 0x03 /* rfkill master switch, type "any" set = radio enabled */
-#define SW_RADIO SW_RFKILL_ALL /* deprecated */
-#define SW_MICROPHONE_INSERT 0x04 /* Set = inserted */
-#define SW_DOCK 0x05 /* Set = plugged into dock */
-#define SW_LINEOUT_INSERT 0x06 /* Set = inserted */
-#define SW_JACK_PHYSICAL_INSERT 0x07 /* Set = mechanical switch set */
-#define SW_VIDEOOUT_INSERT 0x08 /* Set = inserted */
-#define SW_CAMERA_LENS_COVER 0x09 /* Set = lens covered */
-#define SW_KEYPAD_SLIDE 0x0a /* Set = keypad slide out */
-#define SW_FRONT_PROXIMITY 0x0b /* Set = front proximity sensor active */
-#define SW_ROTATE_LOCK 0x0c /* Set = rotate locked/disabled */
-#define SW_LINEIN_INSERT 0x0d /* Set = inserted */
-#define SW_MUTE_DEVICE 0x0e /* Set = device disabled */
-#define SW_PEN_INSERTED 0x0f /* Set = pen inserted */
-#define SW_MACHINE_COVER 0x10 /* Set = cover closed */
-#define SW_MAX 0x10
-#define SW_CNT (SW_MAX + 1)
-
-/* Misc events */
-#define MSC_SERIAL 0x00
-#define MSC_PULSELED 0x01
-#define MSC_GESTURE 0x02
-#define MSC_RAW 0x03
-#define MSC_SCAN 0x04
-#define MSC_TIMESTAMP 0x05
-#define MSC_MAX 0x07
-#define MSC_CNT (MSC_MAX + 1)
-
-/* LEDs */
-#define LED_NUML 0x00
-#define LED_CAPSL 0x01
-#define LED_SCROLLL 0x02
-#define LED_COMPOSE 0x03
-#define LED_KANA 0x04
-#define LED_SLEEP 0x05
-#define LED_SUSPEND 0x06
-#define LED_MUTE 0x07
-#define LED_MISC 0x08
-#define LED_MAIL 0x09
-#define LED_CHARGING 0x0a
-#define LED_MAX 0x0f
-#define LED_CNT (LED_MAX + 1)
-
-/* Autorepeat values */
-#define REP_DELAY 0x00
-#define REP_PERIOD 0x01
-#define REP_MAX 0x01
-#define REP_CNT (REP_MAX + 1)
-
-/* Sounds */
-#define SND_CLICK 0x00
-#define SND_BELL 0x01
-#define SND_TONE 0x02
-#define SND_MAX 0x07
-#define SND_CNT (SND_MAX + 1)
-
-#endif /* __VIRTIO_INPUT_EVENT_CODES__ */
diff --git a/components/drivers/virtio/virtio_internal.h b/components/drivers/virtio/virtio_internal.h
new file mode 100644
index 0000000000..b86ae224b1
--- /dev/null
+++ b/components/drivers/virtio/virtio_internal.h
@@ -0,0 +1,112 @@
+/*
+ * 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_INTERNAL_H__
+#define __VIRTIO_INTERNAL_H__
+
+#include <drivers/virtio.h>
+#include <drivers/core/dm.h>
+
+rt_inline rt_bool_t virtio_legacy_is_little_endian(void)
+{
+#ifdef ARCH_CPU_BIG_ENDIAN
+ return RT_FALSE;
+#else
+ return RT_TRUE;
+#endif
+}
+
+rt_inline rt_bool_t virtio_is_little_endian(struct rt_virtio_device *vdev)
+{
+ return rt_virtio_has_feature(vdev, VIRTIO_F_VERSION_1) ||
+ virtio_legacy_is_little_endian();
+}
+
+#ifdef __CHECKER__
+#define FORCE __attribute__((force))
+#else
+#define FORCE
+#endif
+
+rt_inline rt_uint16_t virtio16_to_cpu(struct rt_virtio_device *vdev, rt_uint16_t val)
+{
+ if (virtio_is_little_endian(vdev))
+ {
+ return rt_le16_to_cpu((FORCE rt_le16_t)val);
+ }
+ else
+ {
+ return rt_be16_to_cpu((FORCE rt_be16_t)val);
+ }
+}
+
+rt_inline rt_uint16_t cpu_to_virtio16(struct rt_virtio_device *vdev, rt_uint16_t val)
+{
+ if (virtio_is_little_endian(vdev))
+ {
+ return (FORCE rt_le16_t)rt_cpu_to_le16(val);
+ }
+ else
+ {
+ return (FORCE rt_be16_t)rt_cpu_to_be16(val);
+ }
+}
+
+rt_inline rt_uint32_t virtio32_to_cpu(struct rt_virtio_device *vdev, rt_uint32_t val)
+{
+ if (virtio_is_little_endian(vdev))
+ {
+ return rt_le32_to_cpu((FORCE rt_le32_t)val);
+ }
+ else
+ {
+ return rt_be32_to_cpu((FORCE rt_be32_t)val);
+ }
+}
+
+rt_inline rt_uint32_t cpu_to_virtio32(struct rt_virtio_device *vdev, rt_uint32_t val)
+{
+ if (virtio_is_little_endian(vdev))
+ {
+ return (FORCE rt_le32_t)rt_cpu_to_le32(val);
+ }
+ else
+ {
+ return (FORCE rt_be32_t)rt_cpu_to_be32(val);
+ }
+}
+
+rt_inline rt_uint64_t virtio64_to_cpu(struct rt_virtio_device *vdev, rt_uint64_t val)
+{
+ if (virtio_is_little_endian(vdev))
+ {
+ return rt_le64_to_cpu((FORCE rt_le64_t)val);
+ }
+ else
+ {
+ return rt_be64_to_cpu((FORCE rt_be64_t)val);
+ }
+}
+
+rt_inline rt_uint64_t cpu_to_virtio64(struct rt_virtio_device *vdev, rt_uint64_t val)
+{
+ if (virtio_is_little_endian(vdev))
+ {
+ return (FORCE rt_le64_t)rt_cpu_to_le64(val);
+ }
+ else
+ {
+ return (FORCE rt_be64_t)rt_cpu_to_be64(val);
+ }
+}
+
+#undef FORCE
+
+#endif /* __VIRTIO_INTERNAL_H__ */
diff --git a/components/drivers/virtio/virtio_mmio.c b/components/drivers/virtio/virtio_mmio.c
new file mode 100644
index 0000000000..12f2f93dcf
--- /dev/null
+++ b/components/drivers/virtio/virtio_mmio.c
@@ -0,0 +1,652 @@
+/*
+ * 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 <rtthread.h>
+
+#define DBG_TAG "virtio.mmio"
+#define DBG_LVL DBG_INFO
+#include <rtdbg.h>
+
+#include <mmu.h>
+
+#include <drivers/ofw.h>
+#include <drivers/pic.h>
+#include <drivers/virtio.h>
+#include <drivers/platform.h>
+#include <drivers/core/bus.h>
+
+#define VIRTIO_MMIO_MAGIC 0x000 /* <RO> Magic value */
+#define VIRTIO_MMIO_VERSION 0x004 /* <RO> Device version number */
+#define VIRTIO_MMIO_DEVICE_ID 0x008 /* <RO> Virtio Subsystem Device ID */
+#define VIRTIO_MMIO_VENDOR_ID 0x00c /* <RO> Virtio Subsystem Vendor ID */
+#define VIRTIO_MMIO_DEVICE_FEATURES 0x010 /* <RO> Flags representing features the device supports */
+#define VIRTIO_MMIO_DEVICE_FEATURES_SEL 0x014 /* <WO> Device (host) features word selection. */
+#define VIRTIO_MMIO_DRIVER_FEATURES 0x020 /* <WO> Device features understood and activated by the driver */
+#define VIRTIO_MMIO_DRIVER_FEATURES_SEL 0x024 /* <WO> Activated (guest) features word selection */
+#define VIRTIO_MMIO_GUEST_PAGE_SIZE 0x028 /* <WO> Guest page size, this value should be a power of 2 */
+#define VIRTIO_MMIO_QUEUE_SEL 0x030 /* <WO> Virtual queue index */
+#define VIRTIO_MMIO_QUEUE_NUM_MAX 0x034 /* <RO> Maximum virtual queue size */
+#define VIRTIO_MMIO_QUEUE_NUM 0x038 /* <WO> Virtual queue size */
+#define VIRTIO_MMIO_QUEUE_ALIGN 0x03c /* <WO> Used Ring alignment in the virtual queue */
+#define VIRTIO_MMIO_QUEUE_PFN 0x040 /* <RW> Guest physical page number of the virtual queue */
+#define VIRTIO_MMIO_QUEUE_READY 0x044 /* <RW> Virtual queue ready bit */
+#define VIRTIO_MMIO_QUEUE_NOTIFY 0x050 /* <WO> Queue notifier */
+#define VIRTIO_MMIO_INTERRUPT_STATUS 0x060 /* <RO> Interrupt status */
+#define VIRTIO_MMIO_INTERRUPT_ACK 0x064 /* <WO> Interrupt acknowledge */
+#define VIRTIO_MMIO_STATUS 0x070 /* <RW> Device status */
+#define VIRTIO_MMIO_QUEUE_DESC_LOW 0x080 /* <WO> Virtual queue's descriptor Area 64 bit long physical address */
+#define VIRTIO_MMIO_QUEUE_DESC_HIGH 0x084 /* <WO> */
+#define VIRTIO_MMIO_QUEUE_AVAIL_LOW 0x090 /* <WO> Virtual queue's available Ring (Driver Area) 64 bit long physical address */
+#define VIRTIO_MMIO_QUEUE_AVAIL_HIGH 0x094 /* <WO> */
+#define VIRTIO_MMIO_QUEUE_USED_LOW 0x0a0 /* <WO> Virtual queue's used Ring (Device Area) 64 bit long physical address */
+#define VIRTIO_MMIO_QUEUE_USED_HIGH 0x0a4 /* <WO> */
+#define VIRTIO_MMIO_SHM_SEL 0x0ac /* <WO> Shared memory region id */
+#define VIRTIO_MMIO_SHM_LEN_LOW 0x0b0 /* <RO> Shared memory region length, 64 bits in two halves */
+#define VIRTIO_MMIO_SHM_LEN_HIGH 0x0b4 /* <RO> */
+#define VIRTIO_MMIO_SHM_BASE_LOW 0x0b8 /* <RO> Shared memory region base address, 64 bits in two halves */
+#define VIRTIO_MMIO_SHM_BASE_HIGH 0x0bc /* <RO> */
+#define VIRTIO_MMIO_CONFIG_GENERATION 0x0fc /* <RO> Configuration atomicity value */
+#define VIRTIO_MMIO_CONFIG 0x100 /* <RO> Configuration space */
+
+#define VIRTIO_MMIO_INT_VIRTQ (1 << 0) /* The device has used a buffer in at least one of the active virtual queues */
+#define VIRTIO_MMIO_INT_CONFIG (1 << 1) /* The configuration of the device has changed */
+
+#define VIRTIO_MMIO_VIRTQ_PAGE_SHIFT ARCH_PAGE_SHIFT
+#define VIRTIO_MMIO_VIRTQ_PAGE_SZIE (1 << VIRTIO_MMIO_VIRTQ_PAGE_SHIFT)
+#define VIRTIO_MMIO_VIRTQ_ALIGN_SHIFT VIRTIO_MMIO_VIRTQ_PAGE_SHIFT
+#define VIRTIO_MMIO_VIRTQ_ALIGN (1 << VIRTIO_MMIO_VIRTQ_ALIGN_SHIFT)
+
+struct virtio_mmio
+{
+ struct rt_virtio_device parent;
+
+ void *base;
+ int irq;
+ rt_ubase_t version;
+
+ struct rt_spinlock spinlock;
+};
+
+#define raw_to_virtio_mmio(raw) rt_container_of(raw, struct virtio_mmio, parent)
+
+rt_inline rt_uint64_t virtio_mmio_read64(struct virtio_mmio *vio, int offset)
+{
+ return rt_cpu_to_le64(HWREG64(vio->base + offset));
+}
+
+rt_inline void virtio_mmio_write64(struct virtio_mmio *vio, int offset, rt_uint64_t value)
+{
+ HWREG64(vio->base + offset) = rt_le64_to_cpu(value);
+}
+
+rt_inline rt_uint32_t virtio_mmio_read32(struct virtio_mmio *vio, int offset)
+{
+ return rt_cpu_to_le32(HWREG32(vio->base + offset));
+}
+
+rt_inline void virtio_mmio_write32(struct virtio_mmio *vio, int offset, rt_uint32_t value)
+{
+ HWREG32(vio->base + offset) = rt_le32_to_cpu(value);
+}
+
+rt_inline rt_uint16_t virtio_mmio_read16(struct virtio_mmio *vio, int offset)
+{
+ return rt_cpu_to_le16(HWREG16(vio->base + offset));
+}
+
+rt_inline void virtio_mmio_write16(struct virtio_mmio *vio, int offset, rt_uint16_t value)
+{
+ HWREG16(vio->base + offset) = rt_le16_to_cpu(value);
+}
+
+rt_inline rt_uint8_t virtio_mmio_read8(struct virtio_mmio *vio, int offset)
+{
+ return HWREG8(vio->base + offset);
+}
+
+rt_inline void virtio_mmio_write8(struct virtio_mmio *vio, int offset, rt_uint8_t value)
+{
+ HWREG8(vio->base + offset) = value;
+}
+
+static void virtio_mmio_isr(int irqno, void *param)
+{
+ rt_uint32_t status;
+ struct virtio_mmio *vio = param;
+
+ /* Read interrupts */
+ status = virtio_mmio_read32(vio, VIRTIO_MMIO_INTERRUPT_STATUS);
+
+ /* Acknowledge interrupts */
+ virtio_mmio_write32(vio, VIRTIO_MMIO_INTERRUPT_ACK, status);
+
+ if (status & VIRTIO_MMIO_INT_CONFIG)
+ {
+ rt_virtio_device_config_changed(&vio->parent);
+ }
+
+ if (status & VIRTIO_MMIO_INT_VIRTQ)
+ {
+ struct rt_virtqueue *vq;
+ rt_ubase_t level = rt_spin_lock_irqsave(&vio->spinlock);
+
+ rt_list_for_each_entry(vq, &vio->parent.vq_node, list)
+ {
+ rt_virtqueue_isr(irqno, vq);
+ }
+
+ rt_spin_unlock_irqrestore(&vio->spinlock, level);
+ }
+}
+
+static rt_bool_t virtio_mmio_notify(struct rt_virtqueue *vq)
+{
+ struct virtio_mmio *vio = raw_to_virtio_mmio(vq->vdev);
+
+ virtio_mmio_write32(vio, VIRTIO_MMIO_QUEUE_NOTIFY, vq->index);
+
+ return RT_TRUE;
+}
+
+static rt_err_t virtio_mmio_read_shm_region(struct virtio_mmio *vio,
+ struct rt_virtio_shm_region *shm)
+{
+ virtio_mmio_write32(vio, VIRTIO_MMIO_SHM_SEL, shm->id);
+
+ shm->size = virtio_mmio_read32(vio, VIRTIO_MMIO_SHM_LEN_HIGH);
+ shm->size <<= 32;
+ shm->size |= virtio_mmio_read32(vio, VIRTIO_MMIO_SHM_LEN_LOW);
+
+ if (shm->size == ~(rt_uint64_t)0UL)
+ {
+ return -RT_EEMPTY;
+ }
+
+ shm->base = virtio_mmio_read32(vio, VIRTIO_MMIO_SHM_BASE_HIGH);
+ shm->base <<= 32;
+ shm->base |= virtio_mmio_read32(vio, VIRTIO_MMIO_SHM_BASE_LOW);
+
+ return RT_EOK;
+}
+
+static rt_err_t virtio_mmio_get_status(struct rt_virtio_device *vdev,
+ rt_uint8_t *out_status)
+{
+ struct virtio_mmio *vio = raw_to_virtio_mmio(vdev);
+
+ *out_status = virtio_mmio_read32(vio, VIRTIO_MMIO_STATUS);
+
+ return RT_EOK;
+}
+
+static rt_err_t virtio_mmio_set_status(struct rt_virtio_device *vdev,
+ rt_uint8_t status)
+{
+ struct virtio_mmio *vio = raw_to_virtio_mmio(vdev);
+
+ RT_ASSERT(status != 0);
+
+ virtio_mmio_write32(vio, VIRTIO_MMIO_STATUS, status);
+
+ return RT_EOK;
+}
+
+static rt_err_t virtio_mmio_get_features(struct rt_virtio_device *vdev,
+ rt_uint64_t *out_features)
+{
+ rt_uint64_t features;
+ struct virtio_mmio *vio = raw_to_virtio_mmio(vdev);
+
+ virtio_mmio_write32(vio, VIRTIO_MMIO_DEVICE_FEATURES_SEL, 1);
+ features = virtio_mmio_read32(vio, VIRTIO_MMIO_DEVICE_FEATURES);
+ features <<= 32;
+
+ virtio_mmio_write32(vio, VIRTIO_MMIO_DEVICE_FEATURES_SEL, 0);
+ features |= virtio_mmio_read32(vio, VIRTIO_MMIO_DEVICE_FEATURES);
+
+ *out_features = features;
+
+ return RT_EOK;
+}
+
+static rt_err_t virtio_mmio_set_features(struct rt_virtio_device *vdev)
+{
+ struct virtio_mmio *vio = raw_to_virtio_mmio(vdev);
+
+ /* Make sure there are no mixed devices */
+ if (vio->version == 2 && !(vdev->features & RT_BIT(VIRTIO_F_VERSION_1)))
+ {
+ LOG_E("%s devices (version 2) must provide VIRTIO_F_VERSION_1 feature",
+ rt_dm_dev_get_name(&vdev->parent));
+
+ return -RT_EINVAL;
+ }
+
+ virtio_mmio_write32(vio, VIRTIO_MMIO_DRIVER_FEATURES_SEL, 1);
+ virtio_mmio_write32(vio, VIRTIO_MMIO_DRIVER_FEATURES,
+ (rt_uint32_t)(vdev->features >> 32));
+
+ virtio_mmio_write32(vio, VIRTIO_MMIO_DRIVER_FEATURES_SEL, 0);
+ virtio_mmio_write32(vio, VIRTIO_MMIO_DRIVER_FEATURES,
+ (rt_uint32_t)vdev->features);
+
+ return RT_EOK;
+}
+
+static rt_err_t virtio_mmio_get_config(struct rt_virtio_device *vdev,
+ rt_uint32_t offset, void *dst, int length)
+{
+ struct virtio_mmio *vio = raw_to_virtio_mmio(vdev);
+
+ offset += VIRTIO_MMIO_CONFIG;
+
+ if (vio->version == 1)
+ {
+ for (int i = 0; i < length; ++i)
+ {
+ ((rt_uint8_t *)dst)[i] = virtio_mmio_read8(vio, offset + i);
+ }
+
+ return RT_EOK;
+ }
+
+ switch (length)
+ {
+ case 4:
+ *(rt_uint32_t *)dst = virtio_mmio_read32(vio, offset);
+ break;
+ case 1:
+ *(rt_uint8_t *)dst = virtio_mmio_read8(vio, offset);
+ break;
+ case 2:
+ *(rt_uint16_t *)dst = virtio_mmio_read16(vio, offset);
+ break;
+ case 8:
+ *(rt_uint64_t *)dst = virtio_mmio_read64(vio, offset);
+ break;
+ default:
+ return -RT_EINVAL;
+ }
+
+ return RT_EOK;
+}
+
+static rt_err_t virtio_mmio_set_config(struct rt_virtio_device *vdev,
+ rt_uint32_t offset, const void *src, int length)
+{
+ struct virtio_mmio *vio = raw_to_virtio_mmio(vdev);
+
+ offset += VIRTIO_MMIO_CONFIG;
+
+ if (vio->version == 1)
+ {
+ for (int i = 0; i < length; ++i)
+ {
+ virtio_mmio_write8(vio, offset + i, ((rt_uint8_t *)src)[i]);
+ }
+
+ return RT_EOK;
+ }
+
+ switch (length)
+ {
+ case 4:
+ virtio_mmio_write32(vio, offset, *(rt_uint32_t *)src);
+ break;
+ case 1:
+ virtio_mmio_write8(vio, offset, *(rt_uint8_t *)src);
+ break;
+ case 2:
+ virtio_mmio_write16(vio, offset, *(rt_uint16_t *)src);
+ break;
+ case 8:
+ virtio_mmio_write64(vio, offset, *(rt_uint64_t *)src);
+ break;
+ default:
+ return -RT_EINVAL;
+ }
+
+ return RT_EOK;
+}
+
+static struct rt_virtqueue *virtio_mmio_install_vq(struct rt_virtio_device *vdev,
+ int index, const char *name, rt_virtqueue_callback cb,
+ struct rt_virtqueue_formula *formula)
+{
+ rt_uint32_t num_max;
+ struct rt_virtqueue *vq;
+ struct virtio_mmio *vio = raw_to_virtio_mmio(vdev);
+
+ virtio_mmio_write32(vio, VIRTIO_MMIO_QUEUE_SEL, index);
+
+ if (virtio_mmio_read32(vio, vio->version == 1 ?
+ VIRTIO_MMIO_QUEUE_PFN : VIRTIO_MMIO_QUEUE_READY))
+ {
+ return RT_NULL;
+ }
+
+ num_max = virtio_mmio_read32(vio, VIRTIO_MMIO_QUEUE_NUM_MAX);
+
+ if (num_max == 0)
+ {
+ LOG_E("%s.virtqueue[%d](%s) num_max is zero",
+ rt_dm_dev_get_name(&vdev->parent), index, name);
+
+ return RT_NULL;
+ }
+
+ vq = rt_virtqueue_create(vdev, name, index, num_max, VIRTIO_MMIO_VIRTQ_ALIGN,
+ virtio_mmio_notify, cb, formula);
+
+ if (!vq)
+ {
+ return vq;
+ }
+
+ vq->num_max = num_max;
+
+ /* Activate the queue */
+ virtio_mmio_write32(vio, VIRTIO_MMIO_QUEUE_NUM, rt_virtqueue_get_virtq_size(vq));
+
+ if (vio->version == 1)
+ {
+ rt_uint32_t pfn = (rt_ubase_t)rt_kmem_v2p((void *)rt_virtqueue_get_desc_addr(vq));
+
+ pfn >>= VIRTIO_MMIO_VIRTQ_ALIGN_SHIFT;
+
+ virtio_mmio_write32(vio, VIRTIO_MMIO_QUEUE_ALIGN, VIRTIO_MMIO_VIRTQ_ALIGN);
+ virtio_mmio_write32(vio, VIRTIO_MMIO_QUEUE_PFN, pfn);
+ }
+ else
+ {
+ rt_uint64_t page;
+
+ page = (rt_ubase_t)rt_kmem_v2p((void *)rt_virtqueue_get_desc_addr(vq));
+ virtio_mmio_write32(vio, VIRTIO_MMIO_QUEUE_DESC_LOW, (rt_uint32_t)page);
+ virtio_mmio_write32(vio, VIRTIO_MMIO_QUEUE_DESC_HIGH, (rt_uint32_t)(page >> 32));
+
+ page = (rt_ubase_t)rt_kmem_v2p((void *)rt_virtqueue_get_avail_addr(vq));
+ virtio_mmio_write32(vio, VIRTIO_MMIO_QUEUE_AVAIL_LOW, (rt_uint32_t)page);
+ virtio_mmio_write32(vio, VIRTIO_MMIO_QUEUE_AVAIL_HIGH, (rt_uint32_t)(page >> 32));
+
+ page = (rt_ubase_t)rt_kmem_v2p((void *)rt_virtqueue_get_used_addr(vq));
+ virtio_mmio_write32(vio, VIRTIO_MMIO_QUEUE_USED_LOW, (rt_uint32_t)page);
+ virtio_mmio_write32(vio, VIRTIO_MMIO_QUEUE_USED_HIGH, (rt_uint32_t)(page >> 32));
+
+ virtio_mmio_write32(vio, VIRTIO_MMIO_QUEUE_READY, 1);
+ }
+
+ return vq;
+}
+
+static rt_err_t virtio_mmio_install_vqs(struct rt_virtio_device *vdev, int vqs_nr,
+ struct rt_virtqueue *vqs[], const char *names[], rt_virtqueue_callback cbs[])
+{
+ struct virtio_mmio *vio = raw_to_virtio_mmio(vdev);
+
+ for (int i = 0, vq_idx = 0; i < vqs_nr; ++i)
+ {
+ if (!names[i])
+ {
+ vqs[i] = RT_NULL;
+
+ continue;
+ }
+
+ vqs[i] = virtio_mmio_install_vq(vdev, vq_idx++, names[i], cbs[i], RT_NULL);
+
+ if (!vqs[i])
+ {
+ rt_virtio_virtqueue_release(vdev);
+
+ return -RT_ERROR;
+ }
+ }
+
+ rt_hw_interrupt_install(vio->irq, virtio_mmio_isr, vio,
+ rt_dm_dev_get_name(&vdev->parent));
+ rt_hw_interrupt_umask(vio->irq);
+
+ return RT_EOK;
+}
+
+static rt_err_t virtio_mmio_release_vqs(struct rt_virtio_device *vdev)
+{
+ struct rt_virtqueue *vq, *vq_next;
+ struct virtio_mmio *vio = raw_to_virtio_mmio(vdev);
+
+ rt_hw_interrupt_mask(vio->irq);
+ rt_pic_detach_irq(vio->irq, vio);
+
+ rt_list_for_each_entry_safe(vq, vq_next, &vio->parent.vq_node, list)
+ {
+ virtio_mmio_write32(vio, VIRTIO_MMIO_QUEUE_SEL, vq->index);
+
+ if (vio->version == 1)
+ {
+ virtio_mmio_write32(vio, VIRTIO_MMIO_QUEUE_PFN, RT_NULL);
+ }
+ else
+ {
+ rt_uint32_t status;
+
+ virtio_mmio_write32(vio, VIRTIO_MMIO_QUEUE_READY, RT_NULL);
+ status = virtio_mmio_read32(vio, VIRTIO_MMIO_QUEUE_READY);
+
+ if (!status)
+ {
+ LOG_W("%s.virtqueue[%s] VIRTIO_MMIO_QUEUE_READY = %d",
+ rt_dm_dev_get_name(&vq->vdev->parent), vq->name, status);
+ }
+ }
+
+ rt_virtqueue_delete(&vio->parent, vq);
+ }
+
+ return RT_EOK;
+}
+
+static rt_err_t virtio_mmio_control_vqs(struct rt_virtio_device *vdev,
+ rt_uint32_t cfg, void *data)
+{
+ rt_err_t err = RT_EOK;
+ struct virtio_mmio *vio = raw_to_virtio_mmio(vdev);
+
+ switch (cfg)
+ {
+ case RT_VIRTQUEUE_CTL_IRQ_AFFINITY:
+ err = rt_pic_irq_set_affinity(vio->irq, (rt_bitmap_t *)data);
+ break;
+
+ case RT_VIRTQUEUE_CTL_READ_SHM_REGION:
+ if (!data)
+ {
+ err = -RT_EINVAL;
+ break;
+ }
+
+ err = virtio_mmio_read_shm_region(vio, data);
+ break;
+
+ default:
+ err = -RT_ENOSYS;
+ break;
+ }
+
+ return err;
+}
+
+static rt_err_t virtio_mmio_generation(struct rt_virtio_device *vdev,
+ rt_uint32_t *out_counter)
+{
+ struct virtio_mmio *vio = raw_to_virtio_mmio(vdev);
+
+ if (vio->version == 1)
+ {
+ *out_counter = 0;
+ }
+ else
+ {
+ *out_counter = virtio_mmio_read32(vio, VIRTIO_MMIO_CONFIG_GENERATION);
+ }
+
+ return RT_EOK;
+}
+
+static rt_err_t virtio_mmio_reset(struct rt_virtio_device *vdev)
+{
+ struct virtio_mmio *vio = raw_to_virtio_mmio(vdev);
+
+ virtio_mmio_write32(vio, VIRTIO_MMIO_STATUS, 0);
+
+ return RT_EOK;
+}
+
+static const struct rt_virtio_transport virtio_mmio_trans =
+{
+ .get_status = virtio_mmio_get_status,
+ .set_status = virtio_mmio_set_status,
+ .get_features = virtio_mmio_get_features,
+ .set_features = virtio_mmio_set_features,
+ .get_config = virtio_mmio_get_config,
+ .set_config = virtio_mmio_set_config,
+ .install_vqs = virtio_mmio_install_vqs,
+ .release_vqs = virtio_mmio_release_vqs,
+ .control_vqs = virtio_mmio_control_vqs,
+ .generation = virtio_mmio_generation,
+ .reset = virtio_mmio_reset,
+};
+
+static rt_err_t virtio_mmio_probe(struct rt_platform_device *pdev)
+{
+ rt_err_t err = RT_EOK;
+ rt_uint32_t magic;
+ struct rt_virtio_device *vdev;
+ struct rt_device *dev = &pdev->parent;
+ struct virtio_mmio *vio = rt_calloc(1, sizeof(*vio));
+
+ if (!vio)
+ {
+ return -RT_ENOMEM;
+ }
+
+ vio->base = rt_dm_dev_iomap(dev, 0);
+
+ if (!vio->base)
+ {
+ err = -RT_EIO;
+
+ goto _fail;
+ }
+
+ vio->irq = rt_dm_dev_get_irq(dev, 0);
+
+ if (vio->irq < 0)
+ {
+ err = vio->irq;
+
+ goto _fail;
+ }
+
+ magic = virtio_mmio_read32(vio, VIRTIO_MMIO_MAGIC);
+
+ /* 0x74726976 (a Little Endian equivalent of the "virt" string). */
+ if (magic != ('v' | 'i' << 8 | 'r' << 16 | 't' << 24))
+ {
+ err = -RT_EINVAL;
+
+ LOG_E("Invalid magic: %x", magic);
+
+ goto _fail;
+ }
+
+ vio->version = virtio_mmio_read32(vio, VIRTIO_MMIO_VERSION);
+
+ /* Only support version 1~2 */
+ if (vio->version < 1 || vio->version > 2)
+ {
+ err = -RT_ENOSYS;
+
+ LOG_E("Not support version: %d", vio->version);
+
+ goto _fail;
+ }
+
+ vdev = &vio->parent;
+
+ vdev->id.device = virtio_mmio_read32(vio, VIRTIO_MMIO_DEVICE_ID);
+
+ if (vdev->id.device == VIRTIO_DEVICE_ID_INVALID)
+ {
+ err = -RT_EEMPTY;
+ goto _fail;
+ }
+
+ vdev->id.vendor = virtio_mmio_read32(vio, VIRTIO_MMIO_VENDOR_ID);
+
+ if (vio->version == 1)
+ {
+ virtio_mmio_write32(vio, VIRTIO_MMIO_GUEST_PAGE_SIZE, VIRTIO_MMIO_VIRTQ_PAGE_SZIE);
+ }
+
+ rt_spin_lock_init(&vio->spinlock);
+
+ vdev->trans = &virtio_mmio_trans;
+ vdev->parent.ofw_node = dev->ofw_node;
+
+ if ((err = rt_virtio_device_register(vdev)))
+ {
+ goto _fail;
+ }
+
+ dev->user_data = vio;
+
+ return RT_EOK;
+
+_fail:
+ if (vio->base)
+ {
+ rt_iounmap(vio->base);
+ }
+ rt_free(vio);
+
+ return err;
+}
+
+static rt_err_t virtio_mmio_remove(struct rt_platform_device *pdev)
+{
+ struct virtio_mmio *vio = pdev->parent.user_data;
+
+ rt_hw_interrupt_mask(vio->irq);
+ rt_pic_detach_irq(vio->irq, vio);
+
+ rt_bus_remove_device(&vio->parent.parent);
+
+ rt_iounmap(vio->base);
+ rt_free(vio);
+
+ return RT_EOK;
+}
+
+static const struct rt_ofw_node_id virtio_mmio_ofw_ids[] =
+{
+ { .compatible = "virtio,mmio" },
+ { /* sentinel */ }
+};
+
+static struct rt_platform_driver virtio_mmio_driver =
+{
+ .name = "virtio-mmio",
+ .ids = virtio_mmio_ofw_ids,
+
+ .probe = virtio_mmio_probe,
+ .remove = virtio_mmio_remove,
+};
+RT_PLATFORM_DRIVER_EXPORT(virtio_mmio_driver);
diff --git a/components/drivers/virtio/virtio_mmio.h b/components/drivers/virtio/virtio_mmio.h
deleted file mode 100644
index bb5bc79b95..0000000000
--- a/components/drivers/virtio/virtio_mmio.h
+++ /dev/null
@@ -1,67 +0,0 @@
-/*
- * Copyright (c) 2006-2023, RT-Thread Development Team
- *
- * SPDX-License-Identifier: Apache-2.0
- *
- * Change Logs:
- * Date Author Notes
- * 2021-9-16 GuEe-GUI the first version
- * 2021-11-11 GuEe-GUI modify to virtio common interface
- */
-
-#ifndef __VIRTIO_MMIO_H__
-#define __VIRTIO_MMIO_H__
-
-#include <rtdef.h>
-
-struct virtio_mmio_config
-{
- rt_uint32_t magic; /* [0x00]<RO> Magic value */
- rt_uint32_t version; /* [0x04]<RO> Device version number */
- rt_uint32_t device_id; /* [0x08]<RO> Virtio Subsystem Device ID */
- rt_uint32_t vendor_id; /* [0x0c]<RO> Virtio Subsystem Vendor ID */
- rt_uint32_t device_features; /* [0x10]<RO> Flags representing features the device supports */
- rt_uint32_t device_features_sel; /* [0x14]<WO> Device (host) features word selection. */
- rt_uint32_t res0[2]; /* [0x18] */
- rt_uint32_t driver_features; /* [0x20]<WO> Device features understood and activated by the driver */
- rt_uint32_t driver_features_sel; /* [0x24]<WO> Activated (guest) features word selection */
- rt_uint32_t guest_page_size; /* [0x28]<WO> Guest page size, this value should be a power of 2 */
- rt_uint32_t res1[1]; /* [0x2c] */
- rt_uint32_t queue_sel; /* [0x30]<WO> Virtual queue index */
- rt_uint32_t queue_num_max; /* [0x34]<RO> Maximum virtual queue size */
- rt_uint32_t queue_num; /* [0x38]<WO> Virtual queue size */
- rt_uint32_t queue_align; /* [0x3c]<WO> Used Ring alignment in the virtual queue */
- rt_uint32_t queue_pfn; /* [0x40]<RW> Guest physical page number of the virtual queue */
- rt_uint32_t queue_ready; /* [0x44]<RW> Virtual queue ready bit */
- rt_uint32_t res2[2]; /* [0x48] */
- rt_uint32_t queue_notify; /* [0x50]<WO> Queue notifier */
- rt_uint32_t res3[3]; /* [0x54] */
- rt_uint32_t interrupt_status; /* [0x60]<RO> Interrupt status */
- rt_uint32_t interrupt_ack; /* [0x64]<WO> Interrupt acknowledge */
- rt_uint32_t res4[2]; /* [0x68] */
- rt_uint32_t status; /* [0x70]<RW> Device status */
- rt_uint32_t res5[3]; /* [0x74] */
- rt_uint32_t queue_desc_low; /* [0x80]<WO> Virtual queue’s Descriptor Area 64 bit long physical address */
- rt_uint32_t queue_desc_high; /* [0x84]<WO> */
- rt_uint32_t res6[2]; /* [0x88] */
- rt_uint32_t queue_driver_low; /* [0x90]<WO> Virtual queue’s Driver Area 64 bit long physical address */
- rt_uint32_t queue_driver_high; /* [0x94]<WO> */
- rt_uint32_t res7[2]; /* [0x98] */
- rt_uint32_t queue_device_low; /* [0xa0]<WO> Virtual queue’s Device Area 64 bit long physical address */
- rt_uint32_t queue_device_high; /* [0xa4]<WO> */
- rt_uint32_t res8[21]; /* [0xa8] */
- rt_uint32_t config_generation; /* [0xfc]<RO> Configuration atomicity value */
- rt_uint32_t config[]; /* [0x100+]<RO> Configuration space */
-
-/*
- * According to the compiler's optimization ways, we should force compiler not
- * to optimization here, but it will cause some compilers generate memory access
- * instructions fail. So we allow user to choose a toggle of optimize here.
- */
-#ifdef RT_USING_VIRTIO_MMIO_ALIGN
-} __attribute__((packed));
-#else
-};
-#endif
-
-#endif /* __VIRTIO_MMIO_H__ */
diff --git a/components/drivers/virtio/virtio_net.c b/components/drivers/virtio/virtio_net.c
deleted file mode 100644
index d92421b656..0000000000
--- a/components/drivers/virtio/virtio_net.c
+++ /dev/null
@@ -1,267 +0,0 @@
-/*
- * Copyright (c) 2006-2023, RT-Thread Development Team
- *
- * SPDX-License-Identifier: Apache-2.0
- *
- * Change Logs:
- * Date Author Notes
- * 2021-11-11 GuEe-GUI the first version
- */
-
-#include <rthw.h>
-#include <rtthread.h>
-#include <cpuport.h>
-#include <mm_aspace.h>
-
-#ifdef RT_USING_VIRTIO_NET
-
-#include <virtio_net.h>
-
-static rt_err_t virtio_net_tx(rt_device_t dev, struct pbuf *p)
-{
- rt_uint16_t id;
- struct virtio_net_device *virtio_net_dev = (struct virtio_net_device *)dev;
- struct virtio_device *virtio_dev = &virtio_net_dev->virtio_dev;
- struct virtq *queue_tx = &virtio_dev->queues[VIRTIO_NET_QUEUE_TX];
-
- id = (queue_tx->avail->idx * 2) % queue_tx->num;
-
- virtio_net_dev->info[id].hdr.flags = 0;
- virtio_net_dev->info[id].hdr.gso_type = 0;
- virtio_net_dev->info[id].hdr.hdr_len = 0;
- virtio_net_dev->info[id].hdr.gso_size = 0;
- virtio_net_dev->info[id].hdr.csum_start = 0;
- virtio_net_dev->info[id].hdr.csum_offset = 0;
- virtio_net_dev->info[id].hdr.num_buffers = 0;
-
- pbuf_copy_partial(p, virtio_net_dev->info[id].rx_buffer, p->tot_len, 0);
-
- virtio_free_desc(virtio_dev, VIRTIO_NET_QUEUE_TX, id);
- virtio_free_desc(virtio_dev, VIRTIO_NET_QUEUE_TX, id + 1);
-
- virtio_fill_desc(virtio_dev, VIRTIO_NET_QUEUE_TX, id,
- VIRTIO_VA2PA(&virtio_net_dev->info[id].hdr), VIRTIO_NET_HDR_SIZE, VIRTQ_DESC_F_NEXT, id + 1);
-
- virtio_fill_desc(virtio_dev, VIRTIO_NET_QUEUE_TX, id + 1,
- VIRTIO_VA2PA(virtio_net_dev->info[id].rx_buffer), p->tot_len, 0, 0);
-
- virtio_submit_chain(virtio_dev, VIRTIO_NET_QUEUE_TX, id);
-
- virtio_queue_notify(virtio_dev, VIRTIO_NET_QUEUE_TX);
-
- virtio_alloc_desc(virtio_dev, VIRTIO_NET_QUEUE_TX);
- virtio_alloc_desc(virtio_dev, VIRTIO_NET_QUEUE_TX);
-
- return RT_EOK;
-}
-
-static struct pbuf *virtio_net_rx(rt_device_t dev)
-{
- rt_uint16_t id;
- rt_uint32_t len;
- struct pbuf *p = RT_NULL;
- struct virtio_net_device *virtio_net_dev = (struct virtio_net_device *)dev;
- struct virtio_device *virtio_dev = &virtio_net_dev->virtio_dev;
- struct virtq *queue_rx = &virtio_dev->queues[VIRTIO_NET_QUEUE_RX];
-
- if (queue_rx->used_idx != queue_rx->used->idx)
- {
- id = (queue_rx->used->ring[queue_rx->used_idx % queue_rx->num].id + 1) % queue_rx->num;
- len = queue_rx->used->ring[queue_rx->used_idx % queue_rx->num].len - VIRTIO_NET_HDR_SIZE;
-
- if (len > VIRTIO_NET_PAYLOAD_MAX_SIZE)
- {
- rt_kprintf("%s: Receive buffer's size = %u is too big!\n", virtio_net_dev->parent.parent.parent.name, len);
- len = VIRTIO_NET_PAYLOAD_MAX_SIZE;
- }
-
- p = pbuf_alloc(PBUF_RAW, len, PBUF_RAM);
-
- if (p != RT_NULL)
- {
- rt_memcpy(p->payload, (void *)queue_rx->desc[id].addr - PV_OFFSET, len);
-
- queue_rx->used_idx++;
-
- virtio_submit_chain(virtio_dev, VIRTIO_NET_QUEUE_RX, id - 1);
-
- virtio_queue_notify(virtio_dev, VIRTIO_NET_QUEUE_RX);
- }
- }
-
- return p;
-}
-
-static rt_err_t virtio_net_init(rt_device_t dev)
-{
- int i;
- rt_uint16_t idx[VIRTIO_NET_RTX_QUEUE_SIZE];
- struct virtio_net_device *virtio_net_dev = (struct virtio_net_device *)dev;
- struct virtio_device *virtio_dev = &virtio_net_dev->virtio_dev;
- struct virtq *queue_rx, *queue_tx;
-
- queue_rx = &virtio_dev->queues[VIRTIO_NET_QUEUE_RX];
- queue_tx = &virtio_dev->queues[VIRTIO_NET_QUEUE_TX];
-
- virtio_alloc_desc_chain(virtio_dev, VIRTIO_NET_QUEUE_RX, queue_rx->num, idx);
- virtio_alloc_desc_chain(virtio_dev, VIRTIO_NET_QUEUE_TX, queue_tx->num, idx);
-
- for (i = 0; i < queue_rx->num; ++i)
- {
- rt_uint16_t id = (i * 2) % queue_rx->num;
- void *addr = virtio_net_dev->info[i].tx_buffer;
-
- /* Descriptor for net_hdr */
- virtio_fill_desc(virtio_dev, VIRTIO_NET_QUEUE_RX, id,
- VIRTIO_VA2PA(addr), VIRTIO_NET_HDR_SIZE, VIRTQ_DESC_F_NEXT | VIRTQ_DESC_F_WRITE, id + 1);
-
- /* Descriptor for data */
- virtio_fill_desc(virtio_dev, VIRTIO_NET_QUEUE_RX, id + 1,
- VIRTIO_VA2PA(addr) + VIRTIO_NET_HDR_SIZE, VIRTIO_NET_MSS, VIRTQ_DESC_F_WRITE, 0);
-
- queue_rx->avail->ring[i] = id;
- }
- rt_hw_dsb();
-
- queue_rx->avail->flags = 0;
- queue_rx->avail->idx = queue_rx->num;
-
- queue_rx->used_idx = queue_rx->used->idx;
-
- queue_tx->avail->flags = VIRTQ_AVAIL_F_NO_INTERRUPT;
- queue_tx->avail->idx = 0;
-
- virtio_queue_notify(virtio_dev, VIRTIO_NET_QUEUE_RX);
-
- return eth_device_linkchange(&virtio_net_dev->parent, RT_TRUE);
-}
-
-static rt_err_t virtio_net_control(rt_device_t dev, int cmd, void *args)
-{
- rt_err_t status = RT_EOK;
- struct virtio_net_device *virtio_net_dev = (struct virtio_net_device *)dev;
-
- switch (cmd)
- {
- case NIOCTL_GADDR:
- if (args == RT_NULL)
- {
- status = -RT_ERROR;
- break;
- }
-
- rt_memcpy(args, virtio_net_dev->config->mac, sizeof(virtio_net_dev->config->mac));
- break;
- default:
- status = -RT_EINVAL;
- break;
- }
-
- return status;
-}
-
-#ifdef RT_USING_DEVICE_OPS
-const static struct rt_device_ops virtio_net_ops =
-{
- virtio_net_init,
- RT_NULL,
- RT_NULL,
- RT_NULL,
- RT_NULL,
- virtio_net_control
-};
-#endif
-
-static void virtio_net_isr(int irqno, void *param)
-{
- struct virtio_net_device *virtio_net_dev = (struct virtio_net_device *)param;
- struct virtio_device *virtio_dev = &virtio_net_dev->virtio_dev;
- struct virtq *queue_rx = &virtio_dev->queues[VIRTIO_NET_QUEUE_RX];
-
- virtio_interrupt_ack(virtio_dev);
- rt_hw_dsb();
-
- if (queue_rx->used_idx != queue_rx->used->idx)
- {
- rt_hw_dsb();
-
- eth_device_ready(&virtio_net_dev->parent);
- }
-}
-
-rt_err_t rt_virtio_net_init(rt_ubase_t *mmio_base, rt_uint32_t irq)
-{
- static int dev_no = 0;
- char dev_name[RT_NAME_MAX];
- struct virtio_device *virtio_dev;
- struct virtio_net_device *virtio_net_dev;
-
- virtio_net_dev = rt_malloc(sizeof(struct virtio_net_device));
-
- if (virtio_net_dev == RT_NULL)
- {
- goto _alloc_fail;
- }
-
- virtio_dev = &virtio_net_dev->virtio_dev;
- virtio_dev->irq = irq;
- virtio_dev->mmio_base = mmio_base;
-
- virtio_net_dev->config = (struct virtio_net_config *)virtio_dev->mmio_config->config;
-
- virtio_reset_device(virtio_dev);
- virtio_status_acknowledge_driver(virtio_dev);
-
- virtio_dev->mmio_config->driver_features = virtio_dev->mmio_config->device_features & ~(
- (1 << VIRTIO_NET_F_CTRL_VQ) |
- (1 << VIRTIO_F_RING_EVENT_IDX));
-
- virtio_status_driver_ok(virtio_dev);
-
- if (virtio_queues_alloc(virtio_dev, 2) != RT_EOK)
- {
- goto _alloc_fail;
- }
-
- if (virtio_queue_init(virtio_dev, VIRTIO_NET_QUEUE_RX, VIRTIO_NET_RTX_QUEUE_SIZE) != RT_EOK)
- {
- goto _alloc_fail;
- }
-
- if (virtio_queue_init(virtio_dev, VIRTIO_NET_QUEUE_TX, VIRTIO_NET_RTX_QUEUE_SIZE) != RT_EOK)
- {
- virtio_queue_destroy(virtio_dev, VIRTIO_NET_QUEUE_RX);
- goto _alloc_fail;
- }
-
- virtio_net_dev->parent.parent.type = RT_Device_Class_NetIf;
-#ifdef RT_USING_DEVICE_OPS
- virtio_net_dev->parent.parent.ops = &virtio_net_ops;
-#else
- virtio_net_dev->parent.parent.init = virtio_net_init;
- virtio_net_dev->parent.parent.open = RT_NULL;
- virtio_net_dev->parent.parent.close = RT_NULL;
- virtio_net_dev->parent.parent.read = RT_NULL;
- virtio_net_dev->parent.parent.write = RT_NULL;
- virtio_net_dev->parent.parent.control = virtio_net_control;
-#endif
- virtio_net_dev->parent.eth_tx = virtio_net_tx;
- virtio_net_dev->parent.eth_rx = virtio_net_rx;
-
- rt_snprintf(dev_name, RT_NAME_MAX, "virtio-net%d", dev_no++);
-
- rt_hw_interrupt_install(irq, virtio_net_isr, virtio_net_dev, dev_name);
- rt_hw_interrupt_umask(irq);
-
- return eth_device_init(&virtio_net_dev->parent, dev_name);
-
-_alloc_fail:
-
- if (virtio_net_dev != RT_NULL)
- {
- virtio_queues_free(virtio_dev);
- rt_free(virtio_net_dev);
- }
- return -RT_ENOMEM;
-}
-#endif /* RT_USING_VIRTIO_NET */
diff --git a/components/drivers/virtio/virtio_pci.c b/components/drivers/virtio/virtio_pci.c
new file mode 100644
index 0000000000..d17b6ee97a
--- /dev/null
+++ b/components/drivers/virtio/virtio_pci.c
@@ -0,0 +1,942 @@
+/*
+ * Copyright (c) 2006-2022, RT-Thread Development Team
+ *
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Change Logs:
+ * Date Author Notes
+ * 2022-11-07 GuEe-GUI first version
+ */
+
+#include <rtthread.h>
+
+#define DBG_TAG "virtio.pci"
+#define DBG_LVL DBG_INFO
+#include <rtdbg.h>
+
+#include <mmu.h>
+
+#include <drivers/pic.h>
+#include <drivers/pci.h>
+#include <drivers/pci_msi.h>
+#include <drivers/virtio.h>
+#include <drivers/core/bus.h>
+
+#define VIRTIO_PCI_CAP_COMMON_CFG 1 /* Common configuration */
+#define VIRTIO_PCI_CAP_NOTIFY_CFG 2 /* Notifications */
+#define VIRTIO_PCI_CAP_ISR_CFG 3 /* ISR Status */
+#define VIRTIO_PCI_CAP_DEVICE_CFG 4 /* Device specific configuration */
+#define VIRTIO_PCI_CAP_PCI_CFG 5 /* PCI configuration access */
+#define VIRTIO_PCI_CAP_SHARED_MEMORY_CFG 8 /* Shared memory region */
+#define VIRTIO_PCI_CAP_VENDOR_CFG 9 /* Vendor-specific data */
+
+struct virtio_pci_cap
+{
+ rt_uint8_t cap_vndr; /* Generic PCI field: PCI_CAP_ID_VNDR */
+ rt_uint8_t cap_next; /* Generic PCI field: next ptr. */
+ rt_uint8_t cap_len; /* Generic PCI field: capability length */
+ rt_uint8_t cfg_type; /* Identifies the structure. */
+ rt_uint8_t bar; /* Where to find it. */
+ rt_uint8_t id; /* Multiple capabilities of the same type */
+ rt_uint8_t padding[2]; /* Pad to full dword. */
+ rt_le32_t offset; /* Offset within bar. */
+ rt_le32_t length; /* Length of the structure, in bytes. */
+};
+
+struct virtio_pci_cap64
+{
+ struct virtio_pci_cap cap;
+ rt_le32_t offset_hi; /* Most sig 32 bits of offset */
+ rt_le32_t length_hi; /* Most sig 32 bits of length */
+};
+
+struct virtio_pci_common_cfg
+{
+ /* About the whole device. */
+ rt_le32_t device_feature_select; /* Read-write */
+ rt_le32_t device_feature; /* Read-only for driver */
+ rt_le32_t driver_feature_select; /* Read-write */
+ rt_le32_t driver_feature; /* Read-write */
+ rt_le16_t config_msix_vector; /* Read-write */
+ rt_le16_t num_queues; /* Read-only for driver */
+ rt_uint8_t device_status; /* Read-write */
+ rt_uint8_t config_generation; /* Read-only for driver */
+
+ /* About a specific virtqueue. */
+ rt_le16_t queue_select; /* Read-write */
+ rt_le16_t queue_size; /* Read-write */
+ rt_le16_t queue_msix_vector; /* Read-write */
+ rt_le16_t queue_enable; /* Read-write */
+ rt_le16_t queue_notify_off; /* Read-only for driver */
+ rt_le32_t queue_desc_low; /* read-write */
+ rt_le32_t queue_desc_high; /* read-write */
+ rt_le32_t queue_avail_low; /* read-write */
+ rt_le32_t queue_avail_high; /* read-write */
+ rt_le32_t queue_used_low; /* read-write */
+ rt_le32_t queue_used_high; /* read-write */
+};
+
+struct virtio_pci_notify_cap
+{
+ struct virtio_pci_cap cap;
+ rt_le32_t notify_off_multiplier; /* Multiplier for queue_notify_off. */
+};
+
+struct virtio_pci_cfg_cap
+{
+ struct virtio_pci_cap cap;
+ rt_uint8_t pci_cfg_data[4]; /* Data for BAR access. */
+};
+
+#define VIRTIO_PCI_VIRTQ_ALIGN 4096
+#define VIRTIO_PCI_ISR_QUEUE RT_BIT(0)
+#define VIRTIO_PCI_ISR_CONFIG RT_BIT(1)
+#define VIRTIO_MSI_NO_VECTOR 0xffff
+
+#define VIRTIO_PCI_DEVICE_START 0x1040
+#define VIRTIO_PCI_DEVICE_END 0x107f
+
+struct virtio_pci
+{
+ struct rt_virtio_device parent;
+ struct rt_pci_device *pdev;
+
+ void *dev_regs;
+ void *isr_regs;
+ void *notify_regs;
+ struct virtio_pci_common_cfg *common;
+
+ rt_size_t dev_regs_offset;
+ rt_size_t isr_regs_offset;
+ rt_size_t notify_regs_offset;
+ rt_size_t common_offset;
+
+ rt_size_t notify_len;
+ rt_uint32_t notify_offset_multiplier;
+
+ int nvectors;
+ struct rt_pci_msix_entry *msix_entries;
+};
+
+#define raw_to_virtio_pci(raw) rt_container_of(raw, struct virtio_pci, parent)
+
+rt_inline rt_uint32_t virtio_pci_read32(void *addr)
+{
+ return rt_cpu_to_le32(HWREG32(addr));
+}
+
+rt_inline void virtio_pci_write32(void *addr, rt_uint32_t value)
+{
+ HWREG32(addr) = rt_le32_to_cpu(value);
+}
+
+rt_inline rt_uint16_t virtio_pci_read16(void *addr)
+{
+ return rt_cpu_to_le16(HWREG16(addr));
+}
+
+rt_inline void virtio_pci_write16(void *addr, rt_uint16_t value)
+{
+ HWREG16(addr) = rt_le16_to_cpu(value);
+}
+
+rt_inline rt_uint8_t virtio_pci_read8(void *addr)
+{
+ return HWREG8(addr);
+}
+
+rt_inline void virtio_pci_write8(void *addr, rt_uint8_t value)
+{
+ HWREG8(addr) = value;
+}
+
+static void virtio_pci_vq_isr(int irqno, void *param)
+{
+ struct rt_virtqueue *vq = param;
+
+ rt_virtqueue_isr(irqno, vq);
+}
+
+static void virtio_pci_config_isr(int irqno, void *param)
+{
+ struct virtio_pci *vp = param;
+
+ rt_virtio_device_config_changed(&vp->parent);
+}
+
+static void virtio_pci_isr(int irqno, void *param)
+{
+ rt_uint8_t isr;
+ struct rt_virtqueue *vq;
+ struct virtio_pci *vp = param;
+
+ isr = virtio_pci_read8(vp->isr_regs);
+
+ if (!isr)
+ {
+ return;
+ }
+
+ if (isr & VIRTIO_PCI_ISR_CONFIG)
+ {
+ virtio_pci_config_isr(irqno, param);
+ }
+
+ if (isr & VIRTIO_PCI_ISR_QUEUE)
+ {
+ rt_list_for_each_entry(vq, &vp->parent.vq_node, list)
+ {
+ virtio_pci_vq_isr(irqno, vq);
+ }
+ }
+}
+
+static rt_bool_t virtio_pci_notify(struct rt_virtqueue *vq)
+{
+ rt_uint16_t offset;
+ struct virtio_pci *vp = raw_to_virtio_pci(vq->vdev);
+
+ virtio_pci_write16(&vp->common->queue_select, vq->index);
+
+ offset = virtio_pci_read16(&vp->common->queue_notify_off);
+ offset *= vp->notify_offset_multiplier;
+
+ /* We no config VIRTIO_F_NOTIFICATION_DATA, so it is only 16 bits */
+ if (offset > vp->notify_len - sizeof(rt_uint16_t))
+ {
+ return RT_FALSE;
+ }
+
+ virtio_pci_write16(vp->notify_regs + offset, vq->index);
+
+ return RT_TRUE;
+}
+
+static rt_uint16_t virtio_pci_queue_vector(struct virtio_pci *vp,
+ rt_uint16_t index, rt_uint16_t vector)
+{
+ struct virtio_pci_common_cfg *cfg = vp->common;
+
+ virtio_pci_write16(&cfg->queue_select, index);
+ virtio_pci_write16(&cfg->queue_msix_vector, vector);
+
+ /* Flush the write out to device */
+ return virtio_pci_read16(&cfg->queue_msix_vector);
+}
+
+static rt_uint16_t virtio_pci_config_vector(struct virtio_pci *vp,
+ rt_uint16_t vector)
+{
+ struct virtio_pci_common_cfg *cfg = vp->common;
+
+ virtio_pci_write16(&cfg->config_msix_vector, vector);
+
+ /* Flush the write out to device */
+ return virtio_pci_read16(&cfg->config_msix_vector);
+}
+
+static rt_err_t virtio_pci_read_shm_region(struct virtio_pci *vp,
+ struct rt_virtio_shm_region *shm)
+{
+ int pos;
+ rt_uint8_t bar;
+ rt_uint64_t offset, len;
+ struct rt_pci_device *pdev = vp->pdev;
+
+ for (pos = rt_pci_find_capability(pdev, PCIY_VENDOR); pos > 0;
+ pos = rt_pci_find_next_capability(pdev, pos, PCIY_VENDOR))
+ {
+ rt_uint32_t value32;
+ rt_uint8_t type, cap_len, id;
+
+ rt_pci_read_config_u8(pdev,
+ pos + rt_offsetof(struct virtio_pci_cap, cfg_type), &type);
+
+ if (type != VIRTIO_PCI_CAP_SHARED_MEMORY_CFG)
+ {
+ continue;
+ }
+
+ rt_pci_read_config_u8(pdev,
+ pos + rt_offsetof(struct virtio_pci_cap, cap_len), &cap_len);
+
+ if (cap_len != sizeof(struct virtio_pci_cap64))
+ {
+ LOG_E("%s: shm cap with bad size offset: %d size: %d",
+ rt_dm_dev_get_name(&pdev->parent), pos, cap_len);
+
+ continue;
+ }
+
+ rt_pci_read_config_u8(pdev,
+ pos + rt_offsetof(struct virtio_pci_cap, id), &id);
+
+ if (id != shm->id)
+ {
+ continue;
+ }
+
+ rt_pci_read_config_u8(pdev,
+ pos + rt_offsetof(struct virtio_pci_cap, bar), &bar);
+
+ if (bar >= PCI_STD_NUM_BARS)
+ {
+ continue;
+ }
+
+ rt_pci_read_config_u32(pdev,
+ pos + rt_offsetof(struct virtio_pci_cap, offset), &value32);
+ offset = value32;
+
+ rt_pci_read_config_u32(pdev,
+ pos + rt_offsetof(struct virtio_pci_cap, length), &value32);
+ len = value32;
+
+ rt_pci_read_config_u32(pdev,
+ pos + rt_offsetof(struct virtio_pci_cap64, offset_hi), &value32);
+ offset |= ((rt_uint64_t)value32) << 32;
+
+ rt_pci_read_config_u32(pdev,
+ pos + rt_offsetof(struct virtio_pci_cap64, length_hi), &value32);
+ len |= ((rt_uint64_t)value32) << 32;
+
+ break;
+ }
+
+ if (!pos)
+ {
+ return -RT_EEMPTY;
+ }
+
+ if (offset + len < offset)
+ {
+ LOG_E("%s: cap offset + len overflow detected",
+ rt_dm_dev_get_name(&pdev->parent));
+
+ return -RT_EIO;
+ }
+
+ if (offset + len > pdev->resource[bar].size)
+ {
+ LOG_E("%s: bar shorter than cap offset + len",
+ rt_dm_dev_get_name(&pdev->parent));
+
+ return -RT_EIO;
+ }
+
+ shm->base = pdev->resource[bar].base + offset;
+ shm->size = len;
+
+ return RT_EOK;
+}
+
+static rt_err_t virtio_pci_get_status(struct rt_virtio_device *vdev,
+ rt_uint8_t *out_status)
+{
+ struct virtio_pci *vp = raw_to_virtio_pci(vdev);
+
+ *out_status = virtio_pci_read32(&vp->common->device_status);
+
+ return RT_EOK;
+}
+
+static rt_err_t virtio_pci_set_status(struct rt_virtio_device *vdev,
+ rt_uint8_t status)
+{
+ struct virtio_pci *vp = raw_to_virtio_pci(vdev);
+
+ virtio_pci_write32(&vp->common->device_status, status);
+
+ return RT_EOK;
+}
+
+static rt_err_t virtio_pci_get_features(struct rt_virtio_device *vdev,
+ rt_uint64_t *out_features)
+{
+ rt_uint64_t features;
+ struct virtio_pci *vp = raw_to_virtio_pci(vdev);
+
+ virtio_pci_write32(&vp->common->device_feature_select, 1);
+ features = virtio_pci_read32(&vp->common->device_feature);
+ features <<= 32;
+
+ virtio_pci_write32(&vp->common->device_feature_select, 0);
+ features |= virtio_pci_read32(&vp->common->device_feature);
+
+ *out_features = features;
+
+ return RT_EOK;
+}
+
+static rt_err_t virtio_pci_set_features(struct rt_virtio_device *vdev)
+{
+ struct virtio_pci *vp = raw_to_virtio_pci(vdev);
+
+ virtio_pci_write32(&vp->common->driver_feature_select, 1);
+ virtio_pci_write32(&vp->common->driver_feature, (rt_uint32_t)(vdev->features >> 32));
+
+ virtio_pci_write32(&vp->common->driver_feature_select, 0);
+ virtio_pci_write32(&vp->common->driver_feature, (rt_uint32_t)vdev->features);
+
+ return RT_EOK;
+}
+
+static rt_err_t virtio_pci_get_config(struct rt_virtio_device *vdev,
+ rt_uint32_t offset, void *dst, int length)
+{
+ rt_uint8_t byte;
+ rt_le16_t word;
+ rt_le32_t dword;
+ struct virtio_pci *vp = raw_to_virtio_pci(vdev);
+
+ switch (length)
+ {
+ case 4:
+ dword = virtio_pci_read32(vp->dev_regs + offset);
+ rt_memcpy(dst, &dword, sizeof(dword));
+ break;
+ case 1:
+ byte = virtio_pci_read8(vp->dev_regs + offset);
+ rt_memcpy(dst, &byte, sizeof(byte));
+ break;
+ case 2:
+ word = virtio_pci_read16(vp->dev_regs + offset);
+ rt_memcpy(dst, &word, sizeof(word));
+ break;
+ case 8:
+ dword = virtio_pci_read32(vp->dev_regs + offset);
+ rt_memcpy(dst, &dword, sizeof(dword));
+ dword = virtio_pci_read32(vp->dev_regs + offset + sizeof(dword));
+ rt_memcpy(dst + sizeof(dword), &dword, sizeof(dword));
+ break;
+ default:
+ return -RT_EINVAL;
+ }
+
+ return RT_EOK;
+}
+
+static rt_err_t virtio_pci_set_config(struct rt_virtio_device *vdev,
+ rt_uint32_t offset, const void *src, int length)
+{
+ rt_uint8_t byte;
+ rt_le16_t word;
+ rt_le32_t dword;
+ struct virtio_pci *vp = raw_to_virtio_pci(vdev);
+
+ switch (length)
+ {
+ case 4:
+ rt_memcpy(&dword, src, sizeof(dword));
+ virtio_pci_write32(vp->dev_regs + offset, dword);
+ break;
+ case 1:
+ rt_memcpy(&byte, src, sizeof(byte));
+ virtio_pci_write8(vp->dev_regs + offset, byte);
+ break;
+ case 2:
+ rt_memcpy(&word, src, sizeof(word));
+ virtio_pci_write16(vp->dev_regs + offset, word);
+ break;
+ case 8:
+ rt_memcpy(&dword, src, sizeof(dword));
+ virtio_pci_write32(vp->dev_regs + offset, dword);
+ rt_memcpy(&dword, src + sizeof(dword), sizeof(dword));
+ virtio_pci_write32(vp->dev_regs + offset + sizeof(dword), dword);
+ break;
+ default:
+ return -RT_EINVAL;
+ }
+
+ return RT_EOK;
+}
+
+static struct rt_virtqueue *virtio_pci_install_vq(struct rt_virtio_device *vdev,
+ int index, const char *name, rt_virtqueue_callback cb,
+ struct rt_virtqueue_formula *formula)
+{
+ rt_uint64_t page;
+ rt_uint32_t num_max;
+ struct rt_virtqueue *vq;
+ struct virtio_pci *vp = raw_to_virtio_pci(vdev);
+ struct virtio_pci_common_cfg *cfg = vp->common;
+
+ if (index >= virtio_pci_read16(&cfg->num_queues))
+ {
+ return RT_NULL;
+ }
+
+ virtio_pci_write16(&cfg->queue_select, index);
+
+ num_max = virtio_pci_read16(&cfg->queue_size);
+
+ if (!num_max || virtio_pci_read16(&cfg->queue_enable))
+ {
+ return RT_NULL;
+ }
+
+ vq = rt_virtqueue_create(vdev, name, index, num_max, VIRTIO_PCI_VIRTQ_ALIGN,
+ virtio_pci_notify, cb, formula);
+
+ if (!vq)
+ {
+ return vq;
+ }
+
+ vq->num_max = num_max;
+
+ virtio_pci_write16(&cfg->queue_size, rt_virtqueue_get_virtq_size(vq));
+
+ page = (rt_ubase_t)rt_kmem_v2p((void *)rt_virtqueue_get_desc_addr(vq));
+ virtio_pci_write32(&cfg->queue_desc_low, (rt_uint32_t)page);
+ virtio_pci_write32(&cfg->queue_desc_high, (rt_uint32_t)(page >> 32));
+
+ page = (rt_ubase_t)rt_kmem_v2p((void *)rt_virtqueue_get_avail_addr(vq));
+ virtio_pci_write32(&cfg->queue_avail_low, (rt_uint32_t)page);
+ virtio_pci_write32(&cfg->queue_avail_high, (rt_uint32_t)(page >> 32));
+
+ page = (rt_ubase_t)rt_kmem_v2p((void *)rt_virtqueue_get_used_addr(vq));
+ virtio_pci_write32(&cfg->queue_used_low, (rt_uint32_t)page);
+ virtio_pci_write32(&cfg->queue_used_high, (rt_uint32_t)(page >> 32));
+
+ virtio_pci_write16(&cfg->queue_enable, 1);
+
+ return vq;
+}
+
+static rt_err_t virtio_pci_install_vqs(struct rt_virtio_device *vdev, int vqs_nr,
+ struct rt_virtqueue *vqs[], const char *names[], rt_virtqueue_callback cbs[])
+{
+ void *isr;
+ rt_err_t err;
+ char name[RT_NAME_MAX];
+ int nvectors = vqs_nr + 1, irq, cpuid = 0;
+ RT_IRQ_AFFINITY_DECLARE(affinity) = { 0 };
+ struct virtio_pci *vp = raw_to_virtio_pci(vdev);
+
+ vp->msix_entries = rt_malloc(nvectors * sizeof(*vp->msix_entries));
+
+ if (!vp->msix_entries)
+ {
+ return -RT_ENOMEM;
+ }
+
+ rt_pci_msix_entry_index_linear(vp->msix_entries, nvectors);
+
+ /* Try MSI-X with one vector per queue */
+ if (rt_pci_msix_enable(vp->pdev, vp->msix_entries, nvectors) < 0)
+ {
+ nvectors = 2;
+
+ /* Try MSI-X with one shared for queues, one vector for config */
+ if (rt_pci_msix_enable(vp->pdev, vp->msix_entries, nvectors) < 0)
+ {
+ /* Only supported INTx */
+ nvectors = 1;
+
+ rt_free(vp->msix_entries);
+ vp->msix_entries = RT_NULL;
+ }
+ }
+
+ for (int i = 0, vq_idx = 0; i < vqs_nr; ++i, ++vq_idx)
+ {
+ if (!names[i])
+ {
+ vqs[i] = RT_NULL;
+
+ continue;
+ }
+
+ vqs[i] = virtio_pci_install_vq(vdev, vq_idx, names[i], cbs[i], RT_NULL);
+
+ if (!vqs[i])
+ {
+ err = -RT_ERROR;
+ goto _fail;
+ }
+
+ if (nvectors >= 2 || (nvectors == 2 && vqs_nr == 1))
+ {
+ int vec_idx = nvectors != 2 ? vq_idx : 0;
+ int msi_idx = nvectors != 2 ? i : 0;
+
+ if (!cbs[i])
+ {
+ virtio_pci_queue_vector(vp, vq_idx, VIRTIO_MSI_NO_VECTOR);
+
+ continue;
+ }
+
+ if (virtio_pci_queue_vector(vp, vq_idx, vec_idx) == VIRTIO_MSI_NO_VECTOR)
+ {
+ err = -RT_EBUSY;
+ goto _fail;
+ }
+
+ irq = vp->msix_entries[msi_idx].irq;
+
+ rt_snprintf(name, RT_NAME_MAX, "%s-%s-%d",
+ rt_dm_dev_get_name(&vdev->parent), names[i], vq_idx);
+
+ RT_IRQ_AFFINITY_SET(affinity, cpuid % RT_CPUS_NR);
+ rt_pic_irq_set_affinity(irq, affinity);
+ RT_IRQ_AFFINITY_CLEAR(affinity, cpuid++ % RT_CPUS_NR);
+
+ rt_hw_interrupt_install(irq, virtio_pci_vq_isr, vqs[i], name);
+ rt_hw_interrupt_umask(irq);
+ }
+ }
+
+ if (nvectors >= 2)
+ {
+ rt_snprintf(name, RT_NAME_MAX, "%s-config",
+ rt_dm_dev_get_name(&vdev->parent));
+
+ isr = virtio_pci_config_isr;
+ irq = vp->msix_entries[nvectors - 1].irq;
+
+ if (virtio_pci_config_vector(vp, nvectors - 1) == VIRTIO_MSI_NO_VECTOR)
+ {
+ err = -RT_EBUSY;
+ goto _fail;
+ }
+
+ RT_IRQ_AFFINITY_SET(affinity, cpuid % RT_CPUS_NR);
+ rt_pic_irq_set_affinity(irq, affinity);
+ RT_IRQ_AFFINITY_CLEAR(affinity, cpuid++ % RT_CPUS_NR);
+ }
+ else
+ {
+ rt_snprintf(name, RT_NAME_MAX, "%s", rt_dm_dev_get_name(&vdev->parent));
+
+ isr = virtio_pci_isr;
+ irq = vp->pdev->irq;
+
+ virtio_pci_config_vector(vp, VIRTIO_MSI_NO_VECTOR);
+ }
+
+ rt_hw_interrupt_install(irq, isr, vp, name);
+ rt_hw_interrupt_umask(irq);
+
+ vp->nvectors = nvectors;
+
+ return RT_EOK;
+
+_fail:
+ rt_virtio_virtqueue_release(vdev);
+
+ return err;
+}
+
+static rt_err_t virtio_pci_release_vqs(struct rt_virtio_device *vdev)
+{
+ int irq;
+ struct rt_virtqueue *vq, *vq_next;
+ struct virtio_pci *vp = raw_to_virtio_pci(vdev);
+
+ rt_list_for_each_entry_safe(vq, vq_next, &vp->parent.vq_node, list)
+ {
+ virtio_pci_write16(&vp->common->queue_select, vq->index);
+
+ if (vp->nvectors >= 2)
+ {
+ virtio_pci_queue_vector(vp, vq->index, VIRTIO_MSI_NO_VECTOR);
+
+ irq = vp->msix_entries[vq->index].irq;
+
+ rt_hw_interrupt_mask(irq);
+ rt_pic_detach_irq(irq, vq);
+ }
+
+ /* Select and deactivate the queue */
+ virtio_pci_write16(&vp->common->queue_enable, 0);
+
+ rt_virtqueue_delete(&vp->parent, vq);
+ }
+
+ if (vp->nvectors >= 2)
+ {
+ irq = vp->msix_entries[vp->nvectors - 1].irq;
+ }
+ else
+ {
+ irq = vp->pdev->irq;
+ }
+
+ rt_hw_interrupt_mask(irq);
+ rt_pic_detach_irq(irq, vp);
+
+ return RT_EOK;
+}
+
+static rt_err_t virtio_pci_control_vqs(struct rt_virtio_device *vdev,
+ rt_uint32_t cfg, void *data)
+{
+ rt_err_t err = RT_EOK;
+ struct virtio_pci *vp = raw_to_virtio_pci(vdev);
+
+ switch (cfg)
+ {
+ case RT_VIRTQUEUE_CTL_IRQ_AFFINITY:
+ if (vp->nvectors == 1)
+ {
+ err = rt_pic_irq_set_affinity(vp->pdev->irq, (rt_bitmap_t *)data);
+ }
+ else
+ {
+ err = -RT_ENOSYS;
+ }
+ break;
+
+ case RT_VIRTQUEUE_CTL_READ_SHM_REGION:
+ if (!data)
+ {
+ err = -RT_EINVAL;
+ break;
+ }
+
+ err = virtio_pci_read_shm_region(vp, data);
+ break;
+
+ default:
+ err = -RT_ENOSYS;
+ break;
+ }
+
+ return err;
+}
+
+static rt_err_t virtio_pci_generation(struct rt_virtio_device *vdev,
+ rt_uint32_t *out_counter)
+{
+ struct virtio_pci *vp = raw_to_virtio_pci(vdev);
+
+ *out_counter = virtio_pci_read8(&vp->common->config_generation);
+
+ return RT_EOK;
+}
+
+static rt_err_t virtio_pci_reset(struct rt_virtio_device *vdev)
+{
+ struct virtio_pci *vp = raw_to_virtio_pci(vdev);
+
+ virtio_pci_write8(&vp->common->device_status, 0);
+
+ while (virtio_pci_read8(&vp->common->device_status))
+ {
+ rt_thread_mdelay(1);
+ }
+
+ return RT_EOK;
+}
+
+static const struct rt_virtio_transport virtio_pci_trans =
+{
+ .get_status = virtio_pci_get_status,
+ .set_status = virtio_pci_set_status,
+ .get_features = virtio_pci_get_features,
+ .set_features = virtio_pci_set_features,
+ .get_config = virtio_pci_get_config,
+ .set_config = virtio_pci_set_config,
+ .install_vqs = virtio_pci_install_vqs,
+ .release_vqs = virtio_pci_release_vqs,
+ .control_vqs = virtio_pci_control_vqs,
+ .generation = virtio_pci_generation,
+ .reset = virtio_pci_reset,
+};
+
+static rt_uint32_t virtio_pci_find_capability(struct rt_pci_device *pdev,
+ rt_uint8_t cfg_type, rt_size_t cap_size, struct virtio_pci_cap *out_cap)
+{
+ int offset;
+
+ for (rt_uint8_t pos = rt_pci_find_capability(pdev, PCIY_VENDOR);
+ pos > 0 && (PCI_REGMAX + 1) - cap_size >= pos;
+ pos = rt_pci_find_next_capability(pdev, pos, PCIY_VENDOR))
+ {
+ offset = pos + rt_offsetof(struct virtio_pci_cap, cap_vndr);
+ rt_pci_read_config_u8(pdev, offset, &out_cap->cap_vndr);
+ offset = pos + rt_offsetof(struct virtio_pci_cap, cap_next);
+ rt_pci_read_config_u8(pdev, offset, &out_cap->cap_next);
+ offset = pos + rt_offsetof(struct virtio_pci_cap, cap_len);
+ rt_pci_read_config_u8(pdev, offset, &out_cap->cap_len);
+ offset = pos + rt_offsetof(struct virtio_pci_cap, cfg_type);
+ rt_pci_read_config_u8(pdev, offset, &out_cap->cfg_type);
+ offset = pos + rt_offsetof(struct virtio_pci_cap, bar);
+ rt_pci_read_config_u8(pdev, offset, &out_cap->bar);
+ offset = pos + rt_offsetof(struct virtio_pci_cap, offset);
+ rt_pci_read_config_u32(pdev, offset, &out_cap->offset);
+ offset = pos + rt_offsetof(struct virtio_pci_cap, length);
+ rt_pci_read_config_u32(pdev, offset, &out_cap->length);
+
+ /* Ignore structures with reserved BAR values */
+ if (out_cap->bar >= RT_PCI_BAR_NR_MAX)
+ {
+ continue;
+ }
+
+ if (out_cap->cfg_type == cfg_type)
+ {
+ return pos;
+ }
+ }
+
+ return 0;
+}
+
+static void virtio_pci_free(struct virtio_pci *vp)
+{
+ if (vp->common)
+ {
+ rt_iounmap(vp->common - vp->common_offset);
+ }
+ if (vp->dev_regs)
+ {
+ rt_iounmap(vp->dev_regs - vp->dev_regs_offset);
+ }
+ if (vp->notify_regs)
+ {
+ rt_iounmap(vp->notify_regs - vp->notify_regs_offset);
+ }
+ if (vp->isr_regs)
+ {
+ rt_iounmap(vp->isr_regs - vp->isr_regs_offset);
+ }
+
+ rt_free(vp);
+}
+
+static rt_err_t virtio_pci_probe(struct rt_pci_device *pdev)
+{
+ rt_err_t err = RT_EOK;
+ rt_uint8_t common, notify, device, isr;
+ struct virtio_pci_cap common_cap, notify_cap, device_cap, isr_cap;
+ struct rt_virtio_device *vdev;
+ struct virtio_pci *vp;
+
+ if (pdev->device < VIRTIO_PCI_DEVICE_START ||
+ pdev->device > VIRTIO_PCI_DEVICE_END)
+ {
+ return -RT_EINVAL;
+ }
+
+ if (!(vp = rt_calloc(1, sizeof(*vp))))
+ {
+ return -RT_ENOMEM;
+ }
+ vp->pdev = pdev;
+
+ if (!(common = virtio_pci_find_capability(pdev, VIRTIO_PCI_CAP_COMMON_CFG,
+ sizeof(struct virtio_pci_cap), &common_cap)))
+ {
+ err = -RT_EINVAL;
+ goto _fail;
+ }
+
+ if (!(device = virtio_pci_find_capability(pdev, VIRTIO_PCI_CAP_DEVICE_CFG,
+ sizeof(struct virtio_pci_cap), &device_cap)))
+ {
+ err = -RT_EINVAL;
+ goto _fail;
+ }
+
+ if (!(notify = virtio_pci_find_capability(pdev, VIRTIO_PCI_CAP_NOTIFY_CFG,
+ sizeof(struct virtio_pci_notify_cap), &notify_cap)))
+ {
+ err = -RT_EINVAL;
+ goto _fail;
+ }
+
+ if (!(isr = virtio_pci_find_capability(pdev, VIRTIO_PCI_CAP_ISR_CFG,
+ sizeof(struct virtio_pci_cap), &isr_cap)))
+ {
+ err = -RT_EINVAL;
+ goto _fail;
+ }
+
+ if (!(vp->common = rt_pci_iomap(pdev, common_cap.bar)))
+ {
+ err = -RT_EIO;
+ goto _fail;
+ }
+ vp->common_offset = common_cap.offset;
+ vp->common += vp->common_offset;
+
+ if (!(vp->dev_regs = rt_pci_iomap(pdev, device_cap.bar)))
+ {
+ err = -RT_EIO;
+ goto _fail;
+ }
+ vp->dev_regs_offset = device_cap.offset;
+ vp->dev_regs += vp->dev_regs_offset;
+
+ if (!(vp->notify_regs = rt_pci_iomap(pdev, notify_cap.bar)))
+ {
+ err = -RT_EIO;
+ goto _fail;
+ }
+ vp->notify_regs_offset = notify_cap.offset;
+ vp->notify_regs += vp->notify_regs_offset;
+ vp->notify_len = notify_cap.length;
+
+ if (!(vp->isr_regs = rt_pci_iomap(pdev, isr_cap.bar)))
+ {
+ err = -RT_EIO;
+ goto _fail;
+ }
+ vp->isr_regs_offset = isr_cap.offset;
+ vp->isr_regs += vp->isr_regs_offset;
+
+ rt_pci_read_config_u32(pdev,
+ notify + rt_offsetof(struct virtio_pci_notify_cap, notify_off_multiplier),
+ &vp->notify_offset_multiplier);
+
+ vdev = &vp->parent;
+ vdev->id.device = pdev->device - VIRTIO_PCI_DEVICE_START;
+ rt_pci_read_config_u16(pdev, PCIR_SUBVEND_0, (rt_uint16_t *)&vdev->id.vendor);
+
+ vdev->trans = &virtio_pci_trans;
+ vdev->parent.ofw_node = pdev->parent.ofw_node;
+
+ if ((err = rt_virtio_device_register(vdev)))
+ {
+ goto _fail;
+ }
+
+ pdev->parent.user_data = vp;
+
+ return err;
+
+_fail:
+ virtio_pci_free(vp);
+
+ return err;
+}
+
+static rt_err_t virtio_pci_remove(struct rt_pci_device *pdev)
+{
+ struct virtio_pci *vp = pdev->parent.user_data;
+
+ rt_bus_remove_device(&vp->parent.parent);
+
+ virtio_pci_free(vp);
+
+ return RT_EOK;
+}
+
+static struct rt_pci_device_id virtio_pci_ids[] =
+{
+ { RT_PCI_DEVICE_ID(PCI_VENDOR_ID_REDHAT_QUMRANET, PCI_ANY_ID), },
+ { /* sentinel */ }
+};
+
+static struct rt_pci_driver virtio_pci_driver =
+{
+ .name = "virtio-pci",
+
+ .ids = virtio_pci_ids,
+ .probe = virtio_pci_probe,
+ .remove = virtio_pci_remove,
+};
+RT_PCI_DRIVER_EXPORT(virtio_pci_driver);
diff --git a/components/drivers/virtio/virtio_queue.c b/components/drivers/virtio/virtio_queue.c
new file mode 100644
index 0000000000..1244fefb1f
--- /dev/null
+++ b/components/drivers/virtio/virtio_queue.c
@@ -0,0 +1,1219 @@
+/*
+ * 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>
+
+#define DBG_TAG "virtio.queue"
+#define DBG_LVL DBG_INFO
+#include <rtdbg.h>
+
+#include <mm_aspace.h>
+
+#include <drivers/dma.h>
+#include <drivers/virtq.h>
+#include <drivers/virtio.h>
+
+#include "virtio_internal.h"
+
+struct virtq_buffer_shadow
+{
+ rt_ubase_t dma_handle;
+ void *dma_buf;
+
+ rt_size_t size;
+ rt_size_t chain_num;
+};
+
+struct virtqueue_split
+{
+ struct virtq virtq;
+ rt_ubase_t virtq_dma;
+
+ rt_uint16_t avail_idx_shadow;
+ rt_uint16_t avail_flags_shadow;
+ struct virtq_buffer_shadow buffer_shadow[0];
+};
+
+struct virtqueue_packed
+{
+ struct virtq virtq;
+ rt_size_t virtq_size;
+ rt_ubase_t virtq_dma;
+ rt_ubase_t driver_event_dma;
+ rt_ubase_t device_event_dma;
+
+ rt_uint16_t last_used_idx;
+ rt_uint16_t avail_used_flags;
+ rt_uint16_t avail_wrap_counter;
+ rt_uint16_t avail_flags_shadow;
+ rt_uint16_t event_flags_shadow;
+ struct virtq_buffer_shadow buffer_shadow[0];
+};
+
+static struct rt_virtqueue *vq_split_create(struct rt_virtio_device *vdev,
+ const char *name, int index, int num, rt_uint32_t align,
+ rt_virtqueue_notifier notify, rt_virtqueue_callback callback,
+ struct rt_virtqueue_formula *formula)
+{
+ void *pages;
+ rt_size_t size;
+ struct virtqueue_split *vq_split;
+ struct rt_virtqueue *vq = RT_NULL;
+ struct virtq_buffer_shadow *buffer_shadow;
+
+ /*
+ * Layout:
+ * +-----------------+
+ * | rt_virtqueue |
+ * +-----------------+
+ * | virtqueue_split |
+ * +-----------------+
+ * | buffer_shadow |
+ * +-----------------+
+ */
+ vq = rt_malloc(sizeof(*vq) +
+ sizeof(struct virtqueue_split) +
+ sizeof(struct virtq_buffer_shadow) * num);
+
+ if (!vq)
+ {
+ return RT_NULL;
+ }
+
+ vq_split = (void *)vq + sizeof(*vq);
+ buffer_shadow = (void *)vq_split + sizeof(*vq_split);
+ rt_memset(buffer_shadow, 0, sizeof(*buffer_shadow) * num);
+
+ /*
+ * +------------------+-----------+----------------------+
+ * | Virtqueue Part | Alignment | Size |
+ * +------------------+-----------+----------------------+
+ * | Descriptor Table | 16 | 16 * (Queue Size) |
+ * +------------------+-----------+----------------------+
+ * | Available Ring | 2 | 6 + 2 * (Queue Size) |
+ * +------------------+-----------+----------------------+
+ * | Used Ring | 4 | 6 + 8 * (Queue Size) |
+ * +------------------+-----------+----------------------+
+ */
+ size = virtq_size(RT_NULL, num, align);
+
+ if (formula->page)
+ {
+ pages = formula->page;
+ }
+ else
+ {
+ pages = rt_dma_alloc(&vdev->parent, size, &vq_split->virtq_dma, RT_DMA_F_LINEAR);
+
+ if (!pages)
+ {
+ rt_free(vq);
+
+ return RT_NULL;
+ }
+ }
+
+ rt_memset(pages, 0, size);
+ virtq_init(&vq_split->virtq, num, pages, align);
+
+ vq_split->avail_idx_shadow = 0;
+ vq_split->avail_flags_shadow = 0;
+
+ vq->name = name;
+ vq->index = index;
+ vq->num_free = num;
+
+ vq->callback = callback;
+
+ vq->vq_split = vq_split;
+ vq->packed_ring = RT_FALSE;
+
+ vq->notify = notify;
+ vq->event = rt_virtio_has_feature(vdev, VIRTIO_F_RING_EVENT_IDX);
+ vq->event_triggered = RT_FALSE;
+ vq->free_head = 0;
+ vq->num_added = 0;
+ vq->last_used_idx = 0;
+
+ vq->vdev = vdev;
+
+ if (!vq->callback)
+ {
+ vq_split->avail_flags_shadow |= VIRTQ_AVAIL_F_NO_INTERRUPT;
+
+ if (!vq->event)
+ {
+ vq_split->virtq.avail->flags = cpu_to_virtio16(vdev,
+ vq_split->avail_flags_shadow);
+ }
+ }
+
+ rt_memcpy(&vq->formula, formula, sizeof(*formula));
+
+ return vq;
+}
+
+static rt_err_t vq_split_delete(struct rt_virtqueue *vq)
+{
+ rt_err_t err = RT_EOK;
+ struct virtq *virtq;
+ struct virtqueue_split *vq_split = vq->vq_split;
+ struct rt_virtqueue_formula *formula = &vq->formula;
+
+ if (!formula->page)
+ {
+ virtq = &vq_split->virtq;
+ rt_dma_free(&vq->vdev->parent, virtq_size(virtq, 0, 0),
+ (void *)virtq->desc, vq_split->virtq_dma, RT_DMA_F_LINEAR);
+ }
+
+ rt_free(vq);
+
+ return err;
+}
+
+static rt_err_t vq_split_add_buf(struct rt_virtqueue *vq,
+ void *dma_buf, rt_size_t size, rt_bool_t is_out)
+{
+ rt_err_t err;
+ rt_uint16_t buf_id;
+ rt_ubase_t dma_addr;
+ rt_size_t virtq_num;
+ int head, next, flags;
+ struct virtq *virtq;
+ struct virtq_desc *desc;
+ struct virtqueue_split *vq_split;
+ struct virtq_buffer_shadow *buffer_shadow;
+ struct rt_virtio_device *vdev = vq->vdev;
+
+ if (!vq->num_free)
+ {
+ LOG_D("%s.virtqueue[%s(%d)] add buffer.len = %d fail",
+ rt_dm_dev_get_name(&vdev->parent), vq->name, vq->index, size);
+
+ /* Recvice buffer NOW! */
+ if (is_out)
+ {
+ vq->notify(vq);
+ }
+
+ return -RT_EFULL;
+ }
+
+ err = rt_dma_sync_out_data(&vdev->parent, dma_buf, size, &dma_addr, RT_DMA_F_LINEAR);
+
+ if (err)
+ {
+ return err;
+ }
+
+ vq_split = vq->vq_split;
+ virtq = &vq_split->virtq;
+ virtq_num = virtq->num;
+
+ head = vq->free_head++ & (virtq_num - 1);
+ rt_hw_dsb();
+
+ next = vq->free_head & (virtq_num - 1);
+ desc = &virtq->desc[head];
+ buffer_shadow = &vq_split->buffer_shadow[head];
+
+ buffer_shadow->dma_handle = dma_addr;
+ buffer_shadow->dma_buf = dma_buf;
+ buffer_shadow->size = size;
+
+ buf_id = (head - vq->num_added) & (virtq_num - 1);
+ vq_split->buffer_shadow[buf_id].chain_num = vq->num_added + 1;
+
+ flags = VIRTQ_DESC_F_NEXT;
+ if (!is_out)
+ {
+ flags |= VIRTQ_DESC_F_WRITE;
+ }
+
+ desc->addr = cpu_to_virtio64(vdev, dma_addr);
+ desc->len = cpu_to_virtio32(vdev, size);
+ desc->flags = cpu_to_virtio16(vdev, flags);
+ desc->next = cpu_to_virtio16(vdev, next);
+
+ /* Update index */
+ ++vq->num_added;
+ --vq->num_free;
+
+ LOG_D("%s.virtqueue[%s(%d)] add buffer(%p, size = %d) head = %d",
+ rt_dm_dev_get_name(&vdev->parent), vq->name, vq->index, dma_buf, size, head);
+
+ return RT_EOK;
+}
+
+static rt_bool_t vq_split_submit(struct rt_virtqueue *vq)
+{
+ int head, prev;
+ rt_uint16_t avail, num_added;
+ struct rt_virtio_device *vdev = vq->vdev;
+ struct virtqueue_split *vq_split = vq->vq_split;
+ struct virtq *virtq = &vq_split->virtq;
+ rt_size_t virtq_num = virtq->num;
+
+ num_added = vq->num_added;
+ head = vq->free_head;
+ prev = (head - 1) & (virtq_num - 1);
+ head = head - num_added;
+
+ LOG_D("%s.virtqueue[%s(%d)] submit head = %d, num_added = %d, idx = %d",
+ rt_dm_dev_get_name(&vdev->parent), vq->name, vq->index,
+ head & (virtq_num - 1), num_added, virtq->avail->idx);
+
+ /* Reset list info */
+ vq->num_added = 0;
+
+ /* Clear last "next" flags */
+ virtq->desc[prev].flags &= ~cpu_to_virtio16(vdev, VIRTQ_DESC_F_NEXT);
+ virtq->desc[prev].next = 0;
+
+ /* Tell the device the first index in our chain of descriptors */
+ avail = vq_split->avail_idx_shadow & (virtq_num - 1);
+ virtq->avail->ring[avail] = cpu_to_virtio32(vdev, head & (virtq_num - 1));
+
+ /* Tell the device another avail ring entry is available */
+ rt_hw_wmb();
+ ++vq_split->avail_idx_shadow;
+ virtq->avail->idx = cpu_to_virtio16(vdev, vq_split->avail_idx_shadow);
+
+ if (vq->event)
+ {
+ rt_uint16_t old = vq_split->avail_idx_shadow - num_added;
+ rt_uint16_t new = vq_split->avail_idx_shadow;
+
+ return virtq_need_event(virtio16_to_cpu(vdev,
+ *virtq_avail_event(virtq)), new, old);
+ }
+
+ return !(virtq->used->flags & cpu_to_virtio16(vdev, VIRTQ_USED_F_NO_NOTIFY));
+}
+
+static rt_bool_t vq_split_poll(struct rt_virtqueue *vq, rt_uint32_t last_used_idx)
+{
+ return (rt_uint16_t)last_used_idx != virtio16_to_cpu(vq->vdev, vq->vq_split->virtq.used->idx);
+}
+
+rt_inline rt_bool_t vq_split_pending(struct rt_virtqueue *vq)
+{
+ return vq->last_used_idx != virtio16_to_cpu(vq->vdev, vq->vq_split->virtq.used->idx);
+}
+
+static void vq_split_disable_callback(struct rt_virtqueue *vq)
+{
+ struct virtqueue_split *vq_split = vq->vq_split;
+ struct virtq *virtq = &vq_split->virtq;
+
+ if (!(vq_split->avail_flags_shadow & VIRTQ_AVAIL_F_NO_INTERRUPT))
+ {
+ vq_split->avail_flags_shadow |= VIRTQ_AVAIL_F_NO_INTERRUPT;
+
+ if (vq->event)
+ {
+ *virtq_used_event(virtq) = 0;
+ }
+ else
+ {
+ virtq->avail->flags = cpu_to_virtio16(vq->vdev, vq_split->avail_flags_shadow);
+ }
+ }
+}
+
+static rt_uint32_t vq_split_enable_callback(struct rt_virtqueue *vq)
+{
+ struct virtqueue_split *vq_split = vq->vq_split;
+ struct virtq *virtq = &vq_split->virtq;
+ rt_uint16_t last_used_idx = vq->last_used_idx;
+
+ if (vq_split->avail_flags_shadow & VIRTQ_AVAIL_F_NO_INTERRUPT)
+ {
+ vq_split->avail_flags_shadow &= ~VIRTQ_AVAIL_F_NO_INTERRUPT;
+
+ if (!vq->event)
+ {
+ virtq->avail->flags = cpu_to_virtio16(vq->vdev, vq_split->avail_flags_shadow);
+ }
+ }
+
+ *virtq_used_event(virtq) = cpu_to_virtio16(vq->vdev, last_used_idx);
+
+ return last_used_idx;
+}
+
+static void *vq_split_read_buf(struct rt_virtqueue *vq, rt_size_t *out_len)
+{
+ void *buf;
+ rt_err_t err;
+ rt_uint32_t idx;
+ rt_uint16_t last_used, next;
+ rt_size_t chain_num;
+ struct virtq *virtq;
+ struct virtqueue_split *vq_split;
+ struct virtq_buffer_shadow *buffer_shadow;
+ struct rt_virtio_device *vdev = vq->vdev;
+
+ if (!vq_split_pending(vq))
+ {
+ LOG_D("%s.virtqueue[%s(%d)] read buffer empty",
+ rt_dm_dev_get_name(&vdev->parent), vq->name, vq->index);
+
+ return RT_NULL;
+ }
+
+ vq_split = vq->vq_split;
+ virtq = &vq_split->virtq;
+
+ last_used = vq->last_used_idx & (virtq->num - 1);
+ next = idx = virtio32_to_cpu(vdev, virtq->used->ring[last_used].id);
+ *out_len = virtio32_to_cpu(vdev, virtq->used->ring[last_used].len);
+ rt_hw_dsb();
+
+ buffer_shadow = &vq_split->buffer_shadow[idx];
+ buf = buffer_shadow->dma_buf;
+ chain_num = buffer_shadow->chain_num;
+
+ LOG_D("%s.virtqueue[%s(%d)] read head = %d, buffer(%p, size = %d)",
+ rt_dm_dev_get_name(&vdev->parent), vq->name, vq->index, idx, buf, *out_len);
+
+ for (int i = 0; i < chain_num; ++i)
+ {
+ idx = next;
+ next = virtq->desc[idx].next;
+
+ if (virtq->desc[idx].flags & VIRTQ_DESC_F_WRITE ||
+ vdev->dma_dispatch)
+ {
+ buffer_shadow = &vq_split->buffer_shadow[idx];
+ err = rt_dma_sync_in_data(&vdev->parent,
+ buffer_shadow->dma_buf,
+ buffer_shadow->size,
+ buffer_shadow->dma_handle, RT_DMA_F_LINEAR);
+
+ if (err)
+ {
+ LOG_E("%s.virtqueue[%s(%d)] read head = %d sync error = %s",
+ rt_dm_dev_get_name(&vdev->parent),
+ vq->name, vq->index, idx, rt_strerror(err));
+ }
+ }
+ }
+
+ vq->num_free += chain_num;
+ ++vq->last_used_idx;
+
+ if (!(vq_split->avail_flags_shadow & VIRTQ_AVAIL_F_NO_INTERRUPT))
+ {
+ HWREG16(virtq_used_event(virtq)) = cpu_to_virtio16(vq->vdev, vq->last_used_idx);
+ rt_hw_dmb();
+ }
+
+ rt_hw_dsb();
+
+ return buf;
+}
+
+static struct rt_virtqueue *vq_packed_create(struct rt_virtio_device *vdev,
+ const char *name, int index, int num, int align,
+ rt_virtqueue_notifier notify, rt_virtqueue_callback callback,
+ struct rt_virtqueue_formula *formula)
+{
+ rt_size_t size, event_size;
+ struct virtq *virtq;
+ struct virtqueue_packed *vq_packed;
+ struct rt_virtqueue *vq = RT_NULL;
+ struct virtq_buffer_shadow *buffer_shadow;
+
+ /*
+ * Layout:
+ * +------------------------+
+ * | rt_virtqueue |
+ * +------------------------+
+ * | virtqueue_packed |
+ * +------------------------+
+ * | buffer_shadow |
+ * +------------------------+
+ */
+ vq = rt_malloc(sizeof(*vq) +
+ sizeof(struct virtqueue_packed) +
+ sizeof(struct virtq_buffer_shadow) * num);
+
+ if (!vq)
+ {
+ return RT_NULL;
+ }
+
+ vq_packed = (void *)vq + sizeof(*vq);
+ buffer_shadow = (void *)vq_packed + sizeof(*vq_packed);
+ rt_memset(buffer_shadow, 0, sizeof(*buffer_shadow) * num);
+
+ /*
+ * +--------------------------+-----------+-------------------+
+ * | Virtqueue Part | Alignment | Size |
+ * +--------------------------+-----------+-------------------+
+ * | Descriptor Ring | 16 | 16 * (Queue Size) |
+ * +--------------------------+-----------+-------------------+
+ * | Device Event Suppression | 4 | 4 |
+ * +--------------------------+-----------+-------------------+
+ * | Driver Event Suppression | 4 | 4 |
+ * +--------------------------+-----------+-------------------+
+ */
+ virtq = &vq_packed->virtq;
+
+ size = num * sizeof(struct virtq_packed_desc);
+ size = RT_ALIGN(size, 4);
+ event_size = sizeof(struct virtq_packed_desc_event);
+ vq_packed->virtq_size = size + event_size * 2;
+
+ if (formula->page)
+ {
+ virtq->desc_packed = formula->page;
+ }
+ else
+ {
+ virtq->desc_packed = rt_dma_alloc(&vdev->parent,
+ vq_packed->virtq_size, &vq_packed->virtq_dma, RT_DMA_F_LINEAR);
+
+ if (!virtq->desc_packed)
+ {
+ rt_free(vq);
+
+ return RT_NULL;
+ }
+ }
+
+ virtq->driver_event = (void *)virtq->desc_packed + size;
+ vq_packed->driver_event_dma = vq_packed->virtq_dma + size;
+
+ virtq->device_event = (void *)virtq->driver_event + event_size;
+ vq_packed->device_event_dma = vq_packed->driver_event_dma + event_size;
+
+ rt_memset(virtq->desc_packed, 0, size);
+ rt_memset(virtq->driver_event, 0, event_size);
+ rt_memset(virtq->device_event, 0, event_size);
+ virtq->num = num;
+ virtq->align = align;
+
+ vq_packed->avail_wrap_counter = 1;
+ vq_packed->event_flags_shadow = 0;
+ vq_packed->avail_used_flags = VIRTQ_DESC_F_AVAIL;
+
+ vq->name = name;
+ vq->index = index;
+ vq->num_free = num;
+
+ vq->callback = callback;
+
+ vq->vq_packed = vq_packed;
+ vq->packed_ring = RT_TRUE;
+
+ vq->notify = notify;
+ vq->event = rt_virtio_has_feature(vdev, VIRTIO_F_RING_EVENT_IDX);
+ vq->event_triggered = RT_FALSE;
+ vq->free_head = 0;
+ vq->num_added = 0;
+ vq->last_used_idx = 0 | RT_BIT(VIRTQ_PACKED_EVENT_WRAP_CTR);
+
+ vq->vdev = vdev;
+
+ if (!vq->callback)
+ {
+ vq_packed->avail_flags_shadow = VIRTQ_PACKED_EVENT_FLAG_DISABLE;
+ vq_packed->virtq.avail->flags = rt_cpu_to_le16(vq_packed->avail_flags_shadow);
+ }
+
+ rt_memcpy(&vq->formula, formula, sizeof(*formula));
+
+ return vq;
+}
+
+static rt_err_t vq_packed_delete(struct rt_virtqueue *vq)
+{
+ rt_err_t err = RT_EOK;
+ struct virtq *virtq;
+ struct virtqueue_packed *vq_packed = vq->vq_packed;
+ struct rt_virtqueue_formula *formula = &vq->formula;
+
+ virtq = &vq_packed->virtq;
+
+ if (virtq->desc_packed && !formula->page)
+ {
+ rt_dma_free(&vq->vdev->parent, vq_packed->virtq_size,
+ (void *)virtq->desc_packed, vq_packed->virtq_dma, RT_DMA_F_LINEAR);
+ }
+
+ rt_free(vq);
+
+ return err;
+}
+
+static rt_err_t vq_packed_add_buf(struct rt_virtqueue *vq,
+ void *dma_buf, rt_size_t size, rt_bool_t is_out)
+{
+ rt_err_t err;
+ rt_uint16_t buf_id;
+ rt_ubase_t dma_addr;
+ rt_size_t virtq_num;
+ int head, flags;
+ struct virtq *virtq;
+ struct virtqueue_packed *vq_packed;
+ struct virtq_packed_desc *desc_packed;
+ struct virtq_buffer_shadow *buffer_shadow;
+ struct rt_virtio_device *vdev = vq->vdev;
+
+ if (!vq->num_free)
+ {
+ LOG_D("%s.virtqueue[%s(%d)] add buffer.len = %d fail",
+ rt_dm_dev_get_name(&vdev->parent), vq->name, vq->index, size);
+
+ /* Recvice buffer NOW! */
+ if (is_out)
+ {
+ vq->notify(vq);
+ }
+
+ return -RT_EFULL;
+ }
+
+ err = rt_dma_sync_out_data(&vdev->parent, dma_buf, size, &dma_addr, RT_DMA_F_LINEAR);
+
+ if (err)
+ {
+ return err;
+ }
+
+ vq_packed = vq->vq_packed;
+ virtq = &vq_packed->virtq;
+ virtq_num = virtq->num;
+
+ head = vq->free_head++ & (virtq_num - 1);
+ rt_hw_dsb();
+
+ desc_packed = &virtq->desc_packed[head];
+ buffer_shadow = &vq_packed->buffer_shadow[head];
+
+ buffer_shadow->dma_handle = dma_addr;
+ buffer_shadow->dma_buf = dma_buf;
+ buffer_shadow->size = size;
+
+ buf_id = (head - vq->num_added) & (virtq_num - 1);
+ vq_packed->buffer_shadow[buf_id].chain_num = vq->num_added + 1;
+
+ flags = VIRTQ_DESC_F_NEXT;
+ if (!is_out)
+ {
+ flags |= VIRTQ_DESC_F_WRITE;
+ }
+
+ desc_packed->addr = rt_cpu_to_le64(dma_addr);
+ desc_packed->len = rt_cpu_to_le32(size);
+ desc_packed->id = rt_cpu_to_le16(buf_id);
+ desc_packed->flags = rt_cpu_to_le16(vq_packed->avail_used_flags | flags);
+
+ /* Ready fot next */
+ if (head + 1 >= virtq->num)
+ {
+ vq_packed->avail_used_flags ^= VIRTQ_DESC_F_AVAIL | VIRTQ_DESC_F_USED;
+ /* Toggle the wrap counter */
+ vq_packed->avail_wrap_counter ^= 1;
+ }
+
+ rt_hw_wmb();
+
+ /* Update index */
+ ++vq->num_added;
+ --vq->num_free;
+
+ LOG_D("%s.virtqueue[%s(%d)] add buffer(%p, size = %d) head = %d",
+ rt_dm_dev_get_name(&vdev->parent), vq->name, vq->index, dma_buf, size, head);
+
+ return RT_EOK;
+}
+
+static rt_bool_t vq_packed_submit(struct rt_virtqueue *vq)
+{
+ int head, prev;
+ rt_uint16_t off_wrap, flags, wrap_counter, event_idx;
+ struct virtq_packed_desc_event device_event;
+ struct virtqueue_packed *vq_packed = vq->vq_packed;
+ struct virtq *virtq = &vq_packed->virtq;
+ rt_size_t virtq_num = virtq->num;
+
+ rt_hw_dmb();
+ rt_memcpy(&device_event, virtq->device_event, sizeof(device_event));
+
+ head = vq->free_head;
+ prev = (head - 1) & (virtq_num - 1);
+ head = head - vq->num_added;
+
+ LOG_D("%s.virtqueue[%s(%d)] submit head = %d, num_added = %d, idx = %d",
+ rt_dm_dev_get_name(&vq->vdev->parent), vq->name, vq->index,
+ head & (virtq_num - 1), vq->num_added, rt_le16_to_cpu(device_event.off_wrap) &
+ ~RT_BIT(VIRTQ_PACKED_EVENT_WRAP_CTR));
+
+ /* Reset list info */
+ vq->num_added = 0;
+
+ /* Clear last "next" flags */
+ virtq->desc_packed[prev].flags &= ~rt_cpu_to_le16(VIRTQ_DESC_F_NEXT);
+
+ flags = rt_le16_to_cpu(device_event.flags);
+
+ if (flags != VIRTQ_PACKED_EVENT_FLAG_DESC)
+ {
+ return (flags != VIRTQ_PACKED_EVENT_FLAG_DISABLE);
+ }
+
+ off_wrap = rt_le16_to_cpu(device_event.off_wrap);
+
+ wrap_counter = off_wrap >> VIRTQ_PACKED_EVENT_WRAP_CTR;
+ event_idx = off_wrap & ~RT_BIT(VIRTQ_PACKED_EVENT_WRAP_CTR);
+ if (wrap_counter != vq_packed->avail_wrap_counter)
+ {
+ event_idx -= virtq->num;
+ }
+
+ return virtq_need_event(event_idx, prev, head);
+}
+
+rt_inline rt_bool_t is_used_desc_packed(const struct virtq *virtq,
+ rt_uint16_t idx, rt_bool_t used_wrap_counter)
+{
+ rt_uint16_t flags;
+ rt_bool_t avail, used;
+
+ flags = rt_le16_to_cpu(virtq->desc_packed[idx].flags);
+ avail = !!(flags & VIRTQ_DESC_F_AVAIL);
+ used = !!(flags & VIRTQ_DESC_F_USED);
+
+ return avail == used && used == used_wrap_counter;
+}
+
+static rt_bool_t packed_used_wrap_counter(rt_uint16_t last_used_idx)
+{
+ return !!(last_used_idx & RT_BIT(VIRTQ_PACKED_EVENT_WRAP_CTR));
+}
+
+static rt_uint16_t packed_last_used(rt_uint16_t last_used_idx)
+{
+ return last_used_idx & ~(-RT_BIT(VIRTQ_PACKED_EVENT_WRAP_CTR));
+}
+
+static rt_bool_t vq_packed_poll(struct rt_virtqueue *vq, rt_uint32_t last_used_idx)
+{
+ rt_bool_t wrap_counter;
+ rt_uint16_t off_wrap = last_used_idx, used_idx;
+
+ wrap_counter = off_wrap >> VIRTQ_PACKED_EVENT_WRAP_CTR;
+ used_idx = off_wrap & ~RT_BIT(VIRTQ_PACKED_EVENT_WRAP_CTR);
+
+ return is_used_desc_packed(&vq->vq_packed->virtq, used_idx, wrap_counter);
+}
+
+rt_inline rt_bool_t vq_packed_pending(struct rt_virtqueue *vq)
+{
+ rt_bool_t wrap_counter;
+ rt_uint16_t last_used, last_used_idx;
+
+ last_used_idx = HWREG16(&vq->last_used_idx);
+ last_used = packed_last_used(last_used_idx);
+ wrap_counter = packed_used_wrap_counter(last_used_idx);
+ return is_used_desc_packed(&vq->vq_packed->virtq, last_used, wrap_counter);
+}
+
+static void vq_packed_disable_callback(struct rt_virtqueue *vq)
+{
+ struct virtqueue_packed *vq_packed = vq->vq_packed;
+
+ if (vq_packed->event_flags_shadow != VIRTQ_PACKED_EVENT_FLAG_DISABLE)
+ {
+ vq_packed->event_flags_shadow = VIRTQ_PACKED_EVENT_FLAG_DISABLE;
+
+ /*
+ * If device triggered an event already it won't trigger one again:
+ * no need to disable.
+ */
+ if (vq->event_triggered)
+ {
+ return;
+ }
+
+ vq_packed->virtq.driver_event->flags = rt_cpu_to_le16(vq_packed->event_flags_shadow);
+ }
+}
+
+static rt_uint32_t vq_packed_enable_callback(struct rt_virtqueue *vq)
+{
+ struct virtqueue_packed *vq_packed = vq->vq_packed;
+
+ if (vq->event)
+ {
+ vq_packed->virtq.driver_event->off_wrap = rt_cpu_to_le16(vq->last_used_idx);
+
+ /* Update event offset and event wrap counter first before updating event flags. */
+ rt_hw_wmb();
+ }
+
+ if (vq_packed->event_flags_shadow == VIRTQ_PACKED_EVENT_FLAG_DISABLE)
+ {
+ vq_packed->event_flags_shadow = vq->event ?
+ VIRTQ_PACKED_EVENT_FLAG_DESC : VIRTQ_PACKED_EVENT_FLAG_ENABLE;
+ vq_packed->virtq.driver_event->flags =
+ rt_cpu_to_le16(vq_packed->event_flags_shadow);
+ }
+
+ return vq->last_used_idx;
+}
+
+static void *vq_packed_read_buf(struct rt_virtqueue *vq, rt_size_t *out_len)
+{
+ void *buf;
+ rt_err_t err;
+ rt_bool_t wrap_counter;
+ rt_uint16_t last_used, last_used_idx, id;
+ rt_size_t chain_num;
+ struct virtq *virtq;
+ struct virtqueue_packed *vq_packed;
+ struct virtq_buffer_shadow *buffer_shadow;
+ struct rt_virtio_device *vdev = vq->vdev;
+
+ if (!vq_packed_pending(vq))
+ {
+ LOG_D("%s.virtqueue[%s(%d)] read buffer empty",
+ rt_dm_dev_get_name(&vdev->parent), vq->name, vq->index);
+
+ return RT_NULL;
+ }
+
+ vq_packed = vq->vq_packed;
+ virtq = &vq_packed->virtq;
+
+ rt_hw_rmb();
+
+ last_used_idx = HWREG16(&vq->last_used_idx);
+ wrap_counter = packed_used_wrap_counter(last_used_idx);
+ last_used = packed_last_used(last_used_idx);
+ id = rt_le16_to_cpu(virtq->desc_packed[last_used].id);
+ *out_len = rt_le32_to_cpu(virtq->desc_packed[last_used].len);
+
+ buffer_shadow = &vq->vq_packed->buffer_shadow[id];
+ buf = buffer_shadow->dma_buf;
+ chain_num = buffer_shadow->chain_num;
+
+ LOG_D("%s.virtqueue[%s(%d)] read head = %d, buffer(%p, size = %d)",
+ rt_dm_dev_get_name(&vdev->parent), vq->name, vq->index, id, buf, *out_len);
+
+ for (int i = 0; i < chain_num; ++i)
+ {
+ if (virtq->desc_packed[id].flags & VIRTQ_DESC_F_WRITE ||
+ vdev->dma_dispatch)
+ {
+ buffer_shadow = &vq->vq_packed->buffer_shadow[id];
+ err = rt_dma_sync_in_data(&vdev->parent,
+ buffer_shadow->dma_buf,
+ buffer_shadow->size,
+ buffer_shadow->dma_handle, RT_DMA_F_LINEAR);
+
+ if (err)
+ {
+ LOG_E("%s.virtqueue[%s(%d)] read head = %d sync error = %s",
+ rt_dm_dev_get_name(&vdev->parent),
+ vq->name, vq->index, id, rt_strerror(err));
+ }
+ }
+
+ ++id;
+ }
+
+ vq->num_free += chain_num;
+ last_used += chain_num;
+
+ if (last_used >= virtq->num)
+ {
+ last_used -= virtq->num;
+ wrap_counter ^= 1;
+ }
+
+ last_used |= (wrap_counter << VIRTQ_PACKED_EVENT_WRAP_CTR);
+ HWREG16(&vq->last_used_idx) = last_used;
+
+ if (vq_packed->event_flags_shadow == VIRTQ_PACKED_EVENT_FLAG_DESC)
+ {
+ HWREG16(&virtq->driver_event->off_wrap) = rt_cpu_to_le16(vq->last_used_idx);
+ rt_hw_dmb();
+ }
+
+ return buf;
+}
+
+rt_inline rt_bool_t virtqueue_pending(struct rt_virtqueue *vq)
+{
+ rt_bool_t res = RT_FALSE;
+
+ if (vq->packed_ring)
+ {
+ res = vq_packed_pending(vq);
+ }
+ else
+ {
+ res = vq_split_pending(vq);
+ }
+
+ return res;
+}
+
+struct rt_virtqueue *rt_virtqueue_create(struct rt_virtio_device *vdev,
+ const char *name, int index, int num, rt_uint32_t align,
+ rt_virtqueue_notifier notify, rt_virtqueue_callback callback,
+ struct rt_virtqueue_formula *formula)
+{
+ struct rt_virtqueue *vq = RT_NULL;
+ struct rt_virtqueue_formula default_formula = {};
+
+ RT_ASSERT(vdev != RT_NULL);
+ RT_ASSERT(num != 0);
+ RT_ASSERT((num & (num - 1)) == 0);
+ RT_ASSERT(notify != RT_NULL);
+ RT_ASSERT(name != RT_NULL);
+
+ formula = formula ? : &default_formula;
+
+ if (rt_virtio_has_feature(vdev, VIRTIO_F_RING_PACKED))
+ {
+ vq = vq_packed_create(vdev, name, index, num, align, notify, callback, formula);
+ }
+ else
+ {
+ vq = vq_split_create(vdev, name, index, num, align, notify, callback, formula);
+ }
+
+ if (vq)
+ {
+ if (!callback)
+ {
+ rt_virtqueue_disable_callback(vq);
+ }
+
+ rt_base_t level = rt_spin_lock_irqsave(&vdev->vq_lock);
+
+ rt_list_init(&vq->list);
+ rt_list_init(&vq->user_list);
+ rt_list_insert_before(&vdev->vq_node, &vq->list);
+
+ rt_spin_unlock_irqrestore(&vdev->vq_lock, level);
+ }
+
+ return vq;
+}
+
+rt_err_t rt_virtqueue_delete(struct rt_virtio_device *vdev, struct rt_virtqueue *vq)
+{
+ rt_ubase_t level;
+ rt_err_t err = RT_EOK;
+
+ RT_ASSERT(vdev != RT_NULL);
+ RT_ASSERT(vq != RT_NULL);
+
+ level = rt_spin_lock_irqsave(&vdev->vq_lock);
+
+ while (virtqueue_pending(vq))
+ {
+ rt_spin_unlock_irqrestore(&vdev->vq_lock, level);
+
+ rt_thread_yield();
+
+ level = rt_spin_lock_irqsave(&vdev->vq_lock);
+ }
+
+ rt_list_remove(&vq->list);
+
+ rt_spin_unlock_irqrestore(&vdev->vq_lock, level);
+
+ if (vq->packed_ring)
+ {
+ vq_packed_delete(vq);
+ }
+ else
+ {
+ vq_split_delete(vq);
+ }
+
+ return err;
+}
+
+rt_err_t rt_virtqueue_add_outbuf(struct rt_virtqueue *vq, void *dma_buf, rt_size_t size)
+{
+ rt_err_t err = -RT_ENOSYS;
+
+ RT_ASSERT(vq != RT_NULL);
+ RT_ASSERT(dma_buf != RT_NULL);
+ RT_ASSERT(size != 0);
+
+ if (vq->packed_ring)
+ {
+ err = vq_packed_add_buf(vq, dma_buf, size, RT_TRUE);
+ }
+ else
+ {
+ err = vq_split_add_buf(vq, dma_buf, size, RT_TRUE);
+ }
+
+ return err;
+}
+
+rt_err_t rt_virtqueue_add_inbuf(struct rt_virtqueue *vq, void *dma_buf, rt_size_t size)
+{
+ rt_err_t err = -RT_ENOSYS;
+
+ RT_ASSERT(vq != RT_NULL);
+ RT_ASSERT(dma_buf != RT_NULL);
+ RT_ASSERT(size != 0);
+
+ if (vq->packed_ring)
+ {
+ err = vq_packed_add_buf(vq, dma_buf, size, RT_FALSE);
+ }
+ else
+ {
+ err = vq_split_add_buf(vq, dma_buf, size, RT_FALSE);
+ }
+
+ return err;
+}
+
+rt_bool_t rt_virtqueue_prepare(struct rt_virtqueue *vq, rt_uint32_t nr)
+{
+ return vq->num_free >= nr;
+}
+
+void rt_virtqueue_wait_prepare(struct rt_virtqueue *vq, rt_uint32_t nr)
+{
+ while (!rt_virtqueue_prepare(vq, nr))
+ {
+ rt_thread_yield();
+ rt_hw_cpu_relax();
+ }
+}
+
+rt_uint32_t rt_virtqueue_next_buf_index(struct rt_virtqueue *vq)
+{
+ RT_ASSERT(vq != RT_NULL);
+
+ return vq->free_head % (vq->packed_ring ?
+ vq->vq_packed->virtq.num : vq->vq_split->virtq.num);
+}
+
+rt_bool_t rt_virtqueue_submit(struct rt_virtqueue *vq)
+{
+ rt_bool_t res = RT_FALSE;
+
+ RT_ASSERT(vq != RT_NULL);
+
+ if (vq->packed_ring)
+ {
+ res = vq_packed_submit(vq);
+ }
+ else
+ {
+ res = vq_split_submit(vq);
+ }
+
+ return res;
+}
+
+rt_bool_t rt_virtqueue_notify(struct rt_virtqueue *vq)
+{
+ RT_ASSERT(vq != RT_NULL);
+
+ if (!vq->notify(vq))
+ {
+ return RT_FALSE;
+ }
+
+ return RT_TRUE;
+}
+
+rt_bool_t rt_virtqueue_kick(struct rt_virtqueue *vq)
+{
+ RT_ASSERT(vq != RT_NULL);
+
+ if (rt_virtqueue_submit(vq))
+ {
+ return rt_virtqueue_notify(vq);
+ }
+
+ return RT_TRUE;
+}
+
+void rt_virtqueue_isr(int irq, struct rt_virtqueue *vq)
+{
+ if (!virtqueue_pending(vq))
+ {
+ LOG_D("%s.virtqueue[%s(%d)] no buffer pending in %s",
+ rt_dm_dev_get_name(&vq->vdev->parent), vq->name, vq->index, "isr");
+
+ return;
+ }
+
+ if (vq->event)
+ {
+ vq->event_triggered = RT_TRUE;
+ }
+
+ if (vq->callback)
+ {
+ vq->callback(vq);
+ }
+}
+
+rt_bool_t rt_virtqueue_poll(struct rt_virtqueue *vq, rt_uint32_t last_used_idx)
+{
+ rt_bool_t res = RT_FALSE;
+
+ RT_ASSERT(vq != RT_NULL);
+
+ if (vq->packed_ring)
+ {
+ res = vq_packed_poll(vq, last_used_idx);
+ }
+ else
+ {
+ res = vq_split_poll(vq, last_used_idx);
+ }
+
+ return res;
+}
+
+void rt_virtqueue_disable_callback(struct rt_virtqueue *vq)
+{
+ if (vq->event_triggered)
+ {
+ return;
+ }
+
+ if (vq->packed_ring)
+ {
+ vq_packed_disable_callback(vq);
+ }
+ else
+ {
+ vq_split_disable_callback(vq);
+ }
+}
+
+rt_bool_t rt_virtqueue_enable_callback(struct rt_virtqueue *vq,
+ rt_uint32_t *out_last_used_idx)
+{
+ rt_uint32_t last_used_idx;
+
+ if (vq->event_triggered)
+ {
+ vq->event_triggered = RT_FALSE;
+ }
+
+ if (vq->packed_ring)
+ {
+ last_used_idx = vq_packed_enable_callback(vq);
+ }
+ else
+ {
+ last_used_idx = vq_split_enable_callback(vq);
+ }
+
+ if (out_last_used_idx)
+ {
+ *out_last_used_idx = last_used_idx;
+ }
+
+ return !rt_virtqueue_poll(vq, last_used_idx);
+}
+
+void *rt_virtqueue_read_buf(struct rt_virtqueue *vq, rt_size_t *out_len)
+{
+ void *buf = RT_NULL;
+ rt_size_t len = 0;
+
+ RT_ASSERT(vq != RT_NULL);
+
+ if (vq->packed_ring)
+ {
+ buf = vq_packed_read_buf(vq, &len);
+ }
+ else
+ {
+ buf = vq_split_read_buf(vq, &len);
+ }
+
+ if (len && out_len)
+ {
+ *out_len = len;
+ }
+
+ return buf;
+}
+
+rt_size_t rt_virtqueue_get_virtq_size(struct rt_virtqueue *vq)
+{
+ RT_ASSERT(vq != RT_NULL);
+
+ if (vq->packed_ring)
+ {
+ return (rt_ubase_t)vq->vq_packed->virtq.num;
+ }
+ else
+ {
+ return (rt_ubase_t)vq->vq_split->virtq.num;
+ }
+}
+
+rt_ubase_t rt_virtqueue_get_desc_addr(struct rt_virtqueue *vq)
+{
+ RT_ASSERT(vq != RT_NULL);
+
+ if (vq->packed_ring)
+ {
+ return (rt_ubase_t)vq->vq_packed->virtq.desc;
+ }
+ else
+ {
+ return (rt_ubase_t)vq->vq_split->virtq.desc;
+ }
+}
+
+rt_ubase_t rt_virtqueue_get_avail_addr(struct rt_virtqueue *vq)
+{
+ RT_ASSERT(vq != RT_NULL);
+
+ if (vq->packed_ring)
+ {
+ return (rt_ubase_t)vq->vq_packed->virtq.driver_event;
+ }
+ else
+ {
+ return (rt_ubase_t)vq->vq_split->virtq.avail;
+ }
+}
+
+rt_ubase_t rt_virtqueue_get_used_addr(struct rt_virtqueue *vq)
+{
+ RT_ASSERT(vq != RT_NULL);
+
+ if (vq->packed_ring)
+ {
+ return (rt_ubase_t)vq->vq_packed->virtq.device_event;
+ }
+ else
+ {
+ return (rt_ubase_t)vq->vq_split->virtq.used;
+ }
+}
diff --git a/components/drivers/virtio/virtio_queue.h b/components/drivers/virtio/virtio_queue.h
deleted file mode 100644
index b2b0bdcd32..0000000000
--- a/components/drivers/virtio/virtio_queue.h
+++ /dev/null
@@ -1,97 +0,0 @@
-/*
- * Copyright (c) 2006-2023, RT-Thread Development Team
- *
- * SPDX-License-Identifier: Apache-2.0
- *
- * Change Logs:
- * Date Author Notes
- * 2021-11-11 GuEe-GUI the first version
- */
-
-#ifndef __VIRTIO_QUEUE_H__
-#define __VIRTIO_QUEUE_H__
-
-#include <rtdef.h>
-
-#define VIRTQ_DESC_F_NEXT 1 /* This marks a buffer as continuing via the next field. */
-#define VIRTQ_DESC_F_WRITE 2 /* This marks a buffer as write-only (otherwise read-only). */
-#define VIRTQ_DESC_F_INDIRECT 4 /* This means the buffer contains a list of buffer descriptors. */
-
-/*
- * The device uses this in used->flags to advise the driver: don't kick me
- * when you add a buffer. It's unreliable, so it's simply an optimization.
- */
-#define VIRTQ_USED_F_NO_NOTIFY 1
-
-/*
- * The driver uses this in avail->flags to advise the device: don't
- * interrupt me when you consume a buffer. It's unreliable, so it's
- * simply an optimization.
- */
-#define VIRTQ_AVAIL_F_NO_INTERRUPT 1
-
-/* Virtqueue descriptors: 16 bytes. These can chain together via "next". */
-struct virtq_desc
-{
- rt_uint64_t addr; /* Address (guest-physical). */
- rt_uint32_t len; /* Length. */
- rt_uint16_t flags; /* The flags as indicated above. */
- rt_uint16_t next; /* We chain unused descriptors via this, too */
-};
-
-struct virtq_avail
-{
- rt_uint16_t flags; /* Notifications */
- rt_uint16_t idx; /* Where the driver would put the next descriptor entry in the ring (modulo the queue size) */
- rt_uint16_t ring[];
-
- /*
- * Only if VIRTIO_F_RING_EVENT_IDX
- * rt_uint16_t used_event;
- */
-};
-
-struct virtq_used_elem
-{
- rt_uint32_t id; /* Index of start of used descriptor chain. */
- rt_uint32_t len; /* Total length of the descriptor chain which was written to. */
-};
-
-struct virtq_used
-{
- rt_uint16_t flags;
- rt_uint16_t idx;
- struct virtq_used_elem ring[];
-
- /*
- * Only if VIRTIO_F_RING_EVENT_IDX
- * rt_uint16_t avail_event;
- */
-};
-
-struct virtq
-{
- rt_uint32_t num;
-
- struct virtq_desc *desc;
- struct virtq_avail *avail;
- struct virtq_used *used;
-
- /* Helper of driver */
- rt_uint16_t used_idx;
- rt_bool_t *free;
- rt_size_t free_count;
-};
-
-#define VIRTQ_DESC_TOTAL_SIZE(ring_size) (sizeof(struct virtq_desc) * (ring_size))
-/* flags, idx, used_event + ring * ring_size */
-#define VIRTQ_AVAIL_TOTAL_SIZE(ring_size) (sizeof(rt_uint16_t) * 3 + sizeof(rt_uint16_t) * (ring_size))
-/* flags, idx, avail_event + ring * ring_size */
-#define VIRTQ_USED_TOTAL_SIZE(ring_size) (sizeof(rt_uint16_t) * 3 + sizeof(struct virtq_used_elem) * (ring_size))
-
-#define VIRTQ_AVAIL_RES_SIZE (sizeof(rt_uint16_t)) /* used_event */
-#define VIRTQ_USED_RES_SIZE (sizeof(rt_uint16_t)) /* avail_event */
-
-#define VIRTQ_INVALID_DESC_ID RT_UINT16_MAX
-
-#endif /* __VIRTIO_QUEUE_H__ */