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 #include #include +#include #include #include #include @@ -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]; };