ia64/xen-unstable

changeset 12731:260426e3924f

This is Anthony Liguori's virtual framebuffer forward ported and
extensively hacked based on feedback from xen-devel.

Its architecture is comparable to the common split device driver
architecture: xenfb and xenkbd modules serve as frontend in domU, and
the user space vncfb or sdlfb process serves as backend in dom0.

Signed-off-by: Markus Armbruster <armbru@redhat.com>
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
author Steven Smith <ssmith@xensource.com>
date Fri Dec 01 09:48:32 2006 +0000 (2006-12-01)
parents 697b0203e68f
children 000609d8c93f
files linux-2.6-xen-sparse/arch/i386/kernel/setup-xen.c linux-2.6-xen-sparse/arch/ia64/kernel/setup.c linux-2.6-xen-sparse/arch/x86_64/kernel/setup-xen.c linux-2.6-xen-sparse/drivers/char/tty_io.c linux-2.6-xen-sparse/drivers/xen/Kconfig linux-2.6-xen-sparse/drivers/xen/Makefile linux-2.6-xen-sparse/drivers/xen/console/console.c linux-2.6-xen-sparse/drivers/xen/fbfront/Makefile linux-2.6-xen-sparse/drivers/xen/fbfront/xenfb.c linux-2.6-xen-sparse/drivers/xen/fbfront/xenkbd.c linux-2.6-xen-sparse/mm/memory.c tools/Makefile tools/python/xen/xend/XendDevices.py tools/python/xen/xend/XendDomainInfo.py tools/python/xen/xend/image.py tools/python/xen/xend/server/vfbif.py tools/python/xen/xm/create.py tools/xenfb/Makefile tools/xenfb/sdlfb.c tools/xenfb/vncfb.c tools/xenfb/xenfb.c tools/xenfb/xenfb.h xen/include/public/io/fbif.h xen/include/public/io/kbdif.h
line diff
     1.1 --- a/linux-2.6-xen-sparse/arch/i386/kernel/setup-xen.c	Fri Dec 01 09:28:14 2006 +0000
     1.2 +++ b/linux-2.6-xen-sparse/arch/i386/kernel/setup-xen.c	Fri Dec 01 09:48:32 2006 +0000
     1.3 @@ -1867,8 +1867,9 @@ 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  }
    1.14  
     2.1 --- a/linux-2.6-xen-sparse/arch/ia64/kernel/setup.c	Fri Dec 01 09:28:14 2006 +0000
     2.2 +++ b/linux-2.6-xen-sparse/arch/ia64/kernel/setup.c	Fri Dec 01 09:48:32 2006 +0000
     2.3 @@ -550,9 +550,9 @@ 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  #endif
     3.1 --- a/linux-2.6-xen-sparse/arch/x86_64/kernel/setup-xen.c	Fri Dec 01 09:28:14 2006 +0000
     3.2 +++ b/linux-2.6-xen-sparse/arch/x86_64/kernel/setup-xen.c	Fri Dec 01 09:48:32 2006 +0000
     3.3 @@ -983,9 +983,10 @@ 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  #else	/* CONFIG_XEN */
    3.16  
     4.1 --- a/linux-2.6-xen-sparse/drivers/char/tty_io.c	Fri Dec 01 09:28:14 2006 +0000
     4.2 +++ /dev/null	Thu Jan 01 00:00:00 1970 +0000
     4.3 @@ -1,3264 +0,0 @@
     4.4 -/*
     4.5 - *  linux/drivers/char/tty_io.c
     4.6 - *
     4.7 - *  Copyright (C) 1991, 1992  Linus Torvalds
     4.8 - */
     4.9 -
    4.10 -/*
    4.11 - * 'tty_io.c' gives an orthogonal feeling to tty's, be they consoles
    4.12 - * or rs-channels. It also implements echoing, cooked mode etc.
    4.13 - *
    4.14 - * Kill-line thanks to John T Kohl, who also corrected VMIN = VTIME = 0.
    4.15 - *
    4.16 - * Modified by Theodore Ts'o, 9/14/92, to dynamically allocate the
    4.17 - * tty_struct and tty_queue structures.  Previously there was an array
    4.18 - * of 256 tty_struct's which was statically allocated, and the
    4.19 - * tty_queue structures were allocated at boot time.  Both are now
    4.20 - * dynamically allocated only when the tty is open.
    4.21 - *
    4.22 - * Also restructured routines so that there is more of a separation
    4.23 - * between the high-level tty routines (tty_io.c and tty_ioctl.c) and
    4.24 - * the low-level tty routines (serial.c, pty.c, console.c).  This
    4.25 - * makes for cleaner and more compact code.  -TYT, 9/17/92 
    4.26 - *
    4.27 - * Modified by Fred N. van Kempen, 01/29/93, to add line disciplines
    4.28 - * which can be dynamically activated and de-activated by the line
    4.29 - * discipline handling modules (like SLIP).
    4.30 - *
    4.31 - * NOTE: pay no attention to the line discipline code (yet); its
    4.32 - * interface is still subject to change in this version...
    4.33 - * -- TYT, 1/31/92
    4.34 - *
    4.35 - * Added functionality to the OPOST tty handling.  No delays, but all
    4.36 - * other bits should be there.
    4.37 - *	-- Nick Holloway <alfie@dcs.warwick.ac.uk>, 27th May 1993.
    4.38 - *
    4.39 - * Rewrote canonical mode and added more termios flags.
    4.40 - * 	-- julian@uhunix.uhcc.hawaii.edu (J. Cowley), 13Jan94
    4.41 - *
    4.42 - * Reorganized FASYNC support so mouse code can share it.
    4.43 - *	-- ctm@ardi.com, 9Sep95
    4.44 - *
    4.45 - * New TIOCLINUX variants added.
    4.46 - *	-- mj@k332.feld.cvut.cz, 19-Nov-95
    4.47 - * 
    4.48 - * Restrict vt switching via ioctl()
    4.49 - *      -- grif@cs.ucr.edu, 5-Dec-95
    4.50 - *
    4.51 - * Move console and virtual terminal code to more appropriate files,
    4.52 - * implement CONFIG_VT and generalize console device interface.
    4.53 - *	-- Marko Kohtala <Marko.Kohtala@hut.fi>, March 97
    4.54 - *
    4.55 - * Rewrote init_dev and release_dev to eliminate races.
    4.56 - *	-- Bill Hawes <whawes@star.net>, June 97
    4.57 - *
    4.58 - * Added devfs support.
    4.59 - *      -- C. Scott Ananian <cananian@alumni.princeton.edu>, 13-Jan-1998
    4.60 - *
    4.61 - * Added support for a Unix98-style ptmx device.
    4.62 - *      -- C. Scott Ananian <cananian@alumni.princeton.edu>, 14-Jan-1998
    4.63 - *
    4.64 - * Reduced memory usage for older ARM systems
    4.65 - *      -- Russell King <rmk@arm.linux.org.uk>
    4.66 - *
    4.67 - * Move do_SAK() into process context.  Less stack use in devfs functions.
    4.68 - * alloc_tty_struct() always uses kmalloc() -- Andrew Morton <andrewm@uow.edu.eu> 17Mar01
    4.69 - */
    4.70 -
    4.71 -#include <linux/config.h>
    4.72 -#include <linux/types.h>
    4.73 -#include <linux/major.h>
    4.74 -#include <linux/errno.h>
    4.75 -#include <linux/signal.h>
    4.76 -#include <linux/fcntl.h>
    4.77 -#include <linux/sched.h>
    4.78 -#include <linux/interrupt.h>
    4.79 -#include <linux/tty.h>
    4.80 -#include <linux/tty_driver.h>
    4.81 -#include <linux/tty_flip.h>
    4.82 -#include <linux/devpts_fs.h>
    4.83 -#include <linux/file.h>
    4.84 -#include <linux/console.h>
    4.85 -#include <linux/timer.h>
    4.86 -#include <linux/ctype.h>
    4.87 -#include <linux/kd.h>
    4.88 -#include <linux/mm.h>
    4.89 -#include <linux/string.h>
    4.90 -#include <linux/slab.h>
    4.91 -#include <linux/poll.h>
    4.92 -#include <linux/proc_fs.h>
    4.93 -#include <linux/init.h>
    4.94 -#include <linux/module.h>
    4.95 -#include <linux/smp_lock.h>
    4.96 -#include <linux/device.h>
    4.97 -#include <linux/idr.h>
    4.98 -#include <linux/wait.h>
    4.99 -#include <linux/bitops.h>
   4.100 -#include <linux/delay.h>
   4.101 -
   4.102 -#include <asm/uaccess.h>
   4.103 -#include <asm/system.h>
   4.104 -
   4.105 -#include <linux/kbd_kern.h>
   4.106 -#include <linux/vt_kern.h>
   4.107 -#include <linux/selection.h>
   4.108 -#include <linux/devfs_fs_kernel.h>
   4.109 -
   4.110 -#include <linux/kmod.h>
   4.111 -
   4.112 -#undef TTY_DEBUG_HANGUP
   4.113 -
   4.114 -#define TTY_PARANOIA_CHECK 1
   4.115 -#define CHECK_TTY_COUNT 1
   4.116 -
   4.117 -struct termios tty_std_termios = {	/* for the benefit of tty drivers  */
   4.118 -	.c_iflag = ICRNL | IXON,
   4.119 -	.c_oflag = OPOST | ONLCR,
   4.120 -	.c_cflag = B38400 | CS8 | CREAD | HUPCL,
   4.121 -	.c_lflag = ISIG | ICANON | ECHO | ECHOE | ECHOK |
   4.122 -		   ECHOCTL | ECHOKE | IEXTEN,
   4.123 -	.c_cc = INIT_C_CC
   4.124 -};
   4.125 -
   4.126 -EXPORT_SYMBOL(tty_std_termios);
   4.127 -
   4.128 -/* This list gets poked at by procfs and various bits of boot up code. This
   4.129 -   could do with some rationalisation such as pulling the tty proc function
   4.130 -   into this file */
   4.131 -   
   4.132 -LIST_HEAD(tty_drivers);			/* linked list of tty drivers */
   4.133 -
   4.134 -/* Semaphore to protect creating and releasing a tty. This is shared with
   4.135 -   vt.c for deeply disgusting hack reasons */
   4.136 -DECLARE_MUTEX(tty_sem);
   4.137 -
   4.138 -int console_use_vt = 1;
   4.139 -
   4.140 -#ifdef CONFIG_UNIX98_PTYS
   4.141 -extern struct tty_driver *ptm_driver;	/* Unix98 pty masters; for /dev/ptmx */
   4.142 -extern int pty_limit;		/* Config limit on Unix98 ptys */
   4.143 -static DEFINE_IDR(allocated_ptys);
   4.144 -static DECLARE_MUTEX(allocated_ptys_lock);
   4.145 -static int ptmx_open(struct inode *, struct file *);
   4.146 -#endif
   4.147 -
   4.148 -extern void disable_early_printk(void);
   4.149 -
   4.150 -static void initialize_tty_struct(struct tty_struct *tty);
   4.151 -
   4.152 -static ssize_t tty_read(struct file *, char __user *, size_t, loff_t *);
   4.153 -static ssize_t tty_write(struct file *, const char __user *, size_t, loff_t *);
   4.154 -ssize_t redirected_tty_write(struct file *, const char __user *, size_t, loff_t *);
   4.155 -static unsigned int tty_poll(struct file *, poll_table *);
   4.156 -static int tty_open(struct inode *, struct file *);
   4.157 -static int tty_release(struct inode *, struct file *);
   4.158 -int tty_ioctl(struct inode * inode, struct file * file,
   4.159 -	      unsigned int cmd, unsigned long arg);
   4.160 -static int tty_fasync(int fd, struct file * filp, int on);
   4.161 -static void release_mem(struct tty_struct *tty, int idx);
   4.162 -
   4.163 -
   4.164 -static struct tty_struct *alloc_tty_struct(void)
   4.165 -{
   4.166 -	struct tty_struct *tty;
   4.167 -
   4.168 -	tty = kmalloc(sizeof(struct tty_struct), GFP_KERNEL);
   4.169 -	if (tty)
   4.170 -		memset(tty, 0, sizeof(struct tty_struct));
   4.171 -	return tty;
   4.172 -}
   4.173 -
   4.174 -static void tty_buffer_free_all(struct tty_struct *);
   4.175 -
   4.176 -static inline void free_tty_struct(struct tty_struct *tty)
   4.177 -{
   4.178 -	kfree(tty->write_buf);
   4.179 -	tty_buffer_free_all(tty);
   4.180 -	kfree(tty);
   4.181 -}
   4.182 -
   4.183 -#define TTY_NUMBER(tty) ((tty)->index + (tty)->driver->name_base)
   4.184 -
   4.185 -char *tty_name(struct tty_struct *tty, char *buf)
   4.186 -{
   4.187 -	if (!tty) /* Hmm.  NULL pointer.  That's fun. */
   4.188 -		strcpy(buf, "NULL tty");
   4.189 -	else
   4.190 -		strcpy(buf, tty->name);
   4.191 -	return buf;
   4.192 -}
   4.193 -
   4.194 -EXPORT_SYMBOL(tty_name);
   4.195 -
   4.196 -int tty_paranoia_check(struct tty_struct *tty, struct inode *inode,
   4.197 -			      const char *routine)
   4.198 -{
   4.199 -#ifdef TTY_PARANOIA_CHECK
   4.200 -	if (!tty) {
   4.201 -		printk(KERN_WARNING
   4.202 -			"null TTY for (%d:%d) in %s\n",
   4.203 -			imajor(inode), iminor(inode), routine);
   4.204 -		return 1;
   4.205 -	}
   4.206 -	if (tty->magic != TTY_MAGIC) {
   4.207 -		printk(KERN_WARNING
   4.208 -			"bad magic number for tty struct (%d:%d) in %s\n",
   4.209 -			imajor(inode), iminor(inode), routine);
   4.210 -		return 1;
   4.211 -	}
   4.212 -#endif
   4.213 -	return 0;
   4.214 -}
   4.215 -
   4.216 -static int check_tty_count(struct tty_struct *tty, const char *routine)
   4.217 -{
   4.218 -#ifdef CHECK_TTY_COUNT
   4.219 -	struct list_head *p;
   4.220 -	int count = 0;
   4.221 -	
   4.222 -	file_list_lock();
   4.223 -	list_for_each(p, &tty->tty_files) {
   4.224 -		count++;
   4.225 -	}
   4.226 -	file_list_unlock();
   4.227 -	if (tty->driver->type == TTY_DRIVER_TYPE_PTY &&
   4.228 -	    tty->driver->subtype == PTY_TYPE_SLAVE &&
   4.229 -	    tty->link && tty->link->count)
   4.230 -		count++;
   4.231 -	if (tty->count != count) {
   4.232 -		printk(KERN_WARNING "Warning: dev (%s) tty->count(%d) "
   4.233 -				    "!= #fd's(%d) in %s\n",
   4.234 -		       tty->name, tty->count, count, routine);
   4.235 -		return count;
   4.236 -       }	
   4.237 -#endif
   4.238 -	return 0;
   4.239 -}
   4.240 -
   4.241 -/*
   4.242 - * Tty buffer allocation management
   4.243 - */
   4.244 -
   4.245 -static void tty_buffer_free_all(struct tty_struct *tty)
   4.246 -{
   4.247 -	struct tty_buffer *thead;
   4.248 -	while((thead = tty->buf.head) != NULL) {
   4.249 -		tty->buf.head = thead->next;
   4.250 -		kfree(thead);
   4.251 -	}
   4.252 -	while((thead = tty->buf.free) != NULL) {
   4.253 -		tty->buf.free = thead->next;
   4.254 -		kfree(thead);
   4.255 -	}
   4.256 -	tty->buf.tail = NULL;
   4.257 -}
   4.258 -
   4.259 -static void tty_buffer_init(struct tty_struct *tty)
   4.260 -{
   4.261 -	spin_lock_init(&tty->buf.lock);
   4.262 -	tty->buf.head = NULL;
   4.263 -	tty->buf.tail = NULL;
   4.264 -	tty->buf.free = NULL;
   4.265 -}
   4.266 -
   4.267 -static struct tty_buffer *tty_buffer_alloc(size_t size)
   4.268 -{
   4.269 -	struct tty_buffer *p = kmalloc(sizeof(struct tty_buffer) + 2 * size, GFP_ATOMIC);
   4.270 -	if(p == NULL)
   4.271 -		return NULL;
   4.272 -	p->used = 0;
   4.273 -	p->size = size;
   4.274 -	p->next = NULL;
   4.275 -	p->active = 0;
   4.276 -	p->commit = 0;
   4.277 -	p->read = 0;
   4.278 -	p->char_buf_ptr = (char *)(p->data);
   4.279 -	p->flag_buf_ptr = (unsigned char *)p->char_buf_ptr + size;
   4.280 -/* 	printk("Flip create %p\n", p); */
   4.281 -	return p;
   4.282 -}
   4.283 -
   4.284 -/* Must be called with the tty_read lock held. This needs to acquire strategy
   4.285 -   code to decide if we should kfree or relink a given expired buffer */
   4.286 -
   4.287 -static void tty_buffer_free(struct tty_struct *tty, struct tty_buffer *b)
   4.288 -{
   4.289 -	/* Dumb strategy for now - should keep some stats */
   4.290 -/* 	printk("Flip dispose %p\n", b); */
   4.291 -	if(b->size >= 512)
   4.292 -		kfree(b);
   4.293 -	else {
   4.294 -		b->next = tty->buf.free;
   4.295 -		tty->buf.free = b;
   4.296 -	}
   4.297 -}
   4.298 -
   4.299 -static struct tty_buffer *tty_buffer_find(struct tty_struct *tty, size_t size)
   4.300 -{
   4.301 -	struct tty_buffer **tbh = &tty->buf.free;
   4.302 -	while((*tbh) != NULL) {
   4.303 -		struct tty_buffer *t = *tbh;
   4.304 -		if(t->size >= size) {
   4.305 -			*tbh = t->next;
   4.306 -			t->next = NULL;
   4.307 -			t->used = 0;
   4.308 -			t->commit = 0;
   4.309 -			t->read = 0;
   4.310 -			/* DEBUG ONLY */
   4.311 -/*			memset(t->data, '*', size); */
   4.312 -/* 			printk("Flip recycle %p\n", t); */
   4.313 -			return t;
   4.314 -		}
   4.315 -		tbh = &((*tbh)->next);
   4.316 -	}
   4.317 -	/* Round the buffer size out */
   4.318 -	size = (size + 0xFF) & ~ 0xFF;
   4.319 -	return tty_buffer_alloc(size);
   4.320 -	/* Should possibly check if this fails for the largest buffer we
   4.321 -	   have queued and recycle that ? */
   4.322 -}
   4.323 -
   4.324 -int tty_buffer_request_room(struct tty_struct *tty, size_t size)
   4.325 -{
   4.326 -	struct tty_buffer *b, *n;
   4.327 -	int left;
   4.328 -	unsigned long flags;
   4.329 -
   4.330 -	spin_lock_irqsave(&tty->buf.lock, flags);
   4.331 -
   4.332 -	/* OPTIMISATION: We could keep a per tty "zero" sized buffer to
   4.333 -	   remove this conditional if its worth it. This would be invisible
   4.334 -	   to the callers */
   4.335 -	if ((b = tty->buf.tail) != NULL) {
   4.336 -		left = b->size - b->used;
   4.337 -		b->active = 1;
   4.338 -	} else
   4.339 -		left = 0;
   4.340 -
   4.341 -	if (left < size) {
   4.342 -		/* This is the slow path - looking for new buffers to use */
   4.343 -		if ((n = tty_buffer_find(tty, size)) != NULL) {
   4.344 -			if (b != NULL) {
   4.345 -				b->next = n;
   4.346 -				b->active = 0;
   4.347 -				b->commit = b->used;
   4.348 -			} else
   4.349 -				tty->buf.head = n;
   4.350 -			tty->buf.tail = n;
   4.351 -			n->active = 1;
   4.352 -		} else
   4.353 -			size = left;
   4.354 -	}
   4.355 -
   4.356 -	spin_unlock_irqrestore(&tty->buf.lock, flags);
   4.357 -	return size;
   4.358 -}
   4.359 -
   4.360 -EXPORT_SYMBOL_GPL(tty_buffer_request_room);
   4.361 -
   4.362 -int tty_insert_flip_string(struct tty_struct *tty, unsigned char *chars, size_t size)
   4.363 -{
   4.364 -	int copied = 0;
   4.365 -	do {
   4.366 -		int space = tty_buffer_request_room(tty, size - copied);
   4.367 -		struct tty_buffer *tb = tty->buf.tail;
   4.368 -		/* If there is no space then tb may be NULL */
   4.369 -		if(unlikely(space == 0))
   4.370 -			break;
   4.371 -		memcpy(tb->char_buf_ptr + tb->used, chars, space);
   4.372 -		memset(tb->flag_buf_ptr + tb->used, TTY_NORMAL, space);
   4.373 -		tb->used += space;
   4.374 -		copied += space;
   4.375 -		chars += space;
   4.376 -/* 		printk("Flip insert %d.\n", space); */
   4.377 -	}
   4.378 -	/* There is a small chance that we need to split the data over
   4.379 -	   several buffers. If this is the case we must loop */
   4.380 -	while (unlikely(size > copied));
   4.381 -	return copied;
   4.382 -}
   4.383 -
   4.384 -EXPORT_SYMBOL_GPL(tty_insert_flip_string);
   4.385 -
   4.386 -int tty_insert_flip_string_flags(struct tty_struct *tty, unsigned char *chars, char *flags, size_t size)
   4.387 -{
   4.388 -	int copied = 0;
   4.389 -	do {
   4.390 -		int space = tty_buffer_request_room(tty, size - copied);
   4.391 -		struct tty_buffer *tb = tty->buf.tail;
   4.392 -		/* If there is no space then tb may be NULL */
   4.393 -		if(unlikely(space == 0))
   4.394 -			break;
   4.395 -		memcpy(tb->char_buf_ptr + tb->used, chars, space);
   4.396 -		memcpy(tb->flag_buf_ptr + tb->used, flags, space);
   4.397 -		tb->used += space;
   4.398 -		copied += space;
   4.399 -		chars += space;
   4.400 -		flags += space;
   4.401 -	}
   4.402 -	/* There is a small chance that we need to split the data over
   4.403 -	   several buffers. If this is the case we must loop */
   4.404 -	while (unlikely(size > copied));
   4.405 -	return copied;
   4.406 -}
   4.407 -
   4.408 -EXPORT_SYMBOL_GPL(tty_insert_flip_string_flags);
   4.409 -
   4.410 -
   4.411 -/*
   4.412 - *	Prepare a block of space in the buffer for data. Returns the length
   4.413 - *	available and buffer pointer to the space which is now allocated and
   4.414 - *	accounted for as ready for normal characters. This is used for drivers
   4.415 - *	that need their own block copy routines into the buffer. There is no
   4.416 - *	guarantee the buffer is a DMA target!
   4.417 - */
   4.418 -
   4.419 -int tty_prepare_flip_string(struct tty_struct *tty, unsigned char **chars, size_t size)
   4.420 -{
   4.421 -	int space = tty_buffer_request_room(tty, size);
   4.422 -	if (likely(space)) {
   4.423 -		struct tty_buffer *tb = tty->buf.tail;
   4.424 -		*chars = tb->char_buf_ptr + tb->used;
   4.425 -		memset(tb->flag_buf_ptr + tb->used, TTY_NORMAL, space);
   4.426 -		tb->used += space;
   4.427 -	}
   4.428 -	return space;
   4.429 -}
   4.430 -
   4.431 -EXPORT_SYMBOL_GPL(tty_prepare_flip_string);
   4.432 -
   4.433 -/*
   4.434 - *	Prepare a block of space in the buffer for data. Returns the length
   4.435 - *	available and buffer pointer to the space which is now allocated and
   4.436 - *	accounted for as ready for characters. This is used for drivers
   4.437 - *	that need their own block copy routines into the buffer. There is no
   4.438 - *	guarantee the buffer is a DMA target!
   4.439 - */
   4.440 -
   4.441 -int tty_prepare_flip_string_flags(struct tty_struct *tty, unsigned char **chars, char **flags, size_t size)
   4.442 -{
   4.443 -	int space = tty_buffer_request_room(tty, size);
   4.444 -	if (likely(space)) {
   4.445 -		struct tty_buffer *tb = tty->buf.tail;
   4.446 -		*chars = tb->char_buf_ptr + tb->used;
   4.447 -		*flags = tb->flag_buf_ptr + tb->used;
   4.448 -		tb->used += space;
   4.449 -	}
   4.450 -	return space;
   4.451 -}
   4.452 -
   4.453 -EXPORT_SYMBOL_GPL(tty_prepare_flip_string_flags);
   4.454 -
   4.455 -
   4.456 -
   4.457 -/*
   4.458 - *	This is probably overkill for real world processors but
   4.459 - *	they are not on hot paths so a little discipline won't do 
   4.460 - *	any harm.
   4.461 - */
   4.462 - 
   4.463 -static void tty_set_termios_ldisc(struct tty_struct *tty, int num)
   4.464 -{
   4.465 -	down(&tty->termios_sem);
   4.466 -	tty->termios->c_line = num;
   4.467 -	up(&tty->termios_sem);
   4.468 -}
   4.469 -
   4.470 -/*
   4.471 - *	This guards the refcounted line discipline lists. The lock
   4.472 - *	must be taken with irqs off because there are hangup path
   4.473 - *	callers who will do ldisc lookups and cannot sleep.
   4.474 - */
   4.475 - 
   4.476 -static DEFINE_SPINLOCK(tty_ldisc_lock);
   4.477 -static DECLARE_WAIT_QUEUE_HEAD(tty_ldisc_wait);
   4.478 -static struct tty_ldisc tty_ldiscs[NR_LDISCS];	/* line disc dispatch table */
   4.479 -
   4.480 -int tty_register_ldisc(int disc, struct tty_ldisc *new_ldisc)
   4.481 -{
   4.482 -	unsigned long flags;
   4.483 -	int ret = 0;
   4.484 -	
   4.485 -	if (disc < N_TTY || disc >= NR_LDISCS)
   4.486 -		return -EINVAL;
   4.487 -	
   4.488 -	spin_lock_irqsave(&tty_ldisc_lock, flags);
   4.489 -	tty_ldiscs[disc] = *new_ldisc;
   4.490 -	tty_ldiscs[disc].num = disc;
   4.491 -	tty_ldiscs[disc].flags |= LDISC_FLAG_DEFINED;
   4.492 -	tty_ldiscs[disc].refcount = 0;
   4.493 -	spin_unlock_irqrestore(&tty_ldisc_lock, flags);
   4.494 -	
   4.495 -	return ret;
   4.496 -}
   4.497 -EXPORT_SYMBOL(tty_register_ldisc);
   4.498 -
   4.499 -int tty_unregister_ldisc(int disc)
   4.500 -{
   4.501 -	unsigned long flags;
   4.502 -	int ret = 0;
   4.503 -
   4.504 -	if (disc < N_TTY || disc >= NR_LDISCS)
   4.505 -		return -EINVAL;
   4.506 -
   4.507 -	spin_lock_irqsave(&tty_ldisc_lock, flags);
   4.508 -	if (tty_ldiscs[disc].refcount)
   4.509 -		ret = -EBUSY;
   4.510 -	else
   4.511 -		tty_ldiscs[disc].flags &= ~LDISC_FLAG_DEFINED;
   4.512 -	spin_unlock_irqrestore(&tty_ldisc_lock, flags);
   4.513 -
   4.514 -	return ret;
   4.515 -}
   4.516 -EXPORT_SYMBOL(tty_unregister_ldisc);
   4.517 -
   4.518 -struct tty_ldisc *tty_ldisc_get(int disc)
   4.519 -{
   4.520 -	unsigned long flags;
   4.521 -	struct tty_ldisc *ld;
   4.522 -
   4.523 -	if (disc < N_TTY || disc >= NR_LDISCS)
   4.524 -		return NULL;
   4.525 -	
   4.526 -	spin_lock_irqsave(&tty_ldisc_lock, flags);
   4.527 -
   4.528 -	ld = &tty_ldiscs[disc];
   4.529 -	/* Check the entry is defined */
   4.530 -	if(ld->flags & LDISC_FLAG_DEFINED)
   4.531 -	{
   4.532 -		/* If the module is being unloaded we can't use it */
   4.533 -		if (!try_module_get(ld->owner))
   4.534 -		       	ld = NULL;
   4.535 -		else /* lock it */
   4.536 -			ld->refcount++;
   4.537 -	}
   4.538 -	else
   4.539 -		ld = NULL;
   4.540 -	spin_unlock_irqrestore(&tty_ldisc_lock, flags);
   4.541 -	return ld;
   4.542 -}
   4.543 -
   4.544 -EXPORT_SYMBOL_GPL(tty_ldisc_get);
   4.545 -
   4.546 -void tty_ldisc_put(int disc)
   4.547 -{
   4.548 -	struct tty_ldisc *ld;
   4.549 -	unsigned long flags;
   4.550 -	
   4.551 -	if (disc < N_TTY || disc >= NR_LDISCS)
   4.552 -		BUG();
   4.553 -		
   4.554 -	spin_lock_irqsave(&tty_ldisc_lock, flags);
   4.555 -	ld = &tty_ldiscs[disc];
   4.556 -	if(ld->refcount == 0)
   4.557 -		BUG();
   4.558 -	ld->refcount --;
   4.559 -	module_put(ld->owner);
   4.560 -	spin_unlock_irqrestore(&tty_ldisc_lock, flags);
   4.561 -}
   4.562 -	
   4.563 -EXPORT_SYMBOL_GPL(tty_ldisc_put);
   4.564 -
   4.565 -static void tty_ldisc_assign(struct tty_struct *tty, struct tty_ldisc *ld)
   4.566 -{
   4.567 -	tty->ldisc = *ld;
   4.568 -	tty->ldisc.refcount = 0;
   4.569 -}
   4.570 -
   4.571 -/**
   4.572 - *	tty_ldisc_try		-	internal helper
   4.573 - *	@tty: the tty
   4.574 - *
   4.575 - *	Make a single attempt to grab and bump the refcount on
   4.576 - *	the tty ldisc. Return 0 on failure or 1 on success. This is
   4.577 - *	used to implement both the waiting and non waiting versions
   4.578 - *	of tty_ldisc_ref
   4.579 - */
   4.580 -
   4.581 -static int tty_ldisc_try(struct tty_struct *tty)
   4.582 -{
   4.583 -	unsigned long flags;
   4.584 -	struct tty_ldisc *ld;
   4.585 -	int ret = 0;
   4.586 -	
   4.587 -	spin_lock_irqsave(&tty_ldisc_lock, flags);
   4.588 -	ld = &tty->ldisc;
   4.589 -	if(test_bit(TTY_LDISC, &tty->flags))
   4.590 -	{
   4.591 -		ld->refcount++;
   4.592 -		ret = 1;
   4.593 -	}
   4.594 -	spin_unlock_irqrestore(&tty_ldisc_lock, flags);
   4.595 -	return ret;
   4.596 -}
   4.597 -
   4.598 -/**
   4.599 - *	tty_ldisc_ref_wait	-	wait for the tty ldisc
   4.600 - *	@tty: tty device
   4.601 - *
   4.602 - *	Dereference the line discipline for the terminal and take a 
   4.603 - *	reference to it. If the line discipline is in flux then 
   4.604 - *	wait patiently until it changes.
   4.605 - *
   4.606 - *	Note: Must not be called from an IRQ/timer context. The caller
   4.607 - *	must also be careful not to hold other locks that will deadlock
   4.608 - *	against a discipline change, such as an existing ldisc reference
   4.609 - *	(which we check for)
   4.610 - */
   4.611 - 
   4.612 -struct tty_ldisc *tty_ldisc_ref_wait(struct tty_struct *tty)
   4.613 -{
   4.614 -	/* wait_event is a macro */
   4.615 -	wait_event(tty_ldisc_wait, tty_ldisc_try(tty));
   4.616 -	if(tty->ldisc.refcount == 0)
   4.617 -		printk(KERN_ERR "tty_ldisc_ref_wait\n");
   4.618 -	return &tty->ldisc;
   4.619 -}
   4.620 -
   4.621 -EXPORT_SYMBOL_GPL(tty_ldisc_ref_wait);
   4.622 -
   4.623 -/**
   4.624 - *	tty_ldisc_ref		-	get the tty ldisc
   4.625 - *	@tty: tty device
   4.626 - *
   4.627 - *	Dereference the line discipline for the terminal and take a 
   4.628 - *	reference to it. If the line discipline is in flux then 
   4.629 - *	return NULL. Can be called from IRQ and timer functions.
   4.630 - */
   4.631 - 
   4.632 -struct tty_ldisc *tty_ldisc_ref(struct tty_struct *tty)
   4.633 -{
   4.634 -	if(tty_ldisc_try(tty))
   4.635 -		return &tty->ldisc;
   4.636 -	return NULL;
   4.637 -}
   4.638 -
   4.639 -EXPORT_SYMBOL_GPL(tty_ldisc_ref);
   4.640 -
   4.641 -/**
   4.642 - *	tty_ldisc_deref		-	free a tty ldisc reference
   4.643 - *	@ld: reference to free up
   4.644 - *
   4.645 - *	Undoes the effect of tty_ldisc_ref or tty_ldisc_ref_wait. May
   4.646 - *	be called in IRQ context.
   4.647 - */
   4.648 - 
   4.649 -void tty_ldisc_deref(struct tty_ldisc *ld)
   4.650 -{
   4.651 -	unsigned long flags;
   4.652 -
   4.653 -	if(ld == NULL)
   4.654 -		BUG();
   4.655 -		
   4.656 -	spin_lock_irqsave(&tty_ldisc_lock, flags);
   4.657 -	if(ld->refcount == 0)
   4.658 -		printk(KERN_ERR "tty_ldisc_deref: no references.\n");
   4.659 -	else
   4.660 -		ld->refcount--;
   4.661 -	if(ld->refcount == 0)
   4.662 -		wake_up(&tty_ldisc_wait);
   4.663 -	spin_unlock_irqrestore(&tty_ldisc_lock, flags);
   4.664 -}
   4.665 -
   4.666 -EXPORT_SYMBOL_GPL(tty_ldisc_deref);
   4.667 -
   4.668 -/**
   4.669 - *	tty_ldisc_enable	-	allow ldisc use
   4.670 - *	@tty: terminal to activate ldisc on
   4.671 - *
   4.672 - *	Set the TTY_LDISC flag when the line discipline can be called
   4.673 - *	again. Do neccessary wakeups for existing sleepers.
   4.674 - *
   4.675 - *	Note: nobody should set this bit except via this function. Clearing
   4.676 - *	directly is allowed.
   4.677 - */
   4.678 -
   4.679 -static void tty_ldisc_enable(struct tty_struct *tty)
   4.680 -{
   4.681 -	set_bit(TTY_LDISC, &tty->flags);
   4.682 -	wake_up(&tty_ldisc_wait);
   4.683 -}
   4.684 -	
   4.685 -/**
   4.686 - *	tty_set_ldisc		-	set line discipline
   4.687 - *	@tty: the terminal to set
   4.688 - *	@ldisc: the line discipline
   4.689 - *
   4.690 - *	Set the discipline of a tty line. Must be called from a process
   4.691 - *	context.
   4.692 - */
   4.693 - 
   4.694 -static int tty_set_ldisc(struct tty_struct *tty, int ldisc)
   4.695 -{
   4.696 -	int retval = 0;
   4.697 -	struct tty_ldisc o_ldisc;
   4.698 -	char buf[64];
   4.699 -	int work;
   4.700 -	unsigned long flags;
   4.701 -	struct tty_ldisc *ld;
   4.702 -	struct tty_struct *o_tty;
   4.703 -
   4.704 -	if ((ldisc < N_TTY) || (ldisc >= NR_LDISCS))
   4.705 -		return -EINVAL;
   4.706 -
   4.707 -restart:
   4.708 -
   4.709 -	ld = tty_ldisc_get(ldisc);
   4.710 -	/* Eduardo Blanco <ejbs@cs.cs.com.uy> */
   4.711 -	/* Cyrus Durgin <cider@speakeasy.org> */
   4.712 -	if (ld == NULL) {
   4.713 -		request_module("tty-ldisc-%d", ldisc);
   4.714 -		ld = tty_ldisc_get(ldisc);
   4.715 -	}
   4.716 -	if (ld == NULL)
   4.717 -		return -EINVAL;
   4.718 -
   4.719 -	/*
   4.720 -	 *	No more input please, we are switching. The new ldisc
   4.721 -	 *	will update this value in the ldisc open function
   4.722 -	 */
   4.723 -
   4.724 -	tty->receive_room = 0;
   4.725 -
   4.726 -	/*
   4.727 -	 *	Problem: What do we do if this blocks ?
   4.728 -	 */
   4.729 -
   4.730 -	tty_wait_until_sent(tty, 0);
   4.731 -
   4.732 -	if (tty->ldisc.num == ldisc) {
   4.733 -		tty_ldisc_put(ldisc);
   4.734 -		return 0;
   4.735 -	}
   4.736 -
   4.737 -	o_ldisc = tty->ldisc;
   4.738 -	o_tty = tty->link;
   4.739 -
   4.740 -	/*
   4.741 -	 *	Make sure we don't change while someone holds a
   4.742 -	 *	reference to the line discipline. The TTY_LDISC bit
   4.743 -	 *	prevents anyone taking a reference once it is clear.
   4.744 -	 *	We need the lock to avoid racing reference takers.
   4.745 -	 */
   4.746 -
   4.747 -	spin_lock_irqsave(&tty_ldisc_lock, flags);
   4.748 -	if (tty->ldisc.refcount || (o_tty && o_tty->ldisc.refcount)) {
   4.749 -		if(tty->ldisc.refcount) {
   4.750 -			/* Free the new ldisc we grabbed. Must drop the lock
   4.751 -			   first. */
   4.752 -			spin_unlock_irqrestore(&tty_ldisc_lock, flags);
   4.753 -			tty_ldisc_put(ldisc);
   4.754 -			/*
   4.755 -			 * There are several reasons we may be busy, including
   4.756 -			 * random momentary I/O traffic. We must therefore
   4.757 -			 * retry. We could distinguish between blocking ops
   4.758 -			 * and retries if we made tty_ldisc_wait() smarter. That
   4.759 -			 * is up for discussion.
   4.760 -			 */
   4.761 -			if (wait_event_interruptible(tty_ldisc_wait, tty->ldisc.refcount == 0) < 0)
   4.762 -				return -ERESTARTSYS;
   4.763 -			goto restart;
   4.764 -		}
   4.765 -		if(o_tty && o_tty->ldisc.refcount) {
   4.766 -			spin_unlock_irqrestore(&tty_ldisc_lock, flags);
   4.767 -			tty_ldisc_put(ldisc);
   4.768 -			if (wait_event_interruptible(tty_ldisc_wait, o_tty->ldisc.refcount == 0) < 0)
   4.769 -				return -ERESTARTSYS;
   4.770 -			goto restart;
   4.771 -		}
   4.772 -	}
   4.773 -
   4.774 -	/* if the TTY_LDISC bit is set, then we are racing against another ldisc change */
   4.775 -
   4.776 -	if (!test_bit(TTY_LDISC, &tty->flags)) {
   4.777 -		spin_unlock_irqrestore(&tty_ldisc_lock, flags);
   4.778 -		tty_ldisc_put(ldisc);
   4.779 -		ld = tty_ldisc_ref_wait(tty);
   4.780 -		tty_ldisc_deref(ld);
   4.781 -		goto restart;
   4.782 -	}
   4.783 -
   4.784 -	clear_bit(TTY_LDISC, &tty->flags);
   4.785 -	clear_bit(TTY_DONT_FLIP, &tty->flags);
   4.786 -	if (o_tty) {
   4.787 -		clear_bit(TTY_LDISC, &o_tty->flags);
   4.788 -		clear_bit(TTY_DONT_FLIP, &o_tty->flags);
   4.789 -	}
   4.790 -	spin_unlock_irqrestore(&tty_ldisc_lock, flags);
   4.791 -
   4.792 -	/*
   4.793 -	 *	From this point on we know nobody has an ldisc
   4.794 -	 *	usage reference, nor can they obtain one until
   4.795 -	 *	we say so later on.
   4.796 -	 */
   4.797 -
   4.798 -	work = cancel_delayed_work(&tty->buf.work);
   4.799 -	/*
   4.800 -	 * Wait for ->hangup_work and ->buf.work handlers to terminate
   4.801 -	 */
   4.802 -	 
   4.803 -	flush_scheduled_work();
   4.804 -	/* Shutdown the current discipline. */
   4.805 -	if (tty->ldisc.close)
   4.806 -		(tty->ldisc.close)(tty);
   4.807 -
   4.808 -	/* Now set up the new line discipline. */
   4.809 -	tty_ldisc_assign(tty, ld);
   4.810 -	tty_set_termios_ldisc(tty, ldisc);
   4.811 -	if (tty->ldisc.open)
   4.812 -		retval = (tty->ldisc.open)(tty);
   4.813 -	if (retval < 0) {
   4.814 -		tty_ldisc_put(ldisc);
   4.815 -		/* There is an outstanding reference here so this is safe */
   4.816 -		tty_ldisc_assign(tty, tty_ldisc_get(o_ldisc.num));
   4.817 -		tty_set_termios_ldisc(tty, tty->ldisc.num);
   4.818 -		if (tty->ldisc.open && (tty->ldisc.open(tty) < 0)) {
   4.819 -			tty_ldisc_put(o_ldisc.num);
   4.820 -			/* This driver is always present */
   4.821 -			tty_ldisc_assign(tty, tty_ldisc_get(N_TTY));
   4.822 -			tty_set_termios_ldisc(tty, N_TTY);
   4.823 -			if (tty->ldisc.open) {
   4.824 -				int r = tty->ldisc.open(tty);
   4.825 -
   4.826 -				if (r < 0)
   4.827 -					panic("Couldn't open N_TTY ldisc for "
   4.828 -					      "%s --- error %d.",
   4.829 -					      tty_name(tty, buf), r);
   4.830 -			}
   4.831 -		}
   4.832 -	}
   4.833 -	/* At this point we hold a reference to the new ldisc and a
   4.834 -	   a reference to the old ldisc. If we ended up flipping back
   4.835 -	   to the existing ldisc we have two references to it */
   4.836 -	
   4.837 -	if (tty->ldisc.num != o_ldisc.num && tty->driver->set_ldisc)
   4.838 -		tty->driver->set_ldisc(tty);
   4.839 -		
   4.840 -	tty_ldisc_put(o_ldisc.num);
   4.841 -	
   4.842 -	/*
   4.843 -	 *	Allow ldisc referencing to occur as soon as the driver
   4.844 -	 *	ldisc callback completes.
   4.845 -	 */
   4.846 -	 
   4.847 -	tty_ldisc_enable(tty);
   4.848 -	if (o_tty)
   4.849 -		tty_ldisc_enable(o_tty);
   4.850 -	
   4.851 -	/* Restart it in case no characters kick it off. Safe if
   4.852 -	   already running */
   4.853 -	if (work)
   4.854 -		schedule_delayed_work(&tty->buf.work, 1);
   4.855 -	return retval;
   4.856 -}
   4.857 -
   4.858 -/*
   4.859 - * This routine returns a tty driver structure, given a device number
   4.860 - */
   4.861 -static struct tty_driver *get_tty_driver(dev_t device, int *index)
   4.862 -{
   4.863 -	struct tty_driver *p;
   4.864 -
   4.865 -	list_for_each_entry(p, &tty_drivers, tty_drivers) {
   4.866 -		dev_t base = MKDEV(p->major, p->minor_start);
   4.867 -		if (device < base || device >= base + p->num)
   4.868 -			continue;
   4.869 -		*index = device - base;
   4.870 -		return p;
   4.871 -	}
   4.872 -	return NULL;
   4.873 -}
   4.874 -
   4.875 -/*
   4.876 - * If we try to write to, or set the state of, a terminal and we're
   4.877 - * not in the foreground, send a SIGTTOU.  If the signal is blocked or
   4.878 - * ignored, go ahead and perform the operation.  (POSIX 7.2)
   4.879 - */
   4.880 -int tty_check_change(struct tty_struct * tty)
   4.881 -{
   4.882 -	if (current->signal->tty != tty)
   4.883 -		return 0;
   4.884 -	if (tty->pgrp <= 0) {
   4.885 -		printk(KERN_WARNING "tty_check_change: tty->pgrp <= 0!\n");
   4.886 -		return 0;
   4.887 -	}
   4.888 -	if (process_group(current) == tty->pgrp)
   4.889 -		return 0;
   4.890 -	if (is_ignored(SIGTTOU))
   4.891 -		return 0;
   4.892 -	if (is_orphaned_pgrp(process_group(current)))
   4.893 -		return -EIO;
   4.894 -	(void) kill_pg(process_group(current), SIGTTOU, 1);
   4.895 -	return -ERESTARTSYS;
   4.896 -}
   4.897 -
   4.898 -EXPORT_SYMBOL(tty_check_change);
   4.899 -
   4.900 -static ssize_t hung_up_tty_read(struct file * file, char __user * buf,
   4.901 -				size_t count, loff_t *ppos)
   4.902 -{
   4.903 -	return 0;
   4.904 -}
   4.905 -
   4.906 -static ssize_t hung_up_tty_write(struct file * file, const char __user * buf,
   4.907 -				 size_t count, loff_t *ppos)
   4.908 -{
   4.909 -	return -EIO;
   4.910 -}
   4.911 -
   4.912 -/* No kernel lock held - none needed ;) */
   4.913 -static unsigned int hung_up_tty_poll(struct file * filp, poll_table * wait)
   4.914 -{
   4.915 -	return POLLIN | POLLOUT | POLLERR | POLLHUP | POLLRDNORM | POLLWRNORM;
   4.916 -}
   4.917 -
   4.918 -static int hung_up_tty_ioctl(struct inode * inode, struct file * file,
   4.919 -			     unsigned int cmd, unsigned long arg)
   4.920 -{
   4.921 -	return cmd == TIOCSPGRP ? -ENOTTY : -EIO;
   4.922 -}
   4.923 -
   4.924 -static struct file_operations tty_fops = {
   4.925 -	.llseek		= no_llseek,
   4.926 -	.read		= tty_read,
   4.927 -	.write		= tty_write,
   4.928 -	.poll		= tty_poll,
   4.929 -	.ioctl		= tty_ioctl,
   4.930 -	.open		= tty_open,
   4.931 -	.release	= tty_release,
   4.932 -	.fasync		= tty_fasync,
   4.933 -};
   4.934 -
   4.935 -#ifdef CONFIG_UNIX98_PTYS
   4.936 -static struct file_operations ptmx_fops = {
   4.937 -	.llseek		= no_llseek,
   4.938 -	.read		= tty_read,
   4.939 -	.write		= tty_write,
   4.940 -	.poll		= tty_poll,
   4.941 -	.ioctl		= tty_ioctl,
   4.942 -	.open		= ptmx_open,
   4.943 -	.release	= tty_release,
   4.944 -	.fasync		= tty_fasync,
   4.945 -};
   4.946 -#endif
   4.947 -
   4.948 -static struct file_operations console_fops = {
   4.949 -	.llseek		= no_llseek,
   4.950 -	.read		= tty_read,
   4.951 -	.write		= redirected_tty_write,
   4.952 -	.poll		= tty_poll,
   4.953 -	.ioctl		= tty_ioctl,
   4.954 -	.open		= tty_open,
   4.955 -	.release	= tty_release,
   4.956 -	.fasync		= tty_fasync,
   4.957 -};
   4.958 -
   4.959 -static struct file_operations hung_up_tty_fops = {
   4.960 -	.llseek		= no_llseek,
   4.961 -	.read		= hung_up_tty_read,
   4.962 -	.write		= hung_up_tty_write,
   4.963 -	.poll		= hung_up_tty_poll,
   4.964 -	.ioctl		= hung_up_tty_ioctl,
   4.965 -	.release	= tty_release,
   4.966 -};
   4.967 -
   4.968 -static DEFINE_SPINLOCK(redirect_lock);
   4.969 -static struct file *redirect;
   4.970 -
   4.971 -/**
   4.972 - *	tty_wakeup	-	request more data
   4.973 - *	@tty: terminal
   4.974 - *
   4.975 - *	Internal and external helper for wakeups of tty. This function
   4.976 - *	informs the line discipline if present that the driver is ready
   4.977 - *	to receive more output data.
   4.978 - */
   4.979 - 
   4.980 -void tty_wakeup(struct tty_struct *tty)
   4.981 -{
   4.982 -	struct tty_ldisc *ld;
   4.983 -	
   4.984 -	if (test_bit(TTY_DO_WRITE_WAKEUP, &tty->flags)) {
   4.985 -		ld = tty_ldisc_ref(tty);
   4.986 -		if(ld) {
   4.987 -			if(ld->write_wakeup)
   4.988 -				ld->write_wakeup(tty);
   4.989 -			tty_ldisc_deref(ld);
   4.990 -		}
   4.991 -	}
   4.992 -	wake_up_interruptible(&tty->write_wait);
   4.993 -}
   4.994 -
   4.995 -EXPORT_SYMBOL_GPL(tty_wakeup);
   4.996 -
   4.997 -/**
   4.998 - *	tty_ldisc_flush	-	flush line discipline queue
   4.999 - *	@tty: tty
  4.1000 - *
  4.1001 - *	Flush the line discipline queue (if any) for this tty. If there
  4.1002 - *	is no line discipline active this is a no-op.
  4.1003 - */
  4.1004 - 
  4.1005 -void tty_ldisc_flush(struct tty_struct *tty)
  4.1006 -{
  4.1007 -	struct tty_ldisc *ld = tty_ldisc_ref(tty);
  4.1008 -	if(ld) {
  4.1009 -		if(ld->flush_buffer)
  4.1010 -			ld->flush_buffer(tty);
  4.1011 -		tty_ldisc_deref(ld);
  4.1012 -	}
  4.1013 -}
  4.1014 -
  4.1015 -EXPORT_SYMBOL_GPL(tty_ldisc_flush);
  4.1016 -	
  4.1017 -/*
  4.1018 - * This can be called by the "eventd" kernel thread.  That is process synchronous,
  4.1019 - * but doesn't hold any locks, so we need to make sure we have the appropriate
  4.1020 - * locks for what we're doing..
  4.1021 - */
  4.1022 -static void do_tty_hangup(void *data)
  4.1023 -{
  4.1024 -	struct tty_struct *tty = (struct tty_struct *) data;
  4.1025 -	struct file * cons_filp = NULL;
  4.1026 -	struct file *filp, *f = NULL;
  4.1027 -	struct task_struct *p;
  4.1028 -	struct tty_ldisc *ld;
  4.1029 -	int    closecount = 0, n;
  4.1030 -
  4.1031 -	if (!tty)
  4.1032 -		return;
  4.1033 -
  4.1034 -	/* inuse_filps is protected by the single kernel lock */
  4.1035 -	lock_kernel();
  4.1036 -
  4.1037 -	spin_lock(&redirect_lock);
  4.1038 -	if (redirect && redirect->private_data == tty) {
  4.1039 -		f = redirect;
  4.1040 -		redirect = NULL;
  4.1041 -	}
  4.1042 -	spin_unlock(&redirect_lock);
  4.1043 -	
  4.1044 -	check_tty_count(tty, "do_tty_hangup");
  4.1045 -	file_list_lock();
  4.1046 -	/* This breaks for file handles being sent over AF_UNIX sockets ? */
  4.1047 -	list_for_each_entry(filp, &tty->tty_files, f_u.fu_list) {
  4.1048 -		if (filp->f_op->write == redirected_tty_write)
  4.1049 -			cons_filp = filp;
  4.1050 -		if (filp->f_op->write != tty_write)
  4.1051 -			continue;
  4.1052 -		closecount++;
  4.1053 -		tty_fasync(-1, filp, 0);	/* can't block */
  4.1054 -		filp->f_op = &hung_up_tty_fops;
  4.1055 -	}
  4.1056 -	file_list_unlock();
  4.1057 -	
  4.1058 -	/* FIXME! What are the locking issues here? This may me overdoing things..
  4.1059 -	 * this question is especially important now that we've removed the irqlock. */
  4.1060 -
  4.1061 -	ld = tty_ldisc_ref(tty);
  4.1062 -	if(ld != NULL)	/* We may have no line discipline at this point */
  4.1063 -	{
  4.1064 -		if (ld->flush_buffer)
  4.1065 -			ld->flush_buffer(tty);
  4.1066 -		if (tty->driver->flush_buffer)
  4.1067 -			tty->driver->flush_buffer(tty);
  4.1068 -		if ((test_bit(TTY_DO_WRITE_WAKEUP, &tty->flags)) &&
  4.1069 -		    ld->write_wakeup)
  4.1070 -			ld->write_wakeup(tty);
  4.1071 -		if (ld->hangup)
  4.1072 -			ld->hangup(tty);
  4.1073 -	}
  4.1074 -
  4.1075 -	/* FIXME: Once we trust the LDISC code better we can wait here for
  4.1076 -	   ldisc completion and fix the driver call race */
  4.1077 -	   
  4.1078 -	wake_up_interruptible(&tty->write_wait);
  4.1079 -	wake_up_interruptible(&tty->read_wait);
  4.1080 -
  4.1081 -	/*
  4.1082 -	 * Shutdown the current line discipline, and reset it to
  4.1083 -	 * N_TTY.
  4.1084 -	 */
  4.1085 -	if (tty->driver->flags & TTY_DRIVER_RESET_TERMIOS)
  4.1086 -	{
  4.1087 -		down(&tty->termios_sem);
  4.1088 -		*tty->termios = tty->driver->init_termios;
  4.1089 -		up(&tty->termios_sem);
  4.1090 -	}
  4.1091 -	
  4.1092 -	/* Defer ldisc switch */
  4.1093 -	/* tty_deferred_ldisc_switch(N_TTY);
  4.1094 -	
  4.1095 -	  This should get done automatically when the port closes and
  4.1096 -	  tty_release is called */
  4.1097 -	
  4.1098 -	read_lock(&tasklist_lock);
  4.1099 -	if (tty->session > 0) {
  4.1100 -		do_each_task_pid(tty->session, PIDTYPE_SID, p) {
  4.1101 -			if (p->signal->tty == tty)
  4.1102 -				p->signal->tty = NULL;
  4.1103 -			if (!p->signal->leader)
  4.1104 -				continue;
  4.1105 -			send_group_sig_info(SIGHUP, SEND_SIG_PRIV, p);
  4.1106 -			send_group_sig_info(SIGCONT, SEND_SIG_PRIV, p);
  4.1107 -			if (tty->pgrp > 0)
  4.1108 -				p->signal->tty_old_pgrp = tty->pgrp;
  4.1109 -		} while_each_task_pid(tty->session, PIDTYPE_SID, p);
  4.1110 -	}
  4.1111 -	read_unlock(&tasklist_lock);
  4.1112 -
  4.1113 -	tty->flags = 0;
  4.1114 -	tty->session = 0;
  4.1115 -	tty->pgrp = -1;
  4.1116 -	tty->ctrl_status = 0;
  4.1117 -	/*
  4.1118 -	 *	If one of the devices matches a console pointer, we
  4.1119 -	 *	cannot just call hangup() because that will cause
  4.1120 -	 *	tty->count and state->count to go out of sync.
  4.1121 -	 *	So we just call close() the right number of times.
  4.1122 -	 */
  4.1123 -	if (cons_filp) {
  4.1124 -		if (tty->driver->close)
  4.1125 -			for (n = 0; n < closecount; n++)
  4.1126 -				tty->driver->close(tty, cons_filp);
  4.1127 -	} else if (tty->driver->hangup)
  4.1128 -		(tty->driver->hangup)(tty);
  4.1129 -		
  4.1130 -	/* We don't want to have driver/ldisc interactions beyond
  4.1131 -	   the ones we did here. The driver layer expects no
  4.1132 -	   calls after ->hangup() from the ldisc side. However we
  4.1133 -	   can't yet guarantee all that */
  4.1134 -
  4.1135 -	set_bit(TTY_HUPPED, &tty->flags);
  4.1136 -	if (ld) {
  4.1137 -		tty_ldisc_enable(tty);
  4.1138 -		tty_ldisc_deref(ld);
  4.1139 -	}
  4.1140 -	unlock_kernel();
  4.1141 -	if (f)
  4.1142 -		fput(f);
  4.1143 -}
  4.1144 -
  4.1145 -void tty_hangup(struct tty_struct * tty)
  4.1146 -{
  4.1147 -#ifdef TTY_DEBUG_HANGUP
  4.1148 -	char	buf[64];
  4.1149 -	
  4.1150 -	printk(KERN_DEBUG "%s hangup...\n", tty_name(tty, buf));
  4.1151 -#endif
  4.1152 -	schedule_work(&tty->hangup_work);
  4.1153 -}
  4.1154 -
  4.1155 -EXPORT_SYMBOL(tty_hangup);
  4.1156 -
  4.1157 -void tty_vhangup(struct tty_struct * tty)
  4.1158 -{
  4.1159 -#ifdef TTY_DEBUG_HANGUP
  4.1160 -	char	buf[64];
  4.1161 -
  4.1162 -	printk(KERN_DEBUG "%s vhangup...\n", tty_name(tty, buf));
  4.1163 -#endif
  4.1164 -	do_tty_hangup((void *) tty);
  4.1165 -}
  4.1166 -EXPORT_SYMBOL(tty_vhangup);
  4.1167 -
  4.1168 -int tty_hung_up_p(struct file * filp)
  4.1169 -{
  4.1170 -	return (filp->f_op == &hung_up_tty_fops);
  4.1171 -}
  4.1172 -
  4.1173 -EXPORT_SYMBOL(tty_hung_up_p);
  4.1174 -
  4.1175 -/*
  4.1176 - * This function is typically called only by the session leader, when
  4.1177 - * it wants to disassociate itself from its controlling tty.
  4.1178 - *
  4.1179 - * It performs the following functions:
  4.1180 - * 	(1)  Sends a SIGHUP and SIGCONT to the foreground process group
  4.1181 - * 	(2)  Clears the tty from being controlling the session
  4.1182 - * 	(3)  Clears the controlling tty for all processes in the
  4.1183 - * 		session group.
  4.1184 - *
  4.1185 - * The argument on_exit is set to 1 if called when a process is
  4.1186 - * exiting; it is 0 if called by the ioctl TIOCNOTTY.
  4.1187 - */
  4.1188 -void disassociate_ctty(int on_exit)
  4.1189 -{
  4.1190 -	struct tty_struct *tty;
  4.1191 -	struct task_struct *p;
  4.1192 -	int tty_pgrp = -1;
  4.1193 -
  4.1194 -	lock_kernel();
  4.1195 -
  4.1196 -	down(&tty_sem);
  4.1197 -	tty = current->signal->tty;
  4.1198 -	if (tty) {
  4.1199 -		tty_pgrp = tty->pgrp;
  4.1200 -		up(&tty_sem);
  4.1201 -		if (on_exit && tty->driver->type != TTY_DRIVER_TYPE_PTY)
  4.1202 -			tty_vhangup(tty);
  4.1203 -	} else {
  4.1204 -		if (current->signal->tty_old_pgrp) {
  4.1205 -			kill_pg(current->signal->tty_old_pgrp, SIGHUP, on_exit);
  4.1206 -			kill_pg(current->signal->tty_old_pgrp, SIGCONT, on_exit);
  4.1207 -		}
  4.1208 -		up(&tty_sem);
  4.1209 -		unlock_kernel();	
  4.1210 -		return;
  4.1211 -	}
  4.1212 -	if (tty_pgrp > 0) {
  4.1213 -		kill_pg(tty_pgrp, SIGHUP, on_exit);
  4.1214 -		if (!on_exit)
  4.1215 -			kill_pg(tty_pgrp, SIGCONT, on_exit);
  4.1216 -	}
  4.1217 -
  4.1218 -	/* Must lock changes to tty_old_pgrp */
  4.1219 -	down(&tty_sem);
  4.1220 -	current->signal->tty_old_pgrp = 0;
  4.1221 -	tty->session = 0;
  4.1222 -	tty->pgrp = -1;
  4.1223 -
  4.1224 -	/* Now clear signal->tty under the lock */
  4.1225 -	read_lock(&tasklist_lock);
  4.1226 -	do_each_task_pid(current->signal->session, PIDTYPE_SID, p) {
  4.1227 -		p->signal->tty = NULL;
  4.1228 -	} while_each_task_pid(current->signal->session, PIDTYPE_SID, p);
  4.1229 -	read_unlock(&tasklist_lock);
  4.1230 -	up(&tty_sem);
  4.1231 -	unlock_kernel();
  4.1232 -}
  4.1233 -
  4.1234 -void stop_tty(struct tty_struct *tty)
  4.1235 -{
  4.1236 -	if (tty->stopped)
  4.1237 -		return;
  4.1238 -	tty->stopped = 1;
  4.1239 -	if (tty->link && tty->link->packet) {
  4.1240 -		tty->ctrl_status &= ~TIOCPKT_START;
  4.1241 -		tty->ctrl_status |= TIOCPKT_STOP;
  4.1242 -		wake_up_interruptible(&tty->link->read_wait);
  4.1243 -	}
  4.1244 -	if (tty->driver->stop)
  4.1245 -		(tty->driver->stop)(tty);
  4.1246 -}
  4.1247 -
  4.1248 -EXPORT_SYMBOL(stop_tty);
  4.1249 -
  4.1250 -void start_tty(struct tty_struct *tty)
  4.1251 -{
  4.1252 -	if (!tty->stopped || tty->flow_stopped)
  4.1253 -		return;
  4.1254 -	tty->stopped = 0;
  4.1255 -	if (tty->link && tty->link->packet) {
  4.1256 -		tty->ctrl_status &= ~TIOCPKT_STOP;
  4.1257 -		tty->ctrl_status |= TIOCPKT_START;
  4.1258 -		wake_up_interruptible(&tty->link->read_wait);
  4.1259 -	}
  4.1260 -	if (tty->driver->start)
  4.1261 -		(tty->driver->start)(tty);
  4.1262 -
  4.1263 -	/* If we have a running line discipline it may need kicking */
  4.1264 -	tty_wakeup(tty);
  4.1265 -	wake_up_interruptible(&tty->write_wait);
  4.1266 -}
  4.1267 -
  4.1268 -EXPORT_SYMBOL(start_tty);
  4.1269 -
  4.1270 -static ssize_t tty_read(struct file * file, char __user * buf, size_t count, 
  4.1271 -			loff_t *ppos)
  4.1272 -{
  4.1273 -	int i;
  4.1274 -	struct tty_struct * tty;
  4.1275 -	struct inode *inode;
  4.1276 -	struct tty_ldisc *ld;
  4.1277 -
  4.1278 -	tty = (struct tty_struct *)file->private_data;
  4.1279 -	inode = file->f_dentry->d_inode;
  4.1280 -	if (tty_paranoia_check(tty, inode, "tty_read"))
  4.1281 -		return -EIO;
  4.1282 -	if (!tty || (test_bit(TTY_IO_ERROR, &tty->flags)))
  4.1283 -		return -EIO;
  4.1284 -
  4.1285 -	/* We want to wait for the line discipline to sort out in this
  4.1286 -	   situation */
  4.1287 -	ld = tty_ldisc_ref_wait(tty);
  4.1288 -	lock_kernel();
  4.1289 -	if (ld->read)
  4.1290 -		i = (ld->read)(tty,file,buf,count);
  4.1291 -	else
  4.1292 -		i = -EIO;
  4.1293 -	tty_ldisc_deref(ld);
  4.1294 -	unlock_kernel();
  4.1295 -	if (i > 0)
  4.1296 -		inode->i_atime = current_fs_time(inode->i_sb);
  4.1297 -	return i;
  4.1298 -}
  4.1299 -
  4.1300 -/*
  4.1301 - * Split writes up in sane blocksizes to avoid
  4.1302 - * denial-of-service type attacks
  4.1303 - */
  4.1304 -static inline ssize_t do_tty_write(
  4.1305 -	ssize_t (*write)(struct tty_struct *, struct file *, const unsigned char *, size_t),
  4.1306 -	struct tty_struct *tty,
  4.1307 -	struct file *file,
  4.1308 -	const char __user *buf,
  4.1309 -	size_t count)
  4.1310 -{
  4.1311 -	ssize_t ret = 0, written = 0;
  4.1312 -	unsigned int chunk;
  4.1313 -	
  4.1314 -	if (down_interruptible(&tty->atomic_write)) {
  4.1315 -		return -ERESTARTSYS;
  4.1316 -	}
  4.1317 -
  4.1318 -	/*
  4.1319 -	 * We chunk up writes into a temporary buffer. This
  4.1320 -	 * simplifies low-level drivers immensely, since they
  4.1321 -	 * don't have locking issues and user mode accesses.
  4.1322 -	 *
  4.1323 -	 * But if TTY_NO_WRITE_SPLIT is set, we should use a
  4.1324 -	 * big chunk-size..
  4.1325 -	 *
  4.1326 -	 * The default chunk-size is 2kB, because the NTTY
  4.1327 -	 * layer has problems with bigger chunks. It will
  4.1328 -	 * claim to be able to handle more characters than
  4.1329 -	 * it actually does.
  4.1330 -	 */
  4.1331 -	chunk = 2048;
  4.1332 -	if (test_bit(TTY_NO_WRITE_SPLIT, &tty->flags))
  4.1333 -		chunk = 65536;
  4.1334 -	if (count < chunk)
  4.1335 -		chunk = count;
  4.1336 -
  4.1337 -	/* write_buf/write_cnt is protected by the atomic_write semaphore */
  4.1338 -	if (tty->write_cnt < chunk) {
  4.1339 -		unsigned char *buf;
  4.1340 -
  4.1341 -		if (chunk < 1024)
  4.1342 -			chunk = 1024;
  4.1343 -
  4.1344 -		buf = kmalloc(chunk, GFP_KERNEL);
  4.1345 -		if (!buf) {
  4.1346 -			up(&tty->atomic_write);
  4.1347 -			return -ENOMEM;
  4.1348 -		}
  4.1349 -		kfree(tty->write_buf);
  4.1350 -		tty->write_cnt = chunk;
  4.1351 -		tty->write_buf = buf;
  4.1352 -	}
  4.1353 -
  4.1354 -	/* Do the write .. */
  4.1355 -	for (;;) {
  4.1356 -		size_t size = count;
  4.1357 -		if (size > chunk)
  4.1358 -			size = chunk;
  4.1359 -		ret = -EFAULT;
  4.1360 -		if (copy_from_user(tty->write_buf, buf, size))
  4.1361 -			break;
  4.1362 -		lock_kernel();
  4.1363 -		ret = write(tty, file, tty->write_buf, size);
  4.1364 -		unlock_kernel();
  4.1365 -		if (ret <= 0)
  4.1366 -			break;
  4.1367 -		written += ret;
  4.1368 -		buf += ret;
  4.1369 -		count -= ret;
  4.1370 -		if (!count)
  4.1371 -			break;
  4.1372 -		ret = -ERESTARTSYS;
  4.1373 -		if (signal_pending(current))
  4.1374 -			break;
  4.1375 -		cond_resched();
  4.1376 -	}
  4.1377 -	if (written) {
  4.1378 -		struct inode *inode = file->f_dentry->d_inode;
  4.1379 -		inode->i_mtime = current_fs_time(inode->i_sb);
  4.1380 -		ret = written;
  4.1381 -	}
  4.1382 -	up(&tty->atomic_write);
  4.1383 -	return ret;
  4.1384 -}
  4.1385 -
  4.1386 -
  4.1387 -static ssize_t tty_write(struct file * file, const char __user * buf, size_t count,
  4.1388 -			 loff_t *ppos)
  4.1389 -{
  4.1390 -	struct tty_struct * tty;
  4.1391 -	struct inode *inode = file->f_dentry->d_inode;
  4.1392 -	ssize_t ret;
  4.1393 -	struct tty_ldisc *ld;
  4.1394 -	
  4.1395 -	tty = (struct tty_struct *)file->private_data;
  4.1396 -	if (tty_paranoia_check(tty, inode, "tty_write"))
  4.1397 -		return -EIO;
  4.1398 -	if (!tty || !tty->driver->write || (test_bit(TTY_IO_ERROR, &tty->flags)))
  4.1399 -		return -EIO;
  4.1400 -
  4.1401 -	ld = tty_ldisc_ref_wait(tty);		
  4.1402 -	if (!ld->write)
  4.1403 -		ret = -EIO;
  4.1404 -	else
  4.1405 -		ret = do_tty_write(ld->write, tty, file, buf, count);
  4.1406 -	tty_ldisc_deref(ld);
  4.1407 -	return ret;
  4.1408 -}
  4.1409 -
  4.1410 -ssize_t redirected_tty_write(struct file * file, const char __user * buf, size_t count,
  4.1411 -			 loff_t *ppos)
  4.1412 -{
  4.1413 -	struct file *p = NULL;
  4.1414 -
  4.1415 -	spin_lock(&redirect_lock);
  4.1416 -	if (redirect) {
  4.1417 -		get_file(redirect);
  4.1418 -		p = redirect;
  4.1419 -	}
  4.1420 -	spin_unlock(&redirect_lock);
  4.1421 -
  4.1422 -	if (p) {
  4.1423 -		ssize_t res;
  4.1424 -		res = vfs_write(p, buf, count, &p->f_pos);
  4.1425 -		fput(p);
  4.1426 -		return res;
  4.1427 -	}
  4.1428 -
  4.1429 -	return tty_write(file, buf, count, ppos);
  4.1430 -}
  4.1431 -
  4.1432 -static char ptychar[] = "pqrstuvwxyzabcde";
  4.1433 -
  4.1434 -static inline void pty_line_name(struct tty_driver *driver, int index, char *p)
  4.1435 -{
  4.1436 -	int i = index + driver->name_base;
  4.1437 -	/* ->name is initialized to "ttyp", but "tty" is expected */
  4.1438 -	sprintf(p, "%s%c%x",
  4.1439 -			driver->subtype == PTY_TYPE_SLAVE ? "tty" : driver->name,
  4.1440 -			ptychar[i >> 4 & 0xf], i & 0xf);
  4.1441 -}
  4.1442 -
  4.1443 -static inline void tty_line_name(struct tty_driver *driver, int index, char *p)
  4.1444 -{
  4.1445 -	sprintf(p, "%s%d", driver->name, index + driver->name_base);
  4.1446 -}
  4.1447 -
  4.1448 -/*
  4.1449 - * WSH 06/09/97: Rewritten to remove races and properly clean up after a
  4.1450 - * failed open.  The new code protects the open with a semaphore, so it's
  4.1451 - * really quite straightforward.  The semaphore locking can probably be
  4.1452 - * relaxed for the (most common) case of reopening a tty.
  4.1453 - */
  4.1454 -static int init_dev(struct tty_driver *driver, int idx,
  4.1455 -	struct tty_struct **ret_tty)
  4.1456 -{
  4.1457 -	struct tty_struct *tty, *o_tty;
  4.1458 -	struct termios *tp, **tp_loc, *o_tp, **o_tp_loc;
  4.1459 -	struct termios *ltp, **ltp_loc, *o_ltp, **o_ltp_loc;
  4.1460 -	int retval=0;
  4.1461 -
  4.1462 -	/* check whether we're reopening an existing tty */
  4.1463 -	if (driver->flags & TTY_DRIVER_DEVPTS_MEM) {
  4.1464 -		tty = devpts_get_tty(idx);
  4.1465 -		if (tty && driver->subtype == PTY_TYPE_MASTER)
  4.1466 -			tty = tty->link;
  4.1467 -	} else {
  4.1468 -		tty = driver->ttys[idx];
  4.1469 -	}
  4.1470 -	if (tty) goto fast_track;
  4.1471 -
  4.1472 -	/*
  4.1473 -	 * First time open is complex, especially for PTY devices.
  4.1474 -	 * This code guarantees that either everything succeeds and the
  4.1475 -	 * TTY is ready for operation, or else the table slots are vacated
  4.1476 -	 * and the allocated memory released.  (Except that the termios 
  4.1477 -	 * and locked termios may be retained.)
  4.1478 -	 */
  4.1479 -
  4.1480 -	if (!try_module_get(driver->owner)) {
  4.1481 -		retval = -ENODEV;
  4.1482 -		goto end_init;
  4.1483 -	}
  4.1484 -
  4.1485 -	o_tty = NULL;
  4.1486 -	tp = o_tp = NULL;
  4.1487 -	ltp = o_ltp = NULL;
  4.1488 -
  4.1489 -	tty = alloc_tty_struct();
  4.1490 -	if(!tty)
  4.1491 -		goto fail_no_mem;
  4.1492 -	initialize_tty_struct(tty);
  4.1493 -	tty->driver = driver;
  4.1494 -	tty->index = idx;
  4.1495 -	tty_line_name(driver, idx, tty->name);
  4.1496 -
  4.1497 -	if (driver->flags & TTY_DRIVER_DEVPTS_MEM) {
  4.1498 -		tp_loc = &tty->termios;
  4.1499 -		ltp_loc = &tty->termios_locked;
  4.1500 -	} else {
  4.1501 -		tp_loc = &driver->termios[idx];
  4.1502 -		ltp_loc = &driver->termios_locked[idx];
  4.1503 -	}
  4.1504 -
  4.1505 -	if (!*tp_loc) {
  4.1506 -		tp = (struct termios *) kmalloc(sizeof(struct termios),
  4.1507 -						GFP_KERNEL);
  4.1508 -		if (!tp)
  4.1509 -			goto free_mem_out;
  4.1510 -		*tp = driver->init_termios;
  4.1511 -	}
  4.1512 -
  4.1513 -	if (!*ltp_loc) {
  4.1514 -		ltp = (struct termios *) kmalloc(sizeof(struct termios),
  4.1515 -						 GFP_KERNEL);
  4.1516 -		if (!ltp)
  4.1517 -			goto free_mem_out;
  4.1518 -		memset(ltp, 0, sizeof(struct termios));
  4.1519 -	}
  4.1520 -
  4.1521 -	if (driver->type == TTY_DRIVER_TYPE_PTY) {
  4.1522 -		o_tty = alloc_tty_struct();
  4.1523 -		if (!o_tty)
  4.1524 -			goto free_mem_out;
  4.1525 -		initialize_tty_struct(o_tty);
  4.1526 -		o_tty->driver = driver->other;
  4.1527 -		o_tty->index = idx;
  4.1528 -		tty_line_name(driver->other, idx, o_tty->name);
  4.1529 -
  4.1530 -		if (driver->flags & TTY_DRIVER_DEVPTS_MEM) {
  4.1531 -			o_tp_loc = &o_tty->termios;
  4.1532 -			o_ltp_loc = &o_tty->termios_locked;
  4.1533 -		} else {
  4.1534 -			o_tp_loc = &driver->other->termios[idx];
  4.1535 -			o_ltp_loc = &driver->other->termios_locked[idx];
  4.1536 -		}
  4.1537 -
  4.1538 -		if (!*o_tp_loc) {
  4.1539 -			o_tp = (struct termios *)
  4.1540 -				kmalloc(sizeof(struct termios), GFP_KERNEL);
  4.1541 -			if (!o_tp)
  4.1542 -				goto free_mem_out;
  4.1543 -			*o_tp = driver->other->init_termios;
  4.1544 -		}
  4.1545 -
  4.1546 -		if (!*o_ltp_loc) {
  4.1547 -			o_ltp = (struct termios *)
  4.1548 -				kmalloc(sizeof(struct termios), GFP_KERNEL);
  4.1549 -			if (!o_ltp)
  4.1550 -				goto free_mem_out;
  4.1551 -			memset(o_ltp, 0, sizeof(struct termios));
  4.1552 -		}
  4.1553 -
  4.1554 -		/*
  4.1555 -		 * Everything allocated ... set up the o_tty structure.
  4.1556 -		 */
  4.1557 -		if (!(driver->other->flags & TTY_DRIVER_DEVPTS_MEM)) {
  4.1558 -			driver->other->ttys[idx] = o_tty;
  4.1559 -		}
  4.1560 -		if (!*o_tp_loc)
  4.1561 -			*o_tp_loc = o_tp;
  4.1562 -		if (!*o_ltp_loc)
  4.1563 -			*o_ltp_loc = o_ltp;
  4.1564 -		o_tty->termios = *o_tp_loc;
  4.1565 -		o_tty->termios_locked = *o_ltp_loc;
  4.1566 -		driver->other->refcount++;
  4.1567 -		if (driver->subtype == PTY_TYPE_MASTER)
  4.1568 -			o_tty->count++;
  4.1569 -
  4.1570 -		/* Establish the links in both directions */
  4.1571 -		tty->link   = o_tty;
  4.1572 -		o_tty->link = tty;
  4.1573 -	}
  4.1574 -
  4.1575 -	/* 
  4.1576 -	 * All structures have been allocated, so now we install them.
  4.1577 -	 * Failures after this point use release_mem to clean up, so 
  4.1578 -	 * there's no need to null out the local pointers.
  4.1579 -	 */
  4.1580 -	if (!(driver->flags & TTY_DRIVER_DEVPTS_MEM)) {
  4.1581 -		driver->ttys[idx] = tty;
  4.1582 -	}
  4.1583 -	
  4.1584 -	if (!*tp_loc)
  4.1585 -		*tp_loc = tp;
  4.1586 -	if (!*ltp_loc)
  4.1587 -		*ltp_loc = ltp;
  4.1588 -	tty->termios = *tp_loc;
  4.1589 -	tty->termios_locked = *ltp_loc;
  4.1590 -	driver->refcount++;
  4.1591 -	tty->count++;
  4.1592 -
  4.1593 -	/* 
  4.1594 -	 * Structures all installed ... call the ldisc open routines.
  4.1595 -	 * If we fail here just call release_mem to clean up.  No need
  4.1596 -	 * to decrement the use counts, as release_mem doesn't care.
  4.1597 -	 */
  4.1598 -
  4.1599 -	if (tty->ldisc.open) {
  4.1600 -		retval = (tty->ldisc.open)(tty);
  4.1601 -		if (retval)
  4.1602 -			goto release_mem_out;
  4.1603 -	}
  4.1604 -	if (o_tty && o_tty->ldisc.open) {
  4.1605 -		retval = (o_tty->ldisc.open)(o_tty);
  4.1606 -		if (retval) {
  4.1607 -			if (tty->ldisc.close)
  4.1608 -				(tty->ldisc.close)(tty);
  4.1609 -			goto release_mem_out;
  4.1610 -		}
  4.1611 -		tty_ldisc_enable(o_tty);
  4.1612 -	}
  4.1613 -	tty_ldisc_enable(tty);
  4.1614 -	goto success;
  4.1615 -
  4.1616 -	/*
  4.1617 -	 * This fast open can be used if the tty is already open.
  4.1618 -	 * No memory is allocated, and the only failures are from
  4.1619 -	 * attempting to open a closing tty or attempting multiple
  4.1620 -	 * opens on a pty master.
  4.1621 -	 */
  4.1622 -fast_track:
  4.1623 -	if (test_bit(TTY_CLOSING, &tty->flags)) {
  4.1624 -		retval = -EIO;
  4.1625 -		goto end_init;
  4.1626 -	}
  4.1627 -	if (driver->type == TTY_DRIVER_TYPE_PTY &&
  4.1628 -	    driver->subtype == PTY_TYPE_MASTER) {
  4.1629 -		/*
  4.1630 -		 * special case for PTY masters: only one open permitted, 
  4.1631 -		 * and the slave side open count is incremented as well.
  4.1632 -		 */
  4.1633 -		if (tty->count) {
  4.1634 -			retval = -EIO;
  4.1635 -			goto end_init;
  4.1636 -		}
  4.1637 -		tty->link->count++;
  4.1638 -	}
  4.1639 -	tty->count++;
  4.1640 -	tty->driver = driver; /* N.B. why do this every time?? */
  4.1641 -
  4.1642 -	/* FIXME */
  4.1643 -	if(!test_bit(TTY_LDISC, &tty->flags))
  4.1644 -		printk(KERN_ERR "init_dev but no ldisc\n");
  4.1645 -success:
  4.1646 -	*ret_tty = tty;
  4.1647 -	
  4.1648 -	/* All paths come through here to release the semaphore */
  4.1649 -end_init:
  4.1650 -	return retval;
  4.1651 -
  4.1652 -	/* Release locally allocated memory ... nothing placed in slots */
  4.1653 -free_mem_out:
  4.1654 -	kfree(o_tp);
  4.1655 -	if (o_tty)
  4.1656 -		free_tty_struct(o_tty);
  4.1657 -	kfree(ltp);
  4.1658 -	kfree(tp);
  4.1659 -	free_tty_struct(tty);
  4.1660 -
  4.1661 -fail_no_mem:
  4.1662 -	module_put(driver->owner);
  4.1663 -	retval = -ENOMEM;
  4.1664 -	goto end_init;
  4.1665 -
  4.1666 -	/* call the tty release_mem routine to clean out this slot */
  4.1667 -release_mem_out:
  4.1668 -	printk(KERN_INFO "init_dev: ldisc open failed, "
  4.1669 -			 "clearing slot %d\n", idx);
  4.1670 -	release_mem(tty, idx);
  4.1671 -	goto end_init;
  4.1672 -}
  4.1673 -
  4.1674 -/*
  4.1675 - * Releases memory associated with a tty structure, and clears out the
  4.1676 - * driver table slots.
  4.1677 - */
  4.1678 -static void release_mem(struct tty_struct *tty, int idx)
  4.1679 -{
  4.1680 -	struct tty_struct *o_tty;
  4.1681 -	struct termios *tp;
  4.1682 -	int devpts = tty->driver->flags & TTY_DRIVER_DEVPTS_MEM;
  4.1683 -
  4.1684 -	if ((o_tty = tty->link) != NULL) {
  4.1685 -		if (!devpts)
  4.1686 -			o_tty->driver->ttys[idx] = NULL;
  4.1687 -		if (o_tty->driver->flags & TTY_DRIVER_RESET_TERMIOS) {
  4.1688 -			tp = o_tty->termios;
  4.1689 -			if (!devpts)
  4.1690 -				o_tty->driver->termios[idx] = NULL;
  4.1691 -			kfree(tp);
  4.1692 -
  4.1693 -			tp = o_tty->termios_locked;
  4.1694 -			if (!devpts)
  4.1695 -				o_tty->driver->termios_locked[idx] = NULL;
  4.1696 -			kfree(tp);
  4.1697 -		}
  4.1698 -		o_tty->magic = 0;
  4.1699 -		o_tty->driver->refcount--;
  4.1700 -		file_list_lock();
  4.1701 -		list_del_init(&o_tty->tty_files);
  4.1702 -		file_list_unlock();
  4.1703 -		free_tty_struct(o_tty);
  4.1704 -	}
  4.1705 -
  4.1706 -	if (!devpts)
  4.1707 -		tty->driver->ttys[idx] = NULL;
  4.1708 -	if (tty->driver->flags & TTY_DRIVER_RESET_TERMIOS) {
  4.1709 -		tp = tty->termios;
  4.1710 -		if (!devpts)
  4.1711 -			tty->driver->termios[idx] = NULL;
  4.1712 -		kfree(tp);
  4.1713 -
  4.1714 -		tp = tty->termios_locked;
  4.1715 -		if (!devpts)
  4.1716 -			tty->driver->termios_locked[idx] = NULL;
  4.1717 -		kfree(tp);
  4.1718 -	}
  4.1719 -
  4.1720 -	tty->magic = 0;
  4.1721 -	tty->driver->refcount--;
  4.1722 -	file_list_lock();
  4.1723 -	list_del_init(&tty->tty_files);
  4.1724 -	file_list_unlock();
  4.1725 -	module_put(tty->driver->owner);
  4.1726 -	free_tty_struct(tty);
  4.1727 -}
  4.1728 -
  4.1729 -/*
  4.1730 - * Even releasing the tty structures is a tricky business.. We have
  4.1731 - * to be very careful that the structures are all released at the
  4.1732 - * same time, as interrupts might otherwise get the wrong pointers.
  4.1733 - *
  4.1734 - * WSH 09/09/97: rewritten to avoid some nasty race conditions that could
  4.1735 - * lead to double frees or releasing memory still in use.
  4.1736 - */
  4.1737 -static void release_dev(struct file * filp)
  4.1738 -{
  4.1739 -	struct tty_struct *tty, *o_tty;
  4.1740 -	int	pty_master, tty_closing, o_tty_closing, do_sleep;
  4.1741 -	int	devpts_master, devpts;
  4.1742 -	int	idx;
  4.1743 -	char	buf[64];
  4.1744 -	unsigned long flags;
  4.1745 -	
  4.1746 -	tty = (struct tty_struct *)filp->private_data;
  4.1747 -	if (tty_paranoia_check(tty, filp->f_dentry->d_inode, "release_dev"))
  4.1748 -		return;
  4.1749 -
  4.1750 -	check_tty_count(tty, "release_dev");
  4.1751 -
  4.1752 -	tty_fasync(-1, filp, 0);
  4.1753 -
  4.1754 -	idx = tty->index;
  4.1755 -	pty_master = (tty->driver->type == TTY_DRIVER_TYPE_PTY &&
  4.1756 -		      tty->driver->subtype == PTY_TYPE_MASTER);
  4.1757 -	devpts = (tty->driver->flags & TTY_DRIVER_DEVPTS_MEM) != 0;
  4.1758 -	devpts_master = pty_master && devpts;
  4.1759 -	o_tty = tty->link;
  4.1760 -
  4.1761 -#ifdef TTY_PARANOIA_CHECK
  4.1762 -	if (idx < 0 || idx >= tty->driver->num) {
  4.1763 -		printk(KERN_DEBUG "release_dev: bad idx when trying to "
  4.1764 -				  "free (%s)\n", tty->name);
  4.1765 -		return;
  4.1766 -	}
  4.1767 -	if (!(tty->driver->flags & TTY_DRIVER_DEVPTS_MEM)) {
  4.1768 -		if (tty != tty->driver->ttys[idx]) {
  4.1769 -			printk(KERN_DEBUG "release_dev: driver.table[%d] not tty "
  4.1770 -			       "for (%s)\n", idx, tty->name);
  4.1771 -			return;
  4.1772 -		}
  4.1773 -		if (tty->termios != tty->driver->termios[idx]) {
  4.1774 -			printk(KERN_DEBUG "release_dev: driver.termios[%d] not termios "
  4.1775 -			       "for (%s)\n",
  4.1776 -			       idx, tty->name);
  4.1777 -			return;
  4.1778 -		}
  4.1779 -		if (tty->termios_locked != tty->driver->termios_locked[idx]) {
  4.1780 -			printk(KERN_DEBUG "release_dev: driver.termios_locked[%d] not "
  4.1781 -			       "termios_locked for (%s)\n",
  4.1782 -			       idx, tty->name);
  4.1783 -			return;
  4.1784 -		}
  4.1785 -	}
  4.1786 -#endif
  4.1787 -
  4.1788 -#ifdef TTY_DEBUG_HANGUP
  4.1789 -	printk(KERN_DEBUG "release_dev of %s (tty count=%d)...",
  4.1790 -	       tty_name(tty, buf), tty->count);
  4.1791 -#endif
  4.1792 -
  4.1793 -#ifdef TTY_PARANOIA_CHECK
  4.1794 -	if (tty->driver->other &&
  4.1795 -	     !(tty->driver->flags & TTY_DRIVER_DEVPTS_MEM)) {
  4.1796 -		if (o_tty != tty->driver->other->ttys[idx]) {
  4.1797 -			printk(KERN_DEBUG "release_dev: other->table[%d] "
  4.1798 -					  "not o_tty for (%s)\n",
  4.1799 -			       idx, tty->name);
  4.1800 -			return;
  4.1801 -		}
  4.1802 -		if (o_tty->termios != tty->driver->other->termios[idx]) {
  4.1803 -			printk(KERN_DEBUG "release_dev: other->termios[%d] "
  4.1804 -					  "not o_termios for (%s)\n",
  4.1805 -			       idx, tty->name);
  4.1806 -			return;
  4.1807 -		}
  4.1808 -		if (o_tty->termios_locked != 
  4.1809 -		      tty->driver->other->termios_locked[idx]) {
  4.1810 -			printk(KERN_DEBUG "release_dev: other->termios_locked["
  4.1811 -					  "%d] not o_termios_locked for (%s)\n",
  4.1812 -			       idx, tty->name);
  4.1813 -			return;
  4.1814 -		}
  4.1815 -		if (o_tty->link != tty) {
  4.1816 -			printk(KERN_DEBUG "release_dev: bad pty pointers\n");
  4.1817 -			return;
  4.1818 -		}
  4.1819 -	}
  4.1820 -#endif
  4.1821 -	if (tty->driver->close)
  4.1822 -		tty->driver->close(tty, filp);
  4.1823 -
  4.1824 -	/*
  4.1825 -	 * Sanity check: if tty->count is going to zero, there shouldn't be
  4.1826 -	 * any waiters on tty->read_wait or tty->write_wait.  We test the
  4.1827 -	 * wait queues and kick everyone out _before_ actually starting to
  4.1828 -	 * close.  This ensures that we won't block while releasing the tty
  4.1829 -	 * structure.
  4.1830 -	 *
  4.1831 -	 * The test for the o_tty closing is necessary, since the master and
  4.1832 -	 * slave sides may close in any order.  If the slave side closes out
  4.1833 -	 * first, its count will be one, since the master side holds an open.
  4.1834 -	 * Thus this test wouldn't be triggered at the time the slave closes,
  4.1835 -	 * so we do it now.
  4.1836 -	 *
  4.1837 -	 * Note that it's possible for the tty to be opened again while we're
  4.1838 -	 * flushing out waiters.  By recalculating the closing flags before
  4.1839 -	 * each iteration we avoid any problems.
  4.1840 -	 */
  4.1841 -	while (1) {
  4.1842 -		/* Guard against races with tty->count changes elsewhere and
  4.1843 -		   opens on /dev/tty */
  4.1844 -		   
  4.1845 -		down(&tty_sem);
  4.1846 -		tty_closing = tty->count <= 1;
  4.1847 -		o_tty_closing = o_tty &&
  4.1848 -			(o_tty->count <= (pty_master ? 1 : 0));
  4.1849 -		do_sleep = 0;
  4.1850 -
  4.1851 -		if (tty_closing) {
  4.1852 -			if (waitqueue_active(&tty->read_wait)) {
  4.1853 -				wake_up(&tty->read_wait);
  4.1854 -				do_sleep++;
  4.1855 -			}
  4.1856 -			if (waitqueue_active(&tty->write_wait)) {
  4.1857 -				wake_up(&tty->write_wait);
  4.1858 -				do_sleep++;
  4.1859 -			}
  4.1860 -		}
  4.1861 -		if (o_tty_closing) {
  4.1862 -			if (waitqueue_active(&o_tty->read_wait)) {
  4.1863 -				wake_up(&o_tty->read_wait);
  4.1864 -				do_sleep++;
  4.1865 -			}
  4.1866 -			if (waitqueue_active(&o_tty->write_wait)) {
  4.1867 -				wake_up(&o_tty->write_wait);
  4.1868 -				do_sleep++;
  4.1869 -			}
  4.1870 -		}
  4.1871 -		if (!do_sleep)
  4.1872 -			break;
  4.1873 -
  4.1874 -		printk(KERN_WARNING "release_dev: %s: read/write wait queue "
  4.1875 -				    "active!\n", tty_name(tty, buf));
  4.1876 -		up(&tty_sem);
  4.1877 -		schedule();
  4.1878 -	}	
  4.1879 -
  4.1880 -	/*
  4.1881 -	 * The closing flags are now consistent with the open counts on 
  4.1882 -	 * both sides, and we've completed the last operation that could 
  4.1883 -	 * block, so it's safe to proceed with closing.
  4.1884 -	 */
  4.1885 -	if (pty_master) {
  4.1886 -		if (--o_tty->count < 0) {
  4.1887 -			printk(KERN_WARNING "release_dev: bad pty slave count "
  4.1888 -					    "(%d) for %s\n",
  4.1889 -			       o_tty->count, tty_name(o_tty, buf));
  4.1890 -			o_tty->count = 0;
  4.1891 -		}
  4.1892 -	}
  4.1893 -	if (--tty->count < 0) {
  4.1894 -		printk(KERN_WARNING "release_dev: bad tty->count (%d) for %s\n",
  4.1895 -		       tty->count, tty_name(tty, buf));
  4.1896 -		tty->count = 0;
  4.1897 -	}
  4.1898 -	
  4.1899 -	/*
  4.1900 -	 * We've decremented tty->count, so we need to remove this file
  4.1901 -	 * descriptor off the tty->tty_files list; this serves two
  4.1902 -	 * purposes:
  4.1903 -	 *  - check_tty_count sees the correct number of file descriptors
  4.1904 -	 *    associated with this tty.
  4.1905 -	 *  - do_tty_hangup no longer sees this file descriptor as
  4.1906 -	 *    something that needs to be handled for hangups.
  4.1907 -	 */
  4.1908 -	file_kill(filp);
  4.1909 -	filp->private_data = NULL;
  4.1910 -
  4.1911 -	/*
  4.1912 -	 * Perform some housekeeping before deciding whether to return.
  4.1913 -	 *
  4.1914 -	 * Set the TTY_CLOSING flag if this was the last open.  In the
  4.1915 -	 * case of a pty we may have to wait around for the other side
  4.1916 -	 * to close, and TTY_CLOSING makes sure we can't be reopened.
  4.1917 -	 */
  4.1918 -	if(tty_closing)
  4.1919 -		set_bit(TTY_CLOSING, &tty->flags);
  4.1920 -	if(o_tty_closing)
  4.1921 -		set_bit(TTY_CLOSING, &o_tty->flags);
  4.1922 -
  4.1923 -	/*
  4.1924 -	 * If _either_ side is closing, make sure there aren't any
  4.1925 -	 * processes that still think tty or o_tty is their controlling
  4.1926 -	 * tty.
  4.1927 -	 */
  4.1928 -	if (tty_closing || o_tty_closing) {
  4.1929 -		struct task_struct *p;
  4.1930 -
  4.1931 -		read_lock(&tasklist_lock);
  4.1932 -		do_each_task_pid(tty->session, PIDTYPE_SID, p) {
  4.1933 -			p->signal->tty = NULL;
  4.1934 -		} while_each_task_pid(tty->session, PIDTYPE_SID, p);
  4.1935 -		if (o_tty)
  4.1936 -			do_each_task_pid(o_tty->session, PIDTYPE_SID, p) {
  4.1937 -				p->signal->tty = NULL;
  4.1938 -			} while_each_task_pid(o_tty->session, PIDTYPE_SID, p);
  4.1939 -		read_unlock(&tasklist_lock);
  4.1940 -	}
  4.1941 -
  4.1942 -	up(&tty_sem);
  4.1943 -
  4.1944 -	/* check whether both sides are closing ... */
  4.1945 -	if (!tty_closing || (o_tty && !o_tty_closing))
  4.1946 -		return;
  4.1947 -	
  4.1948 -#ifdef TTY_DEBUG_HANGUP
  4.1949 -	printk(KERN_DEBUG "freeing tty structure...");
  4.1950 -#endif
  4.1951 -	/*
  4.1952 -	 * Prevent flush_to_ldisc() from rescheduling the work for later.  Then
  4.1953 -	 * kill any delayed work. As this is the final close it does not
  4.1954 -	 * race with the set_ldisc code path.
  4.1955 -	 */
  4.1956 -	clear_bit(TTY_LDISC, &tty->flags);
  4.1957 -	clear_bit(TTY_DONT_FLIP, &tty->flags);
  4.1958 -	cancel_delayed_work(&tty->buf.work);
  4.1959 -
  4.1960 -	/*
  4.1961 -	 * Wait for ->hangup_work and ->buf.work handlers to terminate
  4.1962 -	 */
  4.1963 -	 
  4.1964 -	flush_scheduled_work();
  4.1965 -	
  4.1966 -	/*
  4.1967 -	 * Wait for any short term users (we know they are just driver
  4.1968 -	 * side waiters as the file is closing so user count on the file
  4.1969 -	 * side is zero.
  4.1970 -	 */
  4.1971 -	spin_lock_irqsave(&tty_ldisc_lock, flags);
  4.1972 -	while(tty->ldisc.refcount)
  4.1973 -	{
  4.1974 -		spin_unlock_irqrestore(&tty_ldisc_lock, flags);
  4.1975 -		wait_event(tty_ldisc_wait, tty->ldisc.refcount == 0);
  4.1976 -		spin_lock_irqsave(&tty_ldisc_lock, flags);
  4.1977 -	}
  4.1978 -	spin_unlock_irqrestore(&tty_ldisc_lock, flags);
  4.1979 -	/*
  4.1980 -	 * Shutdown the current line discipline, and reset it to N_TTY.
  4.1981 -	 * N.B. why reset ldisc when we're releasing the memory??
  4.1982 -	 *
  4.1983 -	 * FIXME: this MUST get fixed for the new reflocking
  4.1984 -	 */
  4.1985 -	if (tty->ldisc.close)
  4.1986 -		(tty->ldisc.close)(tty);
  4.1987 -	tty_ldisc_put(tty->ldisc.num);
  4.1988 -	
  4.1989 -	/*
  4.1990 -	 *	Switch the line discipline back
  4.1991 -	 */
  4.1992 -	tty_ldisc_assign(tty, tty_ldisc_get(N_TTY));
  4.1993 -	tty_set_termios_ldisc(tty,N_TTY); 
  4.1994 -	if (o_tty) {
  4.1995 -		/* FIXME: could o_tty be in setldisc here ? */
  4.1996 -		clear_bit(TTY_LDISC, &o_tty->flags);
  4.1997 -		if (o_tty->ldisc.close)
  4.1998 -			(o_tty->ldisc.close)(o_tty);
  4.1999 -		tty_ldisc_put(o_tty->ldisc.num);
  4.2000 -		tty_ldisc_assign(o_tty, tty_ldisc_get(N_TTY));
  4.2001 -		tty_set_termios_ldisc(o_tty,N_TTY); 
  4.2002 -	}
  4.2003 -	/*
  4.2004 -	 * The release_mem function takes care of the details of clearing
  4.2005 -	 * the slots and preserving the termios structure.
  4.2006 -	 */
  4.2007 -	release_mem(tty, idx);
  4.2008 -
  4.2009 -#ifdef CONFIG_UNIX98_PTYS
  4.2010 -	/* Make this pty number available for reallocation */
  4.2011 -	if (devpts) {
  4.2012 -		down(&allocated_ptys_lock);
  4.2013 -		idr_remove(&allocated_ptys, idx);
  4.2014 -		up(&allocated_ptys_lock);
  4.2015 -	}
  4.2016 -#endif
  4.2017 -
  4.2018 -}
  4.2019 -
  4.2020 -/*
  4.2021 - * tty_open and tty_release keep up the tty count that contains the
  4.2022 - * number of opens done on a tty. We cannot use the inode-count, as
  4.2023 - * different inodes might point to the same tty.
  4.2024 - *
  4.2025 - * Open-counting is needed for pty masters, as well as for keeping
  4.2026 - * track of serial lines: DTR is dropped when the last close happens.
  4.2027 - * (This is not done solely through tty->count, now.  - Ted 1/27/92)
  4.2028 - *
  4.2029 - * The termios state of a pty is reset on first open so that
  4.2030 - * settings don't persist across reuse.
  4.2031 - */
  4.2032 -static int tty_open(struct inode * inode, struct file * filp)
  4.2033 -{
  4.2034 -	struct tty_struct *tty;
  4.2035 -	int noctty, retval;
  4.2036 -	struct tty_driver *driver;
  4.2037 -	int index;
  4.2038 -	dev_t device = inode->i_rdev;
  4.2039 -	unsigned short saved_flags = filp->f_flags;
  4.2040 -
  4.2041 -	nonseekable_open(inode, filp);
  4.2042 -	
  4.2043 -retry_open:
  4.2044 -	noctty = filp->f_flags & O_NOCTTY;
  4.2045 -	index  = -1;
  4.2046 -	retval = 0;
  4.2047 -	
  4.2048 -	down(&tty_sem);
  4.2049 -
  4.2050 -	if (device == MKDEV(TTYAUX_MAJOR,0)) {
  4.2051 -		if (!current->signal->tty) {
  4.2052 -			up(&tty_sem);
  4.2053 -			return -ENXIO;
  4.2054 -		}
  4.2055 -		driver = current->signal->tty->driver;
  4.2056 -		index = current->signal->tty->index;
  4.2057 -		filp->f_flags |= O_NONBLOCK; /* Don't let /dev/tty block */
  4.2058 -		/* noctty = 1; */
  4.2059 -		goto got_driver;
  4.2060 -	}
  4.2061 -#ifdef CONFIG_VT
  4.2062 -	if (console_use_vt && (device == MKDEV(TTY_MAJOR,0))) {
  4.2063 -		extern struct tty_driver *console_driver;
  4.2064 -		driver = console_driver;
  4.2065 -		index = fg_console;
  4.2066 -		noctty = 1;
  4.2067 -		goto got_driver;
  4.2068 -	}
  4.2069 -#endif
  4.2070 -	if (device == MKDEV(TTYAUX_MAJOR,1)) {
  4.2071 -		driver = console_device(&index);
  4.2072 -		if (driver) {
  4.2073 -			/* Don't let /dev/console block */
  4.2074 -			filp->f_flags |= O_NONBLOCK;
  4.2075 -			noctty = 1;
  4.2076 -			goto got_driver;
  4.2077 -		}
  4.2078 -		up(&tty_sem);
  4.2079 -		return -ENODEV;
  4.2080 -	}
  4.2081 -
  4.2082 -	driver = get_tty_driver(device, &index);
  4.2083 -	if (!driver) {
  4.2084 -		up(&tty_sem);
  4.2085 -		return -ENODEV;
  4.2086 -	}
  4.2087 -got_driver:
  4.2088 -	retval = init_dev(driver, index, &tty);
  4.2089 -	up(&tty_sem);
  4.2090 -	if (retval)
  4.2091 -		return retval;
  4.2092 -
  4.2093 -	filp->private_data = tty;
  4.2094 -	file_move(filp, &tty->tty_files);
  4.2095 -	check_tty_count(tty, "tty_open");
  4.2096 -	if (tty->driver->type == TTY_DRIVER_TYPE_PTY &&
  4.2097 -	    tty->driver->subtype == PTY_TYPE_MASTER)
  4.2098 -		noctty = 1;
  4.2099 -#ifdef TTY_DEBUG_HANGUP
  4.2100 -	printk(KERN_DEBUG "opening %s...", tty->name);
  4.2101 -#endif
  4.2102 -	if (!retval) {
  4.2103 -		if (tty->driver->open)
  4.2104 -			retval = tty->driver->open(tty, filp);
  4.2105 -		else
  4.2106 -			retval = -ENODEV;
  4.2107 -	}
  4.2108 -	filp->f_flags = saved_flags;
  4.2109 -
  4.2110 -	if (!retval && test_bit(TTY_EXCLUSIVE, &tty->flags) && !capable(CAP_SYS_ADMIN))
  4.2111 -		retval = -EBUSY;
  4.2112 -
  4.2113 -	if (retval) {
  4.2114 -#ifdef TTY_DEBUG_HANGUP
  4.2115 -		printk(KERN_DEBUG "error %d in opening %s...", retval,
  4.2116 -		       tty->name);
  4.2117 -#endif
  4.2118 -		release_dev(filp);
  4.2119 -		if (retval != -ERESTARTSYS)
  4.2120 -			return retval;
  4.2121 -		if (signal_pending(current))
  4.2122 -			return retval;
  4.2123 -		schedule();
  4.2124 -		/*
  4.2125 -		 * Need to reset f_op in case a hangup happened.
  4.2126 -		 */
  4.2127 -		if (filp->f_op == &hung_up_tty_fops)
  4.2128 -			filp->f_op = &tty_fops;
  4.2129 -		goto retry_open;
  4.2130 -	}
  4.2131 -	if (!noctty &&
  4.2132 -	    current->signal->leader &&
  4.2133 -	    !current->signal->tty &&
  4.2134 -	    tty->session == 0) {
  4.2135 -	    	task_lock(current);
  4.2136 -		current->signal->tty = tty;
  4.2137 -		task_unlock(current);
  4.2138 -		current->signal->tty_old_pgrp = 0;
  4.2139 -		tty->session = current->signal->session;
  4.2140 -		tty->pgrp = process_group(current);
  4.2141 -	}
  4.2142 -	return 0;
  4.2143 -}
  4.2144 -
  4.2145 -#ifdef CONFIG_UNIX98_PTYS
  4.2146 -static int ptmx_open(struct inode * inode, struct file * filp)
  4.2147 -{
  4.2148 -	struct tty_struct *tty;
  4.2149 -	int retval;
  4.2150 -	int index;
  4.2151 -	int idr_ret;
  4.2152 -
  4.2153 -	nonseekable_open(inode, filp);
  4.2154 -
  4.2155 -	/* find a device that is not in use. */
  4.2156 -	down(&allocated_ptys_lock);
  4.2157 -	if (!idr_pre_get(&allocated_ptys, GFP_KERNEL)) {
  4.2158 -		up(&allocated_ptys_lock);
  4.2159 -		return -ENOMEM;
  4.2160 -	}
  4.2161 -	idr_ret = idr_get_new(&allocated_ptys, NULL, &index);
  4.2162 -	if (idr_ret < 0) {
  4.2163 -		up(&allocated_ptys_lock);
  4.2164 -		if (idr_ret == -EAGAIN)
  4.2165 -			return -ENOMEM;
  4.2166 -		return -EIO;
  4.2167 -	}
  4.2168 -	if (index >= pty_limit) {
  4.2169 -		idr_remove(&allocated_ptys, index);
  4.2170 -		up(&allocated_ptys_lock);
  4.2171 -		return -EIO;
  4.2172 -	}
  4.2173 -	up(&allocated_ptys_lock);
  4.2174 -
  4.2175 -	down(&tty_sem);
  4.2176 -	retval = init_dev(ptm_driver, index, &tty);
  4.2177 -	up(&tty_sem);
  4.2178 -	
  4.2179 -	if (retval)
  4.2180 -		goto out;
  4.2181 -
  4.2182 -	set_bit(TTY_PTY_LOCK, &tty->flags); /* LOCK THE SLAVE */
  4.2183 -	filp->private_data = tty;
  4.2184 -	file_move(filp, &tty->tty_files);
  4.2185 -
  4.2186 -	retval = -ENOMEM;
  4.2187 -	if (devpts_pty_new(tty->link))
  4.2188 -		goto out1;
  4.2189 -
  4.2190 -	check_tty_count(tty, "tty_open");
  4.2191 -	retval = ptm_driver->open(tty, filp);
  4.2192 -	if (!retval)
  4.2193 -		return 0;
  4.2194 -out1:
  4.2195 -	release_dev(filp);
  4.2196 -out:
  4.2197 -	down(&allocated_ptys_lock);
  4.2198 -	idr_remove(&allocated_ptys, index);
  4.2199 -	up(&allocated_ptys_lock);
  4.2200 -	return retval;
  4.2201 -}
  4.2202 -#endif
  4.2203 -
  4.2204 -static int tty_release(struct inode * inode, struct file * filp)
  4.2205 -{
  4.2206 -	lock_kernel();
  4.2207 -	release_dev(filp);
  4.2208 -	unlock_kernel();
  4.2209 -	return 0;
  4.2210 -}
  4.2211 -
  4.2212 -/* No kernel lock held - fine */
  4.2213 -static unsigned int tty_poll(struct file * filp, poll_table * wait)
  4.2214 -{
  4.2215 -	struct tty_struct * tty;
  4.2216 -	struct tty_ldisc *ld;
  4.2217 -	int ret = 0;
  4.2218 -
  4.2219 -	tty = (struct tty_struct *)filp->private_data;
  4.2220 -	if (tty_paranoia_check(tty, filp->f_dentry->d_inode, "tty_poll"))
  4.2221 -		return 0;
  4.2222 -		
  4.2223 -	ld = tty_ldisc_ref_wait(tty);
  4.2224 -	if (ld->poll)
  4.2225 -		ret = (ld->poll)(tty, filp, wait);
  4.2226 -	tty_ldisc_deref(ld);
  4.2227 -	return ret;
  4.2228 -}
  4.2229 -
  4.2230 -static int tty_fasync(int fd, struct file * filp, int on)
  4.2231 -{
  4.2232 -	struct tty_struct * tty;
  4.2233 -	int retval;
  4.2234 -
  4.2235 -	tty = (struct tty_struct *)filp->private_data;
  4.2236 -	if (tty_paranoia_check(tty, filp->f_dentry->d_inode, "tty_fasync"))
  4.2237 -		return 0;
  4.2238 -	
  4.2239 -	retval = fasync_helper(fd, filp, on, &tty->fasync);
  4.2240 -	if (retval <= 0)
  4.2241 -		return retval;
  4.2242 -
  4.2243 -	if (on) {
  4.2244 -		if (!waitqueue_active(&tty->read_wait))
  4.2245 -			tty->minimum_to_wake = 1;
  4.2246 -		retval = f_setown(filp, (-tty->pgrp) ? : current->pid, 0);
  4.2247 -		if (retval)
  4.2248 -			return retval;
  4.2249 -	} else {
  4.2250 -		if (!tty->fasync && !waitqueue_active(&tty->read_wait))
  4.2251 -			tty->minimum_to_wake = N_TTY_BUF_SIZE;
  4.2252 -	}
  4.2253 -	return 0;
  4.2254 -}
  4.2255 -
  4.2256 -static int tiocsti(struct tty_struct *tty, char __user *p)
  4.2257 -{
  4.2258 -	char ch, mbz = 0;
  4.2259 -	struct tty_ldisc *ld;
  4.2260 -	
  4.2261 -	if ((current->signal->tty != tty) && !capable(CAP_SYS_ADMIN))
  4.2262 -		return -EPERM;
  4.2263 -	if (get_user(ch, p))
  4.2264 -		return -EFAULT;
  4.2265 -	ld = tty_ldisc_ref_wait(tty);
  4.2266 -	ld->receive_buf(tty, &ch, &mbz, 1);
  4.2267 -	tty_ldisc_deref(ld);
  4.2268 -	return 0;
  4.2269 -}
  4.2270 -
  4.2271 -static int tiocgwinsz(struct tty_struct *tty, struct winsize __user * arg)
  4.2272 -{
  4.2273 -	if (copy_to_user(arg, &tty->winsize, sizeof(*arg)))
  4.2274 -		return -EFAULT;
  4.2275 -	return 0;
  4.2276 -}
  4.2277 -
  4.2278 -static int tiocswinsz(struct tty_struct *tty, struct tty_struct *real_tty,
  4.2279 -	struct winsize __user * arg)
  4.2280 -{
  4.2281 -	struct winsize tmp_ws;
  4.2282 -
  4.2283 -	if (copy_from_user(&tmp_ws, arg, sizeof(*arg)))
  4.2284 -		return -EFAULT;
  4.2285 -	if (!memcmp(&tmp_ws, &tty->winsize, sizeof(*arg)))
  4.2286 -		return 0;
  4.2287 -#ifdef CONFIG_VT
  4.2288 -	if (tty->driver->type == TTY_DRIVER_TYPE_CONSOLE) {
  4.2289 -		int rc;
  4.2290 -
  4.2291 -		acquire_console_sem();
  4.2292 -		rc = vc_resize(tty->driver_data, tmp_ws.ws_col, tmp_ws.ws_row);
  4.2293 -		release_console_sem();
  4.2294 -		if (rc)
  4.2295 -			return -ENXIO;
  4.2296 -	}
  4.2297 -#endif
  4.2298 -	if (tty->pgrp > 0)
  4.2299 -		kill_pg(tty->pgrp, SIGWINCH, 1);
  4.2300 -	if ((real_tty->pgrp != tty->pgrp) && (real_tty->pgrp > 0))
  4.2301 -		kill_pg(real_tty->pgrp, SIGWINCH, 1);
  4.2302 -	tty->winsize = tmp_ws;
  4.2303 -	real_tty->winsize = tmp_ws;
  4.2304 -	return 0;
  4.2305 -}
  4.2306 -
  4.2307 -static int tioccons(struct file *file)
  4.2308 -{
  4.2309 -	if (!capable(CAP_SYS_ADMIN))
  4.2310 -		return -EPERM;
  4.2311 -	if (file->f_op->write == redirected_tty_write) {
  4.2312 -		struct file *f;
  4.2313 -		spin_lock(&redirect_lock);
  4.2314 -		f = redirect;
  4.2315 -		redirect = NULL;
  4.2316 -		spin_unlock(&redirect_lock);
  4.2317 -		if (f)
  4.2318 -			fput(f);
  4.2319 -		return 0;
  4.2320 -	}
  4.2321 -	spin_lock(&redirect_lock);
  4.2322 -	if (redirect) {
  4.2323 -		spin_unlock(&redirect_lock);
  4.2324 -		return -EBUSY;
  4.2325 -	}
  4.2326 -	get_file(file);
  4.2327 -	redirect = file;
  4.2328 -	spin_unlock(&redirect_lock);
  4.2329 -	return 0;
  4.2330 -}
  4.2331 -
  4.2332 -
  4.2333 -static int fionbio(struct file *file, int __user *p)
  4.2334 -{
  4.2335 -	int nonblock;
  4.2336 -
  4.2337 -	if (get_user(nonblock, p))
  4.2338 -		return -EFAULT;
  4.2339 -
  4.2340 -	if (nonblock)
  4.2341 -		file->f_flags |= O_NONBLOCK;
  4.2342 -	else
  4.2343 -		file->f_flags &= ~O_NONBLOCK;
  4.2344 -	return 0;
  4.2345 -}
  4.2346 -
  4.2347 -static int tiocsctty(struct tty_struct *tty, int arg)
  4.2348 -{
  4.2349 -	task_t *p;
  4.2350 -
  4.2351 -	if (current->signal->leader &&
  4.2352 -	    (current->signal->session == tty->session))
  4.2353 -		return 0;
  4.2354 -	/*
  4.2355 -	 * The process must be a session leader and
  4.2356 -	 * not have a controlling tty already.
  4.2357 -	 */
  4.2358 -	if (!current->signal->leader || current->signal->tty)
  4.2359 -		return -EPERM;
  4.2360 -	if (tty->session > 0) {
  4.2361 -		/*
  4.2362 -		 * This tty is already the controlling
  4.2363 -		 * tty for another session group!
  4.2364 -		 */
  4.2365 -		if ((arg == 1) && capable(CAP_SYS_ADMIN)) {
  4.2366 -			/*
  4.2367 -			 * Steal it away
  4.2368 -			 */
  4.2369 -
  4.2370 -			read_lock(&tasklist_lock);
  4.2371 -			do_each_task_pid(tty->session, PIDTYPE_SID, p) {
  4.2372 -				p->signal->tty = NULL;
  4.2373 -			} while_each_task_pid(tty->session, PIDTYPE_SID, p);
  4.2374 -			read_unlock(&tasklist_lock);
  4.2375 -		} else
  4.2376 -			return -EPERM;
  4.2377 -	}
  4.2378 -	task_lock(current);
  4.2379 -	current->signal->tty = tty;
  4.2380 -	task_unlock(current);
  4.2381 -	current->signal->tty_old_pgrp = 0;
  4.2382 -	tty->session = current->signal->session;
  4.2383 -	tty->pgrp = process_group(current);
  4.2384 -	return 0;
  4.2385 -}
  4.2386 -
  4.2387 -static int tiocgpgrp(struct tty_struct *tty, struct tty_struct *real_tty, pid_t __user *p)
  4.2388 -{
  4.2389 -	/*
  4.2390 -	 * (tty == real_tty) is a cheap way of
  4.2391 -	 * testing if the tty is NOT a master pty.
  4.2392 -	 */
  4.2393 -	if (tty == real_tty && current->signal->tty != real_tty)
  4.2394 -		return -ENOTTY;
  4.2395 -	return put_user(real_tty->pgrp, p);
  4.2396 -}
  4.2397 -
  4.2398 -static int tiocspgrp(struct tty_struct *tty, struct tty_struct *real_tty, pid_t __user *p)
  4.2399 -{
  4.2400 -	pid_t pgrp;
  4.2401 -	int retval = tty_check_change(real_tty);
  4.2402 -
  4.2403 -	if (retval == -EIO)
  4.2404 -		return -ENOTTY;
  4.2405 -	if (retval)
  4.2406 -		return retval;
  4.2407 -	if (!current->signal->tty ||
  4.2408 -	    (current->signal->tty != real_tty) ||
  4.2409 -	    (real_tty->session != current->signal->session))
  4.2410 -		return -ENOTTY;
  4.2411 -	if (get_user(pgrp, p))
  4.2412 -		return -EFAULT;
  4.2413 -	if (pgrp < 0)
  4.2414 -		return -EINVAL;
  4.2415 -	if (session_of_pgrp(pgrp) != current->signal->session)
  4.2416 -		return -EPERM;
  4.2417 -	real_tty->pgrp = pgrp;
  4.2418 -	return 0;
  4.2419 -}
  4.2420 -
  4.2421 -static int tiocgsid(struct tty_struct *tty, struct tty_struct *real_tty, pid_t __user *p)
  4.2422 -{
  4.2423 -	/*
  4.2424 -	 * (tty == real_tty) is a cheap way of
  4.2425 -	 * testing if the tty is NOT a master pty.
  4.2426 -	*/
  4.2427 -	if (tty == real_tty && current->signal->tty != real_tty)
  4.2428 -		return -ENOTTY;
  4.2429 -	if (real_tty->session <= 0)
  4.2430 -		return -ENOTTY;
  4.2431 -	return put_user(real_tty->session, p);
  4.2432 -}
  4.2433 -
  4.2434 -static int tiocsetd(struct tty_struct *tty, int __user *p)
  4.2435 -{
  4.2436 -	int ldisc;
  4.2437 -
  4.2438 -	if (get_user(ldisc, p))
  4.2439 -		return -EFAULT;
  4.2440 -	return tty_set_ldisc(tty, ldisc);
  4.2441 -}
  4.2442 -
  4.2443 -static int send_break(struct tty_struct *tty, unsigned int duration)
  4.2444 -{
  4.2445 -	tty->driver->break_ctl(tty, -1);
  4.2446 -	if (!signal_pending(current)) {
  4.2447 -		msleep_interruptible(duration);
  4.2448 -	}
  4.2449 -	tty->driver->break_ctl(tty, 0);
  4.2450 -	if (signal_pending(current))
  4.2451 -		return -EINTR;
  4.2452 -	return 0;
  4.2453 -}
  4.2454 -
  4.2455 -static int
  4.2456 -tty_tiocmget(struct tty_struct *tty, struct file *file, int __user *p)
  4.2457 -{
  4.2458 -	int retval = -EINVAL;
  4.2459 -
  4.2460 -	if (tty->driver->tiocmget) {
  4.2461 -		retval = tty->driver->tiocmget(tty, file);
  4.2462 -
  4.2463 -		if (retval >= 0)
  4.2464 -			retval = put_user(retval, p);
  4.2465 -	}
  4.2466 -	return retval;
  4.2467 -}
  4.2468 -
  4.2469 -static int
  4.2470 -tty_tiocmset(struct tty_struct *tty, struct file *file, unsigned int cmd,
  4.2471 -	     unsigned __user *p)
  4.2472 -{
  4.2473 -	int retval = -EINVAL;
  4.2474 -
  4.2475 -	if (tty->driver->tiocmset) {
  4.2476 -		unsigned int set, clear, val;
  4.2477 -
  4.2478 -		retval = get_user(val, p);
  4.2479 -		if (retval)
  4.2480 -			return retval;
  4.2481 -
  4.2482 -		set = clear = 0;
  4.2483 -		switch (cmd) {
  4.2484 -		case TIOCMBIS:
  4.2485 -			set = val;
  4.2486 -			break;
  4.2487 -		case TIOCMBIC:
  4.2488 -			clear = val;
  4.2489 -			break;
  4.2490 -		case TIOCMSET:
  4.2491 -			set = val;
  4.2492 -			clear = ~val;
  4.2493 -			break;
  4.2494 -		}
  4.2495 -
  4.2496 -		set &= TIOCM_DTR|TIOCM_RTS|TIOCM_OUT1|TIOCM_OUT2|TIOCM_LOOP;
  4.2497 -		clear &= TIOCM_DTR|TIOCM_RTS|TIOCM_OUT1|TIOCM_OUT2|TIOCM_LOOP;
  4.2498 -
  4.2499 -		retval = tty->driver->tiocmset(tty, file, set, clear);
  4.2500 -	}
  4.2501 -	return retval;
  4.2502 -}
  4.2503 -
  4.2504 -/*
  4.2505 - * Split this up, as gcc can choke on it otherwise..
  4.2506 - */
  4.2507 -int tty_ioctl(struct inode * inode, struct file * file,
  4.2508 -	      unsigned int cmd, unsigned long arg)
  4.2509 -{
  4.2510 -	struct tty_struct *tty, *real_tty;
  4.2511 -	void __user *p = (void __user *)arg;
  4.2512 -	int retval;
  4.2513 -	struct tty_ldisc *ld;
  4.2514 -	
  4.2515 -	tty = (struct tty_struct *)file->private_data;
  4.2516 -	if (tty_paranoia_check(tty, inode, "tty_ioctl"))
  4.2517 -		return -EINVAL;
  4.2518 -
  4.2519 -	real_tty = tty;
  4.2520 -	if (tty->driver->type == TTY_DRIVER_TYPE_PTY &&
  4.2521 -	    tty->driver->subtype == PTY_TYPE_MASTER)
  4.2522 -		real_tty = tty->link;
  4.2523 -
  4.2524 -	/*
  4.2525 -	 * Break handling by driver
  4.2526 -	 */
  4.2527 -	if (!tty->driver->break_ctl) {
  4.2528 -		switch(cmd) {
  4.2529 -		case TIOCSBRK:
  4.2530 -		case TIOCCBRK:
  4.2531 -			if (tty->driver->ioctl)
  4.2532 -				return tty->driver->ioctl(tty, file, cmd, arg);
  4.2533 -			return -EINVAL;
  4.2534 -			
  4.2535 -		/* These two ioctl's always return success; even if */
  4.2536 -		/* the driver doesn't support them. */
  4.2537 -		case TCSBRK:
  4.2538 -		case TCSBRKP:
  4.2539 -			if (!tty->driver->ioctl)
  4.2540 -				return 0;
  4.2541 -			retval = tty->driver->ioctl(tty, file, cmd, arg);
  4.2542 -			if (retval == -ENOIOCTLCMD)
  4.2543 -				retval = 0;
  4.2544 -			return retval;
  4.2545 -		}
  4.2546 -	}
  4.2547 -
  4.2548 -	/*
  4.2549 -	 * Factor out some common prep work
  4.2550 -	 */
  4.2551 -	switch (cmd) {
  4.2552 -	case TIOCSETD:
  4.2553 -	case TIOCSBRK:
  4.2554 -	case TIOCCBRK:
  4.2555 -	case TCSBRK:
  4.2556 -	case TCSBRKP:			
  4.2557 -		retval = tty_check_change(tty);
  4.2558 -		if (retval)
  4.2559 -			return retval;
  4.2560 -		if (cmd != TIOCCBRK) {
  4.2561 -			tty_wait_until_sent(tty, 0);
  4.2562 -			if (signal_pending(current))
  4.2563 -				return -EINTR;
  4.2564 -		}
  4.2565 -		break;
  4.2566 -	}
  4.2567 -
  4.2568 -	switch (cmd) {
  4.2569 -		case TIOCSTI:
  4.2570 -			return tiocsti(tty, p);
  4.2571 -		case TIOCGWINSZ:
  4.2572 -			return tiocgwinsz(tty, p);
  4.2573 -		case TIOCSWINSZ:
  4.2574 -			return tiocswinsz(tty, real_tty, p);
  4.2575 -		case TIOCCONS:
  4.2576 -			return real_tty!=tty ? -EINVAL : tioccons(file);
  4.2577 -		case FIONBIO:
  4.2578 -			return fionbio(file, p);
  4.2579 -		case TIOCEXCL:
  4.2580 -			set_bit(TTY_EXCLUSIVE, &tty->flags);
  4.2581 -			return 0;
  4.2582 -		case TIOCNXCL:
  4.2583 -			clear_bit(TTY_EXCLUSIVE, &tty->flags);
  4.2584 -			return 0;
  4.2585 -		case TIOCNOTTY:
  4.2586 -			if (current->signal->tty != tty)
  4.2587 -				return -ENOTTY;
  4.2588 -			if (current->signal->leader)
  4.2589 -				disassociate_ctty(0);
  4.2590 -			task_lock(current);
  4.2591 -			current->signal->tty = NULL;
  4.2592 -			task_unlock(current);
  4.2593 -			return 0;
  4.2594 -		case TIOCSCTTY:
  4.2595 -			return tiocsctty(tty, arg);
  4.2596 -		case TIOCGPGRP:
  4.2597 -			return tiocgpgrp(tty, real_tty, p);
  4.2598 -		case TIOCSPGRP:
  4.2599 -			return tiocspgrp(tty, real_tty, p);
  4.2600 -		case TIOCGSID:
  4.2601 -			return tiocgsid(tty, real_tty, p);
  4.2602 -		case TIOCGETD:
  4.2603 -			/* FIXME: check this is ok */
  4.2604 -			return put_user(tty->ldisc.num, (int __user *)p);
  4.2605 -		case TIOCSETD:
  4.2606 -			return tiocsetd(tty, p);
  4.2607 -#ifdef CONFIG_VT
  4.2608 -		case TIOCLINUX:
  4.2609 -			return tioclinux(tty, arg);
  4.2610 -#endif
  4.2611 -		/*
  4.2612 -		 * Break handling
  4.2613 -		 */
  4.2614 -		case TIOCSBRK:	/* Turn break on, unconditionally */
  4.2615 -			tty->driver->break_ctl(tty, -1);
  4.2616 -			return 0;
  4.2617 -			
  4.2618 -		case TIOCCBRK:	/* Turn break off, unconditionally */
  4.2619 -			tty->driver->break_ctl(tty, 0);
  4.2620 -			return 0;
  4.2621 -		case TCSBRK:   /* SVID version: non-zero arg --> no break */
  4.2622 -			/*
  4.2623 -			 * XXX is the above comment correct, or the
  4.2624 -			 * code below correct?  Is this ioctl used at
  4.2625 -			 * all by anyone?
  4.2626 -			 */
  4.2627 -			if (!arg)
  4.2628 -				return send_break(tty, 250);
  4.2629 -			return 0;
  4.2630 -		case TCSBRKP:	/* support for POSIX tcsendbreak() */	
  4.2631 -			return send_break(tty, arg ? arg*100 : 250);
  4.2632 -
  4.2633 -		case TIOCMGET:
  4.2634 -			return tty_tiocmget(tty, file, p);
  4.2635 -
  4.2636 -		case TIOCMSET:
  4.2637 -		case TIOCMBIC:
  4.2638 -		case TIOCMBIS:
  4.2639 -			return tty_tiocmset(tty, file, cmd, p);
  4.2640 -	}
  4.2641 -	if (tty->driver->ioctl) {
  4.2642 -		retval = (tty->driver->ioctl)(tty, file, cmd, arg);
  4.2643 -		if (retval != -ENOIOCTLCMD)
  4.2644 -			return retval;
  4.2645 -	}
  4.2646 -	ld = tty_ldisc_ref_wait(tty);
  4.2647 -	retval = -EINVAL;
  4.2648 -	if (ld->ioctl) {
  4.2649 -		retval = ld->ioctl(tty, file, cmd, arg);
  4.2650 -		if (retval == -ENOIOCTLCMD)
  4.2651 -			retval = -EINVAL;
  4.2652 -	}
  4.2653 -	tty_ldisc_deref(ld);
  4.2654 -	return retval;
  4.2655 -}
  4.2656 -
  4.2657 -
  4.2658 -/*
  4.2659 - * This implements the "Secure Attention Key" ---  the idea is to
  4.2660 - * prevent trojan horses by killing all processes associated with this
  4.2661 - * tty when the user hits the "Secure Attention Key".  Required for
  4.2662 - * super-paranoid applications --- see the Orange Book for more details.
  4.2663 - * 
  4.2664 - * This code could be nicer; ideally it should send a HUP, wait a few
  4.2665 - * seconds, then send a INT, and then a KILL signal.  But you then
  4.2666 - * have to coordinate with the init process, since all processes associated
  4.2667 - * with the current tty must be dead before the new getty is allowed
  4.2668 - * to spawn.
  4.2669 - *
  4.2670 - * Now, if it would be correct ;-/ The current code has a nasty hole -
  4.2671 - * it doesn't catch files in flight. We may send the descriptor to ourselves
  4.2672 - * via AF_UNIX socket, close it and later fetch from socket. FIXME.
  4.2673 - *
  4.2674 - * Nasty bug: do_SAK is being called in interrupt context.  This can
  4.2675 - * deadlock.  We punt it up to process context.  AKPM - 16Mar2001
  4.2676 - */
  4.2677 -static void __do_SAK(void *arg)
  4.2678 -{
  4.2679 -#ifdef TTY_SOFT_SAK
  4.2680 -	tty_hangup(tty);
  4.2681 -#else
  4.2682 -	struct tty_struct *tty = arg;
  4.2683 -	struct task_struct *p;
  4.2684 -	int session;
  4.2685 -	int		i;
  4.2686 -	struct file	*filp;
  4.2687 -	struct tty_ldisc *disc;
  4.2688 -	struct fdtable *fdt;
  4.2689 -	
  4.2690 -	if (!tty)
  4.2691 -		return;
  4.2692 -	session  = tty->session;
  4.2693 -	
  4.2694 -	/* We don't want an ldisc switch during this */
  4.2695 -	disc = tty_ldisc_ref(tty);
  4.2696 -	if (disc && disc->flush_buffer)
  4.2697 -		disc->flush_buffer(tty);
  4.2698 -	tty_ldisc_deref(disc);
  4.2699 -
  4.2700 -	if (tty->driver->flush_buffer)
  4.2701 -		tty->driver->flush_buffer(tty);
  4.2702 -	
  4.2703 -	read_lock(&tasklist_lock);
  4.2704 -	do_each_task_pid(session, PIDTYPE_SID, p) {
  4.2705 -		if (p->signal->tty == tty || session > 0) {
  4.2706 -			printk(KERN_NOTICE "SAK: killed process %d"
  4.2707 -			    " (%s): p->signal->session==tty->session\n",
  4.2708 -			    p->pid, p->comm);
  4.2709 -			send_sig(SIGKILL, p, 1);
  4.2710 -			continue;
  4.2711 -		}
  4.2712 -		task_lock(p);
  4.2713 -		if (p->files) {
  4.2714 -			/*
  4.2715 -			 * We don't take a ref to the file, so we must
  4.2716 -			 * hold ->file_lock instead.
  4.2717 -			 */
  4.2718 -			spin_lock(&p->files->file_lock);
  4.2719 -			fdt = files_fdtable(p->files);
  4.2720 -			for (i=0; i < fdt->max_fds; i++) {
  4.2721 -				filp = fcheck_files(p->files, i);
  4.2722 -				if (!filp)
  4.2723 -					continue;
  4.2724 -				if (filp->f_op->read == tty_read &&
  4.2725 -				    filp->private_data == tty) {
  4.2726 -					printk(KERN_NOTICE "SAK: killed process %d"
  4.2727 -					    " (%s): fd#%d opened to the tty\n",
  4.2728 -					    p->pid, p->comm, i);
  4.2729 -					send_sig(SIGKILL, p, 1);
  4.2730 -					break;
  4.2731 -				}
  4.2732 -			}
  4.2733 -			spin_unlock(&p->files->file_lock);
  4.2734 -		}
  4.2735 -		task_unlock(p);
  4.2736 -	} while_each_task_pid(session, PIDTYPE_SID, p);
  4.2737 -	read_unlock(&tasklist_lock);
  4.2738 -#endif
  4.2739 -}
  4.2740 -
  4.2741 -/*
  4.2742 - * The tq handling here is a little racy - tty->SAK_work may already be queued.
  4.2743 - * Fortunately we don't need to worry, because if ->SAK_work is already queued,
  4.2744 - * the values which we write to it will be identical to the values which it
  4.2745 - * already has. --akpm
  4.2746 - */
  4.2747 -void do_SAK(struct tty_struct *tty)
  4.2748 -{
  4.2749 -	if (!tty)
  4.2750 -		return;
  4.2751 -	PREPARE_WORK(&tty->SAK_work, __do_SAK, tty);
  4.2752 -	schedule_work(&tty->SAK_work);
  4.2753 -}
  4.2754 -
  4.2755 -EXPORT_SYMBOL(do_SAK);
  4.2756 -
  4.2757 -/*
  4.2758 - * This routine is called out of the software interrupt to flush data
  4.2759 - * from the buffer chain to the line discipline.
  4.2760 - */
  4.2761 - 
  4.2762 -static void flush_to_ldisc(void *private_)
  4.2763 -{
  4.2764 -	struct tty_struct *tty = (struct tty_struct *) private_;
  4.2765 -	unsigned long 	flags;
  4.2766 -	struct tty_ldisc *disc;
  4.2767 -	struct tty_buffer *tbuf, *head;
  4.2768 -	int count;
  4.2769 -	char *char_buf;
  4.2770 -	unsigned char *flag_buf;
  4.2771 -
  4.2772 -	disc = tty_ldisc_ref(tty);
  4.2773 -	if (disc == NULL)	/*  !TTY_LDISC */
  4.2774 -		return;
  4.2775 -
  4.2776 -	if (test_bit(TTY_DONT_FLIP, &tty->flags)) {
  4.2777 -		/*
  4.2778 -		 * Do it after the next timer tick:
  4.2779 -		 */
  4.2780 -		schedule_delayed_work(&tty->buf.work, 1);
  4.2781 -		goto out;
  4.2782 -	}
  4.2783 -	spin_lock_irqsave(&tty->buf.lock, flags);
  4.2784 -	head = tty->buf.head;
  4.2785 -	tty->buf.head = NULL;
  4.2786 -	while((tbuf = head) != NULL) {
  4.2787 -		while ((count = tbuf->commit - tbuf->read) != 0) {
  4.2788 -			char_buf = tbuf->char_buf_ptr + tbuf->read;
  4.2789 -			flag_buf = tbuf->flag_buf_ptr + tbuf->read;
  4.2790 -			tbuf->read += count;
  4.2791 -			spin_unlock_irqrestore(&tty->buf.lock, flags);
  4.2792 -			disc->receive_buf(tty, char_buf, flag_buf, count);
  4.2793 -			spin_lock_irqsave(&tty->buf.lock, flags);
  4.2794 -		}
  4.2795 -		if (tbuf->active) {
  4.2796 -			tty->buf.head = head;
  4.2797 -			break;
  4.2798 -		}
  4.2799 -		head = tbuf->next;
  4.2800 -		if (head == NULL)
  4.2801 -			tty->buf.tail = NULL;
  4.2802 -		tty_buffer_free(tty, tbuf);
  4.2803 -	}
  4.2804 -	spin_unlock_irqrestore(&tty->buf.lock, flags);
  4.2805 -out:
  4.2806 -	tty_ldisc_deref(disc);
  4.2807 -}
  4.2808 -
  4.2809 -/*
  4.2810 - * Routine which returns the baud rate of the tty
  4.2811 - *
  4.2812 - * Note that the baud_table needs to be kept in sync with the
  4.2813 - * include/asm/termbits.h file.
  4.2814 - */
  4.2815 -static int baud_table[] = {
  4.2816 -	0, 50, 75, 110, 134, 150, 200, 300, 600, 1200, 1800, 2400, 4800,
  4.2817 -	9600, 19200, 38400, 57600, 115200, 230400, 460800,
  4.2818 -#ifdef __sparc__
  4.2819 -	76800, 153600, 307200, 614400, 921600
  4.2820 -#else
  4.2821 -	500000, 576000, 921600, 1000000, 1152000, 1500000, 2000000,
  4.2822 -	2500000, 3000000, 3500000, 4000000
  4.2823 -#endif
  4.2824 -};
  4.2825 -
  4.2826 -static int n_baud_table = ARRAY_SIZE(baud_table);
  4.2827 -
  4.2828 -/**
  4.2829 - *	tty_termios_baud_rate
  4.2830 - *	@termios: termios structure
  4.2831 - *
  4.2832 - *	Convert termios baud rate data into a speed. This should be called
  4.2833 - *	with the termios lock held if this termios is a terminal termios
  4.2834 - *	structure. May change the termios data.
  4.2835 - */
  4.2836 - 
  4.2837 -int tty_termios_baud_rate(struct termios *termios)
  4.2838 -{
  4.2839 -	unsigned int cbaud;
  4.2840 -	
  4.2841 -	cbaud = termios->c_cflag & CBAUD;
  4.2842 -
  4.2843 -	if (cbaud & CBAUDEX) {
  4.2844 -		cbaud &= ~CBAUDEX;
  4.2845 -
  4.2846 -		if (cbaud < 1 || cbaud + 15 > n_baud_table)
  4.2847 -			termios->c_cflag &= ~CBAUDEX;
  4.2848 -		else
  4.2849 -			cbaud += 15;
  4.2850 -	}
  4.2851 -	return baud_table[cbaud];
  4.2852 -}
  4.2853 -
  4.2854 -EXPORT_SYMBOL(tty_termios_baud_rate);
  4.2855 -
  4.2856 -/**
  4.2857 - *	tty_get_baud_rate	-	get tty bit rates
  4.2858 - *	@tty: tty to query
  4.2859 - *
  4.2860 - *	Returns the baud rate as an integer for this terminal. The
  4.2861 - *	termios lock must be held by the caller and the terminal bit
  4.2862 - *	flags may be updated.
  4.2863 - */
  4.2864 - 
  4.2865 -int tty_get_baud_rate(struct tty_struct *tty)
  4.2866 -{
  4.2867 -	int baud = tty_termios_baud_rate(tty->termios);
  4.2868 -
  4.2869 -	if (baud == 38400 && tty->alt_speed) {
  4.2870 -		if (!tty->warned) {
  4.2871 -			printk(KERN_WARNING "Use of setserial/setrocket to "
  4.2872 -					    "set SPD_* flags is deprecated\n");
  4.2873 -			tty->warned = 1;
  4.2874 -		}
  4.2875 -		baud = tty->alt_speed;
  4.2876 -	}
  4.2877 -	
  4.2878 -	return baud;
  4.2879 -}
  4.2880 -
  4.2881 -EXPORT_SYMBOL(tty_get_baud_rate);
  4.2882 -
  4.2883 -/**
  4.2884 - *	tty_flip_buffer_push	-	terminal
  4.2885 - *	@tty: tty to push
  4.2886 - *
  4.2887 - *	Queue a push of the terminal flip buffers to the line discipline. This
  4.2888 - *	function must not be called from IRQ context if tty->low_latency is set.
  4.2889 - *
  4.2890 - *	In the event of the queue being busy for flipping the work will be
  4.2891 - *	held off and retried later.
  4.2892 - */
  4.2893 -
  4.2894 -void tty_flip_buffer_push(struct tty_struct *tty)
  4.2895 -{
  4.2896 -	unsigned long flags;
  4.2897 -	spin_lock_irqsave(&tty->buf.lock, flags);
  4.2898 -	if (tty->buf.tail != NULL) {
  4.2899 -		tty->buf.tail->active = 0;
  4.2900 -		tty->buf.tail->commit = tty->buf.tail->used;
  4.2901 -	}
  4.2902 -	spin_unlock_irqrestore(&tty->buf.lock, flags);
  4.2903 -
  4.2904 -	if (tty->low_latency)
  4.2905 -		flush_to_ldisc((void *) tty);
  4.2906 -	else
  4.2907 -		schedule_delayed_work(&tty->buf.work, 1);
  4.2908 -}
  4.2909 -
  4.2910 -EXPORT_SYMBOL(tty_flip_buffer_push);
  4.2911 -
  4.2912 -
  4.2913 -/*
  4.2914 - * This subroutine initializes a tty structure.
  4.2915 - */
  4.2916 -static void initialize_tty_struct(struct tty_struct *tty)
  4.2917 -{
  4.2918 -	memset(tty, 0, sizeof(struct tty_struct));
  4.2919 -	tty->magic = TTY_MAGIC;
  4.2920 -	tty_ldisc_assign(tty, tty_ldisc_get(N_TTY));
  4.2921 -	tty->pgrp = -1;
  4.2922 -	tty->overrun_time = jiffies;
  4.2923 -	tty->buf.head = tty->buf.tail = NULL;
  4.2924 -	tty_buffer_init(tty);
  4.2925 -	INIT_WORK(&tty->buf.work, flush_to_ldisc, tty);
  4.2926 -	init_MUTEX(&tty->buf.pty_sem);
  4.2927 -	init_MUTEX(&tty->termios_sem);
  4.2928 -	init_waitqueue_head(&tty->write_wait);
  4.2929 -	init_waitqueue_head(&tty->read_wait);
  4.2930 -	INIT_WORK(&tty->hangup_work, do_tty_hangup, tty);
  4.2931 -	sema_init(&tty->atomic_read, 1);
  4.2932 -	sema_init(&tty->atomic_write, 1);
  4.2933 -	spin_lock_init(&tty->read_lock);
  4.2934 -	INIT_LIST_HEAD(&tty->tty_files);
  4.2935 -	INIT_WORK(&tty->SAK_work, NULL, NULL);
  4.2936 -}
  4.2937 -
  4.2938 -/*
  4.2939 - * The default put_char routine if the driver did not define one.
  4.2940 - */
  4.2941 -static void tty_default_put_char(struct tty_struct *tty, unsigned char ch)
  4.2942 -{
  4.2943 -	tty->driver->write(tty, &ch, 1);
  4.2944 -}
  4.2945 -
  4.2946 -static struct class *tty_class;
  4.2947 -
  4.2948 -/**
  4.2949 - * tty_register_device - register a tty device
  4.2950 - * @driver: the tty driver that describes the tty device
  4.2951 - * @index: the index in the tty driver for this tty device
  4.2952 - * @device: a struct device that is associated with this tty device.
  4.2953 - *	This field is optional, if there is no known struct device for this
  4.2954 - *	tty device it can be set to NULL safely.
  4.2955 - *
  4.2956 - * This call is required to be made to register an individual tty device if
  4.2957 - * the tty driver's flags have the TTY_DRIVER_NO_DEVFS bit set.  If that
  4.2958 - * bit is not set, this function should not be called.
  4.2959 - */
  4.2960 -void tty_register_device(struct tty_driver *driver, unsigned index,
  4.2961 -			 struct device *device)
  4.2962 -{
  4.2963 -	char name[64];
  4.2964 -	dev_t dev = MKDEV(driver->major, driver->minor_start) + index;
  4.2965 -
  4.2966 -	if (index >= driver->num) {
  4.2967 -		printk(KERN_ERR "Attempt to register invalid tty line number "
  4.2968 -		       " (%d).\n", index);
  4.2969 -		return;
  4.2970 -	}
  4.2971 -
  4.2972 -	devfs_mk_cdev(dev, S_IFCHR | S_IRUSR | S_IWUSR,
  4.2973 -			"%s%d", driver->devfs_name, index + driver->name_base);
  4.2974 -
  4.2975 -	if (driver->type == TTY_DRIVER_TYPE_PTY)
  4.2976 -		pty_line_name(driver, index, name);
  4.2977 -	else
  4.2978 -		tty_line_name(driver, index, name);
  4.2979 -	class_device_create(tty_class, NULL, dev, device, "%s", name);
  4.2980 -}
  4.2981 -
  4.2982 -/**
  4.2983 - * tty_unregister_device - unregister a tty device
  4.2984 - * @driver: the tty driver that describes the tty device
  4.2985 - * @index: the index in the tty driver for this tty device
  4.2986 - *
  4.2987 - * If a tty device is registered with a call to tty_register_device() then
  4.2988 - * this function must be made when the tty device is gone.
  4.2989 - */
  4.2990 -void tty_unregister_device(struct tty_driver *driver, unsigned index)
  4.2991 -{
  4.2992 -	devfs_remove("%s%d", driver->devfs_name, index + driver->name_base);
  4.2993 -	class_device_destroy(tty_class, MKDEV(driver->major, driver->minor_start) + index);
  4.2994 -}
  4.2995 -
  4.2996 -EXPORT_SYMBOL(tty_register_device);
  4.2997 -EXPORT_SYMBOL(tty_unregister_device);
  4.2998 -
  4.2999 -struct tty_driver *alloc_tty_driver(int lines)
  4.3000 -{
  4.3001 -	struct tty_driver *driver;
  4.3002 -
  4.3003 -	driver = kmalloc(sizeof(struct tty_driver), GFP_KERNEL);
  4.3004 -	if (driver) {
  4.3005 -		memset(driver, 0, sizeof(struct tty_driver));
  4.3006 -		driver->magic = TTY_DRIVER_MAGIC;
  4.3007 -		driver->num = lines;
  4.3008 -		/* later we'll move allocation of tables here */
  4.3009 -	}
  4.3010 -	return driver;
  4.3011 -}
  4.3012 -
  4.3013 -void put_tty_driver(struct tty_driver *driver)
  4.3014 -{
  4.3015 -	kfree(driver);
  4.3016 -}
  4.3017 -
  4.3018 -void tty_set_operations(struct tty_driver *driver, struct tty_operations *op)
  4.3019 -{
  4.3020 -	driver->open = op->open;
  4.3021 -	driver->close = op->close;
  4.3022 -	driver->write = op->write;
  4.3023 -	driver->put_char = op->put_char;
  4.3024 -	driver->flush_chars = op->flush_chars;
  4.3025 -	driver->write_room = op->write_room;
  4.3026 -	driver->chars_in_buffer = op->chars_in_buffer;
  4.3027 -	driver->ioctl = op->ioctl;
  4.3028 -	driver->set_termios = op->set_termios;
  4.3029 -	driver->throttle = op->throttle;
  4.3030 -	driver->unthrottle = op->unthrottle;
  4.3031 -	driver->stop = op->stop;
  4.3032 -	driver->start = op->start;
  4.3033 -	driver->hangup = op->hangup;
  4.3034 -	driver->break_ctl = op->break_ctl;
  4.3035 -	driver->flush_buffer = op->flush_buffer;
  4.3036 -	driver->set_ldisc = op->set_ldisc;
  4.3037 -	driver->wait_until_sent = op->wait_until_sent;
  4.3038 -	driver->send_xchar = op->send_xchar;
  4.3039 -	driver->read_proc = op->read_proc;
  4.3040 -	driver->write_proc = op->write_proc;
  4.3041 -	driver->tiocmget = op->tiocmget;
  4.3042 -	driver->tiocmset = op->tiocmset;
  4.3043 -}
  4.3044 -
  4.3045 -
  4.3046 -EXPORT_SYMBOL(alloc_tty_driver);
  4.3047 -EXPORT_SYMBOL(put_tty_driver);
  4.3048 -EXPORT_SYMBOL(tty_set_operations);
  4.3049 -
  4.3050 -/*
  4.3051 - * Called by a tty driver to register itself.
  4.3052 - */
  4.3053 -int tty_register_driver(struct tty_driver *driver)
  4.3054 -{
  4.3055 -	int error;
  4.3056 -        int i;
  4.3057 -	dev_t dev;
  4.3058 -	void **p = NULL;
  4.3059 -
  4.3060 -	if (driver->flags & TTY_DRIVER_INSTALLED)
  4.3061 -		return 0;
  4.3062 -
  4.3063 -	if (!(driver->flags & TTY_DRIVER_DEVPTS_MEM)) {
  4.3064 -		p = kmalloc(driver->num * 3 * sizeof(void *), GFP_KERNEL);
  4.3065 -		if (!p)
  4.3066 -			return -ENOMEM;
  4.3067 -		memset(p, 0, driver->num * 3 * sizeof(void *));
  4.3068 -	}
  4.3069 -
  4.3070 -	if (!driver->major) {
  4.3071 -		error = alloc_chrdev_region(&dev, driver->minor_start, driver->num,
  4.3072 -						(char*)driver->name);
  4.3073 -		if (!error) {
  4.3074 -			driver->major = MAJOR(dev);
  4.3075 -			driver->minor_start = MINOR(dev);
  4.3076 -		}
  4.3077 -	} else {
  4.3078 -		dev = MKDEV(driver->major, driver->minor_start);
  4.3079 -		error = register_chrdev_region(dev, driver->num,
  4.3080 -						(char*)driver->name);
  4.3081 -	}
  4.3082 -	if (error < 0) {
  4.3083 -		kfree(p);
  4.3084 -		return error;
  4.3085 -	}
  4.3086 -
  4.3087 -	if (p) {
  4.3088 -		driver->ttys = (struct tty_struct **)p;
  4.3089 -		driver->termios = (struct termios **)(p + driver->num);
  4.3090 -		driver->termios_locked = (struct termios **)(p + driver->num * 2);
  4.3091 -	} else {
  4.3092 -		driver->ttys = NULL;
  4.3093 -		driver->termios = NULL;
  4.3094 -		driver->termios_locked = NULL;
  4.3095 -	}
  4.3096 -
  4.3097 -	cdev_init(&driver->cdev, &tty_fops);
  4.3098 -	driver->cdev.owner = driver->owner;
  4.3099 -	error = cdev_add(&driver->cdev, dev, driver->num);
  4.3100 -	if (error) {
  4.3101 -		cdev_del(&driver->cdev);
  4.3102 -		unregister_chrdev_region(dev, driver->num);
  4.3103 -		driver->ttys = NULL;
  4.3104 -		driver->termios = driver->termios_locked = NULL;
  4.3105 -		kfree(p);
  4.3106 -		return error;
  4.3107 -	}
  4.3108 -
  4.3109 -	if (!driver->put_char)
  4.3110 -		driver->put_char = tty_default_put_char;
  4.3111 -	
  4.3112 -	list_add(&driver->tty_drivers, &tty_drivers);
  4.3113 -	
  4.3114 -	if ( !(driver->flags & TTY_DRIVER_NO_DEVFS) ) {
  4.3115 -		for(i = 0; i < driver->num; i++)
  4.3116 -		    tty_register_device(driver, i, NULL);
  4.3117 -	}
  4.3118 -	proc_tty_register_driver(driver);
  4.3119 -	return 0;
  4.3120 -}
  4.3121 -
  4.3122 -EXPORT_SYMBOL(tty_register_driver);
  4.3123 -
  4.3124 -/*
  4.3125 - * Called by a tty driver to unregister itself.
  4.3126 - */
  4.3127 -int tty_unregister_driver(struct tty_driver *driver)
  4.3128 -{
  4.3129 -	int i;
  4.3130 -	struct termios *tp;
  4.3131 -	void *p;
  4.3132 -
  4.3133 -	if (driver->refcount)
  4.3134 -		return -EBUSY;
  4.3135 -
  4.3136 -	unregister_chrdev_region(MKDEV(driver->major, driver->minor_start),
  4.3137 -				driver->num);
  4.3138 -
  4.3139 -	list_del(&driver->tty_drivers);
  4.3140 -
  4.3141 -	/*
  4.3142 -	 * Free the termios and termios_locked structures because
  4.3143 -	 * we don't want to get memory leaks when modular tty
  4.3144 -	 * drivers are removed from the kernel.
  4.3145 -	 */
  4.3146 -	for (i = 0; i < driver->num; i++) {
  4.3147 -		tp = driver->termios[i];
  4.3148 -		if (tp) {
  4.3149 -			driver->termios[i] = NULL;
  4.3150 -			kfree(tp);
  4.3151 -		}
  4.3152 -		tp = driver->termios_locked[i];
  4.3153 -		if (tp) {
  4.3154 -			driver->termios_locked[i] = NULL;
  4.3155 -			kfree(tp);
  4.3156 -		}
  4.3157 -		if (!(driver->flags & TTY_DRIVER_NO_DEVFS))
  4.3158 -			tty_unregister_device(driver, i);
  4.3159 -	}
  4.3160 -	p = driver->ttys;
  4.3161 -	proc_tty_unregister_driver(driver);
  4.3162 -	driver->ttys = NULL;
  4.3163 -	driver->termios = driver->termios_locked = NULL;
  4.3164 -	kfree(p);
  4.3165 -	cdev_del(&driver->cdev);
  4.3166 -	return 0;
  4.3167 -}
  4.3168 -
  4.3169 -EXPORT_SYMBOL(tty_unregister_driver);
  4.3170 -
  4.3171 -
  4.3172 -/*
  4.3173 - * Initialize the console device. This is called *early*, so
  4.3174 - * we can't necessarily depend on lots of kernel help here.
  4.3175 - * Just do some early initializations, and do the complex setup
  4.3176 - * later.
  4.3177 - */
  4.3178 -void __init console_init(void)
  4.3179 -{
  4.3180 -	initcall_t *call;
  4.3181 -
  4.3182 -	/* Setup the default TTY line discipline. */
  4.3183 -	(void) tty_register_ldisc(N_TTY, &tty_ldisc_N_TTY);
  4.3184 -
  4.3185 -	/*
  4.3186 -	 * set up the console device so that later boot sequences can 
  4.3187 -	 * inform about problems etc..
  4.3188 -	 */
  4.3189 -#ifdef CONFIG_EARLY_PRINTK
  4.3190 -	disable_early_printk();
  4.3191 -#endif
  4.3192 -	call = __con_initcall_start;
  4.3193 -	while (call < __con_initcall_end) {
  4.3194 -		(*call)();
  4.3195 -		call++;
  4.3196 -	}
  4.3197 -}
  4.3198 -
  4.3199 -#ifdef CONFIG_VT
  4.3200 -extern int vty_init(void);
  4.3201 -#endif
  4.3202 -
  4.3203 -static int __init tty_class_init(void)
  4.3204 -{
  4.3205 -	tty_class = class_create(THIS_MODULE, "tty");
  4.3206 -	if (IS_ERR(tty_class))
  4.3207 -		return PTR_ERR(tty_class);
  4.3208 -	return 0;
  4.3209 -}
  4.3210 -
  4.3211 -postcore_initcall(tty_class_init);
  4.3212 -
  4.3213 -/* 3/2004 jmc: why do these devices exist? */
  4.3214 -
  4.3215 -static struct cdev tty_cdev, console_cdev;
  4.3216 -#ifdef CONFIG_UNIX98_PTYS
  4.3217 -static struct cdev ptmx_cdev;
  4.3218 -#endif
  4.3219 -#ifdef CONFIG_VT
  4.3220 -static struct cdev vc0_cdev;
  4.3221 -#endif
  4.3222 -
  4.3223 -/*
  4.3224 - * Ok, now we can initialize the rest of the tty devices and can count
  4.3225 - * on memory allocations, interrupts etc..
  4.3226 - */
  4.3227 -static int __init tty_init(void)
  4.3228 -{
  4.3229 -	cdev_init(&tty_cdev, &tty_fops);
  4.3230 -	if (cdev_add(&tty_cdev, MKDEV(TTYAUX_MAJOR, 0), 1) ||
  4.3231 -	    register_chrdev_region(MKDEV(TTYAUX_MAJOR, 0), 1, "/dev/tty") < 0)
  4.3232 -		panic("Couldn't register /dev/tty driver\n");
  4.3233 -	devfs_mk_cdev(MKDEV(TTYAUX_MAJOR, 0), S_IFCHR|S_IRUGO|S_IWUGO, "tty");
  4.3234 -	class_device_create(tty_class, NULL, MKDEV(TTYAUX_MAJOR, 0), NULL, "tty");
  4.3235 -
  4.3236 -	cdev_init(&console_cdev, &console_fops);
  4.3237 -	if (cdev_add(&console_cdev, MKDEV(TTYAUX_MAJOR, 1), 1) ||
  4.3238 -	    register_chrdev_region(MKDEV(TTYAUX_MAJOR, 1), 1, "/dev/console") < 0)
  4.3239 -		panic("Couldn't register /dev/console driver\n");
  4.3240 -	devfs_mk_cdev(MKDEV(TTYAUX_MAJOR, 1), S_IFCHR|S_IRUSR|S_IWUSR, "console");
  4.3241 -	class_device_create(tty_class, NULL, MKDEV(TTYAUX_MAJOR, 1), NULL, "console");
  4.3242 -
  4.3243 -#ifdef CONFIG_UNIX98_PTYS
  4.3244 -	cdev_init(&ptmx_cdev, &ptmx_fops);
  4.3245 -	if (cdev_add(&ptmx_cdev, MKDEV(TTYAUX_MAJOR, 2), 1) ||
  4.3246 -	    register_chrdev_region(MKDEV(TTYAUX_MAJOR, 2), 1, "/dev/ptmx") < 0)
  4.3247 -		panic("Couldn't register /dev/ptmx driver\n");
  4.3248 -	devfs_mk_cdev(MKDEV(TTYAUX_MAJOR, 2), S_IFCHR|S_IRUGO|S_IWUGO, "ptmx");
  4.3249 -	class_device_create(tty_class, NULL, MKDEV(TTYAUX_MAJOR, 2), NULL, "ptmx");
  4.3250 -#endif
  4.3251 -
  4.3252 -#ifdef CONFIG_VT
  4.3253 -	if (!console_use_vt)
  4.3254 -		goto out_vt;
  4.3255 -	cdev_init(&vc0_cdev, &console_fops);
  4.3256 -	if (cdev_add(&vc0_cdev, MKDEV(TTY_MAJOR, 0), 1) ||
  4.3257 -	    register_chrdev_region(MKDEV(TTY_MAJOR, 0), 1, "/dev/vc/0") < 0)
  4.3258 -		panic("Couldn't register /dev/tty0 driver\n");
  4.3259 -	devfs_mk_cdev(MKDEV(TTY_MAJOR, 0), S_IFCHR|S_IRUSR|S_IWUSR, "vc/0");
  4.3260 -	class_device_create(tty_class, NULL, MKDEV(TTY_MAJOR, 0), NULL, "tty0");
  4.3261 -
  4.3262 -	vty_init();
  4.3263 - out_vt:
  4.3264 -#endif
  4.3265 -	return 0;
  4.3266 -}
  4.3267 -module_init(tty_init);
     5.1 --- a/linux-2.6-xen-sparse/drivers/xen/Kconfig	Fri Dec 01 09:28:14 2006 +0000
     5.2 +++ b/linux-2.6-xen-sparse/drivers/xen/Kconfig	Fri Dec 01 09:48:32 2006 +0000
     5.3 @@ -172,6 +172,29 @@ config XEN_NETDEV_FRONTEND
     5.4  	  dedicated device-driver domain, or your master control domain
     5.5  	  (domain 0), then you almost certainly want to say Y here.
     5.6  
     5.7 +config XEN_FRAMEBUFFER
     5.8 +	tristate "Framebuffer-device frontend driver"
     5.9 +	depends on XEN && FB
    5.10 +	select FB_CFB_FILLRECT
    5.11 +	select FB_CFB_COPYAREA
    5.12 +	select FB_CFB_IMAGEBLIT
    5.13 +	default y
    5.14 +	help
    5.15 +	  The framebuffer-device frontend drivers allows the kernel to create a
    5.16 +	  virtual framebuffer.  This framebuffer can be viewed in another
    5.17 +	  domain.  Unless this domain has access to a real video card, you
    5.18 +	  probably want to say Y here.
    5.19 +
    5.20 +config XEN_KEYBOARD
    5.21 +	tristate "Keyboard-device frontend driver"
    5.22 +	depends on XEN && XEN_FRAMEBUFFER && INPUT
    5.23 +	default y
    5.24 +	help
    5.25 +	  The keyboard-device frontend driver allows the kernel to create a
    5.26 +	  virtual keyboard.  This keyboard can then be driven by another
    5.27 +	  domain.  If you've said Y to CONFIG_XEN_FRAMEBUFFER, you probably
    5.28 +	  want to say Y here.
    5.29 +
    5.30  config XEN_SCRUB_PAGES
    5.31  	bool "Scrub memory before freeing it to Xen"
    5.32  	default y
     6.1 --- a/linux-2.6-xen-sparse/drivers/xen/Makefile	Fri Dec 01 09:28:14 2006 +0000
     6.2 +++ b/linux-2.6-xen-sparse/drivers/xen/Makefile	Fri Dec 01 09:48:32 2006 +0000
     6.3 @@ -15,3 +15,5 @@ obj-$(CONFIG_XEN_BLKDEV_FRONTEND)	+= blk
     6.4  obj-$(CONFIG_XEN_NETDEV_FRONTEND)	+= netfront/
     6.5  obj-$(CONFIG_XEN_PCIDEV_BACKEND)	+= pciback/
     6.6  obj-$(CONFIG_XEN_PCIDEV_FRONTEND)	+= pcifront/
     6.7 +obj-$(CONFIG_XEN_FRAMEBUFFER)		+= fbfront/
     6.8 +obj-$(CONFIG_XEN_KEYBOARD)		+= fbfront/
     7.1 --- a/linux-2.6-xen-sparse/drivers/xen/console/console.c	Fri Dec 01 09:28:14 2006 +0000
     7.2 +++ b/linux-2.6-xen-sparse/drivers/xen/console/console.c	Fri Dec 01 09:48:32 2006 +0000
     7.3 @@ -57,6 +57,7 @@
     7.4  #include <xen/interface/event_channel.h>
     7.5  #include <asm/hypervisor.h>
     7.6  #include <xen/evtchn.h>
     7.7 +#include <xen/xenbus.h>
     7.8  #include <xen/xencons.h>
     7.9  
    7.10  /*
    7.11 @@ -698,6 +699,15 @@ static int __init xencons_init(void)
    7.12  	printk("Xen virtual console successfully installed as %s%d\n",
    7.13  	       DRV(xencons_driver)->name, xc_num);
    7.14  
    7.15 +        /* Check about framebuffer messing up the console */
    7.16 +        if (!is_initial_xendomain() &&
    7.17 +	    !xenbus_exists(XBT_NIL, "device", "vfb")) {
    7.18 +		/* FIXME: this is ugly */
    7.19 +		unregister_console(&kcons_info);
    7.20 +		kcons_info.flags |= CON_CONSDEV;
    7.21 +		register_console(&kcons_info);
    7.22 +	}
    7.23 +
    7.24  	return 0;
    7.25  }
    7.26  
     8.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     8.2 +++ b/linux-2.6-xen-sparse/drivers/xen/fbfront/Makefile	Fri Dec 01 09:48:32 2006 +0000
     8.3 @@ -0,0 +1,2 @@
     8.4 +obj-$(CONFIG_XEN_FRAMEBUFFER)	:= xenfb.o
     8.5 +obj-$(CONFIG_XEN_KEYBOARD)	+= xenkbd.o
     9.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
     9.2 +++ b/linux-2.6-xen-sparse/drivers/xen/fbfront/xenfb.c	Fri Dec 01 09:48:32 2006 +0000
     9.3 @@ -0,0 +1,682 @@
     9.4 +/*
     9.5 + * linux/drivers/video/xenfb.c -- Xen para-virtual frame buffer device
     9.6 + *
     9.7 + * Copyright (C) 2005-2006 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/video/q40fb.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 when they become capable of dealing with the
    9.21 + * frame buffer.
    9.22 + */
    9.23 +
    9.24 +#include <linux/kernel.h>
    9.25 +#include <linux/errno.h>
    9.26 +#include <linux/fb.h>
    9.27 +#include <linux/module.h>
    9.28 +#include <linux/vmalloc.h>
    9.29 +#include <linux/mm.h>
    9.30 +#include <asm/hypervisor.h>
    9.31 +#include <xen/evtchn.h>
    9.32 +#include <xen/interface/io/fbif.h>
    9.33 +#include <xen/xenbus.h>
    9.34 +#include <linux/kthread.h>
    9.35 +
    9.36 +struct xenfb_mapping
    9.37 +{
    9.38 +	struct list_head	link;
    9.39 +	struct vm_area_struct	*vma;
    9.40 +	atomic_t		map_refs;
    9.41 +	int			faults;
    9.42 +	struct xenfb_info	*info;
    9.43 +};
    9.44 +
    9.45 +struct xenfb_info
    9.46 +{
    9.47 +	struct task_struct	*kthread;
    9.48 +	wait_queue_head_t	wq;
    9.49 +
    9.50 +	unsigned char		*fb;
    9.51 +	struct fb_info		*fb_info;
    9.52 +	struct timer_list	refresh;
    9.53 +	int			dirty;
    9.54 +	int			x1, y1, x2, y2;	/* dirty rectangle,
    9.55 +						   protected by mm_lock */
    9.56 +	spinlock_t		mm_lock;
    9.57 +	int			nr_pages;
    9.58 +	struct page		**pages;
    9.59 +	struct list_head	mappings; /* protected by mm_lock */
    9.60 +
    9.61 +	unsigned		evtchn;
    9.62 +	int			irq;
    9.63 +	struct xenfb_page	*page;
    9.64 +	unsigned long 		*mfns;
    9.65 +	int			update_wanted; /* XENFB_TYPE_UPDATE wanted */
    9.66 +
    9.67 +	struct xenbus_device	*xbdev;
    9.68 +};
    9.69 +
    9.70 +static int xenfb_fps = 20;
    9.71 +static unsigned long xenfb_mem_len = XENFB_WIDTH * XENFB_HEIGHT * XENFB_DEPTH / 8;
    9.72 +
    9.73 +static int xenfb_remove(struct xenbus_device *);
    9.74 +static void xenfb_init_shared_page(struct xenfb_info *);
    9.75 +static int xenfb_connect_backend(struct xenbus_device *, struct xenfb_info *);
    9.76 +static void xenfb_disconnect_backend(struct xenfb_info *);
    9.77 +
    9.78 +static void xenfb_do_update(struct xenfb_info *info,
    9.79 +			    int x, int y, int w, int h)
    9.80 +{
    9.81 +	union xenfb_out_event event;
    9.82 +	__u32 prod;
    9.83 +
    9.84 +	event.type = XENFB_TYPE_UPDATE;
    9.85 +	event.update.x = x;
    9.86 +	event.update.y = y;
    9.87 +	event.update.width = w;
    9.88 +	event.update.height = h;
    9.89 +
    9.90 +	prod = info->page->out_prod;
    9.91 +	/* caller ensures !xenfb_queue_full() */
    9.92 +	mb();			/* ensure ring space available */
    9.93 +	XENFB_OUT_RING_REF(info->page, prod) = event;
    9.94 +	wmb();			/* ensure ring contents visible */
    9.95 +	info->page->out_prod = prod + 1;
    9.96 +
    9.97 +	notify_remote_via_evtchn(info->evtchn);
    9.98 +}
    9.99 +
   9.100 +static int xenfb_queue_full(struct xenfb_info *info)
   9.101 +{
   9.102 +	__u32 cons, prod;
   9.103 +
   9.104 +	prod = info->page->out_prod;
   9.105 +	cons = info->page->out_cons;
   9.106 +	return prod - cons == XENFB_OUT_RING_LEN;
   9.107 +}
   9.108 +
   9.109 +static void xenfb_update_screen(struct xenfb_info *info)
   9.110 +{
   9.111 +	unsigned long flags;
   9.112 +	int y1, y2, x1, x2;
   9.113 +	struct xenfb_mapping *map;
   9.114 +
   9.115 +	if (!info->update_wanted)
   9.116 +		return;
   9.117 +	if (xenfb_queue_full(info))
   9.118 +		return;
   9.119 +
   9.120 +	spin_lock_irqsave(&info->mm_lock, flags);
   9.121 +
   9.122 +	y1 = info->y1;
   9.123 +	y2 = info->y2;
   9.124 +	x1 = info->x1;
   9.125 +	x2 = info->x2;
   9.126 +	info->x1 = info->y1 = INT_MAX;
   9.127 +	info->x2 = info->y2 = 0;
   9.128 +
   9.129 +	list_for_each_entry(map, &info->mappings, link) {
   9.130 +		if (!map->faults)
   9.131 +			continue;
   9.132 +		zap_page_range(map->vma, map->vma->vm_start,
   9.133 +			       map->vma->vm_end - map->vma->vm_start, NULL);
   9.134 +		map->faults = 0;
   9.135 +	}
   9.136 +
   9.137 +	spin_unlock_irqrestore(&info->mm_lock, flags);
   9.138 +
   9.139 +	xenfb_do_update(info, x1, y1, x2 - x1, y2 - y1);
   9.140 +}
   9.141 +
   9.142 +static int xenfb_thread(void *data)
   9.143 +{
   9.144 +	struct xenfb_info *info = data;
   9.145 +
   9.146 +	while (!kthread_should_stop()) {
   9.147 +		if (info->dirty) {
   9.148 +			info->dirty = 0;
   9.149 +			xenfb_update_screen(info);
   9.150 +		}
   9.151 +		wait_event_interruptible(info->wq,
   9.152 +			kthread_should_stop() || info->dirty);
   9.153 +		try_to_freeze();
   9.154 +	}
   9.155 +	return 0;
   9.156 +}
   9.157 +
   9.158 +static int xenfb_setcolreg(unsigned regno, unsigned red, unsigned green,
   9.159 +			   unsigned blue, unsigned transp,
   9.160 +			   struct fb_info *info)
   9.161 +{
   9.162 +	u32 v;
   9.163 +
   9.164 +	if (regno > info->cmap.len)
   9.165 +		return 1;
   9.166 +
   9.167 +	red   >>= (16 - info->var.red.length);
   9.168 +	green >>= (16 - info->var.green.length);
   9.169 +	blue  >>= (16 - info->var.blue.length);
   9.170 +
   9.171 +	v = (red << info->var.red.offset) |
   9.172 +	    (green << info->var.green.offset) |
   9.173 +	    (blue << info->var.blue.offset);
   9.174 +
   9.175 +	/* FIXME is this sane?  check against xxxfb_setcolreg()!  */
   9.176 +	switch (info->var.bits_per_pixel) {
   9.177 +	case 16:
   9.178 +	case 24:
   9.179 +	case 32:
   9.180 +		((u32 *)info->pseudo_palette)[regno] = v;
   9.181 +		break;
   9.182 +	}
   9.183 +	
   9.184 +	return 0;
   9.185 +}
   9.186 +
   9.187 +static void xenfb_timer(unsigned long data)
   9.188 +{
   9.189 +	struct xenfb_info *info = (struct xenfb_info *)data;
   9.190 +	info->dirty = 1;
   9.191 +	wake_up(&info->wq);
   9.192 +}
   9.193 +
   9.194 +static void __xenfb_refresh(struct xenfb_info *info,
   9.195 +			    int x1, int y1, int w, int h)
   9.196 +{
   9.197 +	int y2, x2;
   9.198 +
   9.199 +	y2 = y1 + h;
   9.200 +	x2 = x1 + w;
   9.201 +
   9.202 +	if (info->y1 > y1)
   9.203 +		info->y1 = y1;
   9.204 +	if (info->y2 < y2)
   9.205 +		info->y2 = y2;
   9.206 +	if (info->x1 > x1)
   9.207 +		info->x1 = x1;
   9.208 +	if (info->x2 < x2)
   9.209 +		info->x2 = x2;
   9.210 +
   9.211 +	if (timer_pending(&info->refresh))
   9.212 +		return;
   9.213 +
   9.214 +	mod_timer(&info->refresh, jiffies + HZ/xenfb_fps);
   9.215 +}
   9.216 +
   9.217 +static void xenfb_refresh(struct xenfb_info *info,
   9.218 +			  int x1, int y1, int w, int h)
   9.219 +{
   9.220 +	unsigned long flags;
   9.221 +
   9.222 +	spin_lock_irqsave(&info->mm_lock, flags);
   9.223 +	__xenfb_refresh(info, x1, y1, w, h);
   9.224 +	spin_unlock_irqrestore(&info->mm_lock, flags);
   9.225 +}
   9.226 +
   9.227 +static void xenfb_fillrect(struct fb_info *p, const struct fb_fillrect *rect)
   9.228 +{
   9.229 +	struct xenfb_info *info = p->par;
   9.230 +
   9.231 +	cfb_fillrect(p, rect);
   9.232 +	xenfb_refresh(info, rect->dx, rect->dy, rect->width, rect->height);
   9.233 +}
   9.234 +
   9.235 +static void xenfb_imageblit(struct fb_info *p, const struct fb_image *image)
   9.236 +{
   9.237 +	struct xenfb_info *info = p->par;
   9.238 +
   9.239 +	cfb_imageblit(p, image);
   9.240 +	xenfb_refresh(info, image->dx, image->dy, image->width, image->height);
   9.241 +}
   9.242 +
   9.243 +static void xenfb_copyarea(struct fb_info *p, const struct fb_copyarea *area)
   9.244 +{
   9.245 +	struct xenfb_info *info = p->par;
   9.246 +
   9.247 +	cfb_copyarea(p, area);
   9.248 +	xenfb_refresh(info, area->dx, area->dy, area->width, area->height);
   9.249 +}
   9.250 +
   9.251 +static void xenfb_vm_open(struct vm_area_struct *vma)
   9.252 +{
   9.253 +	struct xenfb_mapping *map = vma->vm_private_data;
   9.254 +	atomic_inc(&map->map_refs);
   9.255 +}
   9.256 +
   9.257 +static void xenfb_vm_close(struct vm_area_struct *vma)
   9.258 +{
   9.259 +	struct xenfb_mapping *map = vma->vm_private_data;
   9.260 +	struct xenfb_info *info = map->info;
   9.261 +	unsigned long flags;
   9.262 +
   9.263 +	spin_lock_irqsave(&info->mm_lock, flags);
   9.264 +	if (atomic_dec_and_test(&map->map_refs)) {
   9.265 +		list_del(&map->link);
   9.266 +		kfree(map);
   9.267 +	}
   9.268 +	spin_unlock_irqrestore(&info->mm_lock, flags);
   9.269 +}
   9.270 +
   9.271 +static struct page *xenfb_vm_nopage(struct vm_area_struct *vma,
   9.272 +				    unsigned long vaddr, int *type)
   9.273 +{
   9.274 +	struct xenfb_mapping *map = vma->vm_private_data;
   9.275 +	struct xenfb_info *info = map->info;
   9.276 +	int pgnr = (vaddr - vma->vm_start) >> PAGE_SHIFT;
   9.277 +	unsigned long flags;
   9.278 +	struct page *page;
   9.279 +	int y1, y2;
   9.280 +
   9.281 +	if (pgnr >= info->nr_pages)
   9.282 +		return NOPAGE_SIGBUS;
   9.283 +
   9.284 +	spin_lock_irqsave(&info->mm_lock, flags);
   9.285 +	page = info->pages[pgnr];
   9.286 +	get_page(page);
   9.287 +	map->faults++;
   9.288 +
   9.289 +	y1 = pgnr * PAGE_SIZE / info->fb_info->fix.line_length;
   9.290 +	y2 = (pgnr * PAGE_SIZE + PAGE_SIZE - 1) / info->fb_info->fix.line_length;
   9.291 +	if (y2 > info->fb_info->var.yres)
   9.292 +		y2 = info->fb_info->var.yres;
   9.293 +	__xenfb_refresh(info, 0, y1, info->fb_info->var.xres, y2 - y1);
   9.294 +	spin_unlock_irqrestore(&info->mm_lock, flags);
   9.295 +
   9.296 +	if (type)
   9.297 +		*type = VM_FAULT_MINOR;
   9.298 +
   9.299 +	return page;
   9.300 +}
   9.301 +
   9.302 +static struct vm_operations_struct xenfb_vm_ops = {
   9.303 +	.open	= xenfb_vm_open,
   9.304 +	.close	= xenfb_vm_close,
   9.305 +	.nopage	= xenfb_vm_nopage,
   9.306 +};
   9.307 +
   9.308 +static int xenfb_mmap(struct fb_info *fb_info, struct vm_area_struct *vma)
   9.309 +{
   9.310 +	struct xenfb_info *info = fb_info->par;
   9.311 +	unsigned long flags;
   9.312 +	struct xenfb_mapping *map;
   9.313 +	int map_pages;
   9.314 +
   9.315 +	if (!(vma->vm_flags & VM_WRITE))
   9.316 +		return -EINVAL;
   9.317 +	if (!(vma->vm_flags & VM_SHARED))
   9.318 +		return -EINVAL;
   9.319 +	if (vma->vm_pgoff != 0)
   9.320 +		return -EINVAL;
   9.321 +
   9.322 +	map_pages = (vma->vm_end - vma->vm_start + PAGE_SIZE-1) >> PAGE_SHIFT;
   9.323 +	if (map_pages > info->nr_pages)
   9.324 +		return -EINVAL;
   9.325 +
   9.326 +	map = kzalloc(sizeof(*map), GFP_KERNEL);
   9.327 +	if (map == NULL)
   9.328 +		return -ENOMEM;
   9.329 +
   9.330 +	map->vma = vma;
   9.331 +	map->faults = 0;
   9.332 +	map->info = info;
   9.333 +	atomic_set(&map->map_refs, 1);
   9.334 +
   9.335 +	spin_lock_irqsave(&info->mm_lock, flags);
   9.336 +	list_add(&map->link, &info->mappings);
   9.337 +	spin_unlock_irqrestore(&info->mm_lock, flags);
   9.338 +
   9.339 +	vma->vm_ops = &xenfb_vm_ops;
   9.340 +	vma->vm_flags |= (VM_DONTEXPAND | VM_RESERVED);
   9.341 +	vma->vm_private_data = map;
   9.342 +
   9.343 +	return 0;
   9.344 +}
   9.345 +
   9.346 +static struct fb_ops xenfb_fb_ops = {
   9.347 +	.owner		= THIS_MODULE,
   9.348 +	.fb_setcolreg	= xenfb_setcolreg,
   9.349 +	.fb_fillrect	= xenfb_fillrect,
   9.350 +	.fb_copyarea	= xenfb_copyarea,
   9.351 +	.fb_imageblit	= xenfb_imageblit,
   9.352 +	.fb_mmap	= xenfb_mmap,
   9.353 +};
   9.354 +
   9.355 +static irqreturn_t xenfb_event_handler(int rq, void *dev_id,
   9.356 +				       struct pt_regs *regs)
   9.357 +{
   9.358 +	/*
   9.359 +	 * No in events recognized, simply ignore them all.
   9.360 +	 * If you need to recognize some, see xenbkd's input_handler()
   9.361 +	 * for how to do that.
   9.362 +	 */
   9.363 +	struct xenfb_info *info = dev_id;
   9.364 +	struct xenfb_page *page = info->page;
   9.365 +
   9.366 +	if (page->in_cons != page->in_prod) {
   9.367 +		info->page->in_cons = info->page->in_prod;
   9.368 +		notify_remote_via_evtchn(info->evtchn);
   9.369 +	}
   9.370 +	return IRQ_HANDLED;
   9.371 +}
   9.372 +
   9.373 +static unsigned long vmalloc_to_mfn(void *address)
   9.374 +{
   9.375 +	return pfn_to_mfn(vmalloc_to_pfn(address));
   9.376 +}
   9.377 +
   9.378 +static int __devinit xenfb_probe(struct xenbus_device *dev,
   9.379 +				 const struct xenbus_device_id *id)
   9.380 +{
   9.381 +	struct xenfb_info *info;
   9.382 +	struct fb_info *fb_info;
   9.383 +	int ret;
   9.384 +
   9.385 +	info = kzalloc(sizeof(*info), GFP_KERNEL);
   9.386 +	if (info == NULL) {
   9.387 +		xenbus_dev_fatal(dev, -ENOMEM, "allocating info structure");
   9.388 +		return -ENOMEM;
   9.389 +	}
   9.390 +	dev->dev.driver_data = info;
   9.391 +	info->xbdev = dev;
   9.392 +	info->irq = -1;
   9.393 +	info->x1 = info->y1 = INT_MAX;
   9.394 +	spin_lock_init(&info->mm_lock);
   9.395 +	init_waitqueue_head(&info->wq);
   9.396 +	init_timer(&info->refresh);
   9.397 +	info->refresh.function = xenfb_timer;
   9.398 +	info->refresh.data = (unsigned long)info;
   9.399 +	INIT_LIST_HEAD(&info->mappings);
   9.400 +
   9.401 +	info->fb = vmalloc(xenfb_mem_len);
   9.402 +	if (info->fb == NULL)
   9.403 +		goto error_nomem;
   9.404 +	memset(info->fb, 0, xenfb_mem_len);
   9.405 +
   9.406 +	info->nr_pages = (xenfb_mem_len + PAGE_SIZE - 1) >> PAGE_SHIFT;
   9.407 +
   9.408 +	info->pages = kmalloc(sizeof(struct page *) * info->nr_pages,
   9.409 +			      GFP_KERNEL);
   9.410 +	if (info->pages == NULL)
   9.411 +		goto error_nomem;
   9.412 +
   9.413 +	info->mfns = vmalloc(sizeof(unsigned long) * info->nr_pages);
   9.414 +	if (!info->mfns)
   9.415 +		goto error_nomem;
   9.416 +
   9.417 +	/* set up shared page */
   9.418 +	info->page = (void *)__get_free_page(GFP_KERNEL);
   9.419 +	if (!info->page)
   9.420 +		goto error_nomem;
   9.421 +
   9.422 +	xenfb_init_shared_page(info);
   9.423 +
   9.424 +	fb_info = framebuffer_alloc(sizeof(u32) * 256, NULL);
   9.425 +				/* see fishy hackery below */
   9.426 +	if (fb_info == NULL)
   9.427 +		goto error_nomem;
   9.428 +
   9.429 +	/* FIXME fishy hackery */
   9.430 +	fb_info->pseudo_palette = fb_info->par;
   9.431 +	fb_info->par = info;
   9.432 +	/* /FIXME */
   9.433 +	fb_info->screen_base = info->fb;
   9.434 +
   9.435 +	fb_info->fbops = &xenfb_fb_ops;
   9.436 +	fb_info->var.xres_virtual = fb_info->var.xres = info->page->width;
   9.437 +	fb_info->var.yres_virtual = fb_info->var.yres = info->page->height;
   9.438 +	fb_info->var.bits_per_pixel = info->page->depth;
   9.439 +
   9.440 +	fb_info->var.red = (struct fb_bitfield){16, 8, 0};
   9.441 +	fb_info->var.green = (struct fb_bitfield){8, 8, 0};
   9.442 +	fb_info->var.blue = (struct fb_bitfield){0, 8, 0};
   9.443 +
   9.444 +	fb_info->var.activate = FB_ACTIVATE_NOW;
   9.445 +	fb_info->var.height = -1;
   9.446 +	fb_info->var.width = -1;
   9.447 +	fb_info->var.vmode = FB_VMODE_NONINTERLACED;
   9.448 +
   9.449 +	fb_info->fix.visual = FB_VISUAL_TRUECOLOR;
   9.450 +	fb_info->fix.line_length = info->page->line_length;
   9.451 +	fb_info->fix.smem_start = 0;
   9.452 +	fb_info->fix.smem_len = xenfb_mem_len;
   9.453 +	strcpy(fb_info->fix.id, "xen");
   9.454 +	fb_info->fix.type = FB_TYPE_PACKED_PIXELS;
   9.455 +	fb_info->fix.accel = FB_ACCEL_NONE;
   9.456 +
   9.457 +	fb_info->flags = FBINFO_FLAG_DEFAULT;
   9.458 +
   9.459 +	ret = fb_alloc_cmap(&fb_info->cmap, 256, 0);
   9.460 +	if (ret < 0) {
   9.461 +		framebuffer_release(fb_info);
   9.462 +		xenbus_dev_fatal(dev, ret, "fb_alloc_cmap");
   9.463 +		goto error;
   9.464 +	}
   9.465 +
   9.466 +	ret = register_framebuffer(fb_info);
   9.467 +	if (ret) {
   9.468 +		fb_dealloc_cmap(&info->fb_info->cmap);
   9.469 +		framebuffer_release(fb_info);
   9.470 +		xenbus_dev_fatal(dev, ret, "register_framebuffer");
   9.471 +		goto error;
   9.472 +	}
   9.473 +	info->fb_info = fb_info;
   9.474 +
   9.475 +	/* FIXME should this be delayed until backend XenbusStateConnected? */
   9.476 +	info->kthread = kthread_run(xenfb_thread, info, "xenfb thread");
   9.477 +	if (IS_ERR(info->kthread)) {
   9.478 +		ret = PTR_ERR(info->kthread);
   9.479 +		info->kthread = NULL;
   9.480 +		xenbus_dev_fatal(dev, ret, "register_framebuffer");
   9.481 +		goto error;
   9.482 +	}
   9.483 +
   9.484 +	ret = xenfb_connect_backend(dev, info);
   9.485 +	if (ret < 0)
   9.486 +		goto error;
   9.487 +
   9.488 +	return 0;
   9.489 +
   9.490 + error_nomem:
   9.491 +	ret = -ENOMEM;
   9.492 +	xenbus_dev_fatal(dev, ret, "allocating device memory");
   9.493 + error:
   9.494 +	xenfb_remove(dev);
   9.495 +	return ret;
   9.496 +}
   9.497 +
   9.498 +static int xenfb_resume(struct xenbus_device *dev)
   9.499 +{
   9.500 +	struct xenfb_info *info = dev->dev.driver_data;
   9.501 +
   9.502 +	xenfb_disconnect_backend(info);
   9.503 +	xenfb_init_shared_page(info);
   9.504 +	return xenfb_connect_backend(dev, info);
   9.505 +}
   9.506 +
   9.507 +static int xenfb_remove(struct xenbus_device *dev)
   9.508 +{
   9.509 +	struct xenfb_info *info = dev->dev.driver_data;
   9.510 +
   9.511 +	del_timer(&info->refresh);
   9.512 +	if (info->kthread)
   9.513 +		kthread_stop(info->kthread);
   9.514 +	xenfb_disconnect_backend(info);
   9.515 +	if (info->fb_info) {
   9.516 +		unregister_framebuffer(info->fb_info);
   9.517 +		fb_dealloc_cmap(&info->fb_info->cmap);
   9.518 +		framebuffer_release(info->fb_info);
   9.519 +	}
   9.520 +	free_page((unsigned long)info->page);
   9.521 +	vfree(info->mfns);
   9.522 +	kfree(info->pages);
   9.523 +	vfree(info->fb);
   9.524 +	kfree(info);
   9.525 +
   9.526 +	return 0;
   9.527 +}
   9.528 +
   9.529 +static void xenfb_init_shared_page(struct xenfb_info *info)
   9.530 +{
   9.531 +	int i;
   9.532 +
   9.533 +	for (i = 0; i < info->nr_pages; i++)
   9.534 +		info->pages[i] = vmalloc_to_page(info->fb + i * PAGE_SIZE);
   9.535 +
   9.536 +	for (i = 0; i < info->nr_pages; i++)
   9.537 +		info->mfns[i] = vmalloc_to_mfn(info->fb + i * PAGE_SIZE);
   9.538 +
   9.539 +	info->page->pd[0] = vmalloc_to_mfn(info->mfns);
   9.540 +	info->page->pd[1] = 0;
   9.541 +	info->page->width = XENFB_WIDTH;
   9.542 +	info->page->height = XENFB_HEIGHT;
   9.543 +	info->page->depth = XENFB_DEPTH;
   9.544 +	info->page->line_length = (info->page->depth / 8) * info->page->width;
   9.545 +	info->page->mem_length = xenfb_mem_len;
   9.546 +	info->page->in_cons = info->page->in_prod = 0;
   9.547 +	info->page->out_cons = info->page->out_prod = 0;
   9.548 +}
   9.549 +
   9.550 +static int xenfb_connect_backend(struct xenbus_device *dev,
   9.551 +				 struct xenfb_info *info)
   9.552 +{
   9.553 +	int ret;
   9.554 +	struct xenbus_transaction xbt;
   9.555 +
   9.556 +	ret = xenbus_alloc_evtchn(dev, &info->evtchn);
   9.557 +	if (ret)
   9.558 +		return ret;
   9.559 +	ret = bind_evtchn_to_irqhandler(info->evtchn, xenfb_event_handler,
   9.560 +					0, "xenfb", info);
   9.561 +	if (ret < 0) {
   9.562 +		xenbus_free_evtchn(dev, info->evtchn);
   9.563 +		xenbus_dev_fatal(dev, ret, "bind_evtchn_to_irqhandler");
   9.564 +		return ret;
   9.565 +	}
   9.566 +	info->irq = ret;
   9.567 +
   9.568 + again:
   9.569 +	ret = xenbus_transaction_start(&xbt);
   9.570 +	if (ret) {
   9.571 +		xenbus_dev_fatal(dev, ret, "starting transaction");
   9.572 +		return ret;
   9.573 +	}
   9.574 +	ret = xenbus_printf(xbt, dev->nodename, "page-ref", "%lu",
   9.575 +			    virt_to_mfn(info->page));
   9.576 +	if (ret)
   9.577 +		goto error_xenbus;
   9.578 +	ret = xenbus_printf(xbt, dev->nodename, "event-channel", "%u",
   9.579 +			    info->evtchn);
   9.580 +	if (ret)
   9.581 +		goto error_xenbus;
   9.582 +	ret = xenbus_printf(xbt, dev->nodename, "feature-update", "1");
   9.583 +	if (ret)
   9.584 +		goto error_xenbus;
   9.585 +	ret = xenbus_transaction_end(xbt, 0);
   9.586 +	if (ret) {
   9.587 +		if (ret == -EAGAIN)
   9.588 +			goto again;
   9.589 +		xenbus_dev_fatal(dev, ret, "completing transaction");
   9.590 +		return ret;
   9.591 +	}
   9.592 +
   9.593 +	xenbus_switch_state(dev, XenbusStateInitialised);
   9.594 +	return 0;
   9.595 +
   9.596 + error_xenbus:
   9.597 +	xenbus_transaction_end(xbt, 1);
   9.598 +	xenbus_dev_fatal(dev, ret, "writing xenstore");
   9.599 +	return ret;
   9.600 +}
   9.601 +
   9.602 +static void xenfb_disconnect_backend(struct xenfb_info *info)
   9.603 +{
   9.604 +	if (info->irq >= 0)
   9.605 +		unbind_from_irqhandler(info->irq, info);
   9.606 +	info->irq = -1;
   9.607 +}
   9.608 +
   9.609 +static void xenfb_backend_changed(struct xenbus_device *dev,
   9.610 +				  enum xenbus_state backend_state)
   9.611 +{
   9.612 +	struct xenfb_info *info = dev->dev.driver_data;
   9.613 +	int val;
   9.614 +
   9.615 +	switch (backend_state) {
   9.616 +	case XenbusStateInitialising:
   9.617 +	case XenbusStateInitialised:
   9.618 +	case XenbusStateUnknown:
   9.619 +	case XenbusStateClosed:
   9.620 +		break;
   9.621 +
   9.622 +	case XenbusStateInitWait:
   9.623 +	InitWait:
   9.624 +		xenbus_switch_state(dev, XenbusStateConnected);
   9.625 +		break;
   9.626 +
   9.627 +	case XenbusStateConnected:
   9.628 +		/*
   9.629 +		 * Work around xenbus race condition: If backend goes
   9.630 +		 * through InitWait to Connected fast enough, we can
   9.631 +		 * get Connected twice here.
   9.632 +		 */
   9.633 +		if (dev->state != XenbusStateConnected)
   9.634 +			goto InitWait; /* no InitWait seen yet, fudge it */
   9.635 +
   9.636 +		if (xenbus_scanf(XBT_NIL, info->xbdev->otherend,
   9.637 +				 "request-update", "%d", &val) < 0)
   9.638 +			val = 0;
   9.639 +		if (val)
   9.640 +			info->update_wanted = 1;
   9.641 +		break;
   9.642 +
   9.643 +	case XenbusStateClosing:
   9.644 +		// FIXME is this safe in any dev->state?
   9.645 +		xenbus_frontend_closed(dev);
   9.646 +		break;
   9.647 +	}
   9.648 +}
   9.649 +
   9.650 +static struct xenbus_device_id xenfb_ids[] = {
   9.651 +	{ "vfb" },
   9.652 +	{ "" }
   9.653 +};
   9.654 +
   9.655 +static struct xenbus_driver xenfb = {
   9.656 +	.name = "vfb",
   9.657 +	.owner = THIS_MODULE,
   9.658 +	.ids = xenfb_ids,
   9.659 +	.probe = xenfb_probe,
   9.660 +	.remove = xenfb_remove,
   9.661 +	.resume = xenfb_resume,
   9.662 +	.otherend_changed = xenfb_backend_changed,
   9.663 +};
   9.664 +
   9.665 +static int __init xenfb_init(void)
   9.666 +{
   9.667 +	if (!is_running_on_xen())
   9.668 +		return -ENODEV;
   9.669 +
   9.670 +	/* Nothing to do if running in dom0. */
   9.671 +	if (is_initial_xendomain())
   9.672 +		return -ENODEV;
   9.673 +
   9.674 +	return xenbus_register_frontend(&xenfb);
   9.675 +}
   9.676 +
   9.677 +static void __exit xenfb_cleanup(void)
   9.678 +{
   9.679 +	return xenbus_unregister_driver(&xenfb);
   9.680 +}
   9.681 +
   9.682 +module_init(xenfb_init);
   9.683 +module_exit(xenfb_cleanup);
   9.684 +
   9.685 +MODULE_LICENSE("GPL");
    10.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    10.2 +++ b/linux-2.6-xen-sparse/drivers/xen/fbfront/xenkbd.c	Fri Dec 01 09:48:32 2006 +0000
    10.3 @@ -0,0 +1,300 @@
    10.4 +/*
    10.5 + * linux/drivers/input/keyboard/xenkbd.c -- Xen para-virtual input device
    10.6 + *
    10.7 + * Copyright (C) 2005 Anthony Liguori <aliguori@us.ibm.com>
    10.8 + * Copyright (C) 2006 Red Hat, Inc., Markus Armbruster <armbru@redhat.com>
    10.9 + *
   10.10 + *  Based on linux/drivers/input/mouse/sermouse.c
   10.11 + *
   10.12 + *  This file is subject to the terms and conditions of the GNU General Public
   10.13 + *  License. See the file COPYING in the main directory of this archive for
   10.14 + *  more details.
   10.15 + */
   10.16 +
   10.17 +/*
   10.18 + * TODO:
   10.19 + *
   10.20 + * Switch to grant tables together with xenfb.c.
   10.21 + */
   10.22 +
   10.23 +#include <linux/kernel.h>
   10.24 +#include <linux/errno.h>
   10.25 +#include <linux/module.h>
   10.26 +#include <linux/input.h>
   10.27 +#include <asm/hypervisor.h>
   10.28 +#include <xen/evtchn.h>
   10.29 +#include <xen/interface/io/fbif.h>
   10.30 +#include <xen/interface/io/kbdif.h>
   10.31 +#include <xen/xenbus.h>
   10.32 +
   10.33 +struct xenkbd_info
   10.34 +{
   10.35 +	struct input_dev *dev;
   10.36 +	struct xenkbd_page *page;
   10.37 +	unsigned evtchn;
   10.38 +	int irq;
   10.39 +	struct xenbus_device *xbdev;
   10.40 +};
   10.41 +
   10.42 +static int xenkbd_remove(struct xenbus_device *);
   10.43 +static int xenkbd_connect_backend(struct xenbus_device *, struct xenkbd_info *);
   10.44 +static void xenkbd_disconnect_backend(struct xenkbd_info *);
   10.45 +
   10.46 +/*
   10.47 + * Note: if you need to send out events, see xenfb_do_update() for how
   10.48 + * to do that.
   10.49 + */
   10.50 +
   10.51 +static irqreturn_t input_handler(int rq, void *dev_id, struct pt_regs *regs)
   10.52 +{
   10.53 +	struct xenkbd_info *info = dev_id;
   10.54 +	struct xenkbd_page *page = info->page;
   10.55 +	__u32 cons, prod;
   10.56 +
   10.57 +	prod = page->in_prod;
   10.58 +	if (prod == page->out_cons)
   10.59 +		return IRQ_HANDLED;
   10.60 +	rmb();			/* ensure we see ring contents up to prod */
   10.61 +	for (cons = page->in_cons; cons != prod; cons++) {
   10.62 +		union xenkbd_in_event *event;
   10.63 +		event = &XENKBD_IN_RING_REF(page, cons);
   10.64 +
   10.65 +		switch (event->type) {
   10.66 +		case XENKBD_TYPE_MOTION:
   10.67 +			input_report_rel(info->dev, REL_X, event->motion.rel_x);
   10.68 +			input_report_rel(info->dev, REL_Y, event->motion.rel_y);
   10.69 +			break;
   10.70 +		case XENKBD_TYPE_KEY:
   10.71 +			input_report_key(info->dev, event->key.keycode, event->key.pressed);
   10.72 +			break;
   10.73 +		case XENKBD_TYPE_POS:
   10.74 +			input_report_abs(info->dev, ABS_X, event->pos.abs_x);
   10.75 +			input_report_abs(info->dev, ABS_Y, event->pos.abs_y);
   10.76 +			break;
   10.77 +		}
   10.78 +	}
   10.79 +	input_sync(info->dev);
   10.80 +	mb();			/* ensure we got ring contents */
   10.81 +	page->in_cons = cons;
   10.82 +	notify_remote_via_evtchn(info->evtchn);
   10.83 +
   10.84 +	return IRQ_HANDLED;
   10.85 +}
   10.86 +
   10.87 +int __devinit xenkbd_probe(struct xenbus_device *dev,
   10.88 +			   const struct xenbus_device_id *id)
   10.89 +{
   10.90 +	int ret, i;
   10.91 +	struct xenkbd_info *info;
   10.92 +	struct input_dev *input_dev;
   10.93 +
   10.94 +	info = kzalloc(sizeof(*info), GFP_KERNEL);
   10.95 +	if (!info) {
   10.96 +		xenbus_dev_fatal(dev, -ENOMEM, "allocating info structure");
   10.97 +		return -ENOMEM;
   10.98 +	}
   10.99 +	dev->dev.driver_data = info;
  10.100 +	info->xbdev = dev;
  10.101 +
  10.102 +	info->page = (void *)__get_free_page(GFP_KERNEL);
  10.103 +	if (!info->page)
  10.104 +		goto error_nomem;
  10.105 +	info->page->in_cons = info->page->in_prod = 0;
  10.106 +	info->page->out_cons = info->page->out_prod = 0;
  10.107 +
  10.108 +	input_dev = input_allocate_device();
  10.109 +	if (!input_dev)
  10.110 +		goto error_nomem;
  10.111 +
  10.112 +	input_dev->evbit[0] = BIT(EV_KEY) | BIT(EV_REL) | BIT(EV_ABS);
  10.113 +	input_dev->keybit[LONG(BTN_MOUSE)]
  10.114 +		= BIT(BTN_LEFT) | BIT(BTN_MIDDLE) | BIT(BTN_RIGHT);
  10.115 +	/* TODO additional buttons */
  10.116 +	input_dev->relbit[0] = BIT(REL_X) | BIT(REL_Y);
  10.117 +
  10.118 +	/* FIXME not sure this is quite right */
  10.119 +	for (i = 0; i < 256; i++)
  10.120 +		set_bit(i, input_dev->keybit);
  10.121 +
  10.122 +	input_dev->name = "Xen Virtual Keyboard/Mouse";
  10.123 +
  10.124 +	input_set_abs_params(input_dev, ABS_X, 0, XENFB_WIDTH, 0, 0);
  10.125 +	input_set_abs_params(input_dev, ABS_Y, 0, XENFB_HEIGHT, 0, 0);
  10.126 +
  10.127 +	ret = input_register_device(input_dev);
  10.128 +	if (ret) {
  10.129 +		input_free_device(input_dev);
  10.130 +		xenbus_dev_fatal(dev, ret, "input_register_device");
  10.131 +		goto error;
  10.132 +	}
  10.133 +	info->dev = input_dev;
  10.134 +
  10.135 +	ret = xenkbd_connect_backend(dev, info);
  10.136 +	if (ret < 0)
  10.137 +		goto error;
  10.138 +
  10.139 +	return 0;
  10.140 +
  10.141 + error_nomem:
  10.142 +	ret = -ENOMEM;
  10.143 +	xenbus_dev_fatal(dev, ret, "allocating device memory");
  10.144 + error:
  10.145 +	xenkbd_remove(dev);
  10.146 +	return ret;
  10.147 +}
  10.148 +
  10.149 +static int xenkbd_resume(struct xenbus_device *dev)
  10.150 +{
  10.151 +	struct xenkbd_info *info = dev->dev.driver_data;
  10.152 +
  10.153 +	xenkbd_disconnect_backend(info);
  10.154 +	return xenkbd_connect_backend(dev, info);
  10.155 +}
  10.156 +
  10.157 +static int xenkbd_remove(struct xenbus_device *dev)
  10.158 +{
  10.159 +	struct xenkbd_info *info = dev->dev.driver_data;
  10.160 +
  10.161 +	xenkbd_disconnect_backend(info);
  10.162 +	input_unregister_device(info->dev);
  10.163 +	free_page((unsigned long)info->page);
  10.164 +	kfree(info);
  10.165 +	return 0;
  10.166 +}
  10.167 +
  10.168 +static int xenkbd_connect_backend(struct xenbus_device *dev,
  10.169 +				  struct xenkbd_info *info)
  10.170 +{
  10.171 +	int ret;
  10.172 +	struct xenbus_transaction xbt;
  10.173 +
  10.174 +	ret = xenbus_alloc_evtchn(dev, &info->evtchn);
  10.175 +	if (ret)
  10.176 +		return ret;
  10.177 +	ret = bind_evtchn_to_irqhandler(info->evtchn, input_handler, 0,
  10.178 +					"xenkbd", info);
  10.179 +	if (ret < 0) {
  10.180 +		xenbus_free_evtchn(dev, info->evtchn);
  10.181 +		xenbus_dev_fatal(dev, ret, "bind_evtchn_to_irqhandler");
  10.182 +		return ret;
  10.183 +	}
  10.184 +	info->irq = ret;
  10.185 +
  10.186 + again:
  10.187 +	ret = xenbus_transaction_start(&xbt);
  10.188 +	if (ret) {
  10.189 +		xenbus_dev_fatal(dev, ret, "starting transaction");
  10.190 +		return ret;
  10.191 +	}
  10.192 +	ret = xenbus_printf(xbt, dev->nodename, "page-ref", "%lu",
  10.193 +			    virt_to_mfn(info->page));
  10.194 +	if (ret)
  10.195 +		goto error_xenbus;
  10.196 +	ret = xenbus_printf(xbt, dev->nodename, "event-channel", "%u",
  10.197 +			    info->evtchn);
  10.198 +	if (ret)
  10.199 +		goto error_xenbus;
  10.200 +	ret = xenbus_transaction_end(xbt, 0);
  10.201 +	if (ret) {
  10.202 +		if (ret == -EAGAIN)
  10.203 +			goto again;
  10.204 +		xenbus_dev_fatal(dev, ret, "completing transaction");
  10.205 +		return ret;
  10.206 +	}
  10.207 +
  10.208 +	xenbus_switch_state(dev, XenbusStateInitialised);
  10.209 +	return 0;
  10.210 +
  10.211 + error_xenbus:
  10.212 +	xenbus_transaction_end(xbt, 1);
  10.213 +	xenbus_dev_fatal(dev, ret, "writing xenstore");
  10.214 +	return ret;
  10.215 +}
  10.216 +
  10.217 +static void xenkbd_disconnect_backend(struct xenkbd_info *info)
  10.218 +{
  10.219 +	if (info->irq >= 0)
  10.220 +		unbind_from_irqhandler(info->irq, info);
  10.221 +	info->irq = -1;
  10.222 +}
  10.223 +
  10.224 +static void xenkbd_backend_changed(struct xenbus_device *dev,
  10.225 +				   enum xenbus_state backend_state)
  10.226 +{
  10.227 +	struct xenkbd_info *info = dev->dev.driver_data;
  10.228 +	int ret, val;
  10.229 +
  10.230 +	switch (backend_state) {
  10.231 +	case XenbusStateInitialising:
  10.232 +	case XenbusStateInitialised:
  10.233 +	case XenbusStateUnknown:
  10.234 +	case XenbusStateClosed:
  10.235 +		break;
  10.236 +
  10.237 +	case XenbusStateInitWait:
  10.238 +	InitWait:
  10.239 +		ret = xenbus_scanf(XBT_NIL, info->xbdev->otherend,
  10.240 +				   "feature-abs-pointer", "%d", &val);
  10.241 +		if (ret < 0)
  10.242 +			val = 0;
  10.243 +		if (val) {
  10.244 +			ret = xenbus_printf(XBT_NIL, info->xbdev->nodename,
  10.245 +					    "request-abs-pointer", "1");
  10.246 +			if (ret)
  10.247 +				; /* FIXME */
  10.248 +		}
  10.249 +		xenbus_switch_state(dev, XenbusStateConnected);
  10.250 +		break;
  10.251 +
  10.252 +	case XenbusStateConnected:
  10.253 +		/*
  10.254 +		 * Work around xenbus race condition: If backend goes
  10.255 +		 * through InitWait to Connected fast enough, we can
  10.256 +		 * get Connected twice here.
  10.257 +		 */
  10.258 +		if (dev->state != XenbusStateConnected)
  10.259 +			goto InitWait; /* no InitWait seen yet, fudge it */
  10.260 +		break;
  10.261 +
  10.262 +	case XenbusStateClosing:
  10.263 +		xenbus_frontend_closed(dev);
  10.264 +		break;
  10.265 +	}
  10.266 +}
  10.267 +
  10.268 +static struct xenbus_device_id xenkbd_ids[] = {
  10.269 +	{ "vkbd" },
  10.270 +	{ "" }
  10.271 +};
  10.272 +
  10.273 +static struct xenbus_driver xenkbd = {
  10.274 +	.name = "vkbd",
  10.275 +	.owner = THIS_MODULE,
  10.276 +	.ids = xenkbd_ids,
  10.277 +	.probe = xenkbd_probe,
  10.278 +	.remove = xenkbd_remove,
  10.279 +	.resume = xenkbd_resume,
  10.280 +	.otherend_changed = xenkbd_backend_changed,
  10.281 +};
  10.282 +
  10.283 +static int __init xenkbd_init(void)
  10.284 +{
  10.285 +	if (!is_running_on_xen())
  10.286 +		return -ENODEV;
  10.287 +
  10.288 +	/* Nothing to do if running in dom0. */
  10.289 +	if (is_initial_xendomain())
  10.290 +		return -ENODEV;
  10.291 +
  10.292 +	return xenbus_register_frontend(&xenkbd);
  10.293 +}
  10.294 +
  10.295 +static void __exit xenkbd_cleanup(void)
  10.296 +{
  10.297 +	return xenbus_unregister_driver(&xenkbd);
  10.298 +}
  10.299 +
  10.300 +module_init(xenkbd_init);
  10.301 +module_exit(xenkbd_cleanup);
  10.302 +
  10.303 +MODULE_LICENSE("GPL");
    11.1 --- a/linux-2.6-xen-sparse/mm/memory.c	Fri Dec 01 09:28:14 2006 +0000
    11.2 +++ b/linux-2.6-xen-sparse/mm/memory.c	Fri Dec 01 09:48:32 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 09:28:14 2006 +0000
    12.2 +++ b/tools/Makefile	Fri Dec 01 09:48:32 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 09:28:14 2006 +0000
    13.2 +++ b/tools/python/xen/xend/XendDevices.py	Fri Dec 01 09:48:32 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 --- a/tools/python/xen/xend/XendDomainInfo.py	Fri Dec 01 09:28:14 2006 +0000
    14.2 +++ b/tools/python/xen/xend/XendDomainInfo.py	Fri Dec 01 09:48:32 2006 +0000
    14.3 @@ -458,7 +458,7 @@ class XendDomainInfo:
    14.4              try:
    14.5                  self._constructDomain()
    14.6                  self._storeVmDetails()
    14.7 -                self._createDevices()
    14.8 +                self._restoreDomain()
    14.9                  self._createChannels()
   14.10                  self._storeDomDetails()
   14.11                  self._endRestore()
   14.12 @@ -1387,6 +1387,23 @@ class XendDomainInfo:
   14.13              raise VmError(str(exn))
   14.14  
   14.15  
   14.16 +    def _restoreDomain(self):
   14.17 +        log.debug('XendDomainInfo.restoreDomain: %s %s',
   14.18 +                  self.domid,
   14.19 +                  self.info['cpu_weight'])
   14.20 +
   14.21 +        if not self.infoIsSet('image'):
   14.22 +            raise VmError('Missing image in configuration')
   14.23 +
   14.24 +        try:
   14.25 +            self.image = image.create(self,
   14.26 +                                      self.info['image'],
   14.27 +                                      self.info['device'])
   14.28 +
   14.29 +            self._createDevices()
   14.30 +        except RuntimeError, exn:
   14.31 +            raise VmError(str(exn))
   14.32 +
   14.33      def cleanupDomain(self):
   14.34          """Cleanup domain resources; release devices.  Idempotent.  Nothrow
   14.35          guarantee."""
    15.1 --- a/tools/python/xen/xend/image.py	Fri Dec 01 09:28:14 2006 +0000
    15.2 +++ b/tools/python/xen/xend/image.py	Fri Dec 01 09:48:32 2006 +0000
    15.3 @@ -23,6 +23,7 @@ import math
    15.4  import signal
    15.5  
    15.6  import xen.lowlevel.xc
    15.7 +import xen.util.auxbin
    15.8  from xen.xend.XendConstants import REVERSE_DOMAIN_SHUTDOWN_REASONS
    15.9  from xen.xend.XendError import VmError, XendError
   15.10  from xen.xend.XendLogging import log
   15.11 @@ -199,6 +200,79 @@ class LinuxImageHandler(ImageHandler):
   15.12                                ramdisk        = self.ramdisk,
   15.13                                features       = self.vm.getFeatures())
   15.14  
   15.15 +    def configure(self, imageConfig, deviceConfig):
   15.16 +        ImageHandler.configure(self, imageConfig, deviceConfig)
   15.17 +
   15.18 +        self.pid = 0
   15.19 +        log.info("configuring linux guest")
   15.20 +
   15.21 +        # set up the graphics bits.
   15.22 +        # FIXME: this is much like what we do for HVM, should it be 
   15.23 +        # for all image types now?
   15.24 +        self.display = sxp.child_value(imageConfig, 'display')
   15.25 +        self.xauthority = sxp.child_value(imageConfig, 'xauthority')
   15.26 +        self.vncconsole = sxp.child_value(imageConfig, 'vncconsole')
   15.27 +        vncpasswd = sxp.child_value(imageConfig, 'vncpasswd')
   15.28 +        self.vncpasswd = vncpasswd
   15.29 +
   15.30 +        self.vnc = sxp.child_value(imageConfig, 'vnc')
   15.31 +        self.sdl = sxp.child_value(imageConfig, 'sdl')
   15.32 +        if self.vnc:
   15.33 +            self.vncdisplay = int(sxp.child_value(imageConfig, 'vncdisplay',
   15.34 +                                                  self.vm.getDomid()))
   15.35 +            self.vncunused = sxp.child_value(imageConfig, 'vncunused')
   15.36 +            self.vnclisten = sxp.child_value(imageConfig, 'vnclisten')
   15.37 +            if not(self.vnclisten):
   15.38 +                self.vnclisten = xen.xend.XendRoot.instance().get_vnclisten_address()
   15.39 +
   15.40 +    def createDeviceModel(self):
   15.41 +        if self.pid:
   15.42 +            return
   15.43 +        # Execute device model (for us, it's just the fb frontend)
   15.44 +        if not self.vnc and not self.sdl:
   15.45 +            return
   15.46 +
   15.47 +        if self.vnc:
   15.48 +            args = [xen.util.auxbin.pathTo("xen-vncfb")]
   15.49 +            if self.vncunused:
   15.50 +                args += ['--unused']
   15.51 +            elif self.vncdisplay:
   15.52 +                args += [ "--vncport", "%d" %(5900 + self.vncdisplay,) ]
   15.53 +            if self.vnclisten:
   15.54 +                args += [ "--listen", self.vnclisten ]
   15.55 +
   15.56 +            # password check
   15.57 +            if self.vncpasswd is None:
   15.58 +                # get password from xend-config(if password omitted, None)
   15.59 +                self.vncpasswd = xen.xend.XendRoot.instance().get_vncpasswd_default()
   15.60 +
   15.61 +                if self.vncpasswd is None:
   15.62 +                    raise VmError('vncpasswd is not setup in the guest config or xend-config.')
   15.63 +            if self.vncpasswd != '':
   15.64 +                self.vm.storeVm("vncpasswd", self.vncpasswd)
   15.65 +                log.info("vncpassword set to '%s'", self.vncpasswd)
   15.66 +
   15.67 +        elif self.sdl:
   15.68 +            args = [xen.util.auxbin.pathTo("xen-sdlfb")]
   15.69 +        args = args + [ "--domid", "%d" % self.vm.getDomid(),
   15.70 +                        "--title", self.vm.info['name'] ]
   15.71 +
   15.72 +        env = dict(os.environ)
   15.73 +        if self.display:
   15.74 +            env['DISPLAY'] = self.display
   15.75 +        if self.xauthority:
   15.76 +            env['XAUTHORITY'] = self.xauthority
   15.77 +        log.info("spawning video: %s", args)
   15.78 +        self.pid = os.spawnve(os.P_NOWAIT, args[0], args, env)
   15.79 +        log.info("device model pid: %d", self.pid)
   15.80 +
   15.81 +    def destroy(self):
   15.82 +        if not self.pid:
   15.83 +            return
   15.84 +        os.kill(self.pid, signal.SIGKILL)
   15.85 +        os.waitpid(self.pid, 0)
   15.86 +        self.pid = 0
   15.87 +
   15.88  class PPC_LinuxImageHandler(LinuxImageHandler):
   15.89  
   15.90      ostype = "linux"
    16.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    16.2 +++ b/tools/python/xen/xend/server/vfbif.py	Fri Dec 01 09:48:32 2006 +0000
    16.3 @@ -0,0 +1,29 @@
    16.4 +from xen.xend.server.DevController import DevController
    16.5 +
    16.6 +class VfbifController(DevController):
    16.7 +    """Virtual frame buffer controller. Handles all vfb devices for a domain.
    16.8 +    """
    16.9 +
   16.10 +    def __init__(self, vm):
   16.11 +        DevController.__init__(self, vm)
   16.12 +
   16.13 +    def getDeviceDetails(self, config):
   16.14 +        """@see DevController.getDeviceDetails"""
   16.15 +        devid = 0
   16.16 +        back = {}
   16.17 +        front = {}
   16.18 +        return (devid, back, front)
   16.19 +
   16.20 +class VkbdifController(DevController):
   16.21 +    """Virtual keyboard controller. Handles all vkbd devices for a domain.
   16.22 +    """
   16.23 +
   16.24 +    def __init__(self, vm):
   16.25 +        DevController.__init__(self, vm)
   16.26 +
   16.27 +    def getDeviceDetails(self, config):
   16.28 +        """@see DevController.getDeviceDetails"""
   16.29 +        devid = 0
   16.30 +        back = {}
   16.31 +        front = {}
   16.32 +        return (devid, back, front)
    17.1 --- a/tools/python/xen/xm/create.py	Fri Dec 01 09:28:14 2006 +0000
    17.2 +++ b/tools/python/xen/xm/create.py	Fri Dec 01 09:48:32 2006 +0000
    17.3 @@ -284,6 +284,14 @@ gopts.var('usbport', val='PATH',
    17.4            use="""Add a physical USB port to a domain, as specified by the path
    17.5            to that port.  This option may be repeated to add more than one port.""")
    17.6  
    17.7 +gopts.var('vfb', val="no|yes'",
    17.8 +          fn=set_bool, default=0,
    17.9 +          use="Make the domain a framebuffer backend.")
   17.10 +
   17.11 +gopts.var('vkbd', val="no|yes'",
   17.12 +          fn=set_bool, default=0,
   17.13 +          use="Make the domain a keyboard backend.")
   17.14 +
   17.15  gopts.var('vif', val="type=TYPE,mac=MAC,bridge=BRIDGE,ip=IPADDR,script=SCRIPT,backend=DOM,vifname=NAME",
   17.16            fn=append_value, default=[],
   17.17            use="""Add a network interface with the given MAC address and bridge.
   17.18 @@ -512,8 +520,10 @@ def configure_image(vals):
   17.19          config_image.append(['args', vals.extra])
   17.20  
   17.21      if vals.builder == 'hvm':
   17.22 -        configure_hvm(config_image, vals)
   17.23 -        
   17.24 +        configure_hvm(config_image, vals) 
   17.25 +
   17.26 +    configure_graphics(config_image, vals)        
   17.27 +       
   17.28      return config_image
   17.29      
   17.30  def configure_disks(config_devs, vals):
   17.31 @@ -564,6 +574,13 @@ def configure_usb(config_devs, vals):
   17.32          config_usb = ['usbport', ['path', path]]
   17.33          config_devs.append(['device', config_usb])
   17.34  
   17.35 +def configure_vfbs(config_devs, vals):
   17.36 +    if vals.vfb:
   17.37 +        config_devs.append(['device', ['vfb', []]])
   17.38 +
   17.39 +def configure_vkbds(config_devs, vals):
   17.40 +    if vals.vkbd:
   17.41 +        config_devs.append(['device', ['vkbd', []]])
   17.42  
   17.43  def configure_security(config, vals):
   17.44      """Create the config for ACM security labels.
   17.45 @@ -661,13 +678,20 @@ def configure_vifs(config_devs, vals):
   17.46          config_devs.append(['device', config_vif])
   17.47  
   17.48  
   17.49 +def configure_graphics(config_image, vals):
   17.50 +    """Create the config for graphic consoles.
   17.51 +    """
   17.52 +    args = [ 'vnc', 'vncdisplay', 'vncconsole', 'vncunused',
   17.53 +             'sdl', 'display', 'xauthority', 'vnclisten', 'vncpasswd']
   17.54 +    for a in args:
   17.55 +        if (vals.__dict__[a]):
   17.56 +            config_image.append([a, vals.__dict__[a]])
   17.57 +
   17.58  def configure_hvm(config_image, vals):
   17.59      """Create the config for HVM devices.
   17.60      """
   17.61      args = [ 'device_model', 'pae', 'vcpus', 'boot', 'fda', 'fdb',
   17.62               'localtime', 'serial', 'stdvga', 'isa', 'nographic', 'soundhw',
   17.63 -             'vnc', 'vncdisplay', 'vncunused', 'vncconsole', 'vnclisten',
   17.64 -             'sdl', 'display', 'xauthority',
   17.65               'acpi', 'apic', 'usb', 'usbdevice', 'keymap' ]
   17.66      for a in args:
   17.67          if a in vals.__dict__ and vals.__dict__[a] is not None:
   17.68 @@ -742,6 +766,8 @@ def make_config(vals):
   17.69      configure_vifs(config_devs, vals)
   17.70      configure_usb(config_devs, vals)
   17.71      configure_vtpm(config_devs, vals)
   17.72 +    configure_vfbs(config_devs, vals)
   17.73 +    configure_vkbds(config_devs, vals)
   17.74      configure_security(config, vals)
   17.75      config += config_devs
   17.76  
    18.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    18.2 +++ b/tools/xenfb/Makefile	Fri Dec 01 09:48:32 2006 +0000
    18.3 @@ -0,0 +1,35 @@
    18.4 +XEN_ROOT=../..
    18.5 +include $(XEN_ROOT)/tools/Rules.mk
    18.6 +
    18.7 +CFLAGS += -I$(XEN_LIBXC) -I$(XEN_XENSTORE) -I$(XEN_ROOT)/linux-2.6-xen-sparse/include
    18.8 +LDFLAGS += -L$(XEN_LIBXC) -L$(XEN_XENSTORE)
    18.9 +
   18.10 +INSTALL         = install
   18.11 +INSTALL_PROG    = $(INSTALL) -m0755
   18.12 +INSTALL_DIR     = $(INSTALL) -d -m0755
   18.13 +
   18.14 +.PHONY: all
   18.15 +all: build
   18.16 +
   18.17 +.PHONY: build
   18.18 +build: mk-symlinks
   18.19 +	$(MAKE) vncfb sdlfb
   18.20 +
   18.21 +install: all
   18.22 +	$(INSTALL_DIR) -p $(DESTDIR)/usr/$(LIBDIR)/xen/bin
   18.23 +	$(INSTALL_PROG) vncfb $(DESTDIR)/usr/$(LIBDIR)/xen/bin/xen-vncfb
   18.24 +	$(INSTALL_PROG) sdlfb $(DESTDIR)/usr/$(LIBDIR)/xen/bin/xen-sdlfb
   18.25 +
   18.26 +sdlfb: sdlfb.o xenfb.o
   18.27 +
   18.28 +sdlfb.o: CFLAGS += $(shell sdl-config --cflags)
   18.29 +sdlfb: LDLIBS += $(shell sdl-config --libs) -lxenctrl -lxenstore
   18.30 +
   18.31 +clean:
   18.32 +	$(RM) *.o *~ vncfb sdlfb
   18.33 +
   18.34 +vncfb: vncfb.o xenfb.o
   18.35 +vncfb.o: CFLAGS += $(shell libvncserver-config --cflags)
   18.36 +vncfb: LDLIBS += $(shell libvncserver-config --libs) -lxenctrl -lxenstore
   18.37 +
   18.38 +sdlfb.o xenfb.o vncfb.o: xenfb.h
    19.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    19.2 +++ b/tools/xenfb/sdlfb.c	Fri Dec 01 09:48:32 2006 +0000
    19.3 @@ -0,0 +1,334 @@
    19.4 +#include <SDL.h>
    19.5 +#include <errno.h>
    19.6 +#include <sys/types.h>
    19.7 +#include <sys/select.h>
    19.8 +#include <stdlib.h>
    19.9 +#include <linux/input.h>
   19.10 +#include <getopt.h>
   19.11 +#include <string.h>
   19.12 +#include "xenfb.h"
   19.13 +
   19.14 +struct SDLFBData
   19.15 +{
   19.16 +	SDL_Surface *dst;
   19.17 +	SDL_Surface *src;
   19.18 +};
   19.19 +
   19.20 +/*
   19.21 + * Map from scancode to Linux input layer keycode.  Scancodes are
   19.22 + * hardware-specific.  This map assumes a standard AT or PS/2
   19.23 + * keyboard.
   19.24 + *
   19.25 + * Why use scancodes?  We can't use key symbols, because they don't
   19.26 + * identify keys --- they're what keys are mapped to.  The standard
   19.27 + * German keymap, for instance, maps both KEY_COMMA and KEY_102ND to
   19.28 + * SDLK_LESS.
   19.29 + */
   19.30 +static int keymap[256] = {
   19.31 +	[9] = KEY_ESC,
   19.32 +	[10] = KEY_1,
   19.33 +	[11] = KEY_2,
   19.34 +	[12] = KEY_3,
   19.35 +	[13] = KEY_4,
   19.36 +	[14] = KEY_5,
   19.37 +	[15] = KEY_6,
   19.38 +	[16] = KEY_7,
   19.39 +	[17] = KEY_8,
   19.40 +	[18] = KEY_9,
   19.41 +	[19] = KEY_0,
   19.42 +	[20] = KEY_MINUS,
   19.43 +	[21] = KEY_EQUAL,
   19.44 +	[22] = KEY_BACKSPACE,
   19.45 +	[23] = KEY_TAB,
   19.46 +	[24] = KEY_Q,
   19.47 +	[25] = KEY_W,
   19.48 +	[26] = KEY_E,
   19.49 +	[27] = KEY_R,
   19.50 +	[28] = KEY_T,
   19.51 +	[29] = KEY_Y,
   19.52 +	[30] = KEY_U,
   19.53 +	[31] = KEY_I,
   19.54 +	[32] = KEY_O,
   19.55 +	[33] = KEY_P,
   19.56 +	[34] = KEY_LEFTBRACE,
   19.57 +	[35] = KEY_RIGHTBRACE,
   19.58 +	[36] = KEY_ENTER,
   19.59 +	[37] = KEY_LEFTCTRL,
   19.60 +	[38] = KEY_A,
   19.61 +	[39] = KEY_S,
   19.62 +	[40] = KEY_D,
   19.63 +	[41] = KEY_F,
   19.64 +	[42] = KEY_G,
   19.65 +	[43] = KEY_H,
   19.66 +	[44] = KEY_J,
   19.67 +	[45] = KEY_K,
   19.68 +	[46] = KEY_L,
   19.69 +	[47] = KEY_SEMICOLON,
   19.70 +	[48] = KEY_APOSTROPHE,
   19.71 +	[49] = KEY_GRAVE,
   19.72 +	[50] = KEY_LEFTSHIFT,
   19.73 +	[51] = KEY_BACKSLASH,
   19.74 +	[52] = KEY_Z,
   19.75 +	[53] = KEY_X,
   19.76 +	[54] = KEY_C,
   19.77 +	[55] = KEY_V,
   19.78 +	[56] = KEY_B,
   19.79 +	[57] = KEY_N,
   19.80 +	[58] = KEY_M,
   19.81 +	[59] = KEY_COMMA,
   19.82 +	[60] = KEY_DOT,
   19.83 +	[61] = KEY_SLASH,
   19.84 +	[62] = KEY_RIGHTSHIFT,
   19.85 +	[63] = KEY_KPASTERISK,
   19.86 +	[64] = KEY_LEFTALT,
   19.87 +	[65] = KEY_SPACE,
   19.88 +	[66] = KEY_CAPSLOCK,
   19.89 +	[67] = KEY_F1,
   19.90 +	[68] = KEY_F2,
   19.91 +	[69] = KEY_F3,
   19.92 +	[70] = KEY_F4,
   19.93 +	[71] = KEY_F5,
   19.94 +	[72] = KEY_F6,
   19.95 +	[73] = KEY_F7,
   19.96 +	[74] = KEY_F8,
   19.97 +	[75] = KEY_F9,
   19.98 +	[76] = KEY_F10,
   19.99 +	[77] = KEY_NUMLOCK,
  19.100 +	[78] = KEY_SCROLLLOCK,
  19.101 +	[79] = KEY_KP7,
  19.102 +	[80] = KEY_KP8,
  19.103 +	[81] = KEY_KP9,
  19.104 +	[82] = KEY_KPMINUS,
  19.105 +	[83] = KEY_KP4,
  19.106 +	[84] = KEY_KP5,
  19.107 +	[85] = KEY_KP6,
  19.108 +	[86] = KEY_KPPLUS,
  19.109 +	[87] = KEY_KP1,
  19.110 +	[88] = KEY_KP2,
  19.111 +	[89] = KEY_KP3,
  19.112 +	[90] = KEY_KP0,
  19.113 +	[91] = KEY_KPDOT,
  19.114 +	[94] = KEY_102ND,	/* FIXME is this correct? */
  19.115 +	[95] = KEY_F11,
  19.116 +	[96] = KEY_F12,
  19.117 +	[108] = KEY_KPENTER,
  19.118 +	[109] = KEY_RIGHTCTRL,
  19.119 +	[112] = KEY_KPSLASH,
  19.120 +	[111] = KEY_SYSRQ,
  19.121 +	[113] = KEY_RIGHTALT,
  19.122 +	[97] = KEY_HOME,
  19.123 +	[98] = KEY_UP,
  19.124 +	[99] = KEY_PAGEUP,
  19.125 +	[100] = KEY_LEFT,
  19.126 +	[102] = KEY_RIGHT,
  19.127 +	[103] = KEY_END,
  19.128 +	[104] = KEY_DOWN,
  19.129 +	[105] = KEY_PAGEDOWN,
  19.130 +	[106] = KEY_INSERT,
  19.131 +	[107] = KEY_DELETE,
  19.132 +	[110] = KEY_PAUSE,
  19.133 +	[115] = KEY_LEFTMETA,
  19.134 +	[116] = KEY_RIGHTMETA,
  19.135 +	[117] = KEY_MENU,
  19.136 +};
  19.137 +
  19.138 +static int btnmap[] = {
  19.139 +	[SDL_BUTTON_LEFT] = BTN_LEFT,
  19.140 +	[SDL_BUTTON_MIDDLE] = BTN_MIDDLE,
  19.141 +	[SDL_BUTTON_RIGHT] = BTN_RIGHT,
  19.142 +	/* FIXME not 100% sure about these: */
  19.143 +	[SDL_BUTTON_WHEELUP] = BTN_FORWARD,
  19.144 +	[SDL_BUTTON_WHEELDOWN] BTN_BACK
  19.145 +};
  19.146 +
  19.147 +static void sdl_update(struct xenfb *xenfb, int x, int y, int width, int height)
  19.148 +{
  19.149 +	struct SDLFBData *data = xenfb->user_data;
  19.150 +	SDL_Rect r = { x, y, width, height };
  19.151 +	SDL_BlitSurface(data->src, &r, data->dst, &r);
  19.152 +	SDL_UpdateRect(data->dst, x, y, width, height);
  19.153 +}
  19.154 +
  19.155 +static int sdl_on_event(struct xenfb *xenfb, SDL_Event *event)
  19.156 +{
  19.157 +	int x, y, ret;
  19.158 +
  19.159 +	switch (event->type) {
  19.160 +	case SDL_KEYDOWN:
  19.161 +	case SDL_KEYUP:
  19.162 +		if (keymap[event->key.keysym.scancode] == 0)
  19.163 +			break;
  19.164 +		ret = xenfb_send_key(xenfb,
  19.165 +				     event->type == SDL_KEYDOWN,
  19.166 +				     keymap[event->key.keysym.scancode]);
  19.167 +		if (ret < 0)
  19.168 +			fprintf(stderr, "Key %d %s lost (%s)\n",
  19.169 +				keymap[event->key.keysym.scancode],
  19.170 +				event->type == SDL_KEYDOWN ? "down" : "up",
  19.171 +				strerror(errno));
  19.172 +		break;
  19.173 +	case SDL_MOUSEMOTION:
  19.174 +		if (xenfb->abs_pointer_wanted) {
  19.175 +			SDL_GetMouseState(&x, &y);
  19.176 +			ret = xenfb_send_position(xenfb, x, y);
  19.177 +		} else {
  19.178 +			SDL_GetRelativeMouseState(&x, &y);
  19.179 +			ret = xenfb_send_motion(xenfb, x, y);
  19.180 +		}
  19.181 +		if (ret < 0)
  19.182 +			fprintf(stderr, "Pointer to %d,%d lost (%s)\n",
  19.183 +				x, y, strerror(errno));
  19.184 +		break;
  19.185 +	case SDL_MOUSEBUTTONDOWN:
  19.186 +	case SDL_MOUSEBUTTONUP:
  19.187 +		if (event->button.button >= sizeof(btnmap) / sizeof(*btnmap))
  19.188 +			break;
  19.189 +		if (btnmap[event->button.button] == 0)
  19.190 +			break;
  19.191 +		ret = xenfb_send_key(xenfb,
  19.192 +				     event->type == SDL_MOUSEBUTTONDOWN,
  19.193 +				     btnmap[event->button.button]);
  19.194 +		if (ret < 0)
  19.195 +			fprintf(stderr, "Button %d %s lost (%s)\n",
  19.196 +				btnmap[event->button.button] - BTN_MOUSE,
  19.197 +				event->type == SDL_MOUSEBUTTONDOWN ? "down" : "up",
  19.198 +				strerror(errno));
  19.199 +		break;
  19.200 +	case SDL_QUIT:
  19.201 +		return 0;
  19.202 +	}
  19.203 +
  19.204 +	return 1;
  19.205 +}
  19.206 +
  19.207 +static struct option options[] = {
  19.208 +	{ "domid", 1, NULL, 'd' },
  19.209 +	{ "title", 1, NULL, 't' },
  19.210 +};
  19.211 +
  19.212 +int main(int argc, char **argv)
  19.213 +{
  19.214 +	struct xenfb *xenfb;
  19.215 +	int domid = -1;
  19.216 +        char * title = NULL;
  19.217 +	fd_set readfds;
  19.218 +	int nfds;
  19.219 +	struct SDLFBData data;
  19.220 +	SDL_Rect r;
  19.221 +	struct timeval tv;
  19.222 +	SDL_Event event;
  19.223 +	int do_quit = 0;
  19.224 +	int opt;
  19.225 +	char *endp;
  19.226 +
  19.227 +	while ((opt = getopt_long(argc, argv, "d:t:", options,
  19.228 +				  NULL)) != -1) {
  19.229 +		switch (opt) {
  19.230 +                case 'd':
  19.231 +			domid = strtol(optarg, &endp, 10);
  19.232 +			if (endp == optarg || *endp) {
  19.233 +				fprintf(stderr, "Invalid domain id specified\n");
  19.234 +				exit(1);
  19.235 +			}
  19.236 +			break;
  19.237 +                case 't':
  19.238 +			title = strdup(optarg);
  19.239 +			break;
  19.240 +                }
  19.241 +        }
  19.242 +        if (optind != argc) {
  19.243 +		fprintf(stderr, "Invalid options!\n");
  19.244 +		exit(1);
  19.245 +        }
  19.246 +        if (domid <= 0) {
  19.247 +		fprintf(stderr, "Domain ID must be specified!\n");
  19.248 +		exit(1);
  19.249 +        }
  19.250 +
  19.251 +	xenfb = xenfb_new();
  19.252 +	if (xenfb == NULL) {
  19.253 +		fprintf(stderr, "Could not create framebuffer (%s)\n",
  19.254 +			strerror(errno));
  19.255 +		exit(1);
  19.256 +        }
  19.257 +
  19.258 +	if (xenfb_attach_dom(xenfb, domid) < 0) {
  19.259 +		fprintf(stderr, "Could not connect to domain (%s)\n",
  19.260 +			strerror(errno));
  19.261 +		exit(1);
  19.262 +        }
  19.263 +
  19.264 +	if (SDL_Init(SDL_INIT_VIDEO) < 0) {
  19.265 +		fprintf(stderr, "Could not initialize SDL\n");
  19.266 +		exit(1);
  19.267 +	}
  19.268 +
  19.269 +	data.dst = SDL_SetVideoMode(xenfb->width, xenfb->height, xenfb->depth,
  19.270 +				    SDL_SWSURFACE);
  19.271 +	if (!data.dst) {
  19.272 +		fprintf(stderr, "SDL_SetVideoMode failed\n");
  19.273 +		exit(1);
  19.274 +	}
  19.275 +
  19.276 +	data.src = SDL_CreateRGBSurfaceFrom(xenfb->pixels,
  19.277 +					    xenfb->width, xenfb->height,
  19.278 +					    xenfb->depth, xenfb->row_stride,
  19.279 +					    0xFF0000, 0xFF00, 0xFF, 0);
  19.280 +
  19.281 +	if (!data.src) {
  19.282 +		fprintf(stderr, "SDL_CreateRGBSurfaceFrom failed\n");
  19.283 +		exit(1);
  19.284 +	}
  19.285 +
  19.286 +        if (title == NULL)
  19.287 +		title = strdup("xen-sdlfb");
  19.288 +        SDL_WM_SetCaption(title, title);
  19.289 +
  19.290 +	r.x = r.y = 0;
  19.291 +	r.w = xenfb->width;
  19.292 +	r.h = xenfb->height;
  19.293 +	SDL_BlitSurface(data.src, &r, data.dst, &r);
  19.294 +	SDL_UpdateRect(data.dst, 0, 0, xenfb->width, xenfb->height);
  19.295 +
  19.296 +	xenfb->update = sdl_update;
  19.297 +	xenfb->user_data = &data;
  19.298 +
  19.299 +	SDL_ShowCursor(0);
  19.300 +
  19.301 +	/*
  19.302 +	 * We need to wait for fds becoming ready or SDL events to
  19.303 +	 * arrive.  We time out the select after 10ms to poll for SDL
  19.304 +	 * events.  Clunky, but works.  Could avoid the clunkiness
  19.305 +	 * with a separate thread.
  19.306 +	 */
  19.307 +	for (;;) {
  19.308 +		FD_ZERO(&readfds);
  19.309 +		nfds = xenfb_select_fds(xenfb, &readfds);
  19.310 +		tv = (struct timeval){0, 10000};
  19.311 +
  19.312 +		if (select(nfds, &readfds, NULL, NULL, &tv) < 0) {
  19.313 +			if (errno == EINTR)
  19.314 +				continue;
  19.315 +			fprintf(stderr,
  19.316 +				"Can't select() on event channel (%s)\n",
  19.317 +				strerror(errno));
  19.318 +			break;
  19.319 +		}
  19.320 +
  19.321 +		while (SDL_PollEvent(&event)) {
  19.322 +			if (!sdl_on_event(xenfb, &event))
  19.323 +				do_quit = 1;
  19.324 +		}
  19.325 +
  19.326 +                if (do_quit)
  19.327 +			break;
  19.328 +
  19.329 +		xenfb_poll(xenfb, &readfds);
  19.330 +	}
  19.331 +
  19.332 +	xenfb_delete(xenfb);
  19.333 +
  19.334 +	SDL_Quit();
  19.335 +
  19.336 +	return 0;
  19.337 +}
    20.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    20.2 +++ b/tools/xenfb/vncfb.c	Fri Dec 01 09:48:32 2006 +0000
    20.3 @@ -0,0 +1,393 @@
    20.4 +#define _GNU_SOURCE
    20.5 +#include <errno.h>
    20.6 +#include <getopt.h>
    20.7 +#include <stdlib.h>
    20.8 +#include <signal.h>
    20.9 +#include <unistd.h>
   20.10 +#include <malloc.h>
   20.11 +#include <rfb/rfb.h>
   20.12 +#include <rfb/keysym.h>
   20.13 +#include <linux/input.h>
   20.14 +#include <xs.h>
   20.15 +#include "xenfb.h"
   20.16 +
   20.17 +static int xk2linux[0x10000] = {
   20.18 +	[XK_a] = KEY_A,
   20.19 +	[XK_b] = KEY_B,
   20.20 +	[XK_c] = KEY_C,
   20.21 +	[XK_d] = KEY_D,
   20.22 +	[XK_e] = KEY_E,
   20.23 +	[XK_f] = KEY_F,
   20.24 +	[XK_g] = KEY_G,
   20.25 +	[XK_h] = KEY_H,
   20.26 +	[XK_i] = KEY_I,
   20.27 +	[XK_j] = KEY_J,
   20.28 +	[XK_k] = KEY_K,
   20.29 +	[XK_l] = KEY_L,
   20.30 +	[XK_m] = KEY_M,
   20.31 +	[XK_n] = KEY_N,
   20.32 +	[XK_o] = KEY_O,
   20.33 +	[XK_p] = KEY_P,
   20.34 +	[XK_q] = KEY_Q,
   20.35 +	[XK_r] = KEY_R,
   20.36 +	[XK_s] = KEY_S,
   20.37 +	[XK_t] = KEY_T,
   20.38 +	[XK_u] = KEY_U,
   20.39 +	[XK_v] = KEY_V,
   20.40 +	[XK_w] = KEY_W,
   20.41 +	[XK_x] = KEY_X,
   20.42 +	[XK_y] = KEY_Y,
   20.43 +	[XK_z] = KEY_Z,
   20.44 +	[XK_A] = KEY_A,
   20.45 +	[XK_B] = KEY_B,
   20.46 +	[XK_C] = KEY_C,
   20.47 +	[XK_D] = KEY_D,
   20.48 +	[XK_E] = KEY_E,
   20.49 +	[XK_F] = KEY_F,
   20.50 +	[XK_G] = KEY_G,
   20.51 +	[XK_H] = KEY_H,
   20.52 +	[XK_I] = KEY_I,
   20.53 +	[XK_J] = KEY_J,
   20.54 +	[XK_K] = KEY_K,
   20.55 +	[XK_L] = KEY_L,
   20.56 +	[XK_M] = KEY_M,
   20.57 +	[XK_N] = KEY_N,
   20.58 +	[XK_O] = KEY_O,
   20.59 +	[XK_P] = KEY_P,
   20.60 +	[XK_Q] = KEY_Q,
   20.61 +	[XK_R] = KEY_R,
   20.62 +	[XK_S] = KEY_S,
   20.63 +	[XK_T] = KEY_T,
   20.64 +	[XK_U] = KEY_U,
   20.65 +	[XK_V] = KEY_V,
   20.66 +	[XK_W] = KEY_W,
   20.67 +	[XK_X] = KEY_X,
   20.68 +	[XK_Y] = KEY_Y,
   20.69 +	[XK_Z] = KEY_Z,
   20.70 +	[XK_0] = KEY_0,
   20.71 +	[XK_1] = KEY_1,
   20.72 +	[XK_2] = KEY_2,
   20.73 +	[XK_3] = KEY_3,
   20.74 +	[XK_4] = KEY_4,
   20.75 +	[XK_5] = KEY_5,
   20.76 +	[XK_6] = KEY_6,
   20.77 +	[XK_7] = KEY_7,
   20.78 +	[XK_8] = KEY_8,
   20.79 +	[XK_9] = KEY_9,
   20.80 +	[XK_Return] = KEY_ENTER,
   20.81 +	[XK_BackSpace] = KEY_BACKSPACE,
   20.82 +	[XK_Tab] = KEY_TAB,
   20.83 +	[XK_Pause] = KEY_PAUSE,
   20.84 +	[XK_Delete] = KEY_DELETE,
   20.85 +	[XK_slash] = KEY_SLASH,
   20.86 +	[XK_minus] = KEY_MINUS,
   20.87 +	[XK_equal] = KEY_EQUAL,
   20.88 +	[XK_Escape] = KEY_ESC,
   20.89 +	[XK_braceleft] = KEY_LEFTBRACE,
   20.90 +	[XK_braceright] = KEY_RIGHTBRACE,
   20.91 +	[XK_bracketleft] = KEY_LEFTMETA,
   20.92 +	[XK_bracketright] = KEY_RIGHTMETA,
   20.93 +	[XK_Control_L] = KEY_LEFTCTRL,
   20.94 +	[XK_Control_R] = KEY_RIGHTCTRL,
   20.95 +	[XK_Shift_L] = KEY_LEFTSHIFT,
   20.96 +	[XK_Shift_R] = KEY_RIGHTSHIFT,
   20.97 +	[XK_Alt_L] = KEY_LEFTALT,
   20.98 +	[XK_Alt_R] = KEY_RIGHTALT,
   20.99 +	[XK_semicolon] = KEY_SEMICOLON, 
  20.100 +	[XK_apostrophe] = KEY_APOSTROPHE,
  20.101 +	[XK_grave] = KEY_GRAVE,
  20.102 +	[XK_backslash] = KEY_BACKSLASH,
  20.103 +	[XK_comma] = KEY_COMMA,
  20.104 +	[XK_period] = KEY_DOT,
  20.105 +	[XK_space] = KEY_SPACE,
  20.106 +	[XK_Caps_Lock] = KEY_CAPSLOCK,
  20.107 +	[XK_Num_Lock] = KEY_NUMLOCK,
  20.108 +	[XK_Scroll_Lock] = KEY_SCROLLLOCK,
  20.109 +	[XK_Sys_Req] = KEY_SYSRQ,
  20.110 +	[XK_Linefeed] = KEY_LINEFEED,
  20.111 +	[XK_Home] = KEY_HOME,
  20.112 +	[XK_Pause] = KEY_PAUSE,
  20.113 +	[XK_F1] = KEY_F1,
  20.114 +	[XK_F2] = KEY_F2,
  20.115 +	[XK_F3] = KEY_F3,
  20.116 +	[XK_F4] = KEY_F4,
  20.117 +	[XK_F5] = KEY_F5,
  20.118 +	[XK_F6] = KEY_F6,
  20.119 +	[XK_F7] = KEY_F7,
  20.120 +	[XK_F8] = KEY_F8,
  20.121 +	[XK_F9] = KEY_F9,
  20.122 +	[XK_F10] = KEY_F10,
  20.123 +	[XK_F11] = KEY_F11,
  20.124 +	[XK_F12] = KEY_F12,
  20.125 +	[XK_Up] = KEY_UP,
  20.126 +	[XK_Page_Up] = KEY_PAGEUP,
  20.127 +	[XK_Left] = KEY_LEFT,
  20.128 +	[XK_Right] = KEY_RIGHT,
  20.129 +	[XK_End] = KEY_END,
  20.130 +	[XK_Down] = KEY_DOWN,
  20.131 +	[XK_Page_Down] = KEY_PAGEDOWN,
  20.132 +	[XK_Insert] = KEY_INSERT, 
  20.133 +	[XK_colon] = KEY_SEMICOLON,
  20.134 +	[XK_quotedbl] = KEY_APOSTROPHE,
  20.135 +	[XK_less] = KEY_COMMA,
  20.136 +	[XK_greater] = KEY_DOT,
  20.137 +	[XK_question] = KEY_SLASH,
  20.138 +	[XK_bar] = KEY_BACKSLASH,
  20.139 +	[XK_asciitilde] = KEY_GRAVE,
  20.140 +	[XK_exclam] = KEY_1,
  20.141 +	[XK_at] = KEY_2,
  20.142 +	[XK_numbersign] = KEY_3,
  20.143 +	[XK_dollar] = KEY_4,
  20.144 +	[XK_percent] = KEY_5,
  20.145 +	[XK_asciicircum] = KEY_6,
  20.146 +	[XK_ampersand] = KEY_7,
  20.147 +	[XK_asterisk] = KEY_8,
  20.148 +	[XK_parenleft] = KEY_9,
  20.149 +	[XK_parenright] = KEY_0,
  20.150 +	[XK_underscore] = KEY_MINUS,
  20.151 +	[XK_plus] = KEY_EQUAL,
  20.152 +};
  20.153 +
  20.154 +static void on_kbd_event(rfbBool down, rfbKeySym keycode, rfbClientPtr cl)
  20.155 +{
  20.156 +	/*
  20.157 +	 * We need to map to the key's Linux input layer keycode.
  20.158 +	 * Unfortunately, we don't get the key here, only the
  20.159 +	 * rfbKeySym, which is what the key is mapped to.  Mapping
  20.160 +	 * back to the key is impossible in general, even when you
  20.161 +	 * know the keymap.  For instance, the standard German keymap
  20.162 +	 * maps both KEY_COMMA and KEY_102ND to XK_less.  We simply
  20.163 +	 * assume standard US layout.  This sucks.
  20.164 +	 */
  20.165 +	rfbScreenInfoPtr server = cl->screen;
  20.166 +	struct xenfb *xenfb = server->screenData;
  20.167 +	if (keycode >= sizeof(xk2linux) / sizeof(*xk2linux))
  20.168 +		return;
  20.169 +	if (xk2linux[keycode] == 0)
  20.170 +		return;
  20.171 +	if (xenfb_send_key(xenfb, down, xk2linux[keycode]) < 0)
  20.172 +		fprintf(stderr, "Key %d %s lost (%s)\n",
  20.173 +			xk2linux[keycode], down ? "down" : "up",
  20.174 +			strerror(errno));
  20.175 +}
  20.176 +
  20.177 +static void on_ptr_event(int buttonMask, int x, int y, rfbClientPtr cl)
  20.178 +{
  20.179 +	/* initial pointer state: at (0,0), buttons up */
  20.180 +	static int last_x, last_y, last_button;
  20.181 +	rfbScreenInfoPtr server = cl->screen;
  20.182 +	struct xenfb *xenfb = server->screenData;
  20.183 +	int i, last_down, down, ret;
  20.184 +
  20.185 +	for (i = 0; i < 8; i++) {
  20.186 +		last_down = last_button & (1 << i);
  20.187 +		down = buttonMask & (1 << i);
  20.188 +		if (down == last_down)
  20.189 +			continue;
  20.190 +		/* FIXME this assumes buttons are numbered the same; verify they are */
  20.191 +		if (xenfb_send_key(xenfb, down != 0, BTN_MOUSE + i) < 0)
  20.192 +			fprintf(stderr, "Button %d %s lost (%s)\n",
  20.193 +				i, down ? "down" : "up", strerror(errno));
  20.194 +	}
  20.195 +
  20.196 +	if (x != last_x || y != last_y) {
  20.197 +		if (xenfb->abs_pointer_wanted) 
  20.198 +			ret = xenfb_send_position(xenfb, x, y);
  20.199 +		else
  20.200 +			ret = xenfb_send_motion(xenfb, x - last_x, y - last_y);
  20.201 +		if (ret < 0)
  20.202 +			fprintf(stderr, "Pointer to %d,%d lost (%s)\n",
  20.203 +				x, y, strerror(errno));
  20.204 +	}
  20.205 +
  20.206 +	last_button = buttonMask;
  20.207 +	last_x = x;
  20.208 +	last_y = y;
  20.209 +}
  20.210 +
  20.211 +static void xenstore_write_vncport(int port, int domid)
  20.212 +{
  20.213 +	char *buf = NULL, *path;
  20.214 +	char portstr[10];
  20.215 +	struct xs_handle *xsh = NULL;
  20.216 +
  20.217 +	xsh = xs_daemon_open();
  20.218 +	if (xsh == NULL)
  20.219 +		return;
  20.220 +
  20.221 +	path = xs_get_domain_path(xsh, domid);
  20.222 +	if (path == NULL) {
  20.223 +		fprintf(stderr, "Can't get domain path (%s)\n",
  20.224 +			strerror(errno));
  20.225 +		goto out;
  20.226 +	}
  20.227 +
  20.228 +	if (asprintf(&buf, "%s/console/vnc-port", path) == -1) {
  20.229 +		fprintf(stderr, "Can't make vncport path\n");
  20.230 +		goto out;
  20.231 +	}
  20.232 +
  20.233 +	if (snprintf(portstr, sizeof(portstr), "%d", port) == -1) {
  20.234 +		fprintf(stderr, "Can't make vncport value\n");
  20.235 +		goto out;
  20.236 +	}
  20.237 +
  20.238 +	if (!xs_write(xsh, XBT_NULL, buf, portstr, strlen(portstr)))
  20.239 +		fprintf(stderr, "Can't set vncport (%s)\n",
  20.240 +			strerror(errno));
  20.241 +
  20.242 + out:
  20.243 +	free(buf);
  20.244 +}
  20.245 +
  20.246 +
  20.247 +static void vnc_update(struct xenfb *xenfb, int x, int y, int w, int h)
  20.248 +{
  20.249 +	rfbScreenInfoPtr server = xenfb->user_data;
  20.250 +	rfbMarkRectAsModified(server, x, y, x + w, y + h);
  20.251 +}
  20.252 +
  20.253 +static struct option options[] = {
  20.254 +	{ "domid", 1, NULL, 'd' },
  20.255 +	{ "vncport", 1, NULL, 'p' },
  20.256 +	{ "title", 1, NULL, 't' },
  20.257 +	{ "unused", 0, NULL, 'u' },
  20.258 +	{ "listen", 1, NULL, 'l' },
  20.259 +};
  20.260 +
  20.261 +int main(int argc, char **argv)
  20.262 +{
  20.263 +	rfbScreenInfoPtr server;
  20.264 +	char *fake_argv[7] = { "vncfb", "-rfbport", "5901", 
  20.265 +                               "-desktop", "xen-vncfb", 
  20.266 +                               "-listen", "127.0.0.1" };
  20.267 +	int fake_argc = sizeof(fake_argv) / sizeof(fake_argv[0]);
  20.268 +	int domid = -1, port = -1;
  20.269 +	char *title = NULL;
  20.270 +	char *listen = NULL;
  20.271 +	bool unused = false;
  20.272 +	int opt;
  20.273 +	struct xenfb *xenfb;
  20.274 +	fd_set readfds;
  20.275 +	int nfds;
  20.276 +	char portstr[10];
  20.277 +	char *endp;
  20.278 +
  20.279 +	while ((opt = getopt_long(argc, argv, "d:p:t:u", options,
  20.280 +				  NULL)) != -1) {
  20.281 +		switch (opt) {
  20.282 +                case 'd':
  20.283 +			errno = 0;
  20.284 +			domid = strtol(optarg, &endp, 10);
  20.285 +			if (endp == optarg || *endp || errno) {
  20.286 +				fprintf(stderr, "Invalid domain id specified\n");
  20.287 +				exit(1);
  20.288 +			}
  20.289 +			break;
  20.290 +                case 'p':
  20.291 +			errno = 0;
  20.292 +			port = strtol(optarg, &endp, 10);
  20.293 +			if (endp == optarg || *endp || errno) {
  20.294 +				fprintf(stderr, "Invalid port specified\n");
  20.295 +				exit(1);
  20.296 +			}
  20.297 +			break;
  20.298 +                case 't':
  20.299 +			title = strdup(optarg);
  20.300 +			break;
  20.301 +                case 'u':
  20.302 +			unused = true;
  20.303 +			break;
  20.304 +                case 'l':
  20.305 +			listen = strdup(optarg);
  20.306 +			break;
  20.307 +                }
  20.308 +        }
  20.309 +        if (optind != argc) {
  20.310 +		fprintf(stderr, "Invalid options!\n");
  20.311 +		exit(1);
  20.312 +        }
  20.313 +        if (domid <= 0) {
  20.314 +		fprintf(stderr, "Domain ID must be specified!\n");
  20.315 +		exit(1);
  20.316 +        }
  20.317 +            
  20.318 +        if (port <= 0)
  20.319 +		port = 5900 + domid;
  20.320 +	if (snprintf(portstr, sizeof(portstr), "%d", port) == -1) {
  20.321 +		fprintf(stderr, "Invalid port specified\n");
  20.322 +		exit(1);
  20.323 +        }
  20.324 +            
  20.325 +	fake_argv[2] = portstr;
  20.326 +
  20.327 +        if (title != NULL)
  20.328 +		fake_argv[4] = title;
  20.329 +
  20.330 +        if (listen != NULL)
  20.331 +		fake_argv[6] = listen;
  20.332 +
  20.333 +	signal(SIGPIPE, SIG_IGN);
  20.334 +
  20.335 +	xenfb = xenfb_new();
  20.336 +	if (xenfb == NULL) {
  20.337 +		fprintf(stderr, "Could not create framebuffer (%s)\n",
  20.338 +			strerror(errno));
  20.339 +		exit(1);
  20.340 +	}
  20.341 +
  20.342 +	if (xenfb_attach_dom(xenfb, domid) < 0) {
  20.343 +		fprintf(stderr, "Could not connect to domain (%s)\n",
  20.344 +			strerror(errno));
  20.345 +		exit(1);
  20.346 +	}
  20.347 +
  20.348 +	server = rfbGetScreen(&fake_argc, fake_argv, 
  20.349 +			      xenfb->width, xenfb->height,
  20.350 +			      8, 3, xenfb->depth / 8);
  20.351 +	if (server == NULL) {
  20.352 +		fprintf(stderr, "Could not create VNC server\n");
  20.353 +		exit(1);
  20.354 +	}
  20.355 +
  20.356 +	xenfb->user_data = server;
  20.357 +	xenfb->update = vnc_update;
  20.358 +
  20.359 +        if (unused)
  20.360 +		server->autoPort = true;
  20.361 +
  20.362 +	server->serverFormat.redShift = 16;
  20.363 +	server->serverFormat.greenShift = 8;
  20.364 +	server->serverFormat.blueShift = 0;
  20.365 +	server->kbdAddEvent = on_kbd_event;
  20.366 +	server->ptrAddEvent = on_ptr_event;
  20.367 +	server->frameBuffer = xenfb->pixels;
  20.368 +	server->screenData = xenfb;
  20.369 +	server->cursor = NULL;
  20.370 +	rfbInitServer(server);
  20.371 +
  20.372 +	rfbRunEventLoop(server, -1, true);
  20.373 +
  20.374 +        xenstore_write_vncport(server->port, domid);
  20.375 +
  20.376 +	for (;;) {
  20.377 +		FD_ZERO(&readfds);
  20.378 +		nfds = xenfb_select_fds(xenfb, &readfds);
  20.379 +
  20.380 +		if (select(nfds, &readfds, NULL, NULL, NULL) < 0) {
  20.381 +			if (errno == EINTR)
  20.382 +				continue;
  20.383 +			fprintf(stderr,
  20.384 +				"Can't select() on event channel (%s)\n",
  20.385 +				strerror(errno));
  20.386 +			break;
  20.387 +		}
  20.388 +
  20.389 +		xenfb_poll(xenfb, &readfds);
  20.390 +	}
  20.391 +
  20.392 +	rfbScreenCleanup(server);
  20.393 +	xenfb_delete(xenfb);
  20.394 +
  20.395 +	return 0;
  20.396 +}
    21.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    21.2 +++ b/tools/xenfb/xenfb.c	Fri Dec 01 09:48:32 2006 +0000
    21.3 @@ -0,0 +1,691 @@
    21.4 +#include <stdarg.h>
    21.5 +#include <stdlib.h>
    21.6 +#include <sys/types.h>
    21.7 +#include <fcntl.h>
    21.8 +#include <unistd.h>
    21.9 +#include <xenctrl.h>
   21.10 +#include <xen/io/xenbus.h>
   21.11 +#include <xen/io/fbif.h>
   21.12 +#include <xen/io/kbdif.h>
   21.13 +#include <sys/select.h>
   21.14 +#include <stdbool.h>
   21.15 +#include <xen/linux/evtchn.h>
   21.16 +#include <xen/event_channel.h>
   21.17 +#include <sys/mman.h>
   21.18 +#include <errno.h>
   21.19 +#include <stdio.h>
   21.20 +#include <string.h>
   21.21 +#include <time.h>
   21.22 +#include <xs.h>
   21.23 +
   21.24 +#include "xenfb.h"
   21.25 +
   21.26 +// FIXME defend against malicious frontend?
   21.27 +
   21.28 +struct xenfb_device {
   21.29 +	const char *devicetype;
   21.30 +	char nodename[64];	/* backend xenstore dir */
   21.31 +	char otherend[64];	/* frontend xenstore dir */
   21.32 +	int otherend_id;	/* frontend domid */
   21.33 +	enum xenbus_state state; /* backend state */
   21.34 +	void *page;		/* shared page */
   21.35 +	evtchn_port_t port;
   21.36 +	struct xenfb_private *xenfb;
   21.37 +};
   21.38 +
   21.39 +struct xenfb_private {
   21.40 +	struct xenfb pub;
   21.41 +	int evt_xch;		/* event channel driver handle */
   21.42 +	int xc;			/* hypervisor interface handle */
   21.43 +	struct xs_handle *xsh;	/* xs daemon handle */
   21.44 +	struct xenfb_device fb, kbd;
   21.45 +	size_t fb_len;		/* size of framebuffer */
   21.46 +};
   21.47 +
   21.48 +static void xenfb_detach_dom(struct xenfb_private *);
   21.49 +
   21.50 +static char *xenfb_path_in_dom(struct xs_handle *xsh,
   21.51 +			       char *buf, size_t size,
   21.52 +			       unsigned domid, const char *fmt, ...)
   21.53 +{
   21.54 +	va_list ap;
   21.55 +	char *domp = xs_get_domain_path(xsh, domid);
   21.56 +	int n;
   21.57 +
   21.58 +        if (domp == NULL)
   21.59 +		return NULL;
   21.60 +
   21.61 +	n = snprintf(buf, size, "%s/", domp);
   21.62 +	free(domp);
   21.63 +	if (n >= size)
   21.64 +		return NULL;
   21.65 +
   21.66 +	va_start(ap, fmt);
   21.67 +	n += vsnprintf(buf + n, size - n, fmt, ap);
   21.68 +	va_end(ap);
   21.69 +	if (n >= size)
   21.70 +		return NULL;
   21.71 +
   21.72 +	return buf;
   21.73 +}
   21.74 +
   21.75 +static int xenfb_xs_scanf1(struct xs_handle *xsh,
   21.76 +			   const char *dir, const char *node,
   21.77 +			   const char *fmt, void *dest)
   21.78 +{
   21.79 +	char buf[1024];
   21.80 +	char *p;
   21.81 +	int ret;
   21.82 +
   21.83 +	if (snprintf(buf, sizeof(buf), "%s/%s", dir, node) >= sizeof(buf)) {
   21.84 +		errno = ENOENT;
   21.85 +		return -1;
   21.86 +        }
   21.87 +	p = xs_read(xsh, XBT_NULL, buf, NULL);
   21.88 +	if (!p) {
   21.89 +		errno = ENOENT;
   21.90 +		return -1;
   21.91 +        }
   21.92 +	ret = sscanf(p, fmt, dest);
   21.93 +	free(p);
   21.94 +	if (ret != 1) {
   21.95 +		errno = EDOM;
   21.96 +		return -1;
   21.97 +        }
   21.98 +	return ret;
   21.99 +}
  21.100 +
  21.101 +static int xenfb_xs_printf(struct xs_handle *xsh,
  21.102 +			   const char *dir, const char *node, char *fmt, ...)
  21.103 +{
  21.104 +	va_list ap;
  21.105 +	char key[1024];
  21.106 +	char val[1024];
  21.107 +	int n;
  21.108 +
  21.109 +	if (snprintf(key, sizeof(key), "%s/%s", dir, node) >= sizeof(key)) {
  21.110 +		errno = ENOENT;
  21.111 +		return -1;
  21.112 +        }
  21.113 +
  21.114 +	va_start(ap, fmt);
  21.115 +	n = vsnprintf(val, sizeof(val), fmt, ap);
  21.116 +	va_end(ap);
  21.117 +	if (n >= sizeof(val)) {
  21.118 +		errno = ENOSPC; /* close enough */
  21.119 +		return -1;
  21.120 +	}
  21.121 +
  21.122 +	if (!xs_write(xsh, XBT_NULL, key, val, n))
  21.123 +		return -1;
  21.124 +	return 0;
  21.125 +}
  21.126 +
  21.127 +static void xenfb_device_init(struct xenfb_device *dev,
  21.128 +			      const char *type,
  21.129 +			      struct xenfb_private *xenfb)
  21.130 +{
  21.131 +	dev->devicetype = type;
  21.132 +	dev->otherend_id = -1;
  21.133 +	dev->port = -1;
  21.134 +	dev->xenfb = xenfb;
  21.135 +}
  21.136 +
  21.137 +int xenfb_device_set_domain(struct xenfb_device *dev, int domid)
  21.138 +{
  21.139 +	struct xenfb_private *xenfb = dev->xenfb;
  21.140 +
  21.141 +	dev->otherend_id = domid;
  21.142 +
  21.143 +	if (!xenfb_path_in_dom(xenfb->xsh,
  21.144 +			       dev->otherend, sizeof(dev->otherend),
  21.145 +			       domid, "device/%s/0", dev->devicetype)) {
  21.146 +		errno = ENOENT;
  21.147 +		return -1;
  21.148 +	}
  21.149 +	if (!xenfb_path_in_dom(xenfb->xsh,
  21.150 +			       dev->nodename, sizeof(dev->nodename),
  21.151 +			       0, "backend/%s/%d/0", dev->devicetype, domid)) {
  21.152 +		errno = ENOENT;
  21.153 +		return -1;
  21.154 +	}
  21.155 +
  21.156 +	return 0;
  21.157 +}
  21.158 +
  21.159 +struct xenfb *xenfb_new(void)
  21.160 +{
  21.161 +	struct xenfb_private *xenfb = malloc(sizeof(*xenfb));
  21.162 +	int serrno;
  21.163 +
  21.164 +	if (xenfb == NULL)
  21.165 +		return NULL;
  21.166 +
  21.167 +	memset(xenfb, 0, sizeof(*xenfb));
  21.168 +	xenfb->evt_xch = xenfb->xc = -1;
  21.169 +	xenfb_device_init(&xenfb->fb, "vfb", xenfb);
  21.170 +	xenfb_device_init(&xenfb->kbd, "vkbd", xenfb);
  21.171 +
  21.172 +	xenfb->evt_xch = xc_evtchn_open();
  21.173 +	if (xenfb->evt_xch == -1)
  21.174 +		goto fail;
  21.175 +
  21.176 +	xenfb->xc = xc_interface_open();
  21.177 +	if (xenfb->xc == -1)
  21.178 +		goto fail;
  21.179 +
  21.180 +	xenfb->xsh = xs_daemon_open();
  21.181 +	if (!xenfb->xsh)
  21.182 +		goto fail;
  21.183 +
  21.184 +	return &xenfb->pub;
  21.185 +
  21.186 + fail:
  21.187 +	serrno = errno;
  21.188 +	xenfb_delete(&xenfb->pub);
  21.189 +	errno = serrno;
  21.190 +	return NULL;
  21.191 +}
  21.192 +
  21.193 +void xenfb_delete(struct xenfb *xenfb_pub)
  21.194 +{
  21.195 +	struct xenfb_private *xenfb = (struct xenfb_private *)xenfb_pub;
  21.196 +
  21.197 +	xenfb_detach_dom(xenfb);
  21.198 +	if (xenfb->xc >= 0)
  21.199 +		xc_interface_close(xenfb->xc);
  21.200 +	if (xenfb->evt_xch >= 0)
  21.201 +		xc_evtchn_close(xenfb->evt_xch);
  21.202 +	if (xenfb->xsh)
  21.203 +		xs_daemon_close(xenfb->xsh);
  21.204 +	free(xenfb);
  21.205 +}
  21.206 +
  21.207 +static enum xenbus_state xenfb_read_state(struct xs_handle *xsh,
  21.208 +					  const char *dir)
  21.209 +{
  21.210 +	int ret, state;
  21.211 +
  21.212 +	ret = xenfb_xs_scanf1(xsh, dir, "state", "%d", &state);
  21.213 +	if (ret < 0)
  21.214 +		return XenbusStateUnknown;
  21.215 +
  21.216 +	if ((unsigned)state > XenbusStateClosed)
  21.217 +		state = XenbusStateUnknown;
  21.218 +	return state;
  21.219 +}
  21.220 +
  21.221 +static int xenfb_switch_state(struct xenfb_device *dev,
  21.222 +			      enum xenbus_state state)
  21.223 +{
  21.224 +	struct xs_handle *xsh = dev->xenfb->xsh;
  21.225 +
  21.226 +	if (xenfb_xs_printf(xsh, dev->nodename, "state", "%d", state) < 0)
  21.227 +		return -1;
  21.228 +	dev->state = state;
  21.229 +	return 0;
  21.230 +}
  21.231 +
  21.232 +static int xenfb_wait_for_state(struct xs_handle *xsh, const char *dir,
  21.233 +				unsigned awaited)
  21.234 +{
  21.235 +	unsigned state, dummy;
  21.236 +	char **vec;
  21.237 +
  21.238 +	for (;;) {
  21.239 +		state = xenfb_read_state(xsh, dir);
  21.240 +		if (state < 0)
  21.241 +			return -1;
  21.242 +
  21.243 +		if ((1 << state) & awaited)
  21.244 +			return state;
  21.245 +
  21.246 +		vec = xs_read_watch(xsh, &dummy);
  21.247 +		if (!vec)
  21.248 +			return -1;
  21.249 +		free(vec);
  21.250 +	}
  21.251 +}
  21.252 +
  21.253 +static int xenfb_wait_for_backend_creation(struct xenfb_device *dev)
  21.254 +{
  21.255 +	struct xs_handle *xsh = dev->xenfb->xsh;
  21.256 +	int state;
  21.257 +
  21.258 +	if (!xs_watch(xsh, dev->nodename, ""))
  21.259 +		return -1;
  21.260 +	state = xenfb_wait_for_state(xsh, dev->nodename,
  21.261 +			(1 << XenbusStateInitialising)
  21.262 +			| (1 << XenbusStateClosed)
  21.263 +#if 1 /* TODO fudging state to permit restarting; to be removed */
  21.264 +			| (1 << XenbusStateInitWait)
  21.265 +			| (1 << XenbusStateConnected)
  21.266 +			| (1 << XenbusStateClosing)
  21.267 +#endif
  21.268 +			);
  21.269 +	xs_unwatch(xsh, dev->nodename, "");
  21.270 +
  21.271 +	switch (state) {
  21.272 +#if 1
  21.273 +	case XenbusStateInitWait:
  21.274 +	case XenbusStateConnected:
  21.275 +		printf("Fudging state to %d\n", XenbusStateInitialising); /* FIXME */
  21.276 +#endif
  21.277 +	case XenbusStateInitialising:
  21.278 +	case XenbusStateClosing:
  21.279 +	case XenbusStateClosed:
  21.280 +		break;
  21.281 +	default:
  21.282 +		return -1;
  21.283 +	}
  21.284 +
  21.285 +	return 0;
  21.286 +}
  21.287 +
  21.288 +static int xenfb_hotplug(struct xenfb_device *dev)
  21.289 +{
  21.290 +	if (xenfb_xs_printf(dev->xenfb->xsh, dev->nodename,
  21.291 +			    "hotplug-status", "connected"))
  21.292 +		return -1;
  21.293 +	return 0;
  21.294 +}
  21.295 +
  21.296 +static int xenfb_wait_for_frontend_initialised(struct xenfb_device *dev)
  21.297 +{
  21.298 +	switch (xenfb_wait_for_state(dev->xenfb->xsh, dev->otherend,
  21.299 +#if 1 /* TODO fudging state to permit restarting; to be removed */
  21.300 +			(1 << XenbusStateInitialised)
  21.301 +			| (1 << XenbusStateConnected)
  21.302 +#else
  21.303 +			1 << XenbusStateInitialised,
  21.304 +#endif
  21.305 +			)) {
  21.306 +#if 1
  21.307 +	case XenbusStateConnected:
  21.308 +		printf("Fudging state to %d\n", XenbusStateInitialised); /* FIXME */
  21.309 +#endif
  21.310 +	case XenbusStateInitialised:
  21.311 +		break;
  21.312 +	default:
  21.313 +		return -1;
  21.314 +	}
  21.315 +
  21.316 +	return 0;
  21.317 +}
  21.318 +
  21.319 +static int xenfb_map_fb(struct xenfb_private *xenfb, int domid)
  21.320 +{
  21.321 +	struct xenfb_page *page = xenfb->fb.page;
  21.322 +	int n_fbmfns;
  21.323 +	int n_fbdirs;
  21.324 +	unsigned long *fbmfns;
  21.325 +
  21.326 +	n_fbmfns = (xenfb->fb_len + (XC_PAGE_SIZE - 1)) / XC_PAGE_SIZE;
  21.327 +	n_fbdirs = n_fbmfns * sizeof(unsigned long);
  21.328 +	n_fbdirs = (n_fbdirs + (XC_PAGE_SIZE - 1)) / XC_PAGE_SIZE;
  21.329 +
  21.330 +	/*
  21.331 +	 * Bug alert: xc_map_foreign_batch() can fail partly and
  21.332 +	 * return a non-null value.  This is a design flaw.  When it
  21.333 +	 * happens, we happily continue here, and later crash on
  21.334 +	 * access.
  21.335 +	 */
  21.336 +	fbmfns = xc_map_foreign_batch(xenfb->xc, domid,
  21.337 +			PROT_READ, page->pd, n_fbdirs);
  21.338 +	if (fbmfns == NULL)
  21.339 +		return -1;
  21.340 +
  21.341 +	xenfb->pub.pixels = xc_map_foreign_batch(xenfb->xc, domid,
  21.342 +				PROT_READ | PROT_WRITE, fbmfns, n_fbmfns);
  21.343 +	if (xenfb->pub.pixels == NULL) {
  21.344 +		munmap(fbmfns, n_fbdirs * XC_PAGE_SIZE);
  21.345 +		return -1;
  21.346 +	}
  21.347 +
  21.348 +	return munmap(fbmfns, n_fbdirs * XC_PAGE_SIZE);
  21.349 +}
  21.350 +
  21.351 +static int xenfb_bind(struct xenfb_device *dev)
  21.352 +{
  21.353 +	struct xenfb_private *xenfb = dev->xenfb;
  21.354 +	unsigned long mfn;
  21.355 +	evtchn_port_t evtchn;
  21.356 +
  21.357 +	if (xenfb_xs_scanf1(xenfb->xsh, dev->otherend, "page-ref", "%lu",
  21.358 +			    &mfn) < 0)
  21.359 +		return -1;
  21.360 +	if (xenfb_xs_scanf1(xenfb->xsh, dev->otherend, "event-channel", "%u",
  21.361 +			    &evtchn) < 0)
  21.362 +		return -1;
  21.363 +
  21.364 +	dev->port = xc_evtchn_bind_interdomain(xenfb->evt_xch,
  21.365 +					       dev->otherend_id, evtchn);
  21.366 +	if (dev->port == -1)
  21.367 +		return -1;
  21.368 +
  21.369 +	dev->page = xc_map_foreign_range(xenfb->xc, dev->otherend_id,
  21.370 +			XC_PAGE_SIZE, PROT_READ | PROT_WRITE, mfn);
  21.371 +	if (dev->page == NULL)
  21.372 +		return -1;
  21.373 +
  21.374 +	return 0;
  21.375 +}
  21.376 +
  21.377 +static void xenfb_unbind(struct xenfb_device *dev)
  21.378 +{
  21.379 +	if (dev->page) {
  21.380 +		munmap(dev->page, XC_PAGE_SIZE);
  21.381 +		dev->page = NULL;
  21.382 +	}
  21.383 +        if (dev->port >= 0) {
  21.384 +		xc_evtchn_unbind(dev->xenfb->evt_xch, dev->port);
  21.385 +		dev->port = -1;
  21.386 +	}
  21.387 +}
  21.388 +
  21.389 +static int xenfb_wait_for_frontend_connected(struct xenfb_device *dev)
  21.390 +{
  21.391 +	switch (xenfb_wait_for_state(dev->xenfb->xsh, dev->otherend,
  21.392 +				     1 << XenbusStateConnected)) {
  21.393 +	case XenbusStateConnected:
  21.394 +		break;
  21.395 +	default:
  21.396 +		return -1;
  21.397 +	}
  21.398 +
  21.399 +	return 0;
  21.400 +}
  21.401 +
  21.402 +static void xenfb_dev_fatal(struct xenfb_device *dev, int err,
  21.403 +			    const char *fmt, ...)
  21.404 +{
  21.405 +	struct xs_handle *xsh = dev->xenfb->xsh;
  21.406 +	va_list ap;
  21.407 +	char errdir[80];
  21.408 +	char buf[1024];
  21.409 +	int n;
  21.410 +
  21.411 +	fprintf(stderr, "%s ", dev->nodename); /* somewhat crude */
  21.412 +	va_start(ap, fmt);
  21.413 +	vfprintf(stderr, fmt, ap);
  21.414 +	va_end(ap);
  21.415 +	if (err)
  21.416 +		fprintf(stderr, " (%s)", strerror(err));
  21.417 +	putc('\n', stderr);
  21.418 +
  21.419 +	if (!xenfb_path_in_dom(xsh, errdir, sizeof(errdir), 0,
  21.420 +			       "error/%s", dev->nodename))
  21.421 +		goto out;	/* FIXME complain */
  21.422 +
  21.423 +	va_start(ap, fmt);
  21.424 +	n = snprintf(buf, sizeof(buf), "%d ", err);
  21.425 +	snprintf(buf + n, sizeof(buf) - n, fmt, ap);
  21.426 +	va_end(ap);
  21.427 +
  21.428 +	if (xenfb_xs_printf(xsh, buf, "error", "%s", buf) < 0)
  21.429 +		goto out;	/* FIXME complain */
  21.430 +
  21.431 + out:
  21.432 +	xenfb_switch_state(dev, XenbusStateClosing);
  21.433 +}
  21.434 +
  21.435 +int xenfb_attach_dom(struct xenfb *xenfb_pub, int domid)
  21.436 +{
  21.437 +	struct xenfb_private *xenfb = (struct xenfb_private *)xenfb_pub;
  21.438 +	struct xs_handle *xsh = xenfb->xsh;
  21.439 +	int val, serrno;
  21.440 +	struct xenfb_page *fb_page;
  21.441 +
  21.442 +	xenfb_detach_dom(xenfb);
  21.443 +
  21.444 +	xenfb_device_set_domain(&xenfb->fb, domid);
  21.445 +	xenfb_device_set_domain(&xenfb->kbd, domid);
  21.446 +
  21.447 +	if (xenfb_wait_for_backend_creation(&xenfb->fb) < 0)
  21.448 +		goto error;
  21.449 +	if (xenfb_wait_for_backend_creation(&xenfb->kbd) < 0)
  21.450 +		goto error;
  21.451 +
  21.452 +	if (xenfb_xs_printf(xsh, xenfb->kbd.nodename, "feature-abs-pointer", "1"))
  21.453 +		goto error;
  21.454 +	if (xenfb_switch_state(&xenfb->fb, XenbusStateInitWait))
  21.455 +		goto error;
  21.456 +	if (xenfb_switch_state(&xenfb->kbd, XenbusStateInitWait))
  21.457 +		goto error;
  21.458 +
  21.459 +	if (xenfb_hotplug(&xenfb->fb) < 0)
  21.460 +		goto error;
  21.461 +	if (xenfb_hotplug(&xenfb->kbd) < 0)
  21.462 +		goto error;
  21.463 +
  21.464 +	if (!xs_watch(xsh, xenfb->fb.otherend, ""))
  21.465 +		goto error;
  21.466 +	if (!xs_watch(xsh, xenfb->kbd.otherend, ""))
  21.467 +		goto error;
  21.468 +
  21.469 +	if (xenfb_wait_for_frontend_initialised(&xenfb->fb) < 0)
  21.470 +		goto error;
  21.471 +	if (xenfb_wait_for_frontend_initialised(&xenfb->kbd) < 0)
  21.472 +		goto error;
  21.473 +
  21.474 +	if (xenfb_bind(&xenfb->fb) < 0)
  21.475 +		goto error;
  21.476 +	if (xenfb_bind(&xenfb->kbd) < 0)
  21.477 +		goto error;
  21.478 +
  21.479 +	if (xenfb_xs_scanf1(xsh, xenfb->fb.otherend, "feature-update",
  21.480 +			    "%d", &val) < 0)
  21.481 +		val = 0;
  21.482 +	if (!val) {
  21.483 +		errno = ENOTSUP;
  21.484 +		goto error;
  21.485 +	}
  21.486 +	xenfb_xs_printf(xsh, xenfb->fb.nodename, "request-update", "1");
  21.487 +
  21.488 +	/* TODO check for permitted ranges */
  21.489 +	fb_page = xenfb->fb.page;
  21.490 +	xenfb->pub.depth = fb_page->depth;
  21.491 +	xenfb->pub.width = fb_page->width;
  21.492 +	xenfb->pub.height = fb_page->height;
  21.493 +	/* TODO check for consistency with the above */
  21.494 +	xenfb->fb_len = fb_page->mem_length;
  21.495 +	xenfb->pub.row_stride = fb_page->line_length;
  21.496 +
  21.497 +	if (xenfb_map_fb(xenfb, domid) < 0)
  21.498 +		goto error;
  21.499 +
  21.500 +	if (xenfb_switch_state(&xenfb->fb, XenbusStateConnected))
  21.501 +		goto error;
  21.502 +	if (xenfb_switch_state(&xenfb->kbd, XenbusStateConnected))
  21.503 +		goto error;
  21.504 +
  21.505 +	if (xenfb_wait_for_frontend_connected(&xenfb->kbd) < 0)
  21.506 +		goto error;
  21.507 +	if (xenfb_xs_scanf1(xsh, xenfb->kbd.otherend, "request-abs-pointer",
  21.508 +			    "%d", &val) < 0)
  21.509 +		val = 0;
  21.510 +	xenfb->pub.abs_pointer_wanted = val;
  21.511 +
  21.512 +	return 0;
  21.513 +
  21.514 + error:
  21.515 +	serrno = errno;
  21.516 +	xenfb_detach_dom(xenfb);
  21.517 +	xenfb_dev_fatal(&xenfb->fb, serrno, "on fire");
  21.518 +	xenfb_dev_fatal(&xenfb->kbd, serrno, "on fire");
  21.519 +        errno = serrno;
  21.520 +        return -1;
  21.521 +}
  21.522 +
  21.523 +static void xenfb_detach_dom(struct xenfb_private *xenfb)
  21.524 +{
  21.525 +	xenfb_unbind(&xenfb->fb);
  21.526 +	xenfb_unbind(&xenfb->kbd);
  21.527 +	if (xenfb->pub.pixels) {
  21.528 +		munmap(xenfb->pub.pixels, xenfb->fb_len);
  21.529 +		xenfb->pub.pixels = NULL;
  21.530 +	}
  21.531 +}
  21.532 +
  21.533 +static void xenfb_on_fb_event(struct xenfb_private *xenfb)
  21.534 +{
  21.535 +	uint32_t prod, cons;
  21.536 +	struct xenfb_page *page = xenfb->fb.page;
  21.537 +
  21.538 +	prod = page->out_prod;
  21.539 +	if (prod == page->out_cons)
  21.540 +		return;
  21.541 +	rmb();			/* ensure we see ring contents up to prod */
  21.542 +	for (cons = page->out_cons; cons != prod; cons++) {
  21.543 +		union xenfb_out_event *event = &XENFB_OUT_RING_REF(page, cons);
  21.544 +
  21.545 +		switch (event->type) {
  21.546 +		case XENFB_TYPE_UPDATE:
  21.547 +                    if (xenfb->pub.update)
  21.548 +			xenfb->pub.update(&xenfb->pub,
  21.549 +					  event->update.x, event->update.y,
  21.550 +					  event->update.width, event->update.height);
  21.551 +                    break;
  21.552 +		}
  21.553 +	}
  21.554 +	mb();			/* ensure we're done with ring contents */
  21.555 +	page->out_cons = cons;
  21.556 +	xc_evtchn_notify(xenfb->evt_xch, xenfb->fb.port);
  21.557 +}
  21.558 +
  21.559 +static void xenfb_on_kbd_event(struct xenfb_private *xenfb)
  21.560 +{
  21.561 +	struct xenkbd_page *page = xenfb->kbd.page;
  21.562 +
  21.563 +	/* We don't understand any keyboard events, so just ignore them. */
  21.564 +	if (page->out_prod == page->out_cons)
  21.565 +		return;
  21.566 +	page->out_cons = page->out_prod;
  21.567 +	xc_evtchn_notify(xenfb->evt_xch, xenfb->kbd.port);
  21.568 +}
  21.569 +
  21.570 +static void xenfb_on_state_change(struct xenfb_device *dev)
  21.571 +{
  21.572 +	enum xenbus_state state;
  21.573 +
  21.574 +	state = xenfb_read_state(dev->xenfb->xsh, dev->otherend);
  21.575 +
  21.576 +	switch (state) {
  21.577 +	case XenbusStateUnknown:
  21.578 +	case XenbusStateInitialising:
  21.579 +	case XenbusStateInitWait:
  21.580 +	case XenbusStateInitialised:
  21.581 +	case XenbusStateConnected:
  21.582 +		break;
  21.583 +	case XenbusStateClosing:
  21.584 +		xenfb_unbind(dev);
  21.585 +		xenfb_switch_state(dev, state);
  21.586 +		break;
  21.587 +	case XenbusStateClosed:
  21.588 +		xs_unwatch(dev->xenfb->xsh, dev->otherend, "");
  21.589 +		xenfb_switch_state(dev, state);
  21.590 +	}
  21.591 +}
  21.592 +
  21.593 +int xenfb_poll(struct xenfb *xenfb_pub, fd_set *readfds)
  21.594 +{
  21.595 +	struct xenfb_private *xenfb = (struct xenfb_private *)xenfb_pub;
  21.596 +	evtchn_port_t port;
  21.597 +	unsigned dummy;
  21.598 +	char **vec;
  21.599 +
  21.600 +	if (FD_ISSET(xc_evtchn_fd(xenfb->evt_xch), readfds)) {
  21.601 +		port = xc_evtchn_pending(xenfb->evt_xch);
  21.602 +		if (port == -1)
  21.603 +			return -1;
  21.604 +
  21.605 +		if (port == xenfb->fb.port)
  21.606 +			xenfb_on_fb_event(xenfb);
  21.607 +		else if (port == xenfb->kbd.port)
  21.608 +			xenfb_on_kbd_event(xenfb);
  21.609 +
  21.610 +		if (xc_evtchn_unmask(xenfb->evt_xch, port) == -1)
  21.611 +			return -1;
  21.612 +	}
  21.613 +
  21.614 +	if (FD_ISSET(xs_fileno(xenfb->xsh), readfds)) {
  21.615 +		vec = xs_read_watch(xenfb->xsh, &dummy);
  21.616 +		free(vec);
  21.617 +		xenfb_on_state_change(&xenfb->fb);
  21.618 +		xenfb_on_state_change(&xenfb->kbd);
  21.619 +	}
  21.620 +
  21.621 +	return 0;
  21.622 +}
  21.623 +
  21.624 +int xenfb_select_fds(struct xenfb *xenfb_pub, fd_set *readfds)
  21.625 +{
  21.626 +	struct xenfb_private *xenfb = (struct xenfb_private *)xenfb_pub;
  21.627 +	int fd1 = xc_evtchn_fd(xenfb->evt_xch);
  21.628 +	int fd2 = xs_fileno(xenfb->xsh);
  21.629 +
  21.630 +	FD_SET(fd1, readfds);
  21.631 +	FD_SET(fd2, readfds);
  21.632 +	return fd1 > fd2 ? fd1 + 1 : fd2 + 1;
  21.633 +}
  21.634 +
  21.635 +static int xenfb_kbd_event(struct xenfb_private *xenfb,
  21.636 +			   union xenkbd_in_event *event)
  21.637 +{
  21.638 +	uint32_t prod;
  21.639 +	struct xenkbd_page *page = xenfb->kbd.page;
  21.640 +
  21.641 +	if (xenfb->kbd.state != XenbusStateConnected)
  21.642 +		return 0;
  21.643 +
  21.644 +	prod = page->in_prod;
  21.645 +	if (prod - page->in_cons == XENKBD_IN_RING_LEN) {
  21.646 +		errno = EAGAIN;
  21.647 +		return -1;
  21.648 +	}
  21.649 +
  21.650 +	mb();			/* ensure ring space available */
  21.651 +	XENKBD_IN_RING_REF(page, prod) = *event;
  21.652 +	wmb();			/* ensure ring contents visible */
  21.653 +	page->in_prod = prod + 1;
  21.654 +	return xc_evtchn_notify(xenfb->evt_xch, xenfb->kbd.port);
  21.655 +}
  21.656 +
  21.657 +int xenfb_send_key(struct xenfb *xenfb_pub, bool down, int keycode)
  21.658 +{
  21.659 +	struct xenfb_private *xenfb = (struct xenfb_private *)xenfb_pub;
  21.660 +	union xenkbd_in_event event;
  21.661 +
  21.662 +	memset(&event, 0, XENKBD_IN_EVENT_SIZE);
  21.663 +	event.type = XENKBD_TYPE_KEY;
  21.664 +	event.key.pressed = down ? 1 : 0;
  21.665 +	event.key.keycode = keycode;
  21.666 +
  21.667 +	return xenfb_kbd_event(xenfb, &event);
  21.668 +}
  21.669 +
  21.670 +int xenfb_send_motion(struct xenfb *xenfb_pub, int rel_x, int rel_y)
  21.671 +{
  21.672 +	struct xenfb_private *xenfb = (struct xenfb_private *)xenfb_pub;
  21.673 +	union xenkbd_in_event event;
  21.674 +
  21.675 +	memset(&event, 0, XENKBD_IN_EVENT_SIZE);
  21.676 +	event.type = XENKBD_TYPE_MOTION;
  21.677 +	event.motion.rel_x = rel_x;
  21.678 +	event.motion.rel_y = rel_y;
  21.679 +
  21.680 +	return xenfb_kbd_event(xenfb, &event);
  21.681 +}
  21.682 +
  21.683 +int xenfb_send_position(struct xenfb *xenfb_pub, int abs_x, int abs_y)
  21.684 +{
  21.685 +	struct xenfb_private *xenfb = (struct xenfb_private *)xenfb_pub;
  21.686 +	union xenkbd_in_event event;
  21.687 +
  21.688 +	memset(&event, 0, XENKBD_IN_EVENT_SIZE);
  21.689 +	event.type = XENKBD_TYPE_POS;
  21.690 +	event.pos.abs_x = abs_x;
  21.691 +	event.pos.abs_y = abs_y;
  21.692 +
  21.693 +	return xenfb_kbd_event(xenfb, &event);
  21.694 +}
    22.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    22.2 +++ b/tools/xenfb/xenfb.h	Fri Dec 01 09:48:32 2006 +0000
    22.3 @@ -0,0 +1,34 @@
    22.4 +#ifndef _XENFB_H_
    22.5 +#define _XENFB_H_
    22.6 +
    22.7 +#include <stdbool.h>
    22.8 +#include <sys/types.h>
    22.9 +
   22.10 +struct xenfb
   22.11 +{
   22.12 +	void *pixels;
   22.13 +
   22.14 +	int row_stride;
   22.15 +	int depth;
   22.16 +	int width;
   22.17 +	int height;
   22.18 +	int abs_pointer_wanted;
   22.19 +
   22.20 +	void *user_data;
   22.21 +
   22.22 +	void (*update)(struct xenfb *xenfb, int x, int y, int width, int height);
   22.23 +};
   22.24 +
   22.25 +struct xenfb *xenfb_new(void);
   22.26 +void xenfb_delete(struct xenfb *xenfb);
   22.27 +
   22.28 +int xenfb_attach_dom(struct xenfb *xenfb, int domid);
   22.29 +
   22.30 +int xenfb_select_fds(struct xenfb *xenfb, fd_set *readfds);
   22.31 +int xenfb_poll(struct xenfb *xenfb, fd_set *readfds);
   22.32 +
   22.33 +int xenfb_send_key(struct xenfb *xenfb, bool down, int keycode);
   22.34 +int xenfb_send_motion(struct xenfb *xenfb, int rel_x, int rel_y);
   22.35 +int xenfb_send_position(struct xenfb *xenfb, int abs_x, int abs_y);
   22.36 +
   22.37 +#endif
    23.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    23.2 +++ b/xen/include/public/io/fbif.h	Fri Dec 01 09:48:32 2006 +0000
    23.3 @@ -0,0 +1,116 @@
    23.4 +/*
    23.5 + * fbif.h -- Xen virtual frame buffer device
    23.6 + *
    23.7 + * Copyright (C) 2005 Anthony Liguori <aliguori@us.ibm.com>
    23.8 + * Copyright (C) 2006 Red Hat, Inc., Markus Armbruster <armbru@redhat.com>
    23.9 + *
   23.10 + *  This file is subject to the terms and conditions of the GNU General Public
   23.11 + *  License. See the file COPYING in the main directory of this archive for
   23.12 + *  more details.
   23.13 + */
   23.14 +
   23.15 +#ifndef __XEN_PUBLIC_IO_FBIF_H__
   23.16 +#define __XEN_PUBLIC_IO_FBIF_H__
   23.17 +
   23.18 +#include <asm/types.h>
   23.19 +
   23.20 +/* Out events (frontend -> backend) */
   23.21 +
   23.22 +/*
   23.23 + * Out events may be sent only when requested by backend, and receipt
   23.24 + * of an unknown out event is an error.
   23.25 + */
   23.26 +
   23.27 +/* Event type 1 currently not used */
   23.28 +/*
   23.29 + * Framebuffer update notification event
   23.30 + * Capable frontend sets feature-update in xenstore.
   23.31 + * Backend requests it by setting request-update in xenstore.
   23.32 + */
   23.33 +#define XENFB_TYPE_UPDATE 2
   23.34 +
   23.35 +struct xenfb_update
   23.36 +{
   23.37 +	__u8 type;		/* XENFB_TYPE_UPDATE */
   23.38 +	__s32 x;		/* source x */
   23.39 +	__s32 y;		/* source y */
   23.40 +	__s32 width;		/* rect width */
   23.41 +	__s32 height;		/* rect height */
   23.42 +};
   23.43 +
   23.44 +#define XENFB_OUT_EVENT_SIZE 40
   23.45 +
   23.46 +union xenfb_out_event
   23.47 +{
   23.48 +	__u8 type;
   23.49 +	struct xenfb_update update;
   23.50 +	char pad[XENFB_OUT_EVENT_SIZE];
   23.51 +};
   23.52 +
   23.53 +/* In events (backend -> frontend) */
   23.54 +
   23.55 +/*
   23.56 + * Frontends should ignore unknown in events.
   23.57 + * No in events currently defined.
   23.58 + */
   23.59 +
   23.60 +#define XENFB_IN_EVENT_SIZE 40
   23.61 +
   23.62 +union xenfb_in_event
   23.63 +{
   23.64 +	__u8 type;
   23.65 +	char pad[XENFB_IN_EVENT_SIZE];
   23.66 +};
   23.67 +
   23.68 +/* shared page */
   23.69 +
   23.70 +#define XENFB_IN_RING_SIZE 1024
   23.71 +#define XENFB_IN_RING_LEN (XENFB_IN_RING_SIZE / XENFB_IN_EVENT_SIZE)
   23.72 +#define XENFB_IN_RING_OFFS 1024
   23.73 +#define XENFB_IN_RING(page) \
   23.74 +    ((union xenfb_in_event *)((char *)(page) + XENFB_IN_RING_OFFS))
   23.75 +#define XENFB_IN_RING_REF(page, idx) \
   23.76 +    (XENFB_IN_RING((page))[(idx) % XENFB_IN_RING_LEN])
   23.77 +
   23.78 +#define XENFB_OUT_RING_SIZE 2048
   23.79 +#define XENFB_OUT_RING_LEN (XENFB_OUT_RING_SIZE / XENFB_OUT_EVENT_SIZE)
   23.80 +#define XENFB_OUT_RING_OFFS (XENFB_IN_RING_OFFS + XENFB_IN_RING_SIZE)
   23.81 +#define XENFB_OUT_RING(page) \
   23.82 +    ((union xenfb_out_event *)((char *)(page) + XENFB_OUT_RING_OFFS))
   23.83 +#define XENFB_OUT_RING_REF(page, idx) \
   23.84 +    (XENFB_OUT_RING((page))[(idx) % XENFB_OUT_RING_LEN])
   23.85 +
   23.86 +struct xenfb_page
   23.87 +{
   23.88 +	__u32 in_cons, in_prod;
   23.89 +	__u32 out_cons, out_prod;
   23.90 +
   23.91 +	__s32 width;         /* the width of the framebuffer (in pixels) */
   23.92 +	__s32 height;        /* the height of the framebuffer (in pixels) */
   23.93 +	__u32 line_length;   /* the length of a row of pixels (in bytes) */
   23.94 +	__u32 mem_length;    /* the length of the framebuffer (in bytes) */
   23.95 +	__u8 depth;          /* the depth of a pixel (in bits) */
   23.96 +
   23.97 +	/*
   23.98 +	 * Framebuffer page directory
   23.99 +	 *
  23.100 +	 * Each directory page holds PAGE_SIZE / sizeof(*pd)
  23.101 +	 * framebuffer pages, and can thus map up to PAGE_SIZE *
  23.102 +	 * PAGE_SIZE / sizeof(*pd) bytes.  With PAGE_SIZE == 4096 and
  23.103 +	 * sizeof(unsigned long) == 4, that's 4 Megs.  Two directory
  23.104 +	 * pages should be enough for a while.
  23.105 +	 */
  23.106 +	unsigned long pd[2];
  23.107 +};
  23.108 +
  23.109 +/*
  23.110 + * Wart: xenkbd needs to know resolution.  Put it here until a better
  23.111 + * solution is found, but don't leak it to the backend.
  23.112 + */
  23.113 +#ifdef __KERNEL__
  23.114 +#define XENFB_WIDTH 800
  23.115 +#define XENFB_HEIGHT 600
  23.116 +#define XENFB_DEPTH 32
  23.117 +#endif
  23.118 +
  23.119 +#endif
    24.1 --- /dev/null	Thu Jan 01 00:00:00 1970 +0000
    24.2 +++ b/xen/include/public/io/kbdif.h	Fri Dec 01 09:48:32 2006 +0000
    24.3 @@ -0,0 +1,108 @@
    24.4 +/*
    24.5 + * kbdif.h -- Xen virtual keyboard/mouse
    24.6 + *
    24.7 + * Copyright (C) 2005 Anthony Liguori <aliguori@us.ibm.com>
    24.8 + * Copyright (C) 2006 Red Hat, Inc., Markus Armbruster <armbru@redhat.com>
    24.9 + *
   24.10 + *  This file is subject to the terms and conditions of the GNU General Public
   24.11 + *  License. See the file COPYING in the main directory of this archive for
   24.12 + *  more details.
   24.13 + */
   24.14 +
   24.15 +#ifndef __XEN_PUBLIC_IO_KBDIF_H__
   24.16 +#define __XEN_PUBLIC_IO_KBDIF_H__
   24.17 +
   24.18 +#include <asm/types.h>
   24.19 +
   24.20 +/* In events (backend -> frontend) */
   24.21 +
   24.22 +/*
   24.23 + * Frontends should ignore unknown in events.
   24.24 + */
   24.25 +
   24.26 +/* Pointer movement event */
   24.27 +#define XENKBD_TYPE_MOTION  1
   24.28 +/* Event type 2 currently not used */
   24.29 +/* Key event (includes pointer buttons) */
   24.30 +#define XENKBD_TYPE_KEY     3
   24.31 +/*
   24.32 + * Pointer position event
   24.33 + * Capable backend sets feature-abs-pointer in xenstore.
   24.34 + * Frontend requests ot instead of XENKBD_TYPE_MOTION by setting
   24.35 + * request-abs-update in xenstore.
   24.36 + */
   24.37 +#define XENKBD_TYPE_POS     4
   24.38 +
   24.39 +struct xenkbd_motion
   24.40 +{
   24.41 +	__u8 type;         /* XENKBD_TYPE_MOTION */
   24.42 +	__s32 rel_x;       /* relative X motion */
   24.43 +	__s32 rel_y;       /* relative Y motion */
   24.44 +};
   24.45 +
   24.46 +struct xenkbd_key
   24.47 +{
   24.48 +	__u8 type;         /* XENKBD_TYPE_KEY */
   24.49 +	__u8 pressed;      /* 1 if pressed; 0 otherwise */
   24.50 +	__u32 keycode;     /* KEY_* from linux/input.h */
   24.51 +};
   24.52 +
   24.53 +struct xenkbd_position
   24.54 +{
   24.55 +	__u8 type;         /* XENKBD_TYPE_POS */
   24.56 +	__s32 abs_x;       /* absolute X position (in FB pixels) */
   24.57 +	__s32 abs_y;       /* absolute Y position (in FB pixels) */
   24.58 +};
   24.59 +
   24.60 +#define XENKBD_IN_EVENT_SIZE 40
   24.61 +
   24.62 +union xenkbd_in_event
   24.63 +{
   24.64 +	__u8 type;
   24.65 +	struct xenkbd_motion motion;
   24.66 +	struct xenkbd_key key;
   24.67 +	struct xenkbd_position pos;
   24.68 +	char pad[XENKBD_IN_EVENT_SIZE];
   24.69 +};
   24.70 +
   24.71 +/* Out events (frontend -> backend) */
   24.72 +
   24.73 +/*
   24.74 + * Out events may be sent only when requested by backend, and receipt
   24.75 + * of an unknown out event is an error.
   24.76 + * No out events currently defined.
   24.77 + */
   24.78 +
   24.79 +#define XENKBD_OUT_EVENT_SIZE 40
   24.80 +
   24.81 +union xenkbd_out_event
   24.82 +{
   24.83 +	__u8 type;
   24.84 +	char pad[XENKBD_OUT_EVENT_SIZE];
   24.85 +};
   24.86 +
   24.87 +/* shared page */
   24.88 +
   24.89 +#define XENKBD_IN_RING_SIZE 2048
   24.90 +#define XENKBD_IN_RING_LEN (XENKBD_IN_RING_SIZE / XENKBD_IN_EVENT_SIZE)
   24.91 +#define XENKBD_IN_RING_OFFS 1024
   24.92 +#define XENKBD_IN_RING(page) \
   24.93 +    ((union xenkbd_in_event *)((char *)(page) + XENKBD_IN_RING_OFFS))
   24.94 +#define XENKBD_IN_RING_REF(page, idx) \
   24.95 +    (XENKBD_IN_RING((page))[(idx) % XENKBD_IN_RING_LEN])
   24.96 +
   24.97 +#define XENKBD_OUT_RING_SIZE 1024
   24.98 +#define XENKBD_OUT_RING_LEN (XENKBD_OUT_RING_SIZE / XENKBD_OUT_EVENT_SIZE)
   24.99 +#define XENKBD_OUT_RING_OFFS (XENKBD_IN_RING_OFFS + XENKBD_IN_RING_SIZE)
  24.100 +#define XENKBD_OUT_RING(page) \
  24.101 +    ((union xenkbd_out_event *)((char *)(page) + XENKBD_OUT_RING_OFFS))
  24.102 +#define XENKBD_OUT_RING_REF(page, idx) \
  24.103 +    (XENKBD_OUT_RING((page))[(idx) % XENKBD_OUT_RING_LEN])
  24.104 +
  24.105 +struct xenkbd_page
  24.106 +{
  24.107 +	__u32 in_cons, in_prod;
  24.108 +	__u32 out_cons, out_prod;
  24.109 +};
  24.110 +
  24.111 +#endif