ia64/xen-unstable

view linux-2.6-xen-sparse/drivers/xen/console/console.c @ 14100:e47738923a05

[LINUX] Purge include <linux/config.h>. It has been obsolete for some time now.

Signed-off-by: Ian Campbell <ian.campbell@xensource.com>
author Ian Campbell <ian.campbell@xensource.com>
date Fri Feb 23 16:56:45 2007 +0000 (2007-02-23)
parents 3adf00179a63
children f9fbcc354daa
line source
1 /******************************************************************************
2 * console.c
3 *
4 * Virtual console driver.
5 *
6 * Copyright (c) 2002-2004, K A Fraser.
7 *
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:
13 *
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:
20 *
21 * The above copyright notice and this permission notice shall be included in
22 * all copies or substantial portions of the Software.
23 *
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
30 * IN THE SOFTWARE.
31 */
33 #include <linux/version.h>
34 #include <linux/module.h>
35 #include <linux/errno.h>
36 #include <linux/signal.h>
37 #include <linux/sched.h>
38 #include <linux/interrupt.h>
39 #include <linux/tty.h>
40 #include <linux/tty_flip.h>
41 #include <linux/serial.h>
42 #include <linux/major.h>
43 #include <linux/ptrace.h>
44 #include <linux/ioport.h>
45 #include <linux/mm.h>
46 #include <linux/slab.h>
47 #include <linux/init.h>
48 #include <linux/console.h>
49 #include <linux/bootmem.h>
50 #include <linux/sysrq.h>
51 #include <linux/screen_info.h>
52 #include <linux/vt.h>
53 #include <asm/io.h>
54 #include <asm/irq.h>
55 #include <asm/uaccess.h>
56 #include <xen/interface/xen.h>
57 #include <xen/interface/event_channel.h>
58 #include <asm/hypervisor.h>
59 #include <xen/evtchn.h>
60 #include <xen/xenbus.h>
61 #include <xen/xencons.h>
63 /*
64 * Modes:
65 * 'xencons=off' [XC_OFF]: Console is disabled.
66 * 'xencons=tty' [XC_TTY]: Console attached to '/dev/tty[0-9]+'.
67 * 'xencons=ttyS' [XC_SERIAL]: Console attached to '/dev/ttyS[0-9]+'.
68 * 'xencons=xvc' [XC_XVC]: Console attached to '/dev/xvc0'.
69 * default: DOM0 -> XC_SERIAL ; all others -> XC_TTY.
70 *
71 * NB. In mode XC_TTY, we create dummy consoles for tty2-63. This suppresses
72 * warnings from standard distro startup scripts.
73 */
74 static enum {
75 XC_OFF, XC_TTY, XC_SERIAL, XC_XVC
76 } xc_mode;
77 static int xc_num = -1;
79 /* /dev/xvc0 device number allocated by lanana.org. */
80 #define XEN_XVC_MAJOR 204
81 #define XEN_XVC_MINOR 191
83 #ifdef CONFIG_MAGIC_SYSRQ
84 static unsigned long sysrq_requested;
85 extern int sysrq_enabled;
86 #endif
88 void xencons_early_setup(void)
89 {
90 extern int console_use_vt;
92 if (is_initial_xendomain()) {
93 xc_mode = XC_SERIAL;
94 } else {
95 xc_mode = XC_TTY;
96 console_use_vt = 0;
97 }
98 }
100 static int __init xencons_setup(char *str)
101 {
102 char *q;
103 int n;
104 extern int console_use_vt;
106 console_use_vt = 1;
107 if (!strncmp(str, "ttyS", 4)) {
108 xc_mode = XC_SERIAL;
109 str += 4;
110 } else if (!strncmp(str, "tty", 3)) {
111 xc_mode = XC_TTY;
112 str += 3;
113 console_use_vt = 0;
114 } else if (!strncmp(str, "xvc", 3)) {
115 xc_mode = XC_XVC;
116 str += 3;
117 } else if (!strncmp(str, "off", 3)) {
118 xc_mode = XC_OFF;
119 str += 3;
120 }
122 n = simple_strtol(str, &q, 10);
123 if (q != str)
124 xc_num = n;
126 return 1;
127 }
128 __setup("xencons=", xencons_setup);
130 /* The kernel and user-land drivers share a common transmit buffer. */
131 static unsigned int wbuf_size = 4096;
132 #define WBUF_MASK(_i) ((_i)&(wbuf_size-1))
133 static char *wbuf;
134 static unsigned int wc, wp; /* write_cons, write_prod */
136 static int __init xencons_bufsz_setup(char *str)
137 {
138 unsigned int goal;
139 goal = simple_strtoul(str, NULL, 0);
140 if (goal) {
141 goal = roundup_pow_of_two(goal);
142 if (wbuf_size < goal)
143 wbuf_size = goal;
144 }
145 return 1;
146 }
147 __setup("xencons_bufsz=", xencons_bufsz_setup);
149 /* This lock protects accesses to the common transmit buffer. */
150 static DEFINE_SPINLOCK(xencons_lock);
152 /* Common transmit-kick routine. */
153 static void __xencons_tx_flush(void);
155 static struct tty_driver *xencons_driver;
157 /******************** Kernel console driver ********************************/
159 static void kcons_write(struct console *c, const char *s, unsigned int count)
160 {
161 int i = 0;
162 unsigned long flags;
164 spin_lock_irqsave(&xencons_lock, flags);
166 while (i < count) {
167 for (; i < count; i++) {
168 if ((wp - wc) >= (wbuf_size - 1))
169 break;
170 if ((wbuf[WBUF_MASK(wp++)] = s[i]) == '\n')
171 wbuf[WBUF_MASK(wp++)] = '\r';
172 }
174 __xencons_tx_flush();
175 }
177 spin_unlock_irqrestore(&xencons_lock, flags);
178 }
180 static void kcons_write_dom0(struct console *c, const char *s, unsigned int count)
181 {
183 while (count > 0) {
184 int rc;
185 rc = HYPERVISOR_console_io( CONSOLEIO_write, count, (char *)s);
186 if (rc <= 0)
187 break;
188 count -= rc;
189 s += rc;
190 }
191 }
193 static struct tty_driver *kcons_device(struct console *c, int *index)
194 {
195 *index = 0;
196 return xencons_driver;
197 }
199 static struct console kcons_info = {
200 .device = kcons_device,
201 .flags = CON_PRINTBUFFER | CON_ENABLED,
202 .index = -1,
203 };
205 static int __init xen_console_init(void)
206 {
207 if (!is_running_on_xen())
208 goto out;
210 if (is_initial_xendomain()) {
211 kcons_info.write = kcons_write_dom0;
212 } else {
213 if (!xen_start_info->console.domU.evtchn)
214 goto out;
215 kcons_info.write = kcons_write;
216 }
218 switch (xc_mode) {
219 case XC_XVC:
220 strcpy(kcons_info.name, "xvc");
221 if (xc_num == -1)
222 xc_num = 0;
223 break;
225 case XC_SERIAL:
226 strcpy(kcons_info.name, "ttyS");
227 if (xc_num == -1)
228 xc_num = 0;
229 break;
231 case XC_TTY:
232 strcpy(kcons_info.name, "tty");
233 if (xc_num == -1)
234 xc_num = 1;
235 break;
237 default:
238 goto out;
239 }
241 wbuf = alloc_bootmem(wbuf_size);
243 register_console(&kcons_info);
245 out:
246 return 0;
247 }
248 console_initcall(xen_console_init);
250 /*** Useful function for console debugging -- goes straight to Xen. ***/
251 asmlinkage int xprintk(const char *fmt, ...)
252 {
253 va_list args;
254 int printk_len;
255 static char printk_buf[1024];
257 /* Emit the output into the temporary buffer */
258 va_start(args, fmt);
259 printk_len = vsnprintf(printk_buf, sizeof(printk_buf), fmt, args);
260 va_end(args);
262 /* Send the processed output directly to Xen. */
263 kcons_write_dom0(NULL, printk_buf, printk_len);
265 return 0;
266 }
268 /*** Forcibly flush console data before dying. ***/
269 void xencons_force_flush(void)
270 {
271 int sz;
273 /* Emergency console is synchronous, so there's nothing to flush. */
274 if (!is_running_on_xen() ||
275 is_initial_xendomain() ||
276 !xen_start_info->console.domU.evtchn)
277 return;
279 /* Spin until console data is flushed through to the daemon. */
280 while (wc != wp) {
281 int sent = 0;
282 if ((sz = wp - wc) == 0)
283 continue;
284 sent = xencons_ring_send(&wbuf[WBUF_MASK(wc)], sz);
285 if (sent > 0)
286 wc += sent;
287 }
288 }
291 void dom0_init_screen_info(const struct dom0_vga_console_info *info)
292 {
293 switch (info->video_type) {
294 case XEN_VGATYPE_TEXT_MODE_3:
295 screen_info.orig_video_mode = 3;
296 screen_info.orig_video_ega_bx = 3;
297 screen_info.orig_video_isVGA = 1;
298 screen_info.orig_video_lines = info->u.text_mode_3.rows;
299 screen_info.orig_video_cols = info->u.text_mode_3.columns;
300 screen_info.orig_x = info->u.text_mode_3.cursor_x;
301 screen_info.orig_y = info->u.text_mode_3.cursor_y;
302 screen_info.orig_video_points =
303 info->u.text_mode_3.font_height;
304 break;
305 case XEN_VGATYPE_VESA_LFB:
306 screen_info.orig_video_isVGA = VIDEO_TYPE_VLFB;
307 screen_info.lfb_width = info->u.vesa_lfb.width;
308 screen_info.lfb_height = info->u.vesa_lfb.height;
309 screen_info.lfb_depth = info->u.vesa_lfb.bits_per_pixel;
310 screen_info.lfb_base = info->u.vesa_lfb.lfb_base;
311 screen_info.lfb_size = info->u.vesa_lfb.lfb_size;
312 screen_info.lfb_linelength = info->u.vesa_lfb.bytes_per_line;
313 screen_info.red_size = info->u.vesa_lfb.red_size;
314 screen_info.red_pos = info->u.vesa_lfb.red_pos;
315 screen_info.green_size = info->u.vesa_lfb.green_size;
316 screen_info.green_pos = info->u.vesa_lfb.green_pos;
317 screen_info.blue_size = info->u.vesa_lfb.blue_size;
318 screen_info.blue_pos = info->u.vesa_lfb.blue_pos;
319 screen_info.rsvd_size = info->u.vesa_lfb.rsvd_size;
320 screen_info.rsvd_pos = info->u.vesa_lfb.rsvd_pos;
321 break;
322 }
323 }
326 /******************** User-space console driver (/dev/console) ************/
328 #define DRV(_d) (_d)
329 #define DUMMY_TTY(_tty) ((xc_mode == XC_TTY) && \
330 ((_tty)->index != (xc_num - 1)))
332 static struct termios *xencons_termios[MAX_NR_CONSOLES];
333 static struct termios *xencons_termios_locked[MAX_NR_CONSOLES];
334 static struct tty_struct *xencons_tty;
335 static int xencons_priv_irq;
336 static char x_char;
338 void xencons_rx(char *buf, unsigned len, struct pt_regs *regs)
339 {
340 int i;
341 unsigned long flags;
343 spin_lock_irqsave(&xencons_lock, flags);
344 if (xencons_tty == NULL)
345 goto out;
347 for (i = 0; i < len; i++) {
348 #ifdef CONFIG_MAGIC_SYSRQ
349 if (sysrq_enabled) {
350 if (buf[i] == '\x0f') { /* ^O */
351 sysrq_requested = jiffies;
352 continue; /* don't print the sysrq key */
353 } else if (sysrq_requested) {
354 unsigned long sysrq_timeout =
355 sysrq_requested + HZ*2;
356 sysrq_requested = 0;
357 if (time_before(jiffies, sysrq_timeout)) {
358 spin_unlock_irqrestore(
359 &xencons_lock, flags);
360 handle_sysrq(
361 buf[i], regs, xencons_tty);
362 spin_lock_irqsave(
363 &xencons_lock, flags);
364 continue;
365 }
366 }
367 }
368 #endif
369 tty_insert_flip_char(xencons_tty, buf[i], 0);
370 }
371 tty_flip_buffer_push(xencons_tty);
373 out:
374 spin_unlock_irqrestore(&xencons_lock, flags);
375 }
377 static void __xencons_tx_flush(void)
378 {
379 int sent, sz, work_done = 0;
381 if (x_char) {
382 if (is_initial_xendomain())
383 kcons_write_dom0(NULL, &x_char, 1);
384 else
385 while (x_char)
386 if (xencons_ring_send(&x_char, 1) == 1)
387 break;
388 x_char = 0;
389 work_done = 1;
390 }
392 while (wc != wp) {
393 sz = wp - wc;
394 if (sz > (wbuf_size - WBUF_MASK(wc)))
395 sz = wbuf_size - WBUF_MASK(wc);
396 if (is_initial_xendomain()) {
397 kcons_write_dom0(NULL, &wbuf[WBUF_MASK(wc)], sz);
398 wc += sz;
399 } else {
400 sent = xencons_ring_send(&wbuf[WBUF_MASK(wc)], sz);
401 if (sent == 0)
402 break;
403 wc += sent;
404 }
405 work_done = 1;
406 }
408 if (work_done && (xencons_tty != NULL)) {
409 wake_up_interruptible(&xencons_tty->write_wait);
410 if ((xencons_tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
411 (xencons_tty->ldisc.write_wakeup != NULL))
412 (xencons_tty->ldisc.write_wakeup)(xencons_tty);
413 }
414 }
416 void xencons_tx(void)
417 {
418 unsigned long flags;
420 spin_lock_irqsave(&xencons_lock, flags);
421 __xencons_tx_flush();
422 spin_unlock_irqrestore(&xencons_lock, flags);
423 }
425 /* Privileged receive callback and transmit kicker. */
426 static irqreturn_t xencons_priv_interrupt(int irq, void *dev_id,
427 struct pt_regs *regs)
428 {
429 static char rbuf[16];
430 int l;
432 while ((l = HYPERVISOR_console_io(CONSOLEIO_read, 16, rbuf)) > 0)
433 xencons_rx(rbuf, l, regs);
435 xencons_tx();
437 return IRQ_HANDLED;
438 }
440 static int xencons_write_room(struct tty_struct *tty)
441 {
442 return wbuf_size - (wp - wc);
443 }
445 static int xencons_chars_in_buffer(struct tty_struct *tty)
446 {
447 return wp - wc;
448 }
450 static void xencons_send_xchar(struct tty_struct *tty, char ch)
451 {
452 unsigned long flags;
454 if (DUMMY_TTY(tty))
455 return;
457 spin_lock_irqsave(&xencons_lock, flags);
458 x_char = ch;
459 __xencons_tx_flush();
460 spin_unlock_irqrestore(&xencons_lock, flags);
461 }
463 static void xencons_throttle(struct tty_struct *tty)
464 {
465 if (DUMMY_TTY(tty))
466 return;
468 if (I_IXOFF(tty))
469 xencons_send_xchar(tty, STOP_CHAR(tty));
470 }
472 static void xencons_unthrottle(struct tty_struct *tty)
473 {
474 if (DUMMY_TTY(tty))
475 return;
477 if (I_IXOFF(tty)) {
478 if (x_char != 0)
479 x_char = 0;
480 else
481 xencons_send_xchar(tty, START_CHAR(tty));
482 }
483 }
485 static void xencons_flush_buffer(struct tty_struct *tty)
486 {
487 unsigned long flags;
489 if (DUMMY_TTY(tty))
490 return;
492 spin_lock_irqsave(&xencons_lock, flags);
493 wc = wp = 0;
494 spin_unlock_irqrestore(&xencons_lock, flags);
495 }
497 static inline int __xencons_put_char(int ch)
498 {
499 char _ch = (char)ch;
500 if ((wp - wc) == wbuf_size)
501 return 0;
502 wbuf[WBUF_MASK(wp++)] = _ch;
503 return 1;
504 }
506 static int xencons_write(
507 struct tty_struct *tty,
508 const unsigned char *buf,
509 int count)
510 {
511 int i;
512 unsigned long flags;
514 if (DUMMY_TTY(tty))
515 return count;
517 spin_lock_irqsave(&xencons_lock, flags);
519 for (i = 0; i < count; i++)
520 if (!__xencons_put_char(buf[i]))
521 break;
523 if (i != 0)
524 __xencons_tx_flush();
526 spin_unlock_irqrestore(&xencons_lock, flags);
528 return i;
529 }
531 static void xencons_put_char(struct tty_struct *tty, u_char ch)
532 {
533 unsigned long flags;
535 if (DUMMY_TTY(tty))
536 return;
538 spin_lock_irqsave(&xencons_lock, flags);
539 (void)__xencons_put_char(ch);
540 spin_unlock_irqrestore(&xencons_lock, flags);
541 }
543 static void xencons_flush_chars(struct tty_struct *tty)
544 {
545 unsigned long flags;
547 if (DUMMY_TTY(tty))
548 return;
550 spin_lock_irqsave(&xencons_lock, flags);
551 __xencons_tx_flush();
552 spin_unlock_irqrestore(&xencons_lock, flags);
553 }
555 static void xencons_wait_until_sent(struct tty_struct *tty, int timeout)
556 {
557 unsigned long orig_jiffies = jiffies;
559 if (DUMMY_TTY(tty))
560 return;
562 while (DRV(tty->driver)->chars_in_buffer(tty)) {
563 set_current_state(TASK_INTERRUPTIBLE);
564 schedule_timeout(1);
565 if (signal_pending(current))
566 break;
567 if (timeout && time_after(jiffies, orig_jiffies + timeout))
568 break;
569 }
571 set_current_state(TASK_RUNNING);
572 }
574 static int xencons_open(struct tty_struct *tty, struct file *filp)
575 {
576 unsigned long flags;
578 if (DUMMY_TTY(tty))
579 return 0;
581 spin_lock_irqsave(&xencons_lock, flags);
582 tty->driver_data = NULL;
583 if (xencons_tty == NULL)
584 xencons_tty = tty;
585 __xencons_tx_flush();
586 spin_unlock_irqrestore(&xencons_lock, flags);
588 return 0;
589 }
591 static void xencons_close(struct tty_struct *tty, struct file *filp)
592 {
593 unsigned long flags;
595 if (DUMMY_TTY(tty))
596 return;
598 mutex_lock(&tty_mutex);
600 if (tty->count != 1) {
601 mutex_unlock(&tty_mutex);
602 return;
603 }
605 /* Prevent other threads from re-opening this tty. */
606 set_bit(TTY_CLOSING, &tty->flags);
607 mutex_unlock(&tty_mutex);
609 tty->closing = 1;
610 tty_wait_until_sent(tty, 0);
611 if (DRV(tty->driver)->flush_buffer != NULL)
612 DRV(tty->driver)->flush_buffer(tty);
613 if (tty->ldisc.flush_buffer != NULL)
614 tty->ldisc.flush_buffer(tty);
615 tty->closing = 0;
616 spin_lock_irqsave(&xencons_lock, flags);
617 xencons_tty = NULL;
618 spin_unlock_irqrestore(&xencons_lock, flags);
619 }
621 static struct tty_operations xencons_ops = {
622 .open = xencons_open,
623 .close = xencons_close,
624 .write = xencons_write,
625 .write_room = xencons_write_room,
626 .put_char = xencons_put_char,
627 .flush_chars = xencons_flush_chars,
628 .chars_in_buffer = xencons_chars_in_buffer,
629 .send_xchar = xencons_send_xchar,
630 .flush_buffer = xencons_flush_buffer,
631 .throttle = xencons_throttle,
632 .unthrottle = xencons_unthrottle,
633 .wait_until_sent = xencons_wait_until_sent,
634 };
636 static int __init xencons_init(void)
637 {
638 int rc;
640 if (!is_running_on_xen())
641 return -ENODEV;
643 if (xc_mode == XC_OFF)
644 return 0;
646 if (!is_initial_xendomain()) {
647 rc = xencons_ring_init();
648 if (rc)
649 return rc;
650 }
652 xencons_driver = alloc_tty_driver((xc_mode == XC_TTY) ?
653 MAX_NR_CONSOLES : 1);
654 if (xencons_driver == NULL)
655 return -ENOMEM;
657 DRV(xencons_driver)->name = "xencons";
658 DRV(xencons_driver)->major = TTY_MAJOR;
659 DRV(xencons_driver)->type = TTY_DRIVER_TYPE_SERIAL;
660 DRV(xencons_driver)->subtype = SERIAL_TYPE_NORMAL;
661 DRV(xencons_driver)->init_termios = tty_std_termios;
662 DRV(xencons_driver)->flags =
663 TTY_DRIVER_REAL_RAW |
664 TTY_DRIVER_RESET_TERMIOS;
665 DRV(xencons_driver)->termios = xencons_termios;
666 DRV(xencons_driver)->termios_locked = xencons_termios_locked;
668 switch (xc_mode) {
669 case XC_XVC:
670 DRV(xencons_driver)->name = "xvc";
671 DRV(xencons_driver)->major = XEN_XVC_MAJOR;
672 DRV(xencons_driver)->minor_start = XEN_XVC_MINOR;
673 DRV(xencons_driver)->name_base = xc_num;
674 break;
675 case XC_SERIAL:
676 DRV(xencons_driver)->name = "ttyS";
677 DRV(xencons_driver)->minor_start = 64 + xc_num;
678 DRV(xencons_driver)->name_base = xc_num;
679 break;
680 default:
681 DRV(xencons_driver)->name = "tty";
682 DRV(xencons_driver)->minor_start = 1;
683 DRV(xencons_driver)->name_base = 1;
684 break;
685 }
687 tty_set_operations(xencons_driver, &xencons_ops);
689 if ((rc = tty_register_driver(DRV(xencons_driver))) != 0) {
690 printk("WARNING: Failed to register Xen virtual "
691 "console driver as '%s%d'\n",
692 DRV(xencons_driver)->name,
693 DRV(xencons_driver)->name_base);
694 put_tty_driver(xencons_driver);
695 xencons_driver = NULL;
696 return rc;
697 }
699 if (is_initial_xendomain()) {
700 xencons_priv_irq = bind_virq_to_irqhandler(
701 VIRQ_CONSOLE,
702 0,
703 xencons_priv_interrupt,
704 0,
705 "console",
706 NULL);
707 BUG_ON(xencons_priv_irq < 0);
708 }
710 printk("Xen virtual console successfully installed as %s%d\n",
711 DRV(xencons_driver)->name, xc_num);
713 return 0;
714 }
716 module_init(xencons_init);
718 MODULE_LICENSE("Dual BSD/GPL");