qemu-devel
[Top][All Lists]
Advanced

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

Re: [Qemu-devel] [PATCH qemu 3/6] virtio-input: core code & base class


From: Michael S. Tsirkin
Subject: Re: [Qemu-devel] [PATCH qemu 3/6] virtio-input: core code & base class
Date: Thu, 10 Apr 2014 14:06:21 +0300

On Thu, Apr 10, 2014 at 11:07:51AM +0200, Gerd Hoffmann wrote:
> This patch adds virtio-input support to qemu.  It brings a abstract
> base class providing core support, other classes can build on it to
> actually implement input devices.
> 
> virtio-input basically sends linux input layer events (evdev) over
> virtio.
> 
> Signed-off-by: Gerd Hoffmann <address@hidden>
> ---
>  hw/input/Makefile.objs           |   4 +
>  hw/input/virtio-input.c          | 253 
> +++++++++++++++++++++++++++++++++++++++
>  hw/virtio/virtio-pci.c           |  36 ++++++
>  hw/virtio/virtio-pci.h           |  14 +++
>  include/hw/virtio/virtio-input.h | 105 ++++++++++++++++
>  include/hw/virtio/virtio.h       |   1 +
>  6 files changed, 413 insertions(+)
>  create mode 100644 hw/input/virtio-input.c
>  create mode 100644 include/hw/virtio/virtio-input.h
> 
> diff --git a/hw/input/Makefile.objs b/hw/input/Makefile.objs
> index e8c80b9..ee8bba9 100644
> --- a/hw/input/Makefile.objs
> +++ b/hw/input/Makefile.objs
> @@ -8,6 +8,10 @@ common-obj-$(CONFIG_STELLARIS_INPUT) += stellaris_input.o
>  common-obj-$(CONFIG_TSC2005) += tsc2005.o
>  common-obj-$(CONFIG_VMMOUSE) += vmmouse.o
>  
> +ifeq ($(CONFIG_LINUX),y)
> +common-obj-$(CONFIG_VIRTIO) += virtio-input.o
> +endif
> +
>  obj-$(CONFIG_MILKYMIST) += milkymist-softusb.o
>  obj-$(CONFIG_PXA2XX) += pxa2xx_keypad.o
>  obj-$(CONFIG_TSC210X) += tsc210x.o
> diff --git a/hw/input/virtio-input.c b/hw/input/virtio-input.c
> new file mode 100644
> index 0000000..35f0cfc
> --- /dev/null
> +++ b/hw/input/virtio-input.c
> @@ -0,0 +1,253 @@
> +/*
> + * This work is licensed under the terms of the GNU GPL, version 2 or
> + * (at your option) any later version.  See the COPYING file in the
> + * top-level directory.
> + */
> +
> +#include "qemu/iov.h"
> +
> +#include "hw/qdev.h"
> +#include "hw/virtio/virtio.h"
> +#include "hw/virtio/virtio-input.h"
> +
> +#include "ui/console.h"
> +
> +#include <linux/input.h>
> +
> +/* ----------------------------------------------------------------- */
> +
> +void virtio_input_send(VirtIOInput *vinput, virtio_input_event *event)
> +{
> +    VirtQueueElement elem;
> +    int len;
> +
> +    if (!virtqueue_pop(vinput->evt, &elem)) {
> +        fprintf(stderr, "%s: virtqueue empty, dropping event\n", __func__);
> +        return;

Looks scary.

> +    }
> +    len = iov_from_buf(elem.in_sg, elem.in_num,
> +                       0, event, sizeof(*event));
> +    virtqueue_push(vinput->evt, &elem, len);
> +}
> +
> +static void virtio_input_handle_evt(VirtIODevice *vdev, VirtQueue *vq)
> +{
> +    /* nothing */
> +}
> +
> +static void virtio_input_handle_sts(VirtIODevice *vdev, VirtQueue *vq)
> +{
> +    VirtIOInputClass *vic = VIRTIO_INPUT_GET_CLASS(vdev);
> +    VirtIOInput *vinput = VIRTIO_INPUT(vdev);
> +    virtio_input_event event;
> +    VirtQueueElement elem;
> +    int len;
> +
> +    while (virtqueue_pop(vinput->sts, &elem)) {
> +        memset(&event, 0, sizeof(event));
> +        len = iov_to_buf(elem.out_sg, elem.out_num,
> +                         0, &event, sizeof(event));
> +        if (vic->handle_status) {
> +            vic->handle_status(vinput, &event);
> +        }
> +        virtqueue_push(vinput->sts, &elem, len);
> +    }
> +    virtio_notify(vdev, vinput->sts);
> +}
> +
> +static virtio_input_config *virtio_input_find_config(VirtIOInput *vinput,
> +                                                     uint8_t select,
> +                                                     uint8_t subsel)
> +{
> +    VirtIOInputConfig *cfg;
> +
> +    QTAILQ_FOREACH(cfg, &vinput->cfg_list, node) {
> +        if (select == cfg->config.select &&
> +            subsel == cfg->config.subsel) {
> +            return &cfg->config;
> +        }
> +    }
> +    return NULL;
> +}
> +
> +void virtio_input_add_config(VirtIOInput *vinput,
> +                             virtio_input_config *config)
> +{
> +    VirtIOInputConfig *cfg;
> +
> +    if (virtio_input_find_config(vinput, config->select, config->subsel)) {
> +        /* should not happen */
> +        fprintf(stderr, "%s: duplicate config: %d/%d\n",
> +                __func__, config->select, config->subsel);
> +        abort();
> +    }
> +
> +    cfg = g_new0(VirtIOInputConfig, 1);
> +    cfg->config = *config;
> +    QTAILQ_INSERT_TAIL(&vinput->cfg_list, cfg, node);
> +}
> +
> +void virtio_input_init_config(VirtIOInput *vinput,
> +                              virtio_input_config *config)
> +{
> +    int i = 0;
> +
> +    QTAILQ_INIT(&vinput->cfg_list);
> +    while (config[i].select) {
> +        virtio_input_add_config(vinput, config + i);
> +        i++;
> +    }
> +}
> +
> +void virtio_input_idstr_config(VirtIOInput *vinput,
> +                               uint8_t select, const char *string)
> +{
> +    virtio_input_config id;
> +
> +    if (!string) {
> +        return;
> +    }
> +    memset(&id, 0, sizeof(id));
> +    id.select = select;
> +    id.size = snprintf(id.u.string, sizeof(id.u.string), "%s", string);
> +    virtio_input_add_config(vinput, &id);
> +}
> +
> +static void virtio_input_get_config(VirtIODevice *vdev, uint8_t *config_data)
> +{
> +    VirtIOInput *vinput = VIRTIO_INPUT(vdev);
> +    virtio_input_config *config;
> +
> +    config = virtio_input_find_config(vinput, vinput->cfg_select,
> +                                      vinput->cfg_subsel);
> +    if (config) {
> +        memcpy(config_data, config, vinput->cfg_size);
> +    } else {
> +        memset(config_data, 0, vinput->cfg_size);
> +    }
> +}
> +
> +static void virtio_input_set_config(VirtIODevice *vdev,
> +                                    const uint8_t *config_data)
> +{
> +    VirtIOInput *vinput = VIRTIO_INPUT(vdev);
> +    virtio_input_config *config = (virtio_input_config *)config_data;
> +
> +    vinput->cfg_select = config->select;
> +    vinput->cfg_subsel = config->subsel;
> +    virtio_notify_config(vdev);
> +}
> +
> +static uint32_t virtio_input_get_features(VirtIODevice *vdev, uint32_t f)
> +{
> +    return f;
> +}
> +
> +static void virtio_input_set_status(VirtIODevice *vdev, uint8_t val)
> +{
> +    VirtIOInputClass *vic = VIRTIO_INPUT_GET_CLASS(vdev);
> +    VirtIOInput *vinput = VIRTIO_INPUT(vdev);
> +
> +    if (val & VIRTIO_CONFIG_S_DRIVER_OK) {
> +        if (!vinput->active) {
> +            vinput->active = true;
> +            if (vic->change_active) {
> +                vic->change_active(vinput);
> +            }
> +        }
> +    }
> +}
> +
> +static void virtio_input_reset(VirtIODevice *vdev)
> +{
> +    VirtIOInputClass *vic = VIRTIO_INPUT_GET_CLASS(vdev);
> +    VirtIOInput *vinput = VIRTIO_INPUT(vdev);
> +
> +    if (vinput->active) {
> +        vinput->active = false;
> +        if (vic->change_active) {
> +            vic->change_active(vinput);
> +        }
> +    }
> +}
> +
> +static void virtio_input_device_realize(DeviceState *dev, Error **errp)
> +{
> +    VirtIOInputClass *vic = VIRTIO_INPUT_GET_CLASS(dev);
> +    VirtIODevice *vdev = VIRTIO_DEVICE(dev);
> +    VirtIOInput *vinput = VIRTIO_INPUT(dev);
> +    VirtIOInputConfig *cfg;
> +
> +
> +    if (vic->unrealize) {
> +        vic->realize(dev, errp);
> +        if (error_is_set(errp)) {
> +            return;
> +        }
> +    }
> +
> +    virtio_input_idstr_config(vinput, VIRTIO_INPUT_CFG_ID_SERIAL,
> +                              vinput->input.serial);
> +    virtio_input_idstr_config(vinput, VIRTIO_INPUT_CFG_ID_SEAT,
> +                              vinput->input.seat);
> +
> +    QTAILQ_FOREACH(cfg, &vinput->cfg_list, node) {
> +        if (vinput->cfg_size < cfg->config.size) {
> +            vinput->cfg_size = cfg->config.size;
> +        }
> +    }
> +    vinput->cfg_size += 4;
> +    assert(vinput->cfg_size <= sizeof(virtio_input_config));
> +
> +    virtio_init(vdev, "virtio-input", VIRTIO_ID_INPUT,
> +                vinput->cfg_size);
> +    vinput->evt = virtio_add_queue(vdev, 64, virtio_input_handle_evt);
> +    vinput->sts = virtio_add_queue(vdev, 64, virtio_input_handle_sts);
> +}
> +
> +static void virtio_input_device_unrealize(DeviceState *dev, Error **errp)
> +{
> +    VirtIOInputClass *vic = VIRTIO_INPUT_GET_CLASS(dev);
> +    VirtIODevice *vdev = VIRTIO_DEVICE(dev);
> +
> +    if (vic->unrealize) {
> +        vic->unrealize(dev, errp);
> +        if (error_is_set(errp)) {
> +            return;
> +        }
> +    }
> +    virtio_cleanup(vdev);
> +}
> +
> +static void virtio_input_class_init(ObjectClass *klass, void *data)
> +{
> +    DeviceClass *dc = DEVICE_CLASS(klass);
> +    VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(klass);
> +
> +    set_bit(DEVICE_CATEGORY_INPUT, dc->categories);
> +    vdc->realize      = virtio_input_device_realize;
> +    vdc->unrealize    = virtio_input_device_unrealize;
> +    vdc->get_config   = virtio_input_get_config;
> +    vdc->set_config   = virtio_input_set_config;
> +    vdc->get_features = virtio_input_get_features;
> +    vdc->set_status   = virtio_input_set_status;
> +    vdc->reset        = virtio_input_reset;
> +}
> +
> +static const TypeInfo virtio_input_info = {
> +    .name          = TYPE_VIRTIO_INPUT,
> +    .parent        = TYPE_VIRTIO_DEVICE,
> +    .instance_size = sizeof(VirtIOInput),
> +    .class_size    = sizeof(VirtIOInputClass),
> +    .class_init    = virtio_input_class_init,
> +    .abstract      = true,
> +};
> +
> +/* ----------------------------------------------------------------- */
> +
> +static void virtio_register_types(void)
> +{
> +    type_register_static(&virtio_input_info);
> +}
> +
> +type_init(virtio_register_types)
> diff --git a/hw/virtio/virtio-pci.c b/hw/virtio/virtio-pci.c
> index ce97514..5518192 100644
> --- a/hw/virtio/virtio-pci.c
> +++ b/hw/virtio/virtio-pci.c
> @@ -23,6 +23,7 @@
>  #include "hw/virtio/virtio-serial.h"
>  #include "hw/virtio/virtio-scsi.h"
>  #include "hw/virtio/virtio-balloon.h"
> +#include "hw/virtio/virtio-input.h"
>  #include "hw/pci/pci.h"
>  #include "qemu/error-report.h"
>  #include "hw/pci/msi.h"
> @@ -1531,6 +1532,40 @@ static const TypeInfo virtio_rng_pci_info = {
>      .class_init    = virtio_rng_pci_class_init,
>  };
>  
> +/* virtio-input-pci */
> +
> +static int virtio_input_pci_init(VirtIOPCIProxy *vpci_dev)
> +{
> +    VirtIOInputPCI *vinput = VIRTIO_INPUT_PCI(vpci_dev);
> +    DeviceState *vdev = DEVICE(&vinput->vdev);
> +
> +    qdev_set_parent_bus(vdev, BUS(&vpci_dev->bus));
> +    return qdev_init(vdev);
> +}
> +
> +static void virtio_input_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->init = virtio_input_pci_init;
> +    set_bit(DEVICE_CATEGORY_INPUT, dc->categories);
> +
> +    pcidev_k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET;
> +    pcidev_k->device_id = PCI_DEVICE_ID_VIRTIO_INPUT;
> +    pcidev_k->revision = VIRTIO_PCI_ABI_VERSION;
> +    pcidev_k->class_id = PCI_CLASS_OTHERS;
> +}
> +
> +static const TypeInfo virtio_input_pci_info = {
> +    .name          = TYPE_VIRTIO_INPUT_PCI,
> +    .parent        = TYPE_VIRTIO_PCI,
> +    .instance_size = sizeof(VirtIOInputPCI),
> +    .class_init    = virtio_input_pci_class_init,
> +    .abstract      = true,
> +};
> +
>  /* virtio-pci-bus */
>  
>  static void virtio_pci_bus_new(VirtioBusState *bus, size_t bus_size,
> @@ -1575,6 +1610,7 @@ static const TypeInfo virtio_pci_bus_info = {
>  static void virtio_pci_register_types(void)
>  {
>      type_register_static(&virtio_rng_pci_info);
> +    type_register_static(&virtio_input_pci_info);
>      type_register_static(&virtio_pci_bus_info);
>      type_register_static(&virtio_pci_info);
>  #ifdef CONFIG_VIRTFS
> diff --git a/hw/virtio/virtio-pci.h b/hw/virtio/virtio-pci.h
> index dc332ae..f1e75ad 100644
> --- a/hw/virtio/virtio-pci.h
> +++ b/hw/virtio/virtio-pci.h
> @@ -24,6 +24,7 @@
>  #include "hw/virtio/virtio-balloon.h"
>  #include "hw/virtio/virtio-bus.h"
>  #include "hw/virtio/virtio-9p.h"
> +#include "hw/virtio/virtio-input.h"
>  #ifdef CONFIG_VIRTFS
>  #include "hw/9pfs/virtio-9p.h"
>  #endif
> @@ -39,6 +40,7 @@ typedef struct VirtIOSerialPCI VirtIOSerialPCI;
>  typedef struct VirtIONetPCI VirtIONetPCI;
>  typedef struct VHostSCSIPCI VHostSCSIPCI;
>  typedef struct VirtIORngPCI VirtIORngPCI;
> +typedef struct VirtIOInputPCI VirtIOInputPCI;
>  
>  /* virtio-pci-bus */
>  
> @@ -199,6 +201,18 @@ struct VirtIORngPCI {
>      VirtIORNG vdev;
>  };
>  
> +/*
> + * virtio-input-pci: This extends VirtioPCIProxy.
> + */
> +#define TYPE_VIRTIO_INPUT_PCI "virtio-input-pci"
> +#define VIRTIO_INPUT_PCI(obj) \
> +        OBJECT_CHECK(VirtIOInputPCI, (obj), TYPE_VIRTIO_INPUT_PCI)
> +
> +struct VirtIOInputPCI {
> +    VirtIOPCIProxy parent_obj;
> +    VirtIOInput vdev;
> +};
> +
>  /* Virtio ABI version, if we increment this, we break the guest driver. */
>  #define VIRTIO_PCI_ABI_VERSION          0
>  
> diff --git a/include/hw/virtio/virtio-input.h 
> b/include/hw/virtio/virtio-input.h
> new file mode 100644
> index 0000000..5d37a70
> --- /dev/null
> +++ b/include/hw/virtio/virtio-input.h
> @@ -0,0 +1,105 @@
> +#ifndef _QEMU_VIRTIO_INPUT_H
> +#define _QEMU_VIRTIO_INPUT_H
> +
> +#include "ui/input.h"
> +
> +/* ----------------------------------------------------------------- */
> +/* virtio input protocol                                             */
> +
> +/* The Virtio ID for the virtio input device */
> +#define VIRTIO_ID_INPUT 18
> +
> +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_SEAT    = 0x03,
> +    VIRTIO_INPUT_CFG_PROP_BITS  = 0x10,
> +    VIRTIO_INPUT_CFG_EV_BITS    = 0x11,
> +    VIRTIO_INPUT_CFG_ABS_INFO   = 0x12,
> +};
> +
> +typedef struct virtio_input_absinfo {
> +    uint32_t       min;
> +    uint32_t       max;
> +    uint32_t       fuzz;
> +    uint32_t       flat;
> +} virtio_input_absinfo;
> +
> +typedef struct virtio_input_config {
> +    uint8_t        select;
> +    uint8_t        subsel;
> +    uint8_t        size;
> +    uint8_t        reserved;
> +    union {
> +        char       string[128];
> +        uint8_t    bitmap[128];
> +        virtio_input_absinfo abs;
> +    } u;
> +} virtio_input_config;
> +
> +typedef struct virtio_input_event {
> +    uint16_t       type;
> +    uint16_t       code;
> +    int32_t        value;
> +} virtio_input_event;
> +
> +/* ----------------------------------------------------------------- */
> +/* qemu internals                                                    */
> +
> +#define TYPE_VIRTIO_INPUT "virtio-input-device"
> +#define VIRTIO_INPUT(obj) \
> +        OBJECT_CHECK(VirtIOInput, (obj), TYPE_VIRTIO_INPUT)
> +#define VIRTIO_INPUT_GET_PARENT_CLASS(obj) \
> +        OBJECT_GET_PARENT_CLASS(obj, TYPE_VIRTIO_INPUT)
> +#define VIRTIO_INPUT_GET_CLASS(obj) \
> +        OBJECT_GET_CLASS(VirtIOInputClass, obj, TYPE_VIRTIO_INPUT)
> +#define VIRTIO_INPUT_CLASS(klass) \
> +        OBJECT_CLASS_CHECK(VirtIOInputClass, klass, TYPE_VIRTIO_INPUT)
> +
> +typedef struct VirtIOInput VirtIOInput;
> +typedef struct VirtIOInputClass VirtIOInputClass;
> +typedef struct VirtIOInputConfig VirtIOInputConfig;
> +
> +struct virtio_input_conf {
> +    char *serial;
> +    char *seat;
> +};
> +
> +struct VirtIOInputConfig {
> +    virtio_input_config               config;
> +    QTAILQ_ENTRY(VirtIOInputConfig)   node;
> +};
> +
> +struct VirtIOInput {
> +    VirtIODevice                      parent_obj;
> +    uint8_t                           cfg_select;
> +    uint8_t                           cfg_subsel;
> +    uint32_t                          cfg_size;
> +    QTAILQ_HEAD(, VirtIOInputConfig)  cfg_list;
> +    VirtQueue                         *evt, *sts;
> +    virtio_input_conf                 input;
> +
> +    bool                              active;
> +};
> +
> +struct VirtIOInputClass {
> +    /*< private >*/
> +    VirtioDeviceClass parent;
> +    /*< public >*/
> +
> +    DeviceRealize realize;
> +    DeviceUnrealize unrealize;
> +    void (*change_active)(VirtIOInput *vinput);
> +    void (*handle_status)(VirtIOInput *vinput, virtio_input_event *event);
> +};
> +
> +void virtio_input_send(VirtIOInput *vinput, virtio_input_event *event);
> +void virtio_input_init_config(VirtIOInput *vinput,
> +                              virtio_input_config *config);
> +void virtio_input_add_config(VirtIOInput *vinput,
> +                             virtio_input_config *config);
> +void virtio_input_idstr_config(VirtIOInput *vinput,
> +                               uint8_t select, const char *string);
> +
> +#endif /* _QEMU_VIRTIO_INPUT_H */
> diff --git a/include/hw/virtio/virtio.h b/include/hw/virtio/virtio.h
> index 3e54e90..93d1607 100644
> --- a/include/hw/virtio/virtio.h
> +++ b/include/hw/virtio/virtio.h
> @@ -222,6 +222,7 @@ VirtIODevice *virtio_net_init(DeviceState *dev, NICConf 
> *conf,
>                                struct virtio_net_conf *net,
>                                uint32_t host_features);
>  typedef struct virtio_serial_conf virtio_serial_conf;
> +typedef struct virtio_input_conf virtio_input_conf;
>  typedef struct VirtIOSCSIConf VirtIOSCSIConf;
>  typedef struct VirtIORNGConf VirtIORNGConf;
>  
> -- 
> 1.8.3.1



reply via email to

[Prev in Thread] Current Thread [Next in Thread]