xen-fbfront.c 17 KB

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