ia64/linux-2.6.18-xen.hg

view drivers/xen/console/console.c @ 762:a070228ac76e

add hvc compatibility mode to xencons.

Makes switching back and forth with a pvops kernel easier. Taken from
http://lists.alioth.debian.org/pipermail/pkg-xen-devel/2008-October/002098.html
http://svn.debian.org/viewsvn/kernel?rev=12337&view=rev with thanks to
Bastian Blank.

Signed-off-by: Ian Campbell <ian.campbell@citrix.com>
author Ian Campbell <ian.campbell@citrix.com>
date Thu Dec 11 13:38:48 2008 +0000 (2008-12-11)
parents d34182a37ba9
children
line source
1 /******************************************************************************
2 * console.c
3 *
4 * Virtual console driver.
5 *
6 * Copyright (c) 2002-2004, K A Fraser.
7 *
8 * This program is free software; you can redistribute it and/or
9 * modify it under the terms of the GNU General Public License version 2
10 * as published by the Free Software Foundation; or, when distributed
11 * separately from the Linux kernel or incorporated into other
12 * software packages, subject to the following license:
13 *
14 * Permission is hereby granted, free of charge, to any person obtaining a copy
15 * of this source file (the "Software"), to deal in the Software without
16 * restriction, including without limitation the rights to use, copy, modify,
17 * merge, publish, distribute, sublicense, and/or sell copies of the Software,
18 * and to permit persons to whom the Software is furnished to do so, subject to
19 * the following conditions:
20 *
21 * The above copyright notice and this permission notice shall be included in
22 * all copies or substantial portions of the Software.
23 *
24 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
25 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
26 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
27 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
28 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
29 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
30 * IN THE SOFTWARE.
31 */
33 #include <linux/version.h>
34 #include <linux/module.h>
35 #include <linux/errno.h>
36 #include <linux/signal.h>
37 #include <linux/sched.h>
38 #include <linux/interrupt.h>
39 #include <linux/tty.h>
40 #include <linux/tty_flip.h>
41 #include <linux/serial.h>
42 #include <linux/major.h>
43 #include <linux/ptrace.h>
44 #include <linux/ioport.h>
45 #include <linux/mm.h>
46 #include <linux/slab.h>
47 #include <linux/init.h>
48 #include <linux/console.h>
49 #include <linux/bootmem.h>
50 #include <linux/sysrq.h>
51 #include <linux/screen_info.h>
52 #include <linux/vt.h>
53 #include <asm/io.h>
54 #include <asm/irq.h>
55 #include <asm/uaccess.h>
56 #include <xen/interface/xen.h>
57 #include <xen/interface/event_channel.h>
58 #include <asm/hypervisor.h>
59 #include <xen/evtchn.h>
60 #include <xen/xenbus.h>
61 #include <xen/xencons.h>
63 /*
64 * Modes:
65 * 'xencons=off' [XC_OFF]: Console is disabled.
66 * 'xencons=tty' [XC_TTY]: Console attached to '/dev/tty[0-9]+'.
67 * 'xencons=ttyS' [XC_SERIAL]: Console attached to '/dev/ttyS[0-9]+'.
68 * 'xencons=xvc' [XC_XVC]: Console attached to '/dev/xvc0'.
69 * 'xencons=hvc' [XC_HVC]: Console attached to '/dev/hvc0'.
70 * default: XC_XVC
71 *
72 * NB. In mode XC_TTY, we create dummy consoles for tty2-63. This suppresses
73 * warnings from standard distro startup scripts.
74 */
75 static enum {
76 XC_OFF, XC_TTY, XC_SERIAL, XC_XVC, XC_HVC
77 } xc_mode = XC_XVC;
78 static int xc_num = -1;
80 /* /dev/xvc0 device number allocated by lanana.org. */
81 #define XEN_XVC_MAJOR 204
82 #define XEN_XVC_MINOR 191
84 /* /dev/hvc0 device number */
85 #define XEN_HVC_MAJOR 229
86 #define XEN_HVC_MINOR 0
88 #ifdef CONFIG_MAGIC_SYSRQ
89 static unsigned long sysrq_requested;
90 extern int sysrq_enabled;
91 #endif
93 static int __init xencons_setup(char *str)
94 {
95 char *q;
96 int n;
97 extern int console_use_vt;
99 console_use_vt = 1;
100 if (!strncmp(str, "ttyS", 4)) {
101 xc_mode = XC_SERIAL;
102 str += 4;
103 } else if (!strncmp(str, "tty", 3)) {
104 xc_mode = XC_TTY;
105 str += 3;
106 console_use_vt = 0;
107 } else if (!strncmp(str, "xvc", 3)) {
108 xc_mode = XC_XVC;
109 str += 3;
110 } else if (!strncmp(str, "hvc", 3)) {
111 xc_mode = XC_HVC;
112 str += 3;
113 } else if (!strncmp(str, "off", 3)) {
114 xc_mode = XC_OFF;
115 str += 3;
116 }
118 n = simple_strtol(str, &q, 10);
119 if (q != str)
120 xc_num = n;
122 return 1;
123 }
124 __setup("xencons=", xencons_setup);
126 /* The kernel and user-land drivers share a common transmit buffer. */
127 static unsigned int wbuf_size = 4096;
128 #define WBUF_MASK(_i) ((_i)&(wbuf_size-1))
129 static char *wbuf;
130 static unsigned int wc, wp; /* write_cons, write_prod */
132 static int __init xencons_bufsz_setup(char *str)
133 {
134 unsigned int goal;
135 goal = simple_strtoul(str, NULL, 0);
136 if (goal) {
137 goal = roundup_pow_of_two(goal);
138 if (wbuf_size < goal)
139 wbuf_size = goal;
140 }
141 return 1;
142 }
143 __setup("xencons_bufsz=", xencons_bufsz_setup);
145 /* This lock protects accesses to the common transmit buffer. */
146 static DEFINE_SPINLOCK(xencons_lock);
148 /* Common transmit-kick routine. */
149 static void __xencons_tx_flush(void);
151 static struct tty_driver *xencons_driver;
153 /******************** Kernel console driver ********************************/
155 static void kcons_write(struct console *c, const char *s, unsigned int count)
156 {
157 int i = 0;
158 unsigned long flags;
160 spin_lock_irqsave(&xencons_lock, flags);
162 while (i < count) {
163 for (; i < count; i++) {
164 if ((wp - wc) >= (wbuf_size - 1))
165 break;
166 if ((wbuf[WBUF_MASK(wp++)] = s[i]) == '\n')
167 wbuf[WBUF_MASK(wp++)] = '\r';
168 }
170 __xencons_tx_flush();
171 }
173 spin_unlock_irqrestore(&xencons_lock, flags);
174 }
176 static void kcons_write_dom0(struct console *c, const char *s, unsigned int count)
177 {
179 while (count > 0) {
180 int rc;
181 rc = HYPERVISOR_console_io( CONSOLEIO_write, count, (char *)s);
182 if (rc <= 0)
183 break;
184 count -= rc;
185 s += rc;
186 }
187 }
189 static struct tty_driver *kcons_device(struct console *c, int *index)
190 {
191 *index = 0;
192 return xencons_driver;
193 }
195 static struct console kcons_info = {
196 .device = kcons_device,
197 .flags = CON_PRINTBUFFER | CON_ENABLED,
198 .index = -1,
199 };
201 static int __init xen_console_init(void)
202 {
203 if (!is_running_on_xen())
204 goto out;
206 if (is_initial_xendomain()) {
207 kcons_info.write = kcons_write_dom0;
208 } else {
209 if (!xen_start_info->console.domU.evtchn)
210 goto out;
211 kcons_info.write = kcons_write;
212 }
214 switch (xc_mode) {
215 case XC_XVC:
216 strcpy(kcons_info.name, "xvc");
217 if (xc_num == -1)
218 xc_num = 0;
219 break;
221 case XC_HVC:
222 strcpy(kcons_info.name, "hvc");
223 if (xc_num == -1)
224 xc_num = 0;
225 if (!is_initial_xendomain())
226 add_preferred_console(kcons_info.name, xc_num, NULL);
227 break;
229 case XC_SERIAL:
230 strcpy(kcons_info.name, "ttyS");
231 if (xc_num == -1)
232 xc_num = 0;
233 break;
235 case XC_TTY:
236 strcpy(kcons_info.name, "tty");
237 if (xc_num == -1)
238 xc_num = 1;
239 break;
241 default:
242 goto out;
243 }
245 wbuf = alloc_bootmem(wbuf_size);
247 register_console(&kcons_info);
249 out:
250 return 0;
251 }
252 console_initcall(xen_console_init);
254 /*** Useful function for console debugging -- goes straight to Xen. ***/
255 asmlinkage int xprintk(const char *fmt, ...)
256 {
257 va_list args;
258 int printk_len;
259 static char printk_buf[1024];
261 /* Emit the output into the temporary buffer */
262 va_start(args, fmt);
263 printk_len = vsnprintf(printk_buf, sizeof(printk_buf), fmt, args);
264 va_end(args);
266 /* Send the processed output directly to Xen. */
267 kcons_write_dom0(NULL, printk_buf, printk_len);
269 return 0;
270 }
272 /*** Forcibly flush console data before dying. ***/
273 void xencons_force_flush(void)
274 {
275 int sz;
277 /* Emergency console is synchronous, so there's nothing to flush. */
278 if (!is_running_on_xen() ||
279 is_initial_xendomain() ||
280 !xen_start_info->console.domU.evtchn)
281 return;
283 /* Spin until console data is flushed through to the daemon. */
284 while (wc != wp) {
285 int sent = 0;
286 if ((sz = wp - wc) == 0)
287 continue;
288 sent = xencons_ring_send(&wbuf[WBUF_MASK(wc)], sz);
289 if (sent > 0)
290 wc += sent;
291 }
292 }
295 void __init dom0_init_screen_info(const struct dom0_vga_console_info *info, size_t size)
296 {
297 /* This is drawn from a dump from vgacon:startup in
298 * standard Linux. */
299 screen_info.orig_video_mode = 3;
300 screen_info.orig_video_isVGA = 1;
301 screen_info.orig_video_lines = 25;
302 screen_info.orig_video_cols = 80;
303 screen_info.orig_video_ega_bx = 3;
304 screen_info.orig_video_points = 16;
305 screen_info.orig_y = screen_info.orig_video_lines - 1;
307 switch (info->video_type) {
308 case XEN_VGATYPE_TEXT_MODE_3:
309 if (size < offsetof(struct dom0_vga_console_info, u.text_mode_3)
310 + sizeof(info->u.text_mode_3))
311 break;
312 screen_info.orig_video_lines = info->u.text_mode_3.rows;
313 screen_info.orig_video_cols = info->u.text_mode_3.columns;
314 screen_info.orig_x = info->u.text_mode_3.cursor_x;
315 screen_info.orig_y = info->u.text_mode_3.cursor_y;
316 screen_info.orig_video_points =
317 info->u.text_mode_3.font_height;
318 break;
320 case XEN_VGATYPE_VESA_LFB:
321 if (size < offsetof(struct dom0_vga_console_info,
322 u.vesa_lfb.gbl_caps))
323 break;
324 screen_info.orig_video_isVGA = VIDEO_TYPE_VLFB;
325 screen_info.lfb_width = info->u.vesa_lfb.width;
326 screen_info.lfb_height = info->u.vesa_lfb.height;
327 screen_info.lfb_depth = info->u.vesa_lfb.bits_per_pixel;
328 screen_info.lfb_base = info->u.vesa_lfb.lfb_base;
329 screen_info.lfb_size = info->u.vesa_lfb.lfb_size;
330 screen_info.lfb_linelength = info->u.vesa_lfb.bytes_per_line;
331 screen_info.red_size = info->u.vesa_lfb.red_size;
332 screen_info.red_pos = info->u.vesa_lfb.red_pos;
333 screen_info.green_size = info->u.vesa_lfb.green_size;
334 screen_info.green_pos = info->u.vesa_lfb.green_pos;
335 screen_info.blue_size = info->u.vesa_lfb.blue_size;
336 screen_info.blue_pos = info->u.vesa_lfb.blue_pos;
337 screen_info.rsvd_size = info->u.vesa_lfb.rsvd_size;
338 screen_info.rsvd_pos = info->u.vesa_lfb.rsvd_pos;
339 if (size >= offsetof(struct dom0_vga_console_info,
340 u.vesa_lfb.gbl_caps)
341 + sizeof(info->u.vesa_lfb.gbl_caps))
342 screen_info.capabilities = info->u.vesa_lfb.gbl_caps;
343 if (size >= offsetof(struct dom0_vga_console_info,
344 u.vesa_lfb.mode_attrs)
345 + sizeof(info->u.vesa_lfb.mode_attrs))
346 screen_info.vesa_attributes = info->u.vesa_lfb.mode_attrs;
347 break;
348 }
349 }
352 /******************** User-space console driver (/dev/console) ************/
354 #define DRV(_d) (_d)
355 #define DUMMY_TTY(_tty) ((xc_mode == XC_TTY) && \
356 ((_tty)->index != (xc_num - 1)))
358 static struct termios *xencons_termios[MAX_NR_CONSOLES];
359 static struct termios *xencons_termios_locked[MAX_NR_CONSOLES];
360 static struct tty_struct *xencons_tty;
361 static int xencons_priv_irq;
362 static char x_char;
364 void xencons_rx(char *buf, unsigned len, struct pt_regs *regs)
365 {
366 int i;
367 unsigned long flags;
369 spin_lock_irqsave(&xencons_lock, flags);
370 if (xencons_tty == NULL)
371 goto out;
373 for (i = 0; i < len; i++) {
374 #ifdef CONFIG_MAGIC_SYSRQ
375 if (sysrq_enabled) {
376 if (buf[i] == '\x0f') { /* ^O */
377 if (!sysrq_requested) {
378 sysrq_requested = jiffies;
379 continue; /* don't print sysrq key */
380 }
381 sysrq_requested = 0;
382 } else if (sysrq_requested) {
383 unsigned long sysrq_timeout =
384 sysrq_requested + HZ*2;
385 sysrq_requested = 0;
386 if (time_before(jiffies, sysrq_timeout)) {
387 spin_unlock_irqrestore(
388 &xencons_lock, flags);
389 handle_sysrq(
390 buf[i], regs, xencons_tty);
391 spin_lock_irqsave(
392 &xencons_lock, flags);
393 continue;
394 }
395 }
396 }
397 #endif
398 tty_insert_flip_char(xencons_tty, buf[i], 0);
399 }
400 tty_flip_buffer_push(xencons_tty);
402 out:
403 spin_unlock_irqrestore(&xencons_lock, flags);
404 }
406 static void __xencons_tx_flush(void)
407 {
408 int sent, sz, work_done = 0;
410 if (x_char) {
411 if (is_initial_xendomain())
412 kcons_write_dom0(NULL, &x_char, 1);
413 else
414 while (x_char)
415 if (xencons_ring_send(&x_char, 1) == 1)
416 break;
417 x_char = 0;
418 work_done = 1;
419 }
421 while (wc != wp) {
422 sz = wp - wc;
423 if (sz > (wbuf_size - WBUF_MASK(wc)))
424 sz = wbuf_size - WBUF_MASK(wc);
425 if (is_initial_xendomain()) {
426 kcons_write_dom0(NULL, &wbuf[WBUF_MASK(wc)], sz);
427 wc += sz;
428 } else {
429 sent = xencons_ring_send(&wbuf[WBUF_MASK(wc)], sz);
430 if (sent == 0)
431 break;
432 wc += sent;
433 }
434 work_done = 1;
435 }
437 if (work_done && (xencons_tty != NULL)) {
438 wake_up_interruptible(&xencons_tty->write_wait);
439 if ((xencons_tty->flags & (1 << TTY_DO_WRITE_WAKEUP)) &&
440 (xencons_tty->ldisc.write_wakeup != NULL))
441 (xencons_tty->ldisc.write_wakeup)(xencons_tty);
442 }
443 }
445 void xencons_tx(void)
446 {
447 unsigned long flags;
449 spin_lock_irqsave(&xencons_lock, flags);
450 __xencons_tx_flush();
451 spin_unlock_irqrestore(&xencons_lock, flags);
452 }
454 /* Privileged receive callback and transmit kicker. */
455 static irqreturn_t xencons_priv_interrupt(int irq, void *dev_id,
456 struct pt_regs *regs)
457 {
458 static char rbuf[16];
459 int l;
461 while ((l = HYPERVISOR_console_io(CONSOLEIO_read, 16, rbuf)) > 0)
462 xencons_rx(rbuf, l, regs);
464 xencons_tx();
466 return IRQ_HANDLED;
467 }
469 static int xencons_write_room(struct tty_struct *tty)
470 {
471 return wbuf_size - (wp - wc);
472 }
474 static int xencons_chars_in_buffer(struct tty_struct *tty)
475 {
476 return wp - wc;
477 }
479 static void xencons_send_xchar(struct tty_struct *tty, char ch)
480 {
481 unsigned long flags;
483 if (DUMMY_TTY(tty))
484 return;
486 spin_lock_irqsave(&xencons_lock, flags);
487 x_char = ch;
488 __xencons_tx_flush();
489 spin_unlock_irqrestore(&xencons_lock, flags);
490 }
492 static void xencons_throttle(struct tty_struct *tty)
493 {
494 if (DUMMY_TTY(tty))
495 return;
497 if (I_IXOFF(tty))
498 xencons_send_xchar(tty, STOP_CHAR(tty));
499 }
501 static void xencons_unthrottle(struct tty_struct *tty)
502 {
503 if (DUMMY_TTY(tty))
504 return;
506 if (I_IXOFF(tty)) {
507 if (x_char != 0)
508 x_char = 0;
509 else
510 xencons_send_xchar(tty, START_CHAR(tty));
511 }
512 }
514 static void xencons_flush_buffer(struct tty_struct *tty)
515 {
516 unsigned long flags;
518 if (DUMMY_TTY(tty))
519 return;
521 spin_lock_irqsave(&xencons_lock, flags);
522 wc = wp = 0;
523 spin_unlock_irqrestore(&xencons_lock, flags);
524 }
526 static inline int __xencons_put_char(int ch)
527 {
528 char _ch = (char)ch;
529 if ((wp - wc) == wbuf_size)
530 return 0;
531 wbuf[WBUF_MASK(wp++)] = _ch;
532 return 1;
533 }
535 static int xencons_write(
536 struct tty_struct *tty,
537 const unsigned char *buf,
538 int count)
539 {
540 int i;
541 unsigned long flags;
543 if (DUMMY_TTY(tty))
544 return count;
546 spin_lock_irqsave(&xencons_lock, flags);
548 for (i = 0; i < count; i++)
549 if (!__xencons_put_char(buf[i]))
550 break;
552 if (i != 0)
553 __xencons_tx_flush();
555 spin_unlock_irqrestore(&xencons_lock, flags);
557 return i;
558 }
560 static void xencons_put_char(struct tty_struct *tty, u_char ch)
561 {
562 unsigned long flags;
564 if (DUMMY_TTY(tty))
565 return;
567 spin_lock_irqsave(&xencons_lock, flags);
568 (void)__xencons_put_char(ch);
569 spin_unlock_irqrestore(&xencons_lock, flags);
570 }
572 static void xencons_flush_chars(struct tty_struct *tty)
573 {
574 unsigned long flags;
576 if (DUMMY_TTY(tty))
577 return;
579 spin_lock_irqsave(&xencons_lock, flags);
580 __xencons_tx_flush();
581 spin_unlock_irqrestore(&xencons_lock, flags);
582 }
584 static void xencons_wait_until_sent(struct tty_struct *tty, int timeout)
585 {
586 unsigned long orig_jiffies = jiffies;
588 if (DUMMY_TTY(tty))
589 return;
591 while (DRV(tty->driver)->chars_in_buffer(tty)) {
592 set_current_state(TASK_INTERRUPTIBLE);
593 schedule_timeout(1);
594 if (signal_pending(current))
595 break;
596 if (timeout && time_after(jiffies, orig_jiffies + timeout))
597 break;
598 }
600 set_current_state(TASK_RUNNING);
601 }
603 static int xencons_open(struct tty_struct *tty, struct file *filp)
604 {
605 unsigned long flags;
607 if (DUMMY_TTY(tty))
608 return 0;
610 spin_lock_irqsave(&xencons_lock, flags);
611 tty->driver_data = NULL;
612 if (xencons_tty == NULL)
613 xencons_tty = tty;
614 __xencons_tx_flush();
615 spin_unlock_irqrestore(&xencons_lock, flags);
617 return 0;
618 }
620 static void xencons_close(struct tty_struct *tty, struct file *filp)
621 {
622 unsigned long flags;
624 if (DUMMY_TTY(tty))
625 return;
627 mutex_lock(&tty_mutex);
629 if (tty->count != 1) {
630 mutex_unlock(&tty_mutex);
631 return;
632 }
634 /* Prevent other threads from re-opening this tty. */
635 set_bit(TTY_CLOSING, &tty->flags);
636 mutex_unlock(&tty_mutex);
638 tty->closing = 1;
639 tty_wait_until_sent(tty, 0);
640 if (DRV(tty->driver)->flush_buffer != NULL)
641 DRV(tty->driver)->flush_buffer(tty);
642 if (tty->ldisc.flush_buffer != NULL)
643 tty->ldisc.flush_buffer(tty);
644 tty->closing = 0;
645 spin_lock_irqsave(&xencons_lock, flags);
646 xencons_tty = NULL;
647 spin_unlock_irqrestore(&xencons_lock, flags);
648 }
650 static struct tty_operations xencons_ops = {
651 .open = xencons_open,
652 .close = xencons_close,
653 .write = xencons_write,
654 .write_room = xencons_write_room,
655 .put_char = xencons_put_char,
656 .flush_chars = xencons_flush_chars,
657 .chars_in_buffer = xencons_chars_in_buffer,
658 .send_xchar = xencons_send_xchar,
659 .flush_buffer = xencons_flush_buffer,
660 .throttle = xencons_throttle,
661 .unthrottle = xencons_unthrottle,
662 .wait_until_sent = xencons_wait_until_sent,
663 };
665 static int __init xencons_init(void)
666 {
667 int rc;
669 if (!is_running_on_xen())
670 return -ENODEV;
672 if (xc_mode == XC_OFF)
673 return 0;
675 if (!is_initial_xendomain()) {
676 rc = xencons_ring_init();
677 if (rc)
678 return rc;
679 }
681 xencons_driver = alloc_tty_driver((xc_mode == XC_TTY) ?
682 MAX_NR_CONSOLES : 1);
683 if (xencons_driver == NULL)
684 return -ENOMEM;
686 DRV(xencons_driver)->name = "xencons";
687 DRV(xencons_driver)->major = TTY_MAJOR;
688 DRV(xencons_driver)->type = TTY_DRIVER_TYPE_SERIAL;
689 DRV(xencons_driver)->subtype = SERIAL_TYPE_NORMAL;
690 DRV(xencons_driver)->init_termios = tty_std_termios;
691 DRV(xencons_driver)->flags =
692 TTY_DRIVER_REAL_RAW |
693 TTY_DRIVER_RESET_TERMIOS;
694 DRV(xencons_driver)->termios = xencons_termios;
695 DRV(xencons_driver)->termios_locked = xencons_termios_locked;
697 switch (xc_mode) {
698 case XC_XVC:
699 DRV(xencons_driver)->name = "xvc";
700 DRV(xencons_driver)->major = XEN_XVC_MAJOR;
701 DRV(xencons_driver)->minor_start = XEN_XVC_MINOR;
702 DRV(xencons_driver)->name_base = xc_num;
703 break;
704 case XC_HVC:
705 DRV(xencons_driver)->name = "hvc";
706 DRV(xencons_driver)->major = XEN_HVC_MAJOR;
707 DRV(xencons_driver)->minor_start = XEN_HVC_MINOR;
708 DRV(xencons_driver)->name_base = xc_num;
709 break;
710 case XC_SERIAL:
711 DRV(xencons_driver)->name = "ttyS";
712 DRV(xencons_driver)->minor_start = 64 + xc_num;
713 DRV(xencons_driver)->name_base = xc_num;
714 break;
715 default:
716 DRV(xencons_driver)->name = "tty";
717 DRV(xencons_driver)->minor_start = 1;
718 DRV(xencons_driver)->name_base = 1;
719 break;
720 }
722 tty_set_operations(xencons_driver, &xencons_ops);
724 if ((rc = tty_register_driver(DRV(xencons_driver))) != 0) {
725 printk("WARNING: Failed to register Xen virtual "
726 "console driver as '%s%d'\n",
727 DRV(xencons_driver)->name,
728 DRV(xencons_driver)->name_base);
729 put_tty_driver(xencons_driver);
730 xencons_driver = NULL;
731 return rc;
732 }
734 if (is_initial_xendomain()) {
735 xencons_priv_irq = bind_virq_to_irqhandler(
736 VIRQ_CONSOLE,
737 0,
738 xencons_priv_interrupt,
739 0,
740 "console",
741 NULL);
742 BUG_ON(xencons_priv_irq < 0);
743 }
745 printk("Xen virtual console successfully installed as %s%d\n",
746 DRV(xencons_driver)->name, xc_num);
748 return 0;
749 }
751 module_init(xencons_init);
753 MODULE_LICENSE("Dual BSD/GPL");