diff options
| author | Markus Armbruster <armbru@redhat.com> | 2008-05-26 18:31:11 -0400 |
|---|---|---|
| committer | Thomas Gleixner <tglx@linutronix.de> | 2008-05-27 04:11:36 -0400 |
| commit | e4dcff1f6e7582f76c2c9990b1d9111bbc8e26ef (patch) | |
| tree | d4a06968700cf64e3f8b7b146512a457ac9e7ece | |
| parent | f4ad1ebd7a0fae2782ef9f76c0b94b536742c3e8 (diff) | |
xen pvfb: Dynamic mode support (screen resizing)
The pvfb backend indicates dynamic mode support by creating node
feature_resize with a non-zero value in its xenstore directory.
xen-fbfront sends a resize notification event on mode change. Fully
backwards compatible both ways.
Framebuffer size and initial resolution can be controlled through
kernel parameter xen_fbfront.video. The backend enforces a separate
size limit, which it advertises in node videoram in its xenstore
directory.
xen-kbdfront gets the maximum screen resolution from nodes width and
height in the backend's xenstore directory instead of hardcoding it.
Additional goodie: support for larger framebuffers (512M on a 64-bit
system with 4K pages).
Changing the number of bits per pixels dynamically is not supported,
yet.
Ported from
http://xenbits.xensource.com/linux-2.6.18-xen.hg?rev/92f7b3144f41
http://xenbits.xensource.com/linux-2.6.18-xen.hg?rev/bfc040135633
Signed-off-by: Pat Campbell <plc@novell.com>
Signed-off-by: Markus Armbruster <armbru@redhat.com>
Signed-off-by: Jeremy Fitzhardinge <jeremy.fitzhardinge@citrix.com>
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
| -rw-r--r-- | drivers/input/xen-kbdfront.c | 10 | ||||
| -rw-r--r-- | drivers/video/xen-fbfront.c | 183 | ||||
| -rw-r--r-- | include/xen/interface/io/fbif.h | 29 |
3 files changed, 188 insertions, 34 deletions
diff --git a/drivers/input/xen-kbdfront.c b/drivers/input/xen-kbdfront.c index eaf69cf5b444..9ce3b3baf3a2 100644 --- a/drivers/input/xen-kbdfront.c +++ b/drivers/input/xen-kbdfront.c | |||
| @@ -300,6 +300,16 @@ InitWait: | |||
| 300 | */ | 300 | */ |
| 301 | if (dev->state != XenbusStateConnected) | 301 | if (dev->state != XenbusStateConnected) |
| 302 | goto InitWait; /* no InitWait seen yet, fudge it */ | 302 | goto InitWait; /* no InitWait seen yet, fudge it */ |
| 303 | |||
| 304 | /* Set input abs params to match backend screen res */ | ||
| 305 | if (xenbus_scanf(XBT_NIL, info->xbdev->otherend, | ||
| 306 | "width", "%d", &val) > 0) | ||
| 307 | input_set_abs_params(info->ptr, ABS_X, 0, val, 0, 0); | ||
| 308 | |||
| 309 | if (xenbus_scanf(XBT_NIL, info->xbdev->otherend, | ||
| 310 | "height", "%d", &val) > 0) | ||
| 311 | input_set_abs_params(info->ptr, ABS_Y, 0, val, 0, 0); | ||
| 312 | |||
| 303 | break; | 313 | break; |
| 304 | 314 | ||
| 305 | case XenbusStateClosing: | 315 | case XenbusStateClosing: |
diff --git a/drivers/video/xen-fbfront.c b/drivers/video/xen-fbfront.c index 291eef695594..47ed39b52f9c 100644 --- a/drivers/video/xen-fbfront.c +++ b/drivers/video/xen-fbfront.c | |||
| @@ -43,23 +43,47 @@ struct xenfb_info { | |||
| 43 | struct xenfb_page *page; | 43 | struct xenfb_page *page; |
| 44 | unsigned long *mfns; | 44 | unsigned long *mfns; |
| 45 | int update_wanted; /* XENFB_TYPE_UPDATE wanted */ | 45 | int update_wanted; /* XENFB_TYPE_UPDATE wanted */ |
| 46 | int feature_resize; /* XENFB_TYPE_RESIZE ok */ | ||
| 47 | struct xenfb_resize resize; /* protected by resize_lock */ | ||
| 48 | int resize_dpy; /* ditto */ | ||
| 49 | spinlock_t resize_lock; | ||
| 46 | 50 | ||
| 47 | struct xenbus_device *xbdev; | 51 | struct xenbus_device *xbdev; |
| 48 | }; | 52 | }; |
| 49 | 53 | ||
| 50 | static u32 xenfb_mem_len = XENFB_WIDTH * XENFB_HEIGHT * XENFB_DEPTH / 8; | 54 | #define XENFB_DEFAULT_FB_LEN (XENFB_WIDTH * XENFB_HEIGHT * XENFB_DEPTH / 8) |
| 55 | |||
| 56 | enum { KPARAM_MEM, KPARAM_WIDTH, KPARAM_HEIGHT, KPARAM_CNT }; | ||
| 57 | static int video[KPARAM_CNT] = { 2, XENFB_WIDTH, XENFB_HEIGHT }; | ||
| 58 | module_param_array(video, int, NULL, 0); | ||
| 59 | MODULE_PARM_DESC(video, | ||
| 60 | "Video memory size in MB, width, height in pixels (default 2,800,600)"); | ||
| 51 | 61 | ||
| 52 | static void xenfb_make_preferred_console(void); | 62 | static void xenfb_make_preferred_console(void); |
| 53 | static int xenfb_remove(struct xenbus_device *); | 63 | static int xenfb_remove(struct xenbus_device *); |
| 54 | static void xenfb_init_shared_page(struct xenfb_info *); | 64 | static void xenfb_init_shared_page(struct xenfb_info *, struct fb_info *); |
| 55 | static int xenfb_connect_backend(struct xenbus_device *, struct xenfb_info *); | 65 | static int xenfb_connect_backend(struct xenbus_device *, struct xenfb_info *); |
| 56 | static void xenfb_disconnect_backend(struct xenfb_info *); | 66 | static void xenfb_disconnect_backend(struct xenfb_info *); |
| 57 | 67 | ||
| 68 | static void xenfb_send_event(struct xenfb_info *info, | ||
| 69 | union xenfb_out_event *event) | ||
| 70 | { | ||
| 71 | u32 prod; | ||
| 72 | |||
| 73 | prod = info->page->out_prod; | ||
| 74 | /* caller ensures !xenfb_queue_full() */ | ||
| 75 | mb(); /* ensure ring space available */ | ||
| 76 | XENFB_OUT_RING_REF(info->page, prod) = *event; | ||
| 77 | wmb(); /* ensure ring contents visible */ | ||
| 78 | info->page->out_prod = prod + 1; | ||
| 79 | |||
| 80 | notify_remote_via_irq(info->irq); | ||
| 81 | } | ||
| 82 | |||
| 58 | static void xenfb_do_update(struct xenfb_info *info, | 83 | static void xenfb_do_update(struct xenfb_info *info, |
| 59 | int x, int y, int w, int h) | 84 | int x, int y, int w, int h) |
| 60 | { | 85 | { |
| 61 | union xenfb_out_event event; | 86 | union xenfb_out_event event; |
| 62 | u32 prod; | ||
| 63 | 87 | ||
| 64 | memset(&event, 0, sizeof(event)); | 88 | memset(&event, 0, sizeof(event)); |
| 65 | event.type = XENFB_TYPE_UPDATE; | 89 | event.type = XENFB_TYPE_UPDATE; |
| @@ -68,14 +92,19 @@ static void xenfb_do_update(struct xenfb_info *info, | |||
| 68 | event.update.width = w; | 92 | event.update.width = w; |
| 69 | event.update.height = h; | 93 | event.update.height = h; |
| 70 | 94 | ||
| 71 | prod = info->page->out_prod; | ||
| 72 | /* caller ensures !xenfb_queue_full() */ | 95 | /* caller ensures !xenfb_queue_full() */ |
| 73 | mb(); /* ensure ring space available */ | 96 | xenfb_send_event(info, &event); |
| 74 | XENFB_OUT_RING_REF(info->page, prod) = event; | 97 | } |
| 75 | wmb(); /* ensure ring contents visible */ | ||
| 76 | info->page->out_prod = prod + 1; | ||
| 77 | 98 | ||
| 78 | notify_remote_via_irq(info->irq); | 99 | static void xenfb_do_resize(struct xenfb_info *info) |
| 100 | { | ||
| 101 | union xenfb_out_event event; | ||
| 102 | |||
| 103 | memset(&event, 0, sizeof(event)); | ||
| 104 | event.resize = info->resize; | ||
| 105 | |||
| 106 | /* caller ensures !xenfb_queue_full() */ | ||
| 107 | xenfb_send_event(info, &event); | ||
| 79 | } | 108 | } |
| 80 | 109 | ||
| 81 | static int xenfb_queue_full(struct xenfb_info *info) | 110 | static int xenfb_queue_full(struct xenfb_info *info) |
| @@ -87,12 +116,28 @@ static int xenfb_queue_full(struct xenfb_info *info) | |||
| 87 | return prod - cons == XENFB_OUT_RING_LEN; | 116 | return prod - cons == XENFB_OUT_RING_LEN; |
| 88 | } | 117 | } |
| 89 | 118 | ||
| 119 | static void xenfb_handle_resize_dpy(struct xenfb_info *info) | ||
| 120 | { | ||
| 121 | unsigned long flags; | ||
| 122 | |||
| 123 | spin_lock_irqsave(&info->resize_lock, flags); | ||
| 124 | if (info->resize_dpy) { | ||
| 125 | if (!xenfb_queue_full(info)) { | ||
| 126 | info->resize_dpy = 0; | ||
| 127 | xenfb_do_resize(info); | ||
| 128 | } | ||
| 129 | } | ||
| 130 | spin_unlock_irqrestore(&info->resize_lock, flags); | ||
| 131 | } | ||
| 132 | |||
| 90 | static void xenfb_refresh(struct xenfb_info *info, | 133 | static void xenfb_refresh(struct xenfb_info *info, |
| 91 | int x1, int y1, int w, int h) | 134 | int x1, int y1, int w, int h) |
| 92 | { | 135 | { |
| 93 | unsigned long flags; | 136 | unsigned long flags; |
| 94 | int y2 = y1 + h - 1; | ||
| 95 | int x2 = x1 + w - 1; | 137 | int x2 = x1 + w - 1; |
| 138 | int y2 = y1 + h - 1; | ||
| 139 | |||
| 140 | xenfb_handle_resize_dpy(info); | ||
| 96 | 141 | ||
| 97 | if (!info->update_wanted) | 142 | if (!info->update_wanted) |
| 98 | return; | 143 | return; |
| @@ -225,6 +270,57 @@ static ssize_t xenfb_write(struct fb_info *p, const char __user *buf, | |||
| 225 | return res; | 270 | return res; |
| 226 | } | 271 | } |
| 227 | 272 | ||
| 273 | static int | ||
| 274 | xenfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) | ||
| 275 | { | ||
| 276 | struct xenfb_info *xenfb_info; | ||
| 277 | int required_mem_len; | ||
| 278 | |||
| 279 | xenfb_info = info->par; | ||
| 280 | |||
| 281 | if (!xenfb_info->feature_resize) { | ||
| 282 | if (var->xres == video[KPARAM_WIDTH] && | ||
| 283 | var->yres == video[KPARAM_HEIGHT] && | ||
| 284 | var->bits_per_pixel == xenfb_info->page->depth) { | ||
| 285 | return 0; | ||
| 286 | } | ||
| 287 | return -EINVAL; | ||
| 288 | } | ||
| 289 | |||
| 290 | /* Can't resize past initial width and height */ | ||
| 291 | if (var->xres > video[KPARAM_WIDTH] || var->yres > video[KPARAM_HEIGHT]) | ||
| 292 | return -EINVAL; | ||
| 293 | |||
| 294 | required_mem_len = var->xres * var->yres * xenfb_info->page->depth / 8; | ||
| 295 | if (var->bits_per_pixel == xenfb_info->page->depth && | ||
| 296 | var->xres <= info->fix.line_length / (XENFB_DEPTH / 8) && | ||
| 297 | required_mem_len <= info->fix.smem_len) { | ||
| 298 | var->xres_virtual = var->xres; | ||
| 299 | var->yres_virtual = var->yres; | ||
| 300 | return 0; | ||
| 301 | } | ||
| 302 | return -EINVAL; | ||
| 303 | } | ||
| 304 | |||
| 305 | static int xenfb_set_par(struct fb_info *info) | ||
| 306 | { | ||
| 307 | struct xenfb_info *xenfb_info; | ||
| 308 | unsigned long flags; | ||
| 309 | |||
| 310 | xenfb_info = info->par; | ||
| 311 | |||
| 312 | spin_lock_irqsave(&xenfb_info->resize_lock, flags); | ||
| 313 | xenfb_info->resize.type = XENFB_TYPE_RESIZE; | ||
| 314 | xenfb_info->resize.width = info->var.xres; | ||
| 315 | xenfb_info->resize.height = info->var.yres; | ||
| 316 | xenfb_info->resize.stride = info->fix.line_length; | ||
| 317 | xenfb_info->resize.depth = info->var.bits_per_pixel; | ||
| 318 | xenfb_info->resize.offset = 0; | ||
| 319 | xenfb_info->resize_dpy = 1; | ||
| 320 | spin_unlock_irqrestore(&xenfb_info->resize_lock, flags); | ||
| 321 | return 0; | ||
| 322 | } | ||
| 323 | |||
| 228 | static struct fb_ops xenfb_fb_ops = { | 324 | static struct fb_ops xenfb_fb_ops = { |
| 229 | .owner = THIS_MODULE, | 325 | .owner = THIS_MODULE, |
| 230 | .fb_read = fb_sys_read, | 326 | .fb_read = fb_sys_read, |
| @@ -233,6 +329,8 @@ static struct fb_ops xenfb_fb_ops = { | |||
| 233 | .fb_fillrect = xenfb_fillrect, | 329 | .fb_fillrect = xenfb_fillrect, |
| 234 | .fb_copyarea = xenfb_copyarea, | 330 | .fb_copyarea = xenfb_copyarea, |
| 235 | .fb_imageblit = xenfb_imageblit, | 331 | .fb_imageblit = xenfb_imageblit, |
| 332 | .fb_check_var = xenfb_check_var, | ||
| 333 | .fb_set_par = xenfb_set_par, | ||
| 236 | }; | 334 | }; |
| 237 | 335 | ||
| 238 | static irqreturn_t xenfb_event_handler(int rq, void *dev_id) | 336 | static irqreturn_t xenfb_event_handler(int rq, void *dev_id) |
| @@ -261,6 +359,8 @@ static int __devinit xenfb_probe(struct xenbus_device *dev, | |||
| 261 | { | 359 | { |
| 262 | struct xenfb_info *info; | 360 | struct xenfb_info *info; |
| 263 | struct fb_info *fb_info; | 361 | struct fb_info *fb_info; |
| 362 | int fb_size; | ||
| 363 | int val; | ||
| 264 | int ret; | 364 | int ret; |
| 265 | 365 | ||
| 266 | info = kzalloc(sizeof(*info), GFP_KERNEL); | 366 | info = kzalloc(sizeof(*info), GFP_KERNEL); |
| @@ -268,18 +368,35 @@ static int __devinit xenfb_probe(struct xenbus_device *dev, | |||
| 268 | xenbus_dev_fatal(dev, -ENOMEM, "allocating info structure"); | 368 | xenbus_dev_fatal(dev, -ENOMEM, "allocating info structure"); |
| 269 | return -ENOMEM; | 369 | return -ENOMEM; |
| 270 | } | 370 | } |
| 371 | |||
| 372 | /* Limit kernel param videoram amount to what is in xenstore */ | ||
| 373 | if (xenbus_scanf(XBT_NIL, dev->otherend, "videoram", "%d", &val) == 1) { | ||
| 374 | if (val < video[KPARAM_MEM]) | ||
| 375 | video[KPARAM_MEM] = val; | ||
| 376 | } | ||
| 377 | |||
| 378 | /* If requested res does not fit in available memory, use default */ | ||
| 379 | fb_size = video[KPARAM_MEM] * 1024 * 1024; | ||
| 380 | if (video[KPARAM_WIDTH] * video[KPARAM_HEIGHT] * XENFB_DEPTH / 8 | ||
| 381 | > fb_size) { | ||
| 382 | video[KPARAM_WIDTH] = XENFB_WIDTH; | ||
| 383 | video[KPARAM_HEIGHT] = XENFB_HEIGHT; | ||
| 384 | fb_size = XENFB_DEFAULT_FB_LEN; | ||
| 385 | } | ||
| 386 | |||
| 271 | dev->dev.driver_data = info; | 387 | dev->dev.driver_data = info; |
| 272 | info->xbdev = dev; | 388 | info->xbdev = dev; |
| 273 | info->irq = -1; | 389 | info->irq = -1; |
| 274 | info->x1 = info->y1 = INT_MAX; | 390 | info->x1 = info->y1 = INT_MAX; |
| 275 | spin_lock_init(&info->dirty_lock); | 391 | spin_lock_init(&info->dirty_lock); |
| 392 | spin_lock_init(&info->resize_lock); | ||
| 276 | 393 | ||
| 277 | info->fb = vmalloc(xenfb_mem_len); | 394 | info->fb = vmalloc(fb_size); |
| 278 | if (info->fb == NULL) | 395 | if (info->fb == NULL) |
| 279 | goto error_nomem; | 396 | goto error_nomem; |
| 280 | memset(info->fb, 0, xenfb_mem_len); | 397 | memset(info->fb, 0, fb_size); |
| 281 | 398 | ||
| 282 | info->nr_pages = (xenfb_mem_len + PAGE_SIZE - 1) >> PAGE_SHIFT; | 399 | info->nr_pages = (fb_size + PAGE_SIZE - 1) >> PAGE_SHIFT; |
| 283 | 400 | ||
| 284 | info->mfns = vmalloc(sizeof(unsigned long) * info->nr_pages); | 401 | info->mfns = vmalloc(sizeof(unsigned long) * info->nr_pages); |
| 285 | if (!info->mfns) | 402 | if (!info->mfns) |
| @@ -290,8 +407,6 @@ static int __devinit xenfb_probe(struct xenbus_device *dev, | |||
| 290 | if (!info->page) | 407 | if (!info->page) |
| 291 | goto error_nomem; | 408 | goto error_nomem; |
| 292 | 409 | ||
| 293 | xenfb_init_shared_page(info); | ||
| 294 | |||
| 295 | /* abusing framebuffer_alloc() to allocate pseudo_palette */ | 410 | /* abusing framebuffer_alloc() to allocate pseudo_palette */ |
| 296 | fb_info = framebuffer_alloc(sizeof(u32) * 256, NULL); | 411 | fb_info = framebuffer_alloc(sizeof(u32) * 256, NULL); |
| 297 | if (fb_info == NULL) | 412 | if (fb_info == NULL) |
| @@ -304,9 +419,9 @@ static int __devinit xenfb_probe(struct xenbus_device *dev, | |||
| 304 | fb_info->screen_base = info->fb; | 419 | fb_info->screen_base = info->fb; |
| 305 | 420 | ||
| 306 | fb_info->fbops = &xenfb_fb_ops; | 421 | fb_info->fbops = &xenfb_fb_ops; |
| 307 | fb_info->var.xres_virtual = fb_info->var.xres = info->page->width; | 422 | fb_info->var.xres_virtual = fb_info->var.xres = video[KPARAM_WIDTH]; |
| 308 | fb_info->var.yres_virtual = fb_info->var.yres = info->page->height; | 423 | fb_info->var.yres_virtual = fb_info->var.yres = video[KPARAM_HEIGHT]; |
| 309 | fb_info->var.bits_per_pixel = info->page->depth; | 424 | fb_info->var.bits_per_pixel = XENFB_DEPTH; |
| 310 | 425 | ||
| 311 | fb_info->var.red = (struct fb_bitfield){16, 8, 0}; | 426 | fb_info->var.red = (struct fb_bitfield){16, 8, 0}; |
| 312 | fb_info->var.green = (struct fb_bitfield){8, 8, 0}; | 427 | fb_info->var.green = (struct fb_bitfield){8, 8, 0}; |
| @@ -318,9 +433,9 @@ static int __devinit xenfb_probe(struct xenbus_device *dev, | |||
| 318 | fb_info->var.vmode = FB_VMODE_NONINTERLACED; | 433 | fb_info->var.vmode = FB_VMODE_NONINTERLACED; |
| 319 | 434 | ||
| 320 | fb_info->fix.visual = FB_VISUAL_TRUECOLOR; | 435 | fb_info->fix.visual = FB_VISUAL_TRUECOLOR; |
| 321 | fb_info->fix.line_length = info->page->line_length; | 436 | fb_info->fix.line_length = fb_info->var.xres * XENFB_DEPTH / 8; |
| 322 | fb_info->fix.smem_start = 0; | 437 | fb_info->fix.smem_start = 0; |
| 323 | fb_info->fix.smem_len = xenfb_mem_len; | 438 | fb_info->fix.smem_len = fb_size; |
| 324 | strcpy(fb_info->fix.id, "xen"); | 439 | strcpy(fb_info->fix.id, "xen"); |
| 325 | fb_info->fix.type = FB_TYPE_PACKED_PIXELS; | 440 | fb_info->fix.type = FB_TYPE_PACKED_PIXELS; |
| 326 | fb_info->fix.accel = FB_ACCEL_NONE; | 441 | fb_info->fix.accel = FB_ACCEL_NONE; |
| @@ -337,6 +452,8 @@ static int __devinit xenfb_probe(struct xenbus_device *dev, | |||
| 337 | fb_info->fbdefio = &xenfb_defio; | 452 | fb_info->fbdefio = &xenfb_defio; |
| 338 | fb_deferred_io_init(fb_info); | 453 | fb_deferred_io_init(fb_info); |
| 339 | 454 | ||
| 455 | xenfb_init_shared_page(info, fb_info); | ||
| 456 | |||
| 340 | ret = register_framebuffer(fb_info); | 457 | ret = register_framebuffer(fb_info); |
| 341 | if (ret) { | 458 | if (ret) { |
| 342 | fb_deferred_io_cleanup(fb_info); | 459 | fb_deferred_io_cleanup(fb_info); |
| @@ -389,7 +506,7 @@ static int xenfb_resume(struct xenbus_device *dev) | |||
| 389 | struct xenfb_info *info = dev->dev.driver_data; | 506 | struct xenfb_info *info = dev->dev.driver_data; |
| 390 | 507 | ||
| 391 | xenfb_disconnect_backend(info); | 508 | xenfb_disconnect_backend(info); |
| 392 | xenfb_init_shared_page(info); | 509 | xenfb_init_shared_page(info, info->fb_info); |
| 393 | return xenfb_connect_backend(dev, info); | 510 | return xenfb_connect_backend(dev, info); |
| 394 | } | 511 | } |
| 395 | 512 | ||
| @@ -417,20 +534,23 @@ static unsigned long vmalloc_to_mfn(void *address) | |||
| 417 | return pfn_to_mfn(vmalloc_to_pfn(address)); | 534 | return pfn_to_mfn(vmalloc_to_pfn(address)); |
| 418 | } | 535 | } |
| 419 | 536 | ||
| 420 | static void xenfb_init_shared_page(struct xenfb_info *info) | 537 | static void xenfb_init_shared_page(struct xenfb_info *info, |
| 538 | struct fb_info *fb_info) | ||
| 421 | { | 539 | { |
| 422 | int i; | 540 | int i; |
| 541 | int epd = PAGE_SIZE / sizeof(info->mfns[0]); | ||
| 423 | 542 | ||
| 424 | for (i = 0; i < info->nr_pages; i++) | 543 | for (i = 0; i < info->nr_pages; i++) |
| 425 | info->mfns[i] = vmalloc_to_mfn(info->fb + i * PAGE_SIZE); | 544 | info->mfns[i] = vmalloc_to_mfn(info->fb + i * PAGE_SIZE); |
| 426 | 545 | ||
| 427 | info->page->pd[0] = vmalloc_to_mfn(info->mfns); | 546 | for (i = 0; i * epd < info->nr_pages; i++) |
| 428 | info->page->pd[1] = 0; | 547 | info->page->pd[i] = vmalloc_to_mfn(&info->mfns[i * epd]); |
| 429 | info->page->width = XENFB_WIDTH; | 548 | |
| 430 | info->page->height = XENFB_HEIGHT; | 549 | info->page->width = fb_info->var.xres; |
| 431 | info->page->depth = XENFB_DEPTH; | 550 | info->page->height = fb_info->var.yres; |
| 432 | info->page->line_length = (info->page->depth / 8) * info->page->width; | 551 | info->page->depth = fb_info->var.bits_per_pixel; |
| 433 | info->page->mem_length = xenfb_mem_len; | 552 | info->page->line_length = fb_info->fix.line_length; |
| 553 | info->page->mem_length = fb_info->fix.smem_len; | ||
| 434 | info->page->in_cons = info->page->in_prod = 0; | 554 | info->page->in_cons = info->page->in_prod = 0; |
| 435 | info->page->out_cons = info->page->out_prod = 0; | 555 | info->page->out_cons = info->page->out_prod = 0; |
| 436 | } | 556 | } |
| @@ -530,6 +650,11 @@ InitWait: | |||
| 530 | val = 0; | 650 | val = 0; |
| 531 | if (val) | 651 | if (val) |
| 532 | info->update_wanted = 1; | 652 | info->update_wanted = 1; |
| 653 | |||
| 654 | if (xenbus_scanf(XBT_NIL, dev->otherend, | ||
| 655 | "feature-resize", "%d", &val) < 0) | ||
| 656 | val = 0; | ||
| 657 | info->feature_resize = val; | ||
| 533 | break; | 658 | break; |
| 534 | 659 | ||
| 535 | case XenbusStateClosing: | 660 | case XenbusStateClosing: |
diff --git a/include/xen/interface/io/fbif.h b/include/xen/interface/io/fbif.h index 5a934dd7796d..974a51ed9165 100644 --- a/include/xen/interface/io/fbif.h +++ b/include/xen/interface/io/fbif.h | |||
| @@ -49,11 +49,27 @@ struct xenfb_update { | |||
| 49 | int32_t height; /* rect height */ | 49 | int32_t height; /* rect height */ |
| 50 | }; | 50 | }; |
| 51 | 51 | ||
| 52 | /* | ||
| 53 | * Framebuffer resize notification event | ||
| 54 | * Capable backend sets feature-resize in xenstore. | ||
| 55 | */ | ||
| 56 | #define XENFB_TYPE_RESIZE 3 | ||
| 57 | |||
| 58 | struct xenfb_resize { | ||
| 59 | uint8_t type; /* XENFB_TYPE_RESIZE */ | ||
| 60 | int32_t width; /* width in pixels */ | ||
| 61 | int32_t height; /* height in pixels */ | ||
| 62 | int32_t stride; /* stride in bytes */ | ||
| 63 | int32_t depth; /* depth in bits */ | ||
| 64 | int32_t offset; /* start offset within framebuffer */ | ||
| 65 | }; | ||
| 66 | |||
| 52 | #define XENFB_OUT_EVENT_SIZE 40 | 67 | #define XENFB_OUT_EVENT_SIZE 40 |
| 53 | 68 | ||
| 54 | union xenfb_out_event { | 69 | union xenfb_out_event { |
| 55 | uint8_t type; | 70 | uint8_t type; |
| 56 | struct xenfb_update update; | 71 | struct xenfb_update update; |
| 72 | struct xenfb_resize resize; | ||
| 57 | char pad[XENFB_OUT_EVENT_SIZE]; | 73 | char pad[XENFB_OUT_EVENT_SIZE]; |
| 58 | }; | 74 | }; |
| 59 | 75 | ||
| @@ -105,15 +121,18 @@ struct xenfb_page { | |||
| 105 | * Each directory page holds PAGE_SIZE / sizeof(*pd) | 121 | * Each directory page holds PAGE_SIZE / sizeof(*pd) |
| 106 | * framebuffer pages, and can thus map up to PAGE_SIZE * | 122 | * framebuffer pages, and can thus map up to PAGE_SIZE * |
| 107 | * PAGE_SIZE / sizeof(*pd) bytes. With PAGE_SIZE == 4096 and | 123 | * PAGE_SIZE / sizeof(*pd) bytes. With PAGE_SIZE == 4096 and |
| 108 | * sizeof(unsigned long) == 4, that's 4 Megs. Two directory | 124 | * sizeof(unsigned long) == 4/8, that's 4 Megs 32 bit and 2 |
| 109 | * pages should be enough for a while. | 125 | * Megs 64 bit. 256 directories give enough room for a 512 |
| 126 | * Meg framebuffer with a max resolution of 12,800x10,240. | ||
| 127 | * Should be enough for a while with room leftover for | ||
| 128 | * expansion. | ||
| 110 | */ | 129 | */ |
| 111 | unsigned long pd[2]; | 130 | unsigned long pd[256]; |
| 112 | }; | 131 | }; |
| 113 | 132 | ||
| 114 | /* | 133 | /* |
| 115 | * Wart: xenkbd needs to know resolution. Put it here until a better | 134 | * Wart: xenkbd needs to know default resolution. Put it here until a |
| 116 | * solution is found, but don't leak it to the backend. | 135 | * better solution is found, but don't leak it to the backend. |
| 117 | */ | 136 | */ |
| 118 | #ifdef __KERNEL__ | 137 | #ifdef __KERNEL__ |
| 119 | #define XENFB_WIDTH 800 | 138 | #define XENFB_WIDTH 800 |
