2 * Maru Virtio Touchscreen Device
4 * Copyright (c) 2011 - 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.
32 #include "maru_virtio_touchscreen.h"
33 #include "maru_device_ids.h"
36 MULTI_DEBUG_CHANNEL(qemu, touchscreen);
39 #define DEVICE_NAME "virtio-touchscreen"
44 typedef struct TouchEventEntry {
48 QTAILQ_ENTRY(TouchEventEntry) node;
51 /* the maximum number of touch event that can be put into a queue */
52 #define MAX_TOUCH_EVENT_CNT 256
54 static TouchEventEntry _events_buf[MAX_TOUCH_EVENT_CNT];
55 static QTAILQ_HEAD(, TouchEventEntry) events_queue =
56 QTAILQ_HEAD_INITIALIZER(events_queue);
58 static unsigned int event_ringbuf_cnt; /* _events_buf */
59 static unsigned int event_queue_cnt; /* events_queue */
62 * VirtQueueElement queue
64 typedef struct ElementEntry {
65 unsigned int el_index;
66 unsigned int sg_index;
67 VirtQueueElement elem;
69 QTAILQ_ENTRY(ElementEntry) node;
72 static ElementEntry _elem_buf[10];
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 */
82 /* lock for between communication thread and IO thread */
83 static pthread_mutex_t event_mutex = PTHREAD_MUTEX_INITIALIZER;
84 static pthread_mutex_t elem_mutex = PTHREAD_MUTEX_INITIALIZER;
87 void virtio_touchscreen_event(void *opaque, int x, int y, int z, int buttons_state)
89 TouchEventEntry *entry = NULL;
91 if (unlikely(event_queue_cnt >= MAX_TOUCH_EVENT_CNT)) {
92 INFO("full touch event queue, lose event\n", event_queue_cnt);
94 qemu_bh_schedule(ts->bh);
98 entry = &(_events_buf[event_ringbuf_cnt % MAX_TOUCH_EVENT_CNT]);
101 /* mouse event is copied into the queue */
105 entry->touch.state = buttons_state;
107 pthread_mutex_lock(&event_mutex);
109 entry->index = ++event_queue_cnt; // 1 ~
111 QTAILQ_INSERT_TAIL(&events_queue, entry, node);
113 pthread_mutex_unlock(&event_mutex);
115 /* call maru_virtio_touchscreen_notify */
116 qemu_bh_schedule(ts->bh);
118 TRACE("touch event (%d) : x=%d, y=%d, z=%d, state=%d\n",
119 entry->index, entry->touch.x, entry->touch.y, entry->touch.z, entry->touch.state);
122 static void maru_virtio_touchscreen_handle(VirtIODevice *vdev, VirtQueue *vq)
124 #if 0 /* not used yet */
125 if (ts->eh_entry == NULL) {
127 VirtQueueElement elem;
130 virtqueue_pop(ts->vq, &elem);
131 vbuf = elem.in_sg[0].iov_base;
132 memcpy(&max_trkid, vbuf, sizeof(max_trkid));
135 INFO("virtio touchscreen's maximum of tracking id = %d\n", max_trkid);
137 /* register a event handler */
138 ts->eh_entry = qemu_add_mouse_event_handler(
139 virtio_touchscreen_event, ts, 1, "QEMU Virtio Touchscreen");
140 qemu_activate_mouse_event_handler(ts->eh_entry);
143 virtqueue_push(ts->vq, &elem, 0);
144 virtio_notify(&(ts->vdev), ts->vq);
146 INFO("virtio touchscreen is not added to qemu mouse event handler\n");
151 int virt_sg_index = 0;
152 ElementEntry *elem_entry = NULL;
154 TRACE("maru_virtio_touchscreen_handle\n");
156 if (unlikely(virtio_queue_empty(ts->vq))) {
157 TRACE("virtqueue is empty\n");
162 elem_entry = &(_elem_buf[elem_ringbuf_cnt % 10]);
165 virt_sg_index = virtqueue_pop(ts->vq, &elem_entry->elem);
166 if (virt_sg_index == 0) {
169 } else if (virt_sg_index < 0) {
170 ERR("virtqueue is broken\n");
175 pthread_mutex_lock(&elem_mutex);
177 elem_entry->el_index = ++elem_queue_cnt;
178 elem_entry->sg_index = (unsigned int)virt_sg_index;
180 /* save VirtQueueElement */
181 QTAILQ_INSERT_TAIL(&elem_queue, elem_entry, node);
183 if (ts->waitBuf == true) {
186 /* call maru_virtio_touchscreen_notify */
187 qemu_bh_schedule(ts->bh);
190 pthread_mutex_unlock(&elem_mutex);
194 void maru_virtio_touchscreen_notify(void)
196 ElementEntry *elem_entry = NULL;
199 TRACE("maru_virtio_touchscreen_notify\n");
201 if (unlikely(!virtio_queue_ready(ts->vq))) {
202 ERR("virtio queue is not ready\n");
207 if (event_queue_cnt == 0) {
210 } else if (elem_queue_cnt == 0) {
211 TRACE("no buffer\n");
213 pthread_mutex_lock(&elem_mutex);
214 /* maybe next time */
216 pthread_mutex_unlock(&elem_mutex);
220 elem_entry = QTAILQ_FIRST(&elem_queue);
222 if (elem_entry->sg_index > 0) {
223 TouchEventEntry *event_entry = NULL;
224 VirtQueueElement *element = NULL;
227 element = &elem_entry->elem;
228 vbuf = element->in_sg[elem_entry->sg_index - 1].iov_base;
230 /* get touch event from host queue */
231 event_entry = QTAILQ_FIRST(&events_queue);
233 TRACE("touch(%d) : x=%d, y=%d, z=%d, state=%d | \
234 event_queue_cnt=%d, elem.index=%d, elem.in_num=%d, sg_index=%d\n",
235 event_entry->index, event_entry->touch.x, event_entry->touch.y,
236 event_entry->touch.z, event_entry->touch.state,
237 event_queue_cnt, element->index, element->in_num,
238 elem_entry->sg_index);
240 /* copy event into virtio buffer */
241 memcpy(vbuf, &(event_entry->touch), sizeof(event_entry->touch));
243 pthread_mutex_lock(&event_mutex);
245 /* remove host event */
246 QTAILQ_REMOVE(&events_queue, event_entry, node);
249 pthread_mutex_unlock(&event_mutex);
251 /* put buffer into virtio queue */
252 virtqueue_fill(ts->vq, element, sizeof(EmulTouchEvent), ii++);
255 pthread_mutex_lock(&elem_mutex);
257 QTAILQ_REMOVE(&elem_queue, elem_entry, node);
260 pthread_mutex_unlock(&elem_mutex);
264 /* signal other side */
265 virtqueue_flush(ts->vq, ii);
266 /* notify to guest */
267 virtio_notify(&(ts->vdev), ts->vq);
271 static uint32_t virtio_touchscreen_get_features(
272 VirtIODevice *vdev, uint32_t request_features)
275 return request_features;
278 static void maru_touchscreen_bh(void *opaque)
280 //TouchscreenState *ts = (TouchscreenState *)opaque;
282 maru_virtio_touchscreen_notify();
285 VirtIODevice *maru_virtio_touchscreen_init(DeviceState *dev)
287 INFO("initialize the touchscreen device\n");
289 ts = (TouchscreenState *)virtio_common_init(DEVICE_NAME,
290 VIRTIO_ID_TOUCHSCREEN, 0 /*config_size*/, sizeof(TouchscreenState));
293 ERR("failed to initialize the touchscreen device\n");
297 ts->vdev.get_features = virtio_touchscreen_get_features;
298 ts->vq = virtio_add_queue(&ts->vdev, 64, maru_virtio_touchscreen_handle);
302 /* reset the counters */
303 event_queue_cnt = event_ringbuf_cnt = 0;
304 elem_queue_cnt = elem_ringbuf_cnt = 0;
309 ts->bh = qemu_bh_new(maru_touchscreen_bh, ts);
312 /* register a event handler */
313 ts->eh_entry = qemu_add_mouse_event_handler(
314 virtio_touchscreen_event, ts, 1, "QEMU Virtio Touchscreen");
315 qemu_activate_mouse_event_handler(ts->eh_entry);
316 INFO("virtio touchscreen is added to qemu mouse event handler\n");
322 void maru_virtio_touchscreen_exit(VirtIODevice *vdev)
324 INFO("exit the touchscreen device\n");
327 qemu_remove_mouse_event_handler(ts->eh_entry);
331 qemu_bh_delete(ts->bh);
334 virtio_cleanup(vdev);
336 pthread_mutex_destroy(&event_mutex);
337 pthread_mutex_destroy(&elem_mutex);