ia64/xen-unstable

view tools/ioemu/hw/xenfb.c @ 17170:be143a3a90c6

ioemu: fix xenfb slow case update by shifting to the left before
masking low bits instead of shifting to the right and masking high
bits. Also adds 24bpp support.

Signed-off-by: Samuel Thibault <samuel.thibault@eu.citrix.com>
author Keir Fraser <keir.fraser@citrix.com>
date Mon Mar 03 11:05:18 2008 +0000 (2008-03-03)
parents bf63d055d30c
children 38bbaa69c065
line source
1 #include <stdarg.h>
2 #include <stdlib.h>
3 #include <sys/types.h>
4 #include <fcntl.h>
5 #include <unistd.h>
6 #include <xenctrl.h>
7 #include <xen/io/xenbus.h>
8 #include <xen/io/fbif.h>
9 #include <xen/io/kbdif.h>
10 #include <xen/io/protocols.h>
11 #include <stdbool.h>
12 #include <xen/event_channel.h>
13 #include <sys/mman.h>
14 #include <errno.h>
15 #include <stdio.h>
16 #include <string.h>
17 #include <time.h>
18 #include <xs.h>
20 #include "xenfb.h"
22 #ifdef CONFIG_STUBDOM
23 #include <semaphore.h>
24 #include <sched.h>
25 #include <fbfront.h>
26 #endif
28 #ifndef BTN_LEFT
29 #define BTN_LEFT 0x110 /* from <linux/input.h> */
30 #endif
32 // FIXME defend against malicious frontend?
34 struct xenfb;
36 struct xenfb_device {
37 const char *devicetype;
38 char nodename[64]; /* backend xenstore dir */
39 char otherend[64]; /* frontend xenstore dir */
40 int otherend_id; /* frontend domid */
41 enum xenbus_state state; /* backend state */
42 void *page; /* shared page */
43 evtchn_port_t port;
44 struct xenfb *xenfb;
45 };
47 struct xenfb {
48 DisplayState *ds; /* QEMU graphical console state */
49 int evt_xch; /* event channel driver handle */
50 int xc; /* hypervisor interface handle */
51 struct xs_handle *xsh; /* xs daemon handle */
52 struct xenfb_device fb, kbd;
53 void *pixels; /* guest framebuffer data */
54 size_t fb_len; /* size of framebuffer */
55 int row_stride; /* width of one row in framebuffer */
56 int depth; /* colour depth of guest framebuffer */
57 int width; /* pixel width of guest framebuffer */
58 int height; /* pixel height of guest framebuffer */
59 int abs_pointer_wanted; /* Whether guest supports absolute pointer */
60 int button_state; /* Last seen pointer button state */
61 char protocol[64]; /* frontend protocol */
62 };
64 /* Functions for frontend/backend state machine*/
65 static int xenfb_wait_for_frontend(struct xenfb_device *dev, IOHandler *handler);
66 static int xenfb_wait_for_backend(struct xenfb_device *dev, IOHandler *handler);
67 static void xenfb_backend_created_kbd(void *opaque);
68 static void xenfb_backend_created_fb(void *opaque);
69 static void xenfb_frontend_initialized_kbd(void *opaque);
70 static void xenfb_frontend_initialized_fb(void *opaque);
71 static void xenfb_frontend_connected_kbd(void *opaque);
73 /* Helper functions for checking state of frontend/backend devices */
74 static int xenfb_frontend_connected(struct xenfb_device *dev);
75 static int xenfb_frontend_initialized(struct xenfb_device *dev);
76 static int xenfb_backend_created(struct xenfb_device *dev);
78 /* Functions which tie the PVFB into the QEMU device model */
79 static void xenfb_key_event(void *opaque, int keycode);
80 static void xenfb_mouse_event(void *opaque,
81 int dx, int dy, int dz, int button_state);
82 static void xenfb_guest_copy(struct xenfb *xenfb, int x, int y, int w, int h);
83 static void xenfb_update(void *opaque);
84 static void xenfb_invalidate(void *opaque);
85 static void xenfb_screen_dump(void *opaque, const char *name);
86 static int xenfb_register_console(struct xenfb *xenfb);
88 /*
89 * Tables to map from scancode to Linux input layer keycode.
90 * Scancodes are hardware-specific. These maps assumes a
91 * standard AT or PS/2 keyboard which is what QEMU feeds us.
92 */
93 static const unsigned char atkbd_set2_keycode[512] = {
95 0, 67, 65, 63, 61, 59, 60, 88, 0, 68, 66, 64, 62, 15, 41,117,
96 0, 56, 42, 93, 29, 16, 2, 0, 0, 0, 44, 31, 30, 17, 3, 0,
97 0, 46, 45, 32, 18, 5, 4, 95, 0, 57, 47, 33, 20, 19, 6,183,
98 0, 49, 48, 35, 34, 21, 7,184, 0, 0, 50, 36, 22, 8, 9,185,
99 0, 51, 37, 23, 24, 11, 10, 0, 0, 52, 53, 38, 39, 25, 12, 0,
100 0, 89, 40, 0, 26, 13, 0, 0, 58, 54, 28, 27, 0, 43, 0, 85,
101 0, 86, 91, 90, 92, 0, 14, 94, 0, 79,124, 75, 71,121, 0, 0,
102 82, 83, 80, 76, 77, 72, 1, 69, 87, 78, 81, 74, 55, 73, 70, 99,
104 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
105 217,100,255, 0, 97,165, 0, 0,156, 0, 0, 0, 0, 0, 0,125,
106 173,114, 0,113, 0, 0, 0,126,128, 0, 0,140, 0, 0, 0,127,
107 159, 0,115, 0,164, 0, 0,116,158, 0,150,166, 0, 0, 0,142,
108 157, 0, 0, 0, 0, 0, 0, 0,155, 0, 98, 0, 0,163, 0, 0,
109 226, 0, 0, 0, 0, 0, 0, 0, 0,255, 96, 0, 0, 0,143, 0,
110 0, 0, 0, 0, 0, 0, 0, 0, 0,107, 0,105,102, 0, 0,112,
111 110,111,108,112,106,103, 0,119, 0,118,109, 0, 99,104,119, 0,
113 };
115 static const unsigned char atkbd_unxlate_table[128] = {
117 0,118, 22, 30, 38, 37, 46, 54, 61, 62, 70, 69, 78, 85,102, 13,
118 21, 29, 36, 45, 44, 53, 60, 67, 68, 77, 84, 91, 90, 20, 28, 27,
119 35, 43, 52, 51, 59, 66, 75, 76, 82, 14, 18, 93, 26, 34, 33, 42,
120 50, 49, 58, 65, 73, 74, 89,124, 17, 41, 88, 5, 6, 4, 12, 3,
121 11, 2, 10, 1, 9,119,126,108,117,125,123,107,115,116,121,105,
122 114,122,112,113,127, 96, 97,120, 7, 15, 23, 31, 39, 47, 55, 63,
123 71, 79, 86, 94, 8, 16, 24, 32, 40, 48, 56, 64, 72, 80, 87,111,
124 19, 25, 57, 81, 83, 92, 95, 98, 99,100,101,103,104,106,109,110
126 };
128 static unsigned char scancode2linux[512];
130 static int xenfb_xs_scanf1(struct xs_handle *xsh,
131 const char *dir, const char *node,
132 const char *fmt, void *dest)
133 {
134 char buf[1024];
135 char *p;
136 int ret;
138 if (snprintf(buf, sizeof(buf), "%s/%s", dir, node) >= sizeof(buf)) {
139 errno = ENOENT;
140 return -1;
141 }
142 p = xs_read(xsh, XBT_NULL, buf, NULL);
143 if (!p) {
144 errno = ENOENT;
145 return -1;
146 }
147 ret = sscanf(p, fmt, dest);
148 free(p);
149 if (ret != 1) {
150 errno = EDOM;
151 return -1;
152 }
153 return ret;
154 }
156 static int xenfb_xs_printf(struct xs_handle *xsh,
157 const char *dir, const char *node, char *fmt, ...)
158 {
159 va_list ap;
160 char key[1024];
161 char val[1024];
162 int n;
164 if (snprintf(key, sizeof(key), "%s/%s", dir, node) >= sizeof(key)) {
165 errno = ENOENT;
166 return -1;
167 }
169 va_start(ap, fmt);
170 n = vsnprintf(val, sizeof(val), fmt, ap);
171 va_end(ap);
172 if (n >= sizeof(val)) {
173 errno = ENOSPC; /* close enough */
174 return -1;
175 }
177 if (!xs_write(xsh, XBT_NULL, key, val, n))
178 return -1;
179 return 0;
180 }
182 static void xenfb_device_init(struct xenfb_device *dev,
183 const char *type,
184 struct xenfb *xenfb)
185 {
186 dev->devicetype = type;
187 dev->otherend_id = -1;
188 dev->port = -1;
189 dev->xenfb = xenfb;
190 }
192 static char *xenfb_path_in_dom(struct xs_handle *xsh,
193 char *buf, size_t size,
194 unsigned domid, const char *fmt, ...)
195 {
196 va_list ap;
197 char *domp = xs_get_domain_path(xsh, domid);
198 int n;
200 if (domp == NULL)
201 return NULL;
203 n = snprintf(buf, size, "%s/", domp);
204 free(domp);
205 if (n >= size)
206 return NULL;
208 va_start(ap, fmt);
209 n += vsnprintf(buf + n, size - n, fmt, ap);
210 va_end(ap);
211 if (n >= size)
212 return NULL;
214 return buf;
215 }
217 static int xenfb_device_set_domain(struct xenfb_device *dev, int domid)
218 {
219 dev->otherend_id = domid;
221 if (!xenfb_path_in_dom(dev->xenfb->xsh,
222 dev->otherend, sizeof(dev->otherend),
223 domid, "device/%s/0", dev->devicetype)) {
224 errno = ENOENT;
225 return -1;
226 }
227 if (!xenfb_path_in_dom(dev->xenfb->xsh,
228 dev->nodename, sizeof(dev->nodename),
229 0, "backend/%s/%d/0", dev->devicetype, domid)) {
230 errno = ENOENT;
231 return -1;
232 }
234 return 0;
235 }
237 struct xenfb *xenfb_new(int domid, DisplayState *ds)
238 {
239 struct xenfb *xenfb = qemu_malloc(sizeof(struct xenfb));
240 int serrno;
241 int i;
243 if (xenfb == NULL)
244 return NULL;
246 /* Prepare scancode mapping table */
247 for (i = 0; i < 128; i++) {
248 scancode2linux[i] = atkbd_set2_keycode[atkbd_unxlate_table[i]];
249 scancode2linux[i | 0x80] =
250 atkbd_set2_keycode[atkbd_unxlate_table[i] | 0x80];
251 }
253 memset(xenfb, 0, sizeof(*xenfb));
254 xenfb->evt_xch = xenfb->xc = -1;
255 xenfb_device_init(&xenfb->fb, "vfb", xenfb);
256 xenfb_device_init(&xenfb->kbd, "vkbd", xenfb);
258 xenfb->evt_xch = xc_evtchn_open();
259 if (xenfb->evt_xch == -1)
260 goto fail;
262 xenfb->xc = xc_interface_open();
263 if (xenfb->xc == -1)
264 goto fail;
266 xenfb->xsh = xs_daemon_open();
267 if (!xenfb->xsh)
268 goto fail;
270 xenfb->ds = ds;
271 xenfb_device_set_domain(&xenfb->fb, domid);
272 xenfb_device_set_domain(&xenfb->kbd, domid);
274 fprintf(stderr, "FB: Waiting for KBD backend creation\n");
275 xenfb_wait_for_backend(&xenfb->kbd, xenfb_backend_created_kbd);
277 return xenfb;
279 fail:
280 serrno = errno;
281 xenfb_shutdown(xenfb);
282 errno = serrno;
283 return NULL;
284 }
287 static enum xenbus_state xenfb_read_state(struct xs_handle *xsh,
288 const char *dir)
289 {
290 int ret, state;
292 ret = xenfb_xs_scanf1(xsh, dir, "state", "%d", &state);
293 if (ret < 0)
294 return XenbusStateUnknown;
296 if ((unsigned)state > XenbusStateClosed)
297 state = XenbusStateUnknown;
298 return state;
299 }
301 static int xenfb_switch_state(struct xenfb_device *dev,
302 enum xenbus_state state)
303 {
304 struct xs_handle *xsh = dev->xenfb->xsh;
306 if (xenfb_xs_printf(xsh, dev->nodename, "state", "%d", state) < 0)
307 return -1;
308 dev->state = state;
309 return 0;
310 }
313 static int xenfb_hotplug(struct xenfb_device *dev)
314 {
315 if (xenfb_xs_printf(dev->xenfb->xsh, dev->nodename,
316 "hotplug-status", "connected"))
317 return -1;
318 return 0;
319 }
321 static void xenfb_copy_mfns(int mode, int count, unsigned long *dst, void *src)
322 {
323 uint32_t *src32 = src;
324 uint64_t *src64 = src;
325 int i;
327 for (i = 0; i < count; i++)
328 dst[i] = (mode == 32) ? src32[i] : src64[i];
329 }
331 static int xenfb_map_fb(struct xenfb *xenfb, int domid)
332 {
333 struct xenfb_page *page = xenfb->fb.page;
334 int n_fbmfns;
335 int n_fbdirs;
336 unsigned long *pgmfns = NULL;
337 unsigned long *fbmfns = NULL;
338 void *map, *pd;
339 int mode, ret = -1;
341 /* default to native */
342 pd = page->pd;
343 mode = sizeof(unsigned long) * 8;
345 if (0 == strlen(xenfb->protocol)) {
346 /*
347 * Undefined protocol, some guesswork needed.
348 *
349 * Old frontends which don't set the protocol use
350 * one page directory only, thus pd[1] must be zero.
351 * pd[1] of the 32bit struct layout and the lower
352 * 32 bits of pd[0] of the 64bit struct layout have
353 * the same location, so we can check that ...
354 */
355 uint32_t *ptr32 = NULL;
356 uint32_t *ptr64 = NULL;
357 #if defined(__i386__)
358 ptr32 = (void*)page->pd;
359 ptr64 = ((void*)page->pd) + 4;
360 #elif defined(__x86_64__)
361 ptr32 = ((void*)page->pd) - 4;
362 ptr64 = (void*)page->pd;
363 #endif
364 if (ptr32) {
365 if (0 == ptr32[1]) {
366 mode = 32;
367 pd = ptr32;
368 } else {
369 mode = 64;
370 pd = ptr64;
371 }
372 }
373 #if defined(__x86_64__)
374 } else if (0 == strcmp(xenfb->protocol, XEN_IO_PROTO_ABI_X86_32)) {
375 /* 64bit dom0, 32bit domU */
376 mode = 32;
377 pd = ((void*)page->pd) - 4;
378 #elif defined(__i386__)
379 } else if (0 == strcmp(xenfb->protocol, XEN_IO_PROTO_ABI_X86_64)) {
380 /* 32bit dom0, 64bit domU */
381 mode = 64;
382 pd = ((void*)page->pd) + 4;
383 #endif
384 }
386 n_fbmfns = (xenfb->fb_len + (XC_PAGE_SIZE - 1)) / XC_PAGE_SIZE;
387 n_fbdirs = n_fbmfns * mode / 8;
388 n_fbdirs = (n_fbdirs + (XC_PAGE_SIZE - 1)) / XC_PAGE_SIZE;
390 pgmfns = malloc(sizeof(unsigned long) * n_fbdirs);
391 fbmfns = malloc(sizeof(unsigned long) * n_fbmfns);
392 if (!pgmfns || !fbmfns)
393 goto out;
395 xenfb_copy_mfns(mode, n_fbdirs, pgmfns, pd);
396 map = xc_map_foreign_pages(xenfb->xc, domid,
397 PROT_READ, pgmfns, n_fbdirs);
398 if (map == NULL)
399 goto out;
400 xenfb_copy_mfns(mode, n_fbmfns, fbmfns, map);
401 munmap(map, n_fbdirs * XC_PAGE_SIZE);
403 xenfb->pixels = xc_map_foreign_pages(xenfb->xc, domid,
404 PROT_READ | PROT_WRITE, fbmfns, n_fbmfns);
405 if (xenfb->pixels == NULL)
406 goto out;
408 ret = 0; /* all is fine */
410 out:
411 if (pgmfns)
412 free(pgmfns);
413 if (fbmfns)
414 free(fbmfns);
415 return ret;
416 }
418 static int xenfb_bind(struct xenfb_device *dev)
419 {
420 struct xenfb *xenfb = dev->xenfb;
421 unsigned long mfn;
422 evtchn_port_t evtchn;
424 if (xenfb_xs_scanf1(xenfb->xsh, dev->otherend, "page-ref", "%lu",
425 &mfn) < 0)
426 return -1;
427 if (xenfb_xs_scanf1(xenfb->xsh, dev->otherend, "event-channel", "%u",
428 &evtchn) < 0)
429 return -1;
431 dev->port = xc_evtchn_bind_interdomain(xenfb->evt_xch,
432 dev->otherend_id, evtchn);
433 if (dev->port == -1)
434 return -1;
436 dev->page = xc_map_foreign_range(xenfb->xc, dev->otherend_id,
437 XC_PAGE_SIZE, PROT_READ | PROT_WRITE, mfn);
438 if (dev->page == NULL)
439 return -1;
441 return 0;
442 }
444 static void xenfb_unbind(struct xenfb_device *dev)
445 {
446 if (dev->page) {
447 munmap(dev->page, XC_PAGE_SIZE);
448 dev->page = NULL;
449 }
450 if (dev->port >= 0) {
451 xc_evtchn_unbind(dev->xenfb->evt_xch, dev->port);
452 dev->port = -1;
453 }
454 }
457 static void xenfb_detach_dom(struct xenfb *xenfb)
458 {
459 xenfb_unbind(&xenfb->fb);
460 xenfb_unbind(&xenfb->kbd);
461 if (xenfb->pixels) {
462 munmap(xenfb->pixels, xenfb->fb_len);
463 xenfb->pixels = NULL;
464 }
465 }
467 /* Remove the backend area in xenbus since the framebuffer really is
468 going away. */
469 void xenfb_shutdown(struct xenfb *xenfb)
470 {
471 fprintf(stderr, "FB: Shutting down backend\n");
472 xs_rm(xenfb->xsh, XBT_NULL, xenfb->fb.nodename);
473 xs_rm(xenfb->xsh, XBT_NULL, xenfb->kbd.nodename);
475 xenfb_detach_dom(xenfb);
476 if (xenfb->xc >= 0)
477 xc_interface_close(xenfb->xc);
478 if (xenfb->evt_xch >= 0)
479 xc_evtchn_close(xenfb->evt_xch);
480 if (xenfb->xsh)
481 xs_daemon_close(xenfb->xsh);
482 free(xenfb);
483 }
486 static void xenfb_on_fb_event(struct xenfb *xenfb)
487 {
488 uint32_t prod, cons;
489 struct xenfb_page *page = xenfb->fb.page;
491 prod = page->out_prod;
492 if (prod == page->out_cons)
493 return;
494 xen_rmb(); /* ensure we see ring contents up to prod */
495 for (cons = page->out_cons; cons != prod; cons++) {
496 union xenfb_out_event *event = &XENFB_OUT_RING_REF(page, cons);
497 int x, y, w, h;
499 switch (event->type) {
500 case XENFB_TYPE_UPDATE:
501 x = MAX(event->update.x, 0);
502 y = MAX(event->update.y, 0);
503 w = MIN(event->update.width, xenfb->width - x);
504 h = MIN(event->update.height, xenfb->height - y);
505 if (w < 0 || h < 0) {
506 fprintf(stderr, "%s bogus update ignored\n",
507 xenfb->fb.nodename);
508 break;
509 }
510 if (x != event->update.x || y != event->update.y
511 || w != event->update.width
512 || h != event->update.height) {
513 fprintf(stderr, "%s bogus update clipped\n",
514 xenfb->fb.nodename);
515 break;
516 }
517 xenfb_guest_copy(xenfb, x, y, w, h);
518 break;
519 }
520 }
521 xen_mb(); /* ensure we're done with ring contents */
522 page->out_cons = cons;
523 xc_evtchn_notify(xenfb->evt_xch, xenfb->fb.port);
524 }
526 static void xenfb_on_kbd_event(struct xenfb *xenfb)
527 {
528 struct xenkbd_page *page = xenfb->kbd.page;
530 /* We don't understand any keyboard events, so just ignore them. */
531 if (page->out_prod == page->out_cons)
532 return;
533 page->out_cons = page->out_prod;
534 xc_evtchn_notify(xenfb->evt_xch, xenfb->kbd.port);
535 }
537 static int xenfb_on_state_change(struct xenfb_device *dev)
538 {
539 enum xenbus_state state;
541 state = xenfb_read_state(dev->xenfb->xsh, dev->otherend);
543 switch (state) {
544 case XenbusStateUnknown:
545 /* There was an error reading the frontend state. The
546 domain has probably gone away; in any case, there's
547 not much point in us continuing. */
548 return -1;
549 case XenbusStateInitialising:
550 case XenbusStateInitWait:
551 case XenbusStateInitialised:
552 case XenbusStateConnected:
553 break;
554 case XenbusStateClosing:
555 xenfb_unbind(dev);
556 xenfb_switch_state(dev, state);
557 break;
558 case XenbusStateClosed:
559 xenfb_switch_state(dev, state);
560 }
561 return 0;
562 }
564 /* Send an event to the keyboard frontend driver */
565 static int xenfb_kbd_event(struct xenfb *xenfb,
566 union xenkbd_in_event *event)
567 {
568 uint32_t prod;
569 struct xenkbd_page *page = xenfb->kbd.page;
571 if (xenfb->kbd.state != XenbusStateConnected)
572 return 0;
574 prod = page->in_prod;
575 if (prod - page->in_cons == XENKBD_IN_RING_LEN) {
576 errno = EAGAIN;
577 return -1;
578 }
580 xen_mb(); /* ensure ring space available */
581 XENKBD_IN_RING_REF(page, prod) = *event;
582 xen_wmb(); /* ensure ring contents visible */
583 page->in_prod = prod + 1;
584 return xc_evtchn_notify(xenfb->evt_xch, xenfb->kbd.port);
585 }
587 /* Send a keyboard (or mouse button) event */
588 static int xenfb_send_key(struct xenfb *xenfb, bool down, int keycode)
589 {
590 union xenkbd_in_event event;
592 memset(&event, 0, XENKBD_IN_EVENT_SIZE);
593 event.type = XENKBD_TYPE_KEY;
594 event.key.pressed = down ? 1 : 0;
595 event.key.keycode = keycode;
597 return xenfb_kbd_event(xenfb, &event);
598 }
600 /* Send a relative mouse movement event */
601 static int xenfb_send_motion(struct xenfb *xenfb,
602 int rel_x, int rel_y, int rel_z)
603 {
604 union xenkbd_in_event event;
606 memset(&event, 0, XENKBD_IN_EVENT_SIZE);
607 event.type = XENKBD_TYPE_MOTION;
608 event.motion.rel_x = rel_x;
609 event.motion.rel_y = rel_y;
610 event.motion.rel_z = rel_z;
612 return xenfb_kbd_event(xenfb, &event);
613 }
615 /* Send an absolute mouse movement event */
616 static int xenfb_send_position(struct xenfb *xenfb,
617 int abs_x, int abs_y, int rel_z)
618 {
619 union xenkbd_in_event event;
621 memset(&event, 0, XENKBD_IN_EVENT_SIZE);
622 event.type = XENKBD_TYPE_POS;
623 event.pos.abs_x = abs_x;
624 event.pos.abs_y = abs_y;
625 event.pos.rel_z = rel_z;
627 return xenfb_kbd_event(xenfb, &event);
628 }
630 /* Process events from the frontend event channel */
631 static void xenfb_dispatch_channel(void *opaque)
632 {
633 struct xenfb *xenfb = (struct xenfb *)opaque;
634 evtchn_port_t port;
635 port = xc_evtchn_pending(xenfb->evt_xch);
636 if (port == -1) {
637 xenfb_shutdown(xenfb);
638 exit(1);
639 }
641 if (port == xenfb->fb.port)
642 xenfb_on_fb_event(xenfb);
643 else if (port == xenfb->kbd.port)
644 xenfb_on_kbd_event(xenfb);
646 if (xc_evtchn_unmask(xenfb->evt_xch, port) == -1) {
647 xenfb_shutdown(xenfb);
648 exit(1);
649 }
650 }
652 /* Process ongoing events from the frontend devices */
653 static void xenfb_dispatch_store(void *opaque)
654 {
655 struct xenfb *xenfb = (struct xenfb *)opaque;
656 unsigned dummy;
657 char **vec;
658 int r;
660 vec = xs_read_watch(xenfb->xsh, &dummy);
661 free(vec);
662 r = xenfb_on_state_change(&xenfb->fb);
663 if (r == 0)
664 r = xenfb_on_state_change(&xenfb->kbd);
665 if (r < 0) {
666 xenfb_shutdown(xenfb);
667 exit(1);
668 }
669 }
672 /****************************************************************
673 *
674 * Functions for processing frontend config
675 *
676 ****************************************************************/
679 /* Process the frontend framebuffer config */
680 static int xenfb_read_frontend_fb_config(struct xenfb *xenfb) {
681 struct xenfb_page *fb_page;
682 int val;
684 if (xenfb_xs_scanf1(xenfb->xsh, xenfb->fb.otherend, "feature-update",
685 "%d", &val) < 0)
686 val = 0;
687 if (!val) {
688 fprintf(stderr, "feature-update not supported\n");
689 errno = ENOTSUP;
690 return -1;
691 }
692 if (xenfb_xs_scanf1(xenfb->xsh, xenfb->fb.otherend, "protocol", "%63s",
693 xenfb->protocol) < 0)
694 xenfb->protocol[0] = '\0';
695 xenfb_xs_printf(xenfb->xsh, xenfb->fb.nodename, "request-update", "1");
697 /* TODO check for permitted ranges */
698 fb_page = xenfb->fb.page;
699 xenfb->depth = fb_page->depth;
700 xenfb->width = fb_page->width;
701 xenfb->height = fb_page->height;
702 /* TODO check for consistency with the above */
703 xenfb->fb_len = fb_page->mem_length;
704 xenfb->row_stride = fb_page->line_length;
705 fprintf(stderr, "Framebuffer depth %d width %d height %d line %d\n",
706 fb_page->depth, fb_page->width, fb_page->height, fb_page->line_length);
707 if (xenfb_map_fb(xenfb, xenfb->fb.otherend_id) < 0)
708 return -1;
710 if (xenfb_switch_state(&xenfb->fb, XenbusStateConnected))
711 return -1;
712 if (xenfb_switch_state(&xenfb->kbd, XenbusStateConnected))
713 return -1;
715 return 0;
716 }
718 /* Process the frontend keyboard config */
719 static int xenfb_read_frontend_kbd_config(struct xenfb *xenfb)
720 {
721 int val;
723 if (xenfb_xs_scanf1(xenfb->xsh, xenfb->kbd.otherend, "request-abs-pointer",
724 "%d", &val) < 0)
725 val = 0;
726 xenfb->abs_pointer_wanted = val;
728 return 0;
729 }
732 /****************************************************************
733 *
734 * Functions for frontend/backend state machine
735 *
736 ****************************************************************/
738 /* Register a watch against a frontend device, and setup
739 * QEMU event loop to poll the xenstore FD for notification */
740 static int xenfb_wait_for_frontend(struct xenfb_device *dev, IOHandler *handler)
741 {
742 fprintf(stderr, "Doing frontend watch on %s\n", dev->otherend);
743 if (!xs_watch(dev->xenfb->xsh, dev->otherend, "")) {
744 fprintf(stderr, "Watch for dev failed\n");
745 return -1;
746 }
748 if (qemu_set_fd_handler2(xs_fileno(dev->xenfb->xsh), NULL, handler, NULL, dev) < 0)
749 return -1;
751 return 0;
752 }
754 /* Register a watch against a backend device, and setup
755 * QEMU event loop to poll the xenstore FD for notification */
756 static int xenfb_wait_for_backend(struct xenfb_device *dev, IOHandler *handler)
757 {
758 fprintf(stderr, "Doing backend watch on %s\n", dev->nodename);
759 if (!xs_watch(dev->xenfb->xsh, dev->nodename, "")) {
760 fprintf(stderr, "Watch for dev failed\n");
761 return -1;
762 }
764 if (qemu_set_fd_handler2(xs_fileno(dev->xenfb->xsh), NULL, handler, NULL, dev) < 0)
765 return -1;
767 return 0;
768 }
770 /* Callback invoked while waiting for KBD backend to change
771 * to the created state */
772 static void xenfb_backend_created_kbd(void *opaque)
773 {
774 struct xenfb_device *dev = (struct xenfb_device *)opaque;
775 int ret = xenfb_backend_created(dev);
776 if (ret < 0) {
777 xenfb_shutdown(dev->xenfb);
778 exit(1);
779 }
780 if (ret)
781 return; /* Still waiting */
783 if (xenfb_xs_printf(dev->xenfb->xsh, dev->nodename, "feature-abs-pointer", "1")) {
784 xenfb_shutdown(dev->xenfb);
785 exit(1);
786 }
788 fprintf(stderr, "FB: Waiting for FB backend creation\n");
789 xenfb_wait_for_backend(&dev->xenfb->fb, xenfb_backend_created_fb);
790 }
792 /* Callback invoked while waiting for FB backend to change
793 * to the created state */
794 static void xenfb_backend_created_fb(void *opaque)
795 {
796 struct xenfb_device *dev = (struct xenfb_device *)opaque;
797 int ret = xenfb_backend_created(dev);
798 if (ret < 0) {
799 xenfb_shutdown(dev->xenfb);
800 exit(1);
801 }
802 if (ret)
803 return; /* Still waiting */
805 fprintf(stderr, "FB: Waiting for KBD frontend initialization\n");
806 xenfb_wait_for_frontend(&dev->xenfb->kbd, xenfb_frontend_initialized_kbd);
807 }
809 /* Callback invoked while waiting for KBD frontend to change
810 * to the initialized state */
811 static void xenfb_frontend_initialized_kbd(void *opaque)
812 {
813 struct xenfb_device *dev = (struct xenfb_device *)opaque;
814 int ret = xenfb_frontend_initialized(dev);
815 if (ret < 0) {
816 xenfb_shutdown(dev->xenfb);
817 exit(1);
818 }
819 if (ret)
820 return; /* Still waiting */
823 fprintf(stderr, "FB: Waiting for FB frontend initialization\n");
824 xenfb_wait_for_frontend(&dev->xenfb->fb, xenfb_frontend_initialized_fb);
825 }
827 /* Callback invoked while waiting for FB frontend to change
828 * to the initialized state */
829 static void xenfb_frontend_initialized_fb(void *opaque)
830 {
831 struct xenfb_device *dev = (struct xenfb_device *)opaque;
832 int ret = xenfb_frontend_initialized(dev);
833 if (ret < 0) {
834 xenfb_shutdown(dev->xenfb);
835 exit(1);
836 }
837 if (ret)
838 return; /* Still waiting */
841 if (xenfb_read_frontend_fb_config(dev->xenfb)) {
842 xenfb_shutdown(dev->xenfb);
843 exit(1);
844 }
846 fprintf(stderr, "FB: Waiting for KBD frontend connection\n");
847 xenfb_wait_for_frontend(&dev->xenfb->kbd, xenfb_frontend_connected_kbd);
848 }
850 /* Callback invoked while waiting for KBD frontend to change
851 * to the connected state */
852 static void xenfb_frontend_connected_kbd(void *opaque)
853 {
854 struct xenfb_device *dev = (struct xenfb_device *)opaque;
855 int ret = xenfb_frontend_connected(dev);
856 if (ret < 0) {
857 xenfb_shutdown(dev->xenfb);
858 exit(1);
859 }
860 if (ret)
861 return; /* Still waiting */
863 if (xenfb_read_frontend_kbd_config(dev->xenfb) < 0) {
864 xenfb_shutdown(dev->xenfb);
865 exit(1);
866 }
868 xenfb_register_console(dev->xenfb);
869 }
872 /****************************************************************
873 *
874 * Helper functions for checking state of frontend/backend devices
875 *
876 ****************************************************************/
878 /* Helper to determine if a frontend device is in Connected state */
879 static int xenfb_frontend_connected(struct xenfb_device *dev)
880 {
881 unsigned int state;
882 unsigned int dummy;
883 char **vec;
884 vec = xs_read_watch(dev->xenfb->xsh, &dummy);
885 if (!vec)
886 return -1;
887 free(vec);
889 state = xenfb_read_state(dev->xenfb->xsh, dev->otherend);
890 if (!((1 <<state) & ((1 << XenbusStateUnknown) |
891 (1 << XenbusStateConnected)))) {
892 fprintf(stderr, "FB: Carry on waiting\n");
893 return 1;
894 }
896 /* Don't unwatch frontend - we need to detect shutdown */
897 /*xs_unwatch(dev->xenfb->xsh, dev->otherend, "");*/
899 switch (state) {
900 case XenbusStateConnected:
901 break;
902 default:
903 return -1;
904 }
905 return 0;
906 }
909 /* Helper to determine if a frontend device is in Initialized state */
910 static int xenfb_frontend_initialized(struct xenfb_device *dev)
911 {
912 unsigned int state;
913 unsigned int dummy;
914 char **vec;
915 vec = xs_read_watch(dev->xenfb->xsh, &dummy);
916 if (!vec)
917 return -1;
918 free(vec);
920 state = xenfb_read_state(dev->xenfb->xsh, dev->otherend);
922 if (!((1 << state) & ((1 << XenbusStateUnknown)
923 | (1 << XenbusStateInitialised)
924 #if 1 /* TODO fudging state to permit restarting; to be removed */
925 | (1 << XenbusStateConnected)
926 #endif
927 ))) {
928 fprintf(stderr, "FB: Carry on waiting\n");
929 return 1;
930 }
932 xs_unwatch(dev->xenfb->xsh, dev->otherend, "");
934 switch (state) {
935 #if 1
936 case XenbusStateConnected:
937 printf("Fudging state to %d\n", XenbusStateInitialised); /* FIXME */
938 #endif
939 case XenbusStateInitialised:
940 break;
941 default:
942 return -1;
943 }
945 if (xenfb_bind(dev) < 0)
946 return -1;
948 return 0;
949 }
951 /* Helper to determine if a backend device is in Created state */
952 static int xenfb_backend_created(struct xenfb_device *dev)
953 {
954 unsigned int state;
955 unsigned int dummy;
956 char **vec;
957 vec = xs_read_watch(dev->xenfb->xsh, &dummy);
958 if (!vec)
959 return -1;
960 free(vec);
962 state = xenfb_read_state(dev->xenfb->xsh, dev->nodename);
964 if (!((1 <<state) & ((1 << XenbusStateUnknown)
965 | (1 << XenbusStateInitialising)
966 | (1 << XenbusStateClosed)
967 #if 1 /* TODO fudging state to permit restarting; to be removed */
968 | (1 << XenbusStateInitWait)
969 | (1 << XenbusStateConnected)
970 | (1 << XenbusStateClosing)
971 #endif
972 ))) {
973 fprintf(stderr, "FB: Carry on waiting\n");
974 return 1;
975 }
977 xs_unwatch(dev->xenfb->xsh, dev->nodename, "");
979 switch (state) {
980 #if 1
981 case XenbusStateInitWait:
982 case XenbusStateConnected:
983 printf("Fudging state to %d\n", XenbusStateInitialising); /* FIXME */
984 #endif
985 case XenbusStateInitialising:
986 case XenbusStateClosing:
987 case XenbusStateClosed:
988 break;
989 default:
990 fprintf(stderr, "Wrong state %d\n", state);
991 return -1;
992 }
993 xenfb_switch_state(dev, XenbusStateInitWait);
994 if (xenfb_hotplug(dev) < 0)
995 return -1;
997 return 0;
998 }
1001 /****************************************************************
1003 * QEMU device model integration functions
1005 ****************************************************************/
1007 /*
1008 * Send a key event from the client to the guest OS
1009 * QEMU gives us a raw scancode from an AT / PS/2 style keyboard.
1010 * We have to turn this into a Linux Input layer keycode.
1012 * Extra complexity from the fact that with extended scancodes
1013 * (like those produced by arrow keys) this method gets called
1014 * twice, but we only want to send a single event. So we have to
1015 * track the '0xe0' scancode state & collapse the extended keys
1016 * as needed.
1018 * Wish we could just send scancodes straight to the guest which
1019 * already has code for dealing with this...
1020 */
1021 static void xenfb_key_event(void *opaque, int scancode)
1023 static int extended = 0;
1024 int down = 1;
1025 if (scancode == 0xe0) {
1026 extended = 1;
1027 return;
1028 } else if (scancode & 0x80) {
1029 scancode &= 0x7f;
1030 down = 0;
1032 if (extended) {
1033 scancode |= 0x80;
1034 extended = 0;
1036 xenfb_send_key(opaque, down, scancode2linux[scancode]);
1039 /*
1040 * Send a mouse event from the client to the guest OS
1042 * The QEMU mouse can be in either relative, or absolute mode.
1043 * Movement is sent separately from button state, which has to
1044 * be encoded as virtual key events. We also don't actually get
1045 * given any button up/down events, so have to track changes in
1046 * the button state.
1047 */
1048 static void xenfb_mouse_event(void *opaque,
1049 int dx, int dy, int dz, int button_state)
1051 int i;
1052 struct xenfb *xenfb = opaque;
1053 if (xenfb->abs_pointer_wanted)
1054 xenfb_send_position(xenfb,
1055 dx * xenfb->ds->width / 0x7fff,
1056 dy * xenfb->ds->height / 0x7fff,
1057 dz);
1058 else
1059 xenfb_send_motion(xenfb, dx, dy, dz);
1061 for (i = 0 ; i < 8 ; i++) {
1062 int lastDown = xenfb->button_state & (1 << i);
1063 int down = button_state & (1 << i);
1064 if (down == lastDown)
1065 continue;
1067 if (xenfb_send_key(xenfb, down, BTN_LEFT+i) < 0)
1068 return;
1070 xenfb->button_state = button_state;
1073 /* A convenient function for munging pixels between different depths */
1074 #define BLT(SRC_T,DST_T,RSB,GSB,BSB,RDB,GDB,BDB) \
1075 for (line = y ; line < (y+h) ; line++) { \
1076 SRC_T *src = (SRC_T *)(xenfb->pixels \
1077 + (line * xenfb->row_stride) \
1078 + (x * xenfb->depth / 8)); \
1079 DST_T *dst = (DST_T *)(xenfb->ds->data \
1080 + (line * xenfb->ds->linesize) \
1081 + (x * xenfb->ds->depth / 8)); \
1082 int col; \
1083 const int RSS = 32 - (RSB + GSB + BSB); \
1084 const int GSS = 32 - (GSB + BSB); \
1085 const int BSS = 32 - (BSB); \
1086 const uint32_t RSM = (~0U) << (32 - RSB); \
1087 const uint32_t GSM = (~0U) << (32 - GSB); \
1088 const uint32_t BSM = (~0U) << (32 - BSB); \
1089 const int RDS = 32 - (RDB + GDB + BDB); \
1090 const int GDS = 32 - (GDB + BDB); \
1091 const int BDS = 32 - (BDB); \
1092 const uint32_t RDM = (~0U) << (32 - RDB); \
1093 const uint32_t GDM = (~0U) << (32 - GDB); \
1094 const uint32_t BDM = (~0U) << (32 - BDB); \
1095 for (col = x ; col < (x+w) ; col++) { \
1096 uint32_t spix = *src; \
1097 *dst = (((spix << RSS) & RSM & RDM) >> RDS) | \
1098 (((spix << GSS) & GSM & GDM) >> GDS) | \
1099 (((spix << BSS) & BSM & BDM) >> BDS); \
1100 src = (SRC_T *) ((unsigned long) src + xenfb->depth / 8); \
1101 dst = (DST_T *) ((unsigned long) dst + xenfb->ds->depth / 8); \
1102 } \
1106 /* This copies data from the guest framebuffer region, into QEMU's copy
1107 * NB. QEMU's copy is stored in the pixel format of a) the local X
1108 * server (SDL case) or b) the current VNC client pixel format.
1109 * When shifting between colour depths we preserve the MSB.
1110 */
1111 static void xenfb_guest_copy(struct xenfb *xenfb, int x, int y, int w, int h)
1113 int line;
1115 if (xenfb->depth == xenfb->ds->depth) { /* Perfect match can use fast path */
1116 for (line = y ; line < (y+h) ; line++) {
1117 memcpy(xenfb->ds->data + (line * xenfb->ds->linesize) + (x * xenfb->ds->depth / 8),
1118 xenfb->pixels + (line * xenfb->row_stride) + (x * xenfb->depth / 8),
1119 w * xenfb->depth / 8);
1121 } else { /* Mismatch requires slow pixel munging */
1122 /* 8 bit == r:3 g:3 b:2 */
1123 /* 16 bit == r:5 g:6 b:5 */
1124 /* 24 bit == r:8 g:8 b:8 */
1125 /* 32 bit == r:8 g:8 b:8 (padding:8) */
1126 if (xenfb->depth == 8) {
1127 if (xenfb->ds->depth == 16) {
1128 BLT(uint8_t, uint16_t, 3, 3, 2, 5, 6, 5);
1129 } else if (xenfb->ds->depth == 32) {
1130 BLT(uint8_t, uint32_t, 3, 3, 2, 8, 8, 8);
1132 } else if (xenfb->depth == 16) {
1133 if (xenfb->ds->depth == 8) {
1134 BLT(uint16_t, uint8_t, 5, 6, 5, 3, 3, 2);
1135 } else if (xenfb->ds->depth == 32) {
1136 BLT(uint16_t, uint32_t, 5, 6, 5, 8, 8, 8);
1138 } else if (xenfb->depth == 24 || xenfb->depth == 32) {
1139 if (xenfb->ds->depth == 8) {
1140 BLT(uint32_t, uint8_t, 8, 8, 8, 3, 3, 2);
1141 } else if (xenfb->ds->depth == 16) {
1142 BLT(uint32_t, uint16_t, 8, 8, 8, 5, 6, 5);
1143 } else if (xenfb->ds->depth == 32) {
1144 BLT(uint32_t, uint32_t, 8, 8, 8, 8, 8, 8);
1148 dpy_update(xenfb->ds, x, y, w, h);
1151 /* Periodic update of display, no need for any in our case */
1152 static void xenfb_update(void *opaque)
1154 struct xenfb *xenfb = opaque;
1157 /* QEMU display state changed, so refresh the framebuffer copy */
1158 static void xenfb_invalidate(void *opaque)
1160 struct xenfb *xenfb = opaque;
1161 xenfb_guest_copy(xenfb, 0, 0, xenfb->width, xenfb->height);
1164 /* Screen dump is not used in Xen, so no need to impl this....yet */
1165 static void xenfb_screen_dump(void *opaque, const char *name) { }
1168 /* Register a QEMU graphical console, and key/mouse handler,
1169 * connecting up their events to the frontend */
1170 static int xenfb_register_console(struct xenfb *xenfb) {
1171 /* Register our keyboard & mouse handlers */
1172 qemu_add_kbd_event_handler(xenfb_key_event, xenfb);
1173 qemu_add_mouse_event_handler(xenfb_mouse_event, xenfb,
1174 xenfb->abs_pointer_wanted,
1175 "Xen PVFB Mouse");
1177 /* Tell QEMU to allocate a graphical console */
1178 graphic_console_init(xenfb->ds,
1179 xenfb_update,
1180 xenfb_invalidate,
1181 xenfb_screen_dump,
1182 xenfb);
1183 dpy_resize(xenfb->ds, xenfb->width, xenfb->height);
1185 if (qemu_set_fd_handler2(xc_evtchn_fd(xenfb->evt_xch), NULL, xenfb_dispatch_channel, NULL, xenfb) < 0)
1186 return -1;
1187 if (qemu_set_fd_handler2(xs_fileno(xenfb->xsh), NULL, xenfb_dispatch_store, NULL, xenfb) < 0)
1188 return -1;
1190 fprintf(stderr, "Xen Framebuffer registered\n");
1191 return 0;
1194 #ifdef CONFIG_STUBDOM
1195 static struct semaphore kbd_sem = __SEMAPHORE_INITIALIZER(kbd_sem, 0);
1196 static struct kbdfront_dev *kbd_dev;
1197 static char *kbd_path, *fb_path;
1199 static unsigned char linux2scancode[KEY_MAX + 1];
1201 #define WIDTH 1024
1202 #define HEIGHT 768
1203 #define DEPTH 32
1204 #define LINESIZE (1280 * (DEPTH / 8))
1205 #define MEMSIZE (LINESIZE * HEIGHT)
1207 int xenfb_connect_vkbd(const char *path)
1209 kbd_path = strdup(path);
1210 return 0;
1213 int xenfb_connect_vfb(const char *path)
1215 fb_path = strdup(path);
1216 return 0;
1219 static void xenfb_pv_update(DisplayState *s, int x, int y, int w, int h)
1221 struct fbfront_dev *fb_dev = s->opaque;
1222 fbfront_update(fb_dev, x, y, w, h);
1225 static void xenfb_pv_resize(DisplayState *s, int w, int h)
1227 struct fbfront_dev *fb_dev = s->opaque;
1228 fprintf(stderr,"resize to %dx%d required\n", w, h);
1229 s->width = w;
1230 s->height = h;
1231 /* TODO: send resize event if supported */
1232 memset(s->data, 0, MEMSIZE);
1233 fbfront_update(fb_dev, 0, 0, WIDTH, HEIGHT);
1236 static void xenfb_pv_colourdepth(DisplayState *s, int depth)
1238 /* TODO: send redepth event if supported */
1239 fprintf(stderr,"redepth to %d required\n", depth);
1242 static void xenfb_kbd_handler(void *opaque)
1244 #define KBD_NUM_BATCH 64
1245 union xenkbd_in_event buf[KBD_NUM_BATCH];
1246 int n, i;
1247 DisplayState *s = opaque;
1248 static int buttons;
1249 static int x, y;
1251 n = kbdfront_receive(kbd_dev, buf, KBD_NUM_BATCH);
1252 for (i = 0; i < n; i++) {
1253 switch (buf[i].type) {
1255 case XENKBD_TYPE_MOTION:
1256 fprintf(stderr, "FB backend sent us relative mouse motion event!\n");
1257 break;
1259 case XENKBD_TYPE_POS:
1261 int new_x = buf[i].pos.abs_x;
1262 int new_y = buf[i].pos.abs_y;
1263 if (new_x >= s->width)
1264 new_x = s->width - 1;
1265 if (new_y >= s->height)
1266 new_y = s->height - 1;
1267 if (kbd_mouse_is_absolute()) {
1268 kbd_mouse_event(
1269 new_x * 0x7FFF / (s->width - 1),
1270 new_y * 0x7FFF / (s->height - 1),
1271 buf[i].pos.rel_z,
1272 buttons);
1273 } else {
1274 kbd_mouse_event(
1275 new_x - x,
1276 new_y - y,
1277 buf[i].pos.rel_z,
1278 buttons);
1280 x = new_x;
1281 y = new_y;
1282 break;
1285 case XENKBD_TYPE_KEY:
1287 int keycode = buf[i].key.keycode;
1288 int button = 0;
1290 if (keycode == BTN_LEFT)
1291 button = MOUSE_EVENT_LBUTTON;
1292 else if (keycode == BTN_RIGHT)
1293 button = MOUSE_EVENT_RBUTTON;
1294 else if (keycode == BTN_MIDDLE)
1295 button = MOUSE_EVENT_MBUTTON;
1297 if (button) {
1298 if (buf[i].key.pressed)
1299 buttons |= button;
1300 else
1301 buttons &= ~button;
1302 if (kbd_mouse_is_absolute())
1303 kbd_mouse_event(
1304 x * 0x7FFF / s->width,
1305 y * 0x7FFF / s->height,
1306 0,
1307 buttons);
1308 else
1309 kbd_mouse_event(0, 0, 0, buttons);
1310 } else {
1311 int scancode = linux2scancode[keycode];
1312 if (!scancode) {
1313 fprintf(stderr, "Can't convert keycode %x to scancode\n", keycode);
1314 break;
1316 if (scancode & 0x80) {
1317 kbd_put_keycode(0xe0);
1318 scancode &= 0x7f;
1320 if (!buf[i].key.pressed)
1321 scancode |= 0x80;
1322 kbd_put_keycode(scancode);
1324 break;
1330 static void xenfb_pv_refresh(DisplayState *ds)
1332 vga_hw_update();
1335 static void kbdfront_thread(void *p)
1337 int scancode, keycode;
1338 kbd_dev = init_kbdfront(p, 1);
1339 if (!kbd_dev) {
1340 fprintf(stderr,"can't open keyboard\n");
1341 exit(1);
1343 up(&kbd_sem);
1344 for (scancode = 0; scancode < 128; scancode++) {
1345 keycode = atkbd_set2_keycode[atkbd_unxlate_table[scancode]];
1346 linux2scancode[keycode] = scancode;
1347 keycode = atkbd_set2_keycode[atkbd_unxlate_table[scancode] | 0x80];
1348 linux2scancode[keycode] = scancode | 0x80;
1352 int xenfb_pv_display_init(DisplayState *ds)
1354 void *data;
1355 struct fbfront_dev *fb_dev;
1356 int kbd_fd;
1358 if (!fb_path || !kbd_path)
1359 return -1;
1361 create_thread("kbdfront", kbdfront_thread, (void*) kbd_path);
1363 data = qemu_memalign(PAGE_SIZE, VGA_RAM_SIZE);
1364 fb_dev = init_fbfront(fb_path, data, WIDTH, HEIGHT, DEPTH, LINESIZE, MEMSIZE);
1365 if (!fb_dev) {
1366 fprintf(stderr,"can't open frame buffer\n");
1367 exit(1);
1369 free(fb_path);
1371 down(&kbd_sem);
1372 free(kbd_path);
1374 kbd_fd = kbdfront_open(kbd_dev);
1375 qemu_set_fd_handler(kbd_fd, xenfb_kbd_handler, NULL, ds);
1377 ds->data = data;
1378 ds->linesize = LINESIZE;
1379 ds->depth = DEPTH;
1380 ds->bgr = 0;
1381 ds->width = WIDTH;
1382 ds->height = HEIGHT;
1383 ds->dpy_update = xenfb_pv_update;
1384 ds->dpy_resize = xenfb_pv_resize;
1385 ds->dpy_colourdepth = NULL; //xenfb_pv_colourdepth;
1386 ds->dpy_refresh = xenfb_pv_refresh;
1387 ds->opaque = fb_dev;
1388 return 0;
1390 #endif
1392 /*
1393 * Local variables:
1394 * c-indent-level: 8
1395 * c-basic-offset: 8
1396 * tab-width: 8
1397 * End:
1398 */