mirror of
https://github.com/54shady/kernel_drivers_examples.git
synced 2026-01-13 16:02:37 +00:00
Delete virtio mini driver
This commit is contained in:
@ -1,364 +0,0 @@
|
||||
From 011c832118d82f4ef3d6f0166e20acc17a9bd58f Mon Sep 17 00:00:00 2001
|
||||
From: zeroway <M_O_Bz@163.com>
|
||||
Date: Fri, 14 Jul 2023 19:36:54 +0800
|
||||
Subject: [PATCH] Add virtio mini device
|
||||
|
||||
---
|
||||
hw/virtio/meson.build | 2 +
|
||||
hw/virtio/virtio-mini-pci.c | 62 ++++++++
|
||||
hw/virtio/virtio-mini.c | 154 +++++++++++++++++++
|
||||
hw/virtio/virtio.c | 1 +
|
||||
include/hw/pci/pci.h | 2 +
|
||||
include/hw/virtio/virtio-mini.h | 18 +++
|
||||
include/standard-headers/linux/virtio_ids.h | 5 +-
|
||||
include/standard-headers/linux/virtio_mini.h | 7 +
|
||||
softmmu/qdev-monitor.c | 3 +
|
||||
9 files changed, 253 insertions(+), 1 deletion(-)
|
||||
create mode 100644 hw/virtio/virtio-mini-pci.c
|
||||
create mode 100644 hw/virtio/virtio-mini.c
|
||||
create mode 100644 include/hw/virtio/virtio-mini.h
|
||||
create mode 100644 include/standard-headers/linux/virtio_mini.h
|
||||
|
||||
diff --git a/hw/virtio/meson.build b/hw/virtio/meson.build
|
||||
index 7e8877fd64..29e0442cfb 100644
|
||||
--- a/hw/virtio/meson.build
|
||||
+++ b/hw/virtio/meson.build
|
||||
@@ -1,6 +1,8 @@
|
||||
softmmu_virtio_ss = ss.source_set()
|
||||
softmmu_virtio_ss.add(files('virtio-bus.c'))
|
||||
softmmu_virtio_ss.add(when: 'CONFIG_VIRTIO_PCI', if_true: files('virtio-pci.c'))
|
||||
+softmmu_virtio_ss.add(when: 'CONFIG_VIRTIO_PCI', if_true: files('virtio-mini.c'))
|
||||
+softmmu_virtio_ss.add(when: 'CONFIG_VIRTIO_PCI', if_true: files('virtio-mini-pci.c'))
|
||||
softmmu_virtio_ss.add(when: 'CONFIG_VIRTIO_MMIO', if_true: files('virtio-mmio.c'))
|
||||
|
||||
virtio_ss = ss.source_set()
|
||||
diff --git a/hw/virtio/virtio-mini-pci.c b/hw/virtio/virtio-mini-pci.c
|
||||
new file mode 100644
|
||||
index 0000000000..6e82eb038f
|
||||
--- /dev/null
|
||||
+++ b/hw/virtio/virtio-mini-pci.c
|
||||
@@ -0,0 +1,62 @@
|
||||
+#include "qemu/osdep.h"
|
||||
+#include "hw/hw.h"
|
||||
+#include "hw/qdev-properties.h"
|
||||
+#include "hw/virtio/virtio-pci.h"
|
||||
+#include "hw/virtio/virtio-mini.h"
|
||||
+#include "qom/object.h"
|
||||
+
|
||||
+typedef struct VirtIOMiniPCI VirtIOMiniPCI;
|
||||
+
|
||||
+#define TYPE_VIRTIO_MINI_PCI "virtio-mini-pci-base"
|
||||
+#define VIRTIO_MINI_PCI(obj) \
|
||||
+ OBJECT_CHECK(VirtIOMiniPCI, (obj), TYPE_VIRTIO_MINI_PCI)
|
||||
+
|
||||
+struct VirtIOMiniPCI {
|
||||
+ VirtIOPCIProxy parent_obj;
|
||||
+ VirtIOMini vdev;
|
||||
+};
|
||||
+
|
||||
+static void virtio_mini_pci_realize(VirtIOPCIProxy *vpci_dev, Error **errp) {
|
||||
+ VirtIOMiniPCI *vmini = VIRTIO_MINI_PCI(vpci_dev);
|
||||
+ DeviceState *vdev = DEVICE(&vmini->vdev);
|
||||
+ Error *err = NULL;
|
||||
+
|
||||
+ qdev_set_parent_bus(vdev, BUS(&vpci_dev->bus), &err);
|
||||
+ object_property_set_bool(OBJECT(vdev), "realized", true, &err);
|
||||
+}
|
||||
+
|
||||
+static void virtio_mini_pci_class_init(ObjectClass *klass, void *data) {
|
||||
+ DeviceClass *dc = DEVICE_CLASS(klass);
|
||||
+ VirtioPCIClass *k = VIRTIO_PCI_CLASS(klass);
|
||||
+ PCIDeviceClass *pcidev_k = PCI_DEVICE_CLASS(klass);
|
||||
+
|
||||
+ k->realize = virtio_mini_pci_realize;
|
||||
+ set_bit(DEVICE_CATEGORY_MISC, dc->categories);
|
||||
+
|
||||
+ pcidev_k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET;
|
||||
+ pcidev_k->device_id = PCI_DEVICE_ID_VIRTIO_MINI;
|
||||
+ pcidev_k->revision = VIRTIO_PCI_ABI_VERSION;
|
||||
+ pcidev_k->class_id = PCI_CLASS_OTHERS;
|
||||
+}
|
||||
+
|
||||
+static void virtio_mini_initfn(Object *obj) {
|
||||
+ VirtIOMiniPCI *dev = VIRTIO_MINI_PCI(obj);
|
||||
+ virtio_instance_init_common(obj, &dev->vdev, sizeof(dev->vdev),
|
||||
+ TYPE_VIRTIO_MINI);
|
||||
+}
|
||||
+
|
||||
+static const VirtioPCIDeviceTypeInfo virtio_mini_pci_info = {
|
||||
+ .base_name = TYPE_VIRTIO_MINI_PCI,
|
||||
+ .generic_name = "virtio-mini-pci",
|
||||
+ .transitional_name = "virtio-mini-pci-transitional",
|
||||
+ .non_transitional_name = "virtio-mini-pci-non-transitional",
|
||||
+ .instance_size = sizeof(VirtIOMiniPCI),
|
||||
+ .instance_init = virtio_mini_initfn,
|
||||
+ .class_init = virtio_mini_pci_class_init
|
||||
+};
|
||||
+
|
||||
+static void virtio_mini_pci_register(void)
|
||||
+{
|
||||
+ virtio_pci_types_register(&virtio_mini_pci_info);
|
||||
+}
|
||||
+type_init(virtio_mini_pci_register);
|
||||
diff --git a/hw/virtio/virtio-mini.c b/hw/virtio/virtio-mini.c
|
||||
new file mode 100644
|
||||
index 0000000000..d12b096ff1
|
||||
--- /dev/null
|
||||
+++ b/hw/virtio/virtio-mini.c
|
||||
@@ -0,0 +1,154 @@
|
||||
+#include "qemu/osdep.h"
|
||||
+#include "hw/hw.h"
|
||||
+#include "hw/virtio/virtio.h"
|
||||
+#include "hw/virtio/virtio-mini.h"
|
||||
+#include "qemu/iov.h"
|
||||
+#include "qemu/error-report.h"
|
||||
+#include "standard-headers/linux/virtio_ids.h"
|
||||
+#include "qemu/error-report.h"
|
||||
+#include "sysemu/runstate.h"
|
||||
+
|
||||
+static uint64_t virtio_mini_get_features(VirtIODevice *vdev, uint64_t f, Error **errp)
|
||||
+{
|
||||
+ return f;
|
||||
+}
|
||||
+
|
||||
+static void virtio_mini_set_status(VirtIODevice *vdev, uint8_t status)
|
||||
+{
|
||||
+ if (!vdev->vm_running) {
|
||||
+ return;
|
||||
+ }
|
||||
+ vdev->status = status;
|
||||
+}
|
||||
+
|
||||
+/*
|
||||
+ * callback for receiving virtqueue (outbuf on guest)
|
||||
+ * Guest sendout will trigger this callback
|
||||
+ *
|
||||
+ * echo hello > /proc/virtio-mini-0
|
||||
+ */
|
||||
+static void virtio_mini_handle_outbuf(VirtIODevice *vdev, VirtQueue *vq)
|
||||
+{
|
||||
+ /* acllocation of VirtQueueElement happens in virtqueue_pop call */
|
||||
+ VirtIOMini *vmini = VIRTIO_MINI(vdev);
|
||||
+ VirtQueueElement *vqe;
|
||||
+
|
||||
+ while (!virtio_queue_ready(vq)) {
|
||||
+ return;
|
||||
+ }
|
||||
+ if (!runstate_check(RUN_STATE_RUNNING)) {
|
||||
+ return;
|
||||
+ }
|
||||
+
|
||||
+ vqe = virtqueue_pop(vq, sizeof(VirtQueueElement));
|
||||
+ iov_to_buf(vqe->out_sg, vqe->out_num, 0, vmini->rcv_bufs, vqe->out_sg->iov_len);
|
||||
+ printf("GuestWrite: %s\n", vmini->rcv_bufs);
|
||||
+ virtqueue_push(vq, vqe, 0);
|
||||
+ virtio_notify(vdev, vq);
|
||||
+ g_free(vqe);
|
||||
+
|
||||
+ return;
|
||||
+}
|
||||
+
|
||||
+/*
|
||||
+ * callback for transmitting virtqueue (inbuf on guest)
|
||||
+ * Guest receive data will trigger this callback
|
||||
+ *
|
||||
+ * cat /proc/virtio-mini-0
|
||||
+ */
|
||||
+static void virtio_mini_handle_inbuf(VirtIODevice *vdev, VirtQueue *vq)
|
||||
+{
|
||||
+ VirtIOMini *vmini = VIRTIO_MINI(vdev);
|
||||
+ VirtQueueElement *vqe;
|
||||
+
|
||||
+ while (!virtio_queue_ready(vq)) {
|
||||
+ return;
|
||||
+ }
|
||||
+ if (!runstate_check(RUN_STATE_RUNNING)) {
|
||||
+ return;
|
||||
+ }
|
||||
+ vqe = virtqueue_pop(vq, sizeof(VirtQueueElement));
|
||||
+
|
||||
+ iov_from_buf(vqe->in_sg, vqe->in_num, 0, vmini->rcv_bufs, vqe->in_sg->iov_len);
|
||||
+ printf("GuestReceive: %s\n", vmini->rcv_bufs);
|
||||
+ virtqueue_push(vq, vqe, vqe->in_sg->iov_len);
|
||||
+ virtio_notify(vdev, vq);
|
||||
+ g_free(vqe);
|
||||
+
|
||||
+ return;
|
||||
+}
|
||||
+
|
||||
+static void virtio_mini_device_realize(DeviceState *dev, Error **errp)
|
||||
+{
|
||||
+ VirtIODevice *vdev = VIRTIO_DEVICE(dev);
|
||||
+ VirtIOMini *vmin = VIRTIO_MINI(dev);
|
||||
+ virtio_init(vdev, VIRTIO_ID_MINI, 0);
|
||||
+
|
||||
+ vmin->vq_rx = virtio_add_queue(vdev, 64, virtio_mini_handle_outbuf);
|
||||
+ vmin->vq_tx = virtio_add_queue(vdev, 64, virtio_mini_handle_inbuf);
|
||||
+}
|
||||
+
|
||||
+static void virtio_mini_device_unrealize(DeviceState *dev)
|
||||
+{
|
||||
+ VirtIODevice *vdev = VIRTIO_DEVICE(dev);
|
||||
+ virtio_cleanup(vdev);
|
||||
+}
|
||||
+
|
||||
+static const VMStateDescription vmstate_virtio_mini = {
|
||||
+ .name = "virtio-mini",
|
||||
+ .minimum_version_id = 1,
|
||||
+ .version_id = 1,
|
||||
+ .fields = (VMStateField[]) {
|
||||
+ VMSTATE_VIRTIO_DEVICE,
|
||||
+ VMSTATE_END_OF_LIST()
|
||||
+ },
|
||||
+};
|
||||
+
|
||||
+static int vmstate_virtio_mini_device_pre_save(void * opaque)
|
||||
+{
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static int vmstate_virtio_mini_device_post_load(void * opaque, int version_id)
|
||||
+{
|
||||
+ return 0;
|
||||
+}
|
||||
+
|
||||
+static const VMStateDescription vmstate_virtio_mini_device = {
|
||||
+ .name = "virtio-mini-device",
|
||||
+ .version_id = 1,
|
||||
+ .minimum_version_id = 1,
|
||||
+ .pre_save = vmstate_virtio_mini_device_pre_save,
|
||||
+ .post_load = vmstate_virtio_mini_device_post_load,
|
||||
+ .fields = (VMStateField[]) {
|
||||
+ VMSTATE_BUFFER(rcv_bufs, VirtIOMini),
|
||||
+ VMSTATE_END_OF_LIST()
|
||||
+ },
|
||||
+};
|
||||
+
|
||||
+static void virtio_mini_class_init(ObjectClass *klass, void *data)
|
||||
+{
|
||||
+ DeviceClass *dc = DEVICE_CLASS(klass);
|
||||
+ dc->vmsd = &vmstate_virtio_mini;
|
||||
+ VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(klass);
|
||||
+
|
||||
+ set_bit(DEVICE_CATEGORY_MISC, dc->categories);
|
||||
+ vdc->realize = virtio_mini_device_realize;
|
||||
+ vdc->unrealize = virtio_mini_device_unrealize;
|
||||
+ vdc->get_features = virtio_mini_get_features;
|
||||
+ vdc->set_status = virtio_mini_set_status;
|
||||
+ vdc->vmsd = &vmstate_virtio_mini_device;
|
||||
+}
|
||||
+
|
||||
+static const TypeInfo virtio_mini_info = {
|
||||
+ .name = TYPE_VIRTIO_MINI,
|
||||
+ .parent = TYPE_VIRTIO_DEVICE,
|
||||
+ .instance_size = sizeof(VirtIOMini),
|
||||
+ .class_init = virtio_mini_class_init,
|
||||
+};
|
||||
+
|
||||
+static void virtio_register_types(void) {
|
||||
+ type_register_static(&virtio_mini_info);
|
||||
+}
|
||||
+
|
||||
+type_init(virtio_register_types);
|
||||
diff --git a/hw/virtio/virtio.c b/hw/virtio/virtio.c
|
||||
index 5d607aeaa0..cb959f050b 100644
|
||||
--- a/hw/virtio/virtio.c
|
||||
+++ b/hw/virtio/virtio.c
|
||||
@@ -137,6 +137,7 @@ const char *virtio_device_names[] = {
|
||||
[VIRTIO_ID_BLOCK] = "virtio-blk",
|
||||
[VIRTIO_ID_CONSOLE] = "virtio-serial",
|
||||
[VIRTIO_ID_RNG] = "virtio-rng",
|
||||
+ [VIRTIO_ID_MINI] = "virtio-mini",
|
||||
[VIRTIO_ID_BALLOON] = "virtio-balloon",
|
||||
[VIRTIO_ID_IOMEM] = "virtio-iomem",
|
||||
[VIRTIO_ID_RPMSG] = "virtio-rpmsg",
|
||||
diff --git a/include/hw/pci/pci.h b/include/hw/pci/pci.h
|
||||
index b54b6ef88f..db8c320885 100644
|
||||
--- a/include/hw/pci/pci.h
|
||||
+++ b/include/hw/pci/pci.h
|
||||
@@ -84,6 +84,8 @@ extern bool pci_available;
|
||||
#define PCI_DEVICE_ID_VIRTIO_RNG 0x1005
|
||||
#define PCI_DEVICE_ID_VIRTIO_9P 0x1009
|
||||
#define PCI_DEVICE_ID_VIRTIO_VSOCK 0x1012
|
||||
+/* PCI device ID = VIRTIO_ID_MINI + 0x1040 */
|
||||
+#define PCI_DEVICE_ID_VIRTIO_MINI 0x1055
|
||||
#define PCI_DEVICE_ID_VIRTIO_PMEM 0x1013
|
||||
#define PCI_DEVICE_ID_VIRTIO_IOMMU 0x1014
|
||||
#define PCI_DEVICE_ID_VIRTIO_MEM 0x1015
|
||||
diff --git a/include/hw/virtio/virtio-mini.h b/include/hw/virtio/virtio-mini.h
|
||||
new file mode 100644
|
||||
index 0000000000..7f48ca342c
|
||||
--- /dev/null
|
||||
+++ b/include/hw/virtio/virtio-mini.h
|
||||
@@ -0,0 +1,18 @@
|
||||
+#ifndef QEMU_VIRTIO_MINI_H_
|
||||
+#define QEMU_VIRTIO_MINI_H_
|
||||
+
|
||||
+#include "hw/virtio/virtio-pci.h"
|
||||
+#include "standard-headers/linux/virtio_mini.h"
|
||||
+
|
||||
+#define TYPE_VIRTIO_MINI "virtio-mini-device"
|
||||
+#define VIRTIO_MINI(obj) \
|
||||
+ OBJECT_CHECK(VirtIOMini, (obj), TYPE_VIRTIO_MINI)
|
||||
+
|
||||
+typedef struct VirtIOMini {
|
||||
+ VirtIODevice parent_obj;
|
||||
+ VirtQueue *vq_tx;
|
||||
+ VirtQueue *vq_rx;
|
||||
+ uint8_t rcv_bufs[1024];
|
||||
+} VirtIOMini;
|
||||
+
|
||||
+#endif
|
||||
diff --git a/include/standard-headers/linux/virtio_ids.h b/include/standard-headers/linux/virtio_ids.h
|
||||
index 80d76b75bc..6b2560deea 100644
|
||||
--- a/include/standard-headers/linux/virtio_ids.h
|
||||
+++ b/include/standard-headers/linux/virtio_ids.h
|
||||
@@ -47,7 +47,9 @@
|
||||
#define VIRTIO_ID_INPUT 18 /* virtio input */
|
||||
#define VIRTIO_ID_VSOCK 19 /* virtio vsock transport */
|
||||
#define VIRTIO_ID_CRYPTO 20 /* virtio crypto */
|
||||
-#define VIRTIO_ID_SIGNAL_DIST 21 /* virtio signal distribution device */
|
||||
+/* PCI device ID need plus 0x1040 */
|
||||
+#define VIRTIO_ID_MINI 21 /* virtio mini */
|
||||
+#define VIRTIO_ID_SIGNAL_DIST 42 /* virtio signal distribution device */
|
||||
#define VIRTIO_ID_PSTORE 22 /* virtio pstore device */
|
||||
#define VIRTIO_ID_IOMMU 23 /* virtio IOMMU */
|
||||
#define VIRTIO_ID_MEM 24 /* virtio mem */
|
||||
@@ -69,6 +71,7 @@
|
||||
#define VIRTIO_ID_BT 40 /* virtio bluetooth */
|
||||
#define VIRTIO_ID_GPIO 41 /* virtio gpio */
|
||||
|
||||
+
|
||||
/*
|
||||
* Virtio Transitional IDs
|
||||
*/
|
||||
diff --git a/include/standard-headers/linux/virtio_mini.h b/include/standard-headers/linux/virtio_mini.h
|
||||
new file mode 100644
|
||||
index 0000000000..daf0adf0de
|
||||
--- /dev/null
|
||||
+++ b/include/standard-headers/linux/virtio_mini.h
|
||||
@@ -0,0 +1,7 @@
|
||||
+#ifndef _LINUX_VIRTIO_MINI_H
|
||||
+#define _LINUX_VIRTIO_MINI_H
|
||||
+
|
||||
+#include "standard-headers/linux/virtio_ids.h"
|
||||
+#include "standard-headers/linux/virtio_config.h"
|
||||
+
|
||||
+#endif
|
||||
diff --git a/softmmu/qdev-monitor.c b/softmmu/qdev-monitor.c
|
||||
index 4b0ef65780..24d2d245b4 100644
|
||||
--- a/softmmu/qdev-monitor.c
|
||||
+++ b/softmmu/qdev-monitor.c
|
||||
@@ -99,6 +99,9 @@ static const QDevAlias qdev_alias_table[] = {
|
||||
{ "virtio-net-device", "virtio-net", QEMU_ARCH_VIRTIO_MMIO },
|
||||
{ "virtio-net-ccw", "virtio-net", QEMU_ARCH_VIRTIO_CCW },
|
||||
{ "virtio-net-pci", "virtio-net", QEMU_ARCH_VIRTIO_PCI },
|
||||
+ /* -device virtio-mini,disable-legacy=on */
|
||||
+ { "virtio-mini-device", "virtio-mini", QEMU_ARCH_VIRTIO_MMIO },
|
||||
+ { "virtio-mini-pci", "virtio-mini", QEMU_ARCH_VIRTIO_PCI },
|
||||
{ "virtio-rng-device", "virtio-rng", QEMU_ARCH_VIRTIO_MMIO },
|
||||
{ "virtio-rng-ccw", "virtio-rng", QEMU_ARCH_VIRTIO_CCW },
|
||||
{ "virtio-rng-pci", "virtio-rng", QEMU_ARCH_VIRTIO_PCI },
|
||||
--
|
||||
2.35.1
|
||||
|
||||
@ -6,7 +6,6 @@ DEBFLAGS = -O2
|
||||
endif
|
||||
|
||||
obj-m := crypto-drv.o
|
||||
obj-m := virtio_mini.o
|
||||
KERNELDIR ?= /usr/src/linux
|
||||
CC ?= gcc
|
||||
PWD := $(shell pwd)
|
||||
|
||||
@ -1,225 +0,0 @@
|
||||
#include <linux/module.h>
|
||||
#include <linux/uaccess.h>
|
||||
#include <linux/scatterlist.h>
|
||||
#include <linux/virtio_config.h>
|
||||
#include "virtio_mini.h"
|
||||
|
||||
static int virtio_mini_open(struct inode *inode, struct file *file)
|
||||
{
|
||||
struct virtio_mini_device *vmini = PDE_DATA(inode);
|
||||
|
||||
file->private_data = vmini;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* cat /proc/virtio-mini-0 */
|
||||
static ssize_t virtio_mini_read(struct file *fil, char *buf, size_t count, loff_t *offp)
|
||||
{
|
||||
struct virtio_mini_device *vmini = fil->private_data;
|
||||
char *rcv_buf;
|
||||
struct scatterlist sg;
|
||||
unsigned long res;
|
||||
struct virtqueue *vq = vmini->queues[VIRTIO_MINI_VQ_RX].vq;
|
||||
|
||||
if (vmini->buffers < 1)
|
||||
{
|
||||
printk(KERN_INFO "all buffers read!");
|
||||
return 0;
|
||||
}
|
||||
|
||||
rcv_buf = kzalloc(vmini->buf_lens[vmini->buffers - 1], GFP_KERNEL);
|
||||
if (!rcv_buf)
|
||||
{
|
||||
return ENOMEM;
|
||||
}
|
||||
|
||||
sg_init_one(&sg, rcv_buf, vmini->buf_lens[vmini->buffers - 1]);
|
||||
virtqueue_add_inbuf(vq, &sg, 1, rcv_buf, GFP_KERNEL);
|
||||
virtqueue_kick(vq);
|
||||
|
||||
wait_for_completion(&vmini->data_ready);
|
||||
res = copy_to_user(buf, vmini->read_data, vmini->buf_lens[vmini->buffers]);
|
||||
if (res != 0)
|
||||
{
|
||||
printk(KERN_INFO "Could not read %lu bytes!", res);
|
||||
/* update length to actual number of bytes read */
|
||||
vmini->buf_lens[vmini->buffers] = vmini->buf_lens[vmini->buffers] - res;
|
||||
}
|
||||
|
||||
kfree(rcv_buf);
|
||||
return vmini->buf_lens[vmini->buffers];
|
||||
}
|
||||
|
||||
/* echo hello > /proc/virtio-mini-0 */
|
||||
static ssize_t virtio_mini_write(struct file* fil, const char *buf, size_t count, loff_t *offp)
|
||||
{
|
||||
struct virtio_mini_device *vmini = fil->private_data;
|
||||
void *to_send;
|
||||
unsigned long res;
|
||||
struct scatterlist sg;
|
||||
struct virtqueue *vq = vmini->queues[VIRTIO_MINI_VQ_TX].vq;
|
||||
|
||||
if (vmini->buffers >= VIRTIO_MINI_BUFFERS)
|
||||
{
|
||||
printk(KERN_INFO "all buffers used!");
|
||||
return ENOSPC;
|
||||
}
|
||||
|
||||
/* 分配空间用于保存用户要发送的数据 */
|
||||
to_send = kmalloc(count, GFP_KERNEL);
|
||||
if (!to_send)
|
||||
{
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* 将用户的数据保存到to_send */
|
||||
res = copy_from_user(to_send, buf, count);
|
||||
if (res != 0) {
|
||||
printk(KERN_INFO "Could not write %lu bytes!", res);
|
||||
/* update count to actual number of bytes written */
|
||||
count = count - res;
|
||||
}
|
||||
|
||||
/*
|
||||
* virtqueue中数据是存VirtQueueElement中的in_sg或out_sg散列中的
|
||||
* 驱动中用对应的api来打包,这里virtqueue_add_outbuf
|
||||
* 所以填充的out_sg
|
||||
*
|
||||
* 在设备中通过virtqueue_pop来获取到对应的VirtQueueElement后取出散列中的数据
|
||||
* 1. 取出element
|
||||
* vqe = virtqueue_pop(vq, sizeof(VirtQueueElement));
|
||||
* 2. 取出element里的数据
|
||||
* iov_to_buf(vqe->out_sg, vqe->out_num, 0, rcv_bufs, vqe->out_sg->iov_len);
|
||||
*/
|
||||
sg_init_one(&sg, to_send, count);
|
||||
vmini->buf_lens[vmini->buffers++] = count;
|
||||
virtqueue_add_outbuf(vq, &sg, 1, to_send, GFP_KERNEL);
|
||||
virtqueue_kick(vq);
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
/* host has acknowledged the message; consume buffer */
|
||||
void virtio_mini_tx_notify_cb(struct virtqueue *vq)
|
||||
{
|
||||
int len;
|
||||
void *buf = virtqueue_get_buf(vq, &len);
|
||||
|
||||
/* free sent data */
|
||||
if (buf)
|
||||
{
|
||||
kfree(buf);
|
||||
}
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
void virtio_mini_rx_notify_cb(struct virtqueue *vq)
|
||||
{
|
||||
int len;
|
||||
struct virtio_mini_device *vmini = vq->vdev->priv;
|
||||
|
||||
vmini->read_data = virtqueue_get_buf(vq, &len);
|
||||
vmini->buffers--;
|
||||
complete(&vmini->data_ready);
|
||||
|
||||
printk(KERN_INFO "Received %i bytes", len);
|
||||
}
|
||||
|
||||
int vmini_find_vqs(struct virtio_mini_device *vmini)
|
||||
{
|
||||
int i;
|
||||
int err;
|
||||
struct virtqueue *vqs[VIRTIO_MINI_VQ_MAX];
|
||||
|
||||
static const char *names[VIRTIO_MINI_VQ_MAX] = {
|
||||
[VIRTIO_MINI_VQ_TX] = "virtio-mini-tx",
|
||||
[VIRTIO_MINI_VQ_RX] = "virtio-mini-rx"
|
||||
};
|
||||
|
||||
static vq_callback_t *callbacks[VIRTIO_MINI_VQ_MAX] = {
|
||||
[VIRTIO_MINI_VQ_TX] = virtio_mini_tx_notify_cb,
|
||||
[VIRTIO_MINI_VQ_RX] = virtio_mini_rx_notify_cb
|
||||
};
|
||||
|
||||
err = virtio_find_vqs(vmini->vdev, VIRTIO_MINI_VQ_MAX, vqs, callbacks, names, NULL);
|
||||
if (err)
|
||||
{
|
||||
return err;
|
||||
}
|
||||
|
||||
for (i = 0; i < VIRTIO_MINI_VQ_MAX; i++)
|
||||
vmini->queues[i].vq = vqs[i];
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int probe_virtio_mini(struct virtio_device *vdev)
|
||||
{
|
||||
struct virtio_mini_device *vmini;
|
||||
int err;
|
||||
char proc_name[20];
|
||||
|
||||
printk(KERN_INFO "virtio-mini device found\n");
|
||||
|
||||
vmini = kzalloc(sizeof(struct virtio_mini_device), GFP_KERNEL);
|
||||
if (vmini == NULL) {
|
||||
err = ENOMEM;
|
||||
goto err;
|
||||
}
|
||||
|
||||
/*
|
||||
* make it possible to access underlying virtio_device
|
||||
* from virtio_mini_device and vice versa
|
||||
*/
|
||||
vdev->priv = vmini;
|
||||
vmini->vdev = vdev;
|
||||
err = vmini_find_vqs(vmini);
|
||||
if (err) {
|
||||
printk(KERN_INFO "Error adding virtqueue\n");
|
||||
goto err;
|
||||
}
|
||||
vmini->buffers = 0;
|
||||
|
||||
init_completion(&vmini->data_ready);
|
||||
|
||||
/*
|
||||
* create a proc entry named "/proc/virtio-mini-<bus_idx>"
|
||||
* proc_dir_entry data pointer points to associated virtio_mini_device
|
||||
* allows access to virtqueues from defined file_operations functions
|
||||
*/
|
||||
snprintf(proc_name, sizeof(proc_name), "%s-%i", VIRTIO_MINI_STRING, vdev->index);
|
||||
vmini->pde = proc_create_data(proc_name, 0644, NULL, &pde_fops, vmini);
|
||||
if (!vmini->pde) {
|
||||
printk(KERN_INFO "Error creating proc entry");
|
||||
goto err;
|
||||
}
|
||||
|
||||
printk(KERN_INFO "virtio-mini device probe successfully\n");
|
||||
|
||||
return 0;
|
||||
|
||||
err:
|
||||
kfree(vmini);
|
||||
return err;
|
||||
}
|
||||
|
||||
void remove_virtio_mini(struct virtio_device *vdev)
|
||||
{
|
||||
struct virtio_mini_device *vmini = vdev->priv;
|
||||
|
||||
proc_remove(vmini->pde);
|
||||
complete(&vmini->data_ready);
|
||||
vdev->config->reset(vdev);
|
||||
vdev->config->del_vqs(vdev);
|
||||
kfree(vdev->priv);
|
||||
|
||||
printk(KERN_INFO "virtio-mini device removed\n");
|
||||
}
|
||||
|
||||
module_virtio_driver(driver_virtio_mini);
|
||||
|
||||
MODULE_AUTHOR("zeroway");
|
||||
MODULE_DESCRIPTION("virtio example front-end driver");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
@ -1,77 +0,0 @@
|
||||
#include <linux/proc_fs.h>
|
||||
#include <linux/virtio.h>
|
||||
#include <linux/completion.h>
|
||||
|
||||
#ifndef VIRTIO_ID_MINI
|
||||
#define VIRTIO_ID_MINI 21
|
||||
#endif
|
||||
|
||||
#define VIRTIO_MINI_BUFFERS 1024
|
||||
#define VIRTIO_MINI_STRING "virtio-mini"
|
||||
|
||||
enum {
|
||||
/* device virtqueue indexes */
|
||||
VIRTIO_MINI_VQ_TX = 0,
|
||||
VIRTIO_MINI_VQ_RX,
|
||||
/* # of device virtqueues */
|
||||
VIRTIO_MINI_VQ_MAX
|
||||
};
|
||||
|
||||
MODULE_AUTHOR("Matthias Prangl");
|
||||
MODULE_DESCRIPTION("virtio example front-end driver");
|
||||
MODULE_LICENSE("GPL v2");
|
||||
|
||||
static struct virtio_device_id id_table[] = {
|
||||
{ VIRTIO_ID_MINI, VIRTIO_DEV_ANY_ID },
|
||||
{ 0 },
|
||||
};
|
||||
|
||||
static unsigned int feature_table[] = { };
|
||||
|
||||
struct virtio_mini_vqueue {
|
||||
spinlock_t lock;
|
||||
struct virtqueue *vq;
|
||||
};
|
||||
|
||||
struct virtio_mini_device {
|
||||
struct virtio_mini_vqueue queues[VIRTIO_MINI_VQ_MAX];
|
||||
/* related virtio_device */
|
||||
struct virtio_device *vdev;
|
||||
/* proc dir entry for this instance of the device */
|
||||
struct proc_dir_entry *pde;
|
||||
/* store length of last sent message */
|
||||
unsigned int buffers;
|
||||
unsigned int buf_lens[VIRTIO_MINI_BUFFERS];
|
||||
void *read_data;
|
||||
struct completion data_ready;
|
||||
};
|
||||
|
||||
static int virtio_mini_open(struct inode *inode, struct file *file);
|
||||
static ssize_t virtio_mini_read(struct file *fil, char *buf, size_t count, loff_t *offp);
|
||||
static ssize_t virtio_mini_write(struct file* fil, const char *buf, size_t count, loff_t *offp);
|
||||
|
||||
|
||||
void virtio_mini_vq_tx_cb(struct virtqueue *vq);
|
||||
void virtio_mini_vq_rx_cb(struct virtqueue *vq);
|
||||
|
||||
int vmini_find_vqs(struct virtio_mini_device *vmini);
|
||||
int probe_virtio_mini(struct virtio_device *vdev);
|
||||
|
||||
void remove_virtio_mini(struct virtio_device *vdev);
|
||||
|
||||
static struct file_operations pde_fops = {
|
||||
.owner = THIS_MODULE,
|
||||
.open = virtio_mini_open,
|
||||
.read = virtio_mini_read,
|
||||
.write = virtio_mini_write,
|
||||
};
|
||||
|
||||
static struct virtio_driver driver_virtio_mini = {
|
||||
.driver.name = KBUILD_MODNAME,
|
||||
.driver.owner = THIS_MODULE,
|
||||
.id_table = id_table,
|
||||
.feature_table = feature_table,
|
||||
.feature_table_size = ARRAY_SIZE(feature_table),
|
||||
.probe = probe_virtio_mini,
|
||||
.remove = remove_virtio_mini
|
||||
};
|
||||
Reference in New Issue
Block a user