Update to 3.4-final.
[linux-flexiantxendom0-3.2.10.git] / drivers / xen / console / console.c
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  */
32
33 #include <linux/module.h>
34 #include <linux/errno.h>
35 #include <linux/signal.h>
36 #include <linux/sched.h>
37 #include <linux/interrupt.h>
38 #include <linux/tty.h>
39 #include <linux/tty_flip.h>
40 #include <linux/serial.h>
41 #include <linux/major.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/sysrq.h>
48 #include <linux/vt.h>
49 #include <xen/interface/xen.h>
50 #include <xen/interface/event_channel.h>
51 #include "xencons.h"
52
53 /*
54  * Modes:
55  *  'xencons=off'  [XC_OFF]:     Console is disabled.
56  *  'xencons=tty'  [XC_TTY]:     Console attached to '/dev/tty[0-9]+'.
57  *  'xencons=ttyS' [XC_SERIAL]:  Console attached to '/dev/ttyS[0-9]+'.
58  *  'xencons=xvc'  [XC_XVC]:     Console attached to '/dev/xvc0'.
59  *  'xencons=hvc'  [XC_HVC]:     Console attached to '/dev/hvc0'.
60  *  default:                     XC_XVC
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 {
66         XC_OFF, XC_TTY, XC_SERIAL, XC_XVC, XC_HVC
67 } xc_mode = XC_XVC;
68 static int xc_num = -1;
69
70 /* /dev/xvc0 device number allocated by lanana.org. */
71 #define XEN_XVC_MAJOR 204
72 #define XEN_XVC_MINOR 191
73
74 /* /dev/hvc0 device number */
75 #define XEN_HVC_MAJOR 229
76 #define XEN_HVC_MINOR 0
77
78 static int __init xencons_setup(char *str)
79 {
80         char *q;
81         int n;
82
83         console_use_vt = 1;
84         if (!strncmp(str, "ttyS", 4)) {
85                 xc_mode = XC_SERIAL;
86                 str += 4;
87         } else if (!strncmp(str, "tty", 3)) {
88                 xc_mode = XC_TTY;
89                 str += 3;
90                 console_use_vt = 0;
91         } else if (!strncmp(str, "xvc", 3)) {
92                 xc_mode = XC_XVC;
93                 str += 3;
94         } else if (!strncmp(str, "hvc", 3)) {
95                 xc_mode = XC_HVC;
96                 str += 3;
97         } else if (!strncmp(str, "off", 3)) {
98                 xc_mode = XC_OFF;
99                 str += 3;
100         }
101
102         n = simple_strtol(str, &q, 10);
103         if (q != str)
104                 xc_num = n;
105
106         return 1;
107 }
108 __setup("xencons=", xencons_setup);
109
110 /* The kernel and user-land drivers share a common transmit buffer. */
111 static unsigned int wbuf_size = 4096;
112 #define WBUF_MASK(_i) ((_i)&(wbuf_size-1))
113 static char *wbuf;
114 static unsigned int wc, wp; /* write_cons, write_prod */
115
116 static int __init xencons_bufsz_setup(char *str)
117 {
118         unsigned int goal;
119         goal = simple_strtoul(str, NULL, 0);
120         if (goal) {
121                 goal = roundup_pow_of_two(goal);
122                 if (wbuf_size < goal)
123                         wbuf_size = goal;
124         }
125         return 1;
126 }
127 __setup("xencons_bufsz=", xencons_bufsz_setup);
128
129 /* This lock protects accesses to the common transmit buffer. */
130 static DEFINE_SPINLOCK(xencons_lock);
131
132 /* Common transmit-kick routine. */
133 static void __xencons_tx_flush(void);
134
135 static struct tty_driver *xencons_driver;
136
137 /******************** Kernel console driver ********************************/
138
139 static void kcons_write(struct console *c, const char *s, unsigned int count)
140 {
141         int           i = 0;
142         unsigned long flags;
143
144         spin_lock_irqsave(&xencons_lock, flags);
145
146         while (i < count) {
147                 for (; 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                 }
153
154                 __xencons_tx_flush();
155         }
156
157         spin_unlock_irqrestore(&xencons_lock, flags);
158 }
159
160 static void kcons_write_dom0(struct console *c, const char *s, unsigned int count)
161 {
162
163         while (count > 0) {
164                 int rc;
165                 rc = HYPERVISOR_console_io( CONSOLEIO_write, count, (char *)s);
166                 if (rc <= 0)
167                         break;
168                 count -= rc;
169                 s += rc;
170         }
171 }
172
173 static struct tty_driver *kcons_device(struct console *c, int *index)
174 {
175         *index = 0;
176         return xencons_driver;
177 }
178
179 static struct console kcons_info = {
180         .device = kcons_device,
181         .flags  = CON_PRINTBUFFER | CON_ENABLED,
182         .index  = -1,
183 };
184
185 static int __init xen_console_init(void)
186 {
187         if (!is_running_on_xen())
188                 goto out;
189
190         if (is_initial_xendomain()) {
191                 kcons_info.write = kcons_write_dom0;
192         } else {
193                 if (!xen_start_info->console.domU.evtchn)
194                         goto out;
195                 kcons_info.write = kcons_write;
196         }
197
198         switch (xc_mode) {
199         case XC_XVC:
200                 strcpy(kcons_info.name, "xvc");
201                 if (xc_num == -1)
202                         xc_num = 0;
203                 break;
204
205         case XC_HVC:
206                 strcpy(kcons_info.name, "hvc");
207                 if (xc_num == -1)
208                         xc_num = 0;
209                 if (!is_initial_xendomain())
210                         add_preferred_console(kcons_info.name, xc_num, NULL);
211                 break;
212
213         case XC_SERIAL:
214                 strcpy(kcons_info.name, "ttyS");
215                 if (xc_num == -1)
216                         xc_num = 0;
217                 break;
218
219         case XC_TTY:
220                 strcpy(kcons_info.name, "tty");
221                 if (xc_num == -1)
222                         xc_num = 1;
223                 break;
224
225         default:
226                 goto out;
227         }
228
229         wbuf = kmalloc(wbuf_size, GFP_KERNEL);
230
231         register_console(&kcons_info);
232
233  out:
234         return 0;
235 }
236 console_initcall(xen_console_init);
237
238 #ifdef CONFIG_XEN_PRIVILEGED_GUEST
239 /*** Useful function for console debugging -- goes straight to Xen. ***/
240 int xprintk(const char *fmt, ...)
241 {
242         va_list args;
243         int printk_len;
244         static char printk_buf[1024];
245
246         /* Emit the output into the temporary buffer */
247         va_start(args, fmt);
248         printk_len = vsnprintf(printk_buf, sizeof(printk_buf), fmt, args);
249         va_end(args);
250
251         /* Send the processed output directly to Xen. */
252         kcons_write_dom0(NULL, printk_buf, printk_len);
253
254         return 0;
255 }
256 #endif
257
258 /*** Forcibly flush console data before dying. ***/
259 void xencons_force_flush(void)
260 {
261         int sz;
262
263         /* Emergency console is synchronous, so there's nothing to flush. */
264         if (!is_running_on_xen() ||
265             is_initial_xendomain() ||
266             !xen_start_info->console.domU.evtchn)
267                 return;
268
269         /* Spin until console data is flushed through to the daemon. */
270         while (wc != wp) {
271                 int sent = 0;
272                 if ((sz = wp - wc) == 0)
273                         continue;
274                 sent = xencons_ring_send(&wbuf[WBUF_MASK(wc)], sz);
275                 if (sent > 0)
276                         wc += sent;
277         }
278 }
279
280
281 #ifdef CONFIG_XEN_PRIVILEGED_GUEST
282 #include <linux/screen_info.h>
283
284 void __init dom0_init_screen_info(const struct dom0_vga_console_info *info, size_t size)
285 {
286         /* This is drawn from a dump from vgacon:startup in
287          * standard Linux. */
288         screen_info.orig_video_mode = 3;
289         screen_info.orig_video_isVGA = 1;
290         screen_info.orig_video_lines = 25;
291         screen_info.orig_video_cols = 80;
292         screen_info.orig_video_ega_bx = 3;
293         screen_info.orig_video_points = 16;
294         screen_info.orig_y = screen_info.orig_video_lines - 1;
295
296         switch (info->video_type) {
297         case XEN_VGATYPE_TEXT_MODE_3:
298                 if (size < offsetof(struct dom0_vga_console_info, u.text_mode_3)
299                            + sizeof(info->u.text_mode_3))
300                         break;
301                 screen_info.orig_video_lines = info->u.text_mode_3.rows;
302                 screen_info.orig_video_cols = info->u.text_mode_3.columns;
303                 screen_info.orig_x = info->u.text_mode_3.cursor_x;
304                 screen_info.orig_y = info->u.text_mode_3.cursor_y;
305                 screen_info.orig_video_points =
306                         info->u.text_mode_3.font_height;
307                 break;
308
309         case XEN_VGATYPE_VESA_LFB:
310         case XEN_VGATYPE_EFI_LFB:
311                 if (size < offsetof(struct dom0_vga_console_info,
312                                     u.vesa_lfb.gbl_caps))
313                         break;
314                 screen_info.orig_video_isVGA = VIDEO_TYPE_VLFB;
315                 screen_info.lfb_width = info->u.vesa_lfb.width;
316                 screen_info.lfb_height = info->u.vesa_lfb.height;
317                 screen_info.lfb_depth = info->u.vesa_lfb.bits_per_pixel;
318                 screen_info.lfb_base = info->u.vesa_lfb.lfb_base;
319                 screen_info.lfb_size = info->u.vesa_lfb.lfb_size;
320                 screen_info.lfb_linelength = info->u.vesa_lfb.bytes_per_line;
321                 screen_info.red_size = info->u.vesa_lfb.red_size;
322                 screen_info.red_pos = info->u.vesa_lfb.red_pos;
323                 screen_info.green_size = info->u.vesa_lfb.green_size;
324                 screen_info.green_pos = info->u.vesa_lfb.green_pos;
325                 screen_info.blue_size = info->u.vesa_lfb.blue_size;
326                 screen_info.blue_pos = info->u.vesa_lfb.blue_pos;
327                 screen_info.rsvd_size = info->u.vesa_lfb.rsvd_size;
328                 screen_info.rsvd_pos = info->u.vesa_lfb.rsvd_pos;
329                 if (info->video_type == XEN_VGATYPE_EFI_LFB) {
330                         screen_info.orig_video_isVGA = VIDEO_TYPE_EFI;
331                         break;
332                 }
333                 if (size >= offsetof(struct dom0_vga_console_info,
334                                      u.vesa_lfb.gbl_caps)
335                             + sizeof(info->u.vesa_lfb.gbl_caps))
336                         screen_info.capabilities = info->u.vesa_lfb.gbl_caps;
337                 if (size >= offsetof(struct dom0_vga_console_info,
338                                      u.vesa_lfb.mode_attrs)
339                             + sizeof(info->u.vesa_lfb.mode_attrs))
340                         screen_info.vesa_attributes = info->u.vesa_lfb.mode_attrs;
341                 break;
342         }
343 }
344 #endif
345
346
347 /******************** User-space console driver (/dev/console) ************/
348
349 #define DRV(_d)         (_d)
350 #define DUMMY_TTY(_tty) ((xc_mode == XC_TTY) &&         \
351                          ((_tty)->index != (xc_num - 1)))
352
353 static struct ktermios *xencons_termios[MAX_NR_CONSOLES];
354 static struct tty_struct *xencons_tty;
355 static int xencons_priv_irq;
356 static char x_char;
357
358 void xencons_rx(char *buf, unsigned len)
359 {
360         int           i;
361         unsigned long flags;
362
363         spin_lock_irqsave(&xencons_lock, flags);
364         if (xencons_tty == NULL)
365                 goto out;
366
367         for (i = 0; i < len; i++) {
368 #ifdef CONFIG_MAGIC_SYSRQ
369                 static unsigned long sysrq_requested;
370
371                 if (buf[i] == '\x0f') { /* ^O */
372                         if (!sysrq_requested) {
373                                 sysrq_requested = jiffies;
374                                 continue; /* don't print sysrq key */
375                         }
376                         sysrq_requested = 0;
377                 } else if (sysrq_requested) {
378                         unsigned long sysrq_timeout = sysrq_requested + HZ*2;
379
380                         sysrq_requested = 0;
381                         if (time_before(jiffies, sysrq_timeout)) {
382                                 spin_unlock_irqrestore(&xencons_lock, flags);
383                                 handle_sysrq(buf[i]);
384                                 spin_lock_irqsave(&xencons_lock, flags);
385                                 continue;
386                         }
387                 }
388 #endif
389                 tty_insert_flip_char(xencons_tty, buf[i], 0);
390         }
391         tty_flip_buffer_push(xencons_tty);
392
393  out:
394         spin_unlock_irqrestore(&xencons_lock, flags);
395 }
396
397 static void __xencons_tx_flush(void)
398 {
399         int sent, sz, work_done = 0;
400
401         if (x_char) {
402                 if (is_initial_xendomain())
403                         kcons_write_dom0(NULL, &x_char, 1);
404                 else
405                         while (x_char)
406                                 if (xencons_ring_send(&x_char, 1) == 1)
407                                         break;
408                 x_char = 0;
409                 work_done = 1;
410         }
411
412         while (wc != wp) {
413                 sz = wp - wc;
414                 if (sz > (wbuf_size - WBUF_MASK(wc)))
415                         sz = wbuf_size - WBUF_MASK(wc);
416                 if (is_initial_xendomain()) {
417                         kcons_write_dom0(NULL, &wbuf[WBUF_MASK(wc)], sz);
418                         wc += sz;
419                 } else {
420                         sent = xencons_ring_send(&wbuf[WBUF_MASK(wc)], sz);
421                         if (sent == 0)
422                                 break;
423                         wc += sent;
424                 }
425                 work_done = 1;
426         }
427
428         if (work_done && (xencons_tty != NULL)) {
429                 wake_up_interruptible(&xencons_tty->write_wait);
430                 tty_wakeup(xencons_tty);
431         }
432 }
433
434 void xencons_tx(void)
435 {
436         unsigned long flags;
437
438         spin_lock_irqsave(&xencons_lock, flags);
439         __xencons_tx_flush();
440         spin_unlock_irqrestore(&xencons_lock, flags);
441 }
442
443 /* Privileged receive callback and transmit kicker. */
444 static irqreturn_t xencons_priv_interrupt(int irq, void *dev_id)
445 {
446         static char rbuf[16];
447         int         l;
448
449         while ((l = HYPERVISOR_console_io(CONSOLEIO_read, 16, rbuf)) > 0)
450                 xencons_rx(rbuf, l);
451
452         xencons_tx();
453
454         return IRQ_HANDLED;
455 }
456
457 static int xencons_write_room(struct tty_struct *tty)
458 {
459         return wbuf_size - (wp - wc);
460 }
461
462 static int xencons_chars_in_buffer(struct tty_struct *tty)
463 {
464         return wp - wc;
465 }
466
467 static void xencons_send_xchar(struct tty_struct *tty, char ch)
468 {
469         unsigned long flags;
470
471         if (DUMMY_TTY(tty))
472                 return;
473
474         spin_lock_irqsave(&xencons_lock, flags);
475         x_char = ch;
476         __xencons_tx_flush();
477         spin_unlock_irqrestore(&xencons_lock, flags);
478 }
479
480 static void xencons_throttle(struct tty_struct *tty)
481 {
482         if (DUMMY_TTY(tty))
483                 return;
484
485         if (I_IXOFF(tty))
486                 xencons_send_xchar(tty, STOP_CHAR(tty));
487 }
488
489 static void xencons_unthrottle(struct tty_struct *tty)
490 {
491         if (DUMMY_TTY(tty))
492                 return;
493
494         if (I_IXOFF(tty)) {
495                 if (x_char != 0)
496                         x_char = 0;
497                 else
498                         xencons_send_xchar(tty, START_CHAR(tty));
499         }
500 }
501
502 static void xencons_flush_buffer(struct tty_struct *tty)
503 {
504         unsigned long flags;
505
506         if (DUMMY_TTY(tty))
507                 return;
508
509         spin_lock_irqsave(&xencons_lock, flags);
510         wc = wp = 0;
511         spin_unlock_irqrestore(&xencons_lock, flags);
512 }
513
514 static inline int __xencons_put_char(int ch)
515 {
516         char _ch = (char)ch;
517         if ((wp - wc) == wbuf_size)
518                 return 0;
519         wbuf[WBUF_MASK(wp++)] = _ch;
520         return 1;
521 }
522
523 static int xencons_write(
524         struct tty_struct *tty,
525         const unsigned char *buf,
526         int count)
527 {
528         int i;
529         unsigned long flags;
530
531         if (DUMMY_TTY(tty))
532                 return count;
533
534         spin_lock_irqsave(&xencons_lock, flags);
535
536         for (i = 0; i < count; i++)
537                 if (!__xencons_put_char(buf[i]))
538                         break;
539
540         if (i != 0)
541                 __xencons_tx_flush();
542
543         spin_unlock_irqrestore(&xencons_lock, flags);
544
545         return i;
546 }
547
548 static int xencons_put_char(struct tty_struct *tty, u_char ch)
549 {
550         unsigned long flags;
551         int ret;
552
553         if (DUMMY_TTY(tty))
554                 return 0;
555
556         spin_lock_irqsave(&xencons_lock, flags);
557         ret = __xencons_put_char(ch);
558         spin_unlock_irqrestore(&xencons_lock, flags);
559         return ret;
560 }
561
562 static void xencons_flush_chars(struct tty_struct *tty)
563 {
564         unsigned long flags;
565
566         if (DUMMY_TTY(tty))
567                 return;
568
569         spin_lock_irqsave(&xencons_lock, flags);
570         __xencons_tx_flush();
571         spin_unlock_irqrestore(&xencons_lock, flags);
572 }
573
574 static void xencons_wait_until_sent(struct tty_struct *tty, int timeout)
575 {
576         unsigned long orig_jiffies = jiffies;
577
578         if (DUMMY_TTY(tty))
579                 return;
580
581         while (tty_chars_in_buffer(tty)) {
582                 set_current_state(TASK_INTERRUPTIBLE);
583                 schedule_timeout(1);
584                 if (signal_pending(current))
585                         break;
586                 if (timeout && time_after(jiffies, orig_jiffies + timeout))
587                         break;
588         }
589
590         set_current_state(TASK_RUNNING);
591 }
592
593 static int xencons_open(struct tty_struct *tty, struct file *filp)
594 {
595         unsigned long flags;
596
597         if (DUMMY_TTY(tty))
598                 return 0;
599
600         spin_lock_irqsave(&xencons_lock, flags);
601         tty->driver_data = NULL;
602         if (xencons_tty == NULL)
603                 xencons_tty = tty;
604         __xencons_tx_flush();
605         spin_unlock_irqrestore(&xencons_lock, flags);
606
607         return 0;
608 }
609
610 static void xencons_close(struct tty_struct *tty, struct file *filp)
611 {
612         unsigned long flags;
613
614         if (DUMMY_TTY(tty))
615                 return;
616
617         /*
618          * Must follow lock nesting; callers are prepared for this
619          * (__tty_hangup) or don't care as they drop the lock right after our
620          * return (tty_release) in order to then acquire both in proper order.
621          */
622         tty_unlock();
623         mutex_lock(&tty_mutex);
624         tty_lock();
625
626         if (tty->count != 1) {
627                 mutex_unlock(&tty_mutex);
628                 return;
629         }
630
631         /* Prevent other threads from re-opening this tty. */
632         set_bit(TTY_CLOSING, &tty->flags);
633         mutex_unlock(&tty_mutex);
634
635         tty->closing = 1;
636         tty_wait_until_sent(tty, 0);
637         tty_driver_flush_buffer(tty);
638         if (tty->ldisc->ops->flush_buffer)
639                 tty->ldisc->ops->flush_buffer(tty);
640         tty->closing = 0;
641         spin_lock_irqsave(&xencons_lock, flags);
642         xencons_tty = NULL;
643         spin_unlock_irqrestore(&xencons_lock, flags);
644 }
645
646 static const struct tty_operations xencons_ops = {
647         .open = xencons_open,
648         .close = xencons_close,
649         .write = xencons_write,
650         .write_room = xencons_write_room,
651         .put_char = xencons_put_char,
652         .flush_chars = xencons_flush_chars,
653         .chars_in_buffer = xencons_chars_in_buffer,
654         .send_xchar = xencons_send_xchar,
655         .flush_buffer = xencons_flush_buffer,
656         .throttle = xencons_throttle,
657         .unthrottle = xencons_unthrottle,
658         .wait_until_sent = xencons_wait_until_sent,
659 };
660
661 static int __init xencons_init(void)
662 {
663         int rc;
664
665         if (!is_running_on_xen())
666                 return -ENODEV;
667
668         if (xc_mode == XC_OFF)
669                 return 0;
670
671         if (!is_initial_xendomain()) {
672                 rc = xencons_ring_init();
673                 if (rc)
674                         return rc;
675         }
676
677         xencons_driver = alloc_tty_driver((xc_mode == XC_TTY) ?
678                                           MAX_NR_CONSOLES : 1);
679         if (xencons_driver == NULL)
680                 return -ENOMEM;
681
682         DRV(xencons_driver)->name            = "xencons";
683         DRV(xencons_driver)->major           = TTY_MAJOR;
684         DRV(xencons_driver)->type            = TTY_DRIVER_TYPE_SERIAL;
685         DRV(xencons_driver)->subtype         = SERIAL_TYPE_NORMAL;
686         DRV(xencons_driver)->init_termios    = tty_std_termios;
687         DRV(xencons_driver)->flags           =
688                 TTY_DRIVER_REAL_RAW |
689                 TTY_DRIVER_RESET_TERMIOS;
690         DRV(xencons_driver)->termios         = xencons_termios;
691
692         switch (xc_mode) {
693         case XC_XVC:
694                 DRV(xencons_driver)->name        = "xvc";
695                 DRV(xencons_driver)->major       = XEN_XVC_MAJOR;
696                 DRV(xencons_driver)->minor_start = XEN_XVC_MINOR;
697                 DRV(xencons_driver)->name_base   = xc_num;
698                 break;
699         case XC_HVC:
700                 DRV(xencons_driver)->name        = "hvc";
701                 DRV(xencons_driver)->major       = XEN_HVC_MAJOR;
702                 DRV(xencons_driver)->minor_start = XEN_HVC_MINOR;
703                 DRV(xencons_driver)->name_base   = xc_num;
704                 break;
705         case XC_SERIAL:
706                 DRV(xencons_driver)->name        = "ttyS";
707                 DRV(xencons_driver)->minor_start = 64 + xc_num;
708                 DRV(xencons_driver)->name_base   = xc_num;
709                 break;
710         default:
711                 DRV(xencons_driver)->name        = "tty";
712                 DRV(xencons_driver)->minor_start = 1;
713                 DRV(xencons_driver)->name_base   = 1;
714                 break;
715         }
716
717         tty_set_operations(xencons_driver, &xencons_ops);
718
719         if ((rc = tty_register_driver(DRV(xencons_driver))) != 0) {
720                 pr_warning("WARNING: Failed to register Xen virtual "
721                            "console driver as '%s%d'\n",
722                            DRV(xencons_driver)->name,
723                            DRV(xencons_driver)->name_base);
724                 put_tty_driver(xencons_driver);
725                 xencons_driver = NULL;
726                 return rc;
727         }
728
729         if (is_initial_xendomain()) {
730                 xencons_priv_irq = bind_virq_to_irqhandler(
731                         VIRQ_CONSOLE,
732                         0,
733                         xencons_priv_interrupt,
734                         0,
735                         "console",
736                         NULL);
737                 BUG_ON(xencons_priv_irq < 0);
738         }
739
740         pr_info("Xen virtual console successfully installed as %s%d\n",
741                 DRV(xencons_driver)->name, xc_num);
742
743         return 0;
744 }
745
746 module_init(xencons_init);
747
748 MODULE_LICENSE("Dual BSD/GPL");