virtio_esm_exit(proxy->vdev);
virtio_exit_pci(pci_dev);
}
+
+static int virtio_hwkey_init_pci(PCIDevice *pci_dev)
+{
+ VirtIOPCIProxy *proxy = DO_UPCAST(VirtIOPCIProxy, pci_dev, pci_dev);
+ VirtIODevice *vdev;
+
+ vdev = maru_virtio_hwkey_init(&pci_dev->qdev);
+ if (!vdev) {
+ return -1;
+ }
+ virtio_init_pci(proxy, vdev);
+ return 0;
+}
+
+static void virtio_hwkey_exit_pci(PCIDevice *pci_dev)
+{
+ VirtIOPCIProxy *proxy = DO_UPCAST(VirtIOPCIProxy, pci_dev, pci_dev);
+
+ virtio_pci_stop_ioeventfd(proxy);
+ maru_virtio_hwkey_exit(proxy->vdev);
+ virtio_exit_pci(pci_dev);
+}
+
#endif
static Property virtio_blk_properties[] = {
.instance_size = sizeof(VirtIOPCIProxy),
.class_init = virtio_esm_class_init,
};
+
+static void virtio_hwkey_class_init(ObjectClass *klass, void *data)
+{
+ DeviceClass *dc = DEVICE_CLASS(klass);
+ PCIDeviceClass *k = PCI_DEVICE_CLASS(klass);
+
+ k->init = virtio_hwkey_init_pci;
+ k->exit = virtio_hwkey_exit_pci;
+ k->vendor_id = PCI_VENDOR_ID_REDHAT_QUMRANET;
+ k->device_id = PCI_DEVICE_ID_VIRTIO_HWKEY;
+ k->revision = VIRTIO_PCI_ABI_VERSION;
+ k->class_id = PCI_CLASS_OTHERS;
+ dc->reset = virtio_pci_reset;
+}
+
+static TypeInfo virtio_hwkey_info = {
+ .name = "virtio-hwkey-pci",
+ .parent = TYPE_PCI_DEVICE,
+ .instance_size = sizeof(VirtIOPCIProxy),
+ .class_init = virtio_hwkey_class_init,
+};
+
#endif /* CONFIG_MARU */
static void virtio_pci_register_types(void)
type_register_static(&maru_virtio_touchscreen_info);
type_register_static(&virtio_keyboard_info);
type_register_static(&virtio_esm_info);
+ type_register_static(&virtio_hwkey_info);
#endif
}
--- /dev/null
+/*
+ * Maru Virtio HW Key Device
+ *
+ * Copyright (c) 2013 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Contact:
+ * GiWoong Kim <giwoong.kim@samsung.com>
+ * YeongKyoon Lee <yeongkyoon.lee@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 <pthread.h>
+#include "console.h"
+#include "emul_state.h"
+#include "maru_virtio_hwkey.h"
+#include "maru_device_ids.h"
+#include "debug_ch.h"
+
+MULTI_DEBUG_CHANNEL(qemu, hwkey);
+
+
+#define DEVICE_NAME "virtio-hwkey"
+
+/*
+ * HW key event queue
+ */
+typedef struct HwKeyEventEntry {
+ unsigned int index;
+ EmulHwKeyEvent hwkey;
+
+ QTAILQ_ENTRY(HwKeyEventEntry) node;
+} HwKeyEventEntry;
+
+/* the maximum number of HW key event that can be put into a queue */
+#define MAX_HWKEY_EVENT_CNT 64
+
+static HwKeyEventEntry _events_buf[MAX_HWKEY_EVENT_CNT];
+static QTAILQ_HEAD(, HwKeyEventEntry) events_queue =
+ QTAILQ_HEAD_INITIALIZER(events_queue);
+
+static unsigned int event_ringbuf_cnt; /* _events_buf */
+static unsigned int event_queue_cnt; /* events_queue */
+
+VirtIOHwKey *vhk;
+
+/* lock for between communication thread and IO thread */
+static pthread_mutex_t event_mutex = PTHREAD_MUTEX_INITIALIZER;
+
+
+void maru_hwkey_event(int event_type, int keycode)
+{
+ HwKeyEventEntry *entry = NULL;
+
+ if (unlikely(event_queue_cnt >= MAX_HWKEY_EVENT_CNT)) {
+ INFO("full hwkey event queue, lose event\n", event_queue_cnt);
+
+ qemu_bh_schedule(vhk->bh);
+ return;
+ }
+
+ entry = &(_events_buf[event_ringbuf_cnt % MAX_HWKEY_EVENT_CNT]);
+ event_ringbuf_cnt++;
+
+ /* hwkey event is copied into the queue */
+ entry->hwkey.keycode = keycode;
+ entry->hwkey.event_type = event_type;
+
+ pthread_mutex_lock(&event_mutex);
+
+ entry->index = ++event_queue_cnt; // 1 ~
+
+ QTAILQ_INSERT_TAIL(&events_queue, entry, node);
+
+ pthread_mutex_unlock(&event_mutex);
+
+ /* call maru_virtio_hwkey_notify */
+ qemu_bh_schedule(vhk->bh);
+
+ TRACE("hwkey event (%d) : keycode=%d, event_type=%d\n",
+ entry->index, entry->hwkey.keycode, entry->hwkey.event_type);
+}
+
+void maru_virtio_hwkey_notify(void)
+{
+ HwKeyEventEntry *event_entry = NULL;
+
+ TRACE("maru_virtio_hwkey_notify\n");
+
+ while (true) {
+ if (event_queue_cnt == 0) {
+ TRACE("no event\n");
+ break;
+ }
+
+ /* get touch event from host queue */
+ event_entry = QTAILQ_FIRST(&events_queue);
+
+ TRACE("hwkey(%d) : keycode=%d, event_type=%d | \
+ event_queue_cnt=%d\n",
+ event_entry->index,
+ event_entry->hwkey.keycode, event_entry->hwkey.event_type,
+ event_queue_cnt);
+
+ /* copy event into virtio buffer */
+ //memcpy(vbuf, &(event_entry->touch), sizeof(event_entry->touch));
+ /* TODO: */
+ if (KEY_PRESSED == event_entry->hwkey.event_type) {
+ ps2kbd_put_keycode(event_entry->hwkey.keycode & 0x7f);
+ } else if (KEY_RELEASED == event_entry->hwkey.event_type) {
+ ps2kbd_put_keycode(event_entry->hwkey.keycode | 0x80);
+ } else {
+ ERR("Unknown hwkey event type : keycode=%d, event_type=%d\n",
+ event_entry->hwkey.keycode, event_entry->hwkey.event_type);
+ }
+
+ pthread_mutex_lock(&event_mutex);
+
+ /* remove host event */
+ QTAILQ_REMOVE(&events_queue, event_entry, node);
+ event_queue_cnt--;
+
+ pthread_mutex_unlock(&event_mutex);
+ }
+}
+
+static uint32_t virtio_hwkey_get_features(
+ VirtIODevice *vdev, uint32_t request_features)
+{
+ // TODO:
+ return request_features;
+}
+
+static void maru_hwkey_bh(void *opaque)
+{
+ maru_virtio_hwkey_notify();
+}
+
+VirtIODevice *maru_virtio_hwkey_init(DeviceState *dev)
+{
+ INFO("initialize the hwkey device\n");
+
+ vhk = (VirtIOHwKey *)virtio_common_init(DEVICE_NAME,
+ VIRTIO_ID_HWKEY, 0 /*config_size*/, sizeof(VirtIOHwKey));
+
+ if (vhk == NULL) {
+ ERR("failed to initialize the hwkey device\n");
+ return NULL;
+ }
+
+ vhk->vdev.get_features = virtio_hwkey_get_features;
+ vhk->qdev = dev;
+
+ /* bottom-half */
+ vhk->bh = qemu_bh_new(maru_hwkey_bh, vhk);
+
+ return &(vhk->vdev);
+}
+
+void maru_virtio_hwkey_exit(VirtIODevice *vdev)
+{
+ VirtIOHwKey *vhk = (VirtIOHwKey *)vdev;
+
+ INFO("exit the hwkey device\n");
+
+ if (vhk->bh) {
+ qemu_bh_delete(vhk->bh);
+ }
+
+ virtio_cleanup(vdev);
+
+ pthread_mutex_destroy(&event_mutex);
+}
+
--- /dev/null
+/*
+ * Maru Virtio HW Key Device
+ *
+ * Copyright (c) 2013 Samsung Electronics Co., Ltd All Rights Reserved
+ *
+ * Contact:
+ * GiWoong Kim <giwoong.kim@samsung.com>
+ * YeongKyoon Lee <yeongkyoon.lee@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_HWKEY_H_
+#define MARU_HWKEY_H_
+
+#include "console.h"
+#include "hw/virtio.h"
+
+typedef struct VirtIOHwKey
+{
+ VirtIODevice vdev;
+ /* simply a queue into which buffers are posted
+ by the guest for consumption by the host */
+ VirtQueue *vq;
+
+ QEMUBH *bh;
+ DeviceState *qdev;
+} VirtIOHwKey;
+
+/* This structure must match the kernel definitions */
+typedef struct EmulHwKeyEvent {
+ uint8_t event_type;
+ uint32_t keycode;
+} EmulHwKeyEvent;
+
+
+VirtIODevice *maru_virtio_hwkey_init(DeviceState *dev);
+void maru_virtio_hwkey_exit(VirtIODevice *vdev);
+
+void maru_hwkey_event(int event_type, int keycode);
+void maru_virtio_hwkey_notify(void);
+
+#endif /* MARU_HWKEY_H_ */