2 * Xen para-virtual frame buffer device
4 * Copyright (C) 2005-2006 Anthony Liguori <aliguori@us.ibm.com>
5 * Copyright (C) 2006-2008 Red Hat, Inc., Markus Armbruster <armbru@redhat.com>
7 * Based on linux/drivers/video/q40fb.c
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
17 * Switch to grant tables when they become capable of dealing with the
21 #include <linux/console.h>
22 #include <linux/kernel.h>
23 #include <linux/errno.h>
25 #include <linux/module.h>
26 #include <linux/vmalloc.h>
28 #include <asm/xen/hypervisor.h>
29 #include <xen/events.h>
31 #include <xen/interface/io/fbif.h>
32 #include <xen/interface/io/protocols.h>
33 #include <xen/xenbus.h>
37 struct fb_info
*fb_info
;
38 int x1
, y1
, x2
, y2
; /* dirty rectangle,
39 protected by dirty_lock */
40 spinlock_t dirty_lock
;
43 struct xenfb_page
*page
;
45 int update_wanted
; /* XENFB_TYPE_UPDATE wanted */
47 struct xenbus_device
*xbdev
;
50 static u32 xenfb_mem_len
= XENFB_WIDTH
* XENFB_HEIGHT
* XENFB_DEPTH
/ 8;
52 static void xenfb_make_preferred_console(void);
53 static int xenfb_remove(struct xenbus_device
*);
54 static void xenfb_init_shared_page(struct xenfb_info
*);
55 static int xenfb_connect_backend(struct xenbus_device
*, struct xenfb_info
*);
56 static void xenfb_disconnect_backend(struct xenfb_info
*);
58 static void xenfb_do_update(struct xenfb_info
*info
,
59 int x
, int y
, int w
, int h
)
61 union xenfb_out_event event
;
64 memset(&event
, 0, sizeof(event
));
65 event
.type
= XENFB_TYPE_UPDATE
;
68 event
.update
.width
= w
;
69 event
.update
.height
= h
;
71 prod
= info
->page
->out_prod
;
72 /* caller ensures !xenfb_queue_full() */
73 mb(); /* ensure ring space available */
74 XENFB_OUT_RING_REF(info
->page
, prod
) = event
;
75 wmb(); /* ensure ring contents visible */
76 info
->page
->out_prod
= prod
+ 1;
78 notify_remote_via_irq(info
->irq
);
81 static int xenfb_queue_full(struct xenfb_info
*info
)
85 prod
= info
->page
->out_prod
;
86 cons
= info
->page
->out_cons
;
87 return prod
- cons
== XENFB_OUT_RING_LEN
;
90 static void xenfb_refresh(struct xenfb_info
*info
,
91 int x1
, int y1
, int w
, int h
)
97 if (!info
->update_wanted
)
100 spin_lock_irqsave(&info
->dirty_lock
, flags
);
102 /* Combine with dirty rectangle: */
112 if (xenfb_queue_full(info
)) {
113 /* Can't send right now, stash it in the dirty rectangle */
118 spin_unlock_irqrestore(&info
->dirty_lock
, flags
);
122 /* Clear dirty rectangle: */
123 info
->x1
= info
->y1
= INT_MAX
;
124 info
->x2
= info
->y2
= 0;
126 spin_unlock_irqrestore(&info
->dirty_lock
, flags
);
128 if (x1
<= x2
&& y1
<= y2
)
129 xenfb_do_update(info
, x1
, y1
, x2
- x1
+ 1, y2
- y1
+ 1);
132 static void xenfb_deferred_io(struct fb_info
*fb_info
,
133 struct list_head
*pagelist
)
135 struct xenfb_info
*info
= fb_info
->par
;
137 unsigned long beg
, end
;
138 int y1
, y2
, miny
, maxy
;
142 list_for_each_entry(page
, pagelist
, lru
) {
143 beg
= page
->index
<< PAGE_SHIFT
;
144 end
= beg
+ PAGE_SIZE
- 1;
145 y1
= beg
/ fb_info
->fix
.line_length
;
146 y2
= end
/ fb_info
->fix
.line_length
;
147 if (y2
>= fb_info
->var
.yres
)
148 y2
= fb_info
->var
.yres
- 1;
154 xenfb_refresh(info
, 0, miny
, fb_info
->var
.xres
, maxy
- miny
+ 1);
157 static struct fb_deferred_io xenfb_defio
= {
159 .deferred_io
= xenfb_deferred_io
,
162 static int xenfb_setcolreg(unsigned regno
, unsigned red
, unsigned green
,
163 unsigned blue
, unsigned transp
,
164 struct fb_info
*info
)
168 if (regno
> info
->cmap
.len
)
171 #define CNVT_TOHW(val, width) ((((val)<<(width))+0x7FFF-(val))>>16)
172 red
= CNVT_TOHW(red
, info
->var
.red
.length
);
173 green
= CNVT_TOHW(green
, info
->var
.green
.length
);
174 blue
= CNVT_TOHW(blue
, info
->var
.blue
.length
);
175 transp
= CNVT_TOHW(transp
, info
->var
.transp
.length
);
178 v
= (red
<< info
->var
.red
.offset
) |
179 (green
<< info
->var
.green
.offset
) |
180 (blue
<< info
->var
.blue
.offset
);
182 switch (info
->var
.bits_per_pixel
) {
186 ((u32
*)info
->pseudo_palette
)[regno
] = v
;
193 static void xenfb_fillrect(struct fb_info
*p
, const struct fb_fillrect
*rect
)
195 struct xenfb_info
*info
= p
->par
;
197 sys_fillrect(p
, rect
);
198 xenfb_refresh(info
, rect
->dx
, rect
->dy
, rect
->width
, rect
->height
);
201 static void xenfb_imageblit(struct fb_info
*p
, const struct fb_image
*image
)
203 struct xenfb_info
*info
= p
->par
;
205 sys_imageblit(p
, image
);
206 xenfb_refresh(info
, image
->dx
, image
->dy
, image
->width
, image
->height
);
209 static void xenfb_copyarea(struct fb_info
*p
, const struct fb_copyarea
*area
)
211 struct xenfb_info
*info
= p
->par
;
213 sys_copyarea(p
, area
);
214 xenfb_refresh(info
, area
->dx
, area
->dy
, area
->width
, area
->height
);
217 static ssize_t
xenfb_write(struct fb_info
*p
, const char __user
*buf
,
218 size_t count
, loff_t
*ppos
)
220 struct xenfb_info
*info
= p
->par
;
223 res
= fb_sys_write(p
, buf
, count
, ppos
);
224 xenfb_refresh(info
, 0, 0, info
->page
->width
, info
->page
->height
);
228 static struct fb_ops xenfb_fb_ops
= {
229 .owner
= THIS_MODULE
,
230 .fb_read
= fb_sys_read
,
231 .fb_write
= xenfb_write
,
232 .fb_setcolreg
= xenfb_setcolreg
,
233 .fb_fillrect
= xenfb_fillrect
,
234 .fb_copyarea
= xenfb_copyarea
,
235 .fb_imageblit
= xenfb_imageblit
,
238 static irqreturn_t
xenfb_event_handler(int rq
, void *dev_id
)
241 * No in events recognized, simply ignore them all.
242 * If you need to recognize some, see xen-kbdfront's
243 * input_handler() for how to do that.
245 struct xenfb_info
*info
= dev_id
;
246 struct xenfb_page
*page
= info
->page
;
248 if (page
->in_cons
!= page
->in_prod
) {
249 info
->page
->in_cons
= info
->page
->in_prod
;
250 notify_remote_via_irq(info
->irq
);
253 /* Flush dirty rectangle: */
254 xenfb_refresh(info
, INT_MAX
, INT_MAX
, -INT_MAX
, -INT_MAX
);
259 static int __devinit
xenfb_probe(struct xenbus_device
*dev
,
260 const struct xenbus_device_id
*id
)
262 struct xenfb_info
*info
;
263 struct fb_info
*fb_info
;
266 info
= kzalloc(sizeof(*info
), GFP_KERNEL
);
268 xenbus_dev_fatal(dev
, -ENOMEM
, "allocating info structure");
271 dev
->dev
.driver_data
= info
;
274 info
->x1
= info
->y1
= INT_MAX
;
275 spin_lock_init(&info
->dirty_lock
);
277 info
->fb
= vmalloc(xenfb_mem_len
);
278 if (info
->fb
== NULL
)
280 memset(info
->fb
, 0, xenfb_mem_len
);
282 info
->nr_pages
= (xenfb_mem_len
+ PAGE_SIZE
- 1) >> PAGE_SHIFT
;
284 info
->mfns
= vmalloc(sizeof(unsigned long) * info
->nr_pages
);
288 /* set up shared page */
289 info
->page
= (void *)__get_free_page(GFP_KERNEL
| __GFP_ZERO
);
293 xenfb_init_shared_page(info
);
295 /* abusing framebuffer_alloc() to allocate pseudo_palette */
296 fb_info
= framebuffer_alloc(sizeof(u32
) * 256, NULL
);
300 /* complete the abuse: */
301 fb_info
->pseudo_palette
= fb_info
->par
;
304 fb_info
->screen_base
= info
->fb
;
306 fb_info
->fbops
= &xenfb_fb_ops
;
307 fb_info
->var
.xres_virtual
= fb_info
->var
.xres
= info
->page
->width
;
308 fb_info
->var
.yres_virtual
= fb_info
->var
.yres
= info
->page
->height
;
309 fb_info
->var
.bits_per_pixel
= info
->page
->depth
;
311 fb_info
->var
.red
= (struct fb_bitfield
){16, 8, 0};
312 fb_info
->var
.green
= (struct fb_bitfield
){8, 8, 0};
313 fb_info
->var
.blue
= (struct fb_bitfield
){0, 8, 0};
315 fb_info
->var
.activate
= FB_ACTIVATE_NOW
;
316 fb_info
->var
.height
= -1;
317 fb_info
->var
.width
= -1;
318 fb_info
->var
.vmode
= FB_VMODE_NONINTERLACED
;
320 fb_info
->fix
.visual
= FB_VISUAL_TRUECOLOR
;
321 fb_info
->fix
.line_length
= info
->page
->line_length
;
322 fb_info
->fix
.smem_start
= 0;
323 fb_info
->fix
.smem_len
= xenfb_mem_len
;
324 strcpy(fb_info
->fix
.id
, "xen");
325 fb_info
->fix
.type
= FB_TYPE_PACKED_PIXELS
;
326 fb_info
->fix
.accel
= FB_ACCEL_NONE
;
328 fb_info
->flags
= FBINFO_FLAG_DEFAULT
;
330 ret
= fb_alloc_cmap(&fb_info
->cmap
, 256, 0);
332 framebuffer_release(fb_info
);
333 xenbus_dev_fatal(dev
, ret
, "fb_alloc_cmap");
337 fb_info
->fbdefio
= &xenfb_defio
;
338 fb_deferred_io_init(fb_info
);
340 ret
= register_framebuffer(fb_info
);
342 fb_deferred_io_cleanup(fb_info
);
343 fb_dealloc_cmap(&fb_info
->cmap
);
344 framebuffer_release(fb_info
);
345 xenbus_dev_fatal(dev
, ret
, "register_framebuffer");
348 info
->fb_info
= fb_info
;
350 ret
= xenfb_connect_backend(dev
, info
);
354 xenfb_make_preferred_console();
359 xenbus_dev_fatal(dev
, ret
, "allocating device memory");
365 static __devinit
void
366 xenfb_make_preferred_console(void)
370 if (console_set_on_cmdline
)
373 acquire_console_sem();
374 for (c
= console_drivers
; c
; c
= c
->next
) {
375 if (!strcmp(c
->name
, "tty") && c
->index
== 0)
378 release_console_sem();
380 unregister_console(c
);
381 c
->flags
|= CON_CONSDEV
;
382 c
->flags
&= ~CON_PRINTBUFFER
; /* don't print again */
387 static int xenfb_resume(struct xenbus_device
*dev
)
389 struct xenfb_info
*info
= dev
->dev
.driver_data
;
391 xenfb_disconnect_backend(info
);
392 xenfb_init_shared_page(info
);
393 return xenfb_connect_backend(dev
, info
);
396 static int xenfb_remove(struct xenbus_device
*dev
)
398 struct xenfb_info
*info
= dev
->dev
.driver_data
;
400 xenfb_disconnect_backend(info
);
402 fb_deferred_io_cleanup(info
->fb_info
);
403 unregister_framebuffer(info
->fb_info
);
404 fb_dealloc_cmap(&info
->fb_info
->cmap
);
405 framebuffer_release(info
->fb_info
);
407 free_page((unsigned long)info
->page
);
415 static unsigned long vmalloc_to_mfn(void *address
)
417 return pfn_to_mfn(vmalloc_to_pfn(address
));
420 static void xenfb_init_shared_page(struct xenfb_info
*info
)
424 for (i
= 0; i
< info
->nr_pages
; i
++)
425 info
->mfns
[i
] = vmalloc_to_mfn(info
->fb
+ i
* PAGE_SIZE
);
427 info
->page
->pd
[0] = vmalloc_to_mfn(info
->mfns
);
428 info
->page
->pd
[1] = 0;
429 info
->page
->width
= XENFB_WIDTH
;
430 info
->page
->height
= XENFB_HEIGHT
;
431 info
->page
->depth
= XENFB_DEPTH
;
432 info
->page
->line_length
= (info
->page
->depth
/ 8) * info
->page
->width
;
433 info
->page
->mem_length
= xenfb_mem_len
;
434 info
->page
->in_cons
= info
->page
->in_prod
= 0;
435 info
->page
->out_cons
= info
->page
->out_prod
= 0;
438 static int xenfb_connect_backend(struct xenbus_device
*dev
,
439 struct xenfb_info
*info
)
442 struct xenbus_transaction xbt
;
444 ret
= xenbus_alloc_evtchn(dev
, &evtchn
);
447 ret
= bind_evtchn_to_irqhandler(evtchn
, xenfb_event_handler
,
448 0, dev
->devicetype
, info
);
450 xenbus_free_evtchn(dev
, evtchn
);
451 xenbus_dev_fatal(dev
, ret
, "bind_evtchn_to_irqhandler");
457 ret
= xenbus_transaction_start(&xbt
);
459 xenbus_dev_fatal(dev
, ret
, "starting transaction");
462 ret
= xenbus_printf(xbt
, dev
->nodename
, "page-ref", "%lu",
463 virt_to_mfn(info
->page
));
466 ret
= xenbus_printf(xbt
, dev
->nodename
, "event-channel", "%u",
470 ret
= xenbus_printf(xbt
, dev
->nodename
, "protocol", "%s",
471 XEN_IO_PROTO_ABI_NATIVE
);
474 ret
= xenbus_printf(xbt
, dev
->nodename
, "feature-update", "1");
477 ret
= xenbus_transaction_end(xbt
, 0);
481 xenbus_dev_fatal(dev
, ret
, "completing transaction");
485 xenbus_switch_state(dev
, XenbusStateInitialised
);
489 xenbus_transaction_end(xbt
, 1);
490 xenbus_dev_fatal(dev
, ret
, "writing xenstore");
494 static void xenfb_disconnect_backend(struct xenfb_info
*info
)
497 unbind_from_irqhandler(info
->irq
, info
);
501 static void xenfb_backend_changed(struct xenbus_device
*dev
,
502 enum xenbus_state backend_state
)
504 struct xenfb_info
*info
= dev
->dev
.driver_data
;
507 switch (backend_state
) {
508 case XenbusStateInitialising
:
509 case XenbusStateInitialised
:
510 case XenbusStateUnknown
:
511 case XenbusStateClosed
:
514 case XenbusStateInitWait
:
516 xenbus_switch_state(dev
, XenbusStateConnected
);
519 case XenbusStateConnected
:
521 * Work around xenbus race condition: If backend goes
522 * through InitWait to Connected fast enough, we can
523 * get Connected twice here.
525 if (dev
->state
!= XenbusStateConnected
)
526 goto InitWait
; /* no InitWait seen yet, fudge it */
528 if (xenbus_scanf(XBT_NIL
, info
->xbdev
->otherend
,
529 "request-update", "%d", &val
) < 0)
532 info
->update_wanted
= 1;
535 case XenbusStateClosing
:
536 xenbus_frontend_closed(dev
);
541 static struct xenbus_device_id xenfb_ids
[] = {
546 static struct xenbus_driver xenfb
= {
548 .owner
= THIS_MODULE
,
550 .probe
= xenfb_probe
,
551 .remove
= xenfb_remove
,
552 .resume
= xenfb_resume
,
553 .otherend_changed
= xenfb_backend_changed
,
556 static int __init
xenfb_init(void)
558 if (!is_running_on_xen())
561 /* Nothing to do if running in dom0. */
562 if (is_initial_xendomain())
565 return xenbus_register_frontend(&xenfb
);
568 static void __exit
xenfb_cleanup(void)
570 xenbus_unregister_driver(&xenfb
);
573 module_init(xenfb_init
);
574 module_exit(xenfb_cleanup
);
576 MODULE_DESCRIPTION("Xen virtual framebuffer device frontend");
577 MODULE_LICENSE("GPL");
578 MODULE_ALIAS("xen:vfb");