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 xenfb_send_key(xenfb, down, scancode2linux[scancode]);
294}
295
296
297
298
299
300
301
302
303
304
305static void xenfb_mouse_event(void *opaque,
306 int dx, int dy, int dz, int button_state)
307{
308 struct XenInput *xenfb = opaque;
309 QemuConsole *con = qemu_console_lookup_by_index(0);
310 DisplaySurface *surface;
311 int dw, dh, i;
312
313 if (!con) {
314 xen_pv_printf(&xenfb->c.xendev, 0, "No QEMU console available");
315 return;
316 }
317
318 surface = qemu_console_surface(con);
319 dw = surface_width(surface);
320 dh = surface_height(surface);
321
322 trace_xenfb_mouse_event(opaque, dx, dy, dz, button_state,
323 xenfb->abs_pointer_wanted);
324 if (xenfb->abs_pointer_wanted)
325 xenfb_send_position(xenfb,
326 dx * (dw - 1) / 0x7fff,
327 dy * (dh - 1) / 0x7fff,
328 dz);
329 else
330 xenfb_send_motion(xenfb, dx, dy, dz);
331
332 for (i = 0 ; i < 8 ; i++) {
333 int lastDown = xenfb->button_state & (1 << i);
334 int down = button_state & (1 << i);
335 if (down == lastDown)
336 continue;
337
338 if (xenfb_send_key(xenfb, down, BTN_LEFT+i) < 0)
339 return;
340 }
341 xenfb->button_state = button_state;
342}
343
344static int input_init(struct XenDevice *xendev)
345{
346 xenstore_write_be_int(xendev, "feature-abs-pointer", 1);
347 return 0;
348}
349
350static int input_initialise(struct XenDevice *xendev)
351{
352 struct XenInput *in = container_of(xendev, struct XenInput, c.xendev);
353 int rc;
354
355 rc = common_bind(&in->c);
356 if (rc != 0)
357 return rc;
358
359 qemu_add_kbd_event_handler(xenfb_key_event, in);
360 return 0;
361}
362
363static void input_connected(struct XenDevice *xendev)
364{
365 struct XenInput *in = container_of(xendev, struct XenInput, c.xendev);
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
372 if (in->qmouse) {
373 qemu_remove_mouse_event_handler(in->qmouse);
374 }
375 trace_xenfb_input_connected(xendev, in->abs_pointer_wanted);
376 in->qmouse = qemu_add_mouse_event_handler(xenfb_mouse_event, in,
377 in->abs_pointer_wanted,
378 "Xen PVFB Mouse");
379}
380
381static void input_disconnect(struct XenDevice *xendev)
382{
383 struct XenInput *in = container_of(xendev, struct XenInput, c.xendev);
384
385 if (in->qmouse) {
386 qemu_remove_mouse_event_handler(in->qmouse);
387 in->qmouse = NULL;
388 }
389 qemu_add_kbd_event_handler(NULL, NULL);
390 common_unbind(&in->c);
391}
392
393static void input_event(struct XenDevice *xendev)
394{
395 struct XenInput *xenfb = container_of(xendev, struct XenInput, c.xendev);
396 struct xenkbd_page *page = xenfb->c.page;
397
398
399 if (page->out_prod == page->out_cons)
400 return;
401 page->out_cons = page->out_prod;
402 xen_pv_send_notify(&xenfb->c.xendev);
403}
404
405
406
407static void xenfb_copy_mfns(int mode, int count, xen_pfn_t *dst, void *src)
408{
409 uint32_t *src32 = src;
410 uint64_t *src64 = src;
411 int i;
412
413 for (i = 0; i < count; i++)
414 dst[i] = (mode == 32) ? src32[i] : src64[i];
415}
416
417static int xenfb_map_fb(struct XenFB *xenfb)
418{
419 struct xenfb_page *page = xenfb->c.page;
420 char *protocol = xenfb->c.xendev.protocol;
421 int n_fbdirs;
422 xen_pfn_t *pgmfns = NULL;
423 xen_pfn_t *fbmfns = NULL;
424 void *map, *pd;
425 int mode, ret = -1;
426
427
428 pd = page->pd;
429 mode = sizeof(unsigned long) * 8;
430
431 if (!protocol) {
432
433
434
435
436
437
438
439
440
441 uint32_t *ptr32 = NULL;
442 uint32_t *ptr64 = NULL;
443#if defined(__i386__)
444 ptr32 = (void*)page->pd;
445 ptr64 = ((void*)page->pd) + 4;
446#elif defined(__x86_64__)
447 ptr32 = ((void*)page->pd) - 4;
448 ptr64 = (void*)page->pd;
449#endif
450 if (ptr32) {
451 if (ptr32[1] == 0) {
452 mode = 32;
453 pd = ptr32;
454 } else {
455 mode = 64;
456 pd = ptr64;
457 }
458 }
459#if defined(__x86_64__)
460 } else if (strcmp(protocol, XEN_IO_PROTO_ABI_X86_32) == 0) {
461
462 mode = 32;
463 pd = ((void*)page->pd) - 4;
464#elif defined(__i386__)
465 } else if (strcmp(protocol, XEN_IO_PROTO_ABI_X86_64) == 0) {
466
467 mode = 64;
468 pd = ((void*)page->pd) + 4;
469#endif
470 }
471
472 if (xenfb->pixels) {
473 munmap(xenfb->pixels, xenfb->fbpages * XC_PAGE_SIZE);
474 xenfb->pixels = NULL;
475 }
476
477 xenfb->fbpages = DIV_ROUND_UP(xenfb->fb_len, XC_PAGE_SIZE);
478 n_fbdirs = xenfb->fbpages * mode / 8;
479 n_fbdirs = DIV_ROUND_UP(n_fbdirs, XC_PAGE_SIZE);
480
481 pgmfns = g_malloc0(sizeof(xen_pfn_t) * n_fbdirs);
482 fbmfns = g_malloc0(sizeof(xen_pfn_t) * xenfb->fbpages);
483
484 xenfb_copy_mfns(mode, n_fbdirs, pgmfns, pd);
485 map = xenforeignmemory_map(xen_fmem, xenfb->c.xendev.dom,
486 PROT_READ, n_fbdirs, pgmfns, NULL);
487 if (map == NULL)
488 goto out;
489 xenfb_copy_mfns(mode, xenfb->fbpages, fbmfns, map);
490 xenforeignmemory_unmap(xen_fmem, map, n_fbdirs);
491
492 xenfb->pixels = xenforeignmemory_map(xen_fmem, xenfb->c.xendev.dom,
493 PROT_READ, xenfb->fbpages, fbmfns, NULL);
494 if (xenfb->pixels == NULL)
495 goto out;
496
497 ret = 0;
498
499out:
500 g_free(pgmfns);
501 g_free(fbmfns);
502 return ret;
503}
504
505static int xenfb_configure_fb(struct XenFB *xenfb, size_t fb_len_lim,
506 int width, int height, int depth,
507 size_t fb_len, int offset, int row_stride)
508{
509 size_t mfn_sz = sizeof(*((struct xenfb_page *)0)->pd);
510 size_t pd_len = sizeof(((struct xenfb_page *)0)->pd) / mfn_sz;
511 size_t fb_pages = pd_len * XC_PAGE_SIZE / mfn_sz;
512 size_t fb_len_max = fb_pages * XC_PAGE_SIZE;
513 int max_width, max_height;
514
515 if (fb_len_lim > fb_len_max) {
516 xen_pv_printf(&xenfb->c.xendev, 0,
517 "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_pv_printf(&xenfb->c.xendev, 0,
523 "frontend fb size %zu limited to %zu\n",
524 fb_len, fb_len_lim);
525 fb_len = fb_len_lim;
526 }
527 if (depth != 8 && depth != 16 && depth != 24 && depth != 32) {
528 xen_pv_printf(&xenfb->c.xendev, 0,
529 "can't handle frontend fb depth %d\n",
530 depth);
531 return -1;
532 }
533 if (row_stride <= 0 || row_stride > fb_len) {
534 xen_pv_printf(&xenfb->c.xendev, 0, "invalid frontend stride %d\n",
535 row_stride);
536 return -1;
537 }
538 max_width = row_stride / (depth / 8);
539 if (width < 0 || width > max_width) {
540 xen_pv_printf(&xenfb->c.xendev, 0,
541 "invalid frontend width %d limited to %d\n",
542 width, max_width);
543 width = max_width;
544 }
545 if (offset < 0 || offset >= fb_len) {
546 xen_pv_printf(&xenfb->c.xendev, 0,
547 "invalid frontend offset %d (max %zu)\n",
548 offset, fb_len - 1);
549 return -1;
550 }
551 max_height = (fb_len - offset) / row_stride;
552 if (height < 0 || height > max_height) {
553 xen_pv_printf(&xenfb->c.xendev, 0,
554 "invalid frontend height %d limited to %d\n",
555 height, max_height);
556 height = max_height;
557 }
558 xenfb->fb_len = fb_len;
559 xenfb->row_stride = row_stride;
560 xenfb->depth = depth;
561 xenfb->width = width;
562 xenfb->height = height;
563 xenfb->offset = offset;
564 xenfb->up_fullscreen = 1;
565 xenfb->do_resize = 1;
566 xen_pv_printf(&xenfb->c.xendev, 1,
567 "framebuffer %dx%dx%d offset %d stride %d\n",
568 width, height, depth, offset, row_stride);
569 return 0;
570}
571
572
573#define BLT(SRC_T,DST_T,RSB,GSB,BSB,RDB,GDB,BDB) \
574 for (line = y ; line < (y+h) ; line++) { \
575 SRC_T *src = (SRC_T *)(xenfb->pixels \
576 + xenfb->offset \
577 + (line * xenfb->row_stride) \
578 + (x * xenfb->depth / 8)); \
579 DST_T *dst = (DST_T *)(data \
580 + (line * linesize) \
581 + (x * bpp / 8)); \
582 int col; \
583 const int RSS = 32 - (RSB + GSB + BSB); \
584 const int GSS = 32 - (GSB + BSB); \
585 const int BSS = 32 - (BSB); \
586 const uint32_t RSM = (~0U) << (32 - RSB); \
587 const uint32_t GSM = (~0U) << (32 - GSB); \
588 const uint32_t BSM = (~0U) << (32 - BSB); \
589 const int RDS = 32 - (RDB + GDB + BDB); \
590 const int GDS = 32 - (GDB + BDB); \
591 const int BDS = 32 - (BDB); \
592 const uint32_t RDM = (~0U) << (32 - RDB); \
593 const uint32_t GDM = (~0U) << (32 - GDB); \
594 const uint32_t BDM = (~0U) << (32 - BDB); \
595 for (col = x ; col < (x+w) ; col++) { \
596 uint32_t spix = *src; \
597 *dst = (((spix << RSS) & RSM & RDM) >> RDS) | \
598 (((spix << GSS) & GSM & GDM) >> GDS) | \
599 (((spix << BSS) & BSM & BDM) >> BDS); \
600 src = (SRC_T *) ((unsigned long) src + xenfb->depth / 8); \
601 dst = (DST_T *) ((unsigned long) dst + bpp / 8); \
602 } \
603 }
604
605
606
607
608
609
610
611
612static void xenfb_guest_copy(struct XenFB *xenfb, int x, int y, int w, int h)
613{
614 DisplaySurface *surface = qemu_console_surface(xenfb->con);
615 int line, oops = 0;
616 int bpp = surface_bits_per_pixel(surface);
617 int linesize = surface_stride(surface);
618 uint8_t *data = surface_data(surface);
619
620 if (!is_buffer_shared(surface)) {
621 switch (xenfb->depth) {
622 case 8:
623 if (bpp == 16) {
624 BLT(uint8_t, uint16_t, 3, 3, 2, 5, 6, 5);
625 } else if (bpp == 32) {
626 BLT(uint8_t, uint32_t, 3, 3, 2, 8, 8, 8);
627 } else {
628 oops = 1;
629 }
630 break;
631 case 24:
632 if (bpp == 16) {
633 BLT(uint32_t, uint16_t, 8, 8, 8, 5, 6, 5);
634 } else if (bpp == 32) {
635 BLT(uint32_t, uint32_t, 8, 8, 8, 8, 8, 8);
636 } else {
637 oops = 1;
638 }
639 break;
640 default:
641 oops = 1;
642 }
643 }
644 if (oops)
645 xen_pv_printf(&xenfb->c.xendev, 0, "%s: oops: convert %d -> %d bpp?\n",
646 __FUNCTION__, xenfb->depth, bpp);
647
648 dpy_gfx_update(xenfb->con, x, y, w, h);
649}
650
651#ifdef XENFB_TYPE_REFRESH_PERIOD
652static int xenfb_queue_full(struct XenFB *xenfb)
653{
654 struct xenfb_page *page = xenfb->c.page;
655 uint32_t cons, prod;
656
657 if (!page)
658 return 1;
659
660 prod = page->in_prod;
661 cons = page->in_cons;
662 return prod - cons == XENFB_IN_RING_LEN;
663}
664
665static void xenfb_send_event(struct XenFB *xenfb, union xenfb_in_event *event)
666{
667 uint32_t prod;
668 struct xenfb_page *page = xenfb->c.page;
669
670 prod = page->in_prod;
671
672 xen_mb();
673 XENFB_IN_RING_REF(page, prod) = *event;
674 xen_wmb();
675 page->in_prod = prod + 1;
676
677 xen_pv_send_notify(&xenfb->c.xendev);
678}
679
680static void xenfb_send_refresh_period(struct XenFB *xenfb, int period)
681{
682 union xenfb_in_event event;
683
684 memset(&event, 0, sizeof(event));
685 event.type = XENFB_TYPE_REFRESH_PERIOD;
686 event.refresh_period.period = period;
687 xenfb_send_event(xenfb, &event);
688}
689#endif
690
691
692
693
694
695
696
697
698
699
700static void xenfb_update(void *opaque)
701{
702 struct XenFB *xenfb = opaque;
703 DisplaySurface *surface;
704 int i;
705
706 if (xenfb->c.xendev.be_state != XenbusStateConnected)
707 return;
708
709 if (!xenfb->feature_update) {
710
711
712 xenfb->up_fullscreen = 1;
713 }
714
715
716 if (xenfb->do_resize) {
717 pixman_format_code_t format;
718
719 xenfb->do_resize = 0;
720 switch (xenfb->depth) {
721 case 16:
722 case 32:
723
724 format = qemu_default_pixman_format(xenfb->depth, true);
725 surface = qemu_create_displaysurface_from
726 (xenfb->width, xenfb->height, format,
727 xenfb->row_stride, xenfb->pixels + xenfb->offset);
728 break;
729 default:
730
731 surface = qemu_create_displaysurface(xenfb->width, xenfb->height);
732 break;
733 }
734 dpy_gfx_replace_surface(xenfb->con, surface);
735 xen_pv_printf(&xenfb->c.xendev, 1,
736 "update: resizing: %dx%d @ %d bpp%s\n",
737 xenfb->width, xenfb->height, xenfb->depth,
738 is_buffer_shared(surface) ? " (shared)" : "");
739 xenfb->up_fullscreen = 1;
740 }
741
742
743 if (xenfb->up_fullscreen) {
744 xen_pv_printf(&xenfb->c.xendev, 3, "update: fullscreen\n");
745 xenfb_guest_copy(xenfb, 0, 0, xenfb->width, xenfb->height);
746 } else if (xenfb->up_count) {
747 xen_pv_printf(&xenfb->c.xendev, 3, "update: %d rects\n",
748 xenfb->up_count);
749 for (i = 0; i < xenfb->up_count; i++)
750 xenfb_guest_copy(xenfb,
751 xenfb->up_rects[i].x,
752 xenfb->up_rects[i].y,
753 xenfb->up_rects[i].w,
754 xenfb->up_rects[i].h);
755 } else {
756 xen_pv_printf(&xenfb->c.xendev, 3, "update: nothing\n");
757 }
758 xenfb->up_count = 0;
759 xenfb->up_fullscreen = 0;
760}
761
762static void xenfb_update_interval(void *opaque, uint64_t interval)
763{
764 struct XenFB *xenfb = opaque;
765
766 if (xenfb->feature_update) {
767#ifdef XENFB_TYPE_REFRESH_PERIOD
768 if (xenfb_queue_full(xenfb)) {
769 return;
770 }
771 xenfb_send_refresh_period(xenfb, interval);
772#endif
773 }
774}
775
776
777static void xenfb_invalidate(void *opaque)
778{
779 struct XenFB *xenfb = opaque;
780 xenfb->up_fullscreen = 1;
781}
782
783static void xenfb_handle_events(struct XenFB *xenfb)
784{
785 uint32_t prod, cons, out_cons;
786 struct xenfb_page *page = xenfb->c.page;
787
788 prod = page->out_prod;
789 out_cons = page->out_cons;
790 if (prod - out_cons > XENFB_OUT_RING_LEN) {
791 return;
792 }
793 xen_rmb();
794 for (cons = out_cons; cons != prod; cons++) {
795 union xenfb_out_event *event = &XENFB_OUT_RING_REF(page, cons);
796 uint8_t type = event->type;
797 int x, y, w, h;
798
799 switch (type) {
800 case XENFB_TYPE_UPDATE:
801 if (xenfb->up_count == UP_QUEUE)
802 xenfb->up_fullscreen = 1;
803 if (xenfb->up_fullscreen)
804 break;
805 x = MAX(event->update.x, 0);
806 y = MAX(event->update.y, 0);
807 w = MIN(event->update.width, xenfb->width - x);
808 h = MIN(event->update.height, xenfb->height - y);
809 if (w < 0 || h < 0) {
810 xen_pv_printf(&xenfb->c.xendev, 1, "bogus update ignored\n");
811 break;
812 }
813 if (x != event->update.x ||
814 y != event->update.y ||
815 w != event->update.width ||
816 h != event->update.height) {
817 xen_pv_printf(&xenfb->c.xendev, 1, "bogus update clipped\n");
818 }
819 if (w == xenfb->width && h > xenfb->height / 2) {
820
821
822 xenfb->up_fullscreen = 1;
823 } else {
824 xenfb->up_rects[xenfb->up_count].x = x;
825 xenfb->up_rects[xenfb->up_count].y = y;
826 xenfb->up_rects[xenfb->up_count].w = w;
827 xenfb->up_rects[xenfb->up_count].h = h;
828 xenfb->up_count++;
829 }
830 break;
831#ifdef XENFB_TYPE_RESIZE
832 case XENFB_TYPE_RESIZE:
833 if (xenfb_configure_fb(xenfb, xenfb->fb_len,
834 event->resize.width,
835 event->resize.height,
836 event->resize.depth,
837 xenfb->fb_len,
838 event->resize.offset,
839 event->resize.stride) < 0)
840 break;
841 xenfb_invalidate(xenfb);
842 break;
843#endif
844 }
845 }
846 xen_mb();
847 page->out_cons = cons;
848}
849
850static int fb_init(struct XenDevice *xendev)
851{
852#ifdef XENFB_TYPE_RESIZE
853 xenstore_write_be_int(xendev, "feature-resize", 1);
854#endif
855 return 0;
856}
857
858static int fb_initialise(struct XenDevice *xendev)
859{
860 struct XenFB *fb = container_of(xendev, struct XenFB, c.xendev);
861 struct xenfb_page *fb_page;
862 int videoram;
863 int rc;
864
865 if (xenstore_read_fe_int(xendev, "videoram", &videoram) == -1)
866 videoram = 0;
867
868 rc = common_bind(&fb->c);
869 if (rc != 0)
870 return rc;
871
872 fb_page = fb->c.page;
873 rc = xenfb_configure_fb(fb, videoram * 1024 * 1024U,
874 fb_page->width, fb_page->height, fb_page->depth,
875 fb_page->mem_length, 0, fb_page->line_length);
876 if (rc != 0)
877 return rc;
878
879 rc = xenfb_map_fb(fb);
880 if (rc != 0)
881 return rc;
882
883 fb->con = graphic_console_init(NULL, 0, &xenfb_ops, fb);
884
885 if (xenstore_read_fe_int(xendev, "feature-update", &fb->feature_update) == -1)
886 fb->feature_update = 0;
887 if (fb->feature_update)
888 xenstore_write_be_int(xendev, "request-update", 1);
889
890 xen_pv_printf(xendev, 1, "feature-update=%d, videoram=%d\n",
891 fb->feature_update, videoram);
892 return 0;
893}
894
895static void fb_disconnect(struct XenDevice *xendev)
896{
897 struct XenFB *fb = container_of(xendev, struct XenFB, c.xendev);
898
899
900
901
902
903
904 xenforeignmemory_unmap(xen_fmem, fb->pixels, fb->fbpages);
905 fb->pixels = mmap(fb->pixels, fb->fbpages * XC_PAGE_SIZE,
906 PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANON,
907 -1, 0);
908 if (fb->pixels == MAP_FAILED) {
909 xen_pv_printf(xendev, 0,
910 "Couldn't replace the framebuffer with anonymous memory errno=%d\n",
911 errno);
912 }
913 common_unbind(&fb->c);
914 fb->feature_update = 0;
915 fb->bug_trigger = 0;
916}
917
918static void fb_frontend_changed(struct XenDevice *xendev, const char *node)
919{
920 struct XenFB *fb = container_of(xendev, struct XenFB, c.xendev);
921
922
923
924
925
926
927 if (fb->bug_trigger == 0 && strcmp(node, "state") == 0 &&
928 xendev->fe_state == XenbusStateConnected &&
929 xendev->be_state == XenbusStateConnected) {
930 xen_pv_printf(xendev, 2, "re-trigger connected (frontend bug)\n");
931 xen_be_set_state(xendev, XenbusStateConnected);
932 fb->bug_trigger = 1;
933 }
934}
935
936static void fb_event(struct XenDevice *xendev)
937{
938 struct XenFB *xenfb = container_of(xendev, struct XenFB, c.xendev);
939
940 xenfb_handle_events(xenfb);
941 xen_pv_send_notify(&xenfb->c.xendev);
942}
943
944
945
946struct XenDevOps xen_kbdmouse_ops = {
947 .size = sizeof(struct XenInput),
948 .init = input_init,
949 .initialise = input_initialise,
950 .connected = input_connected,
951 .disconnect = input_disconnect,
952 .event = input_event,
953};
954
955struct XenDevOps xen_framebuffer_ops = {
956 .size = sizeof(struct XenFB),
957 .init = fb_init,
958 .initialise = fb_initialise,
959 .disconnect = fb_disconnect,
960 .event = fb_event,
961 .frontend_changed = fb_frontend_changed,
962};
963
964static const GraphicHwOps xenfb_ops = {
965 .invalidate = xenfb_invalidate,
966 .gfx_update = xenfb_update,
967 .update_interval = xenfb_update_interval,
968};
969