9c367709352b7fc98aebc8aa4c037da5411392cf
[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 index = 0;
62     int written_cnt = 0;
63
64     if (!vkbd) {
65         ERR("VirtIOKeyboard is NULL.\n");
66         return;
67     }
68
69     TRACE("[Enter] virtqueue notifier.\n");
70
71     if (!virtio_queue_ready(vkbd->vq)) {
72         INFO("virtqueue is not ready.\n");
73         return;
74     }
75
76     if (vkbd->kbdqueue.rptr == VIRTIO_KBD_QUEUE_SIZE) {
77         vkbd->kbdqueue.rptr = 0;
78     }
79
80     qemu_mutex_lock(&vkbd->event_mutex);
81     written_cnt = vkbd->kbdqueue.wptr;
82
83     while ((written_cnt--)) {
84         kbdevt = &vkbd->kbdqueue.kbdevent[vkbd->kbdqueue.rptr];
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 VirtIODevice *virtio_keyboard_init(DeviceState *dev)
223 {
224     VirtIOKeyboard *vkbd;
225     INFO("initialize virtio-keyboard device\n");
226
227     vkbd = (VirtIOKeyboard *)virtio_common_init(VIRTIO_KBD_DEVICE_NAME,
228             VIRTIO_ID_KEYBOARD, 0, sizeof(VirtIOKeyboard));
229     if (vkbd == NULL) {
230         ERR("failed to initialize device\n");
231         return NULL;
232     }
233
234     memset(&vkbd->kbdqueue, 0x00, sizeof(vkbd->kbdqueue));
235     vkbd->extension_key = 0;
236     qemu_mutex_init(&vkbd->event_mutex);
237
238
239     vkbd->vdev.get_features = virtio_keyboard_get_features;
240     vkbd->vq = virtio_add_queue(&vkbd->vdev, 128, virtio_keyboard_handle);
241     vkbd->qdev = dev;
242
243     /* bottom half */
244     vkbd->bh = qemu_bh_new(virtio_keyboard_bh, vkbd);
245
246     /* register keyboard handler */
247     qemu_add_kbd_event_handler(virtio_keyboard_event, vkbd);
248  
249     return &vkbd->vdev;
250 }
251
252 void virtio_keyboard_exit(VirtIODevice *vdev)
253 {
254     VirtIOKeyboard *vkbd = (VirtIOKeyboard *)vdev;
255     INFO("destroy device\n");
256
257     qemu_remove_kbd_event_handler();
258
259     if (vkbd->bh) {
260         qemu_bh_delete(vkbd->bh);
261     }
262
263     qemu_mutex_destroy(&vkbd->event_mutex);
264
265     virtio_cleanup(vdev);
266 }