📄 xen-fbfront.c
字号:
return IRQ_HANDLED;}static int __devinit xenfb_probe(struct xenbus_device *dev, const struct xenbus_device_id *id){ struct xenfb_info *info; struct fb_info *fb_info; int fb_size; int val; int ret; info = kzalloc(sizeof(*info), GFP_KERNEL); if (info == NULL) { xenbus_dev_fatal(dev, -ENOMEM, "allocating info structure"); return -ENOMEM; } /* Limit kernel param videoram amount to what is in xenstore */ if (xenbus_scanf(XBT_NIL, dev->otherend, "videoram", "%d", &val) == 1) { if (val < video[KPARAM_MEM]) video[KPARAM_MEM] = val; } /* If requested res does not fit in available memory, use default */ fb_size = video[KPARAM_MEM] * 1024 * 1024; if (video[KPARAM_WIDTH] * video[KPARAM_HEIGHT] * XENFB_DEPTH / 8 > fb_size) { video[KPARAM_WIDTH] = XENFB_WIDTH; video[KPARAM_HEIGHT] = XENFB_HEIGHT; fb_size = XENFB_DEFAULT_FB_LEN; } dev->dev.driver_data = info; info->xbdev = dev; info->irq = -1; info->x1 = info->y1 = INT_MAX; spin_lock_init(&info->dirty_lock); spin_lock_init(&info->resize_lock); info->fb = vmalloc(fb_size); if (info->fb == NULL) goto error_nomem; memset(info->fb, 0, fb_size); info->nr_pages = (fb_size + PAGE_SIZE - 1) >> PAGE_SHIFT; info->mfns = vmalloc(sizeof(unsigned long) * info->nr_pages); if (!info->mfns) goto error_nomem; /* set up shared page */ info->page = (void *)__get_free_page(GFP_KERNEL | __GFP_ZERO); if (!info->page) goto error_nomem; /* abusing framebuffer_alloc() to allocate pseudo_palette */ fb_info = framebuffer_alloc(sizeof(u32) * 256, NULL); if (fb_info == NULL) goto error_nomem; /* complete the abuse: */ fb_info->pseudo_palette = fb_info->par; fb_info->par = info; fb_info->screen_base = info->fb; fb_info->fbops = &xenfb_fb_ops; fb_info->var.xres_virtual = fb_info->var.xres = video[KPARAM_WIDTH]; fb_info->var.yres_virtual = fb_info->var.yres = video[KPARAM_HEIGHT]; fb_info->var.bits_per_pixel = XENFB_DEPTH; fb_info->var.red = (struct fb_bitfield){16, 8, 0}; fb_info->var.green = (struct fb_bitfield){8, 8, 0}; fb_info->var.blue = (struct fb_bitfield){0, 8, 0}; fb_info->var.activate = FB_ACTIVATE_NOW; fb_info->var.height = -1; fb_info->var.width = -1; fb_info->var.vmode = FB_VMODE_NONINTERLACED; fb_info->fix.visual = FB_VISUAL_TRUECOLOR; fb_info->fix.line_length = fb_info->var.xres * XENFB_DEPTH / 8; fb_info->fix.smem_start = 0; fb_info->fix.smem_len = fb_size; strcpy(fb_info->fix.id, "xen"); fb_info->fix.type = FB_TYPE_PACKED_PIXELS; fb_info->fix.accel = FB_ACCEL_NONE; fb_info->flags = FBINFO_FLAG_DEFAULT; ret = fb_alloc_cmap(&fb_info->cmap, 256, 0); if (ret < 0) { framebuffer_release(fb_info); xenbus_dev_fatal(dev, ret, "fb_alloc_cmap"); goto error; } fb_info->fbdefio = &xenfb_defio; fb_deferred_io_init(fb_info); xenfb_init_shared_page(info, fb_info); ret = register_framebuffer(fb_info); if (ret) { fb_deferred_io_cleanup(fb_info); fb_dealloc_cmap(&fb_info->cmap); framebuffer_release(fb_info); xenbus_dev_fatal(dev, ret, "register_framebuffer"); goto error; } info->fb_info = fb_info; ret = xenfb_connect_backend(dev, info); if (ret < 0) goto error; xenfb_make_preferred_console(); return 0; error_nomem: ret = -ENOMEM; xenbus_dev_fatal(dev, ret, "allocating device memory"); error: xenfb_remove(dev); return ret;}static __devinit voidxenfb_make_preferred_console(void){ struct console *c; if (console_set_on_cmdline) return; acquire_console_sem(); for (c = console_drivers; c; c = c->next) { if (!strcmp(c->name, "tty") && c->index == 0) break; } release_console_sem(); if (c) { unregister_console(c); c->flags |= CON_CONSDEV; c->flags &= ~CON_PRINTBUFFER; /* don't print again */ register_console(c); }}static int xenfb_resume(struct xenbus_device *dev){ struct xenfb_info *info = dev->dev.driver_data; xenfb_disconnect_backend(info); xenfb_init_shared_page(info, info->fb_info); return xenfb_connect_backend(dev, info);}static int xenfb_remove(struct xenbus_device *dev){ struct xenfb_info *info = dev->dev.driver_data; xenfb_disconnect_backend(info); if (info->fb_info) { fb_deferred_io_cleanup(info->fb_info); unregister_framebuffer(info->fb_info); fb_dealloc_cmap(&info->fb_info->cmap); framebuffer_release(info->fb_info); } free_page((unsigned long)info->page); vfree(info->mfns); vfree(info->fb); kfree(info); return 0;}static unsigned long vmalloc_to_mfn(void *address){ return pfn_to_mfn(vmalloc_to_pfn(address));}static void xenfb_init_shared_page(struct xenfb_info *info, struct fb_info *fb_info){ int i; int epd = PAGE_SIZE / sizeof(info->mfns[0]); for (i = 0; i < info->nr_pages; i++) info->mfns[i] = vmalloc_to_mfn(info->fb + i * PAGE_SIZE); for (i = 0; i * epd < info->nr_pages; i++) info->page->pd[i] = vmalloc_to_mfn(&info->mfns[i * epd]); info->page->width = fb_info->var.xres; info->page->height = fb_info->var.yres; info->page->depth = fb_info->var.bits_per_pixel; info->page->line_length = fb_info->fix.line_length; info->page->mem_length = fb_info->fix.smem_len; info->page->in_cons = info->page->in_prod = 0; info->page->out_cons = info->page->out_prod = 0;}static int xenfb_connect_backend(struct xenbus_device *dev, struct xenfb_info *info){ int ret, evtchn; struct xenbus_transaction xbt; ret = xenbus_alloc_evtchn(dev, &evtchn); if (ret) return ret; ret = bind_evtchn_to_irqhandler(evtchn, xenfb_event_handler, 0, dev->devicetype, info); if (ret < 0) { xenbus_free_evtchn(dev, evtchn); xenbus_dev_fatal(dev, ret, "bind_evtchn_to_irqhandler"); return ret; } info->irq = ret; again: ret = xenbus_transaction_start(&xbt); if (ret) { xenbus_dev_fatal(dev, ret, "starting transaction"); return ret; } ret = xenbus_printf(xbt, dev->nodename, "page-ref", "%lu", virt_to_mfn(info->page)); if (ret) goto error_xenbus; ret = xenbus_printf(xbt, dev->nodename, "event-channel", "%u", evtchn); if (ret) goto error_xenbus; ret = xenbus_printf(xbt, dev->nodename, "protocol", "%s", XEN_IO_PROTO_ABI_NATIVE); if (ret) goto error_xenbus; ret = xenbus_printf(xbt, dev->nodename, "feature-update", "1"); if (ret) goto error_xenbus; ret = xenbus_transaction_end(xbt, 0); if (ret) { if (ret == -EAGAIN) goto again; xenbus_dev_fatal(dev, ret, "completing transaction"); return ret; } xenbus_switch_state(dev, XenbusStateInitialised); return 0; error_xenbus: xenbus_transaction_end(xbt, 1); xenbus_dev_fatal(dev, ret, "writing xenstore"); return ret;}static void xenfb_disconnect_backend(struct xenfb_info *info){ if (info->irq >= 0) unbind_from_irqhandler(info->irq, info); info->irq = -1;}static void xenfb_backend_changed(struct xenbus_device *dev, enum xenbus_state backend_state){ struct xenfb_info *info = dev->dev.driver_data; int val; switch (backend_state) { case XenbusStateInitialising: case XenbusStateInitialised: case XenbusStateUnknown: case XenbusStateClosed: break; case XenbusStateInitWait:InitWait: xenbus_switch_state(dev, XenbusStateConnected); break; case XenbusStateConnected: /* * Work around xenbus race condition: If backend goes * through InitWait to Connected fast enough, we can * get Connected twice here. */ if (dev->state != XenbusStateConnected) goto InitWait; /* no InitWait seen yet, fudge it */ if (xenbus_scanf(XBT_NIL, info->xbdev->otherend, "request-update", "%d", &val) < 0) val = 0; if (val) info->update_wanted = 1; if (xenbus_scanf(XBT_NIL, dev->otherend, "feature-resize", "%d", &val) < 0) val = 0; info->feature_resize = val; break; case XenbusStateClosing: xenbus_frontend_closed(dev); break; }}static struct xenbus_device_id xenfb_ids[] = { { "vfb" }, { "" }};static struct xenbus_driver xenfb_driver = { .name = "vfb", .owner = THIS_MODULE, .ids = xenfb_ids, .probe = xenfb_probe, .remove = xenfb_remove, .resume = xenfb_resume, .otherend_changed = xenfb_backend_changed,};static int __init xenfb_init(void){ if (!xen_domain()) return -ENODEV; /* Nothing to do if running in dom0. */ if (xen_initial_domain()) return -ENODEV; return xenbus_register_frontend(&xenfb_driver);}static void __exit xenfb_cleanup(void){ xenbus_unregister_driver(&xenfb_driver);}module_init(xenfb_init);module_exit(xenfb_cleanup);MODULE_DESCRIPTION("Xen virtual framebuffer device frontend");MODULE_LICENSE("GPL");MODULE_ALIAS("xen:vfb");
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -