xen-fbfront.c 17 KB

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