sync with tizen_2.2
[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         if (((EmulKbdEvent*)(elem.in_sg[vkbd->kbdqueue.rptr].iov_base))->code != 0) {
85             TRACE("FIXME: virtio queue is full.\n");
86         }
87
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));
93
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);
97         }
98
99         vkbd->kbdqueue.rptr++;
100         if (vkbd->kbdqueue.rptr == VIRTIO_KBD_QUEUE_SIZE) {
101             vkbd->kbdqueue.rptr = 0;
102         }
103     }
104     qemu_mutex_unlock(&vkbd->event_mutex);
105
106     virtqueue_push(vkbd->vq, &elem, sizeof(EmulKbdEvent));
107     virtio_notify(&vkbd->vdev, vkbd->vq);
108
109     TRACE("[Leave] virtqueue notifier.\n");
110 }
111
112 static void virtio_keyboard_event(void *opaque, int keycode)
113 {
114     EmulKbdEvent kbdevt;
115     int *index = NULL;
116     VirtIOKeyboard *vkbd = (VirtIOKeyboard *)opaque;
117
118     if (!vkbd) {
119         ERR("VirtIOKeyboard is NULL.\n");
120         return;
121     }
122
123     index = &(vkbd->kbdqueue.index);
124     TRACE("[Enter] input_event handler. cnt %d\n", vkbd->kbdqueue.wptr);
125
126     if (*index < 0) {
127         ERR("keyboard queue is overflow.\n");
128         return;
129     }
130
131     if (*index == VIRTIO_KBD_QUEUE_SIZE) {
132         *index = 0;
133     }
134
135     if (keycode < 0xe0) {
136         if (vkbd->extension_key) {
137             switch (keycode & 0x7f) {
138             case 28:    /* KP_Enter */
139                 kbdevt.code = 96;
140                 break;
141             case 29:    /* Right Ctrl */
142                 kbdevt.code = 97;
143                 break;
144             case 56:    /* Right Alt */
145                 kbdevt.code = 100;
146                 break;
147             case 71:    /* Home */
148                 kbdevt.code = 102;
149                 break;
150             case 72:    /* Up */
151                 kbdevt.code = 103;
152                 break;
153             case 73:    /* Page Up */
154                 kbdevt.code = 104;
155                 break;
156             case 75:    /* Left */
157                 kbdevt.code = 105;
158                 break;
159             case 77:    /* Right */
160                 kbdevt.code = 106;
161                 break;
162             case 79:    /* End */
163                 kbdevt.code = 107;
164                 break;
165             case 80:    /* Down */
166                 kbdevt.code = 108;
167                 break;
168             case 81:    /* Page Down */
169                 kbdevt.code = 109;
170                 break;
171             case 82:    /* Insert */
172                 kbdevt.code = 110;
173                 break;
174             case 83:    /* Delete */
175                 kbdevt.code = 111;
176                 break;
177             default:
178                 WARN("There is no keymap for this keycode %d.\n", keycode);
179             }
180             vkbd->extension_key = 0;
181         } else {
182             kbdevt.code = keycode & 0x7f;
183         }
184
185         if (!(keycode & 0x80)) {
186             kbdevt.type = 1;    /* KEY_PRESSED */
187         } else {
188             kbdevt.type = 0;    /* KEY_RELEASED */
189         }
190     } else {
191         TRACE("Extension key.\n");
192         kbdevt.code = keycode;
193         vkbd->extension_key = 1;
194     }
195
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));
200
201     vkbd->kbdqueue.wptr++;
202     qemu_mutex_unlock(&vkbd->event_mutex);
203
204     TRACE("[Leave] input_event handler. cnt:%d\n", vkbd->kbdqueue.wptr);
205
206     qemu_bh_schedule(vkbd->bh);
207 }
208
209 static uint32_t virtio_keyboard_get_features(VirtIODevice *vdev,
210                                             uint32_t request_feature)
211 {
212     TRACE("virtio_keyboard_get_features.\n");
213     return 0;
214 }
215
216 static void virtio_keyboard_bh(void *opaque)
217 {
218     virtio_keyboard_notify(opaque);
219 }
220
221 VirtIODevice *virtio_keyboard_init(DeviceState *dev)
222 {
223     VirtIOKeyboard *vkbd;
224     INFO("initialize virtio-keyboard device\n");
225
226     vkbd = (VirtIOKeyboard *)virtio_common_init(VIRTIO_KBD_DEVICE_NAME,
227             VIRTIO_ID_KEYBOARD, 0, sizeof(VirtIOKeyboard));
228     if (vkbd == NULL) {
229         ERR("failed to initialize device\n");
230         return NULL;
231     }
232
233     memset(&vkbd->kbdqueue, 0x00, sizeof(vkbd->kbdqueue));
234     vkbd->extension_key = 0;
235     qemu_mutex_init(&vkbd->event_mutex);
236
237
238     vkbd->vdev.get_features = virtio_keyboard_get_features;
239     vkbd->vq = virtio_add_queue(&vkbd->vdev, 128, virtio_keyboard_handle);
240     vkbd->qdev = dev;
241
242     /* bottom half */
243     vkbd->bh = qemu_bh_new(virtio_keyboard_bh, vkbd);
244
245     /* register keyboard handler */
246     qemu_add_kbd_event_handler(virtio_keyboard_event, vkbd);
247  
248     return &vkbd->vdev;
249 }
250
251 void virtio_keyboard_exit(VirtIODevice *vdev)
252 {
253     VirtIOKeyboard *vkbd = (VirtIOKeyboard *)vdev;
254     INFO("destroy device\n");
255
256     qemu_remove_kbd_event_handler();
257
258     if (vkbd->bh) {
259         qemu_bh_delete(vkbd->bh);
260     }
261
262     qemu_mutex_destroy(&vkbd->event_mutex);
263
264     virtio_cleanup(vdev);
265 }