5e77a65cae1687e7c1d5e6c5c12821ce9b7ef9a9
[sdk/emulator/qemu.git] / tizen / src / hw / maru_virtio_keyboard.c
1 /*
2  * Virtio Keyboard Device
3  *
4  * Copyright (c) 2011 - 2013 Samsung Electronics Co., Ltd All Rights Reserved
5  *
6  * Contact:
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>
11  *
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.
16  *
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.
21  *
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.
25  *
26  * Contributors:
27  * - S-Core Co., Ltd
28  *
29  */
30
31 #include "maru_device_ids.h"
32 #include "maru_virtio_keyboard.h"
33 #include "tizen/src/debug_ch.h"
34
35
36 MULTI_DEBUG_CHANNEL(qemu, virtio-kbd);
37
38 VirtQueueElement elem;
39
40 static void virtio_keyboard_handle(VirtIODevice *vdev, VirtQueue *vq)
41 {
42     VirtIOKeyboard *vkbd = (VirtIOKeyboard *)vdev;
43     int index = 0;
44
45     if (virtio_queue_empty(vkbd->vq)) {
46         INFO("virtqueue is empty.\n");
47         return;
48     }
49
50     /* Get a queue buffer which is written by guest side. */
51     do {
52         index = virtqueue_pop(vq, &elem);
53         TRACE("virtqueue pop.\n");
54     } while (index < VIRTIO_KBD_QUEUE_SIZE);
55 }
56
57 void virtio_keyboard_notify(void *opaque)
58 {
59     VirtIOKeyboard *vkbd = (VirtIOKeyboard *)opaque;
60     EmulKbdEvent *kbdevt;
61     int written_cnt = 0;
62
63     if (!vkbd) {
64         ERR("VirtIOKeyboard is NULL.\n");
65         return;
66     }
67
68     TRACE("[Enter] virtqueue notifier.\n");
69
70     if (!virtio_queue_ready(vkbd->vq)) {
71         INFO("virtqueue is not ready.\n");
72         return;
73     }
74
75     if (vkbd->kbdqueue.rptr == VIRTIO_KBD_QUEUE_SIZE) {
76         vkbd->kbdqueue.rptr = 0;
77     }
78
79     qemu_mutex_lock(&vkbd->event_mutex);
80     written_cnt = vkbd->kbdqueue.wptr;
81
82     while ((written_cnt--)) {
83         kbdevt = &vkbd->kbdqueue.kbdevent[vkbd->kbdqueue.rptr];
84
85         if (((EmulKbdEvent*)(elem.in_sg[vkbd->kbdqueue.rptr].iov_base))->code != 0) {
86             TRACE("FIXME: virtio queue is full.\n");
87         }
88
89         /* Copy keyboard data into guest side. */
90         TRACE("copy: keycode %d, type %d, elem_index %d\n",
91             kbdevt->code, kbdevt->type, vkbd->kbdqueue.rptr);
92         memcpy(elem.in_sg[vkbd->kbdqueue.rptr].iov_base, kbdevt, sizeof(EmulKbdEvent));
93         memset(kbdevt, 0x00, sizeof(EmulKbdEvent));
94
95         if (vkbd->kbdqueue.wptr > 0) {
96             vkbd->kbdqueue.wptr--;
97             TRACE("written_cnt: %d, wptr: %d, qemu_index: %d\n", written_cnt, vkbd->kbdqueue.wptr, vkbd->kbdqueue.rptr);
98         }
99
100         vkbd->kbdqueue.rptr++;
101         if (vkbd->kbdqueue.rptr == VIRTIO_KBD_QUEUE_SIZE) {
102             vkbd->kbdqueue.rptr = 0;
103         }
104     }
105     qemu_mutex_unlock(&vkbd->event_mutex);
106
107     virtqueue_push(vkbd->vq, &elem, sizeof(EmulKbdEvent));
108     virtio_notify(&vkbd->vdev, vkbd->vq);
109
110     TRACE("[Leave] virtqueue notifier.\n");
111 }
112
113 static void virtio_keyboard_event(void *opaque, int keycode)
114 {
115     EmulKbdEvent kbdevt;
116     int *index = NULL;
117     VirtIOKeyboard *vkbd = (VirtIOKeyboard *)opaque;
118
119     if (!vkbd) {
120         ERR("VirtIOKeyboard is NULL.\n");
121         return;
122     }
123
124     index = &(vkbd->kbdqueue.index);
125     TRACE("[Enter] input_event handler. cnt %d\n", vkbd->kbdqueue.wptr);
126
127     if (*index < 0) {
128         ERR("keyboard queue is overflow.\n");
129         return;
130     }
131
132     if (*index == VIRTIO_KBD_QUEUE_SIZE) {
133         *index = 0;
134     }
135
136     if (keycode < 0xe0) {
137         if (vkbd->extension_key) {
138             switch (keycode & 0x7f) {
139             case 28:    /* KP_Enter */
140                 kbdevt.code = 96;
141                 break;
142             case 29:    /* Right Ctrl */
143                 kbdevt.code = 97;
144                 break;
145             case 56:    /* Right Alt */
146                 kbdevt.code = 100;
147                 break;
148             case 71:    /* Home */
149                 kbdevt.code = 102;
150                 break;
151             case 72:    /* Up */
152                 kbdevt.code = 103;
153                 break;
154             case 73:    /* Page Up */
155                 kbdevt.code = 104;
156                 break;
157             case 75:    /* Left */
158                 kbdevt.code = 105;
159                 break;
160             case 77:    /* Right */
161                 kbdevt.code = 106;
162                 break;
163             case 79:    /* End */
164                 kbdevt.code = 107;
165                 break;
166             case 80:    /* Down */
167                 kbdevt.code = 108;
168                 break;
169             case 81:    /* Page Down */
170                 kbdevt.code = 109;
171                 break;
172             case 82:    /* Insert */
173                 kbdevt.code = 110;
174                 break;
175             case 83:    /* Delete */
176                 kbdevt.code = 111;
177                 break;
178             default:
179                 WARN("There is no keymap for this keycode %d.\n", keycode);
180             }
181             vkbd->extension_key = 0;
182         } else {
183             kbdevt.code = keycode & 0x7f;
184         }
185
186         if (!(keycode & 0x80)) {
187             kbdevt.type = 1;    /* KEY_PRESSED */
188         } else {
189             kbdevt.type = 0;    /* KEY_RELEASED */
190         }
191     } else {
192         TRACE("Extension key.\n");
193         kbdevt.code = keycode;
194         vkbd->extension_key = 1;
195     }
196
197     qemu_mutex_lock(&vkbd->event_mutex);
198     memcpy(&vkbd->kbdqueue.kbdevent[(*index)++], &kbdevt, sizeof(kbdevt));
199     TRACE("event: keycode %d, type %d, index %d.\n",
200         kbdevt.code, kbdevt.type, ((*index) - 1));
201
202     vkbd->kbdqueue.wptr++;
203     qemu_mutex_unlock(&vkbd->event_mutex);
204
205     TRACE("[Leave] input_event handler. cnt:%d\n", vkbd->kbdqueue.wptr);
206
207     qemu_bh_schedule(vkbd->bh);
208 }
209
210 static uint32_t virtio_keyboard_get_features(VirtIODevice *vdev,
211                                             uint32_t request_feature)
212 {
213     TRACE("virtio_keyboard_get_features.\n");
214     return 0;
215 }
216
217 static void virtio_keyboard_bh(void *opaque)
218 {
219     virtio_keyboard_notify(opaque);
220 }
221
222 static int virtio_keyboard_device_init(VirtIODevice *vdev)
223 {
224     VirtIOKeyboard *vkbd;
225     DeviceState *qdev = DEVICE(vdev);
226     vkbd = VIRTIO_KEYBOARD(vdev);
227
228     INFO("initialize virtio-keyboard device\n");
229     virtio_init(vdev, TYPE_VIRTIO_KEYBOARD, VIRTIO_ID_KEYBOARD, 0);
230
231     if (vdev == NULL) {
232         ERR("failed to initialize device\n");
233         return -1;
234     }
235
236     memset(&vkbd->kbdqueue, 0x00, sizeof(vkbd->kbdqueue));
237     vkbd->extension_key = 0;
238     qemu_mutex_init(&vkbd->event_mutex);
239
240     vkbd->vq = virtio_add_queue(vdev, 128, virtio_keyboard_handle);
241     vkbd->qdev = qdev;
242
243     /* bottom half */
244     vkbd->bh = qemu_bh_new(virtio_keyboard_bh, vkbd);
245
246     /* register keyboard handler */
247     vkbd->eh_entry = qemu_add_kbd_event_handler(virtio_keyboard_event, vkbd);
248  
249     return 0;
250 }
251
252 static int virtio_keyboard_device_exit(DeviceState *qdev)
253 {
254     VirtIODevice *vdev = VIRTIO_DEVICE(qdev);
255     VirtIOKeyboard *vkbd = (VirtIOKeyboard *)vdev;
256
257     INFO("destroy device\n");
258
259     qemu_remove_kbd_event_handler(vkbd->eh_entry);
260
261     if (vkbd->bh) {
262         qemu_bh_delete(vkbd->bh);
263     }
264
265     qemu_mutex_destroy(&vkbd->event_mutex);
266
267     virtio_cleanup(vdev);
268
269     return 0;
270 }
271
272 static void virtio_keyboard_class_init(ObjectClass *klass, void *data)
273 {
274     DeviceClass *dc = DEVICE_CLASS(klass);
275     VirtioDeviceClass *vdc = VIRTIO_DEVICE_CLASS(klass);
276     dc->exit = virtio_keyboard_device_exit;
277     vdc->init = virtio_keyboard_device_init;
278     vdc->get_features = virtio_keyboard_get_features;
279 }
280
281 static const TypeInfo virtio_keyboard_info = {
282     .name = TYPE_VIRTIO_KEYBOARD,
283     .parent = TYPE_VIRTIO_DEVICE,
284     .instance_size = sizeof(VirtIOKeyboard),
285     .class_init = virtio_keyboard_class_init,
286 };
287
288 static void virtio_register_types(void)
289 {
290     type_register_static(&virtio_keyboard_info);
291 }
292
293 type_init(virtio_register_types)
294