xen-vtx-unstable

view 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
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 <asm-xen/xen-public/event_channel.h>
53 #include <asm-xen/hypervisor.h>
54 #include <asm-xen/evtchn.h>
56 #include "xencons_ring.h"
57 /*
58 * Modes:
59 * 'xencons=off' [XC_OFF]: Console is disabled.
60 * 'xencons=tty' [XC_TTY]: Console attached to '/dev/tty[0-9]+'.
61 * 'xencons=ttyS' [XC_SERIAL]: Console attached to '/dev/ttyS[0-9]+'.
62 * [XC_DEFAULT]: DOM0 -> XC_SERIAL ; all others -> XC_TTY.
63 *
64 * NB. In mode XC_TTY, we create dummy consoles for tty2-63. This suppresses
65 * warnings from standard distro startup scripts.
66 */
67 static enum { XC_OFF, XC_DEFAULT, XC_TTY, XC_SERIAL } xc_mode = XC_DEFAULT;
68 static int xc_num = -1;
70 #ifdef CONFIG_MAGIC_SYSRQ
71 static unsigned long sysrq_requested;
72 extern int sysrq_enabled;
73 #endif
75 static int __init xencons_setup(char *str)
76 {
77 char *q;
78 int n;
80 if ( !strncmp(str, "ttyS", 4) )
81 xc_mode = XC_SERIAL;
82 else if ( !strncmp(str, "tty", 3) )
83 xc_mode = XC_TTY;
84 else if ( !strncmp(str, "off", 3) )
85 xc_mode = XC_OFF;
87 switch ( xc_mode )
88 {
89 case XC_SERIAL:
90 n = simple_strtol( str+4, &q, 10 );
91 if ( q > (str + 4) ) xc_num = n;
92 break;
93 case XC_TTY:
94 n = simple_strtol( str+3, &q, 10 );
95 if ( q > (str + 3) ) xc_num = n;
96 break;
97 default:
98 break;
99 }
101 return 1;
102 }
103 __setup("xencons=", xencons_setup);
105 /* The kernel and user-land drivers share a common transmit buffer. */
106 static unsigned int wbuf_size = 4096;
107 #define WBUF_MASK(_i) ((_i)&(wbuf_size-1))
108 static char *wbuf;
109 static unsigned int wc, wp; /* write_cons, write_prod */
111 static int __init xencons_bufsz_setup(char *str)
112 {
113 unsigned int goal;
114 goal = simple_strtoul(str, NULL, 0);
115 while ( wbuf_size < goal )
116 wbuf_size <<= 1;
117 return 1;
118 }
119 __setup("xencons_bufsz=", xencons_bufsz_setup);
121 /* This lock protects accesses to the common transmit buffer. */
122 static spinlock_t xencons_lock = SPIN_LOCK_UNLOCKED;
124 /* Common transmit-kick routine. */
125 static void __xencons_tx_flush(void);
127 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
128 static struct tty_driver *xencons_driver;
129 #else
130 static struct tty_driver xencons_driver;
131 #endif
134 /******************** Kernel console driver ********************************/
136 static void kcons_write(
137 struct console *c, const char *s, unsigned int count)
138 {
139 int i;
140 unsigned long flags;
142 spin_lock_irqsave(&xencons_lock, flags);
144 for ( i = 0; i < count; i++ )
145 {
146 if ( (wp - wc) >= (wbuf_size - 1) )
147 break;
148 if ( (wbuf[WBUF_MASK(wp++)] = s[i]) == '\n' )
149 wbuf[WBUF_MASK(wp++)] = '\r';
150 }
152 __xencons_tx_flush();
154 spin_unlock_irqrestore(&xencons_lock, flags);
155 }
157 static void kcons_write_dom0(
158 struct console *c, const char *s, unsigned int count)
159 {
160 int rc;
162 while ( (count > 0) &&
163 ((rc = HYPERVISOR_console_io(
164 CONSOLEIO_write, count, (char *)s)) > 0) )
165 {
166 count -= rc;
167 s += rc;
168 }
169 }
171 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
172 static struct tty_driver *kcons_device(struct console *c, int *index)
173 {
174 *index = c->index;
175 return xencons_driver;
176 }
177 #else
178 static kdev_t kcons_device(struct console *c)
179 {
180 return MKDEV(TTY_MAJOR, (xc_mode == XC_SERIAL) ? 64 : 1);
181 }
182 #endif
184 static struct console kcons_info = {
185 .device = kcons_device,
186 .flags = CON_PRINTBUFFER,
187 .index = -1,
188 };
190 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
191 #define __RETCODE 0
192 static int __init xen_console_init(void)
193 #else
194 #define __RETCODE
195 void xen_console_init(void)
196 #endif
197 {
198 if ( xen_start_info->flags & SIF_INITDOMAIN )
199 {
200 if ( xc_mode == XC_DEFAULT )
201 xc_mode = XC_SERIAL;
202 kcons_info.write = kcons_write_dom0;
203 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
204 if ( xc_mode == XC_SERIAL )
205 kcons_info.flags |= CON_ENABLED;
206 #endif
207 }
208 else
209 {
210 if ( xc_mode == XC_DEFAULT )
211 xc_mode = XC_TTY;
212 kcons_info.write = kcons_write;
213 }
215 switch ( xc_mode )
216 {
217 case XC_SERIAL:
218 strcpy(kcons_info.name, "ttyS");
219 if ( xc_num == -1 ) xc_num = 0;
220 break;
222 case XC_TTY:
223 strcpy(kcons_info.name, "tty");
224 if ( xc_num == -1 ) xc_num = 1;
225 break;
227 default:
228 return __RETCODE;
229 }
231 wbuf = alloc_bootmem(wbuf_size);
233 register_console(&kcons_info);
235 return __RETCODE;
236 }
237 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
238 console_initcall(xen_console_init);
239 #endif
241 /*** Useful function for console debugging -- goes straight to Xen. ***/
242 #ifdef CONFIG_XEN_PRIVILEGED_GUEST
243 asmlinkage int xprintk(const char *fmt, ...)
244 #else
245 asmlinkage int xprintk(const char *fmt, ...)
246 #endif
247 {
248 va_list args;
249 int printk_len;
250 static char printk_buf[1024];
252 /* Emit the output into the temporary buffer */
253 va_start(args, fmt);
254 printk_len = vsnprintf(printk_buf, sizeof(printk_buf), fmt, args);
255 va_end(args);
257 /* Send the processed output directly to Xen. */
258 kcons_write_dom0(NULL, printk_buf, printk_len);
260 return 0;
261 }
263 /*** Forcibly flush console data before dying. ***/
264 void xencons_force_flush(void)
265 {
266 int sz;
268 /* Emergency console is synchronous, so there's nothing to flush. */
269 if ( xen_start_info->flags & SIF_INITDOMAIN )
270 return;
273 /* Spin until console data is flushed through to the domain controller. */
274 while ( (wc != wp) )
275 {
276 int sent = 0;
277 if ( (sz = wp - wc) == 0 )
278 continue;
279 sent = xencons_ring_send(&wbuf[WBUF_MASK(wc)], sz);
280 if (sent > 0)
281 wc += sent;
282 }
283 }
286 /******************** User-space console driver (/dev/console) ************/
288 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
289 #define DRV(_d) (_d)
290 #define TTY_INDEX(_tty) ((_tty)->index)
291 #else
292 static int xencons_refcount;
293 static struct tty_struct *xencons_table[MAX_NR_CONSOLES];
294 #define DRV(_d) (&(_d))
295 #define TTY_INDEX(_tty) (MINOR((_tty)->device) - xencons_driver.minor_start)
296 #endif
298 static struct termios *xencons_termios[MAX_NR_CONSOLES];
299 static struct termios *xencons_termios_locked[MAX_NR_CONSOLES];
300 static struct tty_struct *xencons_tty;
301 static int xencons_priv_irq;
302 static char x_char;
304 /* Non-privileged receive callback. */
305 static void xencons_rx(char *buf, unsigned len, struct pt_regs *regs)
306 {
307 int i;
308 unsigned long flags;
310 spin_lock_irqsave(&xencons_lock, flags);
311 if ( xencons_tty != NULL )
312 {
313 for ( i = 0; i < len; i++ ) {
314 #ifdef CONFIG_MAGIC_SYSRQ
315 if (sysrq_enabled) {
316 if (buf[i] == '\x0f') { /* ^O */
317 sysrq_requested = jiffies;
318 continue; /* don't print the sysrq key */
319 } else if (sysrq_requested) {
320 unsigned long sysrq_timeout = sysrq_requested + HZ*2;
321 sysrq_requested = 0;
322 /* if it's been less than a timeout, do the sysrq */
323 if (time_before(jiffies, sysrq_timeout)) {
324 spin_unlock_irqrestore(&xencons_lock, flags);
325 handle_sysrq(buf[i], regs, xencons_tty);
326 spin_lock_irqsave(&xencons_lock, flags);
327 continue;
328 }
329 }
330 }
331 #endif
332 tty_insert_flip_char(xencons_tty, buf[i], 0);
333 }
334 tty_flip_buffer_push(xencons_tty);
335 }
336 spin_unlock_irqrestore(&xencons_lock, flags);
338 }
340 /* Privileged and non-privileged transmit worker. */
341 static void __xencons_tx_flush(void)
342 {
343 int sz, work_done = 0;
345 if ( xen_start_info->flags & SIF_INITDOMAIN )
346 {
347 if ( x_char )
348 {
349 kcons_write_dom0(NULL, &x_char, 1);
350 x_char = 0;
351 work_done = 1;
352 }
354 while ( wc != wp )
355 {
356 sz = wp - wc;
357 if ( sz > (wbuf_size - WBUF_MASK(wc)) )
358 sz = wbuf_size - WBUF_MASK(wc);
359 kcons_write_dom0(NULL, &wbuf[WBUF_MASK(wc)], sz);
360 wc += sz;
361 work_done = 1;
362 }
363 }
364 else
365 {
366 while ( x_char )
367 {
368 if (xencons_ring_send(&x_char, 1) == 1) {
369 x_char = 0;
370 work_done = 1;
371 }
372 }
374 while ( wc != wp )
375 {
376 int sent;
377 sz = wp - wc;
378 if ( sz > (wbuf_size - WBUF_MASK(wc)) )
379 sz = wbuf_size - WBUF_MASK(wc);
380 sent = xencons_ring_send(&wbuf[WBUF_MASK(wc)], sz);
381 if ( sent > 0 ) {
382 wc += sent;
383 work_done = 1;
384 }
385 }
386 }
388 if ( work_done && (xencons_tty != NULL) )
389 {
390 wake_up_interruptible(&xencons_tty->write_wait);
391 if ( (xencons_tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
392 (xencons_tty->ldisc.write_wakeup != NULL) )
393 (xencons_tty->ldisc.write_wakeup)(xencons_tty);
394 }
395 }
397 /* Privileged receive callback and transmit kicker. */
398 static irqreturn_t xencons_priv_interrupt(int irq, void *dev_id,
399 struct pt_regs *regs)
400 {
401 static char rbuf[16];
402 int i, l;
403 unsigned long flags;
405 spin_lock_irqsave(&xencons_lock, flags);
407 if ( xencons_tty != NULL )
408 {
409 /* Receive work. */
410 while ( (l = HYPERVISOR_console_io(CONSOLEIO_read, 16, rbuf)) > 0 )
411 for ( i = 0; i < l; i++ )
412 tty_insert_flip_char(xencons_tty, rbuf[i], 0);
413 if ( xencons_tty->flip.count != 0 )
414 tty_flip_buffer_push(xencons_tty);
415 }
417 /* Transmit work. */
418 __xencons_tx_flush();
420 spin_unlock_irqrestore(&xencons_lock, flags);
422 return IRQ_HANDLED;
423 }
425 static int xencons_write_room(struct tty_struct *tty)
426 {
427 return wbuf_size - (wp - wc);
428 }
430 static int xencons_chars_in_buffer(struct tty_struct *tty)
431 {
432 return wp - wc;
433 }
435 static void xencons_send_xchar(struct tty_struct *tty, char ch)
436 {
437 unsigned long flags;
439 if ( TTY_INDEX(tty) != 0 )
440 return;
442 spin_lock_irqsave(&xencons_lock, flags);
443 x_char = ch;
444 __xencons_tx_flush();
445 spin_unlock_irqrestore(&xencons_lock, flags);
446 }
448 static void xencons_throttle(struct tty_struct *tty)
449 {
450 if ( TTY_INDEX(tty) != 0 )
451 return;
453 if ( I_IXOFF(tty) )
454 xencons_send_xchar(tty, STOP_CHAR(tty));
455 }
457 static void xencons_unthrottle(struct tty_struct *tty)
458 {
459 if ( TTY_INDEX(tty) != 0 )
460 return;
462 if ( I_IXOFF(tty) )
463 {
464 if ( x_char != 0 )
465 x_char = 0;
466 else
467 xencons_send_xchar(tty, START_CHAR(tty));
468 }
469 }
471 static void xencons_flush_buffer(struct tty_struct *tty)
472 {
473 unsigned long flags;
475 if ( TTY_INDEX(tty) != 0 )
476 return;
478 spin_lock_irqsave(&xencons_lock, flags);
479 wc = wp = 0;
480 spin_unlock_irqrestore(&xencons_lock, flags);
481 }
483 static inline int __xencons_put_char(int ch)
484 {
485 char _ch = (char)ch;
486 if ( (wp - wc) == wbuf_size )
487 return 0;
488 wbuf[WBUF_MASK(wp++)] = _ch;
489 return 1;
490 }
492 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
493 static int xencons_write(
494 struct tty_struct *tty,
495 const unsigned char *buf,
496 int count)
497 {
498 int i;
499 unsigned long flags;
501 if ( TTY_INDEX(tty) != 0 )
502 return count;
504 spin_lock_irqsave(&xencons_lock, flags);
506 for ( i = 0; i < count; i++ )
507 if ( !__xencons_put_char(buf[i]) )
508 break;
510 if ( i != 0 )
511 __xencons_tx_flush();
513 spin_unlock_irqrestore(&xencons_lock, flags);
515 return i;
516 }
517 #else
518 static int xencons_write(
519 struct tty_struct *tty,
520 int from_user,
521 const u_char *buf,
522 int count)
523 {
524 int i;
525 unsigned long flags;
527 if ( from_user && verify_area(VERIFY_READ, buf, count) )
528 return -EINVAL;
530 if ( TTY_INDEX(tty) != 0 )
531 return count;
533 spin_lock_irqsave(&xencons_lock, flags);
535 for ( i = 0; i < count; i++ )
536 {
537 char ch;
538 if ( from_user )
539 __get_user(ch, buf + i);
540 else
541 ch = buf[i];
542 if ( !__xencons_put_char(ch) )
543 break;
544 }
546 if ( i != 0 )
547 __xencons_tx_flush();
549 spin_unlock_irqrestore(&xencons_lock, flags);
551 return i;
552 }
553 #endif
555 static void xencons_put_char(struct tty_struct *tty, u_char ch)
556 {
557 unsigned long flags;
559 if ( TTY_INDEX(tty) != 0 )
560 return;
562 spin_lock_irqsave(&xencons_lock, flags);
563 (void)__xencons_put_char(ch);
564 spin_unlock_irqrestore(&xencons_lock, flags);
565 }
567 static void xencons_flush_chars(struct tty_struct *tty)
568 {
569 unsigned long flags;
571 if ( TTY_INDEX(tty) != 0 )
572 return;
574 spin_lock_irqsave(&xencons_lock, flags);
575 __xencons_tx_flush();
576 spin_unlock_irqrestore(&xencons_lock, flags);
577 }
579 static void xencons_wait_until_sent(struct tty_struct *tty, int timeout)
580 {
581 unsigned long orig_jiffies = jiffies;
583 if ( TTY_INDEX(tty) != 0 )
584 return;
586 while ( DRV(tty->driver)->chars_in_buffer(tty) )
587 {
588 set_current_state(TASK_INTERRUPTIBLE);
589 schedule_timeout(1);
590 if ( signal_pending(current) )
591 break;
592 if ( (timeout != 0) && time_after(jiffies, orig_jiffies + timeout) )
593 break;
594 }
596 set_current_state(TASK_RUNNING);
597 }
599 static int xencons_open(struct tty_struct *tty, struct file *filp)
600 {
601 unsigned long flags;
603 if ( TTY_INDEX(tty) != 0 )
604 return 0;
606 spin_lock_irqsave(&xencons_lock, flags);
607 tty->driver_data = NULL;
608 if ( xencons_tty == NULL )
609 xencons_tty = tty;
610 __xencons_tx_flush();
611 spin_unlock_irqrestore(&xencons_lock, flags);
613 return 0;
614 }
616 static void xencons_close(struct tty_struct *tty, struct file *filp)
617 {
618 unsigned long flags;
620 if ( TTY_INDEX(tty) != 0 )
621 return;
623 if ( tty->count == 1 )
624 {
625 tty->closing = 1;
626 tty_wait_until_sent(tty, 0);
627 if ( DRV(tty->driver)->flush_buffer != NULL )
628 DRV(tty->driver)->flush_buffer(tty);
629 if ( tty->ldisc.flush_buffer != NULL )
630 tty->ldisc.flush_buffer(tty);
631 tty->closing = 0;
632 spin_lock_irqsave(&xencons_lock, flags);
633 xencons_tty = NULL;
634 spin_unlock_irqrestore(&xencons_lock, flags);
635 }
636 }
638 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
639 static struct tty_operations xencons_ops = {
640 .open = xencons_open,
641 .close = xencons_close,
642 .write = xencons_write,
643 .write_room = xencons_write_room,
644 .put_char = xencons_put_char,
645 .flush_chars = xencons_flush_chars,
646 .chars_in_buffer = xencons_chars_in_buffer,
647 .send_xchar = xencons_send_xchar,
648 .flush_buffer = xencons_flush_buffer,
649 .throttle = xencons_throttle,
650 .unthrottle = xencons_unthrottle,
651 .wait_until_sent = xencons_wait_until_sent,
652 };
654 #ifdef CONFIG_XEN_PRIVILEGED_GUEST
655 static const char *xennullcon_startup(void)
656 {
657 return NULL;
658 }
660 static int xennullcon_dummy(void)
661 {
662 return 0;
663 }
665 #define DUMMY (void *)xennullcon_dummy
667 /*
668 * The console `switch' structure for the dummy console
669 *
670 * Most of the operations are dummies.
671 */
673 const struct consw xennull_con = {
674 .owner = THIS_MODULE,
675 .con_startup = xennullcon_startup,
676 .con_init = DUMMY,
677 .con_deinit = DUMMY,
678 .con_clear = DUMMY,
679 .con_putc = DUMMY,
680 .con_putcs = DUMMY,
681 .con_cursor = DUMMY,
682 .con_scroll = DUMMY,
683 .con_bmove = DUMMY,
684 .con_switch = DUMMY,
685 .con_blank = DUMMY,
686 .con_font_set = DUMMY,
687 .con_font_get = DUMMY,
688 .con_font_default = DUMMY,
689 .con_font_copy = DUMMY,
690 .con_set_palette = DUMMY,
691 .con_scrolldelta = DUMMY,
692 };
693 #endif
694 #endif
696 static int __init xencons_init(void)
697 {
698 int rc;
700 if ( xc_mode == XC_OFF )
701 return 0;
703 xencons_ring_init();
705 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
706 xencons_driver = alloc_tty_driver((xc_mode == XC_SERIAL) ?
707 1 : MAX_NR_CONSOLES);
708 if ( xencons_driver == NULL )
709 return -ENOMEM;
710 #else
711 memset(&xencons_driver, 0, sizeof(struct tty_driver));
712 xencons_driver.magic = TTY_DRIVER_MAGIC;
713 xencons_driver.refcount = &xencons_refcount;
714 xencons_driver.table = xencons_table;
715 xencons_driver.num = (xc_mode == XC_SERIAL) ? 1 : MAX_NR_CONSOLES;
716 #endif
718 DRV(xencons_driver)->major = TTY_MAJOR;
719 DRV(xencons_driver)->type = TTY_DRIVER_TYPE_SERIAL;
720 DRV(xencons_driver)->subtype = SERIAL_TYPE_NORMAL;
721 DRV(xencons_driver)->init_termios = tty_std_termios;
722 DRV(xencons_driver)->flags =
723 TTY_DRIVER_REAL_RAW | TTY_DRIVER_RESET_TERMIOS | TTY_DRIVER_NO_DEVFS;
724 DRV(xencons_driver)->termios = xencons_termios;
725 DRV(xencons_driver)->termios_locked = xencons_termios_locked;
727 if ( xc_mode == XC_SERIAL )
728 {
729 DRV(xencons_driver)->name = "ttyS";
730 DRV(xencons_driver)->minor_start = 64 + xc_num;
731 DRV(xencons_driver)->name_base = 0 + xc_num;
732 }
733 else
734 {
735 DRV(xencons_driver)->name = "tty";
736 DRV(xencons_driver)->minor_start = xc_num;
737 DRV(xencons_driver)->name_base = xc_num;
738 }
740 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
741 tty_set_operations(xencons_driver, &xencons_ops);
742 #else
743 xencons_driver.open = xencons_open;
744 xencons_driver.close = xencons_close;
745 xencons_driver.write = xencons_write;
746 xencons_driver.write_room = xencons_write_room;
747 xencons_driver.put_char = xencons_put_char;
748 xencons_driver.flush_chars = xencons_flush_chars;
749 xencons_driver.chars_in_buffer = xencons_chars_in_buffer;
750 xencons_driver.send_xchar = xencons_send_xchar;
751 xencons_driver.flush_buffer = xencons_flush_buffer;
752 xencons_driver.throttle = xencons_throttle;
753 xencons_driver.unthrottle = xencons_unthrottle;
754 xencons_driver.wait_until_sent = xencons_wait_until_sent;
755 #endif
757 if ( (rc = tty_register_driver(DRV(xencons_driver))) != 0 )
758 {
759 printk("WARNING: Failed to register Xen virtual "
760 "console driver as '%s%d'\n",
761 DRV(xencons_driver)->name, DRV(xencons_driver)->name_base);
762 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
763 put_tty_driver(xencons_driver);
764 xencons_driver = NULL;
765 #endif
766 return rc;
767 }
769 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
770 tty_register_device(xencons_driver, 0, NULL);
771 #endif
773 if ( xen_start_info->flags & SIF_INITDOMAIN )
774 {
775 xencons_priv_irq = bind_virq_to_irq(VIRQ_CONSOLE);
776 (void)request_irq(xencons_priv_irq,
777 xencons_priv_interrupt, 0, "console", NULL);
778 }
779 else
780 {
782 xencons_ring_register_receiver(xencons_rx);
783 }
785 printk("Xen virtual console successfully installed as %s%d\n",
786 DRV(xencons_driver)->name,
787 DRV(xencons_driver)->name_base );
789 return 0;
790 }
792 module_init(xencons_init);