xen/xen-fbback-resize.patch

371 lines
11 KiB
Diff
Raw Normal View History

diff -r 15cfd1f8fa38 tools/ioemu/hw/xenfb.c
--- a/tools/ioemu/hw/xenfb.c Tue Jan 08 16:45:08 2008 +0000
+++ b/tools/ioemu/hw/xenfb.c Thu Jan 17 12:16:49 2008 -0700
@@ -8,6 +8,7 @@
#include <xen/io/fbif.h>
#include <xen/io/kbdif.h>
#include <xen/io/protocols.h>
+#include <xen/grant_table.h>
#include <stdbool.h>
#include <xen/event_channel.h>
#include <sys/mman.h>
@@ -45,6 +46,7 @@ struct xenfb {
struct xs_handle *xsh; /* xs daemon handle */
struct xenfb_device fb, kbd;
void *pixels; /* guest framebuffer data */
+ void *old_pixels; /* guest FB data before remapping to extended */
size_t fb_len; /* size of framebuffer */
int row_stride; /* width of one row in framebuffer */
int depth; /* colour depth of guest framebuffer */
@@ -52,7 +54,9 @@ struct xenfb {
int height; /* pixel height of guest framebuffer */
int abs_pointer_wanted; /* Whether guest supports absolute pointer */
int button_state; /* Last seen pointer button state */
- char protocol[64]; /* frontend protocol */
+ char protocol[64]; /* frontend protocol */
+ int otherend_bsize; /* frontend bit size */
+ int gnttabdev;
};
/* Functions for frontend/backend state machine*/
@@ -78,6 +82,9 @@ static void xenfb_invalidate(void *opaqu
static void xenfb_invalidate(void *opaque);
static void xenfb_screen_dump(void *opaque, const char *name);
static int xenfb_register_console(struct xenfb *xenfb);
+static int xenfb_send_resize(struct xenfb *xenfb, int width, int height);
+static void xenfb_map_extended_fb(struct xenfb *xenfb, int, int, int);
+static int xenfb_send_map_extended_done(struct xenfb *xenfb);
/*
* Tables to map from scancode to Linux input layer keycode.
@@ -261,9 +268,19 @@ struct xenfb *xenfb_new(int domid, Displ
if (!xenfb->xsh)
goto fail;
+ xenfb->gnttabdev = xc_gnttab_open();
+ if (xenfb->gnttabdev == -1) {
+ fprintf(stderr, "FB: Can't open gnttab device\n");
+ }
+
xenfb->ds = ds;
xenfb_device_set_domain(&xenfb->fb, domid);
xenfb_device_set_domain(&xenfb->kbd, domid);
+
+ /* Indicate we have the frame buffer resize feature, requires grant tables */
+ if (xenfb->gnttabdev > 0) {
+ xenfb_xs_printf(xenfb->xsh, xenfb->fb.nodename, "feature-resize", "1");
+ }
fprintf(stderr, "FB: Waiting for KBD backend creation\n");
xenfb_wait_for_backend(&xenfb->kbd, xenfb_backend_created_kbd);
@@ -320,6 +337,58 @@ static void xenfb_copy_mfns(int mode, in
for (i = 0; i < count; i++)
dst[i] = (mode == 32) ? src32[i] : src64[i];
+}
+
+static void xenfb_map_extended_fb(struct xenfb *xenfb, int extended_mem_length,
+ int gref_cnt, int gref)
+{
+ int n_fbmfns;
+ unsigned long *fbmfns = NULL;
+ void *page;
+ int i;
+ int ep_gref;
+ int amt;
+ int index;
+ void *pixels;
+ int *grefs;
+
+ grefs = xc_gnttab_map_grant_ref (xenfb->gnttabdev,
+ xenfb->fb.otherend_id,
+ gref, 0);
+ if (NULL == grefs) {
+ fprintf(stderr,"FB: Can't map to grant refs\n");
+ return;
+ }
+ n_fbmfns = (extended_mem_length + (XC_PAGE_SIZE - 1)) / XC_PAGE_SIZE;
+ fbmfns = malloc(sizeof(unsigned long) * n_fbmfns);
+ if (fbmfns) {
+ ep_gref = PAGE_SIZE/(xenfb->otherend_bsize/8);
+ amt = index = 0;
+ for(i = 0; i < gref_cnt; i++) {
+ page = xc_gnttab_map_grant_ref (xenfb->gnttabdev,
+ xenfb->fb.otherend_id,
+ grefs[i], 0);
+ if (page) {
+ index = i * ep_gref;
+ amt = ep_gref;
+ if (n_fbmfns - index < ep_gref)
+ amt = n_fbmfns - index;
+ xenfb_copy_mfns(xenfb->otherend_bsize, amt, &fbmfns[index], page);
+ xc_gnttab_munmap(xenfb->gnttabdev, page, 1);
+ }
+ else
+ goto gref_error;
+ }
+ pixels = xc_map_foreign_pages(xenfb->xc, xenfb->fb.otherend_id,
+ PROT_READ | PROT_WRITE, fbmfns, n_fbmfns);
+ if (pixels) {
+ xenfb->old_pixels = xenfb->pixels;
+ xenfb->pixels = pixels;
+ }
+ free(fbmfns);
+ }
+gref_error:
+ xc_gnttab_munmap(xenfb->gnttabdev, grefs, 1);
}
static int xenfb_map_fb(struct xenfb *xenfb, int domid)
@@ -377,6 +446,7 @@ static int xenfb_map_fb(struct xenfb *xe
#endif
}
+ xenfb->otherend_bsize = mode;
n_fbmfns = (xenfb->fb_len + (XC_PAGE_SIZE - 1)) / XC_PAGE_SIZE;
n_fbdirs = n_fbmfns * mode / 8;
n_fbdirs = (n_fbdirs + (XC_PAGE_SIZE - 1)) / XC_PAGE_SIZE;
@@ -456,6 +526,10 @@ static void xenfb_detach_dom(struct xenf
munmap(xenfb->pixels, xenfb->fb_len);
xenfb->pixels = NULL;
}
+ if (xenfb->old_pixels) {
+ munmap(xenfb->old_pixels, xenfb->fb_len);
+ xenfb->old_pixels = NULL;
+ }
}
/* Remove the backend area in xenbus since the framebuffer really is
@@ -473,6 +547,9 @@ void xenfb_shutdown(struct xenfb *xenfb)
xc_evtchn_close(xenfb->evt_xch);
if (xenfb->xsh)
xs_daemon_close(xenfb->xsh);
+ if (xenfb->gnttabdev > 0)
+ xc_gnttab_close(xenfb->gnttabdev);
+
free(xenfb);
}
@@ -510,6 +587,22 @@ static void xenfb_on_fb_event(struct xen
}
xenfb_guest_copy(xenfb, x, y, w, h);
break;
+ case XENFB_TYPE_RESIZE:
+ xenfb->width = event->resize.width;
+ xenfb->height = event->resize.height;
+ xenfb->row_stride = event->resize.stride;
+ dpy_resize(xenfb->ds, xenfb->width, xenfb->height);
+ xenfb_send_resize(xenfb, xenfb->width, xenfb->height);
+ break;
+ case XENFB_TYPE_MAP_EXTENDED:
+ if (xenfb->gnttabdev > 0) {
+ xenfb_map_extended_fb(xenfb,
+ event->map_extended.extended_mem_length,
+ event->map_extended.gref_cnt,
+ event->map_extended.gref);
+ }
+ xenfb_send_map_extended_done(xenfb);
+ break;
}
}
mb(); /* ensure we're done with ring contents */
@@ -555,6 +648,41 @@ static int xenfb_on_state_change(struct
return 0;
}
+/* Send an event to the framebuffer frontend driver */
+static int xenfb_fb_event(struct xenfb *xenfb,
+ union xenfb_in_event *event)
+{
+ uint32_t prod;
+ struct xenfb_page *page = xenfb->fb.page;
+
+ if (xenfb->fb.state != XenbusStateConnected)
+ return 0;
+
+ prod = page->in_prod;
+ if (prod - page->in_cons == XENFB_IN_RING_LEN) {
+ errno = EAGAIN;
+ return -1;
+ }
+
+ mb(); /* ensure ring space available */
+ XENFB_IN_RING_REF(page, prod) = *event;
+ wmb(); /* ensure ring contents visible */
+ page->in_prod = prod + 1;
+ return xc_evtchn_notify(xenfb->evt_xch, xenfb->fb.port);
+}
+
+/* Send a extended memory map done event to kbd driver */
+static int xenfb_send_map_extended_done(struct xenfb *xenfb)
+{
+ union xenfb_in_event event;
+
+ memset(&event, 0, XENFB_IN_EVENT_SIZE);
+ event.type = XENFB_TYPE_MAP_EXTENDED_DONE;
+
+ return xenfb_fb_event(xenfb, &event);
+}
+
+
/* Send an event to the keyboard frontend driver */
static int xenfb_kbd_event(struct xenfb *xenfb,
union xenkbd_in_event *event)
@@ -601,6 +729,19 @@ static int xenfb_send_motion(struct xenf
event.motion.rel_x = rel_x;
event.motion.rel_y = rel_y;
event.motion.rel_z = rel_z;
+
+ return xenfb_kbd_event(xenfb, &event);
+}
+
+/* Send a resize event to kbd driver */
+static int xenfb_send_resize(struct xenfb *xenfb, int width, int height)
+{
+ union xenkbd_in_event event;
+
+ memset(&event, 0, XENKBD_IN_EVENT_SIZE);
+ event.type = XENKBD_TYPE_FBRESIZE;
+ event.fbresize.width = width;
+ event.fbresize.height = height;
return xenfb_kbd_event(xenfb, &event);
}
diff -r 15cfd1f8fa38 xen/include/public/io/fbif.h
--- a/xen/include/public/io/fbif.h Tue Jan 08 16:45:08 2008 +0000
+++ b/xen/include/public/io/fbif.h Thu Jan 17 08:16:28 2008 -0700
@@ -29,8 +29,9 @@
/* Out events (frontend -> backend) */
/*
- * Out events may be sent only when requested by backend, and receipt
- * of an unknown out event is an error.
+ * Out event update is sent only when requested by backend
+ * Events resize and map_extended are frontend generated
+ * It is an error to send any unknown event types
*/
/* Event type 1 currently not used */
@@ -50,12 +51,44 @@ struct xenfb_update
int32_t height; /* rect height */
};
+/*
+ * Framebuffer resize notification event
+ * Capable backend sets feature-resize in xenstore.
+ */
+#define XENFB_TYPE_RESIZE 3
+
+struct xenfb_resize
+{
+ uint8_t type; /* XENFB_TYPE_RESIZE */
+ int32_t width; /* width in pixels */
+ int32_t height; /* height in pixels */
+ int32_t stride; /* stride in pixels */
+ int32_t depth; /* future */
+};
+
+/*
+ * Framebuffer map extended memory event
+ * Causes backend to map extended frame buffer memory
+ * for larger screen resolution support
+ */
+#define XENFB_TYPE_MAP_EXTENDED 4
+
+struct xenfb_map_extended
+{
+ uint8_t type; /* XENFB_TYPE_MAP_EXTENDED */
+ int32_t extended_mem_length; /* extended frame buffer len (in bytes) */
+ int32_t gref_cnt; /* number of mapping refernces used */
+ int32_t gref; /* reference to mapping references */
+};
+
#define XENFB_OUT_EVENT_SIZE 40
union xenfb_out_event
{
uint8_t type;
struct xenfb_update update;
+ struct xenfb_resize resize;
+ struct xenfb_map_extended map_extended;
char pad[XENFB_OUT_EVENT_SIZE];
};
@@ -63,14 +96,26 @@ union xenfb_out_event
/*
* Frontends should ignore unknown in events.
- * No in events currently defined.
*/
+
+/*
+ * Framebuffer map extended memory done event
+ * Causes fronted to end foreign access to extended memory
+ * grant table references
+ */
+#define XENFB_TYPE_MAP_EXTENDED_DONE 1
+
+struct xenfb_map_extended_done
+{
+ uint8_t type; /* XENFB_TYPE_MAP_EXTENDED_DONE */
+};
#define XENFB_IN_EVENT_SIZE 40
union xenfb_in_event
{
uint8_t type;
+ struct xenfb_map_extended_done map_extended_done;
char pad[XENFB_IN_EVENT_SIZE];
};
@@ -116,8 +161,9 @@ struct xenfb_page
};
/*
- * Wart: xenkbd needs to know resolution. Put it here until a better
- * solution is found, but don't leak it to the backend.
+ * Wart: xenkbd needs to know resolution of initial frame buffer. Put
+ * it here until a better solution is found, but don't leak it to
+ * the backend.
*/
#ifdef __KERNEL__
#define XENFB_WIDTH 800
diff -r 15cfd1f8fa38 xen/include/public/io/kbdif.h
--- a/xen/include/public/io/kbdif.h Tue Jan 08 16:45:08 2008 +0000
+++ b/xen/include/public/io/kbdif.h Thu Jan 17 10:43:35 2008 -0700
@@ -44,6 +44,12 @@
* request-abs-update in xenstore.
*/
#define XENKBD_TYPE_POS 4
+/*
+ * Frame buffer resize event. Adjusts absolute max X and Y axis
+ * values in input ptr device. Necessary for proper scaling
+ * when the screen resolution changes
+ */
+#define XENKBD_TYPE_FBRESIZE 5
struct xenkbd_motion
{
@@ -68,6 +74,12 @@ struct xenkbd_position
int32_t abs_z; /* absolute Z position (wheel) */
};
+struct xenkbd_fbresize
+{
+ uint8_t type; /* XENKBD_TYPE_FBRESIZE */
+ int32_t width; /* frame buffer width in pixels */
+ int32_t height; /* frame buffer height in pixels */
+};
#define XENKBD_IN_EVENT_SIZE 40
union xenkbd_in_event
@@ -76,6 +88,7 @@ union xenkbd_in_event
struct xenkbd_motion motion;
struct xenkbd_key key;
struct xenkbd_position pos;
+ struct xenkbd_fbresize fbresize;
char pad[XENKBD_IN_EVENT_SIZE];
};