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