ia64/xen-unstable

view tools/ioemu/hw/xenfb.c @ 16306:4c1b7e48f791

ioemu: Remove dependency on linux/input.h
Signed-off-by: Keir Fraser <keir@xensource.com>
author Keir Fraser <keir@xensource.com>
date Fri Nov 02 09:44:45 2007 +0000 (2007-11-02)
parents aa56bb2fe7d9
children 614dad9f8fdc
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 #ifndef BTN_LEFT
23 #define BTN_LEFT 0x110 /* from <linux/input.h> */
24 #endif
26 // FIXME defend against malicious frontend?
28 struct xenfb;
30 struct xenfb_device {
31 const char *devicetype;
32 char nodename[64]; /* backend xenstore dir */
33 char otherend[64]; /* frontend xenstore dir */
34 int otherend_id; /* frontend domid */
35 enum xenbus_state state; /* backend state */
36 void *page; /* shared page */
37 evtchn_port_t port;
38 struct xenfb *xenfb;
39 };
41 struct xenfb {
42 DisplayState *ds; /* QEMU graphical console state */
43 int evt_xch; /* event channel driver handle */
44 int xc; /* hypervisor interface handle */
45 struct xs_handle *xsh; /* xs daemon handle */
46 struct xenfb_device fb, kbd;
47 void *pixels; /* guest framebuffer data */
48 size_t fb_len; /* size of framebuffer */
49 int row_stride; /* width of one row in framebuffer */
50 int depth; /* colour depth of guest framebuffer */
51 int width; /* pixel width of guest framebuffer */
52 int height; /* pixel height of guest framebuffer */
53 int abs_pointer_wanted; /* Whether guest supports absolute pointer */
54 int button_state; /* Last seen pointer button state */
55 char protocol[64]; /* frontend protocol */
56 };
58 /* Functions for frontend/backend state machine*/
59 static int xenfb_wait_for_frontend(struct xenfb_device *dev, IOHandler *handler);
60 static int xenfb_wait_for_backend(struct xenfb_device *dev, IOHandler *handler);
61 static void xenfb_backend_created_kbd(void *opaque);
62 static void xenfb_backend_created_fb(void *opaque);
63 static void xenfb_frontend_initialized_kbd(void *opaque);
64 static void xenfb_frontend_initialized_fb(void *opaque);
65 static void xenfb_frontend_connected_kbd(void *opaque);
67 /* Helper functions for checking state of frontend/backend devices */
68 static int xenfb_frontend_connected(struct xenfb_device *dev);
69 static int xenfb_frontend_initialized(struct xenfb_device *dev);
70 static int xenfb_backend_created(struct xenfb_device *dev);
72 /* Functions which tie the PVFB into the QEMU device model */
73 static void xenfb_key_event(void *opaque, int keycode);
74 static void xenfb_mouse_event(void *opaque,
75 int dx, int dy, int dz, int button_state);
76 static void xenfb_guest_copy(struct xenfb *xenfb, int x, int y, int w, int h);
77 static void xenfb_update(void *opaque);
78 static void xenfb_invalidate(void *opaque);
79 static void xenfb_screen_dump(void *opaque, const char *name);
80 static int xenfb_register_console(struct xenfb *xenfb);
82 /*
83 * Tables to map from scancode to Linux input layer keycode.
84 * Scancodes are hardware-specific. These maps assumes a
85 * standard AT or PS/2 keyboard which is what QEMU feeds us.
86 */
87 static const unsigned char atkbd_set2_keycode[512] = {
89 0, 67, 65, 63, 61, 59, 60, 88, 0, 68, 66, 64, 62, 15, 41,117,
90 0, 56, 42, 93, 29, 16, 2, 0, 0, 0, 44, 31, 30, 17, 3, 0,
91 0, 46, 45, 32, 18, 5, 4, 95, 0, 57, 47, 33, 20, 19, 6,183,
92 0, 49, 48, 35, 34, 21, 7,184, 0, 0, 50, 36, 22, 8, 9,185,
93 0, 51, 37, 23, 24, 11, 10, 0, 0, 52, 53, 38, 39, 25, 12, 0,
94 0, 89, 40, 0, 26, 13, 0, 0, 58, 54, 28, 27, 0, 43, 0, 85,
95 0, 86, 91, 90, 92, 0, 14, 94, 0, 79,124, 75, 71,121, 0, 0,
96 82, 83, 80, 76, 77, 72, 1, 69, 87, 78, 81, 74, 55, 73, 70, 99,
98 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
99 217,100,255, 0, 97,165, 0, 0,156, 0, 0, 0, 0, 0, 0,125,
100 173,114, 0,113, 0, 0, 0,126,128, 0, 0,140, 0, 0, 0,127,
101 159, 0,115, 0,164, 0, 0,116,158, 0,150,166, 0, 0, 0,142,
102 157, 0, 0, 0, 0, 0, 0, 0,155, 0, 98, 0, 0,163, 0, 0,
103 226, 0, 0, 0, 0, 0, 0, 0, 0,255, 96, 0, 0, 0,143, 0,
104 0, 0, 0, 0, 0, 0, 0, 0, 0,107, 0,105,102, 0, 0,112,
105 110,111,108,112,106,103, 0,119, 0,118,109, 0, 99,104,119, 0,
107 };
109 static const unsigned char atkbd_unxlate_table[128] = {
111 0,118, 22, 30, 38, 37, 46, 54, 61, 62, 70, 69, 78, 85,102, 13,
112 21, 29, 36, 45, 44, 53, 60, 67, 68, 77, 84, 91, 90, 20, 28, 27,
113 35, 43, 52, 51, 59, 66, 75, 76, 82, 14, 18, 93, 26, 34, 33, 42,
114 50, 49, 58, 65, 73, 74, 89,124, 17, 41, 88, 5, 6, 4, 12, 3,
115 11, 2, 10, 1, 9,119,126,108,117,125,123,107,115,116,121,105,
116 114,122,112,113,127, 96, 97,120, 7, 15, 23, 31, 39, 47, 55, 63,
117 71, 79, 86, 94, 8, 16, 24, 32, 40, 48, 56, 64, 72, 80, 87,111,
118 19, 25, 57, 81, 83, 92, 95, 98, 99,100,101,103,104,106,109,110
120 };
122 static unsigned char scancode2linux[512];
124 static int xenfb_xs_scanf1(struct xs_handle *xsh,
125 const char *dir, const char *node,
126 const char *fmt, void *dest)
127 {
128 char buf[1024];
129 char *p;
130 int ret;
132 if (snprintf(buf, sizeof(buf), "%s/%s", dir, node) >= sizeof(buf)) {
133 errno = ENOENT;
134 return -1;
135 }
136 p = xs_read(xsh, XBT_NULL, buf, NULL);
137 if (!p) {
138 errno = ENOENT;
139 return -1;
140 }
141 ret = sscanf(p, fmt, dest);
142 free(p);
143 if (ret != 1) {
144 errno = EDOM;
145 return -1;
146 }
147 return ret;
148 }
150 static int xenfb_xs_printf(struct xs_handle *xsh,
151 const char *dir, const char *node, char *fmt, ...)
152 {
153 va_list ap;
154 char key[1024];
155 char val[1024];
156 int n;
158 if (snprintf(key, sizeof(key), "%s/%s", dir, node) >= sizeof(key)) {
159 errno = ENOENT;
160 return -1;
161 }
163 va_start(ap, fmt);
164 n = vsnprintf(val, sizeof(val), fmt, ap);
165 va_end(ap);
166 if (n >= sizeof(val)) {
167 errno = ENOSPC; /* close enough */
168 return -1;
169 }
171 if (!xs_write(xsh, XBT_NULL, key, val, n))
172 return -1;
173 return 0;
174 }
176 static void xenfb_device_init(struct xenfb_device *dev,
177 const char *type,
178 struct xenfb *xenfb)
179 {
180 dev->devicetype = type;
181 dev->otherend_id = -1;
182 dev->port = -1;
183 dev->xenfb = xenfb;
184 }
186 static char *xenfb_path_in_dom(struct xs_handle *xsh,
187 char *buf, size_t size,
188 unsigned domid, const char *fmt, ...)
189 {
190 va_list ap;
191 char *domp = xs_get_domain_path(xsh, domid);
192 int n;
194 if (domp == NULL)
195 return NULL;
197 n = snprintf(buf, size, "%s/", domp);
198 free(domp);
199 if (n >= size)
200 return NULL;
202 va_start(ap, fmt);
203 n += vsnprintf(buf + n, size - n, fmt, ap);
204 va_end(ap);
205 if (n >= size)
206 return NULL;
208 return buf;
209 }
211 static int xenfb_device_set_domain(struct xenfb_device *dev, int domid)
212 {
213 dev->otherend_id = domid;
215 if (!xenfb_path_in_dom(dev->xenfb->xsh,
216 dev->otherend, sizeof(dev->otherend),
217 domid, "device/%s/0", dev->devicetype)) {
218 errno = ENOENT;
219 return -1;
220 }
221 if (!xenfb_path_in_dom(dev->xenfb->xsh,
222 dev->nodename, sizeof(dev->nodename),
223 0, "backend/%s/%d/0", dev->devicetype, domid)) {
224 errno = ENOENT;
225 return -1;
226 }
228 return 0;
229 }
231 struct xenfb *xenfb_new(int domid, DisplayState *ds)
232 {
233 struct xenfb *xenfb = qemu_malloc(sizeof(struct xenfb));
234 int serrno;
235 int i;
237 if (xenfb == NULL)
238 return NULL;
240 /* Prepare scancode mapping table */
241 for (i = 0; i < 128; i++) {
242 scancode2linux[i] = atkbd_set2_keycode[atkbd_unxlate_table[i]];
243 scancode2linux[i | 0x80] =
244 atkbd_set2_keycode[atkbd_unxlate_table[i] | 0x80];
245 }
247 memset(xenfb, 0, sizeof(*xenfb));
248 xenfb->evt_xch = xenfb->xc = -1;
249 xenfb_device_init(&xenfb->fb, "vfb", xenfb);
250 xenfb_device_init(&xenfb->kbd, "vkbd", xenfb);
252 xenfb->evt_xch = xc_evtchn_open();
253 if (xenfb->evt_xch == -1)
254 goto fail;
256 xenfb->xc = xc_interface_open();
257 if (xenfb->xc == -1)
258 goto fail;
260 xenfb->xsh = xs_daemon_open();
261 if (!xenfb->xsh)
262 goto fail;
264 xenfb->ds = ds;
265 xenfb_device_set_domain(&xenfb->fb, domid);
266 xenfb_device_set_domain(&xenfb->kbd, domid);
268 fprintf(stderr, "FB: Waiting for KBD backend creation\n");
269 xenfb_wait_for_backend(&xenfb->kbd, xenfb_backend_created_kbd);
271 return xenfb;
273 fail:
274 serrno = errno;
275 xenfb_shutdown(xenfb);
276 errno = serrno;
277 return NULL;
278 }
281 static enum xenbus_state xenfb_read_state(struct xs_handle *xsh,
282 const char *dir)
283 {
284 int ret, state;
286 ret = xenfb_xs_scanf1(xsh, dir, "state", "%d", &state);
287 if (ret < 0)
288 return XenbusStateUnknown;
290 if ((unsigned)state > XenbusStateClosed)
291 state = XenbusStateUnknown;
292 return state;
293 }
295 static int xenfb_switch_state(struct xenfb_device *dev,
296 enum xenbus_state state)
297 {
298 struct xs_handle *xsh = dev->xenfb->xsh;
300 if (xenfb_xs_printf(xsh, dev->nodename, "state", "%d", state) < 0)
301 return -1;
302 dev->state = state;
303 return 0;
304 }
307 static int xenfb_hotplug(struct xenfb_device *dev)
308 {
309 if (xenfb_xs_printf(dev->xenfb->xsh, dev->nodename,
310 "hotplug-status", "connected"))
311 return -1;
312 return 0;
313 }
315 static void xenfb_copy_mfns(int mode, int count, unsigned long *dst, void *src)
316 {
317 uint32_t *src32 = src;
318 uint64_t *src64 = src;
319 int i;
321 for (i = 0; i < count; i++)
322 dst[i] = (mode == 32) ? src32[i] : src64[i];
323 }
325 static int xenfb_map_fb(struct xenfb *xenfb, int domid)
326 {
327 struct xenfb_page *page = xenfb->fb.page;
328 int n_fbmfns;
329 int n_fbdirs;
330 unsigned long *pgmfns = NULL;
331 unsigned long *fbmfns = NULL;
332 void *map, *pd;
333 int mode, ret = -1;
335 /* default to native */
336 pd = page->pd;
337 mode = sizeof(unsigned long) * 8;
339 if (0 == strlen(xenfb->protocol)) {
340 /*
341 * Undefined protocol, some guesswork needed.
342 *
343 * Old frontends which don't set the protocol use
344 * one page directory only, thus pd[1] must be zero.
345 * pd[1] of the 32bit struct layout and the lower
346 * 32 bits of pd[0] of the 64bit struct layout have
347 * the same location, so we can check that ...
348 */
349 uint32_t *ptr32 = NULL;
350 uint32_t *ptr64 = NULL;
351 #if defined(__i386__)
352 ptr32 = (void*)page->pd;
353 ptr64 = ((void*)page->pd) + 4;
354 #elif defined(__x86_64__)
355 ptr32 = ((void*)page->pd) - 4;
356 ptr64 = (void*)page->pd;
357 #endif
358 if (ptr32) {
359 if (0 == ptr32[1]) {
360 mode = 32;
361 pd = ptr32;
362 } else {
363 mode = 64;
364 pd = ptr64;
365 }
366 }
367 #if defined(__x86_64__)
368 } else if (0 == strcmp(xenfb->protocol, XEN_IO_PROTO_ABI_X86_32)) {
369 /* 64bit dom0, 32bit domU */
370 mode = 32;
371 pd = ((void*)page->pd) - 4;
372 #elif defined(__i386__)
373 } else if (0 == strcmp(xenfb->protocol, XEN_IO_PROTO_ABI_X86_64)) {
374 /* 32bit dom0, 64bit domU */
375 mode = 64;
376 pd = ((void*)page->pd) + 4;
377 #endif
378 }
380 n_fbmfns = (xenfb->fb_len + (XC_PAGE_SIZE - 1)) / XC_PAGE_SIZE;
381 n_fbdirs = n_fbmfns * mode / 8;
382 n_fbdirs = (n_fbdirs + (XC_PAGE_SIZE - 1)) / XC_PAGE_SIZE;
384 pgmfns = malloc(sizeof(unsigned long) * n_fbdirs);
385 fbmfns = malloc(sizeof(unsigned long) * n_fbmfns);
386 if (!pgmfns || !fbmfns)
387 goto out;
389 xenfb_copy_mfns(mode, n_fbdirs, pgmfns, pd);
390 map = xc_map_foreign_pages(xenfb->xc, domid,
391 PROT_READ, pgmfns, n_fbdirs);
392 if (map == NULL)
393 goto out;
394 xenfb_copy_mfns(mode, n_fbmfns, fbmfns, map);
395 munmap(map, n_fbdirs * XC_PAGE_SIZE);
397 xenfb->pixels = xc_map_foreign_pages(xenfb->xc, domid,
398 PROT_READ | PROT_WRITE, fbmfns, n_fbmfns);
399 if (xenfb->pixels == NULL)
400 goto out;
402 ret = 0; /* all is fine */
404 out:
405 if (pgmfns)
406 free(pgmfns);
407 if (fbmfns)
408 free(fbmfns);
409 return ret;
410 }
412 static int xenfb_bind(struct xenfb_device *dev)
413 {
414 struct xenfb *xenfb = dev->xenfb;
415 unsigned long mfn;
416 evtchn_port_t evtchn;
418 if (xenfb_xs_scanf1(xenfb->xsh, dev->otherend, "page-ref", "%lu",
419 &mfn) < 0)
420 return -1;
421 if (xenfb_xs_scanf1(xenfb->xsh, dev->otherend, "event-channel", "%u",
422 &evtchn) < 0)
423 return -1;
425 dev->port = xc_evtchn_bind_interdomain(xenfb->evt_xch,
426 dev->otherend_id, evtchn);
427 if (dev->port == -1)
428 return -1;
430 dev->page = xc_map_foreign_range(xenfb->xc, dev->otherend_id,
431 XC_PAGE_SIZE, PROT_READ | PROT_WRITE, mfn);
432 if (dev->page == NULL)
433 return -1;
435 return 0;
436 }
438 static void xenfb_unbind(struct xenfb_device *dev)
439 {
440 if (dev->page) {
441 munmap(dev->page, XC_PAGE_SIZE);
442 dev->page = NULL;
443 }
444 if (dev->port >= 0) {
445 xc_evtchn_unbind(dev->xenfb->evt_xch, dev->port);
446 dev->port = -1;
447 }
448 }
451 static void xenfb_detach_dom(struct xenfb *xenfb)
452 {
453 xenfb_unbind(&xenfb->fb);
454 xenfb_unbind(&xenfb->kbd);
455 if (xenfb->pixels) {
456 munmap(xenfb->pixels, xenfb->fb_len);
457 xenfb->pixels = NULL;
458 }
459 }
461 /* Remove the backend area in xenbus since the framebuffer really is
462 going away. */
463 void xenfb_shutdown(struct xenfb *xenfb)
464 {
465 fprintf(stderr, "FB: Shutting down backend\n");
466 xs_rm(xenfb->xsh, XBT_NULL, xenfb->fb.nodename);
467 xs_rm(xenfb->xsh, XBT_NULL, xenfb->kbd.nodename);
469 xenfb_detach_dom(xenfb);
470 if (xenfb->xc >= 0)
471 xc_interface_close(xenfb->xc);
472 if (xenfb->evt_xch >= 0)
473 xc_evtchn_close(xenfb->evt_xch);
474 if (xenfb->xsh)
475 xs_daemon_close(xenfb->xsh);
476 free(xenfb);
477 }
480 static void xenfb_on_fb_event(struct xenfb *xenfb)
481 {
482 uint32_t prod, cons;
483 struct xenfb_page *page = xenfb->fb.page;
485 prod = page->out_prod;
486 if (prod == page->out_cons)
487 return;
488 rmb(); /* ensure we see ring contents up to prod */
489 for (cons = page->out_cons; cons != prod; cons++) {
490 union xenfb_out_event *event = &XENFB_OUT_RING_REF(page, cons);
492 switch (event->type) {
493 case XENFB_TYPE_UPDATE:
494 xenfb_guest_copy(xenfb,
495 event->update.x, event->update.y,
496 event->update.width, event->update.height);
497 break;
498 }
499 }
500 mb(); /* ensure we're done with ring contents */
501 page->out_cons = cons;
502 xc_evtchn_notify(xenfb->evt_xch, xenfb->fb.port);
503 }
505 static void xenfb_on_kbd_event(struct xenfb *xenfb)
506 {
507 struct xenkbd_page *page = xenfb->kbd.page;
509 /* We don't understand any keyboard events, so just ignore them. */
510 if (page->out_prod == page->out_cons)
511 return;
512 page->out_cons = page->out_prod;
513 xc_evtchn_notify(xenfb->evt_xch, xenfb->kbd.port);
514 }
516 static int xenfb_on_state_change(struct xenfb_device *dev)
517 {
518 enum xenbus_state state;
520 state = xenfb_read_state(dev->xenfb->xsh, dev->otherend);
522 switch (state) {
523 case XenbusStateUnknown:
524 /* There was an error reading the frontend state. The
525 domain has probably gone away; in any case, there's
526 not much point in us continuing. */
527 return -1;
528 case XenbusStateInitialising:
529 case XenbusStateInitWait:
530 case XenbusStateInitialised:
531 case XenbusStateConnected:
532 break;
533 case XenbusStateClosing:
534 xenfb_unbind(dev);
535 xenfb_switch_state(dev, state);
536 break;
537 case XenbusStateClosed:
538 xenfb_switch_state(dev, state);
539 }
540 return 0;
541 }
543 /* Send an event to the keyboard frontend driver */
544 static int xenfb_kbd_event(struct xenfb *xenfb,
545 union xenkbd_in_event *event)
546 {
547 uint32_t prod;
548 struct xenkbd_page *page = xenfb->kbd.page;
550 if (xenfb->kbd.state != XenbusStateConnected)
551 return 0;
553 prod = page->in_prod;
554 if (prod - page->in_cons == XENKBD_IN_RING_LEN) {
555 errno = EAGAIN;
556 return -1;
557 }
559 mb(); /* ensure ring space available */
560 XENKBD_IN_RING_REF(page, prod) = *event;
561 wmb(); /* ensure ring contents visible */
562 page->in_prod = prod + 1;
563 return xc_evtchn_notify(xenfb->evt_xch, xenfb->kbd.port);
564 }
566 /* Send a keyboard (or mouse button) event */
567 static int xenfb_send_key(struct xenfb *xenfb, bool down, int keycode)
568 {
569 union xenkbd_in_event event;
571 memset(&event, 0, XENKBD_IN_EVENT_SIZE);
572 event.type = XENKBD_TYPE_KEY;
573 event.key.pressed = down ? 1 : 0;
574 event.key.keycode = keycode;
576 return xenfb_kbd_event(xenfb, &event);
577 }
579 /* Send a relative mouse movement event */
580 static int xenfb_send_motion(struct xenfb *xenfb, int rel_x, int rel_y)
581 {
582 union xenkbd_in_event event;
584 memset(&event, 0, XENKBD_IN_EVENT_SIZE);
585 event.type = XENKBD_TYPE_MOTION;
586 event.motion.rel_x = rel_x;
587 event.motion.rel_y = rel_y;
589 return xenfb_kbd_event(xenfb, &event);
590 }
592 /* Send an absolute mouse movement event */
593 static int xenfb_send_position(struct xenfb *xenfb, int abs_x, int abs_y)
594 {
595 union xenkbd_in_event event;
597 memset(&event, 0, XENKBD_IN_EVENT_SIZE);
598 event.type = XENKBD_TYPE_POS;
599 event.pos.abs_x = abs_x;
600 event.pos.abs_y = abs_y;
602 return xenfb_kbd_event(xenfb, &event);
603 }
605 /* Process events from the frontend event channel */
606 static void xenfb_dispatch_channel(void *opaque)
607 {
608 struct xenfb *xenfb = (struct xenfb *)opaque;
609 evtchn_port_t port;
610 port = xc_evtchn_pending(xenfb->evt_xch);
611 if (port == -1) {
612 xenfb_shutdown(xenfb);
613 exit(1);
614 }
616 if (port == xenfb->fb.port)
617 xenfb_on_fb_event(xenfb);
618 else if (port == xenfb->kbd.port)
619 xenfb_on_kbd_event(xenfb);
621 if (xc_evtchn_unmask(xenfb->evt_xch, port) == -1) {
622 xenfb_shutdown(xenfb);
623 exit(1);
624 }
625 }
627 /* Process ongoing events from the frontend devices */
628 static void xenfb_dispatch_store(void *opaque)
629 {
630 struct xenfb *xenfb = (struct xenfb *)opaque;
631 unsigned dummy;
632 char **vec;
633 int r;
635 vec = xs_read_watch(xenfb->xsh, &dummy);
636 free(vec);
637 r = xenfb_on_state_change(&xenfb->fb);
638 if (r == 0)
639 r = xenfb_on_state_change(&xenfb->kbd);
640 if (r < 0) {
641 xenfb_shutdown(xenfb);
642 exit(1);
643 }
644 }
647 /****************************************************************
648 *
649 * Functions for processing frontend config
650 *
651 ****************************************************************/
654 /* Process the frontend framebuffer config */
655 static int xenfb_read_frontend_fb_config(struct xenfb *xenfb) {
656 struct xenfb_page *fb_page;
657 int val;
659 if (xenfb_xs_scanf1(xenfb->xsh, xenfb->fb.otherend, "feature-update",
660 "%d", &val) < 0)
661 val = 0;
662 if (!val) {
663 fprintf(stderr, "feature-update not supported\n");
664 errno = ENOTSUP;
665 return -1;
666 }
667 if (xenfb_xs_scanf1(xenfb->xsh, xenfb->fb.otherend, "protocol", "%63s",
668 xenfb->protocol) < 0)
669 xenfb->protocol[0] = '\0';
670 xenfb_xs_printf(xenfb->xsh, xenfb->fb.nodename, "request-update", "1");
672 /* TODO check for permitted ranges */
673 fb_page = xenfb->fb.page;
674 xenfb->depth = fb_page->depth;
675 xenfb->width = fb_page->width;
676 xenfb->height = fb_page->height;
677 /* TODO check for consistency with the above */
678 xenfb->fb_len = fb_page->mem_length;
679 xenfb->row_stride = fb_page->line_length;
680 fprintf(stderr, "Framebuffer depth %d width %d height %d line %d\n",
681 fb_page->depth, fb_page->width, fb_page->height, fb_page->line_length);
682 if (xenfb_map_fb(xenfb, xenfb->fb.otherend_id) < 0)
683 return -1;
685 if (xenfb_switch_state(&xenfb->fb, XenbusStateConnected))
686 return -1;
687 if (xenfb_switch_state(&xenfb->kbd, XenbusStateConnected))
688 return -1;
690 return 0;
691 }
693 /* Process the frontend keyboard config */
694 static int xenfb_read_frontend_kbd_config(struct xenfb *xenfb)
695 {
696 int val;
698 if (xenfb_xs_scanf1(xenfb->xsh, xenfb->kbd.otherend, "request-abs-pointer",
699 "%d", &val) < 0)
700 val = 0;
701 xenfb->abs_pointer_wanted = val;
703 return 0;
704 }
707 /****************************************************************
708 *
709 * Functions for frontend/backend state machine
710 *
711 ****************************************************************/
713 /* Register a watch against a frontend device, and setup
714 * QEMU event loop to poll the xenstore FD for notification */
715 static int xenfb_wait_for_frontend(struct xenfb_device *dev, IOHandler *handler)
716 {
717 fprintf(stderr, "Doing frontend watch on %s\n", dev->otherend);
718 if (!xs_watch(dev->xenfb->xsh, dev->otherend, "")) {
719 fprintf(stderr, "Watch for dev failed\n");
720 return -1;
721 }
723 if (qemu_set_fd_handler2(xs_fileno(dev->xenfb->xsh), NULL, handler, NULL, dev) < 0)
724 return -1;
726 return 0;
727 }
729 /* Register a watch against a backend device, and setup
730 * QEMU event loop to poll the xenstore FD for notification */
731 static int xenfb_wait_for_backend(struct xenfb_device *dev, IOHandler *handler)
732 {
733 fprintf(stderr, "Doing backend watch on %s\n", dev->nodename);
734 if (!xs_watch(dev->xenfb->xsh, dev->nodename, "")) {
735 fprintf(stderr, "Watch for dev failed\n");
736 return -1;
737 }
739 if (qemu_set_fd_handler2(xs_fileno(dev->xenfb->xsh), NULL, handler, NULL, dev) < 0)
740 return -1;
742 return 0;
743 }
745 /* Callback invoked while waiting for KBD backend to change
746 * to the created state */
747 static void xenfb_backend_created_kbd(void *opaque)
748 {
749 struct xenfb_device *dev = (struct xenfb_device *)opaque;
750 int ret = xenfb_backend_created(dev);
751 if (ret < 0) {
752 xenfb_shutdown(dev->xenfb);
753 exit(1);
754 }
755 if (ret)
756 return; /* Still waiting */
758 if (xenfb_xs_printf(dev->xenfb->xsh, dev->nodename, "feature-abs-pointer", "1")) {
759 xenfb_shutdown(dev->xenfb);
760 exit(1);
761 }
763 fprintf(stderr, "FB: Waiting for FB backend creation\n");
764 xenfb_wait_for_backend(&dev->xenfb->fb, xenfb_backend_created_fb);
765 }
767 /* Callback invoked while waiting for FB backend to change
768 * to the created state */
769 static void xenfb_backend_created_fb(void *opaque)
770 {
771 struct xenfb_device *dev = (struct xenfb_device *)opaque;
772 int ret = xenfb_backend_created(dev);
773 if (ret < 0) {
774 xenfb_shutdown(dev->xenfb);
775 exit(1);
776 }
777 if (ret)
778 return; /* Still waiting */
780 fprintf(stderr, "FB: Waiting for KBD frontend initialization\n");
781 xenfb_wait_for_frontend(&dev->xenfb->kbd, xenfb_frontend_initialized_kbd);
782 }
784 /* Callback invoked while waiting for KBD frontend to change
785 * to the initialized state */
786 static void xenfb_frontend_initialized_kbd(void *opaque)
787 {
788 struct xenfb_device *dev = (struct xenfb_device *)opaque;
789 int ret = xenfb_frontend_initialized(dev);
790 if (ret < 0) {
791 xenfb_shutdown(dev->xenfb);
792 exit(1);
793 }
794 if (ret)
795 return; /* Still waiting */
798 fprintf(stderr, "FB: Waiting for FB frontend initialization\n");
799 xenfb_wait_for_frontend(&dev->xenfb->fb, xenfb_frontend_initialized_fb);
800 }
802 /* Callback invoked while waiting for FB frontend to change
803 * to the initialized state */
804 static void xenfb_frontend_initialized_fb(void *opaque)
805 {
806 struct xenfb_device *dev = (struct xenfb_device *)opaque;
807 int ret = xenfb_frontend_initialized(dev);
808 if (ret < 0) {
809 xenfb_shutdown(dev->xenfb);
810 exit(1);
811 }
812 if (ret)
813 return; /* Still waiting */
816 if (xenfb_read_frontend_fb_config(dev->xenfb)) {
817 xenfb_shutdown(dev->xenfb);
818 exit(1);
819 }
821 fprintf(stderr, "FB: Waiting for KBD frontend connection\n");
822 xenfb_wait_for_frontend(&dev->xenfb->kbd, xenfb_frontend_connected_kbd);
823 }
825 /* Callback invoked while waiting for KBD frontend to change
826 * to the connected state */
827 static void xenfb_frontend_connected_kbd(void *opaque)
828 {
829 struct xenfb_device *dev = (struct xenfb_device *)opaque;
830 int ret = xenfb_frontend_connected(dev);
831 if (ret < 0) {
832 xenfb_shutdown(dev->xenfb);
833 exit(1);
834 }
835 if (ret)
836 return; /* Still waiting */
838 if (xenfb_read_frontend_kbd_config(dev->xenfb) < 0) {
839 xenfb_shutdown(dev->xenfb);
840 exit(1);
841 }
843 xenfb_register_console(dev->xenfb);
844 }
847 /****************************************************************
848 *
849 * Helper functions for checking state of frontend/backend devices
850 *
851 ****************************************************************/
853 /* Helper to determine if a frontend device is in Connected state */
854 static int xenfb_frontend_connected(struct xenfb_device *dev)
855 {
856 unsigned int state;
857 unsigned int dummy;
858 char **vec;
859 vec = xs_read_watch(dev->xenfb->xsh, &dummy);
860 if (!vec)
861 return -1;
862 free(vec);
864 state = xenfb_read_state(dev->xenfb->xsh, dev->otherend);
865 if (!((1 <<state) & ((1 << XenbusStateUnknown) |
866 (1 << XenbusStateConnected)))) {
867 fprintf(stderr, "FB: Carry on waiting\n");
868 return 1;
869 }
871 /* Don't unwatch frontend - we need to detect shutdown */
872 /*xs_unwatch(dev->xenfb->xsh, dev->otherend, "");*/
874 switch (state) {
875 case XenbusStateConnected:
876 break;
877 default:
878 return -1;
879 }
880 return 0;
881 }
884 /* Helper to determine if a frontend device is in Initialized state */
885 static int xenfb_frontend_initialized(struct xenfb_device *dev)
886 {
887 unsigned int state;
888 unsigned int dummy;
889 char **vec;
890 vec = xs_read_watch(dev->xenfb->xsh, &dummy);
891 if (!vec)
892 return -1;
893 free(vec);
895 state = xenfb_read_state(dev->xenfb->xsh, dev->otherend);
897 if (!((1 << state) & ((1 << XenbusStateUnknown)
898 | (1 << XenbusStateInitialised)
899 #if 1 /* TODO fudging state to permit restarting; to be removed */
900 | (1 << XenbusStateConnected)
901 #endif
902 ))) {
903 fprintf(stderr, "FB: Carry on waiting\n");
904 return 1;
905 }
907 xs_unwatch(dev->xenfb->xsh, dev->otherend, "");
909 switch (state) {
910 #if 1
911 case XenbusStateConnected:
912 printf("Fudging state to %d\n", XenbusStateInitialised); /* FIXME */
913 #endif
914 case XenbusStateInitialised:
915 break;
916 default:
917 return -1;
918 }
920 if (xenfb_bind(dev) < 0)
921 return -1;
923 return 0;
924 }
926 /* Helper to determine if a backend device is in Created state */
927 static int xenfb_backend_created(struct xenfb_device *dev)
928 {
929 unsigned int state;
930 unsigned int dummy;
931 char **vec;
932 vec = xs_read_watch(dev->xenfb->xsh, &dummy);
933 if (!vec)
934 return -1;
935 free(vec);
937 state = xenfb_read_state(dev->xenfb->xsh, dev->nodename);
939 if (!((1 <<state) & ((1 << XenbusStateUnknown)
940 | (1 << XenbusStateInitialising)
941 | (1 << XenbusStateClosed)
942 #if 1 /* TODO fudging state to permit restarting; to be removed */
943 | (1 << XenbusStateInitWait)
944 | (1 << XenbusStateConnected)
945 | (1 << XenbusStateClosing)
946 #endif
947 ))) {
948 fprintf(stderr, "FB: Carry on waiting\n");
949 return 1;
950 }
952 xs_unwatch(dev->xenfb->xsh, dev->nodename, "");
954 switch (state) {
955 #if 1
956 case XenbusStateInitWait:
957 case XenbusStateConnected:
958 printf("Fudging state to %d\n", XenbusStateInitialising); /* FIXME */
959 #endif
960 case XenbusStateInitialising:
961 case XenbusStateClosing:
962 case XenbusStateClosed:
963 break;
964 default:
965 fprintf(stderr, "Wrong state %d\n", state);
966 return -1;
967 }
968 xenfb_switch_state(dev, XenbusStateInitWait);
969 if (xenfb_hotplug(dev) < 0)
970 return -1;
972 return 0;
973 }
976 /****************************************************************
977 *
978 * QEMU device model integration functions
979 *
980 ****************************************************************/
982 /*
983 * Send a key event from the client to the guest OS
984 * QEMU gives us a raw scancode from an AT / PS/2 style keyboard.
985 * We have to turn this into a Linux Input layer keycode.
986 *
987 * Extra complexity from the fact that with extended scancodes
988 * (like those produced by arrow keys) this method gets called
989 * twice, but we only want to send a single event. So we have to
990 * track the '0xe0' scancode state & collapse the extended keys
991 * as needed.
992 *
993 * Wish we could just send scancodes straight to the guest which
994 * already has code for dealing with this...
995 */
996 static void xenfb_key_event(void *opaque, int scancode)
997 {
998 static int extended = 0;
999 int down = 1;
1000 if (scancode == 0xe0) {
1001 extended = 1;
1002 return;
1003 } else if (scancode & 0x80) {
1004 scancode &= 0x7f;
1005 down = 0;
1007 if (extended) {
1008 scancode |= 0x80;
1009 extended = 0;
1011 xenfb_send_key(opaque, down, scancode2linux[scancode]);
1014 /*
1015 * Send a mouse event from the client to the guest OS
1017 * The QEMU mouse can be in either relative, or absolute mode.
1018 * Movement is sent separately from button state, which has to
1019 * be encoded as virtual key events. We also don't actually get
1020 * given any button up/down events, so have to track changes in
1021 * the button state.
1022 */
1023 static void xenfb_mouse_event(void *opaque,
1024 int dx, int dy, int dz, int button_state)
1026 int i;
1027 struct xenfb *xenfb = opaque;
1028 if (xenfb->abs_pointer_wanted)
1029 xenfb_send_position(xenfb,
1030 dx * xenfb->ds->width / 0x7fff,
1031 dy * xenfb->ds->height / 0x7fff);
1032 else
1033 xenfb_send_motion(xenfb, dx, dy);
1035 for (i = 0 ; i < 8 ; i++) {
1036 int lastDown = xenfb->button_state & (1 << i);
1037 int down = button_state & (1 << i);
1038 if (down == lastDown)
1039 continue;
1041 if (xenfb_send_key(xenfb, down, BTN_LEFT+i) < 0)
1042 return;
1044 xenfb->button_state = button_state;
1047 /* A convenient function for munging pixels between different depths */
1048 #define BLT(SRC_T,DST_T,RLS,GLS,BLS,RRS,GRS,BRS,RM,GM,BM) \
1049 for (line = y ; line < h ; line++) { \
1050 SRC_T *src = (SRC_T *)(xenfb->pixels \
1051 + (line * xenfb->row_stride) \
1052 + (x * xenfb->depth / 8)); \
1053 DST_T *dst = (DST_T *)(xenfb->ds->data \
1054 + (line * xenfb->ds->linesize) \
1055 + (x * xenfb->ds->depth / 8)); \
1056 int col; \
1057 for (col = x ; col < w ; col++) { \
1058 *dst = (((*src >> RRS) & RM) << RLS) | \
1059 (((*src >> GRS) & GM) << GLS) | \
1060 (((*src >> GRS) & BM) << BLS); \
1061 src++; \
1062 dst++; \
1063 } \
1067 /* This copies data from the guest framebuffer region, into QEMU's copy
1068 * NB. QEMU's copy is stored in the pixel format of a) the local X
1069 * server (SDL case) or b) the current VNC client pixel format.
1070 * When shifting between colour depths we preserve the MSB.
1071 */
1072 static void xenfb_guest_copy(struct xenfb *xenfb, int x, int y, int w, int h)
1074 int line;
1076 if (xenfb->depth == xenfb->ds->depth) { /* Perfect match can use fast path */
1077 for (line = y ; line < (y+h) ; line++) {
1078 memcpy(xenfb->ds->data + (line * xenfb->ds->linesize) + (x * xenfb->ds->depth / 8),
1079 xenfb->pixels + (line * xenfb->row_stride) + (x * xenfb->depth / 8),
1080 w * xenfb->depth / 8);
1082 } else { /* Mismatch requires slow pixel munging */
1083 if (xenfb->depth == 8) {
1084 /* 8 bit source == r:3 g:3 b:2 */
1085 if (xenfb->ds->depth == 16) {
1086 BLT(uint8_t, uint16_t, 5, 2, 0, 11, 5, 0, 7, 7, 3);
1087 } else if (xenfb->ds->depth == 32) {
1088 BLT(uint8_t, uint32_t, 5, 2, 0, 16, 8, 0, 7, 7, 3);
1090 } else if (xenfb->depth == 16) {
1091 /* 16 bit source == r:5 g:6 b:5 */
1092 if (xenfb->ds->depth == 8) {
1093 BLT(uint16_t, uint8_t, 11, 5, 0, 5, 2, 0, 31, 63, 31);
1094 } else if (xenfb->ds->depth == 32) {
1095 BLT(uint16_t, uint32_t, 11, 5, 0, 16, 8, 0, 31, 63, 31);
1097 } else if (xenfb->depth == 32) {
1098 /* 32 bit source == r:8 g:8 b:8 (padding:8) */
1099 if (xenfb->ds->depth == 8) {
1100 BLT(uint32_t, uint8_t, 16, 8, 0, 5, 2, 0, 255, 255, 255);
1101 } else if (xenfb->ds->depth == 16) {
1102 BLT(uint32_t, uint16_t, 16, 8, 0, 11, 5, 0, 255, 255, 255);
1106 dpy_update(xenfb->ds, x, y, w, h);
1109 /* QEMU display state changed, so refresh the framebuffer copy */
1110 /* XXX - can we optimize this, or the next func at all ? */
1111 static void xenfb_update(void *opaque)
1113 struct xenfb *xenfb = opaque;
1114 xenfb_guest_copy(xenfb, 0, 0, xenfb->width, xenfb->height);
1117 /* QEMU display state changed, so refresh the framebuffer copy */
1118 static void xenfb_invalidate(void *opaque)
1120 struct xenfb *xenfb = opaque;
1121 xenfb_guest_copy(xenfb, 0, 0, xenfb->width, xenfb->height);
1124 /* Screen dump is not used in Xen, so no need to impl this....yet */
1125 static void xenfb_screen_dump(void *opaque, const char *name) { }
1128 /* Register a QEMU graphical console, and key/mouse handler,
1129 * connecting up their events to the frontend */
1130 static int xenfb_register_console(struct xenfb *xenfb) {
1131 /* Register our keyboard & mouse handlers */
1132 qemu_add_kbd_event_handler(xenfb_key_event, xenfb);
1133 qemu_add_mouse_event_handler(xenfb_mouse_event, xenfb,
1134 xenfb->abs_pointer_wanted,
1135 "Xen PVFB Mouse");
1137 /* Tell QEMU to allocate a graphical console */
1138 graphic_console_init(xenfb->ds,
1139 xenfb_update,
1140 xenfb_invalidate,
1141 xenfb_screen_dump,
1142 xenfb);
1143 dpy_resize(xenfb->ds, xenfb->width, xenfb->height);
1145 if (qemu_set_fd_handler2(xenfb->evt_xch, NULL, xenfb_dispatch_channel, NULL, xenfb) < 0)
1146 return -1;
1147 if (qemu_set_fd_handler2(xs_fileno(xenfb->xsh), NULL, xenfb_dispatch_store, NULL, xenfb) < 0)
1148 return -1;
1150 fprintf(stderr, "Xen Framebuffer registered\n");
1151 return 0;
1154 /*
1155 * Local variables:
1156 * c-indent-level: 8
1157 * c-basic-offset: 8
1158 * tab-width: 8
1159 * End:
1160 */