2 * Maru Virtio HW Key Device
4 * Copyright (c) 2013 Samsung Electronics Co., Ltd All Rights Reserved
7 * GiWoong Kim <giwoong.kim@samsung.com>
8 * YeongKyoon Lee <yeongkyoon.lee@samsung.com>
10 * This program is free software; you can redistribute it and/or
11 * modify it under the terms of the GNU General Public License
12 * as published by the Free Software Foundation; either version 2
13 * of the License, or (at your option) any later version.
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
31 #include "emul_state.h"
32 #include "maru_virtio_hwkey.h"
33 #include "maru_device_ids.h"
36 MULTI_DEBUG_CHANNEL(qemu, hwkey);
38 #define DEVICE_NAME "virtio-hwkey"
39 #define MAX_BUF_COUNT 64
45 typedef struct HwKeyEventEntry {
49 QTAILQ_ENTRY(HwKeyEventEntry) node;
52 /* the maximum number of HW key event that can be put into a queue */
53 #define MAX_HWKEY_EVENT_CNT 64
55 static HwKeyEventEntry _events_buf[MAX_HWKEY_EVENT_CNT];
56 static QTAILQ_HEAD(, HwKeyEventEntry) events_queue =
57 QTAILQ_HEAD_INITIALIZER(events_queue);
59 static unsigned int event_ringbuf_cnt; /* _events_buf */
60 static unsigned int event_queue_cnt; /* events_queue */
63 * VirtQueueElement queue
65 typedef struct ElementEntry {
66 unsigned int el_index;
67 unsigned int sg_index;
68 VirtQueueElement elem;
70 QTAILQ_ENTRY(ElementEntry) node;
73 static QTAILQ_HEAD(, ElementEntry) elem_queue =
74 QTAILQ_HEAD_INITIALIZER(elem_queue);
76 static unsigned int elem_ringbuf_cnt; /* _elem_buf */
77 static unsigned int elem_queue_cnt; /* elem_queue */
80 VirtQueueElement elem_vhk;
82 /* lock for between communication thread and IO thread */
83 static pthread_mutex_t event_mutex = PTHREAD_MUTEX_INITIALIZER;
85 void maru_hwkey_event(int event_type, int keycode)
87 HwKeyEventEntry *entry = NULL;
89 if (unlikely(event_queue_cnt >= MAX_HWKEY_EVENT_CNT)) {
90 INFO("full hwkey event queue, lose event\n", event_queue_cnt);
92 qemu_bh_schedule(vhk->bh);
96 entry = &(_events_buf[event_ringbuf_cnt % MAX_HWKEY_EVENT_CNT]);
99 /* hwkey event is copied into the queue */
100 entry->hwkey.keycode = keycode;
101 entry->hwkey.event_type = event_type;
103 pthread_mutex_lock(&event_mutex);
105 entry->index = ++event_queue_cnt; // 1 ~
107 QTAILQ_INSERT_TAIL(&events_queue, entry, node);
109 pthread_mutex_unlock(&event_mutex);
111 /* call maru_virtio_hwkey_notify */
112 qemu_bh_schedule(vhk->bh);
114 TRACE("hwkey event (%d) : keycode=%d, event_type=%d\n",
115 entry->index, entry->hwkey.keycode, entry->hwkey.event_type);
118 static void maru_virtio_hwkey_handle(VirtIODevice *vdev, VirtQueue *vq)
120 int virt_sg_index = 0;
122 TRACE("maru_virtio_hwkey_handle\n");
124 if (unlikely(virtio_queue_empty(vhk->vq))) {
125 TRACE("virtqueue is empty\n");
128 /* Get a queue buffer which is written by guest side. */
130 virt_sg_index = virtqueue_pop(vq, &elem_vhk);
131 TRACE("virtqueue pop.\n");
132 } while (virt_sg_index < MAX_BUF_COUNT);
135 void maru_virtio_hwkey_notify(void)
137 HwKeyEventEntry *event_entry = NULL;
139 TRACE("maru_virtio_hwkey_notify\n");
141 if (unlikely(!virtio_queue_ready(vhk->vq))) {
142 ERR("virtio queue is not ready\n");
147 if (event_queue_cnt == 0) {
152 /* get hwkey event from host queue */
153 event_entry = QTAILQ_FIRST(&events_queue);
155 printf("keycode=%d, event_type=%d, event_queue_cnt=%d, vqidx=%d\n",
156 event_entry->hwkey.keycode, event_entry->hwkey.event_type,
157 event_queue_cnt, vqidx);
159 /* copy event into virtio buffer */
160 memcpy(elem_vhk.in_sg[vqidx++].iov_base, &(event_entry->hwkey), sizeof(EmulHWKeyEvent));
161 if (vqidx == MAX_BUF_COUNT) {
165 virtqueue_push(vhk->vq, &elem_vhk, sizeof(EmulHWKeyEvent));
166 virtio_notify(&vhk->vdev, vhk->vq);
168 pthread_mutex_lock(&event_mutex);
170 /* remove host event */
171 QTAILQ_REMOVE(&events_queue, event_entry, node);
174 pthread_mutex_unlock(&event_mutex);
178 static uint32_t virtio_hwkey_get_features(
179 VirtIODevice *vdev, uint32_t request_features)
182 return request_features;
185 static void maru_hwkey_bh(void *opaque)
187 maru_virtio_hwkey_notify();
190 static int virtio_hwkey_device_init(VirtIODevice *vdev)
192 INFO("initialize the hwkey device\n");
193 DeviceState *qdev = DEVICE(vdev);
194 vhk = VIRTIO_HWKEY(vdev);
196 virtio_init(vdev, TYPE_VIRTIO_HWKEY, VIRTIO_ID_HWKEY, 0);
199 ERR("failed to initialize the hwkey device\n");
203 vhk->vq = virtio_add_queue(vdev, MAX_BUF_COUNT, maru_virtio_hwkey_handle);
207 /* reset the counters */
208 event_queue_cnt = event_ringbuf_cnt = 0;
209 elem_queue_cnt = elem_ringbuf_cnt = 0;
212 vhk->bh = qemu_bh_new(maru_hwkey_bh, vhk);
217 static int virtio_hwkey_device_exit(DeviceState *qdev)
219 VirtIODevice *vdev = VIRTIO_DEVICE(qdev);
221 INFO("exit the hwkey device\n");
224 qemu_bh_delete(vhk->bh);
227 virtio_cleanup(vdev);
229 pthread_mutex_destroy(&event_mutex);
234 static void virtio_hwkey_device_reset(VirtIODevice *vdev)
236 INFO("reset hwkey device\n");
240 static void virtio_hwkey_class_init(ObjectClass *klass, void *data)
242 DeviceClass *dc = DEVICE_CLASS(klass);
243 VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(klass);
244 dc->exit = virtio_hwkey_device_exit;
245 vdc->init = virtio_hwkey_device_init;
246 vdc->reset = virtio_hwkey_device_reset;
247 vdc->get_features = virtio_hwkey_get_features;
250 static const TypeInfo virtio_hwkey_info = {
251 .name = TYPE_VIRTIO_HWKEY,
252 .parent = TYPE_VIRTIO_DEVICE,
253 .instance_size = sizeof(VirtIOHWKey),
254 .class_init = virtio_hwkey_class_init,
257 static void virtio_register_types(void)
259 type_register_static(&virtio_hwkey_info);
262 type_init(virtio_register_types)