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