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