xen-vtx-unstable

annotate linux-2.6-xen-sparse/drivers/xen/console/console.c @ 6774:4d899a738d59

merge?
author cl349@firebug.cl.cam.ac.uk
date Tue Sep 13 15:05:49 2005 +0000 (2005-09-13)
parents 864d936a0482 1f460d0fd6c6
children e7c7196fa329 8ca0f98ba8e2
rev   line source
cl349@4087 1 /******************************************************************************
cl349@4087 2 * console.c
cl349@4087 3 *
cl349@4087 4 * Virtual console driver.
cl349@4087 5 *
cl349@4087 6 * Copyright (c) 2002-2004, K A Fraser.
cl349@4087 7 *
cl349@4087 8 * This file may be distributed separately from the Linux kernel, or
cl349@4087 9 * incorporated into other software packages, subject to the following license:
cl349@4087 10 *
cl349@4087 11 * Permission is hereby granted, free of charge, to any person obtaining a copy
cl349@4087 12 * of this source file (the "Software"), to deal in the Software without
cl349@4087 13 * restriction, including without limitation the rights to use, copy, modify,
cl349@4087 14 * merge, publish, distribute, sublicense, and/or sell copies of the Software,
cl349@4087 15 * and to permit persons to whom the Software is furnished to do so, subject to
cl349@4087 16 * the following conditions:
cl349@4087 17 *
cl349@4087 18 * The above copyright notice and this permission notice shall be included in
cl349@4087 19 * all copies or substantial portions of the Software.
cl349@4087 20 *
cl349@4087 21 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
cl349@4087 22 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
cl349@4087 23 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
cl349@4087 24 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
cl349@4087 25 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
cl349@4087 26 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
cl349@4087 27 * IN THE SOFTWARE.
cl349@4087 28 */
cl349@4087 29
cl349@4087 30 #include <linux/config.h>
cl349@4087 31 #include <linux/version.h>
cl349@4087 32 #include <linux/module.h>
cl349@4087 33 #include <linux/errno.h>
cl349@4087 34 #include <linux/signal.h>
cl349@4087 35 #include <linux/sched.h>
cl349@4087 36 #include <linux/interrupt.h>
cl349@4087 37 #include <linux/tty.h>
cl349@4087 38 #include <linux/tty_flip.h>
cl349@4087 39 #include <linux/serial.h>
cl349@4087 40 #include <linux/major.h>
cl349@4087 41 #include <linux/ptrace.h>
cl349@4087 42 #include <linux/ioport.h>
cl349@4087 43 #include <linux/mm.h>
cl349@4087 44 #include <linux/slab.h>
cl349@4087 45 #include <linux/init.h>
cl349@4087 46 #include <linux/console.h>
kaf24@4535 47 #include <linux/bootmem.h>
cl349@6571 48 #include <linux/sysrq.h>
cl349@4087 49 #include <asm/io.h>
cl349@4087 50 #include <asm/irq.h>
cl349@4087 51 #include <asm/uaccess.h>
cl349@4087 52 #include <asm-xen/xen-public/event_channel.h>
cl349@4087 53 #include <asm-xen/hypervisor.h>
cl349@4087 54 #include <asm-xen/evtchn.h>
cl349@4087 55
cl349@6474 56 #include "xencons_ring.h"
cl349@4087 57 /*
cl349@4087 58 * Modes:
cl349@4087 59 * 'xencons=off' [XC_OFF]: Console is disabled.
cl349@4087 60 * 'xencons=tty' [XC_TTY]: Console attached to '/dev/tty[0-9]+'.
cl349@4087 61 * 'xencons=ttyS' [XC_SERIAL]: Console attached to '/dev/ttyS[0-9]+'.
cl349@4087 62 * [XC_DEFAULT]: DOM0 -> XC_SERIAL ; all others -> XC_TTY.
cl349@4087 63 *
cl349@4087 64 * NB. In mode XC_TTY, we create dummy consoles for tty2-63. This suppresses
cl349@4087 65 * warnings from standard distro startup scripts.
cl349@4087 66 */
cl349@4087 67 static enum { XC_OFF, XC_DEFAULT, XC_TTY, XC_SERIAL } xc_mode = XC_DEFAULT;
iap10@4287 68 static int xc_num = -1;
cl349@4087 69
cl349@6571 70 #ifdef CONFIG_MAGIC_SYSRQ
cl349@6571 71 static unsigned long sysrq_requested;
cl349@6571 72 extern int sysrq_enabled;
cl349@6571 73 #endif
cl349@6571 74
cl349@4087 75 static int __init xencons_setup(char *str)
cl349@4087 76 {
iap10@4287 77 char *q;
iap10@4287 78 int n;
iap10@4287 79
iap10@4287 80 if ( !strncmp(str, "ttyS", 4) )
iap10@4287 81 xc_mode = XC_SERIAL;
iap10@4287 82 else if ( !strncmp(str, "tty", 3) )
cl349@4087 83 xc_mode = XC_TTY;
iap10@4287 84 else if ( !strncmp(str, "off", 3) )
cl349@4087 85 xc_mode = XC_OFF;
iap10@4287 86
kaf24@4288 87 switch ( xc_mode )
iap10@4287 88 {
iap10@4287 89 case XC_SERIAL:
kaf24@4288 90 n = simple_strtol( str+4, &q, 10 );
kaf24@4288 91 if ( q > (str + 4) ) xc_num = n;
kaf24@4288 92 break;
iap10@4287 93 case XC_TTY:
kaf24@4288 94 n = simple_strtol( str+3, &q, 10 );
kaf24@4288 95 if ( q > (str + 3) ) xc_num = n;
kaf24@4288 96 break;
bren@4473 97 default:
bren@4473 98 break;
iap10@4287 99 }
kaf24@4288 100
cl349@4087 101 return 1;
cl349@4087 102 }
cl349@4088 103 __setup("xencons=", xencons_setup);
cl349@4087 104
cl349@4087 105 /* The kernel and user-land drivers share a common transmit buffer. */
kaf24@4535 106 static unsigned int wbuf_size = 4096;
kaf24@4535 107 #define WBUF_MASK(_i) ((_i)&(wbuf_size-1))
kaf24@4535 108 static char *wbuf;
cl349@4087 109 static unsigned int wc, wp; /* write_cons, write_prod */
cl349@4087 110
kaf24@4535 111 static int __init xencons_bufsz_setup(char *str)
kaf24@4535 112 {
kaf24@4535 113 unsigned int goal;
kaf24@4535 114 goal = simple_strtoul(str, NULL, 0);
kaf24@4535 115 while ( wbuf_size < goal )
kaf24@4535 116 wbuf_size <<= 1;
kaf24@4535 117 return 1;
kaf24@4535 118 }
kaf24@4535 119 __setup("xencons_bufsz=", xencons_bufsz_setup);
kaf24@4535 120
cl349@4087 121 /* This lock protects accesses to the common transmit buffer. */
cl349@4087 122 static spinlock_t xencons_lock = SPIN_LOCK_UNLOCKED;
cl349@4087 123
cl349@4087 124 /* Common transmit-kick routine. */
cl349@4087 125 static void __xencons_tx_flush(void);
cl349@4087 126
cl349@4087 127 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
cl349@4087 128 static struct tty_driver *xencons_driver;
cl349@4087 129 #else
cl349@4087 130 static struct tty_driver xencons_driver;
cl349@4087 131 #endif
cl349@4087 132
cl349@4087 133
cl349@4087 134 /******************** Kernel console driver ********************************/
cl349@4087 135
cl349@4087 136 static void kcons_write(
cl349@4087 137 struct console *c, const char *s, unsigned int count)
cl349@4087 138 {
cl349@4087 139 int i;
cl349@4087 140 unsigned long flags;
cl349@4087 141
cl349@4087 142 spin_lock_irqsave(&xencons_lock, flags);
cl349@4087 143
cl349@4087 144 for ( i = 0; i < count; i++ )
cl349@4087 145 {
kaf24@4535 146 if ( (wp - wc) >= (wbuf_size - 1) )
cl349@4087 147 break;
cl349@4087 148 if ( (wbuf[WBUF_MASK(wp++)] = s[i]) == '\n' )
cl349@4087 149 wbuf[WBUF_MASK(wp++)] = '\r';
cl349@4087 150 }
cl349@4087 151
cl349@4087 152 __xencons_tx_flush();
cl349@4087 153
cl349@4087 154 spin_unlock_irqrestore(&xencons_lock, flags);
cl349@4087 155 }
cl349@4087 156
cl349@4087 157 static void kcons_write_dom0(
cl349@4087 158 struct console *c, const char *s, unsigned int count)
cl349@4087 159 {
cl349@4087 160 int rc;
cl349@4087 161
kaf24@4288 162 while ( (count > 0) &&
kaf24@4288 163 ((rc = HYPERVISOR_console_io(
kaf24@4288 164 CONSOLEIO_write, count, (char *)s)) > 0) )
cl349@4087 165 {
kaf24@4288 166 count -= rc;
kaf24@4288 167 s += rc;
cl349@4087 168 }
cl349@4087 169 }
cl349@4087 170
cl349@4087 171 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
cl349@4087 172 static struct tty_driver *kcons_device(struct console *c, int *index)
cl349@4087 173 {
cl349@4087 174 *index = c->index;
cl349@4087 175 return xencons_driver;
cl349@4087 176 }
cl349@4087 177 #else
cl349@4087 178 static kdev_t kcons_device(struct console *c)
cl349@4087 179 {
cl349@4087 180 return MKDEV(TTY_MAJOR, (xc_mode == XC_SERIAL) ? 64 : 1);
cl349@4087 181 }
cl349@4087 182 #endif
cl349@4087 183
cl349@4087 184 static struct console kcons_info = {
vh249@6721 185 .device = kcons_device,
vh249@6721 186 .flags = CON_PRINTBUFFER,
vh249@6721 187 .index = -1,
cl349@4087 188 };
cl349@4087 189
cl349@4087 190 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
cl349@4087 191 #define __RETCODE 0
cl349@4087 192 static int __init xen_console_init(void)
cl349@4087 193 #else
cl349@4087 194 #define __RETCODE
cl349@4087 195 void xen_console_init(void)
cl349@4087 196 #endif
cl349@4087 197 {
cl349@6618 198 if ( xen_start_info->flags & SIF_INITDOMAIN )
cl349@4087 199 {
cl349@4087 200 if ( xc_mode == XC_DEFAULT )
cl349@4087 201 xc_mode = XC_SERIAL;
cl349@4087 202 kcons_info.write = kcons_write_dom0;
cl349@4087 203 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
kaf24@4288 204 if ( xc_mode == XC_SERIAL )
kaf24@4288 205 kcons_info.flags |= CON_ENABLED;
cl349@4087 206 #endif
cl349@4087 207 }
cl349@4087 208 else
cl349@4087 209 {
cl349@4087 210 if ( xc_mode == XC_DEFAULT )
cl349@4087 211 xc_mode = XC_TTY;
cl349@4087 212 kcons_info.write = kcons_write;
cl349@4087 213 }
cl349@4087 214
iap10@4287 215 switch ( xc_mode )
iap10@4287 216 {
iap10@4287 217 case XC_SERIAL:
iap10@4287 218 strcpy(kcons_info.name, "ttyS");
kaf24@4288 219 if ( xc_num == -1 ) xc_num = 0;
kaf24@4288 220 break;
cl349@4087 221
iap10@4287 222 case XC_TTY:
cl349@4087 223 strcpy(kcons_info.name, "tty");
kaf24@4288 224 if ( xc_num == -1 ) xc_num = 1;
kaf24@4288 225 break;
kaf24@4288 226
iap10@4287 227 default:
iap10@4287 228 return __RETCODE;
iap10@4287 229 }
cl349@4087 230
kaf24@4535 231 wbuf = alloc_bootmem(wbuf_size);
kaf24@4535 232
cl349@4087 233 register_console(&kcons_info);
iap10@4287 234
cl349@4087 235 return __RETCODE;
cl349@4087 236 }
cl349@4087 237 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
cl349@4087 238 console_initcall(xen_console_init);
cl349@4087 239 #endif
cl349@4087 240
cl349@4087 241 /*** Useful function for console debugging -- goes straight to Xen. ***/
cl349@6404 242 #ifdef CONFIG_XEN_PRIVILEGED_GUEST
cl349@4087 243 asmlinkage int xprintk(const char *fmt, ...)
cl349@6404 244 #else
cl349@6404 245 asmlinkage int xprintk(const char *fmt, ...)
cl349@6404 246 #endif
cl349@4087 247 {
cl349@4087 248 va_list args;
cl349@4087 249 int printk_len;
cl349@4087 250 static char printk_buf[1024];
cl349@4087 251
cl349@4087 252 /* Emit the output into the temporary buffer */
cl349@4087 253 va_start(args, fmt);
cl349@4087 254 printk_len = vsnprintf(printk_buf, sizeof(printk_buf), fmt, args);
cl349@4087 255 va_end(args);
cl349@4087 256
cl349@4087 257 /* Send the processed output directly to Xen. */
cl349@4087 258 kcons_write_dom0(NULL, printk_buf, printk_len);
cl349@4087 259
cl349@4087 260 return 0;
cl349@4087 261 }
cl349@4087 262
cl349@4087 263 /*** Forcibly flush console data before dying. ***/
cl349@4087 264 void xencons_force_flush(void)
cl349@4087 265 {
cl349@4087 266 int sz;
cl349@4087 267
cl349@4087 268 /* Emergency console is synchronous, so there's nothing to flush. */
cl349@6618 269 if ( xen_start_info->flags & SIF_INITDOMAIN )
cl349@4087 270 return;
cl349@4087 271
cl349@4087 272
cl349@4087 273 /* Spin until console data is flushed through to the domain controller. */
cl349@6474 274 while ( (wc != wp) )
cl349@4087 275 {
cl349@6474 276 int sent = 0;
cl349@4087 277 if ( (sz = wp - wc) == 0 )
cl349@4087 278 continue;
cl349@6474 279 sent = xencons_ring_send(&wbuf[WBUF_MASK(wc)], sz);
cl349@6474 280 if (sent > 0)
cl349@6474 281 wc += sent;
cl349@4087 282 }
cl349@4087 283 }
cl349@4087 284
cl349@4087 285
cl349@4087 286 /******************** User-space console driver (/dev/console) ************/
cl349@4087 287
cl349@4087 288 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
cl349@4087 289 #define DRV(_d) (_d)
cl349@4087 290 #define TTY_INDEX(_tty) ((_tty)->index)
cl349@4087 291 #else
cl349@4087 292 static int xencons_refcount;
cl349@4087 293 static struct tty_struct *xencons_table[MAX_NR_CONSOLES];
cl349@4087 294 #define DRV(_d) (&(_d))
cl349@4087 295 #define TTY_INDEX(_tty) (MINOR((_tty)->device) - xencons_driver.minor_start)
cl349@4087 296 #endif
cl349@4087 297
cl349@4087 298 static struct termios *xencons_termios[MAX_NR_CONSOLES];
cl349@4087 299 static struct termios *xencons_termios_locked[MAX_NR_CONSOLES];
cl349@4087 300 static struct tty_struct *xencons_tty;
cl349@4087 301 static int xencons_priv_irq;
cl349@4087 302 static char x_char;
cl349@4087 303
cl349@4087 304 /* Non-privileged receive callback. */
cl349@6571 305 static void xencons_rx(char *buf, unsigned len, struct pt_regs *regs)
cl349@4087 306 {
cl349@4087 307 int i;
cl349@4087 308 unsigned long flags;
cl349@4087 309
cl349@4087 310 spin_lock_irqsave(&xencons_lock, flags);
cl349@4087 311 if ( xencons_tty != NULL )
cl349@4087 312 {
cl349@6571 313 for ( i = 0; i < len; i++ ) {
cl349@6571 314 #ifdef CONFIG_MAGIC_SYSRQ
cl349@6571 315 if (sysrq_enabled) {
cl349@6571 316 if (buf[i] == '\x0f') { /* ^O */
cl349@6571 317 sysrq_requested = jiffies;
cl349@6571 318 continue; /* don't print the sysrq key */
cl349@6571 319 } else if (sysrq_requested) {
cl349@6571 320 unsigned long sysrq_timeout = sysrq_requested + HZ*2;
cl349@6571 321 sysrq_requested = 0;
cl349@6571 322 /* if it's been less than a timeout, do the sysrq */
cl349@6571 323 if (time_before(jiffies, sysrq_timeout)) {
cl349@6571 324 spin_unlock_irqrestore(&xencons_lock, flags);
cl349@6571 325 handle_sysrq(buf[i], regs, xencons_tty);
cl349@6571 326 spin_lock_irqsave(&xencons_lock, flags);
cl349@6571 327 continue;
cl349@6571 328 }
cl349@6571 329 }
cl349@6571 330 }
cl349@6571 331 #endif
cl349@6474 332 tty_insert_flip_char(xencons_tty, buf[i], 0);
cl349@6571 333 }
cl349@4087 334 tty_flip_buffer_push(xencons_tty);
cl349@4087 335 }
cl349@4087 336 spin_unlock_irqrestore(&xencons_lock, flags);
cl349@4087 337
cl349@4087 338 }
cl349@4087 339
cl349@4087 340 /* Privileged and non-privileged transmit worker. */
cl349@4087 341 static void __xencons_tx_flush(void)
cl349@4087 342 {
cl349@4087 343 int sz, work_done = 0;
cl349@4087 344
cl349@6618 345 if ( xen_start_info->flags & SIF_INITDOMAIN )
cl349@4087 346 {
cl349@4087 347 if ( x_char )
cl349@4087 348 {
cl349@4087 349 kcons_write_dom0(NULL, &x_char, 1);
cl349@4087 350 x_char = 0;
cl349@4087 351 work_done = 1;
cl349@4087 352 }
cl349@4087 353
cl349@4087 354 while ( wc != wp )
cl349@4087 355 {
cl349@4087 356 sz = wp - wc;
kaf24@4535 357 if ( sz > (wbuf_size - WBUF_MASK(wc)) )
kaf24@4535 358 sz = wbuf_size - WBUF_MASK(wc);
cl349@4087 359 kcons_write_dom0(NULL, &wbuf[WBUF_MASK(wc)], sz);
cl349@4087 360 wc += sz;
cl349@4087 361 work_done = 1;
cl349@4087 362 }
cl349@4087 363 }
cl349@4087 364 else
cl349@4087 365 {
cl349@4087 366 while ( x_char )
cl349@4087 367 {
cl349@6474 368 if (xencons_ring_send(&x_char, 1) == 1) {
cl349@6474 369 x_char = 0;
cl349@6474 370 work_done = 1;
cl349@6474 371 }
cl349@4087 372 }
cl349@4087 373
cl349@4087 374 while ( wc != wp )
cl349@4087 375 {
cl349@6474 376 int sent;
cl349@4087 377 sz = wp - wc;
cl349@6474 378 if ( sz > (wbuf_size - WBUF_MASK(wc)) )
cl349@6474 379 sz = wbuf_size - WBUF_MASK(wc);
cl349@6474 380 sent = xencons_ring_send(&wbuf[WBUF_MASK(wc)], sz);
cl349@6474 381 if ( sent > 0 ) {
cl349@6474 382 wc += sent;
cl349@6474 383 work_done = 1;
cl349@6474 384 }
cl349@4087 385 }
cl349@4087 386 }
cl349@4087 387
cl349@4087 388 if ( work_done && (xencons_tty != NULL) )
cl349@4087 389 {
cl349@4087 390 wake_up_interruptible(&xencons_tty->write_wait);
cl349@4087 391 if ( (xencons_tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
cl349@4087 392 (xencons_tty->ldisc.write_wakeup != NULL) )
cl349@4087 393 (xencons_tty->ldisc.write_wakeup)(xencons_tty);
cl349@4087 394 }
cl349@4087 395 }
cl349@4087 396
cl349@4087 397 /* Privileged receive callback and transmit kicker. */
cl349@4087 398 static irqreturn_t xencons_priv_interrupt(int irq, void *dev_id,
cl349@4087 399 struct pt_regs *regs)
cl349@4087 400 {
cl349@4087 401 static char rbuf[16];
cl349@4087 402 int i, l;
cl349@4087 403 unsigned long flags;
cl349@4087 404
cl349@4087 405 spin_lock_irqsave(&xencons_lock, flags);
cl349@4087 406
cl349@4087 407 if ( xencons_tty != NULL )
cl349@4087 408 {
cl349@4087 409 /* Receive work. */
cl349@4087 410 while ( (l = HYPERVISOR_console_io(CONSOLEIO_read, 16, rbuf)) > 0 )
cl349@4087 411 for ( i = 0; i < l; i++ )
cl349@4087 412 tty_insert_flip_char(xencons_tty, rbuf[i], 0);
cl349@4087 413 if ( xencons_tty->flip.count != 0 )
cl349@4087 414 tty_flip_buffer_push(xencons_tty);
cl349@4087 415 }
cl349@4087 416
cl349@4087 417 /* Transmit work. */
cl349@4087 418 __xencons_tx_flush();
cl349@4087 419
cl349@4087 420 spin_unlock_irqrestore(&xencons_lock, flags);
cl349@4087 421
cl349@4087 422 return IRQ_HANDLED;
cl349@4087 423 }
cl349@4087 424
cl349@4087 425 static int xencons_write_room(struct tty_struct *tty)
cl349@4087 426 {
kaf24@4535 427 return wbuf_size - (wp - wc);
cl349@4087 428 }
cl349@4087 429
cl349@4087 430 static int xencons_chars_in_buffer(struct tty_struct *tty)
cl349@4087 431 {
cl349@4087 432 return wp - wc;
cl349@4087 433 }
cl349@4087 434
cl349@4087 435 static void xencons_send_xchar(struct tty_struct *tty, char ch)
cl349@4087 436 {
cl349@4087 437 unsigned long flags;
cl349@4087 438
cl349@4087 439 if ( TTY_INDEX(tty) != 0 )
cl349@4087 440 return;
cl349@4087 441
cl349@4087 442 spin_lock_irqsave(&xencons_lock, flags);
cl349@4087 443 x_char = ch;
cl349@4087 444 __xencons_tx_flush();
cl349@4087 445 spin_unlock_irqrestore(&xencons_lock, flags);
cl349@4087 446 }
cl349@4087 447
cl349@4087 448 static void xencons_throttle(struct tty_struct *tty)
cl349@4087 449 {
cl349@4087 450 if ( TTY_INDEX(tty) != 0 )
cl349@4087 451 return;
cl349@4087 452
cl349@4087 453 if ( I_IXOFF(tty) )
cl349@4087 454 xencons_send_xchar(tty, STOP_CHAR(tty));
cl349@4087 455 }
cl349@4087 456
cl349@4087 457 static void xencons_unthrottle(struct tty_struct *tty)
cl349@4087 458 {
cl349@4087 459 if ( TTY_INDEX(tty) != 0 )
cl349@4087 460 return;
cl349@4087 461
cl349@4087 462 if ( I_IXOFF(tty) )
cl349@4087 463 {
cl349@4087 464 if ( x_char != 0 )
cl349@4087 465 x_char = 0;
cl349@4087 466 else
cl349@4087 467 xencons_send_xchar(tty, START_CHAR(tty));
cl349@4087 468 }
cl349@4087 469 }
cl349@4087 470
cl349@4087 471 static void xencons_flush_buffer(struct tty_struct *tty)
cl349@4087 472 {
cl349@4087 473 unsigned long flags;
cl349@4087 474
cl349@4087 475 if ( TTY_INDEX(tty) != 0 )
cl349@4087 476 return;
cl349@4087 477
cl349@4087 478 spin_lock_irqsave(&xencons_lock, flags);
cl349@4087 479 wc = wp = 0;
cl349@4087 480 spin_unlock_irqrestore(&xencons_lock, flags);
cl349@4087 481 }
cl349@4087 482
cl349@4087 483 static inline int __xencons_put_char(int ch)
cl349@4087 484 {
cl349@4087 485 char _ch = (char)ch;
kaf24@4535 486 if ( (wp - wc) == wbuf_size )
cl349@4087 487 return 0;
cl349@4087 488 wbuf[WBUF_MASK(wp++)] = _ch;
cl349@4087 489 return 1;
cl349@4087 490 }
cl349@4087 491
cl349@4087 492 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
kaf24@4288 493 static int xencons_write(
kaf24@4288 494 struct tty_struct *tty,
kaf24@4288 495 const unsigned char *buf,
kaf24@4288 496 int count)
cl349@4087 497 {
cl349@4087 498 int i;
cl349@4087 499 unsigned long flags;
cl349@4087 500
cl349@4087 501 if ( TTY_INDEX(tty) != 0 )
cl349@4087 502 return count;
cl349@4087 503
cl349@4087 504 spin_lock_irqsave(&xencons_lock, flags);
cl349@4087 505
cl349@4087 506 for ( i = 0; i < count; i++ )
cl349@4087 507 if ( !__xencons_put_char(buf[i]) )
cl349@4087 508 break;
cl349@4087 509
cl349@4087 510 if ( i != 0 )
cl349@4087 511 __xencons_tx_flush();
cl349@4087 512
cl349@4087 513 spin_unlock_irqrestore(&xencons_lock, flags);
cl349@4087 514
cl349@4087 515 return i;
cl349@4087 516 }
cl349@4087 517 #else
kaf24@4288 518 static int xencons_write(
kaf24@4288 519 struct tty_struct *tty,
kaf24@4288 520 int from_user,
kaf24@4288 521 const u_char *buf,
kaf24@4288 522 int count)
cl349@4087 523 {
cl349@4087 524 int i;
cl349@4087 525 unsigned long flags;
cl349@4087 526
cl349@4087 527 if ( from_user && verify_area(VERIFY_READ, buf, count) )
cl349@4087 528 return -EINVAL;
cl349@4087 529
cl349@4087 530 if ( TTY_INDEX(tty) != 0 )
cl349@4087 531 return count;
cl349@4087 532
cl349@4087 533 spin_lock_irqsave(&xencons_lock, flags);
cl349@4087 534
cl349@4087 535 for ( i = 0; i < count; i++ )
cl349@4087 536 {
cl349@4087 537 char ch;
cl349@4087 538 if ( from_user )
cl349@4087 539 __get_user(ch, buf + i);
cl349@4087 540 else
cl349@4087 541 ch = buf[i];
cl349@4087 542 if ( !__xencons_put_char(ch) )
cl349@4087 543 break;
cl349@4087 544 }
cl349@4087 545
cl349@4087 546 if ( i != 0 )
cl349@4087 547 __xencons_tx_flush();
cl349@4087 548
cl349@4087 549 spin_unlock_irqrestore(&xencons_lock, flags);
cl349@4087 550
cl349@4087 551 return i;
cl349@4087 552 }
cl349@4087 553 #endif
cl349@4087 554
cl349@4087 555 static void xencons_put_char(struct tty_struct *tty, u_char ch)
cl349@4087 556 {
cl349@4087 557 unsigned long flags;
cl349@4087 558
cl349@4087 559 if ( TTY_INDEX(tty) != 0 )
cl349@4087 560 return;
cl349@4087 561
cl349@4087 562 spin_lock_irqsave(&xencons_lock, flags);
cl349@4087 563 (void)__xencons_put_char(ch);
cl349@4087 564 spin_unlock_irqrestore(&xencons_lock, flags);
cl349@4087 565 }
cl349@4087 566
cl349@4087 567 static void xencons_flush_chars(struct tty_struct *tty)
cl349@4087 568 {
cl349@4087 569 unsigned long flags;
cl349@4087 570
cl349@4087 571 if ( TTY_INDEX(tty) != 0 )
cl349@4087 572 return;
cl349@4087 573
cl349@4087 574 spin_lock_irqsave(&xencons_lock, flags);
cl349@4087 575 __xencons_tx_flush();
cl349@4087 576 spin_unlock_irqrestore(&xencons_lock, flags);
cl349@4087 577 }
cl349@4087 578
cl349@4087 579 static void xencons_wait_until_sent(struct tty_struct *tty, int timeout)
cl349@4087 580 {
cl349@4087 581 unsigned long orig_jiffies = jiffies;
cl349@4087 582
cl349@4087 583 if ( TTY_INDEX(tty) != 0 )
cl349@4087 584 return;
cl349@4087 585
cl349@4087 586 while ( DRV(tty->driver)->chars_in_buffer(tty) )
cl349@4087 587 {
cl349@4087 588 set_current_state(TASK_INTERRUPTIBLE);
cl349@4087 589 schedule_timeout(1);
cl349@4087 590 if ( signal_pending(current) )
cl349@4087 591 break;
cl349@4087 592 if ( (timeout != 0) && time_after(jiffies, orig_jiffies + timeout) )
cl349@4087 593 break;
cl349@4087 594 }
cl349@4087 595
cl349@4087 596 set_current_state(TASK_RUNNING);
cl349@4087 597 }
cl349@4087 598
cl349@4087 599 static int xencons_open(struct tty_struct *tty, struct file *filp)
cl349@4087 600 {
cl349@4087 601 unsigned long flags;
cl349@4087 602
cl349@4087 603 if ( TTY_INDEX(tty) != 0 )
cl349@4087 604 return 0;
cl349@4087 605
cl349@4087 606 spin_lock_irqsave(&xencons_lock, flags);
cl349@4087 607 tty->driver_data = NULL;
cl349@4087 608 if ( xencons_tty == NULL )
cl349@4087 609 xencons_tty = tty;
cl349@4087 610 __xencons_tx_flush();
cl349@4087 611 spin_unlock_irqrestore(&xencons_lock, flags);
cl349@4087 612
cl349@4087 613 return 0;
cl349@4087 614 }
cl349@4087 615
cl349@4087 616 static void xencons_close(struct tty_struct *tty, struct file *filp)
cl349@4087 617 {
cl349@4087 618 unsigned long flags;
cl349@4087 619
cl349@4087 620 if ( TTY_INDEX(tty) != 0 )
cl349@4087 621 return;
cl349@4087 622
cl349@4087 623 if ( tty->count == 1 )
cl349@4087 624 {
cl349@4087 625 tty->closing = 1;
cl349@4087 626 tty_wait_until_sent(tty, 0);
cl349@4087 627 if ( DRV(tty->driver)->flush_buffer != NULL )
cl349@4087 628 DRV(tty->driver)->flush_buffer(tty);
cl349@4087 629 if ( tty->ldisc.flush_buffer != NULL )
cl349@4087 630 tty->ldisc.flush_buffer(tty);
cl349@4087 631 tty->closing = 0;
cl349@4087 632 spin_lock_irqsave(&xencons_lock, flags);
cl349@4087 633 xencons_tty = NULL;
cl349@4087 634 spin_unlock_irqrestore(&xencons_lock, flags);
cl349@4087 635 }
cl349@4087 636 }
cl349@4087 637
cl349@4087 638 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
cl349@4087 639 static struct tty_operations xencons_ops = {
cl349@4087 640 .open = xencons_open,
cl349@4087 641 .close = xencons_close,
cl349@4087 642 .write = xencons_write,
cl349@4087 643 .write_room = xencons_write_room,
cl349@4087 644 .put_char = xencons_put_char,
cl349@4087 645 .flush_chars = xencons_flush_chars,
cl349@4087 646 .chars_in_buffer = xencons_chars_in_buffer,
cl349@4087 647 .send_xchar = xencons_send_xchar,
cl349@4087 648 .flush_buffer = xencons_flush_buffer,
cl349@4087 649 .throttle = xencons_throttle,
cl349@4087 650 .unthrottle = xencons_unthrottle,
cl349@4087 651 .wait_until_sent = xencons_wait_until_sent,
cl349@4087 652 };
cl349@4087 653
cl349@4087 654 #ifdef CONFIG_XEN_PRIVILEGED_GUEST
cl349@4087 655 static const char *xennullcon_startup(void)
cl349@4087 656 {
cl349@4087 657 return NULL;
cl349@4087 658 }
cl349@4087 659
cl349@4087 660 static int xennullcon_dummy(void)
cl349@4087 661 {
cl349@4087 662 return 0;
cl349@4087 663 }
cl349@4087 664
kaf24@4288 665 #define DUMMY (void *)xennullcon_dummy
cl349@4087 666
cl349@4087 667 /*
cl349@4087 668 * The console `switch' structure for the dummy console
cl349@4087 669 *
cl349@4087 670 * Most of the operations are dummies.
cl349@4087 671 */
cl349@4087 672
cl349@4087 673 const struct consw xennull_con = {
cl349@4087 674 .owner = THIS_MODULE,
cl349@4087 675 .con_startup = xennullcon_startup,
cl349@4087 676 .con_init = DUMMY,
cl349@4087 677 .con_deinit = DUMMY,
cl349@4087 678 .con_clear = DUMMY,
cl349@4087 679 .con_putc = DUMMY,
cl349@4087 680 .con_putcs = DUMMY,
cl349@4087 681 .con_cursor = DUMMY,
cl349@4087 682 .con_scroll = DUMMY,
cl349@4087 683 .con_bmove = DUMMY,
cl349@4087 684 .con_switch = DUMMY,
cl349@4087 685 .con_blank = DUMMY,
cl349@4087 686 .con_font_set = DUMMY,
cl349@4087 687 .con_font_get = DUMMY,
cl349@4087 688 .con_font_default = DUMMY,
cl349@4087 689 .con_font_copy = DUMMY,
cl349@4087 690 .con_set_palette = DUMMY,
cl349@4087 691 .con_scrolldelta = DUMMY,
cl349@4087 692 };
cl349@4087 693 #endif
cl349@4087 694 #endif
cl349@4087 695
cl349@4087 696 static int __init xencons_init(void)
cl349@4087 697 {
cl349@4087 698 int rc;
cl349@4087 699
cl349@4087 700 if ( xc_mode == XC_OFF )
cl349@4087 701 return 0;
cl349@4087 702
cl349@6474 703 xencons_ring_init();
cl349@6474 704
cl349@4087 705 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
cl349@4087 706 xencons_driver = alloc_tty_driver((xc_mode == XC_SERIAL) ?
cl349@4087 707 1 : MAX_NR_CONSOLES);
cl349@4087 708 if ( xencons_driver == NULL )
cl349@4087 709 return -ENOMEM;
cl349@4087 710 #else
cl349@4087 711 memset(&xencons_driver, 0, sizeof(struct tty_driver));
cl349@4087 712 xencons_driver.magic = TTY_DRIVER_MAGIC;
cl349@4087 713 xencons_driver.refcount = &xencons_refcount;
cl349@4087 714 xencons_driver.table = xencons_table;
cl349@4087 715 xencons_driver.num = (xc_mode == XC_SERIAL) ? 1 : MAX_NR_CONSOLES;
cl349@4087 716 #endif
cl349@4087 717
cl349@4087 718 DRV(xencons_driver)->major = TTY_MAJOR;
cl349@4087 719 DRV(xencons_driver)->type = TTY_DRIVER_TYPE_SERIAL;
cl349@4087 720 DRV(xencons_driver)->subtype = SERIAL_TYPE_NORMAL;
cl349@4087 721 DRV(xencons_driver)->init_termios = tty_std_termios;
cl349@4087 722 DRV(xencons_driver)->flags =
cl349@4087 723 TTY_DRIVER_REAL_RAW | TTY_DRIVER_RESET_TERMIOS | TTY_DRIVER_NO_DEVFS;
cl349@4087 724 DRV(xencons_driver)->termios = xencons_termios;
cl349@4087 725 DRV(xencons_driver)->termios_locked = xencons_termios_locked;
cl349@4087 726
cl349@4087 727 if ( xc_mode == XC_SERIAL )
cl349@4087 728 {
cl349@4087 729 DRV(xencons_driver)->name = "ttyS";
iap10@4287 730 DRV(xencons_driver)->minor_start = 64 + xc_num;
iap10@4287 731 DRV(xencons_driver)->name_base = 0 + xc_num;
cl349@4087 732 }
cl349@4087 733 else
cl349@4087 734 {
cl349@4087 735 DRV(xencons_driver)->name = "tty";
iap10@4287 736 DRV(xencons_driver)->minor_start = xc_num;
iap10@4287 737 DRV(xencons_driver)->name_base = xc_num;
cl349@4087 738 }
cl349@4087 739
cl349@4087 740 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
cl349@4087 741 tty_set_operations(xencons_driver, &xencons_ops);
cl349@4087 742 #else
cl349@4087 743 xencons_driver.open = xencons_open;
cl349@4087 744 xencons_driver.close = xencons_close;
cl349@4087 745 xencons_driver.write = xencons_write;
cl349@4087 746 xencons_driver.write_room = xencons_write_room;
cl349@4087 747 xencons_driver.put_char = xencons_put_char;
cl349@4087 748 xencons_driver.flush_chars = xencons_flush_chars;
cl349@4087 749 xencons_driver.chars_in_buffer = xencons_chars_in_buffer;
cl349@4087 750 xencons_driver.send_xchar = xencons_send_xchar;
cl349@4087 751 xencons_driver.flush_buffer = xencons_flush_buffer;
cl349@4087 752 xencons_driver.throttle = xencons_throttle;
cl349@4087 753 xencons_driver.unthrottle = xencons_unthrottle;
cl349@4087 754 xencons_driver.wait_until_sent = xencons_wait_until_sent;
cl349@4087 755 #endif
cl349@4087 756
cl349@4087 757 if ( (rc = tty_register_driver(DRV(xencons_driver))) != 0 )
cl349@4087 758 {
cl349@4087 759 printk("WARNING: Failed to register Xen virtual "
cl349@4087 760 "console driver as '%s%d'\n",
cl349@4087 761 DRV(xencons_driver)->name, DRV(xencons_driver)->name_base);
cl349@4087 762 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
cl349@4087 763 put_tty_driver(xencons_driver);
cl349@4087 764 xencons_driver = NULL;
cl349@4087 765 #endif
cl349@4087 766 return rc;
cl349@4087 767 }
cl349@4087 768
cl349@4087 769 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
cl349@4087 770 tty_register_device(xencons_driver, 0, NULL);
cl349@4087 771 #endif
cl349@4087 772
cl349@6618 773 if ( xen_start_info->flags & SIF_INITDOMAIN )
cl349@4087 774 {
cl349@4087 775 xencons_priv_irq = bind_virq_to_irq(VIRQ_CONSOLE);
cl349@4087 776 (void)request_irq(xencons_priv_irq,
cl349@4087 777 xencons_priv_interrupt, 0, "console", NULL);
cl349@4087 778 }
cl349@4087 779 else
cl349@4087 780 {
cl349@6474 781
cl349@6474 782 xencons_ring_register_receiver(xencons_rx);
cl349@4087 783 }
cl349@4087 784
iap10@4287 785 printk("Xen virtual console successfully installed as %s%d\n",
iap10@4287 786 DRV(xencons_driver)->name,
iap10@4287 787 DRV(xencons_driver)->name_base );
cl349@4087 788
cl349@4087 789 return 0;
cl349@4087 790 }
cl349@4087 791
cl349@4087 792 module_init(xencons_init);