1 /* 2 * Xen para-virtual frame buffer device 3 * 4 * Copyright (C) 2005-2006 Anthony Liguori <aliguori@us.ibm.com> 5 * Copyright (C) 2006-2008 Red Hat, Inc., Markus Armbruster <armbru@redhat.com> 6 * 7 * Based on linux/drivers/video/q40fb.c 8 * 9 * This file is subject to the terms and conditions of the GNU General Public 10 * License. See the file COPYING in the main directory of this archive for 11 * more details. 12 */ 13 14 /* 15 * TODO: 16 * 17 * Switch to grant tables when they become capable of dealing with the 18 * frame buffer. 19 */ 20 21 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 22 23 #include <linux/console.h> 24 #include <linux/kernel.h> 25 #include <linux/errno.h> 26 #include <linux/fb.h> 27 #include <linux/module.h> 28 #include <linux/slab.h> 29 #include <linux/vmalloc.h> 30 #include <linux/mm.h> 31 32 #include <asm/xen/hypervisor.h> 33 34 #include <xen/xen.h> 35 #include <xen/events.h> 36 #include <xen/page.h> 37 #include <xen/interface/io/fbif.h> 38 #include <xen/interface/io/protocols.h> 39 #include <xen/xenbus.h> 40 #include <xen/platform_pci.h> 41 42 struct xenfb_info { 43 unsigned char *fb; 44 struct fb_info *fb_info; 45 int x1, y1, x2, y2; /* dirty rectangle, 46 protected by dirty_lock */ 47 spinlock_t dirty_lock; 48 int nr_pages; 49 int irq; 50 struct xenfb_page *page; 51 unsigned long *gfns; 52 int update_wanted; /* XENFB_TYPE_UPDATE wanted */ 53 int feature_resize; /* XENFB_TYPE_RESIZE ok */ 54 struct xenfb_resize resize; /* protected by resize_lock */ 55 int resize_dpy; /* ditto */ 56 spinlock_t resize_lock; 57 58 struct xenbus_device *xbdev; 59 }; 60 61 #define XENFB_DEFAULT_FB_LEN (XENFB_WIDTH * XENFB_HEIGHT * XENFB_DEPTH / 8) 62 63 enum { KPARAM_MEM, KPARAM_WIDTH, KPARAM_HEIGHT, KPARAM_CNT }; 64 static int video[KPARAM_CNT] = { 2, XENFB_WIDTH, XENFB_HEIGHT }; 65 module_param_array(video, int, NULL, 0); 66 MODULE_PARM_DESC(video, 67 "Video memory size in MB, width, height in pixels (default 2,800,600)"); 68 69 static void xenfb_make_preferred_console(void); 70 static int xenfb_remove(struct xenbus_device *); 71 static void xenfb_init_shared_page(struct xenfb_info *, struct fb_info *); 72 static int xenfb_connect_backend(struct xenbus_device *, struct xenfb_info *); 73 static void xenfb_disconnect_backend(struct xenfb_info *); 74 75 static void xenfb_send_event(struct xenfb_info *info, 76 union xenfb_out_event *event) 77 { 78 u32 prod; 79 80 prod = info->page->out_prod; 81 /* caller ensures !xenfb_queue_full() */ 82 mb(); /* ensure ring space available */ 83 XENFB_OUT_RING_REF(info->page, prod) = *event; 84 wmb(); /* ensure ring contents visible */ 85 info->page->out_prod = prod + 1; 86 87 notify_remote_via_irq(info->irq); 88 } 89 90 static void xenfb_do_update(struct xenfb_info *info, 91 int x, int y, int w, int h) 92 { 93 union xenfb_out_event event; 94 95 memset(&event, 0, sizeof(event)); 96 event.type = XENFB_TYPE_UPDATE; 97 event.update.x = x; 98 event.update.y = y; 99 event.update.width = w; 100 event.update.height = h; 101 102 /* caller ensures !xenfb_queue_full() */ 103 xenfb_send_event(info, &event); 104 } 105 106 static void xenfb_do_resize(struct xenfb_info *info) 107 { 108 union xenfb_out_event event; 109 110 memset(&event, 0, sizeof(event)); 111 event.resize = info->resize; 112 113 /* caller ensures !xenfb_queue_full() */ 114 xenfb_send_event(info, &event); 115 } 116 117 static int xenfb_queue_full(struct xenfb_info *info) 118 { 119 u32 cons, prod; 120 121 prod = info->page->out_prod; 122 cons = info->page->out_cons; 123 return prod - cons == XENFB_OUT_RING_LEN; 124 } 125 126 static void xenfb_handle_resize_dpy(struct xenfb_info *info) 127 { 128 unsigned long flags; 129 130 spin_lock_irqsave(&info->resize_lock, flags); 131 if (info->resize_dpy) { 132 if (!xenfb_queue_full(info)) { 133 info->resize_dpy = 0; 134 xenfb_do_resize(info); 135 } 136 } 137 spin_unlock_irqrestore(&info->resize_lock, flags); 138 } 139 140 static void xenfb_refresh(struct xenfb_info *info, 141 int x1, int y1, int w, int h) 142 { 143 unsigned long flags; 144 int x2 = x1 + w - 1; 145 int y2 = y1 + h - 1; 146 147 xenfb_handle_resize_dpy(info); 148 149 if (!info->update_wanted) 150 return; 151 152 spin_lock_irqsave(&info->dirty_lock, flags); 153 154 /* Combine with dirty rectangle: */ 155 if (info->y1 < y1) 156 y1 = info->y1; 157 if (info->y2 > y2) 158 y2 = info->y2; 159 if (info->x1 < x1) 160 x1 = info->x1; 161 if (info->x2 > x2) 162 x2 = info->x2; 163 164 if (xenfb_queue_full(info)) { 165 /* Can't send right now, stash it in the dirty rectangle */ 166 info->x1 = x1; 167 info->x2 = x2; 168 info->y1 = y1; 169 info->y2 = y2; 170 spin_unlock_irqrestore(&info->dirty_lock, flags); 171 return; 172 } 173 174 /* Clear dirty rectangle: */ 175 info->x1 = info->y1 = INT_MAX; 176 info->x2 = info->y2 = 0; 177 178 spin_unlock_irqrestore(&info->dirty_lock, flags); 179 180 if (x1 <= x2 && y1 <= y2) 181 xenfb_do_update(info, x1, y1, x2 - x1 + 1, y2 - y1 + 1); 182 } 183 184 static void xenfb_deferred_io(struct fb_info *fb_info, struct list_head *pagereflist) 185 { 186 struct xenfb_info *info = fb_info->par; 187 struct fb_deferred_io_pageref *pageref; 188 unsigned long beg, end; 189 int y1, y2, miny, maxy; 190 191 miny = INT_MAX; 192 maxy = 0; 193 list_for_each_entry(pageref, pagereflist, list) { 194 struct page *page = pageref->page; 195 beg = page->index << PAGE_SHIFT; 196 end = beg + PAGE_SIZE - 1; 197 y1 = beg / fb_info->fix.line_length; 198 y2 = end / fb_info->fix.line_length; 199 if (y2 >= fb_info->var.yres) 200 y2 = fb_info->var.yres - 1; 201 if (miny > y1) 202 miny = y1; 203 if (maxy < y2) 204 maxy = y2; 205 } 206 xenfb_refresh(info, 0, miny, fb_info->var.xres, maxy - miny + 1); 207 } 208 209 static struct fb_deferred_io xenfb_defio = { 210 .delay = HZ / 20, 211 .deferred_io = xenfb_deferred_io, 212 }; 213 214 static int xenfb_setcolreg(unsigned regno, unsigned red, unsigned green, 215 unsigned blue, unsigned transp, 216 struct fb_info *info) 217 { 218 u32 v; 219 220 if (regno > info->cmap.len) 221 return 1; 222 223 #define CNVT_TOHW(val, width) ((((val)<<(width))+0x7FFF-(val))>>16) 224 red = CNVT_TOHW(red, info->var.red.length); 225 green = CNVT_TOHW(green, info->var.green.length); 226 blue = CNVT_TOHW(blue, info->var.blue.length); 227 transp = CNVT_TOHW(transp, info->var.transp.length); 228 #undef CNVT_TOHW 229 230 v = (red << info->var.red.offset) | 231 (green << info->var.green.offset) | 232 (blue << info->var.blue.offset); 233 234 switch (info->var.bits_per_pixel) { 235 case 16: 236 case 24: 237 case 32: 238 ((u32 *)info->pseudo_palette)[regno] = v; 239 break; 240 } 241 242 return 0; 243 } 244 245 static void xenfb_fillrect(struct fb_info *p, const struct fb_fillrect *rect) 246 { 247 struct xenfb_info *info = p->par; 248 249 sys_fillrect(p, rect); 250 xenfb_refresh(info, rect->dx, rect->dy, rect->width, rect->height); 251 } 252 253 static void xenfb_imageblit(struct fb_info *p, const struct fb_image *image) 254 { 255 struct xenfb_info *info = p->par; 256 257 sys_imageblit(p, image); 258 xenfb_refresh(info, image->dx, image->dy, image->width, image->height); 259 } 260 261 static void xenfb_copyarea(struct fb_info *p, const struct fb_copyarea *area) 262 { 263 struct xenfb_info *info = p->par; 264 265 sys_copyarea(p, area); 266 xenfb_refresh(info, area->dx, area->dy, area->width, area->height); 267 } 268 269 static ssize_t xenfb_write(struct fb_info *p, const char __user *buf, 270 size_t count, loff_t *ppos) 271 { 272 struct xenfb_info *info = p->par; 273 ssize_t res; 274 275 res = fb_sys_write(p, buf, count, ppos); 276 xenfb_refresh(info, 0, 0, info->page->width, info->page->height); 277 return res; 278 } 279 280 static int 281 xenfb_check_var(struct fb_var_screeninfo *var, struct fb_info *info) 282 { 283 struct xenfb_info *xenfb_info; 284 int required_mem_len; 285 286 xenfb_info = info->par; 287 288 if (!xenfb_info->feature_resize) { 289 if (var->xres == video[KPARAM_WIDTH] && 290 var->yres == video[KPARAM_HEIGHT] && 291 var->bits_per_pixel == xenfb_info->page->depth) { 292 return 0; 293 } 294 return -EINVAL; 295 } 296 297 /* Can't resize past initial width and height */ 298 if (var->xres > video[KPARAM_WIDTH] || var->yres > video[KPARAM_HEIGHT]) 299 return -EINVAL; 300 301 required_mem_len = var->xres * var->yres * xenfb_info->page->depth / 8; 302 if (var->bits_per_pixel == xenfb_info->page->depth && 303 var->xres <= info->fix.line_length / (XENFB_DEPTH / 8) && 304 required_mem_len <= info->fix.smem_len) { 305 var->xres_virtual = var->xres; 306 var->yres_virtual = var->yres; 307 return 0; 308 } 309 return -EINVAL; 310 } 311 312 static int xenfb_set_par(struct fb_info *info) 313 { 314 struct xenfb_info *xenfb_info; 315 unsigned long flags; 316 317 xenfb_info = info->par; 318 319 spin_lock_irqsave(&xenfb_info->resize_lock, flags); 320 xenfb_info->resize.type = XENFB_TYPE_RESIZE; 321 xenfb_info->resize.width = info->var.xres; 322 xenfb_info->resize.height = info->var.yres; 323 xenfb_info->resize.stride = info->fix.line_length; 324 xenfb_info->resize.depth = info->var.bits_per_pixel; 325 xenfb_info->resize.offset = 0; 326 xenfb_info->resize_dpy = 1; 327 spin_unlock_irqrestore(&xenfb_info->resize_lock, flags); 328 return 0; 329 } 330 331 static const struct fb_ops xenfb_fb_ops = { 332 .owner = THIS_MODULE, 333 .fb_read = fb_sys_read, 334 .fb_write = xenfb_write, 335 .fb_setcolreg = xenfb_setcolreg, 336 .fb_fillrect = xenfb_fillrect, 337 .fb_copyarea = xenfb_copyarea, 338 .fb_imageblit = xenfb_imageblit, 339 .fb_check_var = xenfb_check_var, 340 .fb_set_par = xenfb_set_par, 341 .fb_mmap = fb_deferred_io_mmap, 342 }; 343 344 static irqreturn_t xenfb_event_handler(int rq, void *dev_id) 345 { 346 /* 347 * No in events recognized, simply ignore them all. 348 * If you need to recognize some, see xen-kbdfront's 349 * input_handler() for how to do that. 350 */ 351 struct xenfb_info *info = dev_id; 352 struct xenfb_page *page = info->page; 353 354 if (page->in_cons != page->in_prod) { 355 info->page->in_cons = info->page->in_prod; 356 notify_remote_via_irq(info->irq); 357 } 358 359 /* Flush dirty rectangle: */ 360 xenfb_refresh(info, INT_MAX, INT_MAX, -INT_MAX, -INT_MAX); 361 362 return IRQ_HANDLED; 363 } 364 365 static int xenfb_probe(struct xenbus_device *dev, 366 const struct xenbus_device_id *id) 367 { 368 struct xenfb_info *info; 369 struct fb_info *fb_info; 370 int fb_size; 371 int val; 372 int ret = 0; 373 374 info = kzalloc(sizeof(*info), GFP_KERNEL); 375 if (info == NULL) { 376 xenbus_dev_fatal(dev, -ENOMEM, "allocating info structure"); 377 return -ENOMEM; 378 } 379 380 /* Limit kernel param videoram amount to what is in xenstore */ 381 if (xenbus_scanf(XBT_NIL, dev->otherend, "videoram", "%d", &val) == 1) { 382 if (val < video[KPARAM_MEM]) 383 video[KPARAM_MEM] = val; 384 } 385 386 video[KPARAM_WIDTH] = xenbus_read_unsigned(dev->otherend, "width", 387 video[KPARAM_WIDTH]); 388 video[KPARAM_HEIGHT] = xenbus_read_unsigned(dev->otherend, "height", 389 video[KPARAM_HEIGHT]); 390 391 /* If requested res does not fit in available memory, use default */ 392 fb_size = video[KPARAM_MEM] * 1024 * 1024; 393 if (video[KPARAM_WIDTH] * video[KPARAM_HEIGHT] * XENFB_DEPTH / 8 394 > fb_size) { 395 pr_warn("display parameters %d,%d,%d invalid, use defaults\n", 396 video[KPARAM_MEM], video[KPARAM_WIDTH], 397 video[KPARAM_HEIGHT]); 398 video[KPARAM_WIDTH] = XENFB_WIDTH; 399 video[KPARAM_HEIGHT] = XENFB_HEIGHT; 400 fb_size = XENFB_DEFAULT_FB_LEN; 401 } 402 403 dev_set_drvdata(&dev->dev, info); 404 info->xbdev = dev; 405 info->irq = -1; 406 info->x1 = info->y1 = INT_MAX; 407 spin_lock_init(&info->dirty_lock); 408 spin_lock_init(&info->resize_lock); 409 410 info->fb = vzalloc(fb_size); 411 if (info->fb == NULL) 412 goto error_nomem; 413 414 info->nr_pages = (fb_size + PAGE_SIZE - 1) >> PAGE_SHIFT; 415 416 info->gfns = vmalloc(array_size(sizeof(unsigned long), info->nr_pages)); 417 if (!info->gfns) 418 goto error_nomem; 419 420 /* set up shared page */ 421 info->page = (void *)__get_free_page(GFP_KERNEL | __GFP_ZERO); 422 if (!info->page) 423 goto error_nomem; 424 425 /* abusing framebuffer_alloc() to allocate pseudo_palette */ 426 fb_info = framebuffer_alloc(sizeof(u32) * 256, NULL); 427 if (fb_info == NULL) 428 goto error_nomem; 429 430 /* complete the abuse: */ 431 fb_info->pseudo_palette = fb_info->par; 432 fb_info->par = info; 433 434 fb_info->screen_base = info->fb; 435 436 fb_info->fbops = &xenfb_fb_ops; 437 fb_info->var.xres_virtual = fb_info->var.xres = video[KPARAM_WIDTH]; 438 fb_info->var.yres_virtual = fb_info->var.yres = video[KPARAM_HEIGHT]; 439 fb_info->var.bits_per_pixel = XENFB_DEPTH; 440 441 fb_info->var.red = (struct fb_bitfield){16, 8, 0}; 442 fb_info->var.green = (struct fb_bitfield){8, 8, 0}; 443 fb_info->var.blue = (struct fb_bitfield){0, 8, 0}; 444 445 fb_info->var.activate = FB_ACTIVATE_NOW; 446 fb_info->var.height = -1; 447 fb_info->var.width = -1; 448 fb_info->var.vmode = FB_VMODE_NONINTERLACED; 449 450 fb_info->fix.visual = FB_VISUAL_TRUECOLOR; 451 fb_info->fix.line_length = fb_info->var.xres * XENFB_DEPTH / 8; 452 fb_info->fix.smem_start = 0; 453 fb_info->fix.smem_len = fb_size; 454 strcpy(fb_info->fix.id, "xen"); 455 fb_info->fix.type = FB_TYPE_PACKED_PIXELS; 456 fb_info->fix.accel = FB_ACCEL_NONE; 457 458 fb_info->flags = FBINFO_FLAG_DEFAULT | FBINFO_VIRTFB; 459 460 ret = fb_alloc_cmap(&fb_info->cmap, 256, 0); 461 if (ret < 0) { 462 framebuffer_release(fb_info); 463 xenbus_dev_fatal(dev, ret, "fb_alloc_cmap"); 464 goto error; 465 } 466 467 fb_info->fbdefio = &xenfb_defio; 468 fb_deferred_io_init(fb_info); 469 470 xenfb_init_shared_page(info, fb_info); 471 472 ret = xenfb_connect_backend(dev, info); 473 if (ret < 0) { 474 xenbus_dev_fatal(dev, ret, "xenfb_connect_backend"); 475 goto error_fb; 476 } 477 478 ret = register_framebuffer(fb_info); 479 if (ret) { 480 xenbus_dev_fatal(dev, ret, "register_framebuffer"); 481 goto error_fb; 482 } 483 info->fb_info = fb_info; 484 485 xenfb_make_preferred_console(); 486 return 0; 487 488 error_fb: 489 fb_deferred_io_cleanup(fb_info); 490 fb_dealloc_cmap(&fb_info->cmap); 491 framebuffer_release(fb_info); 492 error_nomem: 493 if (!ret) { 494 ret = -ENOMEM; 495 xenbus_dev_fatal(dev, ret, "allocating device memory"); 496 } 497 error: 498 xenfb_remove(dev); 499 return ret; 500 } 501 502 static void xenfb_make_preferred_console(void) 503 { 504 struct console *c; 505 506 if (console_set_on_cmdline) 507 return; 508 509 console_lock(); 510 for_each_console(c) { 511 if (!strcmp(c->name, "tty") && c->index == 0) 512 break; 513 } 514 console_unlock(); 515 if (c) { 516 unregister_console(c); 517 c->flags |= CON_CONSDEV; 518 c->flags &= ~CON_PRINTBUFFER; /* don't print again */ 519 register_console(c); 520 } 521 } 522 523 static int xenfb_resume(struct xenbus_device *dev) 524 { 525 struct xenfb_info *info = dev_get_drvdata(&dev->dev); 526 527 xenfb_disconnect_backend(info); 528 xenfb_init_shared_page(info, info->fb_info); 529 return xenfb_connect_backend(dev, info); 530 } 531 532 static int xenfb_remove(struct xenbus_device *dev) 533 { 534 struct xenfb_info *info = dev_get_drvdata(&dev->dev); 535 536 xenfb_disconnect_backend(info); 537 if (info->fb_info) { 538 fb_deferred_io_cleanup(info->fb_info); 539 unregister_framebuffer(info->fb_info); 540 fb_dealloc_cmap(&info->fb_info->cmap); 541 framebuffer_release(info->fb_info); 542 } 543 free_page((unsigned long)info->page); 544 vfree(info->gfns); 545 vfree(info->fb); 546 kfree(info); 547 548 return 0; 549 } 550 551 static unsigned long vmalloc_to_gfn(void *address) 552 { 553 return xen_page_to_gfn(vmalloc_to_page(address)); 554 } 555 556 static void xenfb_init_shared_page(struct xenfb_info *info, 557 struct fb_info *fb_info) 558 { 559 int i; 560 int epd = PAGE_SIZE / sizeof(info->gfns[0]); 561 562 for (i = 0; i < info->nr_pages; i++) 563 info->gfns[i] = vmalloc_to_gfn(info->fb + i * PAGE_SIZE); 564 565 for (i = 0; i * epd < info->nr_pages; i++) 566 info->page->pd[i] = vmalloc_to_gfn(&info->gfns[i * epd]); 567 568 info->page->width = fb_info->var.xres; 569 info->page->height = fb_info->var.yres; 570 info->page->depth = fb_info->var.bits_per_pixel; 571 info->page->line_length = fb_info->fix.line_length; 572 info->page->mem_length = fb_info->fix.smem_len; 573 info->page->in_cons = info->page->in_prod = 0; 574 info->page->out_cons = info->page->out_prod = 0; 575 } 576 577 static int xenfb_connect_backend(struct xenbus_device *dev, 578 struct xenfb_info *info) 579 { 580 int ret, evtchn, irq; 581 struct xenbus_transaction xbt; 582 583 ret = xenbus_alloc_evtchn(dev, &evtchn); 584 if (ret) 585 return ret; 586 irq = bind_evtchn_to_irqhandler(evtchn, xenfb_event_handler, 587 0, dev->devicetype, info); 588 if (irq < 0) { 589 xenbus_free_evtchn(dev, evtchn); 590 xenbus_dev_fatal(dev, ret, "bind_evtchn_to_irqhandler"); 591 return irq; 592 } 593 again: 594 ret = xenbus_transaction_start(&xbt); 595 if (ret) { 596 xenbus_dev_fatal(dev, ret, "starting transaction"); 597 goto unbind_irq; 598 } 599 ret = xenbus_printf(xbt, dev->nodename, "page-ref", "%lu", 600 virt_to_gfn(info->page)); 601 if (ret) 602 goto error_xenbus; 603 ret = xenbus_printf(xbt, dev->nodename, "event-channel", "%u", 604 evtchn); 605 if (ret) 606 goto error_xenbus; 607 ret = xenbus_printf(xbt, dev->nodename, "protocol", "%s", 608 XEN_IO_PROTO_ABI_NATIVE); 609 if (ret) 610 goto error_xenbus; 611 ret = xenbus_printf(xbt, dev->nodename, "feature-update", "1"); 612 if (ret) 613 goto error_xenbus; 614 ret = xenbus_transaction_end(xbt, 0); 615 if (ret) { 616 if (ret == -EAGAIN) 617 goto again; 618 xenbus_dev_fatal(dev, ret, "completing transaction"); 619 goto unbind_irq; 620 } 621 622 xenbus_switch_state(dev, XenbusStateInitialised); 623 info->irq = irq; 624 return 0; 625 626 error_xenbus: 627 xenbus_transaction_end(xbt, 1); 628 xenbus_dev_fatal(dev, ret, "writing xenstore"); 629 unbind_irq: 630 unbind_from_irqhandler(irq, info); 631 return ret; 632 } 633 634 static void xenfb_disconnect_backend(struct xenfb_info *info) 635 { 636 /* Prevent xenfb refresh */ 637 info->update_wanted = 0; 638 if (info->irq >= 0) 639 unbind_from_irqhandler(info->irq, info); 640 info->irq = -1; 641 } 642 643 static void xenfb_backend_changed(struct xenbus_device *dev, 644 enum xenbus_state backend_state) 645 { 646 struct xenfb_info *info = dev_get_drvdata(&dev->dev); 647 648 switch (backend_state) { 649 case XenbusStateInitialising: 650 case XenbusStateInitialised: 651 case XenbusStateReconfiguring: 652 case XenbusStateReconfigured: 653 case XenbusStateUnknown: 654 break; 655 656 case XenbusStateInitWait: 657 xenbus_switch_state(dev, XenbusStateConnected); 658 break; 659 660 case XenbusStateConnected: 661 /* 662 * Work around xenbus race condition: If backend goes 663 * through InitWait to Connected fast enough, we can 664 * get Connected twice here. 665 */ 666 if (dev->state != XenbusStateConnected) 667 /* no InitWait seen yet, fudge it */ 668 xenbus_switch_state(dev, XenbusStateConnected); 669 670 if (xenbus_read_unsigned(info->xbdev->otherend, 671 "request-update", 0)) 672 info->update_wanted = 1; 673 674 info->feature_resize = xenbus_read_unsigned(dev->otherend, 675 "feature-resize", 0); 676 break; 677 678 case XenbusStateClosed: 679 if (dev->state == XenbusStateClosed) 680 break; 681 fallthrough; /* Missed the backend's CLOSING state */ 682 case XenbusStateClosing: 683 xenbus_frontend_closed(dev); 684 break; 685 } 686 } 687 688 static const struct xenbus_device_id xenfb_ids[] = { 689 { "vfb" }, 690 { "" } 691 }; 692 693 static struct xenbus_driver xenfb_driver = { 694 .ids = xenfb_ids, 695 .probe = xenfb_probe, 696 .remove = xenfb_remove, 697 .resume = xenfb_resume, 698 .otherend_changed = xenfb_backend_changed, 699 .not_essential = true, 700 }; 701 702 static int __init xenfb_init(void) 703 { 704 if (!xen_domain()) 705 return -ENODEV; 706 707 /* Nothing to do if running in dom0. */ 708 if (xen_initial_domain()) 709 return -ENODEV; 710 711 if (!xen_has_pv_devices()) 712 return -ENODEV; 713 714 return xenbus_register_frontend(&xenfb_driver); 715 } 716 717 static void __exit xenfb_cleanup(void) 718 { 719 xenbus_unregister_driver(&xenfb_driver); 720 } 721 722 module_init(xenfb_init); 723 module_exit(xenfb_cleanup); 724 725 MODULE_DESCRIPTION("Xen virtual framebuffer device frontend"); 726 MODULE_LICENSE("GPL"); 727 MODULE_ALIAS("xen:vfb"); 728