ia64/xen-unstable

view linux-2.6-xen-sparse/drivers/xen/console/console.c @ 6432:b54144915ae6

merge?
author cl349@firebug.cl.cam.ac.uk
date Thu Aug 25 16:26:30 2005 +0000 (2005-08-25)
parents 3428d58a85e1 522bc50588ed
children 0610add7c3fe
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 <asm/io.h>
49 #include <asm/irq.h>
50 #include <asm/uaccess.h>
51 #include <asm-xen/xen-public/event_channel.h>
52 #include <asm-xen/hypervisor.h>
53 #include <asm-xen/evtchn.h>
54 #include <asm-xen/ctrl_if.h>
56 /*
57 * Modes:
58 * 'xencons=off' [XC_OFF]: Console is disabled.
59 * 'xencons=tty' [XC_TTY]: Console attached to '/dev/tty[0-9]+'.
60 * 'xencons=ttyS' [XC_SERIAL]: Console attached to '/dev/ttyS[0-9]+'.
61 * [XC_DEFAULT]: DOM0 -> XC_SERIAL ; all others -> XC_TTY.
62 *
63 * NB. In mode XC_TTY, we create dummy consoles for tty2-63. This suppresses
64 * warnings from standard distro startup scripts.
65 */
66 static enum { XC_OFF, XC_DEFAULT, XC_TTY, XC_SERIAL } xc_mode = XC_DEFAULT;
67 static int xc_num = -1;
69 static int __init xencons_setup(char *str)
70 {
71 char *q;
72 int n;
74 if ( !strncmp(str, "ttyS", 4) )
75 xc_mode = XC_SERIAL;
76 else if ( !strncmp(str, "tty", 3) )
77 xc_mode = XC_TTY;
78 else if ( !strncmp(str, "off", 3) )
79 xc_mode = XC_OFF;
81 switch ( xc_mode )
82 {
83 case XC_SERIAL:
84 n = simple_strtol( str+4, &q, 10 );
85 if ( q > (str + 4) ) xc_num = n;
86 break;
87 case XC_TTY:
88 n = simple_strtol( str+3, &q, 10 );
89 if ( q > (str + 3) ) xc_num = n;
90 break;
91 default:
92 break;
93 }
95 return 1;
96 }
97 __setup("xencons=", xencons_setup);
99 /* The kernel and user-land drivers share a common transmit buffer. */
100 static unsigned int wbuf_size = 4096;
101 #define WBUF_MASK(_i) ((_i)&(wbuf_size-1))
102 static char *wbuf;
103 static unsigned int wc, wp; /* write_cons, write_prod */
105 static int __init xencons_bufsz_setup(char *str)
106 {
107 unsigned int goal;
108 goal = simple_strtoul(str, NULL, 0);
109 while ( wbuf_size < goal )
110 wbuf_size <<= 1;
111 return 1;
112 }
113 __setup("xencons_bufsz=", xencons_bufsz_setup);
115 /* This lock protects accesses to the common transmit buffer. */
116 static spinlock_t xencons_lock = SPIN_LOCK_UNLOCKED;
118 /* Common transmit-kick routine. */
119 static void __xencons_tx_flush(void);
121 /* This task is used to defer sending console data until there is space. */
122 static void xencons_tx_flush_task_routine(void *data);
124 static DECLARE_TQUEUE(xencons_tx_flush_task,
125 xencons_tx_flush_task_routine,
126 NULL);
128 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
129 static struct tty_driver *xencons_driver;
130 #else
131 static struct tty_driver xencons_driver;
132 #endif
135 /******************** Kernel console driver ********************************/
137 static void kcons_write(
138 struct console *c, const char *s, unsigned int count)
139 {
140 int i;
141 unsigned long flags;
143 spin_lock_irqsave(&xencons_lock, flags);
145 for ( i = 0; i < count; i++ )
146 {
147 if ( (wp - wc) >= (wbuf_size - 1) )
148 break;
149 if ( (wbuf[WBUF_MASK(wp++)] = s[i]) == '\n' )
150 wbuf[WBUF_MASK(wp++)] = '\r';
151 }
153 __xencons_tx_flush();
155 spin_unlock_irqrestore(&xencons_lock, flags);
156 }
158 static void kcons_write_dom0(
159 struct console *c, const char *s, unsigned int count)
160 {
161 int rc;
163 while ( (count > 0) &&
164 ((rc = HYPERVISOR_console_io(
165 CONSOLEIO_write, count, (char *)s)) > 0) )
166 {
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 {
201 if ( xc_mode == XC_DEFAULT )
202 xc_mode = XC_SERIAL;
203 kcons_info.write = kcons_write_dom0;
204 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
205 if ( xc_mode == XC_SERIAL )
206 kcons_info.flags |= CON_ENABLED;
207 #endif
208 }
209 else
210 {
211 if ( xc_mode == XC_DEFAULT )
212 xc_mode = XC_TTY;
213 kcons_info.write = kcons_write;
214 }
216 switch ( xc_mode )
217 {
218 case XC_SERIAL:
219 strcpy(kcons_info.name, "ttyS");
220 if ( xc_num == -1 ) xc_num = 0;
221 break;
223 case XC_TTY:
224 strcpy(kcons_info.name, "tty");
225 if ( xc_num == -1 ) xc_num = 1;
226 break;
228 default:
229 return __RETCODE;
230 }
232 wbuf = alloc_bootmem(wbuf_size);
234 register_console(&kcons_info);
236 return __RETCODE;
237 }
238 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
239 console_initcall(xen_console_init);
240 #endif
242 /*** Useful function for console debugging -- goes straight to Xen. ***/
243 #ifdef CONFIG_XEN_PRIVILEGED_GUEST
244 asmlinkage int xprintk(const char *fmt, ...)
245 #else
246 asmlinkage int xprintk(const char *fmt, ...)
247 #endif
248 {
249 va_list args;
250 int printk_len;
251 static char printk_buf[1024];
253 /* Emit the output into the temporary buffer */
254 va_start(args, fmt);
255 printk_len = vsnprintf(printk_buf, sizeof(printk_buf), fmt, args);
256 va_end(args);
258 /* Send the processed output directly to Xen. */
259 kcons_write_dom0(NULL, printk_buf, printk_len);
261 return 0;
262 }
264 /*** Forcibly flush console data before dying. ***/
265 void xencons_force_flush(void)
266 {
267 ctrl_msg_t msg;
268 int sz;
270 /* Emergency console is synchronous, so there's nothing to flush. */
271 if ( xen_start_info.flags & SIF_INITDOMAIN )
272 return;
274 /*
275 * We use dangerous control-interface functions that require a quiescent
276 * system and no interrupts. Try to ensure this with a global cli().
277 */
278 local_irq_disable(); /* XXXsmp */
280 /* Spin until console data is flushed through to the domain controller. */
281 while ( (wc != wp) && !ctrl_if_transmitter_empty() )
282 {
283 /* Interrupts are disabled -- we must manually reap responses. */
284 ctrl_if_discard_responses();
286 if ( (sz = wp - wc) == 0 )
287 continue;
288 if ( sz > sizeof(msg.msg) )
289 sz = sizeof(msg.msg);
290 if ( sz > (wbuf_size - WBUF_MASK(wc)) )
291 sz = wbuf_size - WBUF_MASK(wc);
293 msg.type = CMSG_CONSOLE;
294 msg.subtype = CMSG_CONSOLE_DATA;
295 msg.length = sz;
296 memcpy(msg.msg, &wbuf[WBUF_MASK(wc)], sz);
298 if ( ctrl_if_send_message_noblock(&msg, NULL, 0) == 0 )
299 wc += sz;
300 }
301 }
304 /******************** User-space console driver (/dev/console) ************/
306 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
307 #define DRV(_d) (_d)
308 #define TTY_INDEX(_tty) ((_tty)->index)
309 #else
310 static int xencons_refcount;
311 static struct tty_struct *xencons_table[MAX_NR_CONSOLES];
312 #define DRV(_d) (&(_d))
313 #define TTY_INDEX(_tty) (MINOR((_tty)->device) - xencons_driver.minor_start)
314 #endif
316 static struct termios *xencons_termios[MAX_NR_CONSOLES];
317 static struct termios *xencons_termios_locked[MAX_NR_CONSOLES];
318 static struct tty_struct *xencons_tty;
319 static int xencons_priv_irq;
320 static char x_char;
322 /* Non-privileged receive callback. */
323 static void xencons_rx(ctrl_msg_t *msg, unsigned long id)
324 {
325 int i;
326 unsigned long flags;
328 spin_lock_irqsave(&xencons_lock, flags);
329 if ( xencons_tty != NULL )
330 {
331 for ( i = 0; i < msg->length; i++ )
332 tty_insert_flip_char(xencons_tty, msg->msg[i], 0);
333 tty_flip_buffer_push(xencons_tty);
334 }
335 spin_unlock_irqrestore(&xencons_lock, flags);
337 msg->length = 0;
338 ctrl_if_send_response(msg);
339 }
341 /* Privileged and non-privileged transmit worker. */
342 static void __xencons_tx_flush(void)
343 {
344 int sz, work_done = 0;
345 ctrl_msg_t msg;
347 if ( xen_start_info.flags & SIF_INITDOMAIN )
348 {
349 if ( x_char )
350 {
351 kcons_write_dom0(NULL, &x_char, 1);
352 x_char = 0;
353 work_done = 1;
354 }
356 while ( wc != wp )
357 {
358 sz = wp - wc;
359 if ( sz > (wbuf_size - WBUF_MASK(wc)) )
360 sz = wbuf_size - WBUF_MASK(wc);
361 kcons_write_dom0(NULL, &wbuf[WBUF_MASK(wc)], sz);
362 wc += sz;
363 work_done = 1;
364 }
365 }
366 else
367 {
368 while ( x_char )
369 {
370 msg.type = CMSG_CONSOLE;
371 msg.subtype = CMSG_CONSOLE_DATA;
372 msg.length = 1;
373 msg.msg[0] = x_char;
375 if ( ctrl_if_send_message_noblock(&msg, NULL, 0) == 0 )
376 x_char = 0;
377 else if ( ctrl_if_enqueue_space_callback(&xencons_tx_flush_task) )
378 break;
380 work_done = 1;
381 }
383 while ( wc != wp )
384 {
385 sz = wp - wc;
386 if ( sz > sizeof(msg.msg) )
387 sz = sizeof(msg.msg);
388 if ( sz > (wbuf_size - WBUF_MASK(wc)) )
389 sz = wbuf_size - WBUF_MASK(wc);
391 msg.type = CMSG_CONSOLE;
392 msg.subtype = CMSG_CONSOLE_DATA;
393 msg.length = sz;
394 memcpy(msg.msg, &wbuf[WBUF_MASK(wc)], sz);
396 if ( ctrl_if_send_message_noblock(&msg, NULL, 0) == 0 )
397 wc += sz;
398 else if ( ctrl_if_enqueue_space_callback(&xencons_tx_flush_task) )
399 break;
401 work_done = 1;
402 }
403 }
405 if ( work_done && (xencons_tty != NULL) )
406 {
407 wake_up_interruptible(&xencons_tty->write_wait);
408 if ( (xencons_tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
409 (xencons_tty->ldisc.write_wakeup != NULL) )
410 (xencons_tty->ldisc.write_wakeup)(xencons_tty);
411 }
412 }
414 /* Non-privileged transmit kicker. */
415 static void xencons_tx_flush_task_routine(void *data)
416 {
417 unsigned long flags;
418 spin_lock_irqsave(&xencons_lock, flags);
419 __xencons_tx_flush();
420 spin_unlock_irqrestore(&xencons_lock, flags);
421 }
423 /* Privileged receive callback and transmit kicker. */
424 static irqreturn_t xencons_priv_interrupt(int irq, void *dev_id,
425 struct pt_regs *regs)
426 {
427 static char rbuf[16];
428 int i, l;
429 unsigned long flags;
431 spin_lock_irqsave(&xencons_lock, flags);
433 if ( xencons_tty != NULL )
434 {
435 /* Receive work. */
436 while ( (l = HYPERVISOR_console_io(CONSOLEIO_read, 16, rbuf)) > 0 )
437 for ( i = 0; i < l; i++ )
438 tty_insert_flip_char(xencons_tty, rbuf[i], 0);
439 if ( xencons_tty->flip.count != 0 )
440 tty_flip_buffer_push(xencons_tty);
441 }
443 /* Transmit work. */
444 __xencons_tx_flush();
446 spin_unlock_irqrestore(&xencons_lock, flags);
448 return IRQ_HANDLED;
449 }
451 static int xencons_write_room(struct tty_struct *tty)
452 {
453 return wbuf_size - (wp - wc);
454 }
456 static int xencons_chars_in_buffer(struct tty_struct *tty)
457 {
458 return wp - wc;
459 }
461 static void xencons_send_xchar(struct tty_struct *tty, char ch)
462 {
463 unsigned long flags;
465 if ( TTY_INDEX(tty) != 0 )
466 return;
468 spin_lock_irqsave(&xencons_lock, flags);
469 x_char = ch;
470 __xencons_tx_flush();
471 spin_unlock_irqrestore(&xencons_lock, flags);
472 }
474 static void xencons_throttle(struct tty_struct *tty)
475 {
476 if ( TTY_INDEX(tty) != 0 )
477 return;
479 if ( I_IXOFF(tty) )
480 xencons_send_xchar(tty, STOP_CHAR(tty));
481 }
483 static void xencons_unthrottle(struct tty_struct *tty)
484 {
485 if ( TTY_INDEX(tty) != 0 )
486 return;
488 if ( I_IXOFF(tty) )
489 {
490 if ( x_char != 0 )
491 x_char = 0;
492 else
493 xencons_send_xchar(tty, START_CHAR(tty));
494 }
495 }
497 static void xencons_flush_buffer(struct tty_struct *tty)
498 {
499 unsigned long flags;
501 if ( TTY_INDEX(tty) != 0 )
502 return;
504 spin_lock_irqsave(&xencons_lock, flags);
505 wc = wp = 0;
506 spin_unlock_irqrestore(&xencons_lock, flags);
507 }
509 static inline int __xencons_put_char(int ch)
510 {
511 char _ch = (char)ch;
512 if ( (wp - wc) == wbuf_size )
513 return 0;
514 wbuf[WBUF_MASK(wp++)] = _ch;
515 return 1;
516 }
518 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
519 static int xencons_write(
520 struct tty_struct *tty,
521 const unsigned char *buf,
522 int count)
523 {
524 int i;
525 unsigned long flags;
527 if ( TTY_INDEX(tty) != 0 )
528 return count;
530 spin_lock_irqsave(&xencons_lock, flags);
532 for ( i = 0; i < count; i++ )
533 if ( !__xencons_put_char(buf[i]) )
534 break;
536 if ( i != 0 )
537 __xencons_tx_flush();
539 spin_unlock_irqrestore(&xencons_lock, flags);
541 return i;
542 }
543 #else
544 static int xencons_write(
545 struct tty_struct *tty,
546 int from_user,
547 const u_char *buf,
548 int count)
549 {
550 int i;
551 unsigned long flags;
553 if ( from_user && verify_area(VERIFY_READ, buf, count) )
554 return -EINVAL;
556 if ( TTY_INDEX(tty) != 0 )
557 return count;
559 spin_lock_irqsave(&xencons_lock, flags);
561 for ( i = 0; i < count; i++ )
562 {
563 char ch;
564 if ( from_user )
565 __get_user(ch, buf + i);
566 else
567 ch = buf[i];
568 if ( !__xencons_put_char(ch) )
569 break;
570 }
572 if ( i != 0 )
573 __xencons_tx_flush();
575 spin_unlock_irqrestore(&xencons_lock, flags);
577 return i;
578 }
579 #endif
581 static void xencons_put_char(struct tty_struct *tty, u_char ch)
582 {
583 unsigned long flags;
585 if ( TTY_INDEX(tty) != 0 )
586 return;
588 spin_lock_irqsave(&xencons_lock, flags);
589 (void)__xencons_put_char(ch);
590 spin_unlock_irqrestore(&xencons_lock, flags);
591 }
593 static void xencons_flush_chars(struct tty_struct *tty)
594 {
595 unsigned long flags;
597 if ( TTY_INDEX(tty) != 0 )
598 return;
600 spin_lock_irqsave(&xencons_lock, flags);
601 __xencons_tx_flush();
602 spin_unlock_irqrestore(&xencons_lock, flags);
603 }
605 static void xencons_wait_until_sent(struct tty_struct *tty, int timeout)
606 {
607 unsigned long orig_jiffies = jiffies;
609 if ( TTY_INDEX(tty) != 0 )
610 return;
612 while ( DRV(tty->driver)->chars_in_buffer(tty) )
613 {
614 set_current_state(TASK_INTERRUPTIBLE);
615 schedule_timeout(1);
616 if ( signal_pending(current) )
617 break;
618 if ( (timeout != 0) && time_after(jiffies, orig_jiffies + timeout) )
619 break;
620 }
622 set_current_state(TASK_RUNNING);
623 }
625 static int xencons_open(struct tty_struct *tty, struct file *filp)
626 {
627 unsigned long flags;
629 if ( TTY_INDEX(tty) != 0 )
630 return 0;
632 spin_lock_irqsave(&xencons_lock, flags);
633 tty->driver_data = NULL;
634 if ( xencons_tty == NULL )
635 xencons_tty = tty;
636 __xencons_tx_flush();
637 spin_unlock_irqrestore(&xencons_lock, flags);
639 return 0;
640 }
642 static void xencons_close(struct tty_struct *tty, struct file *filp)
643 {
644 unsigned long flags;
646 if ( TTY_INDEX(tty) != 0 )
647 return;
649 if ( tty->count == 1 )
650 {
651 tty->closing = 1;
652 tty_wait_until_sent(tty, 0);
653 if ( DRV(tty->driver)->flush_buffer != NULL )
654 DRV(tty->driver)->flush_buffer(tty);
655 if ( tty->ldisc.flush_buffer != NULL )
656 tty->ldisc.flush_buffer(tty);
657 tty->closing = 0;
658 spin_lock_irqsave(&xencons_lock, flags);
659 xencons_tty = NULL;
660 spin_unlock_irqrestore(&xencons_lock, flags);
661 }
662 }
664 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
665 static struct tty_operations xencons_ops = {
666 .open = xencons_open,
667 .close = xencons_close,
668 .write = xencons_write,
669 .write_room = xencons_write_room,
670 .put_char = xencons_put_char,
671 .flush_chars = xencons_flush_chars,
672 .chars_in_buffer = xencons_chars_in_buffer,
673 .send_xchar = xencons_send_xchar,
674 .flush_buffer = xencons_flush_buffer,
675 .throttle = xencons_throttle,
676 .unthrottle = xencons_unthrottle,
677 .wait_until_sent = xencons_wait_until_sent,
678 };
680 #ifdef CONFIG_XEN_PRIVILEGED_GUEST
681 static const char *xennullcon_startup(void)
682 {
683 return NULL;
684 }
686 static int xennullcon_dummy(void)
687 {
688 return 0;
689 }
691 #define DUMMY (void *)xennullcon_dummy
693 /*
694 * The console `switch' structure for the dummy console
695 *
696 * Most of the operations are dummies.
697 */
699 const struct consw xennull_con = {
700 .owner = THIS_MODULE,
701 .con_startup = xennullcon_startup,
702 .con_init = DUMMY,
703 .con_deinit = DUMMY,
704 .con_clear = DUMMY,
705 .con_putc = DUMMY,
706 .con_putcs = DUMMY,
707 .con_cursor = DUMMY,
708 .con_scroll = DUMMY,
709 .con_bmove = DUMMY,
710 .con_switch = DUMMY,
711 .con_blank = DUMMY,
712 .con_font_set = DUMMY,
713 .con_font_get = DUMMY,
714 .con_font_default = DUMMY,
715 .con_font_copy = DUMMY,
716 .con_set_palette = DUMMY,
717 .con_scrolldelta = DUMMY,
718 };
719 #endif
720 #endif
722 static int __init xencons_init(void)
723 {
724 int rc;
726 if ( xc_mode == XC_OFF )
727 return 0;
729 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
730 xencons_driver = alloc_tty_driver((xc_mode == XC_SERIAL) ?
731 1 : MAX_NR_CONSOLES);
732 if ( xencons_driver == NULL )
733 return -ENOMEM;
734 #else
735 memset(&xencons_driver, 0, sizeof(struct tty_driver));
736 xencons_driver.magic = TTY_DRIVER_MAGIC;
737 xencons_driver.refcount = &xencons_refcount;
738 xencons_driver.table = xencons_table;
739 xencons_driver.num = (xc_mode == XC_SERIAL) ? 1 : MAX_NR_CONSOLES;
740 #endif
742 DRV(xencons_driver)->major = TTY_MAJOR;
743 DRV(xencons_driver)->type = TTY_DRIVER_TYPE_SERIAL;
744 DRV(xencons_driver)->subtype = SERIAL_TYPE_NORMAL;
745 DRV(xencons_driver)->init_termios = tty_std_termios;
746 DRV(xencons_driver)->flags =
747 TTY_DRIVER_REAL_RAW | TTY_DRIVER_RESET_TERMIOS | TTY_DRIVER_NO_DEVFS;
748 DRV(xencons_driver)->termios = xencons_termios;
749 DRV(xencons_driver)->termios_locked = xencons_termios_locked;
751 if ( xc_mode == XC_SERIAL )
752 {
753 DRV(xencons_driver)->name = "ttyS";
754 DRV(xencons_driver)->minor_start = 64 + xc_num;
755 DRV(xencons_driver)->name_base = 0 + xc_num;
756 }
757 else
758 {
759 DRV(xencons_driver)->name = "tty";
760 DRV(xencons_driver)->minor_start = xc_num;
761 DRV(xencons_driver)->name_base = xc_num;
762 }
764 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
765 tty_set_operations(xencons_driver, &xencons_ops);
766 #else
767 xencons_driver.open = xencons_open;
768 xencons_driver.close = xencons_close;
769 xencons_driver.write = xencons_write;
770 xencons_driver.write_room = xencons_write_room;
771 xencons_driver.put_char = xencons_put_char;
772 xencons_driver.flush_chars = xencons_flush_chars;
773 xencons_driver.chars_in_buffer = xencons_chars_in_buffer;
774 xencons_driver.send_xchar = xencons_send_xchar;
775 xencons_driver.flush_buffer = xencons_flush_buffer;
776 xencons_driver.throttle = xencons_throttle;
777 xencons_driver.unthrottle = xencons_unthrottle;
778 xencons_driver.wait_until_sent = xencons_wait_until_sent;
779 #endif
781 if ( (rc = tty_register_driver(DRV(xencons_driver))) != 0 )
782 {
783 printk("WARNING: Failed to register Xen virtual "
784 "console driver as '%s%d'\n",
785 DRV(xencons_driver)->name, DRV(xencons_driver)->name_base);
786 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
787 put_tty_driver(xencons_driver);
788 xencons_driver = NULL;
789 #endif
790 return rc;
791 }
793 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,0)
794 tty_register_device(xencons_driver, 0, NULL);
795 #endif
797 if ( xen_start_info.flags & SIF_INITDOMAIN )
798 {
799 xencons_priv_irq = bind_virq_to_irq(VIRQ_CONSOLE);
800 (void)request_irq(xencons_priv_irq,
801 xencons_priv_interrupt, 0, "console", NULL);
802 }
803 else
804 {
805 (void)ctrl_if_register_receiver(CMSG_CONSOLE, xencons_rx, 0);
806 }
808 printk("Xen virtual console successfully installed as %s%d\n",
809 DRV(xencons_driver)->name,
810 DRV(xencons_driver)->name_base );
812 return 0;
813 }
815 module_init(xencons_init);