ia64/xen-unstable

view linux-2.6-xen-sparse/drivers/xen/console/console.c @ 8810:5aad88c8d379

Remove xennull_con. Use dummy_con.

Signed-off-by: Keir Fraser <keir@xensource.com>
author kaf24@firebug.cl.cam.ac.uk
date Thu Feb 09 15:57:52 2006 +0100 (2006-02-09)
parents 55268b90a519
children e9daf5307296
line source
1 /******************************************************************************
2 * console.c
3 *
4 * Virtual console driver.
5 *
6 * Copyright (c) 2002-2004, K A Fraser.
7 *
8 * This file may be distributed separately from the Linux kernel, or
9 * incorporated into other software packages, subject to the following license:
10 *
11 * Permission is hereby granted, free of charge, to any person obtaining a copy
12 * of this source file (the "Software"), to deal in the Software without
13 * restriction, including without limitation the rights to use, copy, modify,
14 * merge, publish, distribute, sublicense, and/or sell copies of the Software,
15 * and to permit persons to whom the Software is furnished to do so, subject to
16 * the following conditions:
17 *
18 * The above copyright notice and this permission notice shall be included in
19 * all copies or substantial portions of the Software.
20 *
21 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
22 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
23 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
24 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
25 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
26 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
27 * IN THE SOFTWARE.
28 */
30 #include <linux/config.h>
31 #include <linux/version.h>
32 #include <linux/module.h>
33 #include <linux/errno.h>
34 #include <linux/signal.h>
35 #include <linux/sched.h>
36 #include <linux/interrupt.h>
37 #include <linux/tty.h>
38 #include <linux/tty_flip.h>
39 #include <linux/serial.h>
40 #include <linux/major.h>
41 #include <linux/ptrace.h>
42 #include <linux/ioport.h>
43 #include <linux/mm.h>
44 #include <linux/slab.h>
45 #include <linux/init.h>
46 #include <linux/console.h>
47 #include <linux/bootmem.h>
48 #include <linux/sysrq.h>
49 #include <asm/io.h>
50 #include <asm/irq.h>
51 #include <asm/uaccess.h>
52 #include <xen/interface/xen.h>
53 #include <xen/interface/event_channel.h>
54 #include <asm/hypervisor.h>
55 #include <xen/evtchn.h>
56 #include <xen/xencons.h>
58 /*
59 * Modes:
60 * 'xencons=off' [XC_OFF]: Console is disabled.
61 * 'xencons=tty' [XC_TTY]: Console attached to '/dev/tty[0-9]+'.
62 * 'xencons=ttyS' [XC_SERIAL]: Console attached to '/dev/ttyS[0-9]+'.
63 * [XC_DEFAULT]: DOM0 -> XC_SERIAL ; all others -> XC_TTY.
64 *
65 * NB. In mode XC_TTY, we create dummy consoles for tty2-63. This suppresses
66 * warnings from standard distro startup scripts.
67 */
68 static enum { XC_OFF, XC_DEFAULT, XC_TTY, XC_SERIAL } xc_mode = XC_DEFAULT;
69 static int xc_num = -1;
71 #ifdef CONFIG_MAGIC_SYSRQ
72 static unsigned long sysrq_requested;
73 extern int sysrq_enabled;
74 #endif
76 static int __init xencons_setup(char *str)
77 {
78 char *q;
79 int n;
81 if (!strncmp(str, "ttyS", 4))
82 xc_mode = XC_SERIAL;
83 else if (!strncmp(str, "tty", 3))
84 xc_mode = XC_TTY;
85 else if (!strncmp(str, "off", 3))
86 xc_mode = XC_OFF;
88 switch ( xc_mode )
89 {
90 case XC_SERIAL:
91 n = simple_strtol(str+4, &q, 10);
92 if (q > (str + 4))
93 xc_num = n;
94 break;
95 case XC_TTY:
96 n = simple_strtol(str+3, &q, 10);
97 if (q > (str + 3))
98 xc_num = n;
99 break;
100 default:
101 break;
102 }
104 return 1;
105 }
106 __setup("xencons=", xencons_setup);
108 /* The kernel and user-land drivers share a common transmit buffer. */
109 static unsigned int wbuf_size = 4096;
110 #define WBUF_MASK(_i) ((_i)&(wbuf_size-1))
111 static char *wbuf;
112 static unsigned int wc, wp; /* write_cons, write_prod */
114 static int __init xencons_bufsz_setup(char *str)
115 {
116 unsigned int goal;
117 goal = simple_strtoul(str, NULL, 0);
118 while (wbuf_size < goal)
119 wbuf_size <<= 1;
120 return 1;
121 }
122 __setup("xencons_bufsz=", xencons_bufsz_setup);
124 /* This lock protects accesses to the common transmit buffer. */
125 static spinlock_t xencons_lock = SPIN_LOCK_UNLOCKED;
127 /* Common transmit-kick routine. */
128 static void __xencons_tx_flush(void);
130 static struct tty_driver *xencons_driver;
132 /******************** Kernel console driver ********************************/
134 static void kcons_write(
135 struct console *c, const char *s, unsigned int count)
136 {
137 int i = 0;
138 unsigned long flags;
140 spin_lock_irqsave(&xencons_lock, flags);
142 while (i < count) {
143 for (; i < count; i++) {
144 if ((wp - wc) >= (wbuf_size - 1))
145 break;
146 if ((wbuf[WBUF_MASK(wp++)] = s[i]) == '\n')
147 wbuf[WBUF_MASK(wp++)] = '\r';
148 }
150 __xencons_tx_flush();
151 }
153 spin_unlock_irqrestore(&xencons_lock, flags);
154 }
156 static void kcons_write_dom0(
157 struct console *c, const char *s, unsigned int count)
158 {
159 int rc;
161 while ((count > 0) &&
162 ((rc = HYPERVISOR_console_io(
163 CONSOLEIO_write, count, (char *)s)) > 0)) {
164 count -= rc;
165 s += rc;
166 }
167 }
169 static struct tty_driver *kcons_device(struct console *c, int *index)
170 {
171 *index = 0;
172 return xencons_driver;
173 }
175 static struct console kcons_info = {
176 .device = kcons_device,
177 .flags = CON_PRINTBUFFER,
178 .index = -1,
179 };
181 #define __RETCODE 0
182 static int __init xen_console_init(void)
183 {
184 if (xen_init() < 0)
185 return __RETCODE;
187 if (xen_start_info->flags & SIF_INITDOMAIN) {
188 if (xc_mode == XC_DEFAULT)
189 xc_mode = XC_SERIAL;
190 kcons_info.write = kcons_write_dom0;
191 if (xc_mode == XC_SERIAL)
192 kcons_info.flags |= CON_ENABLED;
193 } else {
194 if (xc_mode == XC_DEFAULT)
195 xc_mode = XC_TTY;
196 kcons_info.write = kcons_write;
197 }
199 switch (xc_mode) {
200 case XC_SERIAL:
201 strcpy(kcons_info.name, "ttyS");
202 if (xc_num == -1)
203 xc_num = 0;
204 break;
206 case XC_TTY:
207 strcpy(kcons_info.name, "tty");
208 if (xc_num == -1)
209 xc_num = 1;
210 break;
212 default:
213 return __RETCODE;
214 }
216 wbuf = alloc_bootmem(wbuf_size);
218 register_console(&kcons_info);
220 return __RETCODE;
221 }
222 console_initcall(xen_console_init);
224 /*** Useful function for console debugging -- goes straight to Xen. ***/
225 asmlinkage int xprintk(const char *fmt, ...)
226 {
227 va_list args;
228 int printk_len;
229 static char printk_buf[1024];
231 /* Emit the output into the temporary buffer */
232 va_start(args, fmt);
233 printk_len = vsnprintf(printk_buf, sizeof(printk_buf), fmt, args);
234 va_end(args);
236 /* Send the processed output directly to Xen. */
237 kcons_write_dom0(NULL, printk_buf, printk_len);
239 return 0;
240 }
242 /*** Forcibly flush console data before dying. ***/
243 void xencons_force_flush(void)
244 {
245 int sz;
247 /* Emergency console is synchronous, so there's nothing to flush. */
248 if (xen_start_info->flags & SIF_INITDOMAIN)
249 return;
251 /* Spin until console data is flushed through to the daemon. */
252 while (wc != wp) {
253 int sent = 0;
254 if ((sz = wp - wc) == 0)
255 continue;
256 sent = xencons_ring_send(&wbuf[WBUF_MASK(wc)], sz);
257 if (sent > 0)
258 wc += sent;
259 }
260 }
263 /******************** User-space console driver (/dev/console) ************/
265 #define DRV(_d) (_d)
266 #define TTY_INDEX(_tty) ((_tty)->index)
268 static struct termios *xencons_termios[MAX_NR_CONSOLES];
269 static struct termios *xencons_termios_locked[MAX_NR_CONSOLES];
270 static struct tty_struct *xencons_tty;
271 static int xencons_priv_irq;
272 static char x_char;
274 void xencons_rx(char *buf, unsigned len, struct pt_regs *regs)
275 {
276 int i;
277 unsigned long flags;
279 spin_lock_irqsave(&xencons_lock, flags);
280 if (xencons_tty == NULL)
281 goto out;
283 for (i = 0; i < len; i++) {
284 #ifdef CONFIG_MAGIC_SYSRQ
285 if (sysrq_enabled) {
286 if (buf[i] == '\x0f') { /* ^O */
287 sysrq_requested = jiffies;
288 continue; /* don't print the sysrq key */
289 } else if (sysrq_requested) {
290 unsigned long sysrq_timeout =
291 sysrq_requested + HZ*2;
292 sysrq_requested = 0;
293 if (time_before(jiffies, sysrq_timeout)) {
294 spin_unlock_irqrestore(
295 &xencons_lock, flags);
296 handle_sysrq(
297 buf[i], regs, xencons_tty);
298 spin_lock_irqsave(
299 &xencons_lock, flags);
300 continue;
301 }
302 }
303 }
304 #endif
305 tty_insert_flip_char(xencons_tty, buf[i], 0);
306 }
307 tty_flip_buffer_push(xencons_tty);
309 out:
310 spin_unlock_irqrestore(&xencons_lock, flags);
311 }
313 static void __xencons_tx_flush(void)
314 {
315 int sent, sz, work_done = 0;
317 if (x_char) {
318 if (xen_start_info->flags & SIF_INITDOMAIN)
319 kcons_write_dom0(NULL, &x_char, 1);
320 else
321 while (x_char)
322 if (xencons_ring_send(&x_char, 1) == 1)
323 break;
324 x_char = 0;
325 work_done = 1;
326 }
328 while (wc != wp) {
329 sz = wp - wc;
330 if (sz > (wbuf_size - WBUF_MASK(wc)))
331 sz = wbuf_size - WBUF_MASK(wc);
332 if (xen_start_info->flags & SIF_INITDOMAIN) {
333 kcons_write_dom0(NULL, &wbuf[WBUF_MASK(wc)], sz);
334 wc += sz;
335 } else {
336 sent = xencons_ring_send(&wbuf[WBUF_MASK(wc)], sz);
337 if (sent == 0)
338 break;
339 wc += sent;
340 }
341 work_done = 1;
342 }
344 if (work_done && (xencons_tty != NULL)) {
345 wake_up_interruptible(&xencons_tty->write_wait);
346 if ((xencons_tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
347 (xencons_tty->ldisc.write_wakeup != NULL))
348 (xencons_tty->ldisc.write_wakeup)(xencons_tty);
349 }
350 }
352 void xencons_tx(void)
353 {
354 unsigned long flags;
356 spin_lock_irqsave(&xencons_lock, flags);
357 __xencons_tx_flush();
358 spin_unlock_irqrestore(&xencons_lock, flags);
359 }
361 /* Privileged receive callback and transmit kicker. */
362 static irqreturn_t xencons_priv_interrupt(int irq, void *dev_id,
363 struct pt_regs *regs)
364 {
365 static char rbuf[16];
366 int l;
368 while ((l = HYPERVISOR_console_io(CONSOLEIO_read, 16, rbuf)) > 0)
369 xencons_rx(rbuf, l, regs);
371 xencons_tx();
373 return IRQ_HANDLED;
374 }
376 static int xencons_write_room(struct tty_struct *tty)
377 {
378 return wbuf_size - (wp - wc);
379 }
381 static int xencons_chars_in_buffer(struct tty_struct *tty)
382 {
383 return wp - wc;
384 }
386 static void xencons_send_xchar(struct tty_struct *tty, char ch)
387 {
388 unsigned long flags;
390 if (TTY_INDEX(tty) != 0)
391 return;
393 spin_lock_irqsave(&xencons_lock, flags);
394 x_char = ch;
395 __xencons_tx_flush();
396 spin_unlock_irqrestore(&xencons_lock, flags);
397 }
399 static void xencons_throttle(struct tty_struct *tty)
400 {
401 if (TTY_INDEX(tty) != 0)
402 return;
404 if (I_IXOFF(tty))
405 xencons_send_xchar(tty, STOP_CHAR(tty));
406 }
408 static void xencons_unthrottle(struct tty_struct *tty)
409 {
410 if (TTY_INDEX(tty) != 0)
411 return;
413 if (I_IXOFF(tty)) {
414 if (x_char != 0)
415 x_char = 0;
416 else
417 xencons_send_xchar(tty, START_CHAR(tty));
418 }
419 }
421 static void xencons_flush_buffer(struct tty_struct *tty)
422 {
423 unsigned long flags;
425 if (TTY_INDEX(tty) != 0)
426 return;
428 spin_lock_irqsave(&xencons_lock, flags);
429 wc = wp = 0;
430 spin_unlock_irqrestore(&xencons_lock, flags);
431 }
433 static inline int __xencons_put_char(int ch)
434 {
435 char _ch = (char)ch;
436 if ((wp - wc) == wbuf_size)
437 return 0;
438 wbuf[WBUF_MASK(wp++)] = _ch;
439 return 1;
440 }
442 static int xencons_write(
443 struct tty_struct *tty,
444 const unsigned char *buf,
445 int count)
446 {
447 int i;
448 unsigned long flags;
450 if (TTY_INDEX(tty) != 0)
451 return count;
453 spin_lock_irqsave(&xencons_lock, flags);
455 for (i = 0; i < count; i++)
456 if (!__xencons_put_char(buf[i]))
457 break;
459 if (i != 0)
460 __xencons_tx_flush();
462 spin_unlock_irqrestore(&xencons_lock, flags);
464 return i;
465 }
467 static void xencons_put_char(struct tty_struct *tty, u_char ch)
468 {
469 unsigned long flags;
471 if (TTY_INDEX(tty) != 0)
472 return;
474 spin_lock_irqsave(&xencons_lock, flags);
475 (void)__xencons_put_char(ch);
476 spin_unlock_irqrestore(&xencons_lock, flags);
477 }
479 static void xencons_flush_chars(struct tty_struct *tty)
480 {
481 unsigned long flags;
483 if (TTY_INDEX(tty) != 0)
484 return;
486 spin_lock_irqsave(&xencons_lock, flags);
487 __xencons_tx_flush();
488 spin_unlock_irqrestore(&xencons_lock, flags);
489 }
491 static void xencons_wait_until_sent(struct tty_struct *tty, int timeout)
492 {
493 unsigned long orig_jiffies = jiffies;
495 if (TTY_INDEX(tty) != 0)
496 return;
498 while (DRV(tty->driver)->chars_in_buffer(tty))
499 {
500 set_current_state(TASK_INTERRUPTIBLE);
501 schedule_timeout(1);
502 if (signal_pending(current))
503 break;
504 if ( (timeout != 0) &&
505 time_after(jiffies, orig_jiffies + timeout) )
506 break;
507 }
509 set_current_state(TASK_RUNNING);
510 }
512 static int xencons_open(struct tty_struct *tty, struct file *filp)
513 {
514 unsigned long flags;
516 if (TTY_INDEX(tty) != 0)
517 return 0;
519 spin_lock_irqsave(&xencons_lock, flags);
520 tty->driver_data = NULL;
521 if (xencons_tty == NULL)
522 xencons_tty = tty;
523 __xencons_tx_flush();
524 spin_unlock_irqrestore(&xencons_lock, flags);
526 return 0;
527 }
529 static void xencons_close(struct tty_struct *tty, struct file *filp)
530 {
531 unsigned long flags;
533 if (TTY_INDEX(tty) != 0)
534 return;
536 if (tty->count == 1) {
537 tty->closing = 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);
543 tty->closing = 0;
544 spin_lock_irqsave(&xencons_lock, flags);
545 xencons_tty = NULL;
546 spin_unlock_irqrestore(&xencons_lock, flags);
547 }
548 }
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,
563 };
565 static int __init xencons_init(void)
566 {
567 int rc;
569 if (xen_init() < 0)
570 return -ENODEV;
572 if (xc_mode == XC_OFF)
573 return 0;
575 xencons_ring_init();
577 xencons_driver = alloc_tty_driver((xc_mode == XC_SERIAL) ?
578 1 : MAX_NR_CONSOLES);
579 if (xencons_driver == NULL)
580 return -ENOMEM;
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 |
590 TTY_DRIVER_NO_DEVFS;
591 DRV(xencons_driver)->termios = xencons_termios;
592 DRV(xencons_driver)->termios_locked = xencons_termios_locked;
594 if (xc_mode == XC_SERIAL)
595 {
596 DRV(xencons_driver)->name = "ttyS";
597 DRV(xencons_driver)->minor_start = 64 + xc_num;
598 DRV(xencons_driver)->name_base = 0 + xc_num;
599 } else {
600 DRV(xencons_driver)->name = "tty";
601 DRV(xencons_driver)->minor_start = xc_num;
602 DRV(xencons_driver)->name_base = xc_num;
603 }
605 tty_set_operations(xencons_driver, &xencons_ops);
607 if ((rc = tty_register_driver(DRV(xencons_driver))) != 0) {
608 printk("WARNING: Failed to register Xen virtual "
609 "console driver as '%s%d'\n",
610 DRV(xencons_driver)->name,
611 DRV(xencons_driver)->name_base);
612 put_tty_driver(xencons_driver);
613 xencons_driver = NULL;
614 return rc;
615 }
617 tty_register_device(xencons_driver, 0, NULL);
619 if (xen_start_info->flags & SIF_INITDOMAIN) {
620 xencons_priv_irq = bind_virq_to_irqhandler(
621 VIRQ_CONSOLE,
622 0,
623 xencons_priv_interrupt,
624 0,
625 "console",
626 NULL);
627 BUG_ON(xencons_priv_irq < 0);
628 }
630 printk("Xen virtual console successfully installed as %s%d\n",
631 DRV(xencons_driver)->name,
632 DRV(xencons_driver)->name_base );
634 return 0;
635 }
637 module_init(xencons_init);
639 /*
640 * Local variables:
641 * c-file-style: "linux"
642 * indent-tabs-mode: t
643 * c-indent-level: 8
644 * c-basic-offset: 8
645 * tab-width: 8
646 * End:
647 */