X-Git-Url: http://git.onelab.eu/?a=blobdiff_plain;f=drivers%2Fxen%2Fconsole%2Fconsole.c;fp=drivers%2Fxen%2Fconsole%2Fconsole.c;h=ec7dd9e58447723255c9b2720da57e0d0a1c21c1;hb=4e76c8a9fa413ccc09d3f7f664183dcce3555d57;hp=142ca2baaac48a41ec10a295bea1d713cca2bb0b;hpb=1db395853d4f30d6120458bd279ede1f882a8525;p=linux-2.6.git diff --git a/drivers/xen/console/console.c b/drivers/xen/console/console.c index 142ca2baa..ec7dd9e58 100644 --- a/drivers/xen/console/console.c +++ b/drivers/xen/console/console.c @@ -5,8 +5,11 @@ * * Copyright (c) 2002-2004, K A Fraser. * - * This file may be distributed separately from the Linux kernel, or - * incorporated into other software packages, subject to the following license: + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License version 2 + * as published by the Free Software Foundation; or, when distributed + * separately from the Linux kernel or incorporated into other + * software packages, subject to the following license: * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this source file (the "Software"), to deal in the Software without @@ -45,13 +48,15 @@ #include #include #include +#include #include #include #include -#include -#include -#include -#include +#include +#include +#include +#include +#include /* * Modes: @@ -66,33 +71,39 @@ static enum { XC_OFF, XC_DEFAULT, XC_TTY, XC_SERIAL } xc_mode = XC_DEFAULT; static int xc_num = -1; +#ifdef CONFIG_MAGIC_SYSRQ +static unsigned long sysrq_requested; +extern int sysrq_enabled; +#endif + static int __init xencons_setup(char *str) { - char *q; - int n; - - if ( !strncmp(str, "ttyS", 4) ) - xc_mode = XC_SERIAL; - else if ( !strncmp(str, "tty", 3) ) - xc_mode = XC_TTY; - else if ( !strncmp(str, "off", 3) ) - xc_mode = XC_OFF; - - switch ( xc_mode ) - { - case XC_SERIAL: - n = simple_strtol( str+4, &q, 10 ); - if ( q > (str + 4) ) xc_num = n; - break; - case XC_TTY: - n = simple_strtol( str+3, &q, 10 ); - if ( q > (str + 3) ) xc_num = n; - break; - default: - break; - } - - return 1; + char *q; + int n; + + if (!strncmp(str, "ttyS", 4)) + xc_mode = XC_SERIAL; + else if (!strncmp(str, "tty", 3)) + xc_mode = XC_TTY; + else if (!strncmp(str, "off", 3)) + xc_mode = XC_OFF; + + switch (xc_mode) { + case XC_SERIAL: + n = simple_strtol(str+4, &q, 10); + if (q > (str + 4)) + xc_num = n; + break; + case XC_TTY: + n = simple_strtol(str+3, &q, 10); + if (q > (str + 3)) + xc_num = n; + break; + default: + break; + } + + return 1; } __setup("xencons=", xencons_setup); @@ -104,210 +115,158 @@ static unsigned int wc, wp; /* write_cons, write_prod */ static int __init xencons_bufsz_setup(char *str) { - unsigned int goal; - goal = simple_strtoul(str, NULL, 0); - while ( wbuf_size < goal ) - wbuf_size <<= 1; - return 1; + unsigned int goal; + goal = simple_strtoul(str, NULL, 0); + if (goal) { + goal = roundup_pow_of_two(goal); + if (wbuf_size < goal) + wbuf_size = goal; + } + return 1; } __setup("xencons_bufsz=", xencons_bufsz_setup); /* This lock protects accesses to the common transmit buffer. */ -static spinlock_t xencons_lock = SPIN_LOCK_UNLOCKED; +static DEFINE_SPINLOCK(xencons_lock); /* Common transmit-kick routine. */ static void __xencons_tx_flush(void); -/* This task is used to defer sending console data until there is space. */ -static void xencons_tx_flush_task_routine(void *data); - -static DECLARE_TQUEUE(xencons_tx_flush_task, - xencons_tx_flush_task_routine, - NULL); - -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0) static struct tty_driver *xencons_driver; -#else -static struct tty_driver xencons_driver; -#endif - /******************** Kernel console driver ********************************/ -static void kcons_write( - struct console *c, const char *s, unsigned int count) +static void kcons_write(struct console *c, const char *s, unsigned int count) { - int i; - unsigned long flags; - - spin_lock_irqsave(&xencons_lock, flags); - - for ( i = 0; i < count; i++ ) - { - if ( (wp - wc) >= (wbuf_size - 1) ) - break; - if ( (wbuf[WBUF_MASK(wp++)] = s[i]) == '\n' ) - wbuf[WBUF_MASK(wp++)] = '\r'; - } - - __xencons_tx_flush(); - - spin_unlock_irqrestore(&xencons_lock, flags); + int i = 0; + unsigned long flags; + + spin_lock_irqsave(&xencons_lock, flags); + + while (i < count) { + for (; i < count; i++) { + if ((wp - wc) >= (wbuf_size - 1)) + break; + if ((wbuf[WBUF_MASK(wp++)] = s[i]) == '\n') + wbuf[WBUF_MASK(wp++)] = '\r'; + } + + __xencons_tx_flush(); + } + + spin_unlock_irqrestore(&xencons_lock, flags); } -static void kcons_write_dom0( - struct console *c, const char *s, unsigned int count) +static void kcons_write_dom0(struct console *c, const char *s, unsigned int count) { - int rc; - - while ( (count > 0) && - ((rc = HYPERVISOR_console_io( - CONSOLEIO_write, count, (char *)s)) > 0) ) - { - count -= rc; - s += rc; - } + + while (count > 0) { + int rc; + rc = HYPERVISOR_console_io( CONSOLEIO_write, count, (char *)s); + if (rc <= 0) + break; + count -= rc; + s += rc; + } } -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0) static struct tty_driver *kcons_device(struct console *c, int *index) { - *index = c->index; - return xencons_driver; -} -#else -static kdev_t kcons_device(struct console *c) -{ - return MKDEV(TTY_MAJOR, (xc_mode == XC_SERIAL) ? 64 : 1); + *index = 0; + return xencons_driver; } -#endif static struct console kcons_info = { - device: kcons_device, - flags: CON_PRINTBUFFER, - index: -1 + .device = kcons_device, + .flags = CON_PRINTBUFFER | CON_ENABLED, + .index = -1, }; -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0) #define __RETCODE 0 static int __init xen_console_init(void) -#else -#define __RETCODE -void xen_console_init(void) -#endif { - if ( xen_start_info.flags & SIF_INITDOMAIN ) - { - if ( xc_mode == XC_DEFAULT ) - xc_mode = XC_SERIAL; - kcons_info.write = kcons_write_dom0; -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0) - if ( xc_mode == XC_SERIAL ) - kcons_info.flags |= CON_ENABLED; -#endif - } - else - { - if ( xc_mode == XC_DEFAULT ) - xc_mode = XC_TTY; - kcons_info.write = kcons_write; - } - - switch ( xc_mode ) - { - case XC_SERIAL: - strcpy(kcons_info.name, "ttyS"); - if ( xc_num == -1 ) xc_num = 0; - break; - - case XC_TTY: - strcpy(kcons_info.name, "tty"); - if ( xc_num == -1 ) xc_num = 1; - break; - - default: - return __RETCODE; - } - - wbuf = alloc_bootmem(wbuf_size); - - register_console(&kcons_info); - - return __RETCODE; + if (!is_running_on_xen()) + return __RETCODE; + + if (xen_start_info->flags & SIF_INITDOMAIN) { + if (xc_mode == XC_DEFAULT) + xc_mode = XC_SERIAL; + kcons_info.write = kcons_write_dom0; + } else { + if (xc_mode == XC_DEFAULT) + xc_mode = XC_TTY; + kcons_info.write = kcons_write; + } + + switch (xc_mode) { + case XC_SERIAL: + strcpy(kcons_info.name, "ttyS"); + if (xc_num == -1) + xc_num = 0; + break; + + case XC_TTY: + strcpy(kcons_info.name, "tty"); + if (xc_num == -1) + xc_num = 1; + break; + + default: + return __RETCODE; + } + + wbuf = alloc_bootmem(wbuf_size); + + register_console(&kcons_info); + + return __RETCODE; } -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0) console_initcall(xen_console_init); -#endif /*** Useful function for console debugging -- goes straight to Xen. ***/ asmlinkage int xprintk(const char *fmt, ...) { - va_list args; - int printk_len; - static char printk_buf[1024]; - - /* Emit the output into the temporary buffer */ - va_start(args, fmt); - printk_len = vsnprintf(printk_buf, sizeof(printk_buf), fmt, args); - va_end(args); - - /* Send the processed output directly to Xen. */ - kcons_write_dom0(NULL, printk_buf, printk_len); - - return 0; + va_list args; + int printk_len; + static char printk_buf[1024]; + + /* Emit the output into the temporary buffer */ + va_start(args, fmt); + printk_len = vsnprintf(printk_buf, sizeof(printk_buf), fmt, args); + va_end(args); + + /* Send the processed output directly to Xen. */ + kcons_write_dom0(NULL, printk_buf, printk_len); + + return 0; } /*** Forcibly flush console data before dying. ***/ void xencons_force_flush(void) { - ctrl_msg_t msg; - int sz; - - /* Emergency console is synchronous, so there's nothing to flush. */ - if ( xen_start_info.flags & SIF_INITDOMAIN ) - return; - - /* - * We use dangerous control-interface functions that require a quiescent - * system and no interrupts. Try to ensure this with a global cli(). - */ - local_irq_disable(); /* XXXsmp */ - - /* Spin until console data is flushed through to the domain controller. */ - while ( (wc != wp) && !ctrl_if_transmitter_empty() ) - { - /* Interrupts are disabled -- we must manually reap responses. */ - ctrl_if_discard_responses(); - - if ( (sz = wp - wc) == 0 ) - continue; - if ( sz > sizeof(msg.msg) ) - sz = sizeof(msg.msg); - if ( sz > (wbuf_size - WBUF_MASK(wc)) ) - sz = wbuf_size - WBUF_MASK(wc); - - msg.type = CMSG_CONSOLE; - msg.subtype = CMSG_CONSOLE_DATA; - msg.length = sz; - memcpy(msg.msg, &wbuf[WBUF_MASK(wc)], sz); - - if ( ctrl_if_send_message_noblock(&msg, NULL, 0) == 0 ) - wc += sz; - } + int sz; + + /* Emergency console is synchronous, so there's nothing to flush. */ + if (xen_start_info->flags & SIF_INITDOMAIN) + return; + + /* Spin until console data is flushed through to the daemon. */ + while (wc != wp) { + int sent = 0; + if ((sz = wp - wc) == 0) + continue; + sent = xencons_ring_send(&wbuf[WBUF_MASK(wc)], sz); + if (sent > 0) + wc += sent; + } } /******************** User-space console driver (/dev/console) ************/ -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0) #define DRV(_d) (_d) -#define TTY_INDEX(_tty) ((_tty)->index) -#else -static int xencons_refcount; -static struct tty_struct *xencons_table[MAX_NR_CONSOLES]; -#define DRV(_d) (&(_d)) -#define TTY_INDEX(_tty) (MINOR((_tty)->device) - xencons_driver.minor_start) -#endif +#define DUMMY_TTY(_tty) ((xc_mode != XC_SERIAL) && \ + ((_tty)->index != (xc_num - 1))) static struct termios *xencons_termios[MAX_NR_CONSOLES]; static struct termios *xencons_termios_locked[MAX_NR_CONSOLES]; @@ -315,497 +274,371 @@ static struct tty_struct *xencons_tty; static int xencons_priv_irq; static char x_char; -/* Non-privileged receive callback. */ -static void xencons_rx(ctrl_msg_t *msg, unsigned long id) +void xencons_rx(char *buf, unsigned len, struct pt_regs *regs) { - int i; - unsigned long flags; - - spin_lock_irqsave(&xencons_lock, flags); - if ( xencons_tty != NULL ) - { - for ( i = 0; i < msg->length; i++ ) - tty_insert_flip_char(xencons_tty, msg->msg[i], 0); - tty_flip_buffer_push(xencons_tty); - } - spin_unlock_irqrestore(&xencons_lock, flags); - - msg->length = 0; - ctrl_if_send_response(msg); + int i; + unsigned long flags; + + spin_lock_irqsave(&xencons_lock, flags); + if (xencons_tty == NULL) + goto out; + + for (i = 0; i < len; i++) { +#ifdef CONFIG_MAGIC_SYSRQ + if (sysrq_enabled) { + if (buf[i] == '\x0f') { /* ^O */ + sysrq_requested = jiffies; + continue; /* don't print the sysrq key */ + } else if (sysrq_requested) { + unsigned long sysrq_timeout = + sysrq_requested + HZ*2; + sysrq_requested = 0; + if (time_before(jiffies, sysrq_timeout)) { + spin_unlock_irqrestore( + &xencons_lock, flags); + handle_sysrq( + buf[i], regs, xencons_tty); + spin_lock_irqsave( + &xencons_lock, flags); + continue; + } + } + } +#endif + tty_insert_flip_char(xencons_tty, buf[i], 0); + } + tty_flip_buffer_push(xencons_tty); + + out: + spin_unlock_irqrestore(&xencons_lock, flags); } -/* Privileged and non-privileged transmit worker. */ static void __xencons_tx_flush(void) { - int sz, work_done = 0; - ctrl_msg_t msg; - - if ( xen_start_info.flags & SIF_INITDOMAIN ) - { - if ( x_char ) - { - kcons_write_dom0(NULL, &x_char, 1); - x_char = 0; - work_done = 1; - } - - while ( wc != wp ) - { - sz = wp - wc; - if ( sz > (wbuf_size - WBUF_MASK(wc)) ) - sz = wbuf_size - WBUF_MASK(wc); - kcons_write_dom0(NULL, &wbuf[WBUF_MASK(wc)], sz); - wc += sz; - work_done = 1; - } - } - else - { - while ( x_char ) - { - msg.type = CMSG_CONSOLE; - msg.subtype = CMSG_CONSOLE_DATA; - msg.length = 1; - msg.msg[0] = x_char; - - if ( ctrl_if_send_message_noblock(&msg, NULL, 0) == 0 ) - x_char = 0; - else if ( ctrl_if_enqueue_space_callback(&xencons_tx_flush_task) ) - break; - - work_done = 1; - } - - while ( wc != wp ) - { - sz = wp - wc; - if ( sz > sizeof(msg.msg) ) - sz = sizeof(msg.msg); - if ( sz > (wbuf_size - WBUF_MASK(wc)) ) - sz = wbuf_size - WBUF_MASK(wc); - - msg.type = CMSG_CONSOLE; - msg.subtype = CMSG_CONSOLE_DATA; - msg.length = sz; - memcpy(msg.msg, &wbuf[WBUF_MASK(wc)], sz); - - if ( ctrl_if_send_message_noblock(&msg, NULL, 0) == 0 ) - wc += sz; - else if ( ctrl_if_enqueue_space_callback(&xencons_tx_flush_task) ) - break; - - work_done = 1; - } - } - - if ( work_done && (xencons_tty != NULL) ) - { - wake_up_interruptible(&xencons_tty->write_wait); - if ( (xencons_tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && - (xencons_tty->ldisc.write_wakeup != NULL) ) - (xencons_tty->ldisc.write_wakeup)(xencons_tty); - } + int sent, sz, work_done = 0; + + if (x_char) { + if (xen_start_info->flags & SIF_INITDOMAIN) + kcons_write_dom0(NULL, &x_char, 1); + else + while (x_char) + if (xencons_ring_send(&x_char, 1) == 1) + break; + x_char = 0; + work_done = 1; + } + + while (wc != wp) { + sz = wp - wc; + if (sz > (wbuf_size - WBUF_MASK(wc))) + sz = wbuf_size - WBUF_MASK(wc); + if (xen_start_info->flags & SIF_INITDOMAIN) { + kcons_write_dom0(NULL, &wbuf[WBUF_MASK(wc)], sz); + wc += sz; + } else { + sent = xencons_ring_send(&wbuf[WBUF_MASK(wc)], sz); + if (sent == 0) + break; + wc += sent; + } + work_done = 1; + } + + if (work_done && (xencons_tty != NULL)) { + wake_up_interruptible(&xencons_tty->write_wait); + if ((xencons_tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) && + (xencons_tty->ldisc.write_wakeup != NULL)) + (xencons_tty->ldisc.write_wakeup)(xencons_tty); + } } -/* Non-privileged transmit kicker. */ -static void xencons_tx_flush_task_routine(void *data) +void xencons_tx(void) { - unsigned long flags; - spin_lock_irqsave(&xencons_lock, flags); - __xencons_tx_flush(); - spin_unlock_irqrestore(&xencons_lock, flags); + unsigned long flags; + + spin_lock_irqsave(&xencons_lock, flags); + __xencons_tx_flush(); + spin_unlock_irqrestore(&xencons_lock, flags); } /* Privileged receive callback and transmit kicker. */ static irqreturn_t xencons_priv_interrupt(int irq, void *dev_id, - struct pt_regs *regs) + struct pt_regs *regs) { - static char rbuf[16]; - int i, l; - unsigned long flags; + static char rbuf[16]; + int l; - spin_lock_irqsave(&xencons_lock, flags); + while ((l = HYPERVISOR_console_io(CONSOLEIO_read, 16, rbuf)) > 0) + xencons_rx(rbuf, l, regs); - if ( xencons_tty != NULL ) - { - /* Receive work. */ - while ( (l = HYPERVISOR_console_io(CONSOLEIO_read, 16, rbuf)) > 0 ) - for ( i = 0; i < l; i++ ) - tty_insert_flip_char(xencons_tty, rbuf[i], 0); - if ( xencons_tty->flip.count != 0 ) - tty_flip_buffer_push(xencons_tty); - } + xencons_tx(); - /* Transmit work. */ - __xencons_tx_flush(); - - spin_unlock_irqrestore(&xencons_lock, flags); - - return IRQ_HANDLED; + return IRQ_HANDLED; } static int xencons_write_room(struct tty_struct *tty) { - return wbuf_size - (wp - wc); + return wbuf_size - (wp - wc); } static int xencons_chars_in_buffer(struct tty_struct *tty) { - return wp - wc; + return wp - wc; } static void xencons_send_xchar(struct tty_struct *tty, char ch) { - unsigned long flags; + unsigned long flags; - if ( TTY_INDEX(tty) != 0 ) - return; + if (DUMMY_TTY(tty)) + return; - spin_lock_irqsave(&xencons_lock, flags); - x_char = ch; - __xencons_tx_flush(); - spin_unlock_irqrestore(&xencons_lock, flags); + spin_lock_irqsave(&xencons_lock, flags); + x_char = ch; + __xencons_tx_flush(); + spin_unlock_irqrestore(&xencons_lock, flags); } static void xencons_throttle(struct tty_struct *tty) { - if ( TTY_INDEX(tty) != 0 ) - return; + if (DUMMY_TTY(tty)) + return; - if ( I_IXOFF(tty) ) - xencons_send_xchar(tty, STOP_CHAR(tty)); + if (I_IXOFF(tty)) + xencons_send_xchar(tty, STOP_CHAR(tty)); } static void xencons_unthrottle(struct tty_struct *tty) { - if ( TTY_INDEX(tty) != 0 ) - return; - - if ( I_IXOFF(tty) ) - { - if ( x_char != 0 ) - x_char = 0; - else - xencons_send_xchar(tty, START_CHAR(tty)); - } + if (DUMMY_TTY(tty)) + return; + + if (I_IXOFF(tty)) { + if (x_char != 0) + x_char = 0; + else + xencons_send_xchar(tty, START_CHAR(tty)); + } } static void xencons_flush_buffer(struct tty_struct *tty) { - unsigned long flags; + unsigned long flags; - if ( TTY_INDEX(tty) != 0 ) - return; + if (DUMMY_TTY(tty)) + return; - spin_lock_irqsave(&xencons_lock, flags); - wc = wp = 0; - spin_unlock_irqrestore(&xencons_lock, flags); + spin_lock_irqsave(&xencons_lock, flags); + wc = wp = 0; + spin_unlock_irqrestore(&xencons_lock, flags); } static inline int __xencons_put_char(int ch) { - char _ch = (char)ch; - if ( (wp - wc) == wbuf_size ) - return 0; - wbuf[WBUF_MASK(wp++)] = _ch; - return 1; + char _ch = (char)ch; + if ((wp - wc) == wbuf_size) + return 0; + wbuf[WBUF_MASK(wp++)] = _ch; + return 1; } -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0) static int xencons_write( - struct tty_struct *tty, - const unsigned char *buf, - int count) + struct tty_struct *tty, + const unsigned char *buf, + int count) { - int i; - unsigned long flags; + int i; + unsigned long flags; - if ( TTY_INDEX(tty) != 0 ) - return count; + if (DUMMY_TTY(tty)) + return count; - spin_lock_irqsave(&xencons_lock, flags); + spin_lock_irqsave(&xencons_lock, flags); - for ( i = 0; i < count; i++ ) - if ( !__xencons_put_char(buf[i]) ) - break; + for (i = 0; i < count; i++) + if (!__xencons_put_char(buf[i])) + break; - if ( i != 0 ) - __xencons_tx_flush(); + if (i != 0) + __xencons_tx_flush(); - spin_unlock_irqrestore(&xencons_lock, flags); + spin_unlock_irqrestore(&xencons_lock, flags); - return i; + return i; } -#else -static int xencons_write( - struct tty_struct *tty, - int from_user, - const u_char *buf, - int count) -{ - int i; - unsigned long flags; - - if ( from_user && verify_area(VERIFY_READ, buf, count) ) - return -EINVAL; - - if ( TTY_INDEX(tty) != 0 ) - return count; - - spin_lock_irqsave(&xencons_lock, flags); - - for ( i = 0; i < count; i++ ) - { - char ch; - if ( from_user ) - __get_user(ch, buf + i); - else - ch = buf[i]; - if ( !__xencons_put_char(ch) ) - break; - } - - if ( i != 0 ) - __xencons_tx_flush(); - - spin_unlock_irqrestore(&xencons_lock, flags); - - return i; -} -#endif static void xencons_put_char(struct tty_struct *tty, u_char ch) { - unsigned long flags; + unsigned long flags; - if ( TTY_INDEX(tty) != 0 ) - return; + if (DUMMY_TTY(tty)) + return; - spin_lock_irqsave(&xencons_lock, flags); - (void)__xencons_put_char(ch); - spin_unlock_irqrestore(&xencons_lock, flags); + spin_lock_irqsave(&xencons_lock, flags); + (void)__xencons_put_char(ch); + spin_unlock_irqrestore(&xencons_lock, flags); } static void xencons_flush_chars(struct tty_struct *tty) { - unsigned long flags; + unsigned long flags; - if ( TTY_INDEX(tty) != 0 ) - return; + if (DUMMY_TTY(tty)) + return; - spin_lock_irqsave(&xencons_lock, flags); - __xencons_tx_flush(); - spin_unlock_irqrestore(&xencons_lock, flags); + spin_lock_irqsave(&xencons_lock, flags); + __xencons_tx_flush(); + spin_unlock_irqrestore(&xencons_lock, flags); } static void xencons_wait_until_sent(struct tty_struct *tty, int timeout) { - unsigned long orig_jiffies = jiffies; - - if ( TTY_INDEX(tty) != 0 ) - return; - - while ( DRV(tty->driver)->chars_in_buffer(tty) ) - { - set_current_state(TASK_INTERRUPTIBLE); - schedule_timeout(1); - if ( signal_pending(current) ) - break; - if ( (timeout != 0) && time_after(jiffies, orig_jiffies + timeout) ) - break; - } - - set_current_state(TASK_RUNNING); + unsigned long orig_jiffies = jiffies; + + if (DUMMY_TTY(tty)) + return; + + while (DRV(tty->driver)->chars_in_buffer(tty)) { + set_current_state(TASK_INTERRUPTIBLE); + schedule_timeout(1); + if (signal_pending(current)) + break; + if (timeout && time_after(jiffies, orig_jiffies + timeout)) + break; + } + + set_current_state(TASK_RUNNING); } static int xencons_open(struct tty_struct *tty, struct file *filp) { - unsigned long flags; + unsigned long flags; - if ( TTY_INDEX(tty) != 0 ) - return 0; + if (DUMMY_TTY(tty)) + return 0; - spin_lock_irqsave(&xencons_lock, flags); - tty->driver_data = NULL; - if ( xencons_tty == NULL ) - xencons_tty = tty; - __xencons_tx_flush(); - spin_unlock_irqrestore(&xencons_lock, flags); + spin_lock_irqsave(&xencons_lock, flags); + tty->driver_data = NULL; + if (xencons_tty == NULL) + xencons_tty = tty; + __xencons_tx_flush(); + spin_unlock_irqrestore(&xencons_lock, flags); - return 0; + return 0; } static void xencons_close(struct tty_struct *tty, struct file *filp) { - unsigned long flags; - - if ( TTY_INDEX(tty) != 0 ) - return; - - if ( tty->count == 1 ) - { - tty->closing = 1; - tty_wait_until_sent(tty, 0); - if ( DRV(tty->driver)->flush_buffer != NULL ) - DRV(tty->driver)->flush_buffer(tty); - if ( tty->ldisc.flush_buffer != NULL ) - tty->ldisc.flush_buffer(tty); - tty->closing = 0; - spin_lock_irqsave(&xencons_lock, flags); - xencons_tty = NULL; - spin_unlock_irqrestore(&xencons_lock, flags); - } + unsigned long flags; + + if (DUMMY_TTY(tty)) + return; + + mutex_lock(&tty_mutex); + + if (tty->count != 1) { + mutex_unlock(&tty_mutex); + return; + } + + /* Prevent other threads from re-opening this tty. */ + set_bit(TTY_CLOSING, &tty->flags); + mutex_unlock(&tty_mutex); + + tty->closing = 1; + tty_wait_until_sent(tty, 0); + if (DRV(tty->driver)->flush_buffer != NULL) + DRV(tty->driver)->flush_buffer(tty); + if (tty->ldisc.flush_buffer != NULL) + tty->ldisc.flush_buffer(tty); + tty->closing = 0; + spin_lock_irqsave(&xencons_lock, flags); + xencons_tty = NULL; + spin_unlock_irqrestore(&xencons_lock, flags); } -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0) static struct tty_operations xencons_ops = { - .open = xencons_open, - .close = xencons_close, - .write = xencons_write, - .write_room = xencons_write_room, - .put_char = xencons_put_char, - .flush_chars = xencons_flush_chars, - .chars_in_buffer = xencons_chars_in_buffer, - .send_xchar = xencons_send_xchar, - .flush_buffer = xencons_flush_buffer, - .throttle = xencons_throttle, - .unthrottle = xencons_unthrottle, - .wait_until_sent = xencons_wait_until_sent, + .open = xencons_open, + .close = xencons_close, + .write = xencons_write, + .write_room = xencons_write_room, + .put_char = xencons_put_char, + .flush_chars = xencons_flush_chars, + .chars_in_buffer = xencons_chars_in_buffer, + .send_xchar = xencons_send_xchar, + .flush_buffer = xencons_flush_buffer, + .throttle = xencons_throttle, + .unthrottle = xencons_unthrottle, + .wait_until_sent = xencons_wait_until_sent, }; -#ifdef CONFIG_XEN_PRIVILEGED_GUEST -static const char *xennullcon_startup(void) -{ - return NULL; -} - -static int xennullcon_dummy(void) -{ - return 0; -} - -#define DUMMY (void *)xennullcon_dummy - -/* - * The console `switch' structure for the dummy console - * - * Most of the operations are dummies. - */ - -const struct consw xennull_con = { - .owner = THIS_MODULE, - .con_startup = xennullcon_startup, - .con_init = DUMMY, - .con_deinit = DUMMY, - .con_clear = DUMMY, - .con_putc = DUMMY, - .con_putcs = DUMMY, - .con_cursor = DUMMY, - .con_scroll = DUMMY, - .con_bmove = DUMMY, - .con_switch = DUMMY, - .con_blank = DUMMY, - .con_font_set = DUMMY, - .con_font_get = DUMMY, - .con_font_default = DUMMY, - .con_font_copy = DUMMY, - .con_set_palette = DUMMY, - .con_scrolldelta = DUMMY, -}; -#endif -#endif - static int __init xencons_init(void) { - int rc; - - if ( xc_mode == XC_OFF ) - return 0; - -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0) - xencons_driver = alloc_tty_driver((xc_mode == XC_SERIAL) ? - 1 : MAX_NR_CONSOLES); - if ( xencons_driver == NULL ) - return -ENOMEM; -#else - memset(&xencons_driver, 0, sizeof(struct tty_driver)); - xencons_driver.magic = TTY_DRIVER_MAGIC; - xencons_driver.refcount = &xencons_refcount; - xencons_driver.table = xencons_table; - xencons_driver.num = (xc_mode == XC_SERIAL) ? 1 : MAX_NR_CONSOLES; -#endif - - DRV(xencons_driver)->major = TTY_MAJOR; - DRV(xencons_driver)->type = TTY_DRIVER_TYPE_SERIAL; - DRV(xencons_driver)->subtype = SERIAL_TYPE_NORMAL; - DRV(xencons_driver)->init_termios = tty_std_termios; - DRV(xencons_driver)->flags = - TTY_DRIVER_REAL_RAW | TTY_DRIVER_RESET_TERMIOS | TTY_DRIVER_NO_DEVFS; - DRV(xencons_driver)->termios = xencons_termios; - DRV(xencons_driver)->termios_locked = xencons_termios_locked; - - if ( xc_mode == XC_SERIAL ) - { - DRV(xencons_driver)->name = "ttyS"; - DRV(xencons_driver)->minor_start = 64 + xc_num; - DRV(xencons_driver)->name_base = 0 + xc_num; - } - else - { - DRV(xencons_driver)->name = "tty"; - DRV(xencons_driver)->minor_start = xc_num; - DRV(xencons_driver)->name_base = xc_num; - } - -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0) - tty_set_operations(xencons_driver, &xencons_ops); -#else - xencons_driver.open = xencons_open; - xencons_driver.close = xencons_close; - xencons_driver.write = xencons_write; - xencons_driver.write_room = xencons_write_room; - xencons_driver.put_char = xencons_put_char; - xencons_driver.flush_chars = xencons_flush_chars; - xencons_driver.chars_in_buffer = xencons_chars_in_buffer; - xencons_driver.send_xchar = xencons_send_xchar; - xencons_driver.flush_buffer = xencons_flush_buffer; - xencons_driver.throttle = xencons_throttle; - xencons_driver.unthrottle = xencons_unthrottle; - xencons_driver.wait_until_sent = xencons_wait_until_sent; -#endif - - if ( (rc = tty_register_driver(DRV(xencons_driver))) != 0 ) - { - printk("WARNING: Failed to register Xen virtual " - "console driver as '%s%d'\n", - DRV(xencons_driver)->name, DRV(xencons_driver)->name_base); -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0) - put_tty_driver(xencons_driver); - xencons_driver = NULL; -#endif - return rc; - } - -#if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0) - tty_register_device(xencons_driver, 0, NULL); -#endif - - if ( xen_start_info.flags & SIF_INITDOMAIN ) - { - xencons_priv_irq = bind_virq_to_irq(VIRQ_CONSOLE); - (void)request_irq(xencons_priv_irq, - xencons_priv_interrupt, 0, "console", NULL); - } - else - { - (void)ctrl_if_register_receiver(CMSG_CONSOLE, xencons_rx, 0); - } - - printk("Xen virtual console successfully installed as %s%d\n", - DRV(xencons_driver)->name, - DRV(xencons_driver)->name_base ); - - return 0; + int rc; + + if (!is_running_on_xen()) + return -ENODEV; + + if (xc_mode == XC_OFF) + return 0; + + xencons_ring_init(); + + xencons_driver = alloc_tty_driver((xc_mode == XC_SERIAL) ? + 1 : MAX_NR_CONSOLES); + if (xencons_driver == NULL) + return -ENOMEM; + + DRV(xencons_driver)->name = "xencons"; + DRV(xencons_driver)->major = TTY_MAJOR; + DRV(xencons_driver)->type = TTY_DRIVER_TYPE_SERIAL; + DRV(xencons_driver)->subtype = SERIAL_TYPE_NORMAL; + DRV(xencons_driver)->init_termios = tty_std_termios; + DRV(xencons_driver)->flags = + TTY_DRIVER_REAL_RAW | + TTY_DRIVER_RESET_TERMIOS; + DRV(xencons_driver)->termios = xencons_termios; + DRV(xencons_driver)->termios_locked = xencons_termios_locked; + + if (xc_mode == XC_SERIAL) { + DRV(xencons_driver)->name = "ttyS"; + DRV(xencons_driver)->minor_start = 64 + xc_num; + DRV(xencons_driver)->name_base = 0 + xc_num; + } else { + DRV(xencons_driver)->name = "tty"; + DRV(xencons_driver)->minor_start = 1; + DRV(xencons_driver)->name_base = 1; + } + + tty_set_operations(xencons_driver, &xencons_ops); + + if ((rc = tty_register_driver(DRV(xencons_driver))) != 0) { + printk("WARNING: Failed to register Xen virtual " + "console driver as '%s%d'\n", + DRV(xencons_driver)->name, + DRV(xencons_driver)->name_base); + put_tty_driver(xencons_driver); + xencons_driver = NULL; + return rc; + } + + if (xen_start_info->flags & SIF_INITDOMAIN) { + xencons_priv_irq = bind_virq_to_irqhandler( + VIRQ_CONSOLE, + 0, + xencons_priv_interrupt, + 0, + "console", + NULL); + BUG_ON(xencons_priv_irq < 0); + } + + printk("Xen virtual console successfully installed as %s%d\n", + DRV(xencons_driver)->name, xc_num); + + return 0; } module_init(xencons_init); + +MODULE_LICENSE("Dual BSD/GPL");