1 /******************************************************************************
4 * Virtual console driver.
6 * Copyright (c) 2002-2004, K A Fraser.
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License version 2
10 * as published by the Free Software Foundation; or, when distributed
11 * separately from the Linux kernel or incorporated into other
12 * software packages, subject to the following license:
14 * Permission is hereby granted, free of charge, to any person obtaining a copy
15 * of this source file (the "Software"), to deal in the Software without
16 * restriction, including without limitation the rights to use, copy, modify,
17 * merge, publish, distribute, sublicense, and/or sell copies of the Software,
18 * and to permit persons to whom the Software is furnished to do so, subject to
19 * the following conditions:
21 * The above copyright notice and this permission notice shall be included in
22 * all copies or substantial portions of the Software.
24 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
25 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
26 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
27 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
28 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
29 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
33 #include <linux/config.h>
34 #include <linux/version.h>
35 #include <linux/module.h>
36 #include <linux/errno.h>
37 #include <linux/signal.h>
38 #include <linux/sched.h>
39 #include <linux/interrupt.h>
40 #include <linux/tty.h>
41 #include <linux/tty_flip.h>
42 #include <linux/serial.h>
43 #include <linux/major.h>
44 #include <linux/ptrace.h>
45 #include <linux/ioport.h>
47 #include <linux/slab.h>
48 #include <linux/init.h>
49 #include <linux/console.h>
50 #include <linux/bootmem.h>
51 #include <linux/sysrq.h>
54 #include <asm/uaccess.h>
55 #include <xen/interface/xen.h>
56 #include <xen/interface/event_channel.h>
57 #include <asm/hypervisor.h>
58 #include <xen/evtchn.h>
59 #include <xen/xencons.h>
63 * 'xencons=off' [XC_OFF]: Console is disabled.
64 * 'xencons=tty' [XC_TTY]: Console attached to '/dev/tty[0-9]+'.
65 * 'xencons=ttyS' [XC_SERIAL]: Console attached to '/dev/ttyS[0-9]+'.
66 * [XC_DEFAULT]: DOM0 -> XC_SERIAL ; all others -> XC_TTY.
68 * NB. In mode XC_TTY, we create dummy consoles for tty2-63. This suppresses
69 * warnings from standard distro startup scripts.
71 static enum { XC_OFF, XC_DEFAULT, XC_TTY, XC_SERIAL } xc_mode = XC_DEFAULT;
72 static int xc_num = -1;
74 #ifdef CONFIG_MAGIC_SYSRQ
75 static unsigned long sysrq_requested;
76 extern int sysrq_enabled;
79 static int __init xencons_setup(char *str)
84 if (!strncmp(str, "ttyS", 4))
86 else if (!strncmp(str, "tty", 3))
88 else if (!strncmp(str, "off", 3))
93 n = simple_strtol(str+4, &q, 10);
98 n = simple_strtol(str+3, &q, 10);
108 __setup("xencons=", xencons_setup);
110 /* The kernel and user-land drivers share a common transmit buffer. */
111 static unsigned int wbuf_size = 4096;
112 #define WBUF_MASK(_i) ((_i)&(wbuf_size-1))
114 static unsigned int wc, wp; /* write_cons, write_prod */
116 static int __init xencons_bufsz_setup(char *str)
119 goal = simple_strtoul(str, NULL, 0);
120 while (wbuf_size < goal)
124 __setup("xencons_bufsz=", xencons_bufsz_setup);
126 /* This lock protects accesses to the common transmit buffer. */
127 static spinlock_t xencons_lock = SPIN_LOCK_UNLOCKED;
129 /* Common transmit-kick routine. */
130 static void __xencons_tx_flush(void);
132 static struct tty_driver *xencons_driver;
134 /******************** Kernel console driver ********************************/
136 static void kcons_write(
137 struct console *c, const char *s, unsigned int count)
142 spin_lock_irqsave(&xencons_lock, flags);
145 for (; i < count; i++) {
146 if ((wp - wc) >= (wbuf_size - 1))
148 if ((wbuf[WBUF_MASK(wp++)] = s[i]) == '\n')
149 wbuf[WBUF_MASK(wp++)] = '\r';
152 __xencons_tx_flush();
155 spin_unlock_irqrestore(&xencons_lock, flags);
158 static void kcons_write_dom0(
159 struct console *c, const char *s, unsigned int count)
163 while ((count > 0) &&
164 ((rc = HYPERVISOR_console_io(
165 CONSOLEIO_write, count, (char *)s)) > 0)) {
171 static struct tty_driver *kcons_device(struct console *c, int *index)
174 return xencons_driver;
177 static struct console kcons_info = {
178 .device = kcons_device,
179 .flags = CON_PRINTBUFFER,
184 static int __init xen_console_init(void)
189 if (xen_start_info->flags & SIF_INITDOMAIN) {
190 if (xc_mode == XC_DEFAULT)
192 kcons_info.write = kcons_write_dom0;
193 if (xc_mode == XC_SERIAL)
194 kcons_info.flags |= CON_ENABLED;
196 if (xc_mode == XC_DEFAULT)
198 kcons_info.write = kcons_write;
203 strcpy(kcons_info.name, "ttyS");
209 strcpy(kcons_info.name, "tty");
218 wbuf = alloc_bootmem(wbuf_size);
220 register_console(&kcons_info);
224 console_initcall(xen_console_init);
226 /*** Useful function for console debugging -- goes straight to Xen. ***/
227 asmlinkage int xprintk(const char *fmt, ...)
231 static char printk_buf[1024];
233 /* Emit the output into the temporary buffer */
235 printk_len = vsnprintf(printk_buf, sizeof(printk_buf), fmt, args);
238 /* Send the processed output directly to Xen. */
239 kcons_write_dom0(NULL, printk_buf, printk_len);
244 /*** Forcibly flush console data before dying. ***/
245 void xencons_force_flush(void)
249 /* Emergency console is synchronous, so there's nothing to flush. */
250 if (xen_start_info->flags & SIF_INITDOMAIN)
253 /* Spin until console data is flushed through to the daemon. */
256 if ((sz = wp - wc) == 0)
258 sent = xencons_ring_send(&wbuf[WBUF_MASK(wc)], sz);
265 /******************** User-space console driver (/dev/console) ************/
268 #define TTY_INDEX(_tty) ((_tty)->index)
270 static struct termios *xencons_termios[MAX_NR_CONSOLES];
271 static struct termios *xencons_termios_locked[MAX_NR_CONSOLES];
272 static struct tty_struct *xencons_tty;
273 static int xencons_priv_irq;
276 void xencons_rx(char *buf, unsigned len, struct pt_regs *regs)
281 spin_lock_irqsave(&xencons_lock, flags);
282 if (xencons_tty == NULL)
285 for (i = 0; i < len; i++) {
286 #ifdef CONFIG_MAGIC_SYSRQ
288 if (buf[i] == '\x0f') { /* ^O */
289 sysrq_requested = jiffies;
290 continue; /* don't print the sysrq key */
291 } else if (sysrq_requested) {
292 unsigned long sysrq_timeout =
293 sysrq_requested + HZ*2;
295 if (time_before(jiffies, sysrq_timeout)) {
296 spin_unlock_irqrestore(
297 &xencons_lock, flags);
299 buf[i], regs, xencons_tty);
301 &xencons_lock, flags);
307 tty_insert_flip_char(xencons_tty, buf[i], 0);
309 tty_flip_buffer_push(xencons_tty);
312 spin_unlock_irqrestore(&xencons_lock, flags);
315 static void __xencons_tx_flush(void)
317 int sent, sz, work_done = 0;
320 if (xen_start_info->flags & SIF_INITDOMAIN)
321 kcons_write_dom0(NULL, &x_char, 1);
324 if (xencons_ring_send(&x_char, 1) == 1)
332 if (sz > (wbuf_size - WBUF_MASK(wc)))
333 sz = wbuf_size - WBUF_MASK(wc);
334 if (xen_start_info->flags & SIF_INITDOMAIN) {
335 kcons_write_dom0(NULL, &wbuf[WBUF_MASK(wc)], sz);
338 sent = xencons_ring_send(&wbuf[WBUF_MASK(wc)], sz);
346 if (work_done && (xencons_tty != NULL)) {
347 wake_up_interruptible(&xencons_tty->write_wait);
348 if ((xencons_tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
349 (xencons_tty->ldisc.write_wakeup != NULL))
350 (xencons_tty->ldisc.write_wakeup)(xencons_tty);
354 void xencons_tx(void)
358 spin_lock_irqsave(&xencons_lock, flags);
359 __xencons_tx_flush();
360 spin_unlock_irqrestore(&xencons_lock, flags);
363 /* Privileged receive callback and transmit kicker. */
364 static irqreturn_t xencons_priv_interrupt(int irq, void *dev_id,
365 struct pt_regs *regs)
367 static char rbuf[16];
370 while ((l = HYPERVISOR_console_io(CONSOLEIO_read, 16, rbuf)) > 0)
371 xencons_rx(rbuf, l, regs);
378 static int xencons_write_room(struct tty_struct *tty)
380 return wbuf_size - (wp - wc);
383 static int xencons_chars_in_buffer(struct tty_struct *tty)
388 static void xencons_send_xchar(struct tty_struct *tty, char ch)
392 if (TTY_INDEX(tty) != 0)
395 spin_lock_irqsave(&xencons_lock, flags);
397 __xencons_tx_flush();
398 spin_unlock_irqrestore(&xencons_lock, flags);
401 static void xencons_throttle(struct tty_struct *tty)
403 if (TTY_INDEX(tty) != 0)
407 xencons_send_xchar(tty, STOP_CHAR(tty));
410 static void xencons_unthrottle(struct tty_struct *tty)
412 if (TTY_INDEX(tty) != 0)
419 xencons_send_xchar(tty, START_CHAR(tty));
423 static void xencons_flush_buffer(struct tty_struct *tty)
427 if (TTY_INDEX(tty) != 0)
430 spin_lock_irqsave(&xencons_lock, flags);
432 spin_unlock_irqrestore(&xencons_lock, flags);
435 static inline int __xencons_put_char(int ch)
438 if ((wp - wc) == wbuf_size)
440 wbuf[WBUF_MASK(wp++)] = _ch;
444 static int xencons_write(
445 struct tty_struct *tty,
446 const unsigned char *buf,
452 if (TTY_INDEX(tty) != 0)
455 spin_lock_irqsave(&xencons_lock, flags);
457 for (i = 0; i < count; i++)
458 if (!__xencons_put_char(buf[i]))
462 __xencons_tx_flush();
464 spin_unlock_irqrestore(&xencons_lock, flags);
469 static void xencons_put_char(struct tty_struct *tty, u_char ch)
473 if (TTY_INDEX(tty) != 0)
476 spin_lock_irqsave(&xencons_lock, flags);
477 (void)__xencons_put_char(ch);
478 spin_unlock_irqrestore(&xencons_lock, flags);
481 static void xencons_flush_chars(struct tty_struct *tty)
485 if (TTY_INDEX(tty) != 0)
488 spin_lock_irqsave(&xencons_lock, flags);
489 __xencons_tx_flush();
490 spin_unlock_irqrestore(&xencons_lock, flags);
493 static void xencons_wait_until_sent(struct tty_struct *tty, int timeout)
495 unsigned long orig_jiffies = jiffies;
497 if (TTY_INDEX(tty) != 0)
500 while (DRV(tty->driver)->chars_in_buffer(tty)) {
501 set_current_state(TASK_INTERRUPTIBLE);
503 if (signal_pending(current))
505 if (timeout && time_after(jiffies, orig_jiffies + timeout))
509 set_current_state(TASK_RUNNING);
512 static int xencons_open(struct tty_struct *tty, struct file *filp)
516 if (TTY_INDEX(tty) != 0)
519 spin_lock_irqsave(&xencons_lock, flags);
520 tty->driver_data = NULL;
521 if (xencons_tty == NULL)
523 __xencons_tx_flush();
524 spin_unlock_irqrestore(&xencons_lock, flags);
529 static void xencons_close(struct tty_struct *tty, struct file *filp)
533 if (TTY_INDEX(tty) != 0)
536 if (tty->count == 1) {
538 tty_wait_until_sent(tty, 0);
539 if (DRV(tty->driver)->flush_buffer != NULL)
540 DRV(tty->driver)->flush_buffer(tty);
541 if (tty->ldisc.flush_buffer != NULL)
542 tty->ldisc.flush_buffer(tty);
544 spin_lock_irqsave(&xencons_lock, flags);
546 spin_unlock_irqrestore(&xencons_lock, flags);
550 static struct tty_operations xencons_ops = {
551 .open = xencons_open,
552 .close = xencons_close,
553 .write = xencons_write,
554 .write_room = xencons_write_room,
555 .put_char = xencons_put_char,
556 .flush_chars = xencons_flush_chars,
557 .chars_in_buffer = xencons_chars_in_buffer,
558 .send_xchar = xencons_send_xchar,
559 .flush_buffer = xencons_flush_buffer,
560 .throttle = xencons_throttle,
561 .unthrottle = xencons_unthrottle,
562 .wait_until_sent = xencons_wait_until_sent,
565 static int __init xencons_init(void)
572 if (xc_mode == XC_OFF)
577 xencons_driver = alloc_tty_driver((xc_mode == XC_SERIAL) ?
578 1 : MAX_NR_CONSOLES);
579 if (xencons_driver == NULL)
582 DRV(xencons_driver)->name = "xencons";
583 DRV(xencons_driver)->major = TTY_MAJOR;
584 DRV(xencons_driver)->type = TTY_DRIVER_TYPE_SERIAL;
585 DRV(xencons_driver)->subtype = SERIAL_TYPE_NORMAL;
586 DRV(xencons_driver)->init_termios = tty_std_termios;
587 DRV(xencons_driver)->flags =
588 TTY_DRIVER_REAL_RAW |
589 TTY_DRIVER_RESET_TERMIOS |
591 DRV(xencons_driver)->termios = xencons_termios;
592 DRV(xencons_driver)->termios_locked = xencons_termios_locked;
594 if (xc_mode == XC_SERIAL) {
595 DRV(xencons_driver)->name = "ttyS";
596 DRV(xencons_driver)->minor_start = 64 + xc_num;
597 DRV(xencons_driver)->name_base = 0 + xc_num;
599 DRV(xencons_driver)->name = "tty";
600 DRV(xencons_driver)->minor_start = xc_num;
601 DRV(xencons_driver)->name_base = xc_num;
604 tty_set_operations(xencons_driver, &xencons_ops);
606 if ((rc = tty_register_driver(DRV(xencons_driver))) != 0) {
607 printk("WARNING: Failed to register Xen virtual "
608 "console driver as '%s%d'\n",
609 DRV(xencons_driver)->name,
610 DRV(xencons_driver)->name_base);
611 put_tty_driver(xencons_driver);
612 xencons_driver = NULL;
616 tty_register_device(xencons_driver, 0, NULL);
618 if (xen_start_info->flags & SIF_INITDOMAIN) {
619 xencons_priv_irq = bind_virq_to_irqhandler(
622 xencons_priv_interrupt,
626 BUG_ON(xencons_priv_irq < 0);
629 printk("Xen virtual console successfully installed as %s%d\n",
630 DRV(xencons_driver)->name,
631 DRV(xencons_driver)->name_base );
636 module_init(xencons_init);
638 MODULE_LICENSE("Dual BSD/GPL");
642 * c-file-style: "linux"
643 * indent-tabs-mode: t