debuggers.hg

view linux-2.6.8.1-xen-sparse/drivers/xen/console/console.c @ 2618:fa14084f05cc

bitkeeper revision 1.1159.1.195 (415ca61bv5y6opiJRoJ_c07c3vTfDA)

Make console driver play nice with sysfs. Should work with udev now.
author mwilli2@equilibrium.research
date Fri Oct 01 00:34:35 2004 +0000 (2004-10-01)
parents 11be1dfb262b
children 8a3a77314cb5 ff4e7a241335
line source
1 /******************************************************************************
2 * console.c
3 *
4 * Virtual console driver.
5 *
6 * Copyright (c) 2002-2004, K A Fraser.
7 */
9 #include <linux/config.h>
10 #include <linux/version.h>
11 #include <linux/module.h>
12 #include <linux/errno.h>
13 #include <linux/signal.h>
14 #include <linux/sched.h>
15 #include <linux/interrupt.h>
16 #include <linux/tty.h>
17 #include <linux/tty_flip.h>
18 #include <linux/serial.h>
19 #include <linux/major.h>
20 #include <linux/ptrace.h>
21 #include <linux/ioport.h>
22 #include <linux/mm.h>
23 #include <linux/slab.h>
24 #include <linux/init.h>
25 #include <linux/console.h>
26 #include <asm/io.h>
27 #include <asm/irq.h>
28 #include <asm/uaccess.h>
29 #include <asm/hypervisor-ifs/event_channel.h>
30 #include <asm-xen/hypervisor.h>
31 #include <asm-xen/evtchn.h>
32 #include <asm-xen/ctrl_if.h>
34 /*
35 * Modes:
36 * 'xencons=off' [XC_OFF]: Console is disabled.
37 * 'xencons=tty' [XC_TTY]: Console attached to '/dev/tty[0-9]+'.
38 * 'xencons=ttyS' [XC_SERIAL]: Console attached to '/dev/ttyS[0-9]+'.
39 * [XC_DEFAULT]: DOM0 -> XC_SERIAL ; all others -> XC_TTY.
40 *
41 * NB. In mode XC_TTY, we create dummy consoles for tty2-63. This suppresses
42 * warnings from standard distro startup scripts.
43 */
44 static enum { XC_OFF, XC_DEFAULT, XC_TTY, XC_SERIAL } xc_mode = XC_DEFAULT;
46 static int __init xencons_setup(char *str)
47 {
48 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
49 if (str[0] == '=')
50 str++;
51 #endif
52 if ( !strcmp(str, "tty") )
53 xc_mode = XC_TTY;
54 else if ( !strcmp(str, "ttyS") )
55 xc_mode = XC_SERIAL;
56 else if ( !strcmp(str, "off") )
57 xc_mode = XC_OFF;
58 return 1;
59 }
60 __setup("xencons", xencons_setup);
62 /* The kernel and user-land drivers share a common transmit buffer. */
63 #define WBUF_SIZE 4096
64 #define WBUF_MASK(_i) ((_i)&(WBUF_SIZE-1))
65 static char wbuf[WBUF_SIZE];
66 static unsigned int wc, wp; /* write_cons, write_prod */
68 /* This lock protects accesses to the common transmit buffer. */
69 static spinlock_t xencons_lock = SPIN_LOCK_UNLOCKED;
71 /* Common transmit-kick routine. */
72 static void __xencons_tx_flush(void);
74 /* This task is used to defer sending console data until there is space. */
75 static void xencons_tx_flush_task_routine(void *data);
77 static DECLARE_TQUEUE(xencons_tx_flush_task,
78 xencons_tx_flush_task_routine,
79 NULL);
81 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
82 static struct tty_driver *xencons_driver;
83 #else
84 static struct tty_driver xencons_driver;
85 #endif
88 /******************** Kernel console driver ********************************/
90 static void kcons_write(
91 struct console *c, const char *s, unsigned int count)
92 {
93 int i;
94 unsigned long flags;
96 spin_lock_irqsave(&xencons_lock, flags);
98 for ( i = 0; i < count; i++ )
99 {
100 if ( (wp - wc) >= (WBUF_SIZE - 1) )
101 break;
102 if ( (wbuf[WBUF_MASK(wp++)] = s[i]) == '\n' )
103 wbuf[WBUF_MASK(wp++)] = '\r';
104 }
106 __xencons_tx_flush();
108 spin_unlock_irqrestore(&xencons_lock, flags);
109 }
111 static void kcons_write_dom0(
112 struct console *c, const char *s, unsigned int count)
113 {
114 int rc;
116 while ( count > 0 )
117 {
118 if ( (rc = HYPERVISOR_console_io(CONSOLEIO_write,
119 count, (char *)s)) > 0 )
120 {
121 count -= rc;
122 s += rc;
123 }
124 else
125 break;
126 }
127 }
129 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
130 static struct tty_driver *kcons_device(struct console *c, int *index)
131 {
132 *index = c->index;
133 return xencons_driver;
134 }
135 #else
136 static kdev_t kcons_device(struct console *c)
137 {
138 return MKDEV(TTY_MAJOR, (xc_mode == XC_SERIAL) ? 64 : 1);
139 }
140 #endif
142 static struct console kcons_info = {
143 device: kcons_device,
144 flags: CON_PRINTBUFFER,
145 index: -1
146 };
148 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
149 #define __RETCODE 0
150 static int __init xen_console_init(void)
151 #else
152 #define __RETCODE
153 void xen_console_init(void)
154 #endif
155 {
156 if ( start_info.flags & SIF_INITDOMAIN )
157 {
158 if ( xc_mode == XC_DEFAULT )
159 xc_mode = XC_SERIAL;
160 kcons_info.write = kcons_write_dom0;
161 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
162 if ( xc_mode == XC_SERIAL )
163 kcons_info.flags |= CON_ENABLED;
164 #endif
165 }
166 else
167 {
168 if ( xc_mode == XC_DEFAULT )
169 xc_mode = XC_TTY;
170 kcons_info.write = kcons_write;
171 }
173 if ( xc_mode == XC_OFF )
174 return __RETCODE;
176 if ( xc_mode == XC_SERIAL )
177 strcpy(kcons_info.name, "ttyS");
178 else
179 strcpy(kcons_info.name, "tty");
181 register_console(&kcons_info);
182 return __RETCODE;
183 }
184 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
185 console_initcall(xen_console_init);
186 #endif
188 /*** Useful function for console debugging -- goes straight to Xen. ***/
189 asmlinkage int xprintk(const char *fmt, ...)
190 {
191 va_list args;
192 int printk_len;
193 static char printk_buf[1024];
195 /* Emit the output into the temporary buffer */
196 va_start(args, fmt);
197 printk_len = vsnprintf(printk_buf, sizeof(printk_buf), fmt, args);
198 va_end(args);
200 /* Send the processed output directly to Xen. */
201 kcons_write_dom0(NULL, printk_buf, printk_len);
203 return 0;
204 }
206 /*** Forcibly flush console data before dying. ***/
207 void xencons_force_flush(void)
208 {
209 ctrl_msg_t msg;
210 int sz;
212 /* Emergency console is synchronous, so there's nothing to flush. */
213 if ( start_info.flags & SIF_INITDOMAIN )
214 return;
216 /*
217 * We use dangerous control-interface functions that require a quiescent
218 * system and no interrupts. Try to ensure this with a global cli().
219 */
220 cli();
222 /* Spin until console data is flushed through to the domain controller. */
223 while ( (wc != wp) && !ctrl_if_transmitter_empty() )
224 {
225 /* Interrupts are disabled -- we must manually reap responses. */
226 ctrl_if_discard_responses();
228 if ( (sz = wp - wc) == 0 )
229 continue;
230 if ( sz > sizeof(msg.msg) )
231 sz = sizeof(msg.msg);
232 if ( sz > (WBUF_SIZE - WBUF_MASK(wc)) )
233 sz = WBUF_SIZE - WBUF_MASK(wc);
235 msg.type = CMSG_CONSOLE;
236 msg.subtype = CMSG_CONSOLE_DATA;
237 msg.length = sz;
238 memcpy(msg.msg, &wbuf[WBUF_MASK(wc)], sz);
240 if ( ctrl_if_send_message_noblock(&msg, NULL, 0) == 0 )
241 wc += sz;
242 }
243 }
246 /******************** User-space console driver (/dev/console) ************/
248 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
249 #define DRV(_d) (_d)
250 #define TTY_INDEX(_tty) ((_tty)->index)
251 #else
252 static int xencons_refcount;
253 static struct tty_struct *xencons_table[MAX_NR_CONSOLES];
254 #define DRV(_d) (&(_d))
255 #define TTY_INDEX(_tty) (MINOR((_tty)->device) - xencons_driver.minor_start)
256 #endif
258 static struct termios *xencons_termios[MAX_NR_CONSOLES];
259 static struct termios *xencons_termios_locked[MAX_NR_CONSOLES];
260 static struct tty_struct *xencons_tty;
261 static int xencons_priv_irq;
262 static char x_char;
264 /* Non-privileged receive callback. */
265 static void xencons_rx(ctrl_msg_t *msg, unsigned long id)
266 {
267 int i;
268 unsigned long flags;
270 spin_lock_irqsave(&xencons_lock, flags);
271 if ( xencons_tty != NULL )
272 {
273 for ( i = 0; i < msg->length; i++ )
274 tty_insert_flip_char(xencons_tty, msg->msg[i], 0);
275 tty_flip_buffer_push(xencons_tty);
276 }
277 spin_unlock_irqrestore(&xencons_lock, flags);
279 msg->length = 0;
280 ctrl_if_send_response(msg);
281 }
283 /* Privileged and non-privileged transmit worker. */
284 static void __xencons_tx_flush(void)
285 {
286 int sz, work_done = 0;
287 ctrl_msg_t msg;
289 if ( start_info.flags & SIF_INITDOMAIN )
290 {
291 if ( x_char )
292 {
293 kcons_write_dom0(NULL, &x_char, 1);
294 x_char = 0;
295 work_done = 1;
296 }
298 while ( wc != wp )
299 {
300 sz = wp - wc;
301 if ( sz > (WBUF_SIZE - WBUF_MASK(wc)) )
302 sz = WBUF_SIZE - WBUF_MASK(wc);
303 kcons_write_dom0(NULL, &wbuf[WBUF_MASK(wc)], sz);
304 wc += sz;
305 work_done = 1;
306 }
307 }
308 else
309 {
310 while ( x_char )
311 {
312 msg.type = CMSG_CONSOLE;
313 msg.subtype = CMSG_CONSOLE_DATA;
314 msg.length = 1;
315 msg.msg[0] = x_char;
317 if ( ctrl_if_send_message_noblock(&msg, NULL, 0) == 0 )
318 x_char = 0;
319 else if ( ctrl_if_enqueue_space_callback(&xencons_tx_flush_task) )
320 break;
322 work_done = 1;
323 }
325 while ( wc != wp )
326 {
327 sz = wp - wc;
328 if ( sz > sizeof(msg.msg) )
329 sz = sizeof(msg.msg);
330 if ( sz > (WBUF_SIZE - WBUF_MASK(wc)) )
331 sz = WBUF_SIZE - WBUF_MASK(wc);
333 msg.type = CMSG_CONSOLE;
334 msg.subtype = CMSG_CONSOLE_DATA;
335 msg.length = sz;
336 memcpy(msg.msg, &wbuf[WBUF_MASK(wc)], sz);
338 if ( ctrl_if_send_message_noblock(&msg, NULL, 0) == 0 )
339 wc += sz;
340 else if ( ctrl_if_enqueue_space_callback(&xencons_tx_flush_task) )
341 break;
343 work_done = 1;
344 }
345 }
347 if ( work_done && (xencons_tty != NULL) )
348 {
349 wake_up_interruptible(&xencons_tty->write_wait);
350 if ( (xencons_tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
351 (xencons_tty->ldisc.write_wakeup != NULL) )
352 (xencons_tty->ldisc.write_wakeup)(xencons_tty);
353 }
354 }
356 /* Non-privileged transmit kicker. */
357 static void xencons_tx_flush_task_routine(void *data)
358 {
359 unsigned long flags;
360 spin_lock_irqsave(&xencons_lock, flags);
361 __xencons_tx_flush();
362 spin_unlock_irqrestore(&xencons_lock, flags);
363 }
365 /* Privileged receive callback and transmit kicker. */
366 static irqreturn_t xencons_priv_interrupt(int irq, void *dev_id,
367 struct pt_regs *regs)
368 {
369 static char rbuf[16];
370 int i, l;
371 unsigned long flags;
373 spin_lock_irqsave(&xencons_lock, flags);
375 if ( xencons_tty != NULL )
376 {
377 /* Receive work. */
378 while ( (l = HYPERVISOR_console_io(CONSOLEIO_read, 16, rbuf)) > 0 )
379 for ( i = 0; i < l; i++ )
380 tty_insert_flip_char(xencons_tty, rbuf[i], 0);
381 if ( xencons_tty->flip.count != 0 )
382 tty_flip_buffer_push(xencons_tty);
383 }
385 /* Transmit work. */
386 __xencons_tx_flush();
388 spin_unlock_irqrestore(&xencons_lock, flags);
390 return IRQ_HANDLED;
391 }
393 static int xencons_write_room(struct tty_struct *tty)
394 {
395 return WBUF_SIZE - (wp - wc);
396 }
398 static int xencons_chars_in_buffer(struct tty_struct *tty)
399 {
400 return wp - wc;
401 }
403 static void xencons_send_xchar(struct tty_struct *tty, char ch)
404 {
405 unsigned long flags;
407 if ( TTY_INDEX(tty) != 0 )
408 return;
410 spin_lock_irqsave(&xencons_lock, flags);
411 x_char = ch;
412 __xencons_tx_flush();
413 spin_unlock_irqrestore(&xencons_lock, flags);
414 }
416 static void xencons_throttle(struct tty_struct *tty)
417 {
418 if ( TTY_INDEX(tty) != 0 )
419 return;
421 if ( I_IXOFF(tty) )
422 xencons_send_xchar(tty, STOP_CHAR(tty));
423 }
425 static void xencons_unthrottle(struct tty_struct *tty)
426 {
427 if ( TTY_INDEX(tty) != 0 )
428 return;
430 if ( I_IXOFF(tty) )
431 {
432 if ( x_char != 0 )
433 x_char = 0;
434 else
435 xencons_send_xchar(tty, START_CHAR(tty));
436 }
437 }
439 static void xencons_flush_buffer(struct tty_struct *tty)
440 {
441 unsigned long flags;
443 if ( TTY_INDEX(tty) != 0 )
444 return;
446 spin_lock_irqsave(&xencons_lock, flags);
447 wc = wp = 0;
448 spin_unlock_irqrestore(&xencons_lock, flags);
449 }
451 static inline int __xencons_put_char(int ch)
452 {
453 char _ch = (char)ch;
454 if ( (wp - wc) == WBUF_SIZE )
455 return 0;
456 wbuf[WBUF_MASK(wp++)] = _ch;
457 return 1;
458 }
460 static int xencons_write(struct tty_struct *tty, int from_user,
461 const u_char * buf, int count)
462 {
463 int i;
464 unsigned long flags;
466 if ( from_user && verify_area(VERIFY_READ, buf, count) )
467 return -EINVAL;
469 if ( TTY_INDEX(tty) != 0 )
470 return count;
472 spin_lock_irqsave(&xencons_lock, flags);
474 for ( i = 0; i < count; i++ )
475 {
476 char ch;
477 if ( from_user )
478 __get_user(ch, buf + i);
479 else
480 ch = buf[i];
481 if ( !__xencons_put_char(ch) )
482 break;
483 }
485 if ( i != 0 )
486 __xencons_tx_flush();
488 spin_unlock_irqrestore(&xencons_lock, flags);
490 return i;
491 }
493 static void xencons_put_char(struct tty_struct *tty, u_char ch)
494 {
495 unsigned long flags;
497 if ( TTY_INDEX(tty) != 0 )
498 return;
500 spin_lock_irqsave(&xencons_lock, flags);
501 (void)__xencons_put_char(ch);
502 spin_unlock_irqrestore(&xencons_lock, flags);
503 }
505 static void xencons_flush_chars(struct tty_struct *tty)
506 {
507 unsigned long flags;
509 if ( TTY_INDEX(tty) != 0 )
510 return;
512 spin_lock_irqsave(&xencons_lock, flags);
513 __xencons_tx_flush();
514 spin_unlock_irqrestore(&xencons_lock, flags);
515 }
517 static void xencons_wait_until_sent(struct tty_struct *tty, int timeout)
518 {
519 unsigned long orig_jiffies = jiffies;
521 if ( TTY_INDEX(tty) != 0 )
522 return;
524 while ( DRV(tty->driver)->chars_in_buffer(tty) )
525 {
526 set_current_state(TASK_INTERRUPTIBLE);
527 schedule_timeout(1);
528 if ( signal_pending(current) )
529 break;
530 if ( (timeout != 0) && time_after(jiffies, orig_jiffies + timeout) )
531 break;
532 }
534 set_current_state(TASK_RUNNING);
535 }
537 static int xencons_open(struct tty_struct *tty, struct file *filp)
538 {
539 unsigned long flags;
541 if ( TTY_INDEX(tty) != 0 )
542 return 0;
544 MOD_INC_USE_COUNT;
546 spin_lock_irqsave(&xencons_lock, flags);
547 tty->driver_data = NULL;
548 if ( xencons_tty == NULL )
549 xencons_tty = tty;
550 __xencons_tx_flush();
551 spin_unlock_irqrestore(&xencons_lock, flags);
553 return 0;
554 }
556 static void xencons_close(struct tty_struct *tty, struct file *filp)
557 {
558 unsigned long flags;
560 if ( TTY_INDEX(tty) != 0 )
561 return;
563 if ( tty->count == 1 )
564 {
565 tty->closing = 1;
566 tty_wait_until_sent(tty, 0);
567 if ( DRV(tty->driver)->flush_buffer != NULL )
568 DRV(tty->driver)->flush_buffer(tty);
569 if ( tty->ldisc.flush_buffer != NULL )
570 tty->ldisc.flush_buffer(tty);
571 tty->closing = 0;
572 spin_lock_irqsave(&xencons_lock, flags);
573 xencons_tty = NULL;
574 spin_unlock_irqrestore(&xencons_lock, flags);
575 }
577 MOD_DEC_USE_COUNT;
578 }
580 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
581 static struct tty_operations xencons_ops = {
582 .open = xencons_open,
583 .close = xencons_close,
584 .write = xencons_write,
585 .write_room = xencons_write_room,
586 .put_char = xencons_put_char,
587 .flush_chars = xencons_flush_chars,
588 .chars_in_buffer = xencons_chars_in_buffer,
589 .send_xchar = xencons_send_xchar,
590 .flush_buffer = xencons_flush_buffer,
591 .throttle = xencons_throttle,
592 .unthrottle = xencons_unthrottle,
593 .wait_until_sent = xencons_wait_until_sent,
594 };
596 #ifdef CONFIG_XEN_PRIVILEGED_GUEST
597 static const char *xennullcon_startup(void)
598 {
599 return NULL;
600 }
602 static int xennullcon_dummy(void)
603 {
604 return 0;
605 }
607 #define DUMMY (void *)xennullcon_dummy
609 /*
610 * The console `switch' structure for the dummy console
611 *
612 * Most of the operations are dummies.
613 */
615 const struct consw xennull_con = {
616 .owner = THIS_MODULE,
617 .con_startup = xennullcon_startup,
618 .con_init = DUMMY,
619 .con_deinit = DUMMY,
620 .con_clear = DUMMY,
621 .con_putc = DUMMY,
622 .con_putcs = DUMMY,
623 .con_cursor = DUMMY,
624 .con_scroll = DUMMY,
625 .con_bmove = DUMMY,
626 .con_switch = DUMMY,
627 .con_blank = DUMMY,
628 .con_font_set = DUMMY,
629 .con_font_get = DUMMY,
630 .con_font_default = DUMMY,
631 .con_font_copy = DUMMY,
632 .con_set_palette = DUMMY,
633 .con_scrolldelta = DUMMY,
634 };
635 #endif
636 #endif
638 static int __init xencons_init(void)
639 {
640 if ( xc_mode == XC_OFF )
641 return 0;
643 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
644 xencons_driver = alloc_tty_driver((xc_mode == XC_SERIAL) ?
645 1 : MAX_NR_CONSOLES);
646 if ( xencons_driver == NULL )
647 return -ENOMEM;
648 #else
649 memset(&xencons_driver, 0, sizeof(struct tty_driver));
650 xencons_driver.magic = TTY_DRIVER_MAGIC;
651 xencons_driver.refcount = &xencons_refcount;
652 xencons_driver.table = xencons_table;
653 xencons_driver.num = (xc_mode == XC_SERIAL) ? 1 : MAX_NR_CONSOLES;
654 #endif
656 DRV(xencons_driver)->major = TTY_MAJOR;
657 DRV(xencons_driver)->type = TTY_DRIVER_TYPE_SERIAL;
658 DRV(xencons_driver)->subtype = SERIAL_TYPE_NORMAL;
659 DRV(xencons_driver)->init_termios = tty_std_termios;
660 DRV(xencons_driver)->flags =
661 TTY_DRIVER_REAL_RAW | TTY_DRIVER_RESET_TERMIOS | TTY_DRIVER_NO_DEVFS;
662 DRV(xencons_driver)->termios = xencons_termios;
663 DRV(xencons_driver)->termios_locked = xencons_termios_locked;
665 if ( xc_mode == XC_SERIAL )
666 {
667 DRV(xencons_driver)->name = "ttyS";
668 DRV(xencons_driver)->minor_start = 64;
669 DRV(xencons_driver)->name_base = 0;
670 }
671 else
672 {
673 DRV(xencons_driver)->name = "tty";
674 DRV(xencons_driver)->minor_start = 1;
675 DRV(xencons_driver)->name_base = 1;
676 }
678 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
679 tty_set_operations(xencons_driver, &xencons_ops);
680 #else
681 xencons_driver.open = xencons_open;
682 xencons_driver.close = xencons_close;
683 xencons_driver.write = xencons_write;
684 xencons_driver.write_room = xencons_write_room;
685 xencons_driver.put_char = xencons_put_char;
686 xencons_driver.flush_chars = xencons_flush_chars;
687 xencons_driver.chars_in_buffer = xencons_chars_in_buffer;
688 xencons_driver.send_xchar = xencons_send_xchar;
689 xencons_driver.flush_buffer = xencons_flush_buffer;
690 xencons_driver.throttle = xencons_throttle;
691 xencons_driver.unthrottle = xencons_unthrottle;
692 xencons_driver.wait_until_sent = xencons_wait_until_sent;
693 #endif
695 if ( tty_register_driver(DRV(xencons_driver)) )
696 panic("Couldn't register Xen virtual console driver as %s\n",
697 DRV(xencons_driver)->name);
699 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
700 tty_register_device(xencons_driver, 0, NULL);
701 #endif
703 if ( start_info.flags & SIF_INITDOMAIN )
704 {
705 xencons_priv_irq = bind_virq_to_irq(VIRQ_CONSOLE);
706 (void)request_irq(xencons_priv_irq,
707 xencons_priv_interrupt, 0, "console", NULL);
708 }
709 else
710 {
711 (void)ctrl_if_register_receiver(CMSG_CONSOLE, xencons_rx, 0);
712 }
714 printk("Xen virtual console successfully installed as %s\n",
715 DRV(xencons_driver)->name);
717 return 0;
718 }
720 static void __exit xencons_fini(void)
721 {
722 int ret;
724 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
725 tty_unregister_device(xencons_driver, 0);
726 #endif
728 if ( (ret = tty_unregister_driver(DRV(xencons_driver))) != 0 )
729 printk(KERN_ERR "Unable to unregister Xen console driver: %d\n", ret);
731 if ( start_info.flags & SIF_INITDOMAIN )
732 {
733 free_irq(xencons_priv_irq, NULL);
734 unbind_virq_from_irq(VIRQ_CONSOLE);
735 }
736 else
737 {
738 ctrl_if_unregister_receiver(CMSG_CONSOLE, xencons_rx);
739 }
740 }
742 module_init(xencons_init);
743 module_exit(xencons_fini);