ia64/xen-unstable

changeset 12740:dfaf8493a211

Merge.
author Steven Smith <ssmith@xensource.com>
date Fri Dec 01 13:12:41 2006 +0000 (2006-12-01)
parents 056050ceb300 d57b0e2834d7
children 4d53706e8028
files tools/python/xen/xend/XendDomainInfo.py
line diff
     1.1 --- a/linux-2.6-xen-sparse/arch/i386/kernel/setup-xen.c	Fri Dec 01 13:08:36 2006 +0000
     1.2 +++ b/linux-2.6-xen-sparse/arch/i386/kernel/setup-xen.c	Fri Dec 01 13:12:41 2006 +0000
     1.3 @@ -1867,9 +1867,11 @@ void __init setup_arch(char **cmdline_p)
     1.4  #endif
     1.5  #endif
     1.6  	} else {
     1.7 -		extern int console_use_vt;
     1.8 -		console_use_vt = 0;
     1.9 +#if defined(CONFIG_VT) && defined(CONFIG_DUMMY_CONSOLE)
    1.10 +		conswitchp = &dummy_con;
    1.11 +#endif
    1.12  	}
    1.13 +	xencons_early_setup();
    1.14  }
    1.15  
    1.16  static int
     2.1 --- a/linux-2.6-xen-sparse/arch/ia64/kernel/setup.c	Fri Dec 01 13:08:36 2006 +0000
     2.2 +++ b/linux-2.6-xen-sparse/arch/ia64/kernel/setup.c	Fri Dec 01 13:12:41 2006 +0000
     2.3 @@ -550,14 +550,16 @@ setup_arch (char **cmdline_p)
     2.4  		       xen_start_info->nr_pages, xen_start_info->flags);
     2.5  
     2.6  		if (!is_initial_xendomain()) {
     2.7 -			extern int console_use_vt;
     2.8 +#if !defined(CONFIG_VT) || !defined(CONFIG_DUMMY_CONSOLE)
     2.9  			conswitchp = NULL;
    2.10 -			console_use_vt = 0;
    2.11 +#endif
    2.12  		}
    2.13  	}
    2.14 +	xencons_early_setup();
    2.15  #endif
    2.16  #endif
    2.17  
    2.18 +
    2.19  	/* enable IA-64 Machine Check Abort Handling unless disabled */
    2.20  	if (!strstr(saved_command_line, "nomca"))
    2.21  		ia64_mca_init();
     3.1 --- a/linux-2.6-xen-sparse/arch/x86_64/kernel/setup-xen.c	Fri Dec 01 13:08:36 2006 +0000
     3.2 +++ b/linux-2.6-xen-sparse/arch/x86_64/kernel/setup-xen.c	Fri Dec 01 13:12:41 2006 +0000
     3.3 @@ -983,10 +983,12 @@ void __init setup_arch(char **cmdline_p)
     3.4  #endif
     3.5  #endif
     3.6  		} else {
     3.7 -			extern int console_use_vt;
     3.8 -			console_use_vt = 0;
     3.9 -		}
    3.10 +#if defined(CONFIG_VT) && defined(CONFIG_DUMMY_CONSOLE)
    3.11 +			conswitchp = &dummy_con;
    3.12 +#endif
    3.13 +                }
    3.14  	}
    3.15 +	xencons_early_setup();
    3.16  #else	/* CONFIG_XEN */
    3.17  
    3.18  #ifdef CONFIG_VT
     4.1 --- a/linux-2.6-xen-sparse/drivers/xen/Kconfig	Fri Dec 01 13:08:36 2006 +0000
     4.2 +++ b/linux-2.6-xen-sparse/drivers/xen/Kconfig	Fri Dec 01 13:12:41 2006 +0000
     4.3 @@ -172,6 +172,29 @@ config XEN_NETDEV_FRONTEND
     4.4  	  dedicated device-driver domain, or your master control domain
     4.5  	  (domain 0), then you almost certainly want to say Y here.
     4.6  
     4.7 +config XEN_FRAMEBUFFER
     4.8 +	tristate "Framebuffer-device frontend driver"
     4.9 +	depends on XEN && FB
    4.10 +	select FB_CFB_FILLRECT
    4.11 +	select FB_CFB_COPYAREA
    4.12 +	select FB_CFB_IMAGEBLIT
    4.13 +	default y
    4.14 +	help
    4.15 +	  The framebuffer-device frontend drivers allows the kernel to create a
    4.16 +	  virtual framebuffer.  This framebuffer can be viewed in another
    4.17 +	  domain.  Unless this domain has access to a real video card, you
    4.18 +	  probably want to say Y here.
    4.19 +
    4.20 +config XEN_KEYBOARD
    4.21 +	tristate "Keyboard-device frontend driver"
    4.22 +	depends on XEN && XEN_FRAMEBUFFER && INPUT
    4.23 +	default y
    4.24 +	help
    4.25 +	  The keyboard-device frontend driver allows the kernel to create a
    4.26 +	  virtual keyboard.  This keyboard can then be driven by another
    4.27 +	  domain.  If you've said Y to CONFIG_XEN_FRAMEBUFFER, you probably
    4.28 +	  want to say Y here.
    4.29 +
    4.30  config XEN_SCRUB_PAGES
    4.31  	bool "Scrub memory before freeing it to Xen"
    4.32  	default y
     5.1 --- a/linux-2.6-xen-sparse/drivers/xen/Makefile	Fri Dec 01 13:08:36 2006 +0000
     5.2 +++ b/linux-2.6-xen-sparse/drivers/xen/Makefile	Fri Dec 01 13:12:41 2006 +0000
     5.3 @@ -15,3 +15,5 @@ obj-$(CONFIG_XEN_BLKDEV_FRONTEND)	+= blk
     5.4  obj-$(CONFIG_XEN_NETDEV_FRONTEND)	+= netfront/
     5.5  obj-$(CONFIG_XEN_PCIDEV_BACKEND)	+= pciback/
     5.6  obj-$(CONFIG_XEN_PCIDEV_FRONTEND)	+= pcifront/
     5.7 +obj-$(CONFIG_XEN_FRAMEBUFFER)		+= fbfront/
     5.8 +obj-$(CONFIG_XEN_KEYBOARD)		+= fbfront/
     6.1 --- a/linux-2.6-xen-sparse/drivers/xen/console/console.c	Fri Dec 01 13:08:36 2006 +0000
     6.2 +++ b/linux-2.6-xen-sparse/drivers/xen/console/console.c	Fri Dec 01 13:12:41 2006 +0000
     6.3 @@ -57,6 +57,7 @@
     6.4  #include <xen/interface/event_channel.h>
     6.5  #include <asm/hypervisor.h>
     6.6  #include <xen/evtchn.h>
     6.7 +#include <xen/xenbus.h>
     6.8  #include <xen/xencons.h>
     6.9  
    6.10  /*
    6.11 @@ -65,14 +66,14 @@
    6.12   *  'xencons=tty'  [XC_TTY]:     Console attached to '/dev/tty[0-9]+'.
    6.13   *  'xencons=ttyS' [XC_SERIAL]:  Console attached to '/dev/ttyS[0-9]+'.
    6.14   *  'xencons=xvc'  [XC_XVC]:     Console attached to '/dev/xvc0'.
    6.15 - *                 [XC_DEFAULT]: DOM0 -> XC_SERIAL ; all others -> XC_TTY.
    6.16 + *  default:                     DOM0 -> XC_SERIAL ; all others -> XC_TTY.
    6.17   * 
    6.18   * NB. In mode XC_TTY, we create dummy consoles for tty2-63. This suppresses
    6.19   * warnings from standard distro startup scripts.
    6.20   */
    6.21  static enum {
    6.22 -	XC_OFF, XC_DEFAULT, XC_TTY, XC_SERIAL, XC_XVC
    6.23 -} xc_mode = XC_DEFAULT;
    6.24 +	XC_OFF, XC_TTY, XC_SERIAL, XC_XVC
    6.25 +} xc_mode;
    6.26  static int xc_num = -1;
    6.27  
    6.28  /* /dev/xvc0 device number allocated by lanana.org. */
    6.29 @@ -84,17 +85,32 @@ static unsigned long sysrq_requested;
    6.30  extern int sysrq_enabled;
    6.31  #endif
    6.32  
    6.33 +void xencons_early_setup(void)
    6.34 +{
    6.35 +	extern int console_use_vt;
    6.36 +
    6.37 +	if (is_initial_xendomain()) {
    6.38 +		xc_mode = XC_SERIAL;
    6.39 +	} else {
    6.40 +		xc_mode = XC_TTY;
    6.41 +		console_use_vt = 0;
    6.42 +	}
    6.43 +}
    6.44 +
    6.45  static int __init xencons_setup(char *str)
    6.46  {
    6.47  	char *q;
    6.48  	int n;
    6.49 +	extern int console_use_vt;
    6.50  
    6.51 +	console_use_vt = 1;
    6.52  	if (!strncmp(str, "ttyS", 4)) {
    6.53  		xc_mode = XC_SERIAL;
    6.54  		str += 4;
    6.55  	} else if (!strncmp(str, "tty", 3)) {
    6.56  		xc_mode = XC_TTY;
    6.57  		str += 3;
    6.58 +		console_use_vt = 0;
    6.59  	} else if (!strncmp(str, "xvc", 3)) {
    6.60  		xc_mode = XC_XVC;
    6.61  		str += 3;
    6.62 @@ -192,14 +208,10 @@ static int __init xen_console_init(void)
    6.63  		goto out;
    6.64  
    6.65  	if (is_initial_xendomain()) {
    6.66 -		if (xc_mode == XC_DEFAULT)
    6.67 -			xc_mode = XC_SERIAL;
    6.68  		kcons_info.write = kcons_write_dom0;
    6.69  	} else {
    6.70  		if (!xen_start_info->console.domU.evtchn)
    6.71  			goto out;
    6.72 -		if (xc_mode == XC_DEFAULT)
    6.73 -			xc_mode = XC_TTY;
    6.74  		kcons_info.write = kcons_write;
    6.75  	}
    6.76  
     7.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     7.2 +++ b/linux-2.6-xen-sparse/drivers/xen/fbfront/Makefile	Fri Dec 01 13:12:41 2006 +0000
     7.3 @@ -0,0 +1,2 @@
     7.4 +obj-$(CONFIG_XEN_FRAMEBUFFER)	:= xenfb.o
     7.5 +obj-$(CONFIG_XEN_KEYBOARD)	+= xenkbd.o
     8.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     8.2 +++ b/linux-2.6-xen-sparse/drivers/xen/fbfront/xenfb.c	Fri Dec 01 13:12:41 2006 +0000
     8.3 @@ -0,0 +1,682 @@
     8.4 +/*
     8.5 + * linux/drivers/video/xenfb.c -- Xen para-virtual frame buffer device
     8.6 + *
     8.7 + * Copyright (C) 2005-2006 Anthony Liguori <aliguori@us.ibm.com>
     8.8 + * Copyright (C) 2006 Red Hat, Inc., Markus Armbruster <armbru@redhat.com>
     8.9 + *
    8.10 + *  Based on linux/drivers/video/q40fb.c
    8.11 + *
    8.12 + *  This file is subject to the terms and conditions of the GNU General Public
    8.13 + *  License. See the file COPYING in the main directory of this archive for
    8.14 + *  more details.
    8.15 + */
    8.16 +
    8.17 +/*
    8.18 + * TODO:
    8.19 + *
    8.20 + * Switch to grant tables when they become capable of dealing with the
    8.21 + * frame buffer.
    8.22 + */
    8.23 +
    8.24 +#include <linux/kernel.h>
    8.25 +#include <linux/errno.h>
    8.26 +#include <linux/fb.h>
    8.27 +#include <linux/module.h>
    8.28 +#include <linux/vmalloc.h>
    8.29 +#include <linux/mm.h>
    8.30 +#include <asm/hypervisor.h>
    8.31 +#include <xen/evtchn.h>
    8.32 +#include <xen/interface/io/fbif.h>
    8.33 +#include <xen/xenbus.h>
    8.34 +#include <linux/kthread.h>
    8.35 +
    8.36 +struct xenfb_mapping
    8.37 +{
    8.38 +	struct list_head	link;
    8.39 +	struct vm_area_struct	*vma;
    8.40 +	atomic_t		map_refs;
    8.41 +	int			faults;
    8.42 +	struct xenfb_info	*info;
    8.43 +};
    8.44 +
    8.45 +struct xenfb_info
    8.46 +{
    8.47 +	struct task_struct	*kthread;
    8.48 +	wait_queue_head_t	wq;
    8.49 +
    8.50 +	unsigned char		*fb;
    8.51 +	struct fb_info		*fb_info;
    8.52 +	struct timer_list	refresh;
    8.53 +	int			dirty;
    8.54 +	int			x1, y1, x2, y2;	/* dirty rectangle,
    8.55 +						   protected by mm_lock */
    8.56 +	spinlock_t		mm_lock;
    8.57 +	int			nr_pages;
    8.58 +	struct page		**pages;
    8.59 +	struct list_head	mappings; /* protected by mm_lock */
    8.60 +
    8.61 +	unsigned		evtchn;
    8.62 +	int			irq;
    8.63 +	struct xenfb_page	*page;
    8.64 +	unsigned long 		*mfns;
    8.65 +	int			update_wanted; /* XENFB_TYPE_UPDATE wanted */
    8.66 +
    8.67 +	struct xenbus_device	*xbdev;
    8.68 +};
    8.69 +
    8.70 +static int xenfb_fps = 20;
    8.71 +static unsigned long xenfb_mem_len = XENFB_WIDTH * XENFB_HEIGHT * XENFB_DEPTH / 8;
    8.72 +
    8.73 +static int xenfb_remove(struct xenbus_device *);
    8.74 +static void xenfb_init_shared_page(struct xenfb_info *);
    8.75 +static int xenfb_connect_backend(struct xenbus_device *, struct xenfb_info *);
    8.76 +static void xenfb_disconnect_backend(struct xenfb_info *);
    8.77 +
    8.78 +static void xenfb_do_update(struct xenfb_info *info,
    8.79 +			    int x, int y, int w, int h)
    8.80 +{
    8.81 +	union xenfb_out_event event;
    8.82 +	__u32 prod;
    8.83 +
    8.84 +	event.type = XENFB_TYPE_UPDATE;
    8.85 +	event.update.x = x;
    8.86 +	event.update.y = y;
    8.87 +	event.update.width = w;
    8.88 +	event.update.height = h;
    8.89 +
    8.90 +	prod = info->page->out_prod;
    8.91 +	/* caller ensures !xenfb_queue_full() */
    8.92 +	mb();			/* ensure ring space available */
    8.93 +	XENFB_OUT_RING_REF(info->page, prod) = event;
    8.94 +	wmb();			/* ensure ring contents visible */
    8.95 +	info->page->out_prod = prod + 1;
    8.96 +
    8.97 +	notify_remote_via_evtchn(info->evtchn);
    8.98 +}
    8.99 +
   8.100 +static int xenfb_queue_full(struct xenfb_info *info)
   8.101 +{
   8.102 +	__u32 cons, prod;
   8.103 +
   8.104 +	prod = info->page->out_prod;
   8.105 +	cons = info->page->out_cons;
   8.106 +	return prod - cons == XENFB_OUT_RING_LEN;
   8.107 +}
   8.108 +
   8.109 +static void xenfb_update_screen(struct xenfb_info *info)
   8.110 +{
   8.111 +	unsigned long flags;
   8.112 +	int y1, y2, x1, x2;
   8.113 +	struct xenfb_mapping *map;
   8.114 +
   8.115 +	if (!info->update_wanted)
   8.116 +		return;
   8.117 +	if (xenfb_queue_full(info))
   8.118 +		return;
   8.119 +
   8.120 +	spin_lock_irqsave(&info->mm_lock, flags);
   8.121 +
   8.122 +	y1 = info->y1;
   8.123 +	y2 = info->y2;
   8.124 +	x1 = info->x1;
   8.125 +	x2 = info->x2;
   8.126 +	info->x1 = info->y1 = INT_MAX;
   8.127 +	info->x2 = info->y2 = 0;
   8.128 +
   8.129 +	list_for_each_entry(map, &info->mappings, link) {
   8.130 +		if (!map->faults)
   8.131 +			continue;
   8.132 +		zap_page_range(map->vma, map->vma->vm_start,
   8.133 +			       map->vma->vm_end - map->vma->vm_start, NULL);
   8.134 +		map->faults = 0;
   8.135 +	}
   8.136 +
   8.137 +	spin_unlock_irqrestore(&info->mm_lock, flags);
   8.138 +
   8.139 +	xenfb_do_update(info, x1, y1, x2 - x1, y2 - y1);
   8.140 +}
   8.141 +
   8.142 +static int xenfb_thread(void *data)
   8.143 +{
   8.144 +	struct xenfb_info *info = data;
   8.145 +
   8.146 +	while (!kthread_should_stop()) {
   8.147 +		if (info->dirty) {
   8.148 +			info->dirty = 0;
   8.149 +			xenfb_update_screen(info);
   8.150 +		}
   8.151 +		wait_event_interruptible(info->wq,
   8.152 +			kthread_should_stop() || info->dirty);
   8.153 +		try_to_freeze();
   8.154 +	}
   8.155 +	return 0;
   8.156 +}
   8.157 +
   8.158 +static int xenfb_setcolreg(unsigned regno, unsigned red, unsigned green,
   8.159 +			   unsigned blue, unsigned transp,
   8.160 +			   struct fb_info *info)
   8.161 +{
   8.162 +	u32 v;
   8.163 +
   8.164 +	if (regno > info->cmap.len)
   8.165 +		return 1;
   8.166 +
   8.167 +	red   >>= (16 - info->var.red.length);
   8.168 +	green >>= (16 - info->var.green.length);
   8.169 +	blue  >>= (16 - info->var.blue.length);
   8.170 +
   8.171 +	v = (red << info->var.red.offset) |
   8.172 +	    (green << info->var.green.offset) |
   8.173 +	    (blue << info->var.blue.offset);
   8.174 +
   8.175 +	/* FIXME is this sane?  check against xxxfb_setcolreg()!  */
   8.176 +	switch (info->var.bits_per_pixel) {
   8.177 +	case 16:
   8.178 +	case 24:
   8.179 +	case 32:
   8.180 +		((u32 *)info->pseudo_palette)[regno] = v;
   8.181 +		break;
   8.182 +	}
   8.183 +	
   8.184 +	return 0;
   8.185 +}
   8.186 +
   8.187 +static void xenfb_timer(unsigned long data)
   8.188 +{
   8.189 +	struct xenfb_info *info = (struct xenfb_info *)data;
   8.190 +	info->dirty = 1;
   8.191 +	wake_up(&info->wq);
   8.192 +}
   8.193 +
   8.194 +static void __xenfb_refresh(struct xenfb_info *info,
   8.195 +			    int x1, int y1, int w, int h)
   8.196 +{
   8.197 +	int y2, x2;
   8.198 +
   8.199 +	y2 = y1 + h;
   8.200 +	x2 = x1 + w;
   8.201 +
   8.202 +	if (info->y1 > y1)
   8.203 +		info->y1 = y1;
   8.204 +	if (info->y2 < y2)
   8.205 +		info->y2 = y2;
   8.206 +	if (info->x1 > x1)
   8.207 +		info->x1 = x1;
   8.208 +	if (info->x2 < x2)
   8.209 +		info->x2 = x2;
   8.210 +
   8.211 +	if (timer_pending(&info->refresh))
   8.212 +		return;
   8.213 +
   8.214 +	mod_timer(&info->refresh, jiffies + HZ/xenfb_fps);
   8.215 +}
   8.216 +
   8.217 +static void xenfb_refresh(struct xenfb_info *info,
   8.218 +			  int x1, int y1, int w, int h)
   8.219 +{
   8.220 +	unsigned long flags;
   8.221 +
   8.222 +	spin_lock_irqsave(&info->mm_lock, flags);
   8.223 +	__xenfb_refresh(info, x1, y1, w, h);
   8.224 +	spin_unlock_irqrestore(&info->mm_lock, flags);
   8.225 +}
   8.226 +
   8.227 +static void xenfb_fillrect(struct fb_info *p, const struct fb_fillrect *rect)
   8.228 +{
   8.229 +	struct xenfb_info *info = p->par;
   8.230 +
   8.231 +	cfb_fillrect(p, rect);
   8.232 +	xenfb_refresh(info, rect->dx, rect->dy, rect->width, rect->height);
   8.233 +}
   8.234 +
   8.235 +static void xenfb_imageblit(struct fb_info *p, const struct fb_image *image)
   8.236 +{
   8.237 +	struct xenfb_info *info = p->par;
   8.238 +
   8.239 +	cfb_imageblit(p, image);
   8.240 +	xenfb_refresh(info, image->dx, image->dy, image->width, image->height);
   8.241 +}
   8.242 +
   8.243 +static void xenfb_copyarea(struct fb_info *p, const struct fb_copyarea *area)
   8.244 +{
   8.245 +	struct xenfb_info *info = p->par;
   8.246 +
   8.247 +	cfb_copyarea(p, area);
   8.248 +	xenfb_refresh(info, area->dx, area->dy, area->width, area->height);
   8.249 +}
   8.250 +
   8.251 +static void xenfb_vm_open(struct vm_area_struct *vma)
   8.252 +{
   8.253 +	struct xenfb_mapping *map = vma->vm_private_data;
   8.254 +	atomic_inc(&map->map_refs);
   8.255 +}
   8.256 +
   8.257 +static void xenfb_vm_close(struct vm_area_struct *vma)
   8.258 +{
   8.259 +	struct xenfb_mapping *map = vma->vm_private_data;
   8.260 +	struct xenfb_info *info = map->info;
   8.261 +	unsigned long flags;
   8.262 +
   8.263 +	spin_lock_irqsave(&info->mm_lock, flags);
   8.264 +	if (atomic_dec_and_test(&map->map_refs)) {
   8.265 +		list_del(&map->link);
   8.266 +		kfree(map);
   8.267 +	}
   8.268 +	spin_unlock_irqrestore(&info->mm_lock, flags);
   8.269 +}
   8.270 +
   8.271 +static struct page *xenfb_vm_nopage(struct vm_area_struct *vma,
   8.272 +				    unsigned long vaddr, int *type)
   8.273 +{
   8.274 +	struct xenfb_mapping *map = vma->vm_private_data;
   8.275 +	struct xenfb_info *info = map->info;
   8.276 +	int pgnr = (vaddr - vma->vm_start) >> PAGE_SHIFT;
   8.277 +	unsigned long flags;
   8.278 +	struct page *page;
   8.279 +	int y1, y2;
   8.280 +
   8.281 +	if (pgnr >= info->nr_pages)
   8.282 +		return NOPAGE_SIGBUS;
   8.283 +
   8.284 +	spin_lock_irqsave(&info->mm_lock, flags);
   8.285 +	page = info->pages[pgnr];
   8.286 +	get_page(page);
   8.287 +	map->faults++;
   8.288 +
   8.289 +	y1 = pgnr * PAGE_SIZE / info->fb_info->fix.line_length;
   8.290 +	y2 = (pgnr * PAGE_SIZE + PAGE_SIZE - 1) / info->fb_info->fix.line_length;
   8.291 +	if (y2 > info->fb_info->var.yres)
   8.292 +		y2 = info->fb_info->var.yres;
   8.293 +	__xenfb_refresh(info, 0, y1, info->fb_info->var.xres, y2 - y1);
   8.294 +	spin_unlock_irqrestore(&info->mm_lock, flags);
   8.295 +
   8.296 +	if (type)
   8.297 +		*type = VM_FAULT_MINOR;
   8.298 +
   8.299 +	return page;
   8.300 +}
   8.301 +
   8.302 +static struct vm_operations_struct xenfb_vm_ops = {
   8.303 +	.open	= xenfb_vm_open,
   8.304 +	.close	= xenfb_vm_close,
   8.305 +	.nopage	= xenfb_vm_nopage,
   8.306 +};
   8.307 +
   8.308 +static int xenfb_mmap(struct fb_info *fb_info, struct vm_area_struct *vma)
   8.309 +{
   8.310 +	struct xenfb_info *info = fb_info->par;
   8.311 +	unsigned long flags;
   8.312 +	struct xenfb_mapping *map;
   8.313 +	int map_pages;
   8.314 +
   8.315 +	if (!(vma->vm_flags & VM_WRITE))
   8.316 +		return -EINVAL;
   8.317 +	if (!(vma->vm_flags & VM_SHARED))
   8.318 +		return -EINVAL;
   8.319 +	if (vma->vm_pgoff != 0)
   8.320 +		return -EINVAL;
   8.321 +
   8.322 +	map_pages = (vma->vm_end - vma->vm_start + PAGE_SIZE-1) >> PAGE_SHIFT;
   8.323 +	if (map_pages > info->nr_pages)
   8.324 +		return -EINVAL;
   8.325 +
   8.326 +	map = kzalloc(sizeof(*map), GFP_KERNEL);
   8.327 +	if (map == NULL)
   8.328 +		return -ENOMEM;
   8.329 +
   8.330 +	map->vma = vma;
   8.331 +	map->faults = 0;
   8.332 +	map->info = info;
   8.333 +	atomic_set(&map->map_refs, 1);
   8.334 +
   8.335 +	spin_lock_irqsave(&info->mm_lock, flags);
   8.336 +	list_add(&map->link, &info->mappings);
   8.337 +	spin_unlock_irqrestore(&info->mm_lock, flags);
   8.338 +
   8.339 +	vma->vm_ops = &xenfb_vm_ops;
   8.340 +	vma->vm_flags |= (VM_DONTEXPAND | VM_RESERVED);
   8.341 +	vma->vm_private_data = map;
   8.342 +
   8.343 +	return 0;
   8.344 +}
   8.345 +
   8.346 +static struct fb_ops xenfb_fb_ops = {
   8.347 +	.owner		= THIS_MODULE,
   8.348 +	.fb_setcolreg	= xenfb_setcolreg,
   8.349 +	.fb_fillrect	= xenfb_fillrect,
   8.350 +	.fb_copyarea	= xenfb_copyarea,
   8.351 +	.fb_imageblit	= xenfb_imageblit,
   8.352 +	.fb_mmap	= xenfb_mmap,
   8.353 +};
   8.354 +
   8.355 +static irqreturn_t xenfb_event_handler(int rq, void *dev_id,
   8.356 +				       struct pt_regs *regs)
   8.357 +{
   8.358 +	/*
   8.359 +	 * No in events recognized, simply ignore them all.
   8.360 +	 * If you need to recognize some, see xenbkd's input_handler()
   8.361 +	 * for how to do that.
   8.362 +	 */
   8.363 +	struct xenfb_info *info = dev_id;
   8.364 +	struct xenfb_page *page = info->page;
   8.365 +
   8.366 +	if (page->in_cons != page->in_prod) {
   8.367 +		info->page->in_cons = info->page->in_prod;
   8.368 +		notify_remote_via_evtchn(info->evtchn);
   8.369 +	}
   8.370 +	return IRQ_HANDLED;
   8.371 +}
   8.372 +
   8.373 +static unsigned long vmalloc_to_mfn(void *address)
   8.374 +{
   8.375 +	return pfn_to_mfn(vmalloc_to_pfn(address));
   8.376 +}
   8.377 +
   8.378 +static int __devinit xenfb_probe(struct xenbus_device *dev,
   8.379 +				 const struct xenbus_device_id *id)
   8.380 +{
   8.381 +	struct xenfb_info *info;
   8.382 +	struct fb_info *fb_info;
   8.383 +	int ret;
   8.384 +
   8.385 +	info = kzalloc(sizeof(*info), GFP_KERNEL);
   8.386 +	if (info == NULL) {
   8.387 +		xenbus_dev_fatal(dev, -ENOMEM, "allocating info structure");
   8.388 +		return -ENOMEM;
   8.389 +	}
   8.390 +	dev->dev.driver_data = info;
   8.391 +	info->xbdev = dev;
   8.392 +	info->irq = -1;
   8.393 +	info->x1 = info->y1 = INT_MAX;
   8.394 +	spin_lock_init(&info->mm_lock);
   8.395 +	init_waitqueue_head(&info->wq);
   8.396 +	init_timer(&info->refresh);
   8.397 +	info->refresh.function = xenfb_timer;
   8.398 +	info->refresh.data = (unsigned long)info;
   8.399 +	INIT_LIST_HEAD(&info->mappings);
   8.400 +
   8.401 +	info->fb = vmalloc(xenfb_mem_len);
   8.402 +	if (info->fb == NULL)
   8.403 +		goto error_nomem;
   8.404 +	memset(info->fb, 0, xenfb_mem_len);
   8.405 +
   8.406 +	info->nr_pages = (xenfb_mem_len + PAGE_SIZE - 1) >> PAGE_SHIFT;
   8.407 +
   8.408 +	info->pages = kmalloc(sizeof(struct page *) * info->nr_pages,
   8.409 +			      GFP_KERNEL);
   8.410 +	if (info->pages == NULL)
   8.411 +		goto error_nomem;
   8.412 +
   8.413 +	info->mfns = vmalloc(sizeof(unsigned long) * info->nr_pages);
   8.414 +	if (!info->mfns)
   8.415 +		goto error_nomem;
   8.416 +
   8.417 +	/* set up shared page */
   8.418 +	info->page = (void *)__get_free_page(GFP_KERNEL);
   8.419 +	if (!info->page)
   8.420 +		goto error_nomem;
   8.421 +
   8.422 +	xenfb_init_shared_page(info);
   8.423 +
   8.424 +	fb_info = framebuffer_alloc(sizeof(u32) * 256, NULL);
   8.425 +				/* see fishy hackery below */
   8.426 +	if (fb_info == NULL)
   8.427 +		goto error_nomem;
   8.428 +
   8.429 +	/* FIXME fishy hackery */
   8.430 +	fb_info->pseudo_palette = fb_info->par;
   8.431 +	fb_info->par = info;
   8.432 +	/* /FIXME */
   8.433 +	fb_info->screen_base = info->fb;
   8.434 +
   8.435 +	fb_info->fbops = &xenfb_fb_ops;
   8.436 +	fb_info->var.xres_virtual = fb_info->var.xres = info->page->width;
   8.437 +	fb_info->var.yres_virtual = fb_info->var.yres = info->page->height;
   8.438 +	fb_info->var.bits_per_pixel = info->page->depth;
   8.439 +
   8.440 +	fb_info->var.red = (struct fb_bitfield){16, 8, 0};
   8.441 +	fb_info->var.green = (struct fb_bitfield){8, 8, 0};
   8.442 +	fb_info->var.blue = (struct fb_bitfield){0, 8, 0};
   8.443 +
   8.444 +	fb_info->var.activate = FB_ACTIVATE_NOW;
   8.445 +	fb_info->var.height = -1;
   8.446 +	fb_info->var.width = -1;
   8.447 +	fb_info->var.vmode = FB_VMODE_NONINTERLACED;
   8.448 +
   8.449 +	fb_info->fix.visual = FB_VISUAL_TRUECOLOR;
   8.450 +	fb_info->fix.line_length = info->page->line_length;
   8.451 +	fb_info->fix.smem_start = 0;
   8.452 +	fb_info->fix.smem_len = xenfb_mem_len;
   8.453 +	strcpy(fb_info->fix.id, "xen");
   8.454 +	fb_info->fix.type = FB_TYPE_PACKED_PIXELS;
   8.455 +	fb_info->fix.accel = FB_ACCEL_NONE;
   8.456 +
   8.457 +	fb_info->flags = FBINFO_FLAG_DEFAULT;
   8.458 +
   8.459 +	ret = fb_alloc_cmap(&fb_info->cmap, 256, 0);
   8.460 +	if (ret < 0) {
   8.461 +		framebuffer_release(fb_info);
   8.462 +		xenbus_dev_fatal(dev, ret, "fb_alloc_cmap");
   8.463 +		goto error;
   8.464 +	}
   8.465 +
   8.466 +	ret = register_framebuffer(fb_info);
   8.467 +	if (ret) {
   8.468 +		fb_dealloc_cmap(&info->fb_info->cmap);
   8.469 +		framebuffer_release(fb_info);
   8.470 +		xenbus_dev_fatal(dev, ret, "register_framebuffer");
   8.471 +		goto error;
   8.472 +	}
   8.473 +	info->fb_info = fb_info;
   8.474 +
   8.475 +	/* FIXME should this be delayed until backend XenbusStateConnected? */
   8.476 +	info->kthread = kthread_run(xenfb_thread, info, "xenfb thread");
   8.477 +	if (IS_ERR(info->kthread)) {
   8.478 +		ret = PTR_ERR(info->kthread);
   8.479 +		info->kthread = NULL;
   8.480 +		xenbus_dev_fatal(dev, ret, "register_framebuffer");
   8.481 +		goto error;
   8.482 +	}
   8.483 +
   8.484 +	ret = xenfb_connect_backend(dev, info);
   8.485 +	if (ret < 0)
   8.486 +		goto error;
   8.487 +
   8.488 +	return 0;
   8.489 +
   8.490 + error_nomem:
   8.491 +	ret = -ENOMEM;
   8.492 +	xenbus_dev_fatal(dev, ret, "allocating device memory");
   8.493 + error:
   8.494 +	xenfb_remove(dev);
   8.495 +	return ret;
   8.496 +}
   8.497 +
   8.498 +static int xenfb_resume(struct xenbus_device *dev)
   8.499 +{
   8.500 +	struct xenfb_info *info = dev->dev.driver_data;
   8.501 +
   8.502 +	xenfb_disconnect_backend(info);
   8.503 +	xenfb_init_shared_page(info);
   8.504 +	return xenfb_connect_backend(dev, info);
   8.505 +}
   8.506 +
   8.507 +static int xenfb_remove(struct xenbus_device *dev)
   8.508 +{
   8.509 +	struct xenfb_info *info = dev->dev.driver_data;
   8.510 +
   8.511 +	del_timer(&info->refresh);
   8.512 +	if (info->kthread)
   8.513 +		kthread_stop(info->kthread);
   8.514 +	xenfb_disconnect_backend(info);
   8.515 +	if (info->fb_info) {
   8.516 +		unregister_framebuffer(info->fb_info);
   8.517 +		fb_dealloc_cmap(&info->fb_info->cmap);
   8.518 +		framebuffer_release(info->fb_info);
   8.519 +	}
   8.520 +	free_page((unsigned long)info->page);
   8.521 +	vfree(info->mfns);
   8.522 +	kfree(info->pages);
   8.523 +	vfree(info->fb);
   8.524 +	kfree(info);
   8.525 +
   8.526 +	return 0;
   8.527 +}
   8.528 +
   8.529 +static void xenfb_init_shared_page(struct xenfb_info *info)
   8.530 +{
   8.531 +	int i;
   8.532 +
   8.533 +	for (i = 0; i < info->nr_pages; i++)
   8.534 +		info->pages[i] = vmalloc_to_page(info->fb + i * PAGE_SIZE);
   8.535 +
   8.536 +	for (i = 0; i < info->nr_pages; i++)
   8.537 +		info->mfns[i] = vmalloc_to_mfn(info->fb + i * PAGE_SIZE);
   8.538 +
   8.539 +	info->page->pd[0] = vmalloc_to_mfn(info->mfns);
   8.540 +	info->page->pd[1] = 0;
   8.541 +	info->page->width = XENFB_WIDTH;
   8.542 +	info->page->height = XENFB_HEIGHT;
   8.543 +	info->page->depth = XENFB_DEPTH;
   8.544 +	info->page->line_length = (info->page->depth / 8) * info->page->width;
   8.545 +	info->page->mem_length = xenfb_mem_len;
   8.546 +	info->page->in_cons = info->page->in_prod = 0;
   8.547 +	info->page->out_cons = info->page->out_prod = 0;
   8.548 +}
   8.549 +
   8.550 +static int xenfb_connect_backend(struct xenbus_device *dev,
   8.551 +				 struct xenfb_info *info)
   8.552 +{
   8.553 +	int ret;
   8.554 +	struct xenbus_transaction xbt;
   8.555 +
   8.556 +	ret = xenbus_alloc_evtchn(dev, &info->evtchn);
   8.557 +	if (ret)
   8.558 +		return ret;
   8.559 +	ret = bind_evtchn_to_irqhandler(info->evtchn, xenfb_event_handler,
   8.560 +					0, "xenfb", info);
   8.561 +	if (ret < 0) {
   8.562 +		xenbus_free_evtchn(dev, info->evtchn);
   8.563 +		xenbus_dev_fatal(dev, ret, "bind_evtchn_to_irqhandler");
   8.564 +		return ret;
   8.565 +	}
   8.566 +	info->irq = ret;
   8.567 +
   8.568 + again:
   8.569 +	ret = xenbus_transaction_start(&xbt);
   8.570 +	if (ret) {
   8.571 +		xenbus_dev_fatal(dev, ret, "starting transaction");
   8.572 +		return ret;
   8.573 +	}
   8.574 +	ret = xenbus_printf(xbt, dev->nodename, "page-ref", "%lu",
   8.575 +			    virt_to_mfn(info->page));
   8.576 +	if (ret)
   8.577 +		goto error_xenbus;
   8.578 +	ret = xenbus_printf(xbt, dev->nodename, "event-channel", "%u",
   8.579 +			    info->evtchn);
   8.580 +	if (ret)
   8.581 +		goto error_xenbus;
   8.582 +	ret = xenbus_printf(xbt, dev->nodename, "feature-update", "1");
   8.583 +	if (ret)
   8.584 +		goto error_xenbus;
   8.585 +	ret = xenbus_transaction_end(xbt, 0);
   8.586 +	if (ret) {
   8.587 +		if (ret == -EAGAIN)
   8.588 +			goto again;
   8.589 +		xenbus_dev_fatal(dev, ret, "completing transaction");
   8.590 +		return ret;
   8.591 +	}
   8.592 +
   8.593 +	xenbus_switch_state(dev, XenbusStateInitialised);
   8.594 +	return 0;
   8.595 +
   8.596 + error_xenbus:
   8.597 +	xenbus_transaction_end(xbt, 1);
   8.598 +	xenbus_dev_fatal(dev, ret, "writing xenstore");
   8.599 +	return ret;
   8.600 +}
   8.601 +
   8.602 +static void xenfb_disconnect_backend(struct xenfb_info *info)
   8.603 +{
   8.604 +	if (info->irq >= 0)
   8.605 +		unbind_from_irqhandler(info->irq, info);
   8.606 +	info->irq = -1;
   8.607 +}
   8.608 +
   8.609 +static void xenfb_backend_changed(struct xenbus_device *dev,
   8.610 +				  enum xenbus_state backend_state)
   8.611 +{
   8.612 +	struct xenfb_info *info = dev->dev.driver_data;
   8.613 +	int val;
   8.614 +
   8.615 +	switch (backend_state) {
   8.616 +	case XenbusStateInitialising:
   8.617 +	case XenbusStateInitialised:
   8.618 +	case XenbusStateUnknown:
   8.619 +	case XenbusStateClosed:
   8.620 +		break;
   8.621 +
   8.622 +	case XenbusStateInitWait:
   8.623 +	InitWait:
   8.624 +		xenbus_switch_state(dev, XenbusStateConnected);
   8.625 +		break;
   8.626 +
   8.627 +	case XenbusStateConnected:
   8.628 +		/*
   8.629 +		 * Work around xenbus race condition: If backend goes
   8.630 +		 * through InitWait to Connected fast enough, we can
   8.631 +		 * get Connected twice here.
   8.632 +		 */
   8.633 +		if (dev->state != XenbusStateConnected)
   8.634 +			goto InitWait; /* no InitWait seen yet, fudge it */
   8.635 +
   8.636 +		if (xenbus_scanf(XBT_NIL, info->xbdev->otherend,
   8.637 +				 "request-update", "%d", &val) < 0)
   8.638 +			val = 0;
   8.639 +		if (val)
   8.640 +			info->update_wanted = 1;
   8.641 +		break;
   8.642 +
   8.643 +	case XenbusStateClosing:
   8.644 +		// FIXME is this safe in any dev->state?
   8.645 +		xenbus_frontend_closed(dev);
   8.646 +		break;
   8.647 +	}
   8.648 +}
   8.649 +
   8.650 +static struct xenbus_device_id xenfb_ids[] = {
   8.651 +	{ "vfb" },
   8.652 +	{ "" }
   8.653 +};
   8.654 +
   8.655 +static struct xenbus_driver xenfb = {
   8.656 +	.name = "vfb",
   8.657 +	.owner = THIS_MODULE,
   8.658 +	.ids = xenfb_ids,
   8.659 +	.probe = xenfb_probe,
   8.660 +	.remove = xenfb_remove,
   8.661 +	.resume = xenfb_resume,
   8.662 +	.otherend_changed = xenfb_backend_changed,
   8.663 +};
   8.664 +
   8.665 +static int __init xenfb_init(void)
   8.666 +{
   8.667 +	if (!is_running_on_xen())
   8.668 +		return -ENODEV;
   8.669 +
   8.670 +	/* Nothing to do if running in dom0. */
   8.671 +	if (is_initial_xendomain())
   8.672 +		return -ENODEV;
   8.673 +
   8.674 +	return xenbus_register_frontend(&xenfb);
   8.675 +}
   8.676 +
   8.677 +static void __exit xenfb_cleanup(void)
   8.678 +{
   8.679 +	return xenbus_unregister_driver(&xenfb);
   8.680 +}
   8.681 +
   8.682 +module_init(xenfb_init);
   8.683 +module_exit(xenfb_cleanup);
   8.684 +
   8.685 +MODULE_LICENSE("GPL");
     9.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     9.2 +++ b/linux-2.6-xen-sparse/drivers/xen/fbfront/xenkbd.c	Fri Dec 01 13:12:41 2006 +0000
     9.3 @@ -0,0 +1,300 @@
     9.4 +/*
     9.5 + * linux/drivers/input/keyboard/xenkbd.c -- Xen para-virtual input device
     9.6 + *
     9.7 + * Copyright (C) 2005 Anthony Liguori <aliguori@us.ibm.com>
     9.8 + * Copyright (C) 2006 Red Hat, Inc., Markus Armbruster <armbru@redhat.com>
     9.9 + *
    9.10 + *  Based on linux/drivers/input/mouse/sermouse.c
    9.11 + *
    9.12 + *  This file is subject to the terms and conditions of the GNU General Public
    9.13 + *  License. See the file COPYING in the main directory of this archive for
    9.14 + *  more details.
    9.15 + */
    9.16 +
    9.17 +/*
    9.18 + * TODO:
    9.19 + *
    9.20 + * Switch to grant tables together with xenfb.c.
    9.21 + */
    9.22 +
    9.23 +#include <linux/kernel.h>
    9.24 +#include <linux/errno.h>
    9.25 +#include <linux/module.h>
    9.26 +#include <linux/input.h>
    9.27 +#include <asm/hypervisor.h>
    9.28 +#include <xen/evtchn.h>
    9.29 +#include <xen/interface/io/fbif.h>
    9.30 +#include <xen/interface/io/kbdif.h>
    9.31 +#include <xen/xenbus.h>
    9.32 +
    9.33 +struct xenkbd_info
    9.34 +{
    9.35 +	struct input_dev *dev;
    9.36 +	struct xenkbd_page *page;
    9.37 +	unsigned evtchn;
    9.38 +	int irq;
    9.39 +	struct xenbus_device *xbdev;
    9.40 +};
    9.41 +
    9.42 +static int xenkbd_remove(struct xenbus_device *);
    9.43 +static int xenkbd_connect_backend(struct xenbus_device *, struct xenkbd_info *);
    9.44 +static void xenkbd_disconnect_backend(struct xenkbd_info *);
    9.45 +
    9.46 +/*
    9.47 + * Note: if you need to send out events, see xenfb_do_update() for how
    9.48 + * to do that.
    9.49 + */
    9.50 +
    9.51 +static irqreturn_t input_handler(int rq, void *dev_id, struct pt_regs *regs)
    9.52 +{
    9.53 +	struct xenkbd_info *info = dev_id;
    9.54 +	struct xenkbd_page *page = info->page;
    9.55 +	__u32 cons, prod;
    9.56 +
    9.57 +	prod = page->in_prod;
    9.58 +	if (prod == page->out_cons)
    9.59 +		return IRQ_HANDLED;
    9.60 +	rmb();			/* ensure we see ring contents up to prod */
    9.61 +	for (cons = page->in_cons; cons != prod; cons++) {
    9.62 +		union xenkbd_in_event *event;
    9.63 +		event = &XENKBD_IN_RING_REF(page, cons);
    9.64 +
    9.65 +		switch (event->type) {
    9.66 +		case XENKBD_TYPE_MOTION:
    9.67 +			input_report_rel(info->dev, REL_X, event->motion.rel_x);
    9.68 +			input_report_rel(info->dev, REL_Y, event->motion.rel_y);
    9.69 +			break;
    9.70 +		case XENKBD_TYPE_KEY:
    9.71 +			input_report_key(info->dev, event->key.keycode, event->key.pressed);
    9.72 +			break;
    9.73 +		case XENKBD_TYPE_POS:
    9.74 +			input_report_abs(info->dev, ABS_X, event->pos.abs_x);
    9.75 +			input_report_abs(info->dev, ABS_Y, event->pos.abs_y);
    9.76 +			break;
    9.77 +		}
    9.78 +	}
    9.79 +	input_sync(info->dev);
    9.80 +	mb();			/* ensure we got ring contents */
    9.81 +	page->in_cons = cons;
    9.82 +	notify_remote_via_evtchn(info->evtchn);
    9.83 +
    9.84 +	return IRQ_HANDLED;
    9.85 +}
    9.86 +
    9.87 +int __devinit xenkbd_probe(struct xenbus_device *dev,
    9.88 +			   const struct xenbus_device_id *id)
    9.89 +{
    9.90 +	int ret, i;
    9.91 +	struct xenkbd_info *info;
    9.92 +	struct input_dev *input_dev;
    9.93 +
    9.94 +	info = kzalloc(sizeof(*info), GFP_KERNEL);
    9.95 +	if (!info) {
    9.96 +		xenbus_dev_fatal(dev, -ENOMEM, "allocating info structure");
    9.97 +		return -ENOMEM;
    9.98 +	}
    9.99 +	dev->dev.driver_data = info;
   9.100 +	info->xbdev = dev;
   9.101 +
   9.102 +	info->page = (void *)__get_free_page(GFP_KERNEL);
   9.103 +	if (!info->page)
   9.104 +		goto error_nomem;
   9.105 +	info->page->in_cons = info->page->in_prod = 0;
   9.106 +	info->page->out_cons = info->page->out_prod = 0;
   9.107 +
   9.108 +	input_dev = input_allocate_device();
   9.109 +	if (!input_dev)
   9.110 +		goto error_nomem;
   9.111 +
   9.112 +	input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_REL) | BIT(EV_ABS);
   9.113 +	input_dev->keybit[LONG(BTN_MOUSE)]
   9.114 +		= BIT(BTN_LEFT) | BIT(BTN_MIDDLE) | BIT(BTN_RIGHT);
   9.115 +	/* TODO additional buttons */
   9.116 +	input_dev->relbit[0] = BIT(REL_X) | BIT(REL_Y);
   9.117 +
   9.118 +	/* FIXME not sure this is quite right */
   9.119 +	for (i = 0; i < 256; i++)
   9.120 +		set_bit(i, input_dev->keybit);
   9.121 +
   9.122 +	input_dev->name = "Xen Virtual Keyboard/Mouse";
   9.123 +
   9.124 +	input_set_abs_params(input_dev, ABS_X, 0, XENFB_WIDTH, 0, 0);
   9.125 +	input_set_abs_params(input_dev, ABS_Y, 0, XENFB_HEIGHT, 0, 0);
   9.126 +
   9.127 +	ret = input_register_device(input_dev);
   9.128 +	if (ret) {
   9.129 +		input_free_device(input_dev);
   9.130 +		xenbus_dev_fatal(dev, ret, "input_register_device");
   9.131 +		goto error;
   9.132 +	}
   9.133 +	info->dev = input_dev;
   9.134 +
   9.135 +	ret = xenkbd_connect_backend(dev, info);
   9.136 +	if (ret < 0)
   9.137 +		goto error;
   9.138 +
   9.139 +	return 0;
   9.140 +
   9.141 + error_nomem:
   9.142 +	ret = -ENOMEM;
   9.143 +	xenbus_dev_fatal(dev, ret, "allocating device memory");
   9.144 + error:
   9.145 +	xenkbd_remove(dev);
   9.146 +	return ret;
   9.147 +}
   9.148 +
   9.149 +static int xenkbd_resume(struct xenbus_device *dev)
   9.150 +{
   9.151 +	struct xenkbd_info *info = dev->dev.driver_data;
   9.152 +
   9.153 +	xenkbd_disconnect_backend(info);
   9.154 +	return xenkbd_connect_backend(dev, info);
   9.155 +}
   9.156 +
   9.157 +static int xenkbd_remove(struct xenbus_device *dev)
   9.158 +{
   9.159 +	struct xenkbd_info *info = dev->dev.driver_data;
   9.160 +
   9.161 +	xenkbd_disconnect_backend(info);
   9.162 +	input_unregister_device(info->dev);
   9.163 +	free_page((unsigned long)info->page);
   9.164 +	kfree(info);
   9.165 +	return 0;
   9.166 +}
   9.167 +
   9.168 +static int xenkbd_connect_backend(struct xenbus_device *dev,
   9.169 +				  struct xenkbd_info *info)
   9.170 +{
   9.171 +	int ret;
   9.172 +	struct xenbus_transaction xbt;
   9.173 +
   9.174 +	ret = xenbus_alloc_evtchn(dev, &info->evtchn);
   9.175 +	if (ret)
   9.176 +		return ret;
   9.177 +	ret = bind_evtchn_to_irqhandler(info->evtchn, input_handler, 0,
   9.178 +					"xenkbd", info);
   9.179 +	if (ret < 0) {
   9.180 +		xenbus_free_evtchn(dev, info->evtchn);
   9.181 +		xenbus_dev_fatal(dev, ret, "bind_evtchn_to_irqhandler");
   9.182 +		return ret;
   9.183 +	}
   9.184 +	info->irq = ret;
   9.185 +
   9.186 + again:
   9.187 +	ret = xenbus_transaction_start(&xbt);
   9.188 +	if (ret) {
   9.189 +		xenbus_dev_fatal(dev, ret, "starting transaction");
   9.190 +		return ret;
   9.191 +	}
   9.192 +	ret = xenbus_printf(xbt, dev->nodename, "page-ref", "%lu",
   9.193 +			    virt_to_mfn(info->page));
   9.194 +	if (ret)
   9.195 +		goto error_xenbus;
   9.196 +	ret = xenbus_printf(xbt, dev->nodename, "event-channel", "%u",
   9.197 +			    info->evtchn);
   9.198 +	if (ret)
   9.199 +		goto error_xenbus;
   9.200 +	ret = xenbus_transaction_end(xbt, 0);
   9.201 +	if (ret) {
   9.202 +		if (ret == -EAGAIN)
   9.203 +			goto again;
   9.204 +		xenbus_dev_fatal(dev, ret, "completing transaction");
   9.205 +		return ret;
   9.206 +	}
   9.207 +
   9.208 +	xenbus_switch_state(dev, XenbusStateInitialised);
   9.209 +	return 0;
   9.210 +
   9.211 + error_xenbus:
   9.212 +	xenbus_transaction_end(xbt, 1);
   9.213 +	xenbus_dev_fatal(dev, ret, "writing xenstore");
   9.214 +	return ret;
   9.215 +}
   9.216 +
   9.217 +static void xenkbd_disconnect_backend(struct xenkbd_info *info)
   9.218 +{
   9.219 +	if (info->irq >= 0)
   9.220 +		unbind_from_irqhandler(info->irq, info);
   9.221 +	info->irq = -1;
   9.222 +}
   9.223 +
   9.224 +static void xenkbd_backend_changed(struct xenbus_device *dev,
   9.225 +				   enum xenbus_state backend_state)
   9.226 +{
   9.227 +	struct xenkbd_info *info = dev->dev.driver_data;
   9.228 +	int ret, val;
   9.229 +
   9.230 +	switch (backend_state) {
   9.231 +	case XenbusStateInitialising:
   9.232 +	case XenbusStateInitialised:
   9.233 +	case XenbusStateUnknown:
   9.234 +	case XenbusStateClosed:
   9.235 +		break;
   9.236 +
   9.237 +	case XenbusStateInitWait:
   9.238 +	InitWait:
   9.239 +		ret = xenbus_scanf(XBT_NIL, info->xbdev->otherend,
   9.240 +				   "feature-abs-pointer", "%d", &val);
   9.241 +		if (ret < 0)
   9.242 +			val = 0;
   9.243 +		if (val) {
   9.244 +			ret = xenbus_printf(XBT_NIL, info->xbdev->nodename,
   9.245 +					    "request-abs-pointer", "1");
   9.246 +			if (ret)
   9.247 +				; /* FIXME */
   9.248 +		}
   9.249 +		xenbus_switch_state(dev, XenbusStateConnected);
   9.250 +		break;
   9.251 +
   9.252 +	case XenbusStateConnected:
   9.253 +		/*
   9.254 +		 * Work around xenbus race condition: If backend goes
   9.255 +		 * through InitWait to Connected fast enough, we can
   9.256 +		 * get Connected twice here.
   9.257 +		 */
   9.258 +		if (dev->state != XenbusStateConnected)
   9.259 +			goto InitWait; /* no InitWait seen yet, fudge it */
   9.260 +		break;
   9.261 +
   9.262 +	case XenbusStateClosing:
   9.263 +		xenbus_frontend_closed(dev);
   9.264 +		break;
   9.265 +	}
   9.266 +}
   9.267 +
   9.268 +static struct xenbus_device_id xenkbd_ids[] = {
   9.269 +	{ "vkbd" },
   9.270 +	{ "" }
   9.271 +};
   9.272 +
   9.273 +static struct xenbus_driver xenkbd = {
   9.274 +	.name = "vkbd",
   9.275 +	.owner = THIS_MODULE,
   9.276 +	.ids = xenkbd_ids,
   9.277 +	.probe = xenkbd_probe,
   9.278 +	.remove = xenkbd_remove,
   9.279 +	.resume = xenkbd_resume,
   9.280 +	.otherend_changed = xenkbd_backend_changed,
   9.281 +};
   9.282 +
   9.283 +static int __init xenkbd_init(void)
   9.284 +{
   9.285 +	if (!is_running_on_xen())
   9.286 +		return -ENODEV;
   9.287 +
   9.288 +	/* Nothing to do if running in dom0. */
   9.289 +	if (is_initial_xendomain())
   9.290 +		return -ENODEV;
   9.291 +
   9.292 +	return xenbus_register_frontend(&xenkbd);
   9.293 +}
   9.294 +
   9.295 +static void __exit xenkbd_cleanup(void)
   9.296 +{
   9.297 +	return xenbus_unregister_driver(&xenkbd);
   9.298 +}
   9.299 +
   9.300 +module_init(xenkbd_init);
   9.301 +module_exit(xenkbd_cleanup);
   9.302 +
   9.303 +MODULE_LICENSE("GPL");
    10.1 --- a/linux-2.6-xen-sparse/include/xen/xencons.h	Fri Dec 01 13:08:36 2006 +0000
    10.2 +++ b/linux-2.6-xen-sparse/include/xen/xencons.h	Fri Dec 01 13:12:41 2006 +0000
    10.3 @@ -14,4 +14,6 @@ void xencons_tx(void);
    10.4  int xencons_ring_init(void);
    10.5  int xencons_ring_send(const char *data, unsigned len);
    10.6  
    10.7 +void xencons_early_setup(void);
    10.8 +
    10.9  #endif /* __ASM_XENCONS_H__ */
    11.1 --- a/linux-2.6-xen-sparse/mm/memory.c	Fri Dec 01 13:08:36 2006 +0000
    11.2 +++ b/linux-2.6-xen-sparse/mm/memory.c	Fri Dec 01 13:12:41 2006 +0000
    11.3 @@ -882,6 +882,7 @@ unsigned long zap_page_range(struct vm_a
    11.4  		tlb_finish_mmu(tlb, address, end);
    11.5  	return end;
    11.6  }
    11.7 +EXPORT_SYMBOL(zap_page_range);
    11.8  
    11.9  /*
   11.10   * Do a quick page-table lookup for a single page.
    12.1 --- a/tools/Makefile	Fri Dec 01 13:08:36 2006 +0000
    12.2 +++ b/tools/Makefile	Fri Dec 01 13:12:41 2006 +0000
    12.3 @@ -19,6 +19,7 @@ SUBDIRS-y += xenstat
    12.4  SUBDIRS-y += libaio
    12.5  SUBDIRS-y += blktap
    12.6  SUBDIRS-y += libfsimage
    12.7 +SUBDIRS-y += xenfb
    12.8  SUBDIRS-$(LIBXENAPI_BINDINGS) += libxen
    12.9  
   12.10  # These don't cross-compile
    13.1 --- a/tools/python/xen/xend/XendDevices.py	Fri Dec 01 13:08:36 2006 +0000
    13.2 +++ b/tools/python/xen/xend/XendDevices.py	Fri Dec 01 13:12:41 2006 +0000
    13.3 @@ -19,7 +19,7 @@
    13.4  # A collection of DevControllers 
    13.5  #
    13.6  
    13.7 -from xen.xend.server import blkif, netif, tpmif, pciif, iopif, irqif, usbif
    13.8 +from xen.xend.server import blkif, netif, tpmif, pciif, iopif, irqif, usbif, vfbif
    13.9  from xen.xend.server.BlktapController import BlktapController
   13.10  
   13.11  class XendDevices:
   13.12 @@ -41,6 +41,8 @@ class XendDevices:
   13.13          'irq': irqif.IRQController,
   13.14          'usb': usbif.UsbifController,
   13.15          'tap': BlktapController,
   13.16 +        'vfb': vfbif.VfbifController,
   13.17 +        'vkbd': vfbif.VkbdifController,
   13.18      }
   13.19  
   13.20      #@classmethod
    14.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    14.2 +++ b/tools/python/xen/xend/server/vfbif.py	Fri Dec 01 13:12:41 2006 +0000
    14.3 @@ -0,0 +1,74 @@
    14.4 +from xen.xend.server.DevController import DevController
    14.5 +
    14.6 +from xen.xend.XendError import VmError
    14.7 +import xen.xend
    14.8 +import os
    14.9 +
   14.10 +def spawn_detached(path, args, env):
   14.11 +    p = os.fork()
   14.12 +    if p == 0:
   14.13 +        os.spawnve(os.P_NOWAIT, path, args, env)
   14.14 +        os._exit(0)
   14.15 +    else:
   14.16 +        os.waitpid(p, 0)
   14.17 +        
   14.18 +class VfbifController(DevController):
   14.19 +    """Virtual frame buffer controller. Handles all vfb devices for a domain.
   14.20 +    Note that we only support a single vfb per domain at the moment.
   14.21 +    """
   14.22 +
   14.23 +    def __init__(self, vm):
   14.24 +        DevController.__init__(self, vm)
   14.25 +        self.config = {}
   14.26 +        
   14.27 +    def getDeviceDetails(self, config):
   14.28 +        """@see DevController.getDeviceDetails"""
   14.29 +        devid = 0
   14.30 +        back = {}
   14.31 +        front = {}
   14.32 +        return (devid, back, front)
   14.33 +
   14.34 +    def getDeviceConfiguration(self, devid):
   14.35 +        r = DevController.getDeviceConfiguration(self, devid)
   14.36 +        for (k,v) in self.config.iteritems():
   14.37 +            r[k] = v
   14.38 +        return r
   14.39 +    
   14.40 +    def createDevice(self, config):
   14.41 +        DevController.createDevice(self, config)
   14.42 +        self.config = config
   14.43 +        std_args = [ "--domid", "%d" % self.vm.getDomid(),
   14.44 +                     "--title", self.vm.getName() ]
   14.45 +        t = config.get("type", None)
   14.46 +        if t == "vnc":
   14.47 +            # Try to start the vnc backend
   14.48 +            args = [xen.util.auxbin.pathTo("xen-vncfb")]
   14.49 +            if config.has_key("vncunused"):
   14.50 +                args += ["--unused"]
   14.51 +            elif config.has_key("vncdisplay"):
   14.52 +                args += ["--vncport", "%d" % (5900 + config["vncdisplay"])]
   14.53 +            vnclisten = config.get("vnclisten",
   14.54 +                                   xen.xend.XendRoot.instance().get_vnclisten_address())
   14.55 +            args += [ "--listen", vnclisten ]
   14.56 +            spawn_detached(args[0], args + std_args, os.environ)
   14.57 +        elif t == "sdl":
   14.58 +            args = [xen.util.auxbin.pathTo("xen-sdlfb")]
   14.59 +            env = dict(os.environ)
   14.60 +            if config.has_key("display"):
   14.61 +                env['DISPLAY'] = config["display"]
   14.62 +            if config.has_key("xauthority"):
   14.63 +                env['XAUTHORITY'] = config["xauthority"]
   14.64 +            spawn_detached(args[0], args + std_args, env)
   14.65 +        else:
   14.66 +            raise VmError('Unknown vfb type %s (%s)' % (t, repr(config)))
   14.67 +
   14.68 +class VkbdifController(DevController):
   14.69 +    """Virtual keyboard controller. Handles all vkbd devices for a domain.
   14.70 +    """
   14.71 +
   14.72 +    def getDeviceDetails(self, config):
   14.73 +        """@see DevController.getDeviceDetails"""
   14.74 +        devid = 0
   14.75 +        back = {}
   14.76 +        front = {}
   14.77 +        return (devid, back, front)
    15.1 --- a/tools/python/xen/xm/create.py	Fri Dec 01 13:08:36 2006 +0000
    15.2 +++ b/tools/python/xen/xm/create.py	Fri Dec 01 13:12:41 2006 +0000
    15.3 @@ -284,6 +284,18 @@ gopts.var('usbport', val='PATH',
    15.4            use="""Add a physical USB port to a domain, as specified by the path
    15.5            to that port.  This option may be repeated to add more than one port.""")
    15.6  
    15.7 +gopts.var('vfb', val="type={vnc,sdl},vncunused=1,vncdisplay=N,vnclisten=ADDR,display=DISPLAY,xauthority=XAUTHORITY",
    15.8 +          fn=append_value, default=[],
    15.9 +          use="""Make the domain a framebuffer backend.
   15.10 +          The backend type should be either sdl or vnc.
   15.11 +          For type=vnc, connect an external vncviewer.  The server will listen
   15.12 +          on ADDR (default 127.0.0.1) on port N+5900.  N defaults to the
   15.13 +          domain id.  If vncunused=1, the server will try to find an arbitrary
   15.14 +          unused port above 5900.
   15.15 +          For type=sdl, a viewer will be started automatically using the
   15.16 +          given DISPLAY and XAUTHORITY, which default to the current user's
   15.17 +          ones.""")
   15.18 +
   15.19  gopts.var('vif', val="type=TYPE,mac=MAC,bridge=BRIDGE,ip=IPADDR,script=SCRIPT,backend=DOM,vifname=NAME",
   15.20            fn=append_value, default=[],
   15.21            use="""Add a network interface with the given MAC address and bridge.
   15.22 @@ -512,8 +524,8 @@ def configure_image(vals):
   15.23          config_image.append(['args', vals.extra])
   15.24  
   15.25      if vals.builder == 'hvm':
   15.26 -        configure_hvm(config_image, vals)
   15.27 -        
   15.28 +        configure_hvm(config_image, vals) 
   15.29 +       
   15.30      return config_image
   15.31      
   15.32  def configure_disks(config_devs, vals):
   15.33 @@ -564,6 +576,23 @@ def configure_usb(config_devs, vals):
   15.34          config_usb = ['usbport', ['path', path]]
   15.35          config_devs.append(['device', config_usb])
   15.36  
   15.37 +def configure_vfbs(config_devs, vals):
   15.38 +    for f in vals.vfb:
   15.39 +        d = comma_sep_kv_to_dict(f)
   15.40 +        config = ['vfb']
   15.41 +        if not d.has_key("type"):
   15.42 +            d['type'] = 'sdl'
   15.43 +        for (k,v) in d.iteritems():
   15.44 +            if not k in [ 'vnclisten', 'vncunused', 'vncdisplay', 'display',
   15.45 +                          'xauthority', 'type' ]:
   15.46 +                err("configuration option %s unknown to vfbs" % k)
   15.47 +            config.append([k,v])
   15.48 +        if not d.has_key("display") and os.environ.has_key("DISPLAY"):
   15.49 +            config.append(["display", os.environ['DISPLAY']])
   15.50 +        if not d.has_key("xauthority"):
   15.51 +            config.append(["xauthority", get_xauthority()])
   15.52 +        config_devs.append(['device', ['vkbd']])
   15.53 +        config_devs.append(['device', config])
   15.54  
   15.55  def configure_security(config, vals):
   15.56      """Create the config for ACM security labels.
   15.57 @@ -742,6 +771,7 @@ def make_config(vals):
   15.58      configure_vifs(config_devs, vals)
   15.59      configure_usb(config_devs, vals)
   15.60      configure_vtpm(config_devs, vals)
   15.61 +    configure_vfbs(config_devs, vals)
   15.62      configure_security(config, vals)
   15.63      config += config_devs
   15.64  
    16.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    16.2 +++ b/tools/xenfb/Makefile	Fri Dec 01 13:12:41 2006 +0000
    16.3 @@ -0,0 +1,35 @@
    16.4 +XEN_ROOT=../..
    16.5 +include $(XEN_ROOT)/tools/Rules.mk
    16.6 +
    16.7 +CFLAGS += -I$(XEN_LIBXC) -I$(XEN_XENSTORE) -I$(XEN_ROOT)/linux-2.6-xen-sparse/include
    16.8 +LDFLAGS += -L$(XEN_LIBXC) -L$(XEN_XENSTORE)
    16.9 +
   16.10 +INSTALL         = install
   16.11 +INSTALL_PROG    = $(INSTALL) -m0755
   16.12 +INSTALL_DIR     = $(INSTALL) -d -m0755
   16.13 +
   16.14 +.PHONY: all
   16.15 +all: build
   16.16 +
   16.17 +.PHONY: build
   16.18 +build: mk-symlinks
   16.19 +	$(MAKE) vncfb sdlfb
   16.20 +
   16.21 +install: all
   16.22 +	$(INSTALL_DIR) -p $(DESTDIR)/usr/$(LIBDIR)/xen/bin
   16.23 +	$(INSTALL_PROG) vncfb $(DESTDIR)/usr/$(LIBDIR)/xen/bin/xen-vncfb
   16.24 +	$(INSTALL_PROG) sdlfb $(DESTDIR)/usr/$(LIBDIR)/xen/bin/xen-sdlfb
   16.25 +
   16.26 +sdlfb: sdlfb.o xenfb.o
   16.27 +
   16.28 +sdlfb.o: CFLAGS += $(shell sdl-config --cflags)
   16.29 +sdlfb: LDLIBS += $(shell sdl-config --libs) -lxenctrl -lxenstore
   16.30 +
   16.31 +clean:
   16.32 +	$(RM) *.o *~ vncfb sdlfb
   16.33 +
   16.34 +vncfb: vncfb.o xenfb.o
   16.35 +vncfb.o: CFLAGS += $(shell libvncserver-config --cflags)
   16.36 +vncfb: LDLIBS += $(shell libvncserver-config --libs) -lxenctrl -lxenstore
   16.37 +
   16.38 +sdlfb.o xenfb.o vncfb.o: xenfb.h
    17.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    17.2 +++ b/tools/xenfb/sdlfb.c	Fri Dec 01 13:12:41 2006 +0000
    17.3 @@ -0,0 +1,342 @@
    17.4 +#include <SDL.h>
    17.5 +#include <errno.h>
    17.6 +#include <sys/types.h>
    17.7 +#include <sys/select.h>
    17.8 +#include <stdlib.h>
    17.9 +#include <linux/input.h>
   17.10 +#include <getopt.h>
   17.11 +#include <string.h>
   17.12 +#include "xenfb.h"
   17.13 +
   17.14 +struct SDLFBData
   17.15 +{
   17.16 +	SDL_Surface *dst;
   17.17 +	SDL_Surface *src;
   17.18 +};
   17.19 +
   17.20 +/*
   17.21 + * Map from scancode to Linux input layer keycode.  Scancodes are
   17.22 + * hardware-specific.  This map assumes a standard AT or PS/2
   17.23 + * keyboard.
   17.24 + *
   17.25 + * Why use scancodes?  We can't use key symbols, because they don't
   17.26 + * identify keys --- they're what keys are mapped to.  The standard
   17.27 + * German keymap, for instance, maps both KEY_COMMA and KEY_102ND to
   17.28 + * SDLK_LESS.
   17.29 + */
   17.30 +static int keymap[256] = {
   17.31 +	[9] = KEY_ESC,
   17.32 +	[10] = KEY_1,
   17.33 +	[11] = KEY_2,
   17.34 +	[12] = KEY_3,
   17.35 +	[13] = KEY_4,
   17.36 +	[14] = KEY_5,
   17.37 +	[15] = KEY_6,
   17.38 +	[16] = KEY_7,
   17.39 +	[17] = KEY_8,
   17.40 +	[18] = KEY_9,
   17.41 +	[19] = KEY_0,
   17.42 +	[20] = KEY_MINUS,
   17.43 +	[21] = KEY_EQUAL,
   17.44 +	[22] = KEY_BACKSPACE,
   17.45 +	[23] = KEY_TAB,
   17.46 +	[24] = KEY_Q,
   17.47 +	[25] = KEY_W,
   17.48 +	[26] = KEY_E,
   17.49 +	[27] = KEY_R,
   17.50 +	[28] = KEY_T,
   17.51 +	[29] = KEY_Y,
   17.52 +	[30] = KEY_U,
   17.53 +	[31] = KEY_I,
   17.54 +	[32] = KEY_O,
   17.55 +	[33] = KEY_P,
   17.56 +	[34] = KEY_LEFTBRACE,
   17.57 +	[35] = KEY_RIGHTBRACE,
   17.58 +	[36] = KEY_ENTER,
   17.59 +	[37] = KEY_LEFTCTRL,
   17.60 +	[38] = KEY_A,
   17.61 +	[39] = KEY_S,
   17.62 +	[40] = KEY_D,
   17.63 +	[41] = KEY_F,
   17.64 +	[42] = KEY_G,
   17.65 +	[43] = KEY_H,
   17.66 +	[44] = KEY_J,
   17.67 +	[45] = KEY_K,
   17.68 +	[46] = KEY_L,
   17.69 +	[47] = KEY_SEMICOLON,
   17.70 +	[48] = KEY_APOSTROPHE,
   17.71 +	[49] = KEY_GRAVE,
   17.72 +	[50] = KEY_LEFTSHIFT,
   17.73 +	[51] = KEY_BACKSLASH,
   17.74 +	[52] = KEY_Z,
   17.75 +	[53] = KEY_X,
   17.76 +	[54] = KEY_C,
   17.77 +	[55] = KEY_V,
   17.78 +	[56] = KEY_B,
   17.79 +	[57] = KEY_N,
   17.80 +	[58] = KEY_M,
   17.81 +	[59] = KEY_COMMA,
   17.82 +	[60] = KEY_DOT,
   17.83 +	[61] = KEY_SLASH,
   17.84 +	[62] = KEY_RIGHTSHIFT,
   17.85 +	[63] = KEY_KPASTERISK,
   17.86 +	[64] = KEY_LEFTALT,
   17.87 +	[65] = KEY_SPACE,
   17.88 +	[66] = KEY_CAPSLOCK,
   17.89 +	[67] = KEY_F1,
   17.90 +	[68] = KEY_F2,
   17.91 +	[69] = KEY_F3,
   17.92 +	[70] = KEY_F4,
   17.93 +	[71] = KEY_F5,
   17.94 +	[72] = KEY_F6,
   17.95 +	[73] = KEY_F7,
   17.96 +	[74] = KEY_F8,
   17.97 +	[75] = KEY_F9,
   17.98 +	[76] = KEY_F10,
   17.99 +	[77] = KEY_NUMLOCK,
  17.100 +	[78] = KEY_SCROLLLOCK,
  17.101 +	[79] = KEY_KP7,
  17.102 +	[80] = KEY_KP8,
  17.103 +	[81] = KEY_KP9,
  17.104 +	[82] = KEY_KPMINUS,
  17.105 +	[83] = KEY_KP4,
  17.106 +	[84] = KEY_KP5,
  17.107 +	[85] = KEY_KP6,
  17.108 +	[86] = KEY_KPPLUS,
  17.109 +	[87] = KEY_KP1,
  17.110 +	[88] = KEY_KP2,
  17.111 +	[89] = KEY_KP3,
  17.112 +	[90] = KEY_KP0,
  17.113 +	[91] = KEY_KPDOT,
  17.114 +	[94] = KEY_102ND,	/* FIXME is this correct? */
  17.115 +	[95] = KEY_F11,
  17.116 +	[96] = KEY_F12,
  17.117 +	[108] = KEY_KPENTER,
  17.118 +	[109] = KEY_RIGHTCTRL,
  17.119 +	[112] = KEY_KPSLASH,
  17.120 +	[111] = KEY_SYSRQ,
  17.121 +	[113] = KEY_RIGHTALT,
  17.122 +	[97] = KEY_HOME,
  17.123 +	[98] = KEY_UP,
  17.124 +	[99] = KEY_PAGEUP,
  17.125 +	[100] = KEY_LEFT,
  17.126 +	[102] = KEY_RIGHT,
  17.127 +	[103] = KEY_END,
  17.128 +	[104] = KEY_DOWN,
  17.129 +	[105] = KEY_PAGEDOWN,
  17.130 +	[106] = KEY_INSERT,
  17.131 +	[107] = KEY_DELETE,
  17.132 +	[110] = KEY_PAUSE,
  17.133 +	[115] = KEY_LEFTMETA,
  17.134 +	[116] = KEY_RIGHTMETA,
  17.135 +	[117] = KEY_MENU,
  17.136 +};
  17.137 +
  17.138 +static int btnmap[] = {
  17.139 +	[SDL_BUTTON_LEFT] = BTN_LEFT,
  17.140 +	[SDL_BUTTON_MIDDLE] = BTN_MIDDLE,
  17.141 +	[SDL_BUTTON_RIGHT] = BTN_RIGHT,
  17.142 +	/* FIXME not 100% sure about these: */
  17.143 +	[SDL_BUTTON_WHEELUP] = BTN_FORWARD,
  17.144 +	[SDL_BUTTON_WHEELDOWN] BTN_BACK
  17.145 +};
  17.146 +
  17.147 +static void sdl_update(struct xenfb *xenfb, int x, int y, int width, int height)
  17.148 +{
  17.149 +	struct SDLFBData *data = xenfb->user_data;
  17.150 +	SDL_Rect r = { x, y, width, height };
  17.151 +	SDL_BlitSurface(data->src, &r, data->dst, &r);
  17.152 +	SDL_UpdateRect(data->dst, x, y, width, height);
  17.153 +}
  17.154 +
  17.155 +static int sdl_on_event(struct xenfb *xenfb, SDL_Event *event)
  17.156 +{
  17.157 +	int x, y, ret;
  17.158 +
  17.159 +	switch (event->type) {
  17.160 +	case SDL_KEYDOWN:
  17.161 +	case SDL_KEYUP:
  17.162 +		if (keymap[event->key.keysym.scancode] == 0)
  17.163 +			break;
  17.164 +		ret = xenfb_send_key(xenfb,
  17.165 +				     event->type == SDL_KEYDOWN,
  17.166 +				     keymap[event->key.keysym.scancode]);
  17.167 +		if (ret < 0)
  17.168 +			fprintf(stderr, "Key %d %s lost (%s)\n",
  17.169 +				keymap[event->key.keysym.scancode],
  17.170 +				event->type == SDL_KEYDOWN ? "down" : "up",
  17.171 +				strerror(errno));
  17.172 +		break;
  17.173 +	case SDL_MOUSEMOTION:
  17.174 +		if (xenfb->abs_pointer_wanted) {
  17.175 +			SDL_GetMouseState(&x, &y);
  17.176 +			ret = xenfb_send_position(xenfb, x, y);
  17.177 +		} else {
  17.178 +			SDL_GetRelativeMouseState(&x, &y);
  17.179 +			ret = xenfb_send_motion(xenfb, x, y);
  17.180 +		}
  17.181 +		if (ret < 0)
  17.182 +			fprintf(stderr, "Pointer to %d,%d lost (%s)\n",
  17.183 +				x, y, strerror(errno));
  17.184 +		break;
  17.185 +	case SDL_MOUSEBUTTONDOWN:
  17.186 +	case SDL_MOUSEBUTTONUP:
  17.187 +		if (event->button.button >= sizeof(btnmap) / sizeof(*btnmap))
  17.188 +			break;
  17.189 +		if (btnmap[event->button.button] == 0)
  17.190 +			break;
  17.191 +		ret = xenfb_send_key(xenfb,
  17.192 +				     event->type == SDL_MOUSEBUTTONDOWN,
  17.193 +				     btnmap[event->button.button]);
  17.194 +		if (ret < 0)
  17.195 +			fprintf(stderr, "Button %d %s lost (%s)\n",
  17.196 +				btnmap[event->button.button] - BTN_MOUSE,
  17.197 +				event->type == SDL_MOUSEBUTTONDOWN ? "down" : "up",
  17.198 +				strerror(errno));
  17.199 +		break;
  17.200 +	case SDL_QUIT:
  17.201 +		return 0;
  17.202 +	}
  17.203 +
  17.204 +	return 1;
  17.205 +}
  17.206 +
  17.207 +static struct option options[] = {
  17.208 +	{ "domid", 1, NULL, 'd' },
  17.209 +	{ "title", 1, NULL, 't' },
  17.210 +	{ NULL }
  17.211 +};
  17.212 +
  17.213 +int main(int argc, char **argv)
  17.214 +{
  17.215 +	struct xenfb *xenfb;
  17.216 +	int domid = -1;
  17.217 +        char * title = NULL;
  17.218 +	fd_set readfds;
  17.219 +	int nfds;
  17.220 +	struct SDLFBData data;
  17.221 +	SDL_Rect r;
  17.222 +	struct timeval tv;
  17.223 +	SDL_Event event;
  17.224 +	int do_quit = 0;
  17.225 +	int opt;
  17.226 +	char *endp;
  17.227 +	int retval;
  17.228 +
  17.229 +	while ((opt = getopt_long(argc, argv, "d:t:", options,
  17.230 +				  NULL)) != -1) {
  17.231 +		switch (opt) {
  17.232 +                case 'd':
  17.233 +			domid = strtol(optarg, &endp, 10);
  17.234 +			if (endp == optarg || *endp) {
  17.235 +				fprintf(stderr, "Invalid domain id specified\n");
  17.236 +				exit(1);
  17.237 +			}
  17.238 +			break;
  17.239 +                case 't':
  17.240 +			title = strdup(optarg);
  17.241 +			break;
  17.242 +		case '?':
  17.243 +			exit(1);
  17.244 +                }
  17.245 +        }
  17.246 +        if (optind != argc) {
  17.247 +		fprintf(stderr, "Invalid options!\n");
  17.248 +		exit(1);
  17.249 +        }
  17.250 +        if (domid <= 0) {
  17.251 +		fprintf(stderr, "Domain ID must be specified!\n");
  17.252 +		exit(1);
  17.253 +        }
  17.254 +
  17.255 +	xenfb = xenfb_new();
  17.256 +	if (xenfb == NULL) {
  17.257 +		fprintf(stderr, "Could not create framebuffer (%s)\n",
  17.258 +			strerror(errno));
  17.259 +		exit(1);
  17.260 +        }
  17.261 +
  17.262 +	if (xenfb_attach_dom(xenfb, domid) < 0) {
  17.263 +		fprintf(stderr, "Could not connect to domain (%s)\n",
  17.264 +			strerror(errno));
  17.265 +		exit(1);
  17.266 +        }
  17.267 +
  17.268 +	if (SDL_Init(SDL_INIT_VIDEO) < 0) {
  17.269 +		fprintf(stderr, "Could not initialize SDL\n");
  17.270 +		exit(1);
  17.271 +	}
  17.272 +
  17.273 +	data.dst = SDL_SetVideoMode(xenfb->width, xenfb->height, xenfb->depth,
  17.274 +				    SDL_SWSURFACE);
  17.275 +	if (!data.dst) {
  17.276 +		fprintf(stderr, "SDL_SetVideoMode failed\n");
  17.277 +		exit(1);
  17.278 +	}
  17.279 +
  17.280 +	data.src = SDL_CreateRGBSurfaceFrom(xenfb->pixels,
  17.281 +					    xenfb->width, xenfb->height,
  17.282 +					    xenfb->depth, xenfb->row_stride,
  17.283 +					    0xFF0000, 0xFF00, 0xFF, 0);
  17.284 +
  17.285 +	if (!data.src) {
  17.286 +		fprintf(stderr, "SDL_CreateRGBSurfaceFrom failed\n");
  17.287 +		exit(1);
  17.288 +	}
  17.289 +
  17.290 +        if (title == NULL)
  17.291 +		title = strdup("xen-sdlfb");
  17.292 +        SDL_WM_SetCaption(title, title);
  17.293 +
  17.294 +	r.x = r.y = 0;
  17.295 +	r.w = xenfb->width;
  17.296 +	r.h = xenfb->height;
  17.297 +	SDL_BlitSurface(data.src, &r, data.dst, &r);
  17.298 +	SDL_UpdateRect(data.dst, 0, 0, xenfb->width, xenfb->height);
  17.299 +
  17.300 +	xenfb->update = sdl_update;
  17.301 +	xenfb->user_data = &data;
  17.302 +
  17.303 +	SDL_ShowCursor(0);
  17.304 +
  17.305 +	/*
  17.306 +	 * We need to wait for fds becoming ready or SDL events to
  17.307 +	 * arrive.  We time out the select after 10ms to poll for SDL
  17.308 +	 * events.  Clunky, but works.  Could avoid the clunkiness
  17.309 +	 * with a separate thread.
  17.310 +	 */
  17.311 +	for (;;) {
  17.312 +		FD_ZERO(&readfds);
  17.313 +		nfds = xenfb_select_fds(xenfb, &readfds);
  17.314 +		tv = (struct timeval){0, 10000};
  17.315 +
  17.316 +		if (select(nfds, &readfds, NULL, NULL, &tv) < 0) {
  17.317 +			if (errno == EINTR)
  17.318 +				continue;
  17.319 +			fprintf(stderr,
  17.320 +				"Can't select() on event channel (%s)\n",
  17.321 +				strerror(errno));
  17.322 +			break;
  17.323 +		}
  17.324 +
  17.325 +		while (SDL_PollEvent(&event)) {
  17.326 +			if (!sdl_on_event(xenfb, &event))
  17.327 +				do_quit = 1;
  17.328 +		}
  17.329 +
  17.330 +                if (do_quit)
  17.331 +			break;
  17.332 +
  17.333 +		retval = xenfb_poll(xenfb, &readfds);
  17.334 +		if (retval == -2)
  17.335 +		    xenfb_teardown(xenfb);
  17.336 +		if (retval < 0)
  17.337 +		    break;
  17.338 +	}
  17.339 +
  17.340 +	xenfb_delete(xenfb);
  17.341 +
  17.342 +	SDL_Quit();
  17.343 +
  17.344 +	return 0;
  17.345 +}
    18.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    18.2 +++ b/tools/xenfb/vncfb.c	Fri Dec 01 13:12:41 2006 +0000
    18.3 @@ -0,0 +1,401 @@
    18.4 +#define _GNU_SOURCE
    18.5 +#include <errno.h>
    18.6 +#include <getopt.h>
    18.7 +#include <stdlib.h>
    18.8 +#include <signal.h>
    18.9 +#include <unistd.h>
   18.10 +#include <malloc.h>
   18.11 +#include <rfb/rfb.h>
   18.12 +#include <rfb/keysym.h>
   18.13 +#include <linux/input.h>
   18.14 +#include <xs.h>
   18.15 +#include "xenfb.h"
   18.16 +
   18.17 +static int xk2linux[0x10000] = {
   18.18 +	[XK_a] = KEY_A,
   18.19 +	[XK_b] = KEY_B,
   18.20 +	[XK_c] = KEY_C,
   18.21 +	[XK_d] = KEY_D,
   18.22 +	[XK_e] = KEY_E,
   18.23 +	[XK_f] = KEY_F,
   18.24 +	[XK_g] = KEY_G,
   18.25 +	[XK_h] = KEY_H,
   18.26 +	[XK_i] = KEY_I,
   18.27 +	[XK_j] = KEY_J,
   18.28 +	[XK_k] = KEY_K,
   18.29 +	[XK_l] = KEY_L,
   18.30 +	[XK_m] = KEY_M,
   18.31 +	[XK_n] = KEY_N,
   18.32 +	[XK_o] = KEY_O,
   18.33 +	[XK_p] = KEY_P,
   18.34 +	[XK_q] = KEY_Q,
   18.35 +	[XK_r] = KEY_R,
   18.36 +	[XK_s] = KEY_S,
   18.37 +	[XK_t] = KEY_T,
   18.38 +	[XK_u] = KEY_U,
   18.39 +	[XK_v] = KEY_V,
   18.40 +	[XK_w] = KEY_W,
   18.41 +	[XK_x] = KEY_X,
   18.42 +	[XK_y] = KEY_Y,
   18.43 +	[XK_z] = KEY_Z,
   18.44 +	[XK_A] = KEY_A,
   18.45 +	[XK_B] = KEY_B,
   18.46 +	[XK_C] = KEY_C,
   18.47 +	[XK_D] = KEY_D,
   18.48 +	[XK_E] = KEY_E,
   18.49 +	[XK_F] = KEY_F,
   18.50 +	[XK_G] = KEY_G,
   18.51 +	[XK_H] = KEY_H,
   18.52 +	[XK_I] = KEY_I,
   18.53 +	[XK_J] = KEY_J,
   18.54 +	[XK_K] = KEY_K,
   18.55 +	[XK_L] = KEY_L,
   18.56 +	[XK_M] = KEY_M,
   18.57 +	[XK_N] = KEY_N,
   18.58 +	[XK_O] = KEY_O,
   18.59 +	[XK_P] = KEY_P,
   18.60 +	[XK_Q] = KEY_Q,
   18.61 +	[XK_R] = KEY_R,
   18.62 +	[XK_S] = KEY_S,
   18.63 +	[XK_T] = KEY_T,
   18.64 +	[XK_U] = KEY_U,
   18.65 +	[XK_V] = KEY_V,
   18.66 +	[XK_W] = KEY_W,
   18.67 +	[XK_X] = KEY_X,
   18.68 +	[XK_Y] = KEY_Y,
   18.69 +	[XK_Z] = KEY_Z,
   18.70 +	[XK_0] = KEY_0,
   18.71 +	[XK_1] = KEY_1,
   18.72 +	[XK_2] = KEY_2,
   18.73 +	[XK_3] = KEY_3,
   18.74 +	[XK_4] = KEY_4,
   18.75 +	[XK_5] = KEY_5,
   18.76 +	[XK_6] = KEY_6,
   18.77 +	[XK_7] = KEY_7,
   18.78 +	[XK_8] = KEY_8,
   18.79 +	[XK_9] = KEY_9,
   18.80 +	[XK_Return] = KEY_ENTER,
   18.81 +	[XK_BackSpace] = KEY_BACKSPACE,
   18.82 +	[XK_Tab] = KEY_TAB,
   18.83 +	[XK_Pause] = KEY_PAUSE,
   18.84 +	[XK_Delete] = KEY_DELETE,
   18.85 +	[XK_slash] = KEY_SLASH,
   18.86 +	[XK_minus] = KEY_MINUS,
   18.87 +	[XK_equal] = KEY_EQUAL,
   18.88 +	[XK_Escape] = KEY_ESC,
   18.89 +	[XK_braceleft] = KEY_LEFTBRACE,
   18.90 +	[XK_braceright] = KEY_RIGHTBRACE,
   18.91 +	[XK_bracketleft] = KEY_LEFTMETA,
   18.92 +	[XK_bracketright] = KEY_RIGHTMETA,
   18.93 +	[XK_Control_L] = KEY_LEFTCTRL,
   18.94 +	[XK_Control_R] = KEY_RIGHTCTRL,
   18.95 +	[XK_Shift_L] = KEY_LEFTSHIFT,
   18.96 +	[XK_Shift_R] = KEY_RIGHTSHIFT,
   18.97 +	[XK_Alt_L] = KEY_LEFTALT,
   18.98 +	[XK_Alt_R] = KEY_RIGHTALT,
   18.99 +	[XK_semicolon] = KEY_SEMICOLON, 
  18.100 +	[XK_apostrophe] = KEY_APOSTROPHE,
  18.101 +	[XK_grave] = KEY_GRAVE,
  18.102 +	[XK_backslash] = KEY_BACKSLASH,
  18.103 +	[XK_comma] = KEY_COMMA,
  18.104 +	[XK_period] = KEY_DOT,
  18.105 +	[XK_space] = KEY_SPACE,
  18.106 +	[XK_Caps_Lock] = KEY_CAPSLOCK,
  18.107 +	[XK_Num_Lock] = KEY_NUMLOCK,
  18.108 +	[XK_Scroll_Lock] = KEY_SCROLLLOCK,
  18.109 +	[XK_Sys_Req] = KEY_SYSRQ,
  18.110 +	[XK_Linefeed] = KEY_LINEFEED,
  18.111 +	[XK_Home] = KEY_HOME,
  18.112 +	[XK_Pause] = KEY_PAUSE,
  18.113 +	[XK_F1] = KEY_F1,
  18.114 +	[XK_F2] = KEY_F2,
  18.115 +	[XK_F3] = KEY_F3,
  18.116 +	[XK_F4] = KEY_F4,
  18.117 +	[XK_F5] = KEY_F5,
  18.118 +	[XK_F6] = KEY_F6,
  18.119 +	[XK_F7] = KEY_F7,
  18.120 +	[XK_F8] = KEY_F8,
  18.121 +	[XK_F9] = KEY_F9,
  18.122 +	[XK_F10] = KEY_F10,
  18.123 +	[XK_F11] = KEY_F11,
  18.124 +	[XK_F12] = KEY_F12,
  18.125 +	[XK_Up] = KEY_UP,
  18.126 +	[XK_Page_Up] = KEY_PAGEUP,
  18.127 +	[XK_Left] = KEY_LEFT,
  18.128 +	[XK_Right] = KEY_RIGHT,
  18.129 +	[XK_End] = KEY_END,
  18.130 +	[XK_Down] = KEY_DOWN,
  18.131 +	[XK_Page_Down] = KEY_PAGEDOWN,
  18.132 +	[XK_Insert] = KEY_INSERT, 
  18.133 +	[XK_colon] = KEY_SEMICOLON,
  18.134 +	[XK_quotedbl] = KEY_APOSTROPHE,
  18.135 +	[XK_less] = KEY_COMMA,
  18.136 +	[XK_greater] = KEY_DOT,
  18.137 +	[XK_question] = KEY_SLASH,
  18.138 +	[XK_bar] = KEY_BACKSLASH,
  18.139 +	[XK_asciitilde] = KEY_GRAVE,
  18.140 +	[XK_exclam] = KEY_1,
  18.141 +	[XK_at] = KEY_2,
  18.142 +	[XK_numbersign] = KEY_3,
  18.143 +	[XK_dollar] = KEY_4,
  18.144 +	[XK_percent] = KEY_5,
  18.145 +	[XK_asciicircum] = KEY_6,
  18.146 +	[XK_ampersand] = KEY_7,
  18.147 +	[XK_asterisk] = KEY_8,
  18.148 +	[XK_parenleft] = KEY_9,
  18.149 +	[XK_parenright] = KEY_0,
  18.150 +	[XK_underscore] = KEY_MINUS,
  18.151 +	[XK_plus] = KEY_EQUAL,
  18.152 +};
  18.153 +
  18.154 +static void on_kbd_event(rfbBool down, rfbKeySym keycode, rfbClientPtr cl)
  18.155 +{
  18.156 +	/*
  18.157 +	 * We need to map to the key's Linux input layer keycode.
  18.158 +	 * Unfortunately, we don't get the key here, only the
  18.159 +	 * rfbKeySym, which is what the key is mapped to.  Mapping
  18.160 +	 * back to the key is impossible in general, even when you
  18.161 +	 * know the keymap.  For instance, the standard German keymap
  18.162 +	 * maps both KEY_COMMA and KEY_102ND to XK_less.  We simply
  18.163 +	 * assume standard US layout.  This sucks.
  18.164 +	 */
  18.165 +	rfbScreenInfoPtr server = cl->screen;
  18.166 +	struct xenfb *xenfb = server->screenData;
  18.167 +	if (keycode >= sizeof(xk2linux) / sizeof(*xk2linux))
  18.168 +		return;
  18.169 +	if (xk2linux[keycode] == 0)
  18.170 +		return;
  18.171 +	if (xenfb_send_key(xenfb, down, xk2linux[keycode]) < 0)
  18.172 +		fprintf(stderr, "Key %d %s lost (%s)\n",
  18.173 +			xk2linux[keycode], down ? "down" : "up",
  18.174 +			strerror(errno));
  18.175 +}
  18.176 +
  18.177 +static void on_ptr_event(int buttonMask, int x, int y, rfbClientPtr cl)
  18.178 +{
  18.179 +	/* initial pointer state: at (0,0), buttons up */
  18.180 +	static int last_x, last_y, last_button;
  18.181 +	rfbScreenInfoPtr server = cl->screen;
  18.182 +	struct xenfb *xenfb = server->screenData;
  18.183 +	int i, last_down, down, ret;
  18.184 +
  18.185 +	for (i = 0; i < 8; i++) {
  18.186 +		last_down = last_button & (1 << i);
  18.187 +		down = buttonMask & (1 << i);
  18.188 +		if (down == last_down)
  18.189 +			continue;
  18.190 +		/* FIXME this assumes buttons are numbered the same; verify they are */
  18.191 +		if (xenfb_send_key(xenfb, down != 0, BTN_MOUSE + i) < 0)
  18.192 +			fprintf(stderr, "Button %d %s lost (%s)\n",
  18.193 +				i, down ? "down" : "up", strerror(errno));
  18.194 +	}
  18.195 +
  18.196 +	if (x != last_x || y != last_y) {
  18.197 +		if (xenfb->abs_pointer_wanted) 
  18.198 +			ret = xenfb_send_position(xenfb, x, y);
  18.199 +		else
  18.200 +			ret = xenfb_send_motion(xenfb, x - last_x, y - last_y);
  18.201 +		if (ret < 0)
  18.202 +			fprintf(stderr, "Pointer to %d,%d lost (%s)\n",
  18.203 +				x, y, strerror(errno));
  18.204 +	}
  18.205 +
  18.206 +	last_button = buttonMask;
  18.207 +	last_x = x;
  18.208 +	last_y = y;
  18.209 +}
  18.210 +
  18.211 +static void xenstore_write_vncport(int port, int domid)
  18.212 +{
  18.213 +	char *buf = NULL, *path;
  18.214 +	char portstr[10];
  18.215 +	struct xs_handle *xsh = NULL;
  18.216 +
  18.217 +	xsh = xs_daemon_open();
  18.218 +	if (xsh == NULL)
  18.219 +		return;
  18.220 +
  18.221 +	path = xs_get_domain_path(xsh, domid);
  18.222 +	if (path == NULL) {
  18.223 +		fprintf(stderr, "Can't get domain path (%s)\n",
  18.224 +			strerror(errno));
  18.225 +		goto out;
  18.226 +	}
  18.227 +
  18.228 +	if (asprintf(&buf, "%s/console/vnc-port", path) == -1) {
  18.229 +		fprintf(stderr, "Can't make vncport path\n");
  18.230 +		goto out;
  18.231 +	}
  18.232 +
  18.233 +	if (snprintf(portstr, sizeof(portstr), "%d", port) == -1) {
  18.234 +		fprintf(stderr, "Can't make vncport value\n");
  18.235 +		goto out;
  18.236 +	}
  18.237 +
  18.238 +	if (!xs_write(xsh, XBT_NULL, buf, portstr, strlen(portstr)))
  18.239 +		fprintf(stderr, "Can't set vncport (%s)\n",
  18.240 +			strerror(errno));
  18.241 +
  18.242 + out:
  18.243 +	free(buf);
  18.244 +}
  18.245 +
  18.246 +
  18.247 +static void vnc_update(struct xenfb *xenfb, int x, int y, int w, int h)
  18.248 +{
  18.249 +	rfbScreenInfoPtr server = xenfb->user_data;
  18.250 +	rfbMarkRectAsModified(server, x, y, x + w, y + h);
  18.251 +}
  18.252 +
  18.253 +static struct option options[] = {
  18.254 +	{ "domid", 1, NULL, 'd' },
  18.255 +	{ "vncport", 1, NULL, 'p' },
  18.256 +	{ "title", 1, NULL, 't' },
  18.257 +	{ "unused", 0, NULL, 'u' },
  18.258 +	{ "listen", 1, NULL, 'l' },
  18.259 +	{ NULL }
  18.260 +};
  18.261 +
  18.262 +int main(int argc, char **argv)
  18.263 +{
  18.264 +	rfbScreenInfoPtr server;
  18.265 +	char *fake_argv[7] = { "vncfb", "-rfbport", "5901", 
  18.266 +                               "-desktop", "xen-vncfb", 
  18.267 +                               "-listen", "127.0.0.1" };
  18.268 +	int fake_argc = sizeof(fake_argv) / sizeof(fake_argv[0]);
  18.269 +	int domid = -1, port = -1;
  18.270 +	char *title = NULL;
  18.271 +	char *listen = NULL;
  18.272 +	bool unused = false;
  18.273 +	int opt;
  18.274 +	struct xenfb *xenfb;
  18.275 +	fd_set readfds;
  18.276 +	int nfds;
  18.277 +	char portstr[10];
  18.278 +	char *endp;
  18.279 +	int r;
  18.280 +
  18.281 +	while ((opt = getopt_long(argc, argv, "d:p:t:u", options,
  18.282 +				  NULL)) != -1) {
  18.283 +		switch (opt) {
  18.284 +                case 'd':
  18.285 +			errno = 0;
  18.286 +			domid = strtol(optarg, &endp, 10);
  18.287 +			if (endp == optarg || *endp || errno) {
  18.288 +				fprintf(stderr, "Invalid domain id specified\n");
  18.289 +				exit(1);
  18.290 +			}
  18.291 +			break;
  18.292 +                case 'p':
  18.293 +			errno = 0;
  18.294 +			port = strtol(optarg, &endp, 10);
  18.295 +			if (endp == optarg || *endp || errno) {
  18.296 +				fprintf(stderr, "Invalid port specified\n");
  18.297 +				exit(1);
  18.298 +			}
  18.299 +			break;
  18.300 +                case 't':
  18.301 +			title = strdup(optarg);
  18.302 +			break;
  18.303 +                case 'u':
  18.304 +			unused = true;
  18.305 +			break;
  18.306 +                case 'l':
  18.307 +			listen = strdup(optarg);
  18.308 +			break;
  18.309 +		case '?':
  18.310 +			exit(1);
  18.311 +                }
  18.312 +        }
  18.313 +        if (optind != argc) {
  18.314 +		fprintf(stderr, "Invalid options!\n");
  18.315 +		exit(1);
  18.316 +        }
  18.317 +        if (domid <= 0) {
  18.318 +		fprintf(stderr, "Domain ID must be specified!\n");
  18.319 +		exit(1);
  18.320 +        }
  18.321 +            
  18.322 +        if (port <= 0)
  18.323 +		port = 5900 + domid;
  18.324 +	if (snprintf(portstr, sizeof(portstr), "%d", port) == -1) {
  18.325 +		fprintf(stderr, "Invalid port specified\n");
  18.326 +		exit(1);
  18.327 +        }
  18.328 +            
  18.329 +	fake_argv[2] = portstr;
  18.330 +
  18.331 +        if (title != NULL)
  18.332 +		fake_argv[4] = title;
  18.333 +
  18.334 +        if (listen != NULL)
  18.335 +		fake_argv[6] = listen;
  18.336 +
  18.337 +	signal(SIGPIPE, SIG_IGN);
  18.338 +
  18.339 +	xenfb = xenfb_new();
  18.340 +	if (xenfb == NULL) {
  18.341 +		fprintf(stderr, "Could not create framebuffer (%s)\n",
  18.342 +			strerror(errno));
  18.343 +		exit(1);
  18.344 +	}
  18.345 +
  18.346 +	if (xenfb_attach_dom(xenfb, domid) < 0) {
  18.347 +		fprintf(stderr, "Could not connect to domain (%s)\n",
  18.348 +			strerror(errno));
  18.349 +		exit(1);
  18.350 +	}
  18.351 +
  18.352 +	server = rfbGetScreen(&fake_argc, fake_argv, 
  18.353 +			      xenfb->width, xenfb->height,
  18.354 +			      8, 3, xenfb->depth / 8);
  18.355 +	if (server == NULL) {
  18.356 +		fprintf(stderr, "Could not create VNC server\n");
  18.357 +		exit(1);
  18.358 +	}
  18.359 +
  18.360 +	xenfb->user_data = server;
  18.361 +	xenfb->update = vnc_update;
  18.362 +
  18.363 +        if (unused)
  18.364 +		server->autoPort = true;
  18.365 +
  18.366 +	server->serverFormat.redShift = 16;
  18.367 +	server->serverFormat.greenShift = 8;
  18.368 +	server->serverFormat.blueShift = 0;
  18.369 +	server->kbdAddEvent = on_kbd_event;
  18.370 +	server->ptrAddEvent = on_ptr_event;
  18.371 +	server->frameBuffer = xenfb->pixels;
  18.372 +	server->screenData = xenfb;
  18.373 +	server->cursor = NULL;
  18.374 +	rfbInitServer(server);
  18.375 +
  18.376 +	rfbRunEventLoop(server, -1, true);
  18.377 +
  18.378 +        xenstore_write_vncport(server->port, domid);
  18.379 +
  18.380 +	for (;;) {
  18.381 +		FD_ZERO(&readfds);
  18.382 +		nfds = xenfb_select_fds(xenfb, &readfds);
  18.383 +
  18.384 +		if (select(nfds, &readfds, NULL, NULL, NULL) < 0) {
  18.385 +			if (errno == EINTR)
  18.386 +				continue;
  18.387 +			fprintf(stderr,
  18.388 +				"Can't select() on event channel (%s)\n",
  18.389 +				strerror(errno));
  18.390 +			break;
  18.391 +		}
  18.392 +
  18.393 +		r = xenfb_poll(xenfb, &readfds);
  18.394 +		if (r == -2)
  18.395 +		    xenfb_teardown(xenfb);
  18.396 +		if (r < 0)
  18.397 +		    break;
  18.398 +	}
  18.399 +
  18.400 +	rfbScreenCleanup(server);
  18.401 +	xenfb_delete(xenfb);
  18.402 +
  18.403 +	return 0;
  18.404 +}
    19.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    19.2 +++ b/tools/xenfb/xenfb.c	Fri Dec 01 13:12:41 2006 +0000
    19.3 @@ -0,0 +1,711 @@
    19.4 +#include <stdarg.h>
    19.5 +#include <stdlib.h>
    19.6 +#include <sys/types.h>
    19.7 +#include <fcntl.h>
    19.8 +#include <unistd.h>
    19.9 +#include <xenctrl.h>
   19.10 +#include <xen/io/xenbus.h>
   19.11 +#include <xen/io/fbif.h>
   19.12 +#include <xen/io/kbdif.h>
   19.13 +#include <sys/select.h>
   19.14 +#include <stdbool.h>
   19.15 +#include <xen/linux/evtchn.h>
   19.16 +#include <xen/event_channel.h>
   19.17 +#include <sys/mman.h>
   19.18 +#include <errno.h>
   19.19 +#include <stdio.h>
   19.20 +#include <string.h>
   19.21 +#include <time.h>
   19.22 +#include <xs.h>
   19.23 +
   19.24 +#include "xenfb.h"
   19.25 +
   19.26 +// FIXME defend against malicious frontend?
   19.27 +
   19.28 +struct xenfb_device {
   19.29 +	const char *devicetype;
   19.30 +	char nodename[64];	/* backend xenstore dir */
   19.31 +	char otherend[64];	/* frontend xenstore dir */
   19.32 +	int otherend_id;	/* frontend domid */
   19.33 +	enum xenbus_state state; /* backend state */
   19.34 +	void *page;		/* shared page */
   19.35 +	evtchn_port_t port;
   19.36 +	struct xenfb_private *xenfb;
   19.37 +};
   19.38 +
   19.39 +struct xenfb_private {
   19.40 +	struct xenfb pub;
   19.41 +	int evt_xch;		/* event channel driver handle */
   19.42 +	int xc;			/* hypervisor interface handle */
   19.43 +	struct xs_handle *xsh;	/* xs daemon handle */
   19.44 +	struct xenfb_device fb, kbd;
   19.45 +	size_t fb_len;		/* size of framebuffer */
   19.46 +};
   19.47 +
   19.48 +static void xenfb_detach_dom(struct xenfb_private *);
   19.49 +
   19.50 +static char *xenfb_path_in_dom(struct xs_handle *xsh,
   19.51 +			       char *buf, size_t size,
   19.52 +			       unsigned domid, const char *fmt, ...)
   19.53 +{
   19.54 +	va_list ap;
   19.55 +	char *domp = xs_get_domain_path(xsh, domid);
   19.56 +	int n;
   19.57 +
   19.58 +        if (domp == NULL)
   19.59 +		return NULL;
   19.60 +
   19.61 +	n = snprintf(buf, size, "%s/", domp);
   19.62 +	free(domp);
   19.63 +	if (n >= size)
   19.64 +		return NULL;
   19.65 +
   19.66 +	va_start(ap, fmt);
   19.67 +	n += vsnprintf(buf + n, size - n, fmt, ap);
   19.68 +	va_end(ap);
   19.69 +	if (n >= size)
   19.70 +		return NULL;
   19.71 +
   19.72 +	return buf;
   19.73 +}
   19.74 +
   19.75 +static int xenfb_xs_scanf1(struct xs_handle *xsh,
   19.76 +			   const char *dir, const char *node,
   19.77 +			   const char *fmt, void *dest)
   19.78 +{
   19.79 +	char buf[1024];
   19.80 +	char *p;
   19.81 +	int ret;
   19.82 +
   19.83 +	if (snprintf(buf, sizeof(buf), "%s/%s", dir, node) >= sizeof(buf)) {
   19.84 +		errno = ENOENT;
   19.85 +		return -1;
   19.86 +        }
   19.87 +	p = xs_read(xsh, XBT_NULL, buf, NULL);
   19.88 +	if (!p) {
   19.89 +		errno = ENOENT;
   19.90 +		return -1;
   19.91 +        }
   19.92 +	ret = sscanf(p, fmt, dest);
   19.93 +	free(p);
   19.94 +	if (ret != 1) {
   19.95 +		errno = EDOM;
   19.96 +		return -1;
   19.97 +        }
   19.98 +	return ret;
   19.99 +}
  19.100 +
  19.101 +static int xenfb_xs_printf(struct xs_handle *xsh,
  19.102 +			   const char *dir, const char *node, char *fmt, ...)
  19.103 +{
  19.104 +	va_list ap;
  19.105 +	char key[1024];
  19.106 +	char val[1024];
  19.107 +	int n;
  19.108 +
  19.109 +	if (snprintf(key, sizeof(key), "%s/%s", dir, node) >= sizeof(key)) {
  19.110 +		errno = ENOENT;
  19.111 +		return -1;
  19.112 +        }
  19.113 +
  19.114 +	va_start(ap, fmt);
  19.115 +	n = vsnprintf(val, sizeof(val), fmt, ap);
  19.116 +	va_end(ap);
  19.117 +	if (n >= sizeof(val)) {
  19.118 +		errno = ENOSPC; /* close enough */
  19.119 +		return -1;
  19.120 +	}
  19.121 +
  19.122 +	if (!xs_write(xsh, XBT_NULL, key, val, n))
  19.123 +		return -1;
  19.124 +	return 0;
  19.125 +}
  19.126 +
  19.127 +static void xenfb_device_init(struct xenfb_device *dev,
  19.128 +			      const char *type,
  19.129 +			      struct xenfb_private *xenfb)
  19.130 +{
  19.131 +	dev->devicetype = type;
  19.132 +	dev->otherend_id = -1;
  19.133 +	dev->port = -1;
  19.134 +	dev->xenfb = xenfb;
  19.135 +}
  19.136 +
  19.137 +int xenfb_device_set_domain(struct xenfb_device *dev, int domid)
  19.138 +{
  19.139 +	struct xenfb_private *xenfb = dev->xenfb;
  19.140 +
  19.141 +	dev->otherend_id = domid;
  19.142 +
  19.143 +	if (!xenfb_path_in_dom(xenfb->xsh,
  19.144 +			       dev->otherend, sizeof(dev->otherend),
  19.145 +			       domid, "device/%s/0", dev->devicetype)) {
  19.146 +		errno = ENOENT;
  19.147 +		return -1;
  19.148 +	}
  19.149 +	if (!xenfb_path_in_dom(xenfb->xsh,
  19.150 +			       dev->nodename, sizeof(dev->nodename),
  19.151 +			       0, "backend/%s/%d/0", dev->devicetype, domid)) {
  19.152 +		errno = ENOENT;
  19.153 +		return -1;
  19.154 +	}
  19.155 +
  19.156 +	return 0;
  19.157 +}
  19.158 +
  19.159 +struct xenfb *xenfb_new(void)
  19.160 +{
  19.161 +	struct xenfb_private *xenfb = malloc(sizeof(*xenfb));
  19.162 +	int serrno;
  19.163 +
  19.164 +	if (xenfb == NULL)
  19.165 +		return NULL;
  19.166 +
  19.167 +	memset(xenfb, 0, sizeof(*xenfb));
  19.168 +	xenfb->evt_xch = xenfb->xc = -1;
  19.169 +	xenfb_device_init(&xenfb->fb, "vfb", xenfb);
  19.170 +	xenfb_device_init(&xenfb->kbd, "vkbd", xenfb);
  19.171 +
  19.172 +	xenfb->evt_xch = xc_evtchn_open();
  19.173 +	if (xenfb->evt_xch == -1)
  19.174 +		goto fail;
  19.175 +
  19.176 +	xenfb->xc = xc_interface_open();
  19.177 +	if (xenfb->xc == -1)
  19.178 +		goto fail;
  19.179 +
  19.180 +	xenfb->xsh = xs_daemon_open();
  19.181 +	if (!xenfb->xsh)
  19.182 +		goto fail;
  19.183 +
  19.184 +	return &xenfb->pub;
  19.185 +
  19.186 + fail:
  19.187 +	serrno = errno;
  19.188 +	xenfb_delete(&xenfb->pub);
  19.189 +	errno = serrno;
  19.190 +	return NULL;
  19.191 +}
  19.192 +
  19.193 +/* Remove the backend area in xenbus since the framebuffer really is
  19.194 +   going away. */
  19.195 +void xenfb_teardown(struct xenfb *xenfb_pub)
  19.196 +{
  19.197 +       struct xenfb_private *xenfb = (struct xenfb_private *)xenfb_pub;
  19.198 +
  19.199 +       xs_rm(xenfb->xsh, XBT_NULL, xenfb->fb.nodename);
  19.200 +       xs_rm(xenfb->xsh, XBT_NULL, xenfb->kbd.nodename);
  19.201 +}
  19.202 +
  19.203 +
  19.204 +void xenfb_delete(struct xenfb *xenfb_pub)
  19.205 +{
  19.206 +	struct xenfb_private *xenfb = (struct xenfb_private *)xenfb_pub;
  19.207 +
  19.208 +	xenfb_detach_dom(xenfb);
  19.209 +	if (xenfb->xc >= 0)
  19.210 +		xc_interface_close(xenfb->xc);
  19.211 +	if (xenfb->evt_xch >= 0)
  19.212 +		xc_evtchn_close(xenfb->evt_xch);
  19.213 +	if (xenfb->xsh)
  19.214 +		xs_daemon_close(xenfb->xsh);
  19.215 +	free(xenfb);
  19.216 +}
  19.217 +
  19.218 +static enum xenbus_state xenfb_read_state(struct xs_handle *xsh,
  19.219 +					  const char *dir)
  19.220 +{
  19.221 +	int ret, state;
  19.222 +
  19.223 +	ret = xenfb_xs_scanf1(xsh, dir, "state", "%d", &state);
  19.224 +	if (ret < 0)
  19.225 +		return XenbusStateUnknown;
  19.226 +
  19.227 +	if ((unsigned)state > XenbusStateClosed)
  19.228 +		state = XenbusStateUnknown;
  19.229 +	return state;
  19.230 +}
  19.231 +
  19.232 +static int xenfb_switch_state(struct xenfb_device *dev,
  19.233 +			      enum xenbus_state state)
  19.234 +{
  19.235 +	struct xs_handle *xsh = dev->xenfb->xsh;
  19.236 +
  19.237 +	if (xenfb_xs_printf(xsh, dev->nodename, "state", "%d", state) < 0)
  19.238 +		return -1;
  19.239 +	dev->state = state;
  19.240 +	return 0;
  19.241 +}
  19.242 +
  19.243 +static int xenfb_wait_for_state(struct xs_handle *xsh, const char *dir,
  19.244 +				unsigned awaited)
  19.245 +{
  19.246 +	unsigned state, dummy;
  19.247 +	char **vec;
  19.248 +
  19.249 +	for (;;) {
  19.250 +		state = xenfb_read_state(xsh, dir);
  19.251 +		if (state < 0)
  19.252 +			return -1;
  19.253 +
  19.254 +		if ((1 << state) & awaited)
  19.255 +			return state;
  19.256 +
  19.257 +		vec = xs_read_watch(xsh, &dummy);
  19.258 +		if (!vec)
  19.259 +			return -1;
  19.260 +		free(vec);
  19.261 +	}
  19.262 +}
  19.263 +
  19.264 +static int xenfb_wait_for_backend_creation(struct xenfb_device *dev)
  19.265 +{
  19.266 +	struct xs_handle *xsh = dev->xenfb->xsh;
  19.267 +	int state;
  19.268 +
  19.269 +	if (!xs_watch(xsh, dev->nodename, ""))
  19.270 +		return -1;
  19.271 +	state = xenfb_wait_for_state(xsh, dev->nodename,
  19.272 +			(1 << XenbusStateInitialising)
  19.273 +			| (1 << XenbusStateClosed)
  19.274 +#if 1 /* TODO fudging state to permit restarting; to be removed */
  19.275 +			| (1 << XenbusStateInitWait)
  19.276 +			| (1 << XenbusStateConnected)
  19.277 +			| (1 << XenbusStateClosing)
  19.278 +#endif
  19.279 +			);
  19.280 +	xs_unwatch(xsh, dev->nodename, "");
  19.281 +
  19.282 +	switch (state) {
  19.283 +#if 1
  19.284 +	case XenbusStateInitWait:
  19.285 +	case XenbusStateConnected:
  19.286 +		printf("Fudging state to %d\n", XenbusStateInitialising); /* FIXME */
  19.287 +#endif
  19.288 +	case XenbusStateInitialising:
  19.289 +	case XenbusStateClosing:
  19.290 +	case XenbusStateClosed:
  19.291 +		break;
  19.292 +	default:
  19.293 +		return -1;
  19.294 +	}
  19.295 +
  19.296 +	return 0;
  19.297 +}
  19.298 +
  19.299 +static int xenfb_hotplug(struct xenfb_device *dev)
  19.300 +{
  19.301 +	if (xenfb_xs_printf(dev->xenfb->xsh, dev->nodename,
  19.302 +			    "hotplug-status", "connected"))
  19.303 +		return -1;
  19.304 +	return 0;
  19.305 +}
  19.306 +
  19.307 +static int xenfb_wait_for_frontend_initialised(struct xenfb_device *dev)
  19.308 +{
  19.309 +	switch (xenfb_wait_for_state(dev->xenfb->xsh, dev->otherend,
  19.310 +#if 1 /* TODO fudging state to permit restarting; to be removed */
  19.311 +			(1 << XenbusStateInitialised)
  19.312 +			| (1 << XenbusStateConnected)
  19.313 +#else
  19.314 +			1 << XenbusStateInitialised,
  19.315 +#endif
  19.316 +			)) {
  19.317 +#if 1
  19.318 +	case XenbusStateConnected:
  19.319 +		printf("Fudging state to %d\n", XenbusStateInitialised); /* FIXME */
  19.320 +#endif
  19.321 +	case XenbusStateInitialised:
  19.322 +		break;
  19.323 +	default:
  19.324 +		return -1;
  19.325 +	}
  19.326 +
  19.327 +	return 0;
  19.328 +}
  19.329 +
  19.330 +static int xenfb_map_fb(struct xenfb_private *xenfb, int domid)
  19.331 +{
  19.332 +	struct xenfb_page *page = xenfb->fb.page;
  19.333 +	int n_fbmfns;
  19.334 +	int n_fbdirs;
  19.335 +	unsigned long *fbmfns;
  19.336 +
  19.337 +	n_fbmfns = (xenfb->fb_len + (XC_PAGE_SIZE - 1)) / XC_PAGE_SIZE;
  19.338 +	n_fbdirs = n_fbmfns * sizeof(unsigned long);
  19.339 +	n_fbdirs = (n_fbdirs + (XC_PAGE_SIZE - 1)) / XC_PAGE_SIZE;
  19.340 +
  19.341 +	/*
  19.342 +	 * Bug alert: xc_map_foreign_batch() can fail partly and
  19.343 +	 * return a non-null value.  This is a design flaw.  When it
  19.344 +	 * happens, we happily continue here, and later crash on
  19.345 +	 * access.
  19.346 +	 */
  19.347 +	fbmfns = xc_map_foreign_batch(xenfb->xc, domid,
  19.348 +			PROT_READ, page->pd, n_fbdirs);
  19.349 +	if (fbmfns == NULL)
  19.350 +		return -1;
  19.351 +
  19.352 +	xenfb->pub.pixels = xc_map_foreign_batch(xenfb->xc, domid,
  19.353 +				PROT_READ | PROT_WRITE, fbmfns, n_fbmfns);
  19.354 +	if (xenfb->pub.pixels == NULL) {
  19.355 +		munmap(fbmfns, n_fbdirs * XC_PAGE_SIZE);
  19.356 +		return -1;
  19.357 +	}
  19.358 +
  19.359 +	return munmap(fbmfns, n_fbdirs * XC_PAGE_SIZE);
  19.360 +}
  19.361 +
  19.362 +static int xenfb_bind(struct xenfb_device *dev)
  19.363 +{
  19.364 +	struct xenfb_private *xenfb = dev->xenfb;
  19.365 +	unsigned long mfn;
  19.366 +	evtchn_port_t evtchn;
  19.367 +
  19.368 +	if (xenfb_xs_scanf1(xenfb->xsh, dev->otherend, "page-ref", "%lu",
  19.369 +			    &mfn) < 0)
  19.370 +		return -1;
  19.371 +	if (xenfb_xs_scanf1(xenfb->xsh, dev->otherend, "event-channel", "%u",
  19.372 +			    &evtchn) < 0)
  19.373 +		return -1;
  19.374 +
  19.375 +	dev->port = xc_evtchn_bind_interdomain(xenfb->evt_xch,
  19.376 +					       dev->otherend_id, evtchn);
  19.377 +	if (dev->port == -1)
  19.378 +		return -1;
  19.379 +
  19.380 +	dev->page = xc_map_foreign_range(xenfb->xc, dev->otherend_id,
  19.381 +			XC_PAGE_SIZE, PROT_READ | PROT_WRITE, mfn);
  19.382 +	if (dev->page == NULL)
  19.383 +		return -1;
  19.384 +
  19.385 +	return 0;
  19.386 +}
  19.387 +
  19.388 +static void xenfb_unbind(struct xenfb_device *dev)
  19.389 +{
  19.390 +	if (dev->page) {
  19.391 +		munmap(dev->page, XC_PAGE_SIZE);
  19.392 +		dev->page = NULL;
  19.393 +	}
  19.394 +        if (dev->port >= 0) {
  19.395 +		xc_evtchn_unbind(dev->xenfb->evt_xch, dev->port);
  19.396 +		dev->port = -1;
  19.397 +	}
  19.398 +}
  19.399 +
  19.400 +static int xenfb_wait_for_frontend_connected(struct xenfb_device *dev)
  19.401 +{
  19.402 +	switch (xenfb_wait_for_state(dev->xenfb->xsh, dev->otherend,
  19.403 +				     1 << XenbusStateConnected)) {
  19.404 +	case XenbusStateConnected:
  19.405 +		break;
  19.406 +	default:
  19.407 +		return -1;
  19.408 +	}
  19.409 +
  19.410 +	return 0;
  19.411 +}
  19.412 +
  19.413 +static void xenfb_dev_fatal(struct xenfb_device *dev, int err,
  19.414 +			    const char *fmt, ...)
  19.415 +{
  19.416 +	struct xs_handle *xsh = dev->xenfb->xsh;
  19.417 +	va_list ap;
  19.418 +	char errdir[80];
  19.419 +	char buf[1024];
  19.420 +	int n;
  19.421 +
  19.422 +	fprintf(stderr, "%s ", dev->nodename); /* somewhat crude */
  19.423 +	va_start(ap, fmt);
  19.424 +	vfprintf(stderr, fmt, ap);
  19.425 +	va_end(ap);
  19.426 +	if (err)
  19.427 +		fprintf(stderr, " (%s)", strerror(err));
  19.428 +	putc('\n', stderr);
  19.429 +
  19.430 +	if (!xenfb_path_in_dom(xsh, errdir, sizeof(errdir), 0,
  19.431 +			       "error/%s", dev->nodename))
  19.432 +		goto out;	/* FIXME complain */
  19.433 +
  19.434 +	va_start(ap, fmt);
  19.435 +	n = snprintf(buf, sizeof(buf), "%d ", err);
  19.436 +	snprintf(buf + n, sizeof(buf) - n, fmt, ap);
  19.437 +	va_end(ap);
  19.438 +
  19.439 +	if (xenfb_xs_printf(xsh, buf, "error", "%s", buf) < 0)
  19.440 +		goto out;	/* FIXME complain */
  19.441 +
  19.442 + out:
  19.443 +	xenfb_switch_state(dev, XenbusStateClosing);
  19.444 +}
  19.445 +
  19.446 +int xenfb_attach_dom(struct xenfb *xenfb_pub, int domid)
  19.447 +{
  19.448 +	struct xenfb_private *xenfb = (struct xenfb_private *)xenfb_pub;
  19.449 +	struct xs_handle *xsh = xenfb->xsh;
  19.450 +	int val, serrno;
  19.451 +	struct xenfb_page *fb_page;
  19.452 +
  19.453 +	xenfb_detach_dom(xenfb);
  19.454 +
  19.455 +	xenfb_device_set_domain(&xenfb->fb, domid);
  19.456 +	xenfb_device_set_domain(&xenfb->kbd, domid);
  19.457 +
  19.458 +	if (xenfb_wait_for_backend_creation(&xenfb->fb) < 0)
  19.459 +		goto error;
  19.460 +	if (xenfb_wait_for_backend_creation(&xenfb->kbd) < 0)
  19.461 +		goto error;
  19.462 +
  19.463 +	if (xenfb_xs_printf(xsh, xenfb->kbd.nodename, "feature-abs-pointer", "1"))
  19.464 +		goto error;
  19.465 +	if (xenfb_switch_state(&xenfb->fb, XenbusStateInitWait))
  19.466 +		goto error;
  19.467 +	if (xenfb_switch_state(&xenfb->kbd, XenbusStateInitWait))
  19.468 +		goto error;
  19.469 +
  19.470 +	if (xenfb_hotplug(&xenfb->fb) < 0)
  19.471 +		goto error;
  19.472 +	if (xenfb_hotplug(&xenfb->kbd) < 0)
  19.473 +		goto error;
  19.474 +
  19.475 +	if (!xs_watch(xsh, xenfb->fb.otherend, ""))
  19.476 +		goto error;
  19.477 +	if (!xs_watch(xsh, xenfb->kbd.otherend, ""))
  19.478 +		goto error;
  19.479 +
  19.480 +	if (xenfb_wait_for_frontend_initialised(&xenfb->fb) < 0)
  19.481 +		goto error;
  19.482 +	if (xenfb_wait_for_frontend_initialised(&xenfb->kbd) < 0)
  19.483 +		goto error;
  19.484 +
  19.485 +	if (xenfb_bind(&xenfb->fb) < 0)
  19.486 +		goto error;
  19.487 +	if (xenfb_bind(&xenfb->kbd) < 0)
  19.488 +		goto error;
  19.489 +
  19.490 +	if (xenfb_xs_scanf1(xsh, xenfb->fb.otherend, "feature-update",
  19.491 +			    "%d", &val) < 0)
  19.492 +		val = 0;
  19.493 +	if (!val) {
  19.494 +		errno = ENOTSUP;
  19.495 +		goto error;
  19.496 +	}
  19.497 +	xenfb_xs_printf(xsh, xenfb->fb.nodename, "request-update", "1");
  19.498 +
  19.499 +	/* TODO check for permitted ranges */
  19.500 +	fb_page = xenfb->fb.page;
  19.501 +	xenfb->pub.depth = fb_page->depth;
  19.502 +	xenfb->pub.width = fb_page->width;
  19.503 +	xenfb->pub.height = fb_page->height;
  19.504 +	/* TODO check for consistency with the above */
  19.505 +	xenfb->fb_len = fb_page->mem_length;
  19.506 +	xenfb->pub.row_stride = fb_page->line_length;
  19.507 +
  19.508 +	if (xenfb_map_fb(xenfb, domid) < 0)
  19.509 +		goto error;
  19.510 +
  19.511 +	if (xenfb_switch_state(&xenfb->fb, XenbusStateConnected))
  19.512 +		goto error;
  19.513 +	if (xenfb_switch_state(&xenfb->kbd, XenbusStateConnected))
  19.514 +		goto error;
  19.515 +
  19.516 +	if (xenfb_wait_for_frontend_connected(&xenfb->kbd) < 0)
  19.517 +		goto error;
  19.518 +	if (xenfb_xs_scanf1(xsh, xenfb->kbd.otherend, "request-abs-pointer",
  19.519 +			    "%d", &val) < 0)
  19.520 +		val = 0;
  19.521 +	xenfb->pub.abs_pointer_wanted = val;
  19.522 +
  19.523 +	return 0;
  19.524 +
  19.525 + error:
  19.526 +	serrno = errno;
  19.527 +	xenfb_detach_dom(xenfb);
  19.528 +	xenfb_dev_fatal(&xenfb->fb, serrno, "on fire");
  19.529 +	xenfb_dev_fatal(&xenfb->kbd, serrno, "on fire");
  19.530 +        errno = serrno;
  19.531 +        return -1;
  19.532 +}
  19.533 +
  19.534 +static void xenfb_detach_dom(struct xenfb_private *xenfb)
  19.535 +{
  19.536 +	xenfb_unbind(&xenfb->fb);
  19.537 +	xenfb_unbind(&xenfb->kbd);
  19.538 +	if (xenfb->pub.pixels) {
  19.539 +		munmap(xenfb->pub.pixels, xenfb->fb_len);
  19.540 +		xenfb->pub.pixels = NULL;
  19.541 +	}
  19.542 +}
  19.543 +
  19.544 +static void xenfb_on_fb_event(struct xenfb_private *xenfb)
  19.545 +{
  19.546 +	uint32_t prod, cons;
  19.547 +	struct xenfb_page *page = xenfb->fb.page;
  19.548 +
  19.549 +	prod = page->out_prod;
  19.550 +	if (prod == page->out_cons)
  19.551 +		return;
  19.552 +	rmb();			/* ensure we see ring contents up to prod */
  19.553 +	for (cons = page->out_cons; cons != prod; cons++) {
  19.554 +		union xenfb_out_event *event = &XENFB_OUT_RING_REF(page, cons);
  19.555 +
  19.556 +		switch (event->type) {
  19.557 +		case XENFB_TYPE_UPDATE:
  19.558 +                    if (xenfb->pub.update)
  19.559 +			xenfb->pub.update(&xenfb->pub,
  19.560 +					  event->update.x, event->update.y,
  19.561 +					  event->update.width, event->update.height);
  19.562 +                    break;
  19.563 +		}
  19.564 +	}
  19.565 +	mb();			/* ensure we're done with ring contents */
  19.566 +	page->out_cons = cons;
  19.567 +	xc_evtchn_notify(xenfb->evt_xch, xenfb->fb.port);
  19.568 +}
  19.569 +
  19.570 +static void xenfb_on_kbd_event(struct xenfb_private *xenfb)
  19.571 +{
  19.572 +	struct xenkbd_page *page = xenfb->kbd.page;
  19.573 +
  19.574 +	/* We don't understand any keyboard events, so just ignore them. */
  19.575 +	if (page->out_prod == page->out_cons)
  19.576 +		return;
  19.577 +	page->out_cons = page->out_prod;
  19.578 +	xc_evtchn_notify(xenfb->evt_xch, xenfb->kbd.port);
  19.579 +}
  19.580 +
  19.581 +static int xenfb_on_state_change(struct xenfb_device *dev)
  19.582 +{
  19.583 +	enum xenbus_state state;
  19.584 +
  19.585 +	state = xenfb_read_state(dev->xenfb->xsh, dev->otherend);
  19.586 +
  19.587 +	switch (state) {
  19.588 +	case XenbusStateUnknown:
  19.589 +		/* There was an error reading the frontend state.  The
  19.590 +		   domain has probably gone away; in any case, there's
  19.591 +		   not much point in us continuing. */
  19.592 +		return -1;
  19.593 +	case XenbusStateInitialising:
  19.594 +	case XenbusStateInitWait:
  19.595 +	case XenbusStateInitialised:
  19.596 +	case XenbusStateConnected:
  19.597 +		break;
  19.598 +	case XenbusStateClosing:
  19.599 +		xenfb_unbind(dev);
  19.600 +		xenfb_switch_state(dev, state);
  19.601 +		break;
  19.602 +	case XenbusStateClosed:
  19.603 +		xenfb_switch_state(dev, state);
  19.604 +	}
  19.605 +	return 0;
  19.606 +}
  19.607 +
  19.608 +/* Returns 0 normally, -1 on error, or -2 if the domain went away. */
  19.609 +int xenfb_poll(struct xenfb *xenfb_pub, fd_set *readfds)
  19.610 +{
  19.611 +	struct xenfb_private *xenfb = (struct xenfb_private *)xenfb_pub;
  19.612 +	evtchn_port_t port;
  19.613 +	unsigned dummy;
  19.614 +	char **vec;
  19.615 +	int r;
  19.616 +
  19.617 +	if (FD_ISSET(xc_evtchn_fd(xenfb->evt_xch), readfds)) {
  19.618 +		port = xc_evtchn_pending(xenfb->evt_xch);
  19.619 +		if (port == -1)
  19.620 +			return -1;
  19.621 +
  19.622 +		if (port == xenfb->fb.port)
  19.623 +			xenfb_on_fb_event(xenfb);
  19.624 +		else if (port == xenfb->kbd.port)
  19.625 +			xenfb_on_kbd_event(xenfb);
  19.626 +
  19.627 +		if (xc_evtchn_unmask(xenfb->evt_xch, port) == -1)
  19.628 +			return -1;
  19.629 +	}
  19.630 +
  19.631 +	if (FD_ISSET(xs_fileno(xenfb->xsh), readfds)) {
  19.632 +		vec = xs_read_watch(xenfb->xsh, &dummy);
  19.633 +		free(vec);
  19.634 +		r = xenfb_on_state_change(&xenfb->fb);
  19.635 +		if (r == 0)
  19.636 +			r = xenfb_on_state_change(&xenfb->kbd);
  19.637 +		if (r == -1)
  19.638 +			return -2;
  19.639 +	}
  19.640 +
  19.641 +	return 0;
  19.642 +}
  19.643 +
  19.644 +int xenfb_select_fds(struct xenfb *xenfb_pub, fd_set *readfds)
  19.645 +{
  19.646 +	struct xenfb_private *xenfb = (struct xenfb_private *)xenfb_pub;
  19.647 +	int fd1 = xc_evtchn_fd(xenfb->evt_xch);
  19.648 +	int fd2 = xs_fileno(xenfb->xsh);
  19.649 +
  19.650 +	FD_SET(fd1, readfds);
  19.651 +	FD_SET(fd2, readfds);
  19.652 +	return fd1 > fd2 ? fd1 + 1 : fd2 + 1;
  19.653 +}
  19.654 +
  19.655 +static int xenfb_kbd_event(struct xenfb_private *xenfb,
  19.656 +			   union xenkbd_in_event *event)
  19.657 +{
  19.658 +	uint32_t prod;
  19.659 +	struct xenkbd_page *page = xenfb->kbd.page;
  19.660 +
  19.661 +	if (xenfb->kbd.state != XenbusStateConnected)
  19.662 +		return 0;
  19.663 +
  19.664 +	prod = page->in_prod;
  19.665 +	if (prod - page->in_cons == XENKBD_IN_RING_LEN) {
  19.666 +		errno = EAGAIN;
  19.667 +		return -1;
  19.668 +	}
  19.669 +
  19.670 +	mb();			/* ensure ring space available */
  19.671 +	XENKBD_IN_RING_REF(page, prod) = *event;
  19.672 +	wmb();			/* ensure ring contents visible */
  19.673 +	page->in_prod = prod + 1;
  19.674 +	return xc_evtchn_notify(xenfb->evt_xch, xenfb->kbd.port);
  19.675 +}
  19.676 +
  19.677 +int xenfb_send_key(struct xenfb *xenfb_pub, bool down, int keycode)
  19.678 +{
  19.679 +	struct xenfb_private *xenfb = (struct xenfb_private *)xenfb_pub;
  19.680 +	union xenkbd_in_event event;
  19.681 +
  19.682 +	memset(&event, 0, XENKBD_IN_EVENT_SIZE);
  19.683 +	event.type = XENKBD_TYPE_KEY;
  19.684 +	event.key.pressed = down ? 1 : 0;
  19.685 +	event.key.keycode = keycode;
  19.686 +
  19.687 +	return xenfb_kbd_event(xenfb, &event);
  19.688 +}
  19.689 +
  19.690 +int xenfb_send_motion(struct xenfb *xenfb_pub, int rel_x, int rel_y)
  19.691 +{
  19.692 +	struct xenfb_private *xenfb = (struct xenfb_private *)xenfb_pub;
  19.693 +	union xenkbd_in_event event;
  19.694 +
  19.695 +	memset(&event, 0, XENKBD_IN_EVENT_SIZE);
  19.696 +	event.type = XENKBD_TYPE_MOTION;
  19.697 +	event.motion.rel_x = rel_x;
  19.698 +	event.motion.rel_y = rel_y;
  19.699 +
  19.700 +	return xenfb_kbd_event(xenfb, &event);
  19.701 +}
  19.702 +
  19.703 +int xenfb_send_position(struct xenfb *xenfb_pub, int abs_x, int abs_y)
  19.704 +{
  19.705 +	struct xenfb_private *xenfb = (struct xenfb_private *)xenfb_pub;
  19.706 +	union xenkbd_in_event event;
  19.707 +
  19.708 +	memset(&event, 0, XENKBD_IN_EVENT_SIZE);
  19.709 +	event.type = XENKBD_TYPE_POS;
  19.710 +	event.pos.abs_x = abs_x;
  19.711 +	event.pos.abs_y = abs_y;
  19.712 +
  19.713 +	return xenfb_kbd_event(xenfb, &event);
  19.714 +}
    20.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    20.2 +++ b/tools/xenfb/xenfb.h	Fri Dec 01 13:12:41 2006 +0000
    20.3 @@ -0,0 +1,35 @@
    20.4 +#ifndef _XENFB_H_
    20.5 +#define _XENFB_H_
    20.6 +
    20.7 +#include <stdbool.h>
    20.8 +#include <sys/types.h>
    20.9 +
   20.10 +struct xenfb
   20.11 +{
   20.12 +	void *pixels;
   20.13 +
   20.14 +	int row_stride;
   20.15 +	int depth;
   20.16 +	int width;
   20.17 +	int height;
   20.18 +	int abs_pointer_wanted;
   20.19 +
   20.20 +	void *user_data;
   20.21 +
   20.22 +	void (*update)(struct xenfb *xenfb, int x, int y, int width, int height);
   20.23 +};
   20.24 +
   20.25 +struct xenfb *xenfb_new(void);
   20.26 +void xenfb_delete(struct xenfb *xenfb);
   20.27 +void xenfb_teardown(struct xenfb *xenfb);
   20.28 +
   20.29 +int xenfb_attach_dom(struct xenfb *xenfb, int domid);
   20.30 +
   20.31 +int xenfb_select_fds(struct xenfb *xenfb, fd_set *readfds);
   20.32 +int xenfb_poll(struct xenfb *xenfb, fd_set *readfds);
   20.33 +
   20.34 +int xenfb_send_key(struct xenfb *xenfb, bool down, int keycode);
   20.35 +int xenfb_send_motion(struct xenfb *xenfb, int rel_x, int rel_y);
   20.36 +int xenfb_send_position(struct xenfb *xenfb, int abs_x, int abs_y);
   20.37 +
   20.38 +#endif
    21.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    21.2 +++ b/xen/include/public/io/fbif.h	Fri Dec 01 13:12:41 2006 +0000
    21.3 @@ -0,0 +1,116 @@
    21.4 +/*
    21.5 + * fbif.h -- Xen virtual frame buffer device
    21.6 + *
    21.7 + * Copyright (C) 2005 Anthony Liguori <aliguori@us.ibm.com>
    21.8 + * Copyright (C) 2006 Red Hat, Inc., Markus Armbruster <armbru@redhat.com>
    21.9 + *
   21.10 + *  This file is subject to the terms and conditions of the GNU General Public
   21.11 + *  License. See the file COPYING in the main directory of this archive for
   21.12 + *  more details.
   21.13 + */
   21.14 +
   21.15 +#ifndef __XEN_PUBLIC_IO_FBIF_H__
   21.16 +#define __XEN_PUBLIC_IO_FBIF_H__
   21.17 +
   21.18 +#include <asm/types.h>
   21.19 +
   21.20 +/* Out events (frontend -> backend) */
   21.21 +
   21.22 +/*
   21.23 + * Out events may be sent only when requested by backend, and receipt
   21.24 + * of an unknown out event is an error.
   21.25 + */
   21.26 +
   21.27 +/* Event type 1 currently not used */
   21.28 +/*
   21.29 + * Framebuffer update notification event
   21.30 + * Capable frontend sets feature-update in xenstore.
   21.31 + * Backend requests it by setting request-update in xenstore.
   21.32 + */
   21.33 +#define XENFB_TYPE_UPDATE 2
   21.34 +
   21.35 +struct xenfb_update
   21.36 +{
   21.37 +	__u8 type;		/* XENFB_TYPE_UPDATE */
   21.38 +	__s32 x;		/* source x */
   21.39 +	__s32 y;		/* source y */
   21.40 +	__s32 width;		/* rect width */
   21.41 +	__s32 height;		/* rect height */
   21.42 +};
   21.43 +
   21.44 +#define XENFB_OUT_EVENT_SIZE 40
   21.45 +
   21.46 +union xenfb_out_event
   21.47 +{
   21.48 +	__u8 type;
   21.49 +	struct xenfb_update update;
   21.50 +	char pad[XENFB_OUT_EVENT_SIZE];
   21.51 +};
   21.52 +
   21.53 +/* In events (backend -> frontend) */
   21.54 +
   21.55 +/*
   21.56 + * Frontends should ignore unknown in events.
   21.57 + * No in events currently defined.
   21.58 + */
   21.59 +
   21.60 +#define XENFB_IN_EVENT_SIZE 40
   21.61 +
   21.62 +union xenfb_in_event
   21.63 +{
   21.64 +	__u8 type;
   21.65 +	char pad[XENFB_IN_EVENT_SIZE];
   21.66 +};
   21.67 +
   21.68 +/* shared page */
   21.69 +
   21.70 +#define XENFB_IN_RING_SIZE 1024
   21.71 +#define XENFB_IN_RING_LEN (XENFB_IN_RING_SIZE / XENFB_IN_EVENT_SIZE)
   21.72 +#define XENFB_IN_RING_OFFS 1024
   21.73 +#define XENFB_IN_RING(page) \
   21.74 +    ((union xenfb_in_event *)((char *)(page) + XENFB_IN_RING_OFFS))
   21.75 +#define XENFB_IN_RING_REF(page, idx) \
   21.76 +    (XENFB_IN_RING((page))[(idx) % XENFB_IN_RING_LEN])
   21.77 +
   21.78 +#define XENFB_OUT_RING_SIZE 2048
   21.79 +#define XENFB_OUT_RING_LEN (XENFB_OUT_RING_SIZE / XENFB_OUT_EVENT_SIZE)
   21.80 +#define XENFB_OUT_RING_OFFS (XENFB_IN_RING_OFFS + XENFB_IN_RING_SIZE)
   21.81 +#define XENFB_OUT_RING(page) \
   21.82 +    ((union xenfb_out_event *)((char *)(page) + XENFB_OUT_RING_OFFS))
   21.83 +#define XENFB_OUT_RING_REF(page, idx) \
   21.84 +    (XENFB_OUT_RING((page))[(idx) % XENFB_OUT_RING_LEN])
   21.85 +
   21.86 +struct xenfb_page
   21.87 +{
   21.88 +	__u32 in_cons, in_prod;
   21.89 +	__u32 out_cons, out_prod;
   21.90 +
   21.91 +	__s32 width;         /* the width of the framebuffer (in pixels) */
   21.92 +	__s32 height;        /* the height of the framebuffer (in pixels) */
   21.93 +	__u32 line_length;   /* the length of a row of pixels (in bytes) */
   21.94 +	__u32 mem_length;    /* the length of the framebuffer (in bytes) */
   21.95 +	__u8 depth;          /* the depth of a pixel (in bits) */
   21.96 +
   21.97 +	/*
   21.98 +	 * Framebuffer page directory
   21.99 +	 *
  21.100 +	 * Each directory page holds PAGE_SIZE / sizeof(*pd)
  21.101 +	 * framebuffer pages, and can thus map up to PAGE_SIZE *
  21.102 +	 * PAGE_SIZE / sizeof(*pd) bytes.  With PAGE_SIZE == 4096 and
  21.103 +	 * sizeof(unsigned long) == 4, that's 4 Megs.  Two directory
  21.104 +	 * pages should be enough for a while.
  21.105 +	 */
  21.106 +	unsigned long pd[2];
  21.107 +};
  21.108 +
  21.109 +/*
  21.110 + * Wart: xenkbd needs to know resolution.  Put it here until a better
  21.111 + * solution is found, but don't leak it to the backend.
  21.112 + */
  21.113 +#ifdef __KERNEL__
  21.114 +#define XENFB_WIDTH 800
  21.115 +#define XENFB_HEIGHT 600
  21.116 +#define XENFB_DEPTH 32
  21.117 +#endif
  21.118 +
  21.119 +#endif
    22.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    22.2 +++ b/xen/include/public/io/kbdif.h	Fri Dec 01 13:12:41 2006 +0000
    22.3 @@ -0,0 +1,108 @@
    22.4 +/*
    22.5 + * kbdif.h -- Xen virtual keyboard/mouse
    22.6 + *
    22.7 + * Copyright (C) 2005 Anthony Liguori <aliguori@us.ibm.com>
    22.8 + * Copyright (C) 2006 Red Hat, Inc., Markus Armbruster <armbru@redhat.com>
    22.9 + *
   22.10 + *  This file is subject to the terms and conditions of the GNU General Public
   22.11 + *  License. See the file COPYING in the main directory of this archive for
   22.12 + *  more details.
   22.13 + */
   22.14 +
   22.15 +#ifndef __XEN_PUBLIC_IO_KBDIF_H__
   22.16 +#define __XEN_PUBLIC_IO_KBDIF_H__
   22.17 +
   22.18 +#include <asm/types.h>
   22.19 +
   22.20 +/* In events (backend -> frontend) */
   22.21 +
   22.22 +/*
   22.23 + * Frontends should ignore unknown in events.
   22.24 + */
   22.25 +
   22.26 +/* Pointer movement event */
   22.27 +#define XENKBD_TYPE_MOTION  1
   22.28 +/* Event type 2 currently not used */
   22.29 +/* Key event (includes pointer buttons) */
   22.30 +#define XENKBD_TYPE_KEY     3
   22.31 +/*
   22.32 + * Pointer position event
   22.33 + * Capable backend sets feature-abs-pointer in xenstore.
   22.34 + * Frontend requests ot instead of XENKBD_TYPE_MOTION by setting
   22.35 + * request-abs-update in xenstore.
   22.36 + */
   22.37 +#define XENKBD_TYPE_POS     4
   22.38 +
   22.39 +struct xenkbd_motion
   22.40 +{
   22.41 +	__u8 type;         /* XENKBD_TYPE_MOTION */
   22.42 +	__s32 rel_x;       /* relative X motion */
   22.43 +	__s32 rel_y;       /* relative Y motion */
   22.44 +};
   22.45 +
   22.46 +struct xenkbd_key
   22.47 +{
   22.48 +	__u8 type;         /* XENKBD_TYPE_KEY */
   22.49 +	__u8 pressed;      /* 1 if pressed; 0 otherwise */
   22.50 +	__u32 keycode;     /* KEY_* from linux/input.h */
   22.51 +};
   22.52 +
   22.53 +struct xenkbd_position
   22.54 +{
   22.55 +	__u8 type;         /* XENKBD_TYPE_POS */
   22.56 +	__s32 abs_x;       /* absolute X position (in FB pixels) */
   22.57 +	__s32 abs_y;       /* absolute Y position (in FB pixels) */
   22.58 +};
   22.59 +
   22.60 +#define XENKBD_IN_EVENT_SIZE 40
   22.61 +
   22.62 +union xenkbd_in_event
   22.63 +{
   22.64 +	__u8 type;
   22.65 +	struct xenkbd_motion motion;
   22.66 +	struct xenkbd_key key;
   22.67 +	struct xenkbd_position pos;
   22.68 +	char pad[XENKBD_IN_EVENT_SIZE];
   22.69 +};
   22.70 +
   22.71 +/* Out events (frontend -> backend) */
   22.72 +
   22.73 +/*
   22.74 + * Out events may be sent only when requested by backend, and receipt
   22.75 + * of an unknown out event is an error.
   22.76 + * No out events currently defined.
   22.77 + */
   22.78 +
   22.79 +#define XENKBD_OUT_EVENT_SIZE 40
   22.80 +
   22.81 +union xenkbd_out_event
   22.82 +{
   22.83 +	__u8 type;
   22.84 +	char pad[XENKBD_OUT_EVENT_SIZE];
   22.85 +};
   22.86 +
   22.87 +/* shared page */
   22.88 +
   22.89 +#define XENKBD_IN_RING_SIZE 2048
   22.90 +#define XENKBD_IN_RING_LEN (XENKBD_IN_RING_SIZE / XENKBD_IN_EVENT_SIZE)
   22.91 +#define XENKBD_IN_RING_OFFS 1024
   22.92 +#define XENKBD_IN_RING(page) \
   22.93 +    ((union xenkbd_in_event *)((char *)(page) + XENKBD_IN_RING_OFFS))
   22.94 +#define XENKBD_IN_RING_REF(page, idx) \
   22.95 +    (XENKBD_IN_RING((page))[(idx) % XENKBD_IN_RING_LEN])
   22.96 +
   22.97 +#define XENKBD_OUT_RING_SIZE 1024
   22.98 +#define XENKBD_OUT_RING_LEN (XENKBD_OUT_RING_SIZE / XENKBD_OUT_EVENT_SIZE)
   22.99 +#define XENKBD_OUT_RING_OFFS (XENKBD_IN_RING_OFFS + XENKBD_IN_RING_SIZE)
  22.100 +#define XENKBD_OUT_RING(page) \
  22.101 +    ((union xenkbd_out_event *)((char *)(page) + XENKBD_OUT_RING_OFFS))
  22.102 +#define XENKBD_OUT_RING_REF(page, idx) \
  22.103 +    (XENKBD_OUT_RING((page))[(idx) % XENKBD_OUT_RING_LEN])
  22.104 +
  22.105 +struct xenkbd_page
  22.106 +{
  22.107 +	__u32 in_cons, in_prod;
  22.108 +	__u32 out_cons, out_prod;
  22.109 +};
  22.110 +
  22.111 +#endif