1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27#include <stdarg.h>
28#include <stdlib.h>
29#include <sys/types.h>
30#include <fcntl.h>
31#include <unistd.h>
32#include <sys/mman.h>
33#include <errno.h>
34#include <stdio.h>
35#include <string.h>
36#include <time.h>
37
38#include "hw.h"
39#include "console.h"
40#include "qemu-char.h"
41#include "xen_backend.h"
42
43#include <xen/event_channel.h>
44#include <xen/io/fbif.h>
45#include <xen/io/kbdif.h>
46#include <xen/io/protocols.h>
47
48#ifndef BTN_LEFT
49#define BTN_LEFT 0x110
50#endif
51
52
53
54struct common {
55 struct XenDevice xendev;
56 void *page;
57 DisplayState *ds;
58};
59
60struct XenInput {
61 struct common c;
62 int abs_pointer_wanted;
63 int button_state;
64 int extended;
65 QEMUPutMouseEntry *qmouse;
66};
67
68#define UP_QUEUE 8
69
70struct XenFB {
71 struct common c;
72 size_t fb_len;
73 int row_stride;
74 int depth;
75 int width;
76 int height;
77 int offset;
78 void *pixels;
79 int fbpages;
80 int feature_update;
81 int refresh_period;
82 int bug_trigger;
83 int have_console;
84 int do_resize;
85
86 struct {
87 int x,y,w,h;
88 } up_rects[UP_QUEUE];
89 int up_count;
90 int up_fullscreen;
91};
92
93
94
95static int common_bind(struct common *c)
96{
97 int mfn;
98
99 if (xenstore_read_fe_int(&c->xendev, "page-ref", &mfn) == -1)
100 return -1;
101 if (xenstore_read_fe_int(&c->xendev, "event-channel", &c->xendev.remote_port) == -1)
102 return -1;
103
104 c->page = xc_map_foreign_range(xen_xc, c->xendev.dom,
105 XC_PAGE_SIZE,
106 PROT_READ | PROT_WRITE, mfn);
107 if (c->page == NULL)
108 return -1;
109
110 xen_be_bind_evtchn(&c->xendev);
111 xen_be_printf(&c->xendev, 1, "ring mfn %d, remote-port %d, local-port %d\n",
112 mfn, c->xendev.remote_port, c->xendev.local_port);
113
114 return 0;
115}
116
117static void common_unbind(struct common *c)
118{
119 xen_be_unbind_evtchn(&c->xendev);
120 if (c->page) {
121 munmap(c->page, XC_PAGE_SIZE);
122 c->page = NULL;
123 }
124}
125
126
127
128#if 0
129
130
131
132
133
134
135
136
137
138const unsigned char atkbd_set2_keycode[512] = {
139
140 0, 67, 65, 63, 61, 59, 60, 88, 0, 68, 66, 64, 62, 15, 41,117,
141 0, 56, 42, 93, 29, 16, 2, 0, 0, 0, 44, 31, 30, 17, 3, 0,
142 0, 46, 45, 32, 18, 5, 4, 95, 0, 57, 47, 33, 20, 19, 6,183,
143 0, 49, 48, 35, 34, 21, 7,184, 0, 0, 50, 36, 22, 8, 9,185,
144 0, 51, 37, 23, 24, 11, 10, 0, 0, 52, 53, 38, 39, 25, 12, 0,
145 0, 89, 40, 0, 26, 13, 0, 0, 58, 54, 28, 27, 0, 43, 0, 85,
146 0, 86, 91, 90, 92, 0, 14, 94, 0, 79,124, 75, 71,121, 0, 0,
147 82, 83, 80, 76, 77, 72, 1, 69, 87, 78, 81, 74, 55, 73, 70, 99,
148
149 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
150 217,100,255, 0, 97,165, 0, 0,156, 0, 0, 0, 0, 0, 0,125,
151 173,114, 0,113, 0, 0, 0,126,128, 0, 0,140, 0, 0, 0,127,
152 159, 0,115, 0,164, 0, 0,116,158, 0,150,166, 0, 0, 0,142,
153 157, 0, 0, 0, 0, 0, 0, 0,155, 0, 98, 0, 0,163, 0, 0,
154 226, 0, 0, 0, 0, 0, 0, 0, 0,255, 96, 0, 0, 0,143, 0,
155 0, 0, 0, 0, 0, 0, 0, 0, 0,107, 0,105,102, 0, 0,112,
156 110,111,108,112,106,103, 0,119, 0,118,109, 0, 99,104,119, 0,
157
158};
159
160const unsigned char atkbd_unxlate_table[128] = {
161
162 0,118, 22, 30, 38, 37, 46, 54, 61, 62, 70, 69, 78, 85,102, 13,
163 21, 29, 36, 45, 44, 53, 60, 67, 68, 77, 84, 91, 90, 20, 28, 27,
164 35, 43, 52, 51, 59, 66, 75, 76, 82, 14, 18, 93, 26, 34, 33, 42,
165 50, 49, 58, 65, 73, 74, 89,124, 17, 41, 88, 5, 6, 4, 12, 3,
166 11, 2, 10, 1, 9,119,126,108,117,125,123,107,115,116,121,105,
167 114,122,112,113,127, 96, 97,120, 7, 15, 23, 31, 39, 47, 55, 63,
168 71, 79, 86, 94, 8, 16, 24, 32, 40, 48, 56, 64, 72, 80, 87,111,
169 19, 25, 57, 81, 83, 92, 95, 98, 99,100,101,103,104,106,109,110
170
171};
172#endif
173
174
175
176
177
178
179
180static const unsigned char scancode2linux[512] = {
181 0, 1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15,
182 16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
183 32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
184 48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
185 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79,
186 80, 81, 82, 83, 99, 0, 86, 87, 88,117, 0, 0, 95,183,184,185,
187 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
188 93, 0, 0, 89, 0, 0, 85, 91, 90, 92, 0, 94, 0,124,121, 0,
189
190 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
191 165, 0, 0, 0, 0, 0, 0, 0, 0,163, 0, 0, 96, 97, 0, 0,
192 113,140,164, 0,166, 0, 0, 0, 0, 0,255, 0, 0, 0,114, 0,
193 115, 0,150, 0, 0, 98,255, 99,100, 0, 0, 0, 0, 0, 0, 0,
194 0, 0, 0, 0, 0,119,119,102,103,104, 0,105,112,106,118,107,
195 108,109,110,111, 0, 0, 0, 0, 0, 0, 0,125,126,127,116,142,
196 0, 0, 0,143, 0,217,156,173,128,159,158,157,155,226, 0,112,
197 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
198};
199
200
201static int xenfb_kbd_event(struct XenInput *xenfb,
202 union xenkbd_in_event *event)
203{
204 struct xenkbd_page *page = xenfb->c.page;
205 uint32_t prod;
206
207 if (xenfb->c.xendev.be_state != XenbusStateConnected)
208 return 0;
209 if (!page)
210 return 0;
211
212 prod = page->in_prod;
213 if (prod - page->in_cons == XENKBD_IN_RING_LEN) {
214 errno = EAGAIN;
215 return -1;
216 }
217
218 xen_mb();
219 XENKBD_IN_RING_REF(page, prod) = *event;
220 xen_wmb();
221 page->in_prod = prod + 1;
222 return xen_be_send_notify(&xenfb->c.xendev);
223}
224
225
226static int xenfb_send_key(struct XenInput *xenfb, bool down, int keycode)
227{
228 union xenkbd_in_event event;
229
230 memset(&event, 0, XENKBD_IN_EVENT_SIZE);
231 event.type = XENKBD_TYPE_KEY;
232 event.key.pressed = down ? 1 : 0;
233 event.key.keycode = keycode;
234
235 return xenfb_kbd_event(xenfb, &event);
236}
237
238
239static int xenfb_send_motion(struct XenInput *xenfb,
240 int rel_x, int rel_y, int rel_z)
241{
242 union xenkbd_in_event event;
243
244 memset(&event, 0, XENKBD_IN_EVENT_SIZE);
245 event.type = XENKBD_TYPE_MOTION;
246 event.motion.rel_x = rel_x;
247 event.motion.rel_y = rel_y;
248#if __XEN_LATEST_INTERFACE_VERSION__ >= 0x00030207
249 event.motion.rel_z = rel_z;
250#endif
251
252 return xenfb_kbd_event(xenfb, &event);
253}
254
255
256static int xenfb_send_position(struct XenInput *xenfb,
257 int abs_x, int abs_y, int z)
258{
259 union xenkbd_in_event event;
260
261 memset(&event, 0, XENKBD_IN_EVENT_SIZE);
262 event.type = XENKBD_TYPE_POS;
263 event.pos.abs_x = abs_x;
264 event.pos.abs_y = abs_y;
265#if __XEN_LATEST_INTERFACE_VERSION__ == 0x00030207
266 event.pos.abs_z = z;
267#endif
268#if __XEN_LATEST_INTERFACE_VERSION__ >= 0x00030208
269 event.pos.rel_z = z;
270#endif
271
272 return xenfb_kbd_event(xenfb, &event);
273}
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289static void xenfb_key_event(void *opaque, int scancode)
290{
291 struct XenInput *xenfb = opaque;
292 int down = 1;
293
294 if (scancode == 0xe0) {
295 xenfb->extended = 1;
296 return;
297 } else if (scancode & 0x80) {
298 scancode &= 0x7f;
299 down = 0;
300 }
301 if (xenfb->extended) {
302 scancode |= 0x80;
303 xenfb->extended = 0;
304 }
305 xenfb_send_key(xenfb, down, scancode2linux[scancode]);
306}
307
308
309
310
311
312
313
314
315
316
317static void xenfb_mouse_event(void *opaque,
318 int dx, int dy, int dz, int button_state)
319{
320 struct XenInput *xenfb = opaque;
321 int dw = ds_get_width(xenfb->c.ds);
322 int dh = ds_get_height(xenfb->c.ds);
323 int i;
324
325 if (xenfb->abs_pointer_wanted)
326 xenfb_send_position(xenfb,
327 dx * (dw - 1) / 0x7fff,
328 dy * (dh - 1) / 0x7fff,
329 dz);
330 else
331 xenfb_send_motion(xenfb, dx, dy, dz);
332
333 for (i = 0 ; i < 8 ; i++) {
334 int lastDown = xenfb->button_state & (1 << i);
335 int down = button_state & (1 << i);
336 if (down == lastDown)
337 continue;
338
339 if (xenfb_send_key(xenfb, down, BTN_LEFT+i) < 0)
340 return;
341 }
342 xenfb->button_state = button_state;
343}
344
345static int input_init(struct XenDevice *xendev)
346{
347 xenstore_write_be_int(xendev, "feature-abs-pointer", 1);
348 return 0;
349}
350
351static int input_initialise(struct XenDevice *xendev)
352{
353 struct XenInput *in = container_of(xendev, struct XenInput, c.xendev);
354 int rc;
355
356 if (!in->c.ds) {
357 char *vfb = xenstore_read_str(NULL, "device/vfb");
358 if (vfb == NULL) {
359
360 in->c.ds = get_displaystate();
361 } else {
362 g_free(vfb);
363 xen_be_printf(xendev, 1, "ds not set (yet)\n");
364 return -1;
365 }
366 }
367
368 rc = common_bind(&in->c);
369 if (rc != 0)
370 return rc;
371
372 qemu_add_kbd_event_handler(xenfb_key_event, in);
373 return 0;
374}
375
376static void input_connected(struct XenDevice *xendev)
377{
378 struct XenInput *in = container_of(xendev, struct XenInput, c.xendev);
379
380 if (xenstore_read_fe_int(xendev, "request-abs-pointer",
381 &in->abs_pointer_wanted) == -1) {
382 in->abs_pointer_wanted = 0;
383 }
384
385 if (in->qmouse) {
386 qemu_remove_mouse_event_handler(in->qmouse);
387 }
388 in->qmouse = qemu_add_mouse_event_handler(xenfb_mouse_event, in,
389 in->abs_pointer_wanted,
390 "Xen PVFB Mouse");
391}
392
393static void input_disconnect(struct XenDevice *xendev)
394{
395 struct XenInput *in = container_of(xendev, struct XenInput, c.xendev);
396
397 if (in->qmouse) {
398 qemu_remove_mouse_event_handler(in->qmouse);
399 in->qmouse = NULL;
400 }
401 qemu_add_kbd_event_handler(NULL, NULL);
402 common_unbind(&in->c);
403}
404
405static void input_event(struct XenDevice *xendev)
406{
407 struct XenInput *xenfb = container_of(xendev, struct XenInput, c.xendev);
408 struct xenkbd_page *page = xenfb->c.page;
409
410
411 if (page->out_prod == page->out_cons)
412 return;
413 page->out_cons = page->out_prod;
414 xen_be_send_notify(&xenfb->c.xendev);
415}
416
417
418
419static void xenfb_copy_mfns(int mode, int count, unsigned long *dst, void *src)
420{
421 uint32_t *src32 = src;
422 uint64_t *src64 = src;
423 int i;
424
425 for (i = 0; i < count; i++)
426 dst[i] = (mode == 32) ? src32[i] : src64[i];
427}
428
429static int xenfb_map_fb(struct XenFB *xenfb)
430{
431 struct xenfb_page *page = xenfb->c.page;
432 char *protocol = xenfb->c.xendev.protocol;
433 int n_fbdirs;
434 unsigned long *pgmfns = NULL;
435 unsigned long *fbmfns = NULL;
436 void *map, *pd;
437 int mode, ret = -1;
438
439
440 pd = page->pd;
441 mode = sizeof(unsigned long) * 8;
442
443 if (!protocol) {
444
445
446
447
448
449
450
451
452
453 uint32_t *ptr32 = NULL;
454 uint32_t *ptr64 = NULL;
455#if defined(__i386__)
456 ptr32 = (void*)page->pd;
457 ptr64 = ((void*)page->pd) + 4;
458#elif defined(__x86_64__)
459 ptr32 = ((void*)page->pd) - 4;
460 ptr64 = (void*)page->pd;
461#endif
462 if (ptr32) {
463 if (ptr32[1] == 0) {
464 mode = 32;
465 pd = ptr32;
466 } else {
467 mode = 64;
468 pd = ptr64;
469 }
470 }
471#if defined(__x86_64__)
472 } else if (strcmp(protocol, XEN_IO_PROTO_ABI_X86_32) == 0) {
473
474 mode = 32;
475 pd = ((void*)page->pd) - 4;
476#elif defined(__i386__)
477 } else if (strcmp(protocol, XEN_IO_PROTO_ABI_X86_64) == 0) {
478
479 mode = 64;
480 pd = ((void*)page->pd) + 4;
481#endif
482 }
483
484 if (xenfb->pixels) {
485 munmap(xenfb->pixels, xenfb->fbpages * XC_PAGE_SIZE);
486 xenfb->pixels = NULL;
487 }
488
489 xenfb->fbpages = (xenfb->fb_len + (XC_PAGE_SIZE - 1)) / XC_PAGE_SIZE;
490 n_fbdirs = xenfb->fbpages * mode / 8;
491 n_fbdirs = (n_fbdirs + (XC_PAGE_SIZE - 1)) / XC_PAGE_SIZE;
492
493 pgmfns = g_malloc0(sizeof(unsigned long) * n_fbdirs);
494 fbmfns = g_malloc0(sizeof(unsigned long) * xenfb->fbpages);
495
496 xenfb_copy_mfns(mode, n_fbdirs, pgmfns, pd);
497 map = xc_map_foreign_pages(xen_xc, xenfb->c.xendev.dom,
498 PROT_READ, pgmfns, n_fbdirs);
499 if (map == NULL)
500 goto out;
501 xenfb_copy_mfns(mode, xenfb->fbpages, fbmfns, map);
502 munmap(map, n_fbdirs * XC_PAGE_SIZE);
503
504 xenfb->pixels = xc_map_foreign_pages(xen_xc, xenfb->c.xendev.dom,
505 PROT_READ | PROT_WRITE, fbmfns, xenfb->fbpages);
506 if (xenfb->pixels == NULL)
507 goto out;
508
509 ret = 0;
510
511out:
512 g_free(pgmfns);
513 g_free(fbmfns);
514 return ret;
515}
516
517static int xenfb_configure_fb(struct XenFB *xenfb, size_t fb_len_lim,
518 int width, int height, int depth,
519 size_t fb_len, int offset, int row_stride)
520{
521 size_t mfn_sz = sizeof(*((struct xenfb_page *)0)->pd);
522 size_t pd_len = sizeof(((struct xenfb_page *)0)->pd) / mfn_sz;
523 size_t fb_pages = pd_len * XC_PAGE_SIZE / mfn_sz;
524 size_t fb_len_max = fb_pages * XC_PAGE_SIZE;
525 int max_width, max_height;
526
527 if (fb_len_lim > fb_len_max) {
528 xen_be_printf(&xenfb->c.xendev, 0, "fb size limit %zu exceeds %zu, corrected\n",
529 fb_len_lim, fb_len_max);
530 fb_len_lim = fb_len_max;
531 }
532 if (fb_len_lim && fb_len > fb_len_lim) {
533 xen_be_printf(&xenfb->c.xendev, 0, "frontend fb size %zu limited to %zu\n",
534 fb_len, fb_len_lim);
535 fb_len = fb_len_lim;
536 }
537 if (depth != 8 && depth != 16 && depth != 24 && depth != 32) {
538 xen_be_printf(&xenfb->c.xendev, 0, "can't handle frontend fb depth %d\n",
539 depth);
540 return -1;
541 }
542 if (row_stride <= 0 || row_stride > fb_len) {
543 xen_be_printf(&xenfb->c.xendev, 0, "invalid frontend stride %d\n", row_stride);
544 return -1;
545 }
546 max_width = row_stride / (depth / 8);
547 if (width < 0 || width > max_width) {
548 xen_be_printf(&xenfb->c.xendev, 0, "invalid frontend width %d limited to %d\n",
549 width, max_width);
550 width = max_width;
551 }
552 if (offset < 0 || offset >= fb_len) {
553 xen_be_printf(&xenfb->c.xendev, 0, "invalid frontend offset %d (max %zu)\n",
554 offset, fb_len - 1);
555 return -1;
556 }
557 max_height = (fb_len - offset) / row_stride;
558 if (height < 0 || height > max_height) {
559 xen_be_printf(&xenfb->c.xendev, 0, "invalid frontend height %d limited to %d\n",
560 height, max_height);
561 height = max_height;
562 }
563 xenfb->fb_len = fb_len;
564 xenfb->row_stride = row_stride;
565 xenfb->depth = depth;
566 xenfb->width = width;
567 xenfb->height = height;
568 xenfb->offset = offset;
569 xenfb->up_fullscreen = 1;
570 xenfb->do_resize = 1;
571 xen_be_printf(&xenfb->c.xendev, 1, "framebuffer %dx%dx%d offset %d stride %d\n",
572 width, height, depth, offset, row_stride);
573 return 0;
574}
575
576
577#define BLT(SRC_T,DST_T,RSB,GSB,BSB,RDB,GDB,BDB) \
578 for (line = y ; line < (y+h) ; line++) { \
579 SRC_T *src = (SRC_T *)(xenfb->pixels \
580 + xenfb->offset \
581 + (line * xenfb->row_stride) \
582 + (x * xenfb->depth / 8)); \
583 DST_T *dst = (DST_T *)(data \
584 + (line * linesize) \
585 + (x * bpp / 8)); \
586 int col; \
587 const int RSS = 32 - (RSB + GSB + BSB); \
588 const int GSS = 32 - (GSB + BSB); \
589 const int BSS = 32 - (BSB); \
590 const uint32_t RSM = (~0U) << (32 - RSB); \
591 const uint32_t GSM = (~0U) << (32 - GSB); \
592 const uint32_t BSM = (~0U) << (32 - BSB); \
593 const int RDS = 32 - (RDB + GDB + BDB); \
594 const int GDS = 32 - (GDB + BDB); \
595 const int BDS = 32 - (BDB); \
596 const uint32_t RDM = (~0U) << (32 - RDB); \
597 const uint32_t GDM = (~0U) << (32 - GDB); \
598 const uint32_t BDM = (~0U) << (32 - BDB); \
599 for (col = x ; col < (x+w) ; col++) { \
600 uint32_t spix = *src; \
601 *dst = (((spix << RSS) & RSM & RDM) >> RDS) | \
602 (((spix << GSS) & GSM & GDM) >> GDS) | \
603 (((spix << BSS) & BSM & BDM) >> BDS); \
604 src = (SRC_T *) ((unsigned long) src + xenfb->depth / 8); \
605 dst = (DST_T *) ((unsigned long) dst + bpp / 8); \
606 } \
607 }
608
609
610
611
612
613
614
615
616static void xenfb_guest_copy(struct XenFB *xenfb, int x, int y, int w, int h)
617{
618 int line, oops = 0;
619 int bpp = ds_get_bits_per_pixel(xenfb->c.ds);
620 int linesize = ds_get_linesize(xenfb->c.ds);
621 uint8_t *data = ds_get_data(xenfb->c.ds);
622
623 if (!is_buffer_shared(xenfb->c.ds->surface)) {
624 switch (xenfb->depth) {
625 case 8:
626 if (bpp == 16) {
627 BLT(uint8_t, uint16_t, 3, 3, 2, 5, 6, 5);
628 } else if (bpp == 32) {
629 BLT(uint8_t, uint32_t, 3, 3, 2, 8, 8, 8);
630 } else {
631 oops = 1;
632 }
633 break;
634 case 24:
635 if (bpp == 16) {
636 BLT(uint32_t, uint16_t, 8, 8, 8, 5, 6, 5);
637 } else if (bpp == 32) {
638 BLT(uint32_t, uint32_t, 8, 8, 8, 8, 8, 8);
639 } else {
640 oops = 1;
641 }
642 break;
643 default:
644 oops = 1;
645 }
646 }
647 if (oops)
648 xen_be_printf(&xenfb->c.xendev, 0, "%s: oops: convert %d -> %d bpp?\n",
649 __FUNCTION__, xenfb->depth, bpp);
650
651 dpy_update(xenfb->c.ds, x, y, w, h);
652}
653
654#ifdef XENFB_TYPE_REFRESH_PERIOD
655static int xenfb_queue_full(struct XenFB *xenfb)
656{
657 struct xenfb_page *page = xenfb->c.page;
658 uint32_t cons, prod;
659
660 if (!page)
661 return 1;
662
663 prod = page->in_prod;
664 cons = page->in_cons;
665 return prod - cons == XENFB_IN_RING_LEN;
666}
667
668static void xenfb_send_event(struct XenFB *xenfb, union xenfb_in_event *event)
669{
670 uint32_t prod;
671 struct xenfb_page *page = xenfb->c.page;
672
673 prod = page->in_prod;
674
675 xen_mb();
676 XENFB_IN_RING_REF(page, prod) = *event;
677 xen_wmb();
678 page->in_prod = prod + 1;
679
680 xen_be_send_notify(&xenfb->c.xendev);
681}
682
683static void xenfb_send_refresh_period(struct XenFB *xenfb, int period)
684{
685 union xenfb_in_event event;
686
687 memset(&event, 0, sizeof(event));
688 event.type = XENFB_TYPE_REFRESH_PERIOD;
689 event.refresh_period.period = period;
690 xenfb_send_event(xenfb, &event);
691}
692#endif
693
694
695
696
697
698
699
700
701
702
703static void xenfb_update(void *opaque)
704{
705 struct XenFB *xenfb = opaque;
706 int i;
707
708 if (xenfb->c.xendev.be_state != XenbusStateConnected)
709 return;
710
711 if (xenfb->feature_update) {
712#ifdef XENFB_TYPE_REFRESH_PERIOD
713 struct DisplayChangeListener *l;
714 int period = 99999999;
715 int idle = 1;
716
717 if (xenfb_queue_full(xenfb))
718 return;
719
720 for (l = xenfb->c.ds->listeners; l != NULL; l = l->next) {
721 if (l->idle)
722 continue;
723 idle = 0;
724 if (!l->gui_timer_interval) {
725 if (period > GUI_REFRESH_INTERVAL)
726 period = GUI_REFRESH_INTERVAL;
727 } else {
728 if (period > l->gui_timer_interval)
729 period = l->gui_timer_interval;
730 }
731 }
732 if (idle)
733 period = XENFB_NO_REFRESH;
734
735 if (xenfb->refresh_period != period) {
736 xenfb_send_refresh_period(xenfb, period);
737 xenfb->refresh_period = period;
738 xen_be_printf(&xenfb->c.xendev, 1, "refresh period: %d\n", period);
739 }
740#else
741 ;
742#endif
743 } else {
744
745
746 xenfb->up_fullscreen = 1;
747 }
748
749
750 if (xenfb->do_resize) {
751 xenfb->do_resize = 0;
752 switch (xenfb->depth) {
753 case 16:
754 case 32:
755
756 qemu_free_displaysurface(xenfb->c.ds);
757 xenfb->c.ds->surface = qemu_create_displaysurface_from
758 (xenfb->width, xenfb->height, xenfb->depth,
759 xenfb->row_stride, xenfb->pixels + xenfb->offset);
760 break;
761 default:
762
763 qemu_resize_displaysurface(xenfb->c.ds, xenfb->width, xenfb->height);
764 break;
765 }
766 xen_be_printf(&xenfb->c.xendev, 1, "update: resizing: %dx%d @ %d bpp%s\n",
767 xenfb->width, xenfb->height, xenfb->depth,
768 is_buffer_shared(xenfb->c.ds->surface) ? " (shared)" : "");
769 dpy_resize(xenfb->c.ds);
770 xenfb->up_fullscreen = 1;
771 }
772
773
774 if (xenfb->up_fullscreen) {
775 xen_be_printf(&xenfb->c.xendev, 3, "update: fullscreen\n");
776 xenfb_guest_copy(xenfb, 0, 0, xenfb->width, xenfb->height);
777 } else if (xenfb->up_count) {
778 xen_be_printf(&xenfb->c.xendev, 3, "update: %d rects\n", xenfb->up_count);
779 for (i = 0; i < xenfb->up_count; i++)
780 xenfb_guest_copy(xenfb,
781 xenfb->up_rects[i].x,
782 xenfb->up_rects[i].y,
783 xenfb->up_rects[i].w,
784 xenfb->up_rects[i].h);
785 } else {
786 xen_be_printf(&xenfb->c.xendev, 3, "update: nothing\n");
787 }
788 xenfb->up_count = 0;
789 xenfb->up_fullscreen = 0;
790}
791
792
793static void xenfb_invalidate(void *opaque)
794{
795 struct XenFB *xenfb = opaque;
796 xenfb->up_fullscreen = 1;
797}
798
799static void xenfb_handle_events(struct XenFB *xenfb)
800{
801 uint32_t prod, cons;
802 struct xenfb_page *page = xenfb->c.page;
803
804 prod = page->out_prod;
805 if (prod == page->out_cons)
806 return;
807 xen_rmb();
808 for (cons = page->out_cons; cons != prod; cons++) {
809 union xenfb_out_event *event = &XENFB_OUT_RING_REF(page, cons);
810 int x, y, w, h;
811
812 switch (event->type) {
813 case XENFB_TYPE_UPDATE:
814 if (xenfb->up_count == UP_QUEUE)
815 xenfb->up_fullscreen = 1;
816 if (xenfb->up_fullscreen)
817 break;
818 x = MAX(event->update.x, 0);
819 y = MAX(event->update.y, 0);
820 w = MIN(event->update.width, xenfb->width - x);
821 h = MIN(event->update.height, xenfb->height - y);
822 if (w < 0 || h < 0) {
823 xen_be_printf(&xenfb->c.xendev, 1, "bogus update ignored\n");
824 break;
825 }
826 if (x != event->update.x ||
827 y != event->update.y ||
828 w != event->update.width ||
829 h != event->update.height) {
830 xen_be_printf(&xenfb->c.xendev, 1, "bogus update clipped\n");
831 }
832 if (w == xenfb->width && h > xenfb->height / 2) {
833
834
835 xenfb->up_fullscreen = 1;
836 } else {
837 xenfb->up_rects[xenfb->up_count].x = x;
838 xenfb->up_rects[xenfb->up_count].y = y;
839 xenfb->up_rects[xenfb->up_count].w = w;
840 xenfb->up_rects[xenfb->up_count].h = h;
841 xenfb->up_count++;
842 }
843 break;
844#ifdef XENFB_TYPE_RESIZE
845 case XENFB_TYPE_RESIZE:
846 if (xenfb_configure_fb(xenfb, xenfb->fb_len,
847 event->resize.width,
848 event->resize.height,
849 event->resize.depth,
850 xenfb->fb_len,
851 event->resize.offset,
852 event->resize.stride) < 0)
853 break;
854 xenfb_invalidate(xenfb);
855 break;
856#endif
857 }
858 }
859 xen_mb();
860 page->out_cons = cons;
861}
862
863static int fb_init(struct XenDevice *xendev)
864{
865 struct XenFB *fb = container_of(xendev, struct XenFB, c.xendev);
866
867 fb->refresh_period = -1;
868
869#ifdef XENFB_TYPE_RESIZE
870 xenstore_write_be_int(xendev, "feature-resize", 1);
871#endif
872 return 0;
873}
874
875static int fb_initialise(struct XenDevice *xendev)
876{
877 struct XenFB *fb = container_of(xendev, struct XenFB, c.xendev);
878 struct xenfb_page *fb_page;
879 int videoram;
880 int rc;
881
882 if (xenstore_read_fe_int(xendev, "videoram", &videoram) == -1)
883 videoram = 0;
884
885 rc = common_bind(&fb->c);
886 if (rc != 0)
887 return rc;
888
889 fb_page = fb->c.page;
890 rc = xenfb_configure_fb(fb, videoram * 1024 * 1024U,
891 fb_page->width, fb_page->height, fb_page->depth,
892 fb_page->mem_length, 0, fb_page->line_length);
893 if (rc != 0)
894 return rc;
895
896 rc = xenfb_map_fb(fb);
897 if (rc != 0)
898 return rc;
899
900#if 0
901 if (!fb->have_console) {
902 fb->c.ds = graphic_console_init(xenfb_update,
903 xenfb_invalidate,
904 NULL,
905 NULL,
906 fb);
907 fb->have_console = 1;
908 }
909#endif
910
911 if (xenstore_read_fe_int(xendev, "feature-update", &fb->feature_update) == -1)
912 fb->feature_update = 0;
913 if (fb->feature_update)
914 xenstore_write_be_int(xendev, "request-update", 1);
915
916 xen_be_printf(xendev, 1, "feature-update=%d, videoram=%d\n",
917 fb->feature_update, videoram);
918 return 0;
919}
920
921static void fb_disconnect(struct XenDevice *xendev)
922{
923 struct XenFB *fb = container_of(xendev, struct XenFB, c.xendev);
924
925
926
927
928
929
930 fb->pixels = mmap(fb->pixels, fb->fbpages * XC_PAGE_SIZE,
931 PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANON,
932 -1, 0);
933 common_unbind(&fb->c);
934 fb->feature_update = 0;
935 fb->bug_trigger = 0;
936}
937
938static void fb_frontend_changed(struct XenDevice *xendev, const char *node)
939{
940 struct XenFB *fb = container_of(xendev, struct XenFB, c.xendev);
941
942
943
944
945
946
947 if (fb->bug_trigger == 0 && strcmp(node, "state") == 0 &&
948 xendev->fe_state == XenbusStateConnected &&
949 xendev->be_state == XenbusStateConnected) {
950 xen_be_printf(xendev, 2, "re-trigger connected (frontend bug)\n");
951 xen_be_set_state(xendev, XenbusStateConnected);
952 fb->bug_trigger = 1;
953 }
954}
955
956static void fb_event(struct XenDevice *xendev)
957{
958 struct XenFB *xenfb = container_of(xendev, struct XenFB, c.xendev);
959
960 xenfb_handle_events(xenfb);
961 xen_be_send_notify(&xenfb->c.xendev);
962}
963
964
965
966struct XenDevOps xen_kbdmouse_ops = {
967 .size = sizeof(struct XenInput),
968 .init = input_init,
969 .initialise = input_initialise,
970 .connected = input_connected,
971 .disconnect = input_disconnect,
972 .event = input_event,
973};
974
975struct XenDevOps xen_framebuffer_ops = {
976 .size = sizeof(struct XenFB),
977 .init = fb_init,
978 .initialise = fb_initialise,
979 .disconnect = fb_disconnect,
980 .event = fb_event,
981 .frontend_changed = fb_frontend_changed,
982};
983
984
985
986
987
988void xen_init_display(int domid)
989{
990 struct XenDevice *xfb, *xin;
991 struct XenFB *fb;
992 struct XenInput *in;
993 int i = 0;
994
995wait_more:
996 i++;
997 main_loop_wait(true);
998 xfb = xen_be_find_xendev("vfb", domid, 0);
999 xin = xen_be_find_xendev("vkbd", domid, 0);
1000 if (!xfb || !xin) {
1001 if (i < 256) {
1002 usleep(10000);
1003 goto wait_more;
1004 }
1005 xen_be_printf(NULL, 1, "displaystate setup failed\n");
1006 return;
1007 }
1008
1009
1010 fb = container_of(xfb, struct XenFB, c.xendev);
1011 fb->c.ds = graphic_console_init(xenfb_update,
1012 xenfb_invalidate,
1013 NULL,
1014 NULL,
1015 fb);
1016 fb->have_console = 1;
1017
1018
1019 in = container_of(xin, struct XenInput, c.xendev);
1020 in->c.ds = fb->c.ds;
1021
1022
1023 xen_be_check_state(xin);
1024 xen_be_check_state(xfb);
1025}
1026