2 * Virtio Keyboard Device
4 * Copyright (c) 2011 - 2013 Samsung Electronics Co., Ltd All Rights Reserved
7 * Kitae Kim <kt920.kim@samsung.com>
8 * GiWoong Kim <giwoong.kim@samsung.com>
9 * SeokYeon Hwang <syeon.hwang@samsung.com>
10 * YeongKyoon Lee <yeongkyoon.lee@samsung.com>
12 * This program is free software; you can redistribute it and/or
13 * modify it under the terms of the GNU General Public License
14 * as published by the Free Software Foundation; either version 2
15 * of the License, or (at your option) any later version.
17 * This program is distributed in the hope that it will be useful,
18 * but WITHOUT ANY WARRANTY; without even the implied warranty of
19 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
20 * GNU General Public License for more details.
22 * You should have received a copy of the GNU General Public License
23 * along with this program; if not, write to the Free Software
24 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
31 #include "maru_device_ids.h"
32 #include "maru_virtio_keyboard.h"
33 #include "tizen/src/debug_ch.h"
36 MULTI_DEBUG_CHANNEL(qemu, virtio-kbd);
38 VirtQueueElement elem;
40 static void virtio_keyboard_handle(VirtIODevice *vdev, VirtQueue *vq)
42 VirtIOKeyboard *vkbd = (VirtIOKeyboard *)vdev;
45 if (virtio_queue_empty(vkbd->vq)) {
46 INFO("virtqueue is empty.\n");
50 /* Get a queue buffer which is written by guest side. */
52 index = virtqueue_pop(vq, &elem);
53 TRACE("virtqueue pop.\n");
54 } while (index < VIRTIO_KBD_QUEUE_SIZE);
57 void virtio_keyboard_notify(void *opaque)
59 VirtIOKeyboard *vkbd = (VirtIOKeyboard *)opaque;
64 ERR("VirtIOKeyboard is NULL.\n");
68 TRACE("[Enter] virtqueue notifier.\n");
70 if (!virtio_queue_ready(vkbd->vq)) {
71 INFO("virtqueue is not ready.\n");
75 if (vkbd->kbdqueue.rptr == VIRTIO_KBD_QUEUE_SIZE) {
76 vkbd->kbdqueue.rptr = 0;
79 qemu_mutex_lock(&vkbd->event_mutex);
80 written_cnt = vkbd->kbdqueue.wptr;
82 while ((written_cnt--)) {
83 kbdevt = &vkbd->kbdqueue.kbdevent[vkbd->kbdqueue.rptr];
84 if (((EmulKbdEvent*)(elem.in_sg[vkbd->kbdqueue.rptr].iov_base))->code != 0) {
85 TRACE("FIXME: virtio queue is full.\n");
88 /* Copy keyboard data into guest side. */
89 TRACE("copy: keycode %d, type %d, elem_index %d\n",
90 kbdevt->code, kbdevt->type, vkbd->kbdqueue.rptr);
91 memcpy(elem.in_sg[vkbd->kbdqueue.rptr].iov_base, kbdevt, sizeof(EmulKbdEvent));
92 memset(kbdevt, 0x00, sizeof(EmulKbdEvent));
94 if (vkbd->kbdqueue.wptr > 0) {
95 vkbd->kbdqueue.wptr--;
96 TRACE("written_cnt: %d, wptr: %d, qemu_index: %d\n", written_cnt, vkbd->kbdqueue.wptr, vkbd->kbdqueue.rptr);
99 vkbd->kbdqueue.rptr++;
100 if (vkbd->kbdqueue.rptr == VIRTIO_KBD_QUEUE_SIZE) {
101 vkbd->kbdqueue.rptr = 0;
104 qemu_mutex_unlock(&vkbd->event_mutex);
106 virtqueue_push(vkbd->vq, &elem, sizeof(EmulKbdEvent));
107 virtio_notify(&vkbd->vdev, vkbd->vq);
109 TRACE("[Leave] virtqueue notifier.\n");
112 static void virtio_keyboard_event(void *opaque, int keycode)
116 VirtIOKeyboard *vkbd = (VirtIOKeyboard *)opaque;
119 ERR("VirtIOKeyboard is NULL.\n");
123 index = &(vkbd->kbdqueue.index);
124 TRACE("[Enter] input_event handler. cnt %d\n", vkbd->kbdqueue.wptr);
127 ERR("keyboard queue is overflow.\n");
131 if (*index == VIRTIO_KBD_QUEUE_SIZE) {
135 if (keycode < 0xe0) {
136 if (vkbd->extension_key) {
137 switch (keycode & 0x7f) {
138 case 28: /* KP_Enter */
141 case 29: /* Right Ctrl */
144 case 56: /* Right Alt */
153 case 73: /* Page Up */
168 case 81: /* Page Down */
171 case 82: /* Insert */
174 case 83: /* Delete */
178 WARN("There is no keymap for this keycode %d.\n", keycode);
180 vkbd->extension_key = 0;
182 kbdevt.code = keycode & 0x7f;
185 if (!(keycode & 0x80)) {
186 kbdevt.type = 1; /* KEY_PRESSED */
188 kbdevt.type = 0; /* KEY_RELEASED */
191 TRACE("Extension key.\n");
192 kbdevt.code = keycode;
193 vkbd->extension_key = 1;
196 qemu_mutex_lock(&vkbd->event_mutex);
197 memcpy(&vkbd->kbdqueue.kbdevent[(*index)++], &kbdevt, sizeof(kbdevt));
198 TRACE("event: keycode %d, type %d, index %d.\n",
199 kbdevt.code, kbdevt.type, ((*index) - 1));
201 vkbd->kbdqueue.wptr++;
202 qemu_mutex_unlock(&vkbd->event_mutex);
204 TRACE("[Leave] input_event handler. cnt:%d\n", vkbd->kbdqueue.wptr);
206 qemu_bh_schedule(vkbd->bh);
209 static uint32_t virtio_keyboard_get_features(VirtIODevice *vdev,
210 uint32_t request_feature)
212 TRACE("virtio_keyboard_get_features.\n");
216 static void virtio_keyboard_bh(void *opaque)
218 virtio_keyboard_notify(opaque);
221 VirtIODevice *virtio_keyboard_init(DeviceState *dev)
223 VirtIOKeyboard *vkbd;
224 INFO("initialize virtio-keyboard device\n");
226 vkbd = (VirtIOKeyboard *)virtio_common_init(VIRTIO_KBD_DEVICE_NAME,
227 VIRTIO_ID_KEYBOARD, 0, sizeof(VirtIOKeyboard));
229 ERR("failed to initialize device\n");
233 memset(&vkbd->kbdqueue, 0x00, sizeof(vkbd->kbdqueue));
234 vkbd->extension_key = 0;
235 qemu_mutex_init(&vkbd->event_mutex);
238 vkbd->vdev.get_features = virtio_keyboard_get_features;
239 vkbd->vq = virtio_add_queue(&vkbd->vdev, 128, virtio_keyboard_handle);
243 vkbd->bh = qemu_bh_new(virtio_keyboard_bh, vkbd);
245 /* register keyboard handler */
246 qemu_add_kbd_event_handler(virtio_keyboard_event, vkbd);
251 void virtio_keyboard_exit(VirtIODevice *vdev)
253 VirtIOKeyboard *vkbd = (VirtIOKeyboard *)vdev;
254 INFO("destroy device\n");
256 qemu_remove_kbd_event_handler();
259 qemu_bh_delete(vkbd->bh);
262 qemu_mutex_destroy(&vkbd->event_mutex);
264 virtio_cleanup(vdev);