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