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