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