root/drivers/video/fbdev/xen-fbfront.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. xenfb_send_event
  2. xenfb_do_update
  3. xenfb_do_resize
  4. xenfb_queue_full
  5. xenfb_handle_resize_dpy
  6. xenfb_refresh
  7. xenfb_deferred_io
  8. xenfb_setcolreg
  9. xenfb_fillrect
  10. xenfb_imageblit
  11. xenfb_copyarea
  12. xenfb_write
  13. xenfb_check_var
  14. xenfb_set_par
  15. xenfb_event_handler
  16. xenfb_probe
  17. xenfb_make_preferred_console
  18. xenfb_resume
  19. xenfb_remove
  20. vmalloc_to_gfn
  21. xenfb_init_shared_page
  22. xenfb_connect_backend
  23. xenfb_disconnect_backend
  24. xenfb_backend_changed
  25. xenfb_init
  26. xenfb_cleanup

   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,
 185                               struct list_head *pagelist)
 186 {
 187         struct xenfb_info *info = fb_info->par;
 188         struct page *page;
 189         unsigned long beg, end;
 190         int y1, y2, miny, maxy;
 191 
 192         miny = INT_MAX;
 193         maxy = 0;
 194         list_for_each_entry(page, pagelist, lru) {
 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 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 };
 342 
 343 static irqreturn_t xenfb_event_handler(int rq, void *dev_id)
 344 {
 345         /*
 346          * No in events recognized, simply ignore them all.
 347          * If you need to recognize some, see xen-kbdfront's
 348          * input_handler() for how to do that.
 349          */
 350         struct xenfb_info *info = dev_id;
 351         struct xenfb_page *page = info->page;
 352 
 353         if (page->in_cons != page->in_prod) {
 354                 info->page->in_cons = info->page->in_prod;
 355                 notify_remote_via_irq(info->irq);
 356         }
 357 
 358         /* Flush dirty rectangle: */
 359         xenfb_refresh(info, INT_MAX, INT_MAX, -INT_MAX, -INT_MAX);
 360 
 361         return IRQ_HANDLED;
 362 }
 363 
 364 static int xenfb_probe(struct xenbus_device *dev,
 365                        const struct xenbus_device_id *id)
 366 {
 367         struct xenfb_info *info;
 368         struct fb_info *fb_info;
 369         int fb_size;
 370         int val;
 371         int ret = 0;
 372 
 373         info = kzalloc(sizeof(*info), GFP_KERNEL);
 374         if (info == NULL) {
 375                 xenbus_dev_fatal(dev, -ENOMEM, "allocating info structure");
 376                 return -ENOMEM;
 377         }
 378 
 379         /* Limit kernel param videoram amount to what is in xenstore */
 380         if (xenbus_scanf(XBT_NIL, dev->otherend, "videoram", "%d", &val) == 1) {
 381                 if (val < video[KPARAM_MEM])
 382                         video[KPARAM_MEM] = val;
 383         }
 384 
 385         video[KPARAM_WIDTH] = xenbus_read_unsigned(dev->otherend, "width",
 386                                                    video[KPARAM_WIDTH]);
 387         video[KPARAM_HEIGHT] = xenbus_read_unsigned(dev->otherend, "height",
 388                                                     video[KPARAM_HEIGHT]);
 389 
 390         /* If requested res does not fit in available memory, use default */
 391         fb_size = video[KPARAM_MEM] * 1024 * 1024;
 392         if (video[KPARAM_WIDTH] * video[KPARAM_HEIGHT] * XENFB_DEPTH / 8
 393             > fb_size) {
 394                 pr_warn("display parameters %d,%d,%d invalid, use defaults\n",
 395                         video[KPARAM_MEM], video[KPARAM_WIDTH],
 396                         video[KPARAM_HEIGHT]);
 397                 video[KPARAM_WIDTH] = XENFB_WIDTH;
 398                 video[KPARAM_HEIGHT] = XENFB_HEIGHT;
 399                 fb_size = XENFB_DEFAULT_FB_LEN;
 400         }
 401 
 402         dev_set_drvdata(&dev->dev, info);
 403         info->xbdev = dev;
 404         info->irq = -1;
 405         info->x1 = info->y1 = INT_MAX;
 406         spin_lock_init(&info->dirty_lock);
 407         spin_lock_init(&info->resize_lock);
 408 
 409         info->fb = vzalloc(fb_size);
 410         if (info->fb == NULL)
 411                 goto error_nomem;
 412 
 413         info->nr_pages = (fb_size + PAGE_SIZE - 1) >> PAGE_SHIFT;
 414 
 415         info->gfns = vmalloc(array_size(sizeof(unsigned long), info->nr_pages));
 416         if (!info->gfns)
 417                 goto error_nomem;
 418 
 419         /* set up shared page */
 420         info->page = (void *)__get_free_page(GFP_KERNEL | __GFP_ZERO);
 421         if (!info->page)
 422                 goto error_nomem;
 423 
 424         /* abusing framebuffer_alloc() to allocate pseudo_palette */
 425         fb_info = framebuffer_alloc(sizeof(u32) * 256, NULL);
 426         if (fb_info == NULL)
 427                 goto error_nomem;
 428 
 429         /* complete the abuse: */
 430         fb_info->pseudo_palette = fb_info->par;
 431         fb_info->par = info;
 432 
 433         fb_info->screen_base = info->fb;
 434 
 435         fb_info->fbops = &xenfb_fb_ops;
 436         fb_info->var.xres_virtual = fb_info->var.xres = video[KPARAM_WIDTH];
 437         fb_info->var.yres_virtual = fb_info->var.yres = video[KPARAM_HEIGHT];
 438         fb_info->var.bits_per_pixel = XENFB_DEPTH;
 439 
 440         fb_info->var.red = (struct fb_bitfield){16, 8, 0};
 441         fb_info->var.green = (struct fb_bitfield){8, 8, 0};
 442         fb_info->var.blue = (struct fb_bitfield){0, 8, 0};
 443 
 444         fb_info->var.activate = FB_ACTIVATE_NOW;
 445         fb_info->var.height = -1;
 446         fb_info->var.width = -1;
 447         fb_info->var.vmode = FB_VMODE_NONINTERLACED;
 448 
 449         fb_info->fix.visual = FB_VISUAL_TRUECOLOR;
 450         fb_info->fix.line_length = fb_info->var.xres * XENFB_DEPTH / 8;
 451         fb_info->fix.smem_start = 0;
 452         fb_info->fix.smem_len = fb_size;
 453         strcpy(fb_info->fix.id, "xen");
 454         fb_info->fix.type = FB_TYPE_PACKED_PIXELS;
 455         fb_info->fix.accel = FB_ACCEL_NONE;
 456 
 457         fb_info->flags = FBINFO_FLAG_DEFAULT | FBINFO_VIRTFB;
 458 
 459         ret = fb_alloc_cmap(&fb_info->cmap, 256, 0);
 460         if (ret < 0) {
 461                 framebuffer_release(fb_info);
 462                 xenbus_dev_fatal(dev, ret, "fb_alloc_cmap");
 463                 goto error;
 464         }
 465 
 466         fb_info->fbdefio = &xenfb_defio;
 467         fb_deferred_io_init(fb_info);
 468 
 469         xenfb_init_shared_page(info, fb_info);
 470 
 471         ret = xenfb_connect_backend(dev, info);
 472         if (ret < 0) {
 473                 xenbus_dev_fatal(dev, ret, "xenfb_connect_backend");
 474                 goto error_fb;
 475         }
 476 
 477         ret = register_framebuffer(fb_info);
 478         if (ret) {
 479                 xenbus_dev_fatal(dev, ret, "register_framebuffer");
 480                 goto error_fb;
 481         }
 482         info->fb_info = fb_info;
 483 
 484         xenfb_make_preferred_console();
 485         return 0;
 486 
 487 error_fb:
 488         fb_deferred_io_cleanup(fb_info);
 489         fb_dealloc_cmap(&fb_info->cmap);
 490         framebuffer_release(fb_info);
 491 error_nomem:
 492         if (!ret) {
 493                 ret = -ENOMEM;
 494                 xenbus_dev_fatal(dev, ret, "allocating device memory");
 495         }
 496 error:
 497         xenfb_remove(dev);
 498         return ret;
 499 }
 500 
 501 static void xenfb_make_preferred_console(void)
 502 {
 503         struct console *c;
 504 
 505         if (console_set_on_cmdline)
 506                 return;
 507 
 508         console_lock();
 509         for_each_console(c) {
 510                 if (!strcmp(c->name, "tty") && c->index == 0)
 511                         break;
 512         }
 513         console_unlock();
 514         if (c) {
 515                 unregister_console(c);
 516                 c->flags |= CON_CONSDEV;
 517                 c->flags &= ~CON_PRINTBUFFER; /* don't print again */
 518                 register_console(c);
 519         }
 520 }
 521 
 522 static int xenfb_resume(struct xenbus_device *dev)
 523 {
 524         struct xenfb_info *info = dev_get_drvdata(&dev->dev);
 525 
 526         xenfb_disconnect_backend(info);
 527         xenfb_init_shared_page(info, info->fb_info);
 528         return xenfb_connect_backend(dev, info);
 529 }
 530 
 531 static int xenfb_remove(struct xenbus_device *dev)
 532 {
 533         struct xenfb_info *info = dev_get_drvdata(&dev->dev);
 534 
 535         xenfb_disconnect_backend(info);
 536         if (info->fb_info) {
 537                 fb_deferred_io_cleanup(info->fb_info);
 538                 unregister_framebuffer(info->fb_info);
 539                 fb_dealloc_cmap(&info->fb_info->cmap);
 540                 framebuffer_release(info->fb_info);
 541         }
 542         free_page((unsigned long)info->page);
 543         vfree(info->gfns);
 544         vfree(info->fb);
 545         kfree(info);
 546 
 547         return 0;
 548 }
 549 
 550 static unsigned long vmalloc_to_gfn(void *address)
 551 {
 552         return xen_page_to_gfn(vmalloc_to_page(address));
 553 }
 554 
 555 static void xenfb_init_shared_page(struct xenfb_info *info,
 556                                    struct fb_info *fb_info)
 557 {
 558         int i;
 559         int epd = PAGE_SIZE / sizeof(info->gfns[0]);
 560 
 561         for (i = 0; i < info->nr_pages; i++)
 562                 info->gfns[i] = vmalloc_to_gfn(info->fb + i * PAGE_SIZE);
 563 
 564         for (i = 0; i * epd < info->nr_pages; i++)
 565                 info->page->pd[i] = vmalloc_to_gfn(&info->gfns[i * epd]);
 566 
 567         info->page->width = fb_info->var.xres;
 568         info->page->height = fb_info->var.yres;
 569         info->page->depth = fb_info->var.bits_per_pixel;
 570         info->page->line_length = fb_info->fix.line_length;
 571         info->page->mem_length = fb_info->fix.smem_len;
 572         info->page->in_cons = info->page->in_prod = 0;
 573         info->page->out_cons = info->page->out_prod = 0;
 574 }
 575 
 576 static int xenfb_connect_backend(struct xenbus_device *dev,
 577                                  struct xenfb_info *info)
 578 {
 579         int ret, evtchn, irq;
 580         struct xenbus_transaction xbt;
 581 
 582         ret = xenbus_alloc_evtchn(dev, &evtchn);
 583         if (ret)
 584                 return ret;
 585         irq = bind_evtchn_to_irqhandler(evtchn, xenfb_event_handler,
 586                                         0, dev->devicetype, info);
 587         if (irq < 0) {
 588                 xenbus_free_evtchn(dev, evtchn);
 589                 xenbus_dev_fatal(dev, ret, "bind_evtchn_to_irqhandler");
 590                 return irq;
 591         }
 592  again:
 593         ret = xenbus_transaction_start(&xbt);
 594         if (ret) {
 595                 xenbus_dev_fatal(dev, ret, "starting transaction");
 596                 goto unbind_irq;
 597         }
 598         ret = xenbus_printf(xbt, dev->nodename, "page-ref", "%lu",
 599                             virt_to_gfn(info->page));
 600         if (ret)
 601                 goto error_xenbus;
 602         ret = xenbus_printf(xbt, dev->nodename, "event-channel", "%u",
 603                             evtchn);
 604         if (ret)
 605                 goto error_xenbus;
 606         ret = xenbus_printf(xbt, dev->nodename, "protocol", "%s",
 607                             XEN_IO_PROTO_ABI_NATIVE);
 608         if (ret)
 609                 goto error_xenbus;
 610         ret = xenbus_printf(xbt, dev->nodename, "feature-update", "1");
 611         if (ret)
 612                 goto error_xenbus;
 613         ret = xenbus_transaction_end(xbt, 0);
 614         if (ret) {
 615                 if (ret == -EAGAIN)
 616                         goto again;
 617                 xenbus_dev_fatal(dev, ret, "completing transaction");
 618                 goto unbind_irq;
 619         }
 620 
 621         xenbus_switch_state(dev, XenbusStateInitialised);
 622         info->irq = irq;
 623         return 0;
 624 
 625  error_xenbus:
 626         xenbus_transaction_end(xbt, 1);
 627         xenbus_dev_fatal(dev, ret, "writing xenstore");
 628  unbind_irq:
 629         unbind_from_irqhandler(irq, info);
 630         return ret;
 631 }
 632 
 633 static void xenfb_disconnect_backend(struct xenfb_info *info)
 634 {
 635         /* Prevent xenfb refresh */
 636         info->update_wanted = 0;
 637         if (info->irq >= 0)
 638                 unbind_from_irqhandler(info->irq, info);
 639         info->irq = -1;
 640 }
 641 
 642 static void xenfb_backend_changed(struct xenbus_device *dev,
 643                                   enum xenbus_state backend_state)
 644 {
 645         struct xenfb_info *info = dev_get_drvdata(&dev->dev);
 646 
 647         switch (backend_state) {
 648         case XenbusStateInitialising:
 649         case XenbusStateInitialised:
 650         case XenbusStateReconfiguring:
 651         case XenbusStateReconfigured:
 652         case XenbusStateUnknown:
 653                 break;
 654 
 655         case XenbusStateInitWait:
 656                 xenbus_switch_state(dev, XenbusStateConnected);
 657                 break;
 658 
 659         case XenbusStateConnected:
 660                 /*
 661                  * Work around xenbus race condition: If backend goes
 662                  * through InitWait to Connected fast enough, we can
 663                  * get Connected twice here.
 664                  */
 665                 if (dev->state != XenbusStateConnected)
 666                         /* no InitWait seen yet, fudge it */
 667                         xenbus_switch_state(dev, XenbusStateConnected);
 668 
 669                 if (xenbus_read_unsigned(info->xbdev->otherend,
 670                                          "request-update", 0))
 671                         info->update_wanted = 1;
 672 
 673                 info->feature_resize = xenbus_read_unsigned(dev->otherend,
 674                                                         "feature-resize", 0);
 675                 break;
 676 
 677         case XenbusStateClosed:
 678                 if (dev->state == XenbusStateClosed)
 679                         break;
 680                 /* fall through - Missed the backend's CLOSING state. */
 681         case XenbusStateClosing:
 682                 xenbus_frontend_closed(dev);
 683                 break;
 684         }
 685 }
 686 
 687 static const struct xenbus_device_id xenfb_ids[] = {
 688         { "vfb" },
 689         { "" }
 690 };
 691 
 692 static struct xenbus_driver xenfb_driver = {
 693         .ids = xenfb_ids,
 694         .probe = xenfb_probe,
 695         .remove = xenfb_remove,
 696         .resume = xenfb_resume,
 697         .otherend_changed = xenfb_backend_changed,
 698 };
 699 
 700 static int __init xenfb_init(void)
 701 {
 702         if (!xen_domain())
 703                 return -ENODEV;
 704 
 705         /* Nothing to do if running in dom0. */
 706         if (xen_initial_domain())
 707                 return -ENODEV;
 708 
 709         if (!xen_has_pv_devices())
 710                 return -ENODEV;
 711 
 712         return xenbus_register_frontend(&xenfb_driver);
 713 }
 714 
 715 static void __exit xenfb_cleanup(void)
 716 {
 717         xenbus_unregister_driver(&xenfb_driver);
 718 }
 719 
 720 module_init(xenfb_init);
 721 module_exit(xenfb_cleanup);
 722 
 723 MODULE_DESCRIPTION("Xen virtual framebuffer device frontend");
 724 MODULE_LICENSE("GPL");
 725 MODULE_ALIAS("xen:vfb");

/* [<][>][^][v][top][bottom][index][help] */