direct-io.hg

view linux-2.6-xen-sparse/drivers/xen/console/console.c @ 7547:03612b7f69d5

Don't use XendRoot.get_vif_bridge to provide a default bridge -- instead, pass
no bridge parameter and let the vif-bridge script find one for itself.

Signed-off-by: Ewan Mellor <ewan@xensource.com>
author emellor@leeni.uk.xensource.com
date Sun Oct 30 13:45:06 2005 +0100 (2005-10-30)
parents 5a97ee0633e8
children 5a4893a537ca
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/xen.h>
53 #include <asm-xen/xen-public/event_channel.h>
54 #include <asm/hypervisor.h>
55 #include <asm-xen/evtchn.h>
57 #include "xencons_ring.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 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
131 static struct tty_driver *xencons_driver;
132 #else
133 static struct tty_driver xencons_driver;
134 #endif
137 /******************** Kernel console driver ********************************/
139 static void kcons_write(
140 struct console *c, const char *s, unsigned int count)
141 {
142 int i;
143 unsigned long flags;
145 spin_lock_irqsave(&xencons_lock, flags);
147 for (i = 0; i < count; i++) {
148 if ((wp - wc) >= (wbuf_size - 1))
149 break;
150 if ((wbuf[WBUF_MASK(wp++)] = s[i]) == '\n')
151 wbuf[WBUF_MASK(wp++)] = '\r';
152 }
154 __xencons_tx_flush();
156 spin_unlock_irqrestore(&xencons_lock, flags);
157 }
159 static void kcons_write_dom0(
160 struct console *c, const char *s, unsigned int count)
161 {
162 int rc;
164 while ((count > 0) &&
165 ((rc = HYPERVISOR_console_io(
166 CONSOLEIO_write, count, (char *)s)) > 0)) {
167 count -= rc;
168 s += rc;
169 }
170 }
172 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
173 static struct tty_driver *kcons_device(struct console *c, int *index)
174 {
175 *index = c->index;
176 return xencons_driver;
177 }
178 #else
179 static kdev_t kcons_device(struct console *c)
180 {
181 return MKDEV(TTY_MAJOR, (xc_mode == XC_SERIAL) ? 64 : 1);
182 }
183 #endif
185 static struct console kcons_info = {
186 .device = kcons_device,
187 .flags = CON_PRINTBUFFER,
188 .index = -1,
189 };
191 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
192 #define __RETCODE 0
193 static int __init xen_console_init(void)
194 #else
195 #define __RETCODE
196 void xen_console_init(void)
197 #endif
198 {
199 if (xen_start_info->flags & SIF_INITDOMAIN) {
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 } else {
208 if (xc_mode == XC_DEFAULT)
209 xc_mode = XC_TTY;
210 kcons_info.write = kcons_write;
211 }
213 switch (xc_mode) {
214 case XC_SERIAL:
215 strcpy(kcons_info.name, "ttyS");
216 if (xc_num == -1)
217 xc_num = 0;
218 break;
220 case XC_TTY:
221 strcpy(kcons_info.name, "tty");
222 if (xc_num == -1)
223 xc_num = 1;
224 break;
226 default:
227 return __RETCODE;
228 }
230 wbuf = alloc_bootmem(wbuf_size);
232 register_console(&kcons_info);
234 return __RETCODE;
235 }
236 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
237 console_initcall(xen_console_init);
238 #endif
240 /*** Useful function for console debugging -- goes straight to Xen. ***/
241 #ifdef CONFIG_XEN_PRIVILEGED_GUEST
242 asmlinkage int xprintk(const char *fmt, ...)
243 #else
244 asmlinkage int xprintk(const char *fmt, ...)
245 #endif
246 {
247 va_list args;
248 int printk_len;
249 static char printk_buf[1024];
251 /* Emit the output into the temporary buffer */
252 va_start(args, fmt);
253 printk_len = vsnprintf(printk_buf, sizeof(printk_buf), fmt, args);
254 va_end(args);
256 /* Send the processed output directly to Xen. */
257 kcons_write_dom0(NULL, printk_buf, printk_len);
259 return 0;
260 }
262 /*** Forcibly flush console data before dying. ***/
263 void xencons_force_flush(void)
264 {
265 int sz;
267 /* Emergency console is synchronous, so there's nothing to flush. */
268 if (xen_start_info->flags & SIF_INITDOMAIN)
269 return;
272 /* Spin until console data is flushed through to the daemon. */
273 while (wc != wp) {
274 int sent = 0;
275 if ((sz = wp - wc) == 0)
276 continue;
277 sent = xencons_ring_send(&wbuf[WBUF_MASK(wc)], sz);
278 if (sent > 0)
279 wc += sent;
280 }
281 }
284 /******************** User-space console driver (/dev/console) ************/
286 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
287 #define DRV(_d) (_d)
288 #define TTY_INDEX(_tty) ((_tty)->index)
289 #else
290 static int xencons_refcount;
291 static struct tty_struct *xencons_table[MAX_NR_CONSOLES];
292 #define DRV(_d) (&(_d))
293 #define TTY_INDEX(_tty) (MINOR((_tty)->device) - xencons_driver.minor_start)
294 #endif
296 static struct termios *xencons_termios[MAX_NR_CONSOLES];
297 static struct termios *xencons_termios_locked[MAX_NR_CONSOLES];
298 static struct tty_struct *xencons_tty;
299 static int xencons_priv_irq;
300 static char x_char;
302 /* Non-privileged receive callback. */
303 static void xencons_rx(char *buf, unsigned len, struct pt_regs *regs)
304 {
305 int i;
306 unsigned long flags;
308 spin_lock_irqsave(&xencons_lock, flags);
309 if (xencons_tty == NULL)
310 goto out;
312 for (i = 0; i < len; i++) {
313 #ifdef CONFIG_MAGIC_SYSRQ
314 if (sysrq_enabled) {
315 if (buf[i] == '\x0f') { /* ^O */
316 sysrq_requested = jiffies;
317 continue; /* don't print the sysrq key */
318 } else if (sysrq_requested) {
319 unsigned long sysrq_timeout =
320 sysrq_requested + HZ*2;
321 sysrq_requested = 0;
322 if (time_before(jiffies, sysrq_timeout)) {
323 spin_unlock_irqrestore(
324 &xencons_lock, flags);
325 handle_sysrq(
326 buf[i], regs, xencons_tty);
327 spin_lock_irqsave(
328 &xencons_lock, flags);
329 continue;
330 }
331 }
332 }
333 #endif
334 tty_insert_flip_char(xencons_tty, buf[i], 0);
335 }
336 tty_flip_buffer_push(xencons_tty);
338 out:
339 spin_unlock_irqrestore(&xencons_lock, flags);
340 }
342 /* Privileged and non-privileged transmit worker. */
343 static void __xencons_tx_flush(void)
344 {
345 int sz, work_done = 0;
347 if (xen_start_info->flags & SIF_INITDOMAIN) {
348 if (x_char) {
349 kcons_write_dom0(NULL, &x_char, 1);
350 x_char = 0;
351 work_done = 1;
352 }
354 while (wc != wp) {
355 sz = wp - wc;
356 if (sz > (wbuf_size - WBUF_MASK(wc)))
357 sz = wbuf_size - WBUF_MASK(wc);
358 kcons_write_dom0(NULL, &wbuf[WBUF_MASK(wc)], sz);
359 wc += sz;
360 work_done = 1;
361 }
362 } else {
363 while (x_char) {
364 if (xencons_ring_send(&x_char, 1) == 1) {
365 x_char = 0;
366 work_done = 1;
367 }
368 }
370 while (wc != wp) {
371 int sent;
372 sz = wp - wc;
373 if (sz > (wbuf_size - WBUF_MASK(wc)))
374 sz = wbuf_size - WBUF_MASK(wc);
375 sent = xencons_ring_send(&wbuf[WBUF_MASK(wc)], sz);
376 if (sent > 0) {
377 wc += sent;
378 work_done = 1;
379 }
380 }
381 }
383 if (work_done && (xencons_tty != NULL))
384 {
385 wake_up_interruptible(&xencons_tty->write_wait);
386 if ((xencons_tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
387 (xencons_tty->ldisc.write_wakeup != NULL))
388 (xencons_tty->ldisc.write_wakeup)(xencons_tty);
389 }
390 }
392 /* Privileged receive callback and transmit kicker. */
393 static irqreturn_t xencons_priv_interrupt(int irq, void *dev_id,
394 struct pt_regs *regs)
395 {
396 static char rbuf[16];
397 int i, l;
398 unsigned long flags;
400 spin_lock_irqsave(&xencons_lock, flags);
402 if (xencons_tty != NULL)
403 {
404 /* Receive work. */
405 while ((l = HYPERVISOR_console_io(
406 CONSOLEIO_read, 16, rbuf)) > 0)
407 for (i = 0; i < l; i++)
408 tty_insert_flip_char(xencons_tty, rbuf[i], 0);
409 if (xencons_tty->flip.count != 0)
410 tty_flip_buffer_push(xencons_tty);
411 }
413 /* Transmit work. */
414 __xencons_tx_flush();
416 spin_unlock_irqrestore(&xencons_lock, flags);
418 return IRQ_HANDLED;
419 }
421 static int xencons_write_room(struct tty_struct *tty)
422 {
423 return wbuf_size - (wp - wc);
424 }
426 static int xencons_chars_in_buffer(struct tty_struct *tty)
427 {
428 return wp - wc;
429 }
431 static void xencons_send_xchar(struct tty_struct *tty, char ch)
432 {
433 unsigned long flags;
435 if (TTY_INDEX(tty) != 0)
436 return;
438 spin_lock_irqsave(&xencons_lock, flags);
439 x_char = ch;
440 __xencons_tx_flush();
441 spin_unlock_irqrestore(&xencons_lock, flags);
442 }
444 static void xencons_throttle(struct tty_struct *tty)
445 {
446 if (TTY_INDEX(tty) != 0)
447 return;
449 if (I_IXOFF(tty))
450 xencons_send_xchar(tty, STOP_CHAR(tty));
451 }
453 static void xencons_unthrottle(struct tty_struct *tty)
454 {
455 if (TTY_INDEX(tty) != 0)
456 return;
458 if (I_IXOFF(tty)) {
459 if (x_char != 0)
460 x_char = 0;
461 else
462 xencons_send_xchar(tty, START_CHAR(tty));
463 }
464 }
466 static void xencons_flush_buffer(struct tty_struct *tty)
467 {
468 unsigned long flags;
470 if (TTY_INDEX(tty) != 0)
471 return;
473 spin_lock_irqsave(&xencons_lock, flags);
474 wc = wp = 0;
475 spin_unlock_irqrestore(&xencons_lock, flags);
476 }
478 static inline int __xencons_put_char(int ch)
479 {
480 char _ch = (char)ch;
481 if ((wp - wc) == wbuf_size)
482 return 0;
483 wbuf[WBUF_MASK(wp++)] = _ch;
484 return 1;
485 }
487 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
488 static int xencons_write(
489 struct tty_struct *tty,
490 const unsigned char *buf,
491 int count)
492 {
493 int i;
494 unsigned long flags;
496 if (TTY_INDEX(tty) != 0)
497 return count;
499 spin_lock_irqsave(&xencons_lock, flags);
501 for (i = 0; i < count; i++)
502 if (!__xencons_put_char(buf[i]))
503 break;
505 if (i != 0)
506 __xencons_tx_flush();
508 spin_unlock_irqrestore(&xencons_lock, flags);
510 return i;
511 }
512 #else
513 static int xencons_write(
514 struct tty_struct *tty,
515 int from_user,
516 const u_char *buf,
517 int count)
518 {
519 int i;
520 unsigned long flags;
522 if (from_user && verify_area(VERIFY_READ, buf, count))
523 return -EINVAL;
525 if (TTY_INDEX(tty) != 0)
526 return count;
528 spin_lock_irqsave(&xencons_lock, flags);
530 for (i = 0; i < count; i++) {
531 char ch;
532 if (from_user)
533 __get_user(ch, buf + i);
534 else
535 ch = buf[i];
536 if (!__xencons_put_char(ch))
537 break;
538 }
540 if (i != 0)
541 __xencons_tx_flush();
543 spin_unlock_irqrestore(&xencons_lock, flags);
545 return i;
546 }
547 #endif
549 static void xencons_put_char(struct tty_struct *tty, u_char ch)
550 {
551 unsigned long flags;
553 if (TTY_INDEX(tty) != 0)
554 return;
556 spin_lock_irqsave(&xencons_lock, flags);
557 (void)__xencons_put_char(ch);
558 spin_unlock_irqrestore(&xencons_lock, flags);
559 }
561 static void xencons_flush_chars(struct tty_struct *tty)
562 {
563 unsigned long flags;
565 if (TTY_INDEX(tty) != 0)
566 return;
568 spin_lock_irqsave(&xencons_lock, flags);
569 __xencons_tx_flush();
570 spin_unlock_irqrestore(&xencons_lock, flags);
571 }
573 static void xencons_wait_until_sent(struct tty_struct *tty, int timeout)
574 {
575 unsigned long orig_jiffies = jiffies;
577 if (TTY_INDEX(tty) != 0)
578 return;
580 while (DRV(tty->driver)->chars_in_buffer(tty))
581 {
582 set_current_state(TASK_INTERRUPTIBLE);
583 schedule_timeout(1);
584 if (signal_pending(current))
585 break;
586 if ( (timeout != 0) &&
587 time_after(jiffies, orig_jiffies + timeout) )
588 break;
589 }
591 set_current_state(TASK_RUNNING);
592 }
594 static int xencons_open(struct tty_struct *tty, struct file *filp)
595 {
596 unsigned long flags;
598 if (TTY_INDEX(tty) != 0)
599 return 0;
601 spin_lock_irqsave(&xencons_lock, flags);
602 tty->driver_data = NULL;
603 if (xencons_tty == NULL)
604 xencons_tty = tty;
605 __xencons_tx_flush();
606 spin_unlock_irqrestore(&xencons_lock, flags);
608 return 0;
609 }
611 static void xencons_close(struct tty_struct *tty, struct file *filp)
612 {
613 unsigned long flags;
615 if (TTY_INDEX(tty) != 0)
616 return;
618 if (tty->count == 1) {
619 tty->closing = 1;
620 tty_wait_until_sent(tty, 0);
621 if (DRV(tty->driver)->flush_buffer != NULL)
622 DRV(tty->driver)->flush_buffer(tty);
623 if (tty->ldisc.flush_buffer != NULL)
624 tty->ldisc.flush_buffer(tty);
625 tty->closing = 0;
626 spin_lock_irqsave(&xencons_lock, flags);
627 xencons_tty = NULL;
628 spin_unlock_irqrestore(&xencons_lock, flags);
629 }
630 }
632 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
633 static struct tty_operations xencons_ops = {
634 .open = xencons_open,
635 .close = xencons_close,
636 .write = xencons_write,
637 .write_room = xencons_write_room,
638 .put_char = xencons_put_char,
639 .flush_chars = xencons_flush_chars,
640 .chars_in_buffer = xencons_chars_in_buffer,
641 .send_xchar = xencons_send_xchar,
642 .flush_buffer = xencons_flush_buffer,
643 .throttle = xencons_throttle,
644 .unthrottle = xencons_unthrottle,
645 .wait_until_sent = xencons_wait_until_sent,
646 };
648 #ifdef CONFIG_XEN_PRIVILEGED_GUEST
649 static const char *xennullcon_startup(void)
650 {
651 return NULL;
652 }
654 static int xennullcon_dummy(void)
655 {
656 return 0;
657 }
659 #define DUMMY (void *)xennullcon_dummy
661 /*
662 * The console `switch' structure for the dummy console
663 *
664 * Most of the operations are dummies.
665 */
667 const struct consw xennull_con = {
668 .owner = THIS_MODULE,
669 .con_startup = xennullcon_startup,
670 .con_init = DUMMY,
671 .con_deinit = DUMMY,
672 .con_clear = DUMMY,
673 .con_putc = DUMMY,
674 .con_putcs = DUMMY,
675 .con_cursor = DUMMY,
676 .con_scroll = DUMMY,
677 .con_bmove = DUMMY,
678 .con_switch = DUMMY,
679 .con_blank = DUMMY,
680 .con_font_set = DUMMY,
681 .con_font_get = DUMMY,
682 .con_font_default = DUMMY,
683 .con_font_copy = DUMMY,
684 .con_set_palette = DUMMY,
685 .con_scrolldelta = DUMMY,
686 };
687 #endif
688 #endif
690 static int __init xencons_init(void)
691 {
692 int rc;
694 if (xen_init() < 0)
695 return -ENODEV;
697 if (xc_mode == XC_OFF)
698 return 0;
700 xencons_ring_init();
702 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
703 xencons_driver = alloc_tty_driver((xc_mode == XC_SERIAL) ?
704 1 : MAX_NR_CONSOLES);
705 if (xencons_driver == NULL)
706 return -ENOMEM;
707 #else
708 memset(&xencons_driver, 0, sizeof(struct tty_driver));
709 xencons_driver.magic = TTY_DRIVER_MAGIC;
710 xencons_driver.refcount = &xencons_refcount;
711 xencons_driver.table = xencons_table;
712 xencons_driver.num =
713 (xc_mode == XC_SERIAL) ? 1 : MAX_NR_CONSOLES;
714 #endif
716 DRV(xencons_driver)->major = TTY_MAJOR;
717 DRV(xencons_driver)->type = TTY_DRIVER_TYPE_SERIAL;
718 DRV(xencons_driver)->subtype = SERIAL_TYPE_NORMAL;
719 DRV(xencons_driver)->init_termios = tty_std_termios;
720 DRV(xencons_driver)->flags =
721 TTY_DRIVER_REAL_RAW |
722 TTY_DRIVER_RESET_TERMIOS |
723 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 } else {
733 DRV(xencons_driver)->name = "tty";
734 DRV(xencons_driver)->minor_start = xc_num;
735 DRV(xencons_driver)->name_base = xc_num;
736 }
738 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
739 tty_set_operations(xencons_driver, &xencons_ops);
740 #else
741 xencons_driver.open = xencons_open;
742 xencons_driver.close = xencons_close;
743 xencons_driver.write = xencons_write;
744 xencons_driver.write_room = xencons_write_room;
745 xencons_driver.put_char = xencons_put_char;
746 xencons_driver.flush_chars = xencons_flush_chars;
747 xencons_driver.chars_in_buffer = xencons_chars_in_buffer;
748 xencons_driver.send_xchar = xencons_send_xchar;
749 xencons_driver.flush_buffer = xencons_flush_buffer;
750 xencons_driver.throttle = xencons_throttle;
751 xencons_driver.unthrottle = xencons_unthrottle;
752 xencons_driver.wait_until_sent = xencons_wait_until_sent;
753 #endif
755 if ((rc = tty_register_driver(DRV(xencons_driver))) != 0) {
756 printk("WARNING: Failed to register Xen virtual "
757 "console driver as '%s%d'\n",
758 DRV(xencons_driver)->name, DRV(xencons_driver)->name_base);
759 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
760 put_tty_driver(xencons_driver);
761 xencons_driver = NULL;
762 #endif
763 return rc;
764 }
766 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
767 tty_register_device(xencons_driver, 0, NULL);
768 #endif
770 if (xen_start_info->flags & SIF_INITDOMAIN) {
771 xencons_priv_irq = bind_virq_to_irq(VIRQ_CONSOLE, 0);
772 (void)request_irq(xencons_priv_irq,
773 xencons_priv_interrupt, 0, "console", NULL);
774 } else {
775 xencons_ring_register_receiver(xencons_rx);
776 }
778 printk("Xen virtual console successfully installed as %s%d\n",
779 DRV(xencons_driver)->name,
780 DRV(xencons_driver)->name_base );
782 return 0;
783 }
785 module_init(xencons_init);
787 /*
788 * Local variables:
789 * c-file-style: "linux"
790 * indent-tabs-mode: t
791 * c-indent-level: 8
792 * c-basic-offset: 8
793 * tab-width: 8
794 * End:
795 */