#include "maru_virtio_power.h"
#include "maru_virtio_nfc.h"
#include "maru_virtio_vmodem.h"
+#include "maru_virtio_rotary.h"
typedef struct VirtIOTouchscreenPCI VirtIOTouchscreenPCI;
typedef struct VirtIOEVDIPCI VirtIOEVDIPCI;
typedef struct VirtIOPOWERPCI VirtIOPOWERPCI;
typedef struct VirtIOJACKPCI VirtIOJACKPCI;
typedef struct VirtIOVModemPCI VirtIOVModemPCI;
+typedef struct VirtIORotaryPCI VirtIORotaryPCI;
/*
* virtio-touchscreen-pci: This extends VirtioPCIProxy.
VirtIOVModem vdev;
};
+/*
+ * virtio-rotary-pci: This extends VirtioPCIProxy.
+ */
+#define TYPE_VIRTIO_ROTARY_PCI "virtio-rotary-pci"
+#define VIRTIO_ROTARY_PCI(obj) \
+ OBJECT_CHECK(VirtIORotaryPCI, (obj), TYPE_VIRTIO_ROTARY_PCI)
+struct VirtIORotaryPCI {
+ VirtIOPCIProxy parent_obj;
+ VirtIORotary vdev;
+};
+
/* virtio-touchscreen-pci */
.class_init = virtio_vmodem_pci_class_init,
};
+/* virtio-rotary-pci */
+
+static int virtio_rotary_pci_init(VirtIOPCIProxy *vpci_dev)
+{
+ VirtIORotaryPCI *dev = VIRTIO_ROTARY_PCI(vpci_dev);
+ DeviceState *vdev = DEVICE(&dev->vdev);
+
+ qdev_set_parent_bus(vdev, BUS(&vpci_dev->bus));
+ if (qdev_init(vdev) < 0) {
+ return -1;
+ }
+ return 0;
+}
+
+static void virtio_rotary_pci_class_init(ObjectClass *klass, void *data)
+{
+ VirtioPCIClass *k = VIRTIO_PCI_CLASS(klass);
+ PCIDeviceClass *pcidev_k = PCI_DEVICE_CLASS(klass);
+
+ k->init = virtio_rotary_pci_init;
+ pcidev_k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET;
+ pcidev_k->device_id = PCI_DEVICE_ID_VIRTIO_ROTARY;
+ pcidev_k->revision = VIRTIO_PCI_ABI_VERSION;
+ pcidev_k->class_id = PCI_CLASS_OTHERS;
+}
+
+static void virtio_rotary_pci_instance_init(Object *obj)
+{
+ VirtIORotaryPCI *dev = VIRTIO_ROTARY_PCI(obj);
+ object_initialize(&dev->vdev, sizeof(dev->vdev), TYPE_VIRTIO_ROTARY);
+ object_property_add_child(obj, "virtio-backend", OBJECT(&dev->vdev), NULL);
+}
+
+static TypeInfo virtio_rotary_pci_info = {
+ .name = TYPE_VIRTIO_ROTARY_PCI,
+ .parent = TYPE_VIRTIO_PCI,
+ .instance_size = sizeof(VirtIORotaryPCI),
+ .instance_init = virtio_rotary_pci_instance_init,
+ .class_init = virtio_rotary_pci_class_init,
+};
+
static void maru_virtio_pci_register_types(void)
{
type_register_static(&virtio_evdi_pci_info);
type_register_static(&virtio_jack_pci_info);
type_register_static(&virtio_power_pci_info);
type_register_static(&virtio_vmodem_pci_info);
+ type_register_static(&virtio_rotary_pci_info);
}
type_init(maru_virtio_pci_register_types)
--- /dev/null
+/*
+ * Maru Virtio Rotary Device
+ *
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Contact:
+ * Jinhyung Jo <Jinhyung Jo@samsung.com>
+ * Sangho Park <sangho1206.park@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Contributors:
+ * - S-Core Co., Ltd
+ *
+ */
+
+
+#include "hw/maru_device_ids.h"
+#include "maru_virtio_rotary.h"
+#include "util/new_debug_ch.h"
+
+DECLARE_DEBUG_CHANNEL(rotary);
+
+static VirtIORotary *g_vrtr;
+static VirtQueueElement elem;
+
+static void virtio_rotary_handle(VirtIODevice *vdev, VirtQueue *vq)
+{
+ VirtIORotary *vrtr = VIRTIO_ROTARY(vdev);
+ int index = 0;
+
+ if (virtio_queue_empty(vrtr->vq)) {
+ LOG_INFO("[%s] virtio queue is empty\n", __func__);
+ return;
+ }
+
+ /* Get a queue buffer which is written by guest side. */
+ do {
+ index = virtqueue_pop(vq, &elem);
+ LOG_TRACE("[%s] virtqueue_pop: index(%d)\n", __func__, index);
+ } while (index < ROTARY_QUEUE_SIZE);
+}
+
+void maru_rotary_event(int32_t delta, int32_t type)
+{
+ MrRotaryEvent event = {0, };
+ uint32_t *index = NULL;
+
+ LOG_TRACE("[%s] ENTER: delta(%d), type(%d)\n", __func__, delta, type);
+
+ if (!g_vrtr) {
+ LOG_SEVERE("[%s] VirtIORotary instance is NULL\n", __func__);
+ return;
+ }
+
+ if (!virtio_queue_ready(g_vrtr->vq)) {
+ LOG_INFO("[%s] virtqueue is not ready\n", __func__);
+ return;
+ }
+
+ index = &(g_vrtr->queue.idx);
+ LOG_TRACE("[%s] wptr(%u)\n", __func__, g_vrtr->queue.wptr);
+
+ if (*index == ROTARY_QUEUE_SIZE) {
+ *index = 0;
+ }
+ event.delta = delta;
+ event.type = type;
+
+ qemu_mutex_lock(&g_vrtr->mutex);
+ memcpy(&g_vrtr->queue.event[*index], &event, sizeof(MrRotaryEvent));
+ LOG_TRACE("[%s] event: delta(%d), type(%d), index(%u)\n",
+ __func__, event.delta, event.type, *index);
+ (*index)++;
+ g_vrtr->queue.wptr++;
+ qemu_mutex_unlock(&g_vrtr->mutex);
+ qemu_bh_schedule(g_vrtr->bh);
+ LOG_TRACE("[%s] LEAVE\n", __func__);
+}
+
+static void virtio_rotary_bh(void *opaque)
+{
+ VirtIORotary *vrtr = (VirtIORotary *)opaque;
+ MrRotaryEvent *cur_event;
+ uint32_t exec_cnt = 0;
+
+ LOG_TRACE("[%s] ENTER\n", __func__);
+
+ if (!vrtr) {
+ LOG_SEVERE("[%s] VirtIORotary instance is NULL\n", __func__);
+ }
+
+ if (unlikely(!virtio_queue_ready(vrtr->vq))) {
+ LOG_WARNING("[%s] virt queue is not ready\n", __func__);
+ return;
+ }
+
+ if (vrtr->queue.rptr == ROTARY_QUEUE_SIZE) {
+ vrtr->queue.rptr = 0;
+ }
+
+ qemu_mutex_lock(&vrtr->mutex);
+ exec_cnt = vrtr->queue.wptr;
+
+ while (exec_cnt--) {
+ cur_event = &vrtr->queue.event[vrtr->queue.rptr];
+
+ if (((MrRotaryEvent *)(elem.in_sg[vrtr->queue.rptr].iov_base))->delta
+ != 0) {
+ LOG_TRACE("[%s] FIXME: virtio queue is full\n", __func__);
+ }
+
+ memcpy(elem.in_sg[vrtr->queue.rptr].iov_base,
+ cur_event,
+ sizeof(MrRotaryEvent));
+ memset(cur_event, 0x00, sizeof(MrRotaryEvent));
+
+ if (vrtr->queue.wptr > 0) {
+ vrtr->queue.wptr--;
+ LOG_TRACE("[%s] exec_cnt(%u), wptr(%u), rptr(%u)\n",
+ __func__, exec_cnt, vrtr->queue.wptr, vrtr->queue.rptr);
+ }
+
+ vrtr->queue.rptr++;
+ if (vrtr->queue.rptr == ROTARY_QUEUE_SIZE) {
+ vrtr->queue.rptr = 0;
+ }
+ }
+ qemu_mutex_unlock(&vrtr->mutex);
+
+ virtqueue_push(vrtr->vq, &elem, sizeof(MrRotaryEvent));
+ virtio_notify(&vrtr->vdev, vrtr->vq);
+ LOG_TRACE("[%s] LEAVE\n", __func__);
+}
+
+static uint32_t virtio_rotary_get_features(VirtIODevice *vdev,
+ uint32_t request_features)
+{
+ return request_features;
+}
+
+static void virtio_rotary_device_realize(DeviceState *dev, Error **errp)
+{
+ VirtIODevice *vdev = VIRTIO_DEVICE(dev);
+ VirtIORotary *vrtr = VIRTIO_ROTARY(vdev);
+
+ if (!vrtr) {
+ LOG_SEVERE("failed to initialize rotary device\n");
+ return;
+ }
+
+ virtio_init(vdev, TYPE_VIRTIO_ROTARY, VIRTIO_ID_ROTARY, 0);
+ qemu_mutex_init(&vrtr->mutex);
+
+ vrtr->vq = virtio_add_queue(&vrtr->vdev,
+ ROTARY_QUEUE_SIZE,
+ virtio_rotary_handle);
+
+ vrtr->qdev = dev;
+
+ vrtr->bh = qemu_bh_new(virtio_rotary_bh, vrtr);
+
+ g_vrtr = vrtr;
+
+ LOG_INFO("initialize rotary device\n");
+}
+
+static void virtio_rotary_device_unrealize(DeviceState *dev, Error **errp)
+{
+ VirtIODevice *vdev = VIRTIO_DEVICE(dev);
+ VirtIORotary *vrtr = VIRTIO_ROTARY(vdev);
+
+ if (vrtr->bh) {
+ qemu_bh_delete(vrtr->bh);
+ }
+
+ qemu_mutex_destroy(&vrtr->mutex);
+ virtio_cleanup(vdev);
+
+ LOG_INFO("exit rotaty device\n");
+}
+
+static void virtio_rotary_device_reset(VirtIODevice *vdev)
+{
+ VirtIORotary *vrtr = VIRTIO_ROTARY(vdev);
+
+ memset(&vrtr->queue, 0x00, sizeof(VirtIORotaryQueue));
+ LOG_INFO("reset roraty device\n");
+}
+
+static void virtio_rotary_class_init(ObjectClass *klass, void *data)
+{
+ VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(klass);
+ vdc->unrealize = virtio_rotary_device_unrealize;
+ vdc->realize = virtio_rotary_device_realize;
+ vdc->reset = virtio_rotary_device_reset;
+ vdc->get_features = virtio_rotary_get_features;
+}
+
+static const TypeInfo virtio_rotary_info = {
+ .name = TYPE_VIRTIO_ROTARY,
+ .parent = TYPE_VIRTIO_DEVICE,
+ .instance_size = sizeof(VirtIORotary),
+ .class_init = virtio_rotary_class_init,
+};
+
+static void virtio_register_types(void)
+{
+ type_register_static(&virtio_rotary_info);
+}
+
+type_init(virtio_register_types)
--- /dev/null
+/*
+ * Maru Virtio Rotary Device
+ *
+ * Copyright (c) 2014 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Contact:
+ * Jinhyung Jo <jinhyung.jo@samsung.com>
+ * Sangho Park <sangho1206.park@samsung.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ *
+ * Contributors:
+ * - S-Core Co., Ltd
+ *
+ */
+
+
+#ifndef MARU_ROTARY_H_
+#define MARU_ROTARY_H_
+
+#ifdef __cplusplus
+extern "C" {
+#endif
+
+#include "hw/virtio/virtio.h"
+
+/* number of queue must be power of 2 */
+#define ROTARY_QUEUE_SIZE 512
+
+typedef struct MrRotaryEvent {
+ int32_t delta;
+ int32_t type;
+} MrRotaryEvent;
+
+typedef struct VirtIORotaryQueue {
+ uint32_t idx;
+ uint32_t rptr;
+ uint32_t wptr;
+ MrRotaryEvent event[ROTARY_QUEUE_SIZE];
+} VirtIORotaryQueue;
+
+typedef struct VirtIORotary {
+ VirtIODevice vdev;
+ VirtQueue *vq;
+ DeviceState *qdev;
+
+ QEMUBH *bh;
+ QemuMutex mutex;
+ VirtIORotaryQueue queue;
+} VirtIORotary;
+
+#define TYPE_VIRTIO_ROTARY "virtio-rotary-device"
+#define VIRTIO_ROTARY(obj) \
+ OBJECT_CHECK(VirtIORotary, (obj), TYPE_VIRTIO_ROTARY)
+
+void maru_rotary_event(int32_t delta, int32_t type);
+
+#ifdef __cplusplus
+}
+#endif
+
+#endif /* MARU_ROTARY_H_ */