debuggers.hg

view linux-2.6.10-xen-sparse/drivers/xen/console/console.c @ 3522:610068179f96

bitkeeper revision 1.1159.212.24 (41f26e32I9xLcTR7BS9n8xcvRPkmCQ)

Merge ssh://srg//auto/groups/xeno/BK/xeno.bk
into equilibrium.research:/home/irchomes/mwilli2/src/xen-3.0-devel.bk
author mwilli2@equilibrium.research
date Sat Jan 22 15:16:02 2005 +0000 (2005-01-22)
parents 39a7a74fd6f9 50402a6cc3d8
children 0a4b76b6b5a0
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 <asm/io.h>
48 #include <asm/irq.h>
49 #include <asm/uaccess.h>
50 #include <asm-xen/xen-public/event_channel.h>
51 #include <asm-xen/hypervisor.h>
52 #include <asm-xen/evtchn.h>
53 #include <asm-xen/ctrl_if.h>
55 /*
56 * Modes:
57 * 'xencons=off' [XC_OFF]: Console is disabled.
58 * 'xencons=tty' [XC_TTY]: Console attached to '/dev/tty[0-9]+'.
59 * 'xencons=ttyS' [XC_SERIAL]: Console attached to '/dev/ttyS[0-9]+'.
60 * [XC_DEFAULT]: DOM0 -> XC_SERIAL ; all others -> XC_TTY.
61 *
62 * NB. In mode XC_TTY, we create dummy consoles for tty2-63. This suppresses
63 * warnings from standard distro startup scripts.
64 */
65 static enum { XC_OFF, XC_DEFAULT, XC_TTY, XC_SERIAL } xc_mode = XC_DEFAULT;
67 static int __init xencons_setup(char *str)
68 {
69 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
70 if (str[0] == '=')
71 str++;
72 #endif
73 if ( !strcmp(str, "tty") )
74 xc_mode = XC_TTY;
75 else if ( !strcmp(str, "ttyS") )
76 xc_mode = XC_SERIAL;
77 else if ( !strcmp(str, "off") )
78 xc_mode = XC_OFF;
79 return 1;
80 }
81 __setup("xencons", xencons_setup);
83 /* The kernel and user-land drivers share a common transmit buffer. */
84 #define WBUF_SIZE 4096
85 #define WBUF_MASK(_i) ((_i)&(WBUF_SIZE-1))
86 static char wbuf[WBUF_SIZE];
87 static unsigned int wc, wp; /* write_cons, write_prod */
89 /* This lock protects accesses to the common transmit buffer. */
90 static spinlock_t xencons_lock = SPIN_LOCK_UNLOCKED;
92 /* Common transmit-kick routine. */
93 static void __xencons_tx_flush(void);
95 /* This task is used to defer sending console data until there is space. */
96 static void xencons_tx_flush_task_routine(void *data);
98 static DECLARE_TQUEUE(xencons_tx_flush_task,
99 xencons_tx_flush_task_routine,
100 NULL);
102 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
103 static struct tty_driver *xencons_driver;
104 #else
105 static struct tty_driver xencons_driver;
106 #endif
109 /******************** Kernel console driver ********************************/
111 static void kcons_write(
112 struct console *c, const char *s, unsigned int count)
113 {
114 int i;
115 unsigned long flags;
117 spin_lock_irqsave(&xencons_lock, flags);
119 for ( i = 0; i < count; i++ )
120 {
121 if ( (wp - wc) >= (WBUF_SIZE - 1) )
122 break;
123 if ( (wbuf[WBUF_MASK(wp++)] = s[i]) == '\n' )
124 wbuf[WBUF_MASK(wp++)] = '\r';
125 }
127 __xencons_tx_flush();
129 spin_unlock_irqrestore(&xencons_lock, flags);
130 }
132 static void kcons_write_dom0(
133 struct console *c, const char *s, unsigned int count)
134 {
135 int rc;
137 while ( count > 0 )
138 {
139 if ( (rc = HYPERVISOR_console_io(CONSOLEIO_write,
140 count, (char *)s)) > 0 )
141 {
142 count -= rc;
143 s += rc;
144 }
145 else
146 break;
147 }
148 }
150 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
151 static struct tty_driver *kcons_device(struct console *c, int *index)
152 {
153 *index = c->index;
154 return xencons_driver;
155 }
156 #else
157 static kdev_t kcons_device(struct console *c)
158 {
159 return MKDEV(TTY_MAJOR, (xc_mode == XC_SERIAL) ? 64 : 1);
160 }
161 #endif
163 static struct console kcons_info = {
164 device: kcons_device,
165 flags: CON_PRINTBUFFER,
166 index: -1
167 };
169 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
170 #define __RETCODE 0
171 static int __init xen_console_init(void)
172 #else
173 #define __RETCODE
174 void xen_console_init(void)
175 #endif
176 {
177 if ( xen_start_info.flags & SIF_INITDOMAIN )
178 {
179 if ( xc_mode == XC_DEFAULT )
180 xc_mode = XC_SERIAL;
181 kcons_info.write = kcons_write_dom0;
182 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
183 if ( xc_mode == XC_SERIAL )
184 kcons_info.flags |= CON_ENABLED;
185 #endif
186 }
187 else
188 {
189 if ( xc_mode == XC_DEFAULT )
190 xc_mode = XC_TTY;
191 kcons_info.write = kcons_write;
192 }
194 if ( xc_mode == XC_OFF )
195 return __RETCODE;
197 if ( xc_mode == XC_SERIAL )
198 strcpy(kcons_info.name, "ttyS");
199 else
200 strcpy(kcons_info.name, "tty");
202 register_console(&kcons_info);
203 return __RETCODE;
204 }
205 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
206 console_initcall(xen_console_init);
207 #endif
209 /*** Useful function for console debugging -- goes straight to Xen. ***/
210 asmlinkage int xprintk(const char *fmt, ...)
211 {
212 va_list args;
213 int printk_len;
214 static char printk_buf[1024];
216 /* Emit the output into the temporary buffer */
217 va_start(args, fmt);
218 printk_len = vsnprintf(printk_buf, sizeof(printk_buf), fmt, args);
219 va_end(args);
221 /* Send the processed output directly to Xen. */
222 kcons_write_dom0(NULL, printk_buf, printk_len);
224 return 0;
225 }
227 /*** Forcibly flush console data before dying. ***/
228 void xencons_force_flush(void)
229 {
230 ctrl_msg_t msg;
231 int sz;
233 /* Emergency console is synchronous, so there's nothing to flush. */
234 if ( xen_start_info.flags & SIF_INITDOMAIN )
235 return;
237 /*
238 * We use dangerous control-interface functions that require a quiescent
239 * system and no interrupts. Try to ensure this with a global cli().
240 */
241 local_irq_disable(); /* XXXsmp */
243 /* Spin until console data is flushed through to the domain controller. */
244 while ( (wc != wp) && !ctrl_if_transmitter_empty() )
245 {
246 /* Interrupts are disabled -- we must manually reap responses. */
247 ctrl_if_discard_responses();
249 if ( (sz = wp - wc) == 0 )
250 continue;
251 if ( sz > sizeof(msg.msg) )
252 sz = sizeof(msg.msg);
253 if ( sz > (WBUF_SIZE - WBUF_MASK(wc)) )
254 sz = WBUF_SIZE - WBUF_MASK(wc);
256 msg.type = CMSG_CONSOLE;
257 msg.subtype = CMSG_CONSOLE_DATA;
258 msg.length = sz;
259 memcpy(msg.msg, &wbuf[WBUF_MASK(wc)], sz);
261 if ( ctrl_if_send_message_noblock(&msg, NULL, 0) == 0 )
262 wc += sz;
263 }
264 }
267 /******************** User-space console driver (/dev/console) ************/
269 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
270 #define DRV(_d) (_d)
271 #define TTY_INDEX(_tty) ((_tty)->index)
272 #else
273 static int xencons_refcount;
274 static struct tty_struct *xencons_table[MAX_NR_CONSOLES];
275 #define DRV(_d) (&(_d))
276 #define TTY_INDEX(_tty) (MINOR((_tty)->device) - xencons_driver.minor_start)
277 #endif
279 static struct termios *xencons_termios[MAX_NR_CONSOLES];
280 static struct termios *xencons_termios_locked[MAX_NR_CONSOLES];
281 static struct tty_struct *xencons_tty;
282 static int xencons_priv_irq;
283 static char x_char;
285 /* Non-privileged receive callback. */
286 static void xencons_rx(ctrl_msg_t *msg, unsigned long id)
287 {
288 int i;
289 unsigned long flags;
291 spin_lock_irqsave(&xencons_lock, flags);
292 if ( xencons_tty != NULL )
293 {
294 for ( i = 0; i < msg->length; i++ )
295 tty_insert_flip_char(xencons_tty, msg->msg[i], 0);
296 tty_flip_buffer_push(xencons_tty);
297 }
298 spin_unlock_irqrestore(&xencons_lock, flags);
300 msg->length = 0;
301 ctrl_if_send_response(msg);
302 }
304 /* Privileged and non-privileged transmit worker. */
305 static void __xencons_tx_flush(void)
306 {
307 int sz, work_done = 0;
308 ctrl_msg_t msg;
310 if ( xen_start_info.flags & SIF_INITDOMAIN )
311 {
312 if ( x_char )
313 {
314 kcons_write_dom0(NULL, &x_char, 1);
315 x_char = 0;
316 work_done = 1;
317 }
319 while ( wc != wp )
320 {
321 sz = wp - wc;
322 if ( sz > (WBUF_SIZE - WBUF_MASK(wc)) )
323 sz = WBUF_SIZE - WBUF_MASK(wc);
324 kcons_write_dom0(NULL, &wbuf[WBUF_MASK(wc)], sz);
325 wc += sz;
326 work_done = 1;
327 }
328 }
329 else
330 {
331 while ( x_char )
332 {
333 msg.type = CMSG_CONSOLE;
334 msg.subtype = CMSG_CONSOLE_DATA;
335 msg.length = 1;
336 msg.msg[0] = x_char;
338 if ( ctrl_if_send_message_noblock(&msg, NULL, 0) == 0 )
339 x_char = 0;
340 else if ( ctrl_if_enqueue_space_callback(&xencons_tx_flush_task) )
341 break;
343 work_done = 1;
344 }
346 while ( wc != wp )
347 {
348 sz = wp - wc;
349 if ( sz > sizeof(msg.msg) )
350 sz = sizeof(msg.msg);
351 if ( sz > (WBUF_SIZE - WBUF_MASK(wc)) )
352 sz = WBUF_SIZE - WBUF_MASK(wc);
354 msg.type = CMSG_CONSOLE;
355 msg.subtype = CMSG_CONSOLE_DATA;
356 msg.length = sz;
357 memcpy(msg.msg, &wbuf[WBUF_MASK(wc)], sz);
359 if ( ctrl_if_send_message_noblock(&msg, NULL, 0) == 0 )
360 wc += sz;
361 else if ( ctrl_if_enqueue_space_callback(&xencons_tx_flush_task) )
362 break;
364 work_done = 1;
365 }
366 }
368 if ( work_done && (xencons_tty != NULL) )
369 {
370 wake_up_interruptible(&xencons_tty->write_wait);
371 if ( (xencons_tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
372 (xencons_tty->ldisc.write_wakeup != NULL) )
373 (xencons_tty->ldisc.write_wakeup)(xencons_tty);
374 }
375 }
377 /* Non-privileged transmit kicker. */
378 static void xencons_tx_flush_task_routine(void *data)
379 {
380 unsigned long flags;
381 spin_lock_irqsave(&xencons_lock, flags);
382 __xencons_tx_flush();
383 spin_unlock_irqrestore(&xencons_lock, flags);
384 }
386 /* Privileged receive callback and transmit kicker. */
387 static irqreturn_t xencons_priv_interrupt(int irq, void *dev_id,
388 struct pt_regs *regs)
389 {
390 static char rbuf[16];
391 int i, l;
392 unsigned long flags;
394 spin_lock_irqsave(&xencons_lock, flags);
396 if ( xencons_tty != NULL )
397 {
398 /* Receive work. */
399 while ( (l = HYPERVISOR_console_io(CONSOLEIO_read, 16, rbuf)) > 0 )
400 for ( i = 0; i < l; i++ )
401 tty_insert_flip_char(xencons_tty, rbuf[i], 0);
402 if ( xencons_tty->flip.count != 0 )
403 tty_flip_buffer_push(xencons_tty);
404 }
406 /* Transmit work. */
407 __xencons_tx_flush();
409 spin_unlock_irqrestore(&xencons_lock, flags);
411 return IRQ_HANDLED;
412 }
414 static int xencons_write_room(struct tty_struct *tty)
415 {
416 return WBUF_SIZE - (wp - wc);
417 }
419 static int xencons_chars_in_buffer(struct tty_struct *tty)
420 {
421 return wp - wc;
422 }
424 static void xencons_send_xchar(struct tty_struct *tty, char ch)
425 {
426 unsigned long flags;
428 if ( TTY_INDEX(tty) != 0 )
429 return;
431 spin_lock_irqsave(&xencons_lock, flags);
432 x_char = ch;
433 __xencons_tx_flush();
434 spin_unlock_irqrestore(&xencons_lock, flags);
435 }
437 static void xencons_throttle(struct tty_struct *tty)
438 {
439 if ( TTY_INDEX(tty) != 0 )
440 return;
442 if ( I_IXOFF(tty) )
443 xencons_send_xchar(tty, STOP_CHAR(tty));
444 }
446 static void xencons_unthrottle(struct tty_struct *tty)
447 {
448 if ( TTY_INDEX(tty) != 0 )
449 return;
451 if ( I_IXOFF(tty) )
452 {
453 if ( x_char != 0 )
454 x_char = 0;
455 else
456 xencons_send_xchar(tty, START_CHAR(tty));
457 }
458 }
460 static void xencons_flush_buffer(struct tty_struct *tty)
461 {
462 unsigned long flags;
464 if ( TTY_INDEX(tty) != 0 )
465 return;
467 spin_lock_irqsave(&xencons_lock, flags);
468 wc = wp = 0;
469 spin_unlock_irqrestore(&xencons_lock, flags);
470 }
472 static inline int __xencons_put_char(int ch)
473 {
474 char _ch = (char)ch;
475 if ( (wp - wc) == WBUF_SIZE )
476 return 0;
477 wbuf[WBUF_MASK(wp++)] = _ch;
478 return 1;
479 }
481 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
482 static int xencons_write(struct tty_struct *tty, const unsigned char *buf,
483 int count)
484 {
485 int i;
486 unsigned long flags;
488 if ( TTY_INDEX(tty) != 0 )
489 return count;
491 spin_lock_irqsave(&xencons_lock, flags);
493 for ( i = 0; i < count; i++ )
494 if ( !__xencons_put_char(buf[i]) )
495 break;
497 if ( i != 0 )
498 __xencons_tx_flush();
500 spin_unlock_irqrestore(&xencons_lock, flags);
502 return i;
503 }
504 #else
505 static int xencons_write(struct tty_struct *tty, int from_user,
506 const u_char *buf, int count)
507 {
508 int i;
509 unsigned long flags;
511 if ( from_user && verify_area(VERIFY_READ, buf, count) )
512 return -EINVAL;
514 if ( TTY_INDEX(tty) != 0 )
515 return count;
517 spin_lock_irqsave(&xencons_lock, flags);
519 for ( i = 0; i < count; i++ )
520 {
521 char ch;
522 if ( from_user )
523 __get_user(ch, buf + i);
524 else
525 ch = buf[i];
526 if ( !__xencons_put_char(ch) )
527 break;
528 }
530 if ( i != 0 )
531 __xencons_tx_flush();
533 spin_unlock_irqrestore(&xencons_lock, flags);
535 return i;
536 }
537 #endif
539 static void xencons_put_char(struct tty_struct *tty, u_char ch)
540 {
541 unsigned long flags;
543 if ( TTY_INDEX(tty) != 0 )
544 return;
546 spin_lock_irqsave(&xencons_lock, flags);
547 (void)__xencons_put_char(ch);
548 spin_unlock_irqrestore(&xencons_lock, flags);
549 }
551 static void xencons_flush_chars(struct tty_struct *tty)
552 {
553 unsigned long flags;
555 if ( TTY_INDEX(tty) != 0 )
556 return;
558 spin_lock_irqsave(&xencons_lock, flags);
559 __xencons_tx_flush();
560 spin_unlock_irqrestore(&xencons_lock, flags);
561 }
563 static void xencons_wait_until_sent(struct tty_struct *tty, int timeout)
564 {
565 unsigned long orig_jiffies = jiffies;
567 if ( TTY_INDEX(tty) != 0 )
568 return;
570 while ( DRV(tty->driver)->chars_in_buffer(tty) )
571 {
572 set_current_state(TASK_INTERRUPTIBLE);
573 schedule_timeout(1);
574 if ( signal_pending(current) )
575 break;
576 if ( (timeout != 0) && time_after(jiffies, orig_jiffies + timeout) )
577 break;
578 }
580 set_current_state(TASK_RUNNING);
581 }
583 static int xencons_open(struct tty_struct *tty, struct file *filp)
584 {
585 unsigned long flags;
587 if ( TTY_INDEX(tty) != 0 )
588 return 0;
590 spin_lock_irqsave(&xencons_lock, flags);
591 tty->driver_data = NULL;
592 if ( xencons_tty == NULL )
593 xencons_tty = tty;
594 __xencons_tx_flush();
595 spin_unlock_irqrestore(&xencons_lock, flags);
597 return 0;
598 }
600 static void xencons_close(struct tty_struct *tty, struct file *filp)
601 {
602 unsigned long flags;
604 if ( TTY_INDEX(tty) != 0 )
605 return;
607 if ( tty->count == 1 )
608 {
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 }
620 }
622 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
623 static struct tty_operations xencons_ops = {
624 .open = xencons_open,
625 .close = xencons_close,
626 .write = xencons_write,
627 .write_room = xencons_write_room,
628 .put_char = xencons_put_char,
629 .flush_chars = xencons_flush_chars,
630 .chars_in_buffer = xencons_chars_in_buffer,
631 .send_xchar = xencons_send_xchar,
632 .flush_buffer = xencons_flush_buffer,
633 .throttle = xencons_throttle,
634 .unthrottle = xencons_unthrottle,
635 .wait_until_sent = xencons_wait_until_sent,
636 };
638 #ifdef CONFIG_XEN_PRIVILEGED_GUEST
639 static const char *xennullcon_startup(void)
640 {
641 return NULL;
642 }
644 static int xennullcon_dummy(void)
645 {
646 return 0;
647 }
649 #define DUMMY (void *)xennullcon_dummy
651 /*
652 * The console `switch' structure for the dummy console
653 *
654 * Most of the operations are dummies.
655 */
657 const struct consw xennull_con = {
658 .owner = THIS_MODULE,
659 .con_startup = xennullcon_startup,
660 .con_init = DUMMY,
661 .con_deinit = DUMMY,
662 .con_clear = DUMMY,
663 .con_putc = DUMMY,
664 .con_putcs = DUMMY,
665 .con_cursor = DUMMY,
666 .con_scroll = DUMMY,
667 .con_bmove = DUMMY,
668 .con_switch = DUMMY,
669 .con_blank = DUMMY,
670 .con_font_set = DUMMY,
671 .con_font_get = DUMMY,
672 .con_font_default = DUMMY,
673 .con_font_copy = DUMMY,
674 .con_set_palette = DUMMY,
675 .con_scrolldelta = DUMMY,
676 };
677 #endif
678 #endif
680 static int __init xencons_init(void)
681 {
682 int rc;
684 if ( xc_mode == XC_OFF )
685 return 0;
687 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
688 xencons_driver = alloc_tty_driver((xc_mode == XC_SERIAL) ?
689 1 : MAX_NR_CONSOLES);
690 if ( xencons_driver == NULL )
691 return -ENOMEM;
692 #else
693 memset(&xencons_driver, 0, sizeof(struct tty_driver));
694 xencons_driver.magic = TTY_DRIVER_MAGIC;
695 xencons_driver.refcount = &xencons_refcount;
696 xencons_driver.table = xencons_table;
697 xencons_driver.num = (xc_mode == XC_SERIAL) ? 1 : MAX_NR_CONSOLES;
698 #endif
700 DRV(xencons_driver)->major = TTY_MAJOR;
701 DRV(xencons_driver)->type = TTY_DRIVER_TYPE_SERIAL;
702 DRV(xencons_driver)->subtype = SERIAL_TYPE_NORMAL;
703 DRV(xencons_driver)->init_termios = tty_std_termios;
704 DRV(xencons_driver)->flags =
705 TTY_DRIVER_REAL_RAW | TTY_DRIVER_RESET_TERMIOS | TTY_DRIVER_NO_DEVFS;
706 DRV(xencons_driver)->termios = xencons_termios;
707 DRV(xencons_driver)->termios_locked = xencons_termios_locked;
709 if ( xc_mode == XC_SERIAL )
710 {
711 DRV(xencons_driver)->name = "ttyS";
712 DRV(xencons_driver)->minor_start = 64;
713 DRV(xencons_driver)->name_base = 0;
714 }
715 else
716 {
717 DRV(xencons_driver)->name = "tty";
718 DRV(xencons_driver)->minor_start = 1;
719 DRV(xencons_driver)->name_base = 1;
720 }
722 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
723 tty_set_operations(xencons_driver, &xencons_ops);
724 #else
725 xencons_driver.open = xencons_open;
726 xencons_driver.close = xencons_close;
727 xencons_driver.write = xencons_write;
728 xencons_driver.write_room = xencons_write_room;
729 xencons_driver.put_char = xencons_put_char;
730 xencons_driver.flush_chars = xencons_flush_chars;
731 xencons_driver.chars_in_buffer = xencons_chars_in_buffer;
732 xencons_driver.send_xchar = xencons_send_xchar;
733 xencons_driver.flush_buffer = xencons_flush_buffer;
734 xencons_driver.throttle = xencons_throttle;
735 xencons_driver.unthrottle = xencons_unthrottle;
736 xencons_driver.wait_until_sent = xencons_wait_until_sent;
737 #endif
739 if ( (rc = tty_register_driver(DRV(xencons_driver))) != 0 )
740 {
741 printk("WARNING: Failed to register Xen virtual "
742 "console driver as '%s%d'\n",
743 DRV(xencons_driver)->name, DRV(xencons_driver)->name_base);
744 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
745 put_tty_driver(xencons_driver);
746 xencons_driver = NULL;
747 #endif
748 return rc;
749 }
751 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
752 tty_register_device(xencons_driver, 0, NULL);
753 #endif
755 if ( xen_start_info.flags & SIF_INITDOMAIN )
756 {
757 xencons_priv_irq = bind_virq_to_irq(VIRQ_CONSOLE);
758 (void)request_irq(xencons_priv_irq,
759 xencons_priv_interrupt, 0, "console", NULL);
760 }
761 else
762 {
763 (void)ctrl_if_register_receiver(CMSG_CONSOLE, xencons_rx, 0);
764 }
766 printk("Xen virtual console successfully installed as %s\n",
767 DRV(xencons_driver)->name);
769 return 0;
770 }
772 module_init(xencons_init);