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