find -type f | xargs sed -i 's/[\t ]*$//g' # Yes, again. Note the star in the regex.
[qemu] / console.c
index 279b7e0..ff725c2 100644 (file)
--- a/console.c
+++ b/console.c
@@ -1,8 +1,8 @@
 /*
  * QEMU graphical console
- * 
+ *
  * Copyright (c) 2004 Fabrice Bellard
- * 
+ *
  * Permission is hereby granted, free of charge, to any person obtaining a copy
  * of this software and associated documentation files (the "Software"), to deal
  * in the Software without restriction, including without limitation the rights
@@ -27,8 +27,8 @@
 #define DEFAULT_BACKSCROLL 512
 #define MAX_CONSOLES 12
 
-#define RGBA(r, g, b, a) (((a) << 24) | ((r) << 16) | ((g) << 8) | (b))
-#define RGB(r, g, b) RGBA(r, g, b, 0xff)
+#define QEMU_RGBA(r, g, b, a) (((a) << 24) | ((r) << 16) | ((g) << 8) | (b))
+#define QEMU_RGB(r, g, b) QEMU_RGBA(r, g, b, 0xff)
 
 typedef struct TextAttributes {
     uint8_t fgcol:4;
@@ -104,10 +104,16 @@ int qemu_fifo_read(QEMUFIFO *f, uint8_t *buf, int len1)
     return len1;
 }
 
+typedef enum {
+    GRAPHIC_CONSOLE,
+    TEXT_CONSOLE,
+    TEXT_CONSOLE_FIXED_SIZE
+} console_type_t;
+
 /* ??? This is mis-named.
    It is used for both text and graphical consoles.  */
 struct TextConsole {
-    int text_console; /* true if text console */
+    console_type_t console_type;
     DisplayState *ds;
     /* Graphic console state.  */
     vga_hw_update_ptr hw_update;
@@ -121,6 +127,7 @@ struct TextConsole {
     int total_height;
     int backscroll_height;
     int x, y;
+    int x_saved, y_saved;
     int y_displayed;
     int y_base;
     TextAttributes t_attrib_default; /* default text attributes */
@@ -131,10 +138,7 @@ struct TextConsole {
     int esc_params[MAX_ESC_PARAMS];
     int nb_esc_params;
 
-    /* kbd read handler */
-    IOCanRWHandler *fd_can_read; 
-    IOReadHandler *fd_read;
-    void *fd_opaque;
+    CharDriverState *chr;
     /* fifo for key pressed */
     QEMUFIFO out_fifo;
     uint8_t out_fifo_buf[16];
@@ -147,7 +151,7 @@ static int nb_consoles = 0;
 
 void vga_hw_update(void)
 {
-    if (active_console->hw_update)
+    if (active_console && active_console->hw_update)
         active_console->hw_update(active_console->hw);
 }
 
@@ -176,8 +180,8 @@ static unsigned int vga_get_color(DisplayState *ds, unsigned int rgba)
         r = (rgba >> 16) & 0xff;
         g = (rgba >> 8) & 0xff;
         b = (rgba) & 0xff;
-        color = (rgb_to_index[r] * 6 * 6) + 
-            (rgb_to_index[g] * 6) + 
+        color = (rgb_to_index[r] * 6 * 6) +
+            (rgb_to_index[g] * 6) +
             (rgb_to_index[b]);
         break;
 #endif
@@ -201,14 +205,14 @@ static unsigned int vga_get_color(DisplayState *ds, unsigned int rgba)
     return color;
 }
 
-static void vga_fill_rect (DisplayState *ds, 
+static void vga_fill_rect (DisplayState *ds,
                            int posx, int posy, int width, int height, uint32_t color)
 {
     uint8_t *d, *d1;
     int x, y, bpp;
-    
+
     bpp = (ds->depth + 7) >> 3;
-    d1 = ds->data + 
+    d1 = ds->data +
         ds->linesize * posy + bpp * posx;
     for (y = 0; y < height; y++) {
         d = d1;
@@ -246,9 +250,9 @@ static void vga_bitblt(DisplayState *ds, int xs, int ys, int xd, int yd, int w,
     bpp = (ds->depth + 7) >> 3;
     wb = w * bpp;
     if (yd <= ys) {
-        s = ds->data + 
+        s = ds->data +
             ds->linesize * ys + bpp * xs;
-        d = ds->data + 
+        d = ds->data +
             ds->linesize * yd + bpp * xd;
         for (y = 0; y < h; y++) {
             memmove(d, s, wb);
@@ -256,9 +260,9 @@ static void vga_bitblt(DisplayState *ds, int xs, int ys, int xd, int yd, int w,
             s += ds->linesize;
         }
     } else {
-        s = ds->data + 
+        s = ds->data +
             ds->linesize * (ys + h - 1) + bpp * xs;
-        d = ds->data + 
+        d = ds->data +
             ds->linesize * (yd + h - 1) + bpp * xd;
        for (y = 0; y < h; y++) {
             memmove(d, s, wb);
@@ -330,24 +334,24 @@ enum color_names {
 
 static const uint32_t color_table_rgb[2][8] = {
     {   /* dark */
-        RGB(0x00, 0x00, 0x00),  /* black */
-        RGB(0xaa, 0x00, 0x00),  /* red */
-        RGB(0x00, 0xaa, 0x00),  /* green */
-        RGB(0xaa, 0xaa, 0x00),  /* yellow */
-        RGB(0x00, 0x00, 0xaa),  /* blue */
-        RGB(0xaa, 0x00, 0xaa),  /* magenta */
-        RGB(0x00, 0xaa, 0xaa),  /* cyan */
-        RGB(0xaa, 0xaa, 0xaa),  /* white */
+        QEMU_RGB(0x00, 0x00, 0x00),  /* black */
+        QEMU_RGB(0xaa, 0x00, 0x00),  /* red */
+        QEMU_RGB(0x00, 0xaa, 0x00),  /* green */
+        QEMU_RGB(0xaa, 0xaa, 0x00),  /* yellow */
+        QEMU_RGB(0x00, 0x00, 0xaa),  /* blue */
+        QEMU_RGB(0xaa, 0x00, 0xaa),  /* magenta */
+        QEMU_RGB(0x00, 0xaa, 0xaa),  /* cyan */
+        QEMU_RGB(0xaa, 0xaa, 0xaa),  /* white */
     },
     {   /* bright */
-        RGB(0x00, 0x00, 0x00),  /* black */
-        RGB(0xff, 0x00, 0x00),  /* red */
-        RGB(0x00, 0xff, 0x00),  /* green */
-        RGB(0xff, 0xff, 0x00),  /* yellow */
-        RGB(0x00, 0x00, 0xff),  /* blue */
-        RGB(0xff, 0x00, 0xff),  /* magenta */
-        RGB(0x00, 0xff, 0xff),  /* cyan */
-        RGB(0xff, 0xff, 0xff),  /* white */
+        QEMU_RGB(0x00, 0x00, 0x00),  /* black */
+        QEMU_RGB(0xff, 0x00, 0x00),  /* red */
+        QEMU_RGB(0x00, 0xff, 0x00),  /* green */
+        QEMU_RGB(0xff, 0xff, 0x00),  /* yellow */
+        QEMU_RGB(0x00, 0x00, 0xff),  /* blue */
+        QEMU_RGB(0xff, 0x00, 0xff),  /* magenta */
+        QEMU_RGB(0x00, 0xff, 0xff),  /* cyan */
+        QEMU_RGB(0xff, 0xff, 0xff),  /* white */
     }
 };
 
@@ -401,7 +405,7 @@ static void console_print_text_attributes(TextAttributes *t_attrib, char ch)
 }
 #endif
 
-static void vga_putcharxy(DisplayState *ds, int x, int y, int ch, 
+static void vga_putcharxy(DisplayState *ds, int x, int y, int ch,
                           TextAttributes *t_attrib)
 {
     uint8_t *d;
@@ -424,7 +428,7 @@ static void vga_putcharxy(DisplayState *ds, int x, int y, int ch,
     }
 
     bpp = (ds->depth + 7) >> 3;
-    d = ds->data + 
+    d = ds->data +
         ds->linesize * y * FONT_HEIGHT + bpp * x * FONT_WIDTH;
     linesize = ds->linesize;
     font_ptr = vgafont16 + FONT_HEIGHT * ch;
@@ -521,9 +525,9 @@ static void update_xy(TextConsole *s, int x, int y)
             y2 += s->total_height;
         if (y2 < s->height) {
             c = &s->cells[y1 * s->width + x];
-            vga_putcharxy(s->ds, x, y2, c->ch, 
+            vga_putcharxy(s->ds, x, y2, c->ch,
                           &(c->t_attrib));
-            dpy_update(s->ds, x * FONT_WIDTH, y2 * FONT_HEIGHT, 
+            dpy_update(s->ds, x * FONT_WIDTH, y2 * FONT_HEIGHT,
                        FONT_WIDTH, FONT_HEIGHT);
         }
     }
@@ -535,21 +539,24 @@ static void console_show_cursor(TextConsole *s, int show)
     int y, y1;
 
     if (s == active_console) {
+        int x = s->x;
+        if (x >= s->width) {
+            x = s->width - 1;
+        }
         y1 = (s->y_base + s->y) % s->total_height;
         y = y1 - s->y_displayed;
         if (y < 0)
             y += s->total_height;
         if (y < s->height) {
-            c = &s->cells[y1 * s->width + s->x];
+            c = &s->cells[y1 * s->width + x];
             if (show) {
                 TextAttributes t_attrib = s->t_attrib_default;
                 t_attrib.invers = !(t_attrib.invers); /* invert fg and bg */
-                vga_putcharxy(s->ds, s->x, y, c->ch, &t_attrib);
+                vga_putcharxy(s->ds, x, y, c->ch, &t_attrib);
             } else {
-                vga_putcharxy(s->ds, s->x, y, c->ch, 
-                              &(c->t_attrib));
+                vga_putcharxy(s->ds, x, y, c->ch, &(c->t_attrib));
             }
-            dpy_update(s->ds, s->x * FONT_WIDTH, y * FONT_HEIGHT, 
+            dpy_update(s->ds, x * FONT_WIDTH, y * FONT_HEIGHT,
                        FONT_WIDTH, FONT_HEIGHT);
         }
     }
@@ -560,7 +567,7 @@ static void console_refresh(TextConsole *s)
     TextCell *c;
     int x, y, y1;
 
-    if (s != active_console) 
+    if (s != active_console)
         return;
 
     vga_fill_rect(s->ds, 0, 0, s->ds->width, s->ds->height,
@@ -569,7 +576,7 @@ static void console_refresh(TextConsole *s)
     for(y = 0; y < s->height; y++) {
         c = s->cells + y1 * s->width;
         for(x = 0; x < s->width; x++) {
-            vga_putcharxy(s->ds, x, y, c->ch, 
+            vga_putcharxy(s->ds, x, y, c->ch,
                           &(c->t_attrib));
             c++;
         }
@@ -584,9 +591,9 @@ static void console_scroll(int ydelta)
 {
     TextConsole *s;
     int i, y1;
-    
+
     s = active_console;
-    if (!s || !s->text_console)
+    if (!s || (s->console_type == GRAPHIC_CONSOLE))
         return;
 
     if (ydelta > 0) {
@@ -619,7 +626,6 @@ static void console_put_lf(TextConsole *s)
     TextCell *c;
     int x, y1;
 
-    s->x = 0;
     s->y++;
     if (s->y >= s->height) {
         s->y = s->height - 1;
@@ -640,13 +646,13 @@ static void console_put_lf(TextConsole *s)
             c++;
         }
         if (s == active_console && s->y_displayed == s->y_base) {
-            vga_bitblt(s->ds, 0, FONT_HEIGHT, 0, 0, 
-                       s->width * FONT_WIDTH, 
+            vga_bitblt(s->ds, 0, FONT_HEIGHT, 0, 0,
+                       s->width * FONT_WIDTH,
                        (s->height - 1) * FONT_HEIGHT);
             vga_fill_rect(s->ds, 0, (s->height - 1) * FONT_HEIGHT,
-                          s->width * FONT_WIDTH, FONT_HEIGHT, 
+                          s->width * FONT_WIDTH, FONT_HEIGHT,
                           color_table[0][s->t_attrib_default.bgcol]);
-            dpy_update(s->ds, 0, 0, 
+            dpy_update(s->ds, 0, 0,
                        s->width * FONT_WIDTH, s->height * FONT_HEIGHT);
         }
     }
@@ -660,10 +666,6 @@ static void console_handle_escape(TextConsole *s)
 {
     int i;
 
-    if (s->nb_esc_params == 0) { /* ESC[m sets all attributes to default */
-        s->t_attrib = s->t_attrib_default;
-        return;
-    }
     for (i=0; i<s->nb_esc_params; i++) {
         switch (s->esc_params[i]) {
             case 0: /* reset all console attributes to default */
@@ -753,10 +755,21 @@ static void console_handle_escape(TextConsole *s)
     }
 }
 
+static void console_clear_xy(TextConsole *s, int x, int y)
+{
+    int y1 = (s->y_base + y) % s->total_height;
+    TextCell *c = &s->cells[y1 * s->width + x];
+    c->ch = ' ';
+    c->t_attrib = s->t_attrib_default;
+    c++;
+    update_xy(s, x, y);
+}
+
 static void console_putchar(TextConsole *s, int ch)
 {
     TextCell *c;
-    int y1, i, x;
+    int y1, i;
+    int x, y;
 
     switch(s->state) {
     case TTY_STATE_NORM:
@@ -768,11 +781,12 @@ static void console_putchar(TextConsole *s, int ch)
             console_put_lf(s);
             break;
         case '\b':  /* backspace */
-            if (s->x > 0) 
+            if (s->x > 0)
                 s->x--;
             break;
         case '\t':  /* tabspace */
             if (s->x + (8 - (s->x % 8)) > s->width) {
+                s->x = 0;
                 console_put_lf(s);
             } else {
                 s->x = s->x + (8 - (s->x % 8));
@@ -781,18 +795,27 @@ static void console_putchar(TextConsole *s, int ch)
         case '\a':  /* alert aka. bell */
             /* TODO: has to be implemented */
             break;
+        case 14:
+            /* SI (shift in), character set 0 (ignored) */
+            break;
+        case 15:
+            /* SO (shift out), character set 1 (ignored) */
+            break;
         case 27:    /* esc (introducing an escape sequence) */
             s->state = TTY_STATE_ESC;
             break;
         default:
+            if (s->x >= s->width) {
+                /* line wrap */
+                s->x = 0;
+                console_put_lf(s);
+            }
             y1 = (s->y_base + s->y) % s->total_height;
             c = &s->cells[y1 * s->width + s->x];
             c->ch = ch;
             c->t_attrib = s->t_attrib;
             update_xy(s, s->x, s->y);
             s->x++;
-            if (s->x >= s->width)
-                console_put_lf(s);
             break;
         }
         break;
@@ -809,39 +832,157 @@ static void console_putchar(TextConsole *s, int ch)
     case TTY_STATE_CSI: /* handle escape sequence parameters */
         if (ch >= '0' && ch <= '9') {
             if (s->nb_esc_params < MAX_ESC_PARAMS) {
-                s->esc_params[s->nb_esc_params] = 
+                s->esc_params[s->nb_esc_params] =
                     s->esc_params[s->nb_esc_params] * 10 + ch - '0';
             }
         } else {
             s->nb_esc_params++;
             if (ch == ';')
                 break;
+#ifdef DEBUG_CONSOLE
+            fprintf(stderr, "escape sequence CSI%d;%d%c, %d parameters\n",
+                    s->esc_params[0], s->esc_params[1], ch, s->nb_esc_params);
+#endif
             s->state = TTY_STATE_NORM;
             switch(ch) {
-            case 'D':
-                if (s->x > 0)
-                    s->x--;
+            case 'A':
+                /* move cursor up */
+                if (s->esc_params[0] == 0) {
+                    s->esc_params[0] = 1;
+                }
+                s->y -= s->esc_params[0];
+                if (s->y < 0) {
+                    s->y = 0;
+                }
+                break;
+            case 'B':
+                /* move cursor down */
+                if (s->esc_params[0] == 0) {
+                    s->esc_params[0] = 1;
+                }
+                s->y += s->esc_params[0];
+                if (s->y >= s->height) {
+                    s->y = s->height - 1;
+                }
                 break;
             case 'C':
-                if (s->x < (s->width - 1))
-                    s->x++;
+                /* move cursor right */
+                if (s->esc_params[0] == 0) {
+                    s->esc_params[0] = 1;
+                }
+                s->x += s->esc_params[0];
+                if (s->x >= s->width) {
+                    s->x = s->width - 1;
+                }
+                break;
+            case 'D':
+                /* move cursor left */
+                if (s->esc_params[0] == 0) {
+                    s->esc_params[0] = 1;
+                }
+                s->x -= s->esc_params[0];
+                if (s->x < 0) {
+                    s->x = 0;
+                }
                 break;
+            case 'G':
+                /* move cursor to column */
+                s->x = s->esc_params[0] - 1;
+                if (s->x < 0) {
+                    s->x = 0;
+                }
+                break;
+            case 'f':
+            case 'H':
+                /* move cursor to row, column */
+                s->x = s->esc_params[1] - 1;
+                if (s->x < 0) {
+                    s->x = 0;
+                }
+                s->y = s->esc_params[0] - 1;
+                if (s->y < 0) {
+                    s->y = 0;
+                }
+                break;
+            case 'J':
+                switch (s->esc_params[0]) {
+                case 0:
+                    /* clear to end of screen */
+                    for (y = s->y; y < s->height; y++) {
+                        for (x = 0; x < s->width; x++) {
+                            if (y == s->y && x < s->x) {
+                                continue;
+                            }
+                            console_clear_xy(s, x, y);
+                        }
+                    }
+                    break;
+                case 1:
+                    /* clear from beginning of screen */
+                    for (y = 0; y <= s->y; y++) {
+                        for (x = 0; x < s->width; x++) {
+                            if (y == s->y && x > s->x) {
+                                break;
+                            }
+                            console_clear_xy(s, x, y);
+                        }
+                    }
+                    break;
+                case 2:
+                    /* clear entire screen */
+                    for (y = 0; y <= s->height; y++) {
+                        for (x = 0; x < s->width; x++) {
+                            console_clear_xy(s, x, y);
+                        }
+                    }
+                break;
+                }
             case 'K':
+                switch (s->esc_params[0]) {
+                case 0:
                 /* clear to eol */
-                y1 = (s->y_base + s->y) % s->total_height;
                 for(x = s->x; x < s->width; x++) {
-                    c = &s->cells[y1 * s->width + x];
-                    c->ch = ' ';
-                    c->t_attrib = s->t_attrib_default;
-                    c++;
-                    update_xy(s, x, s->y);
+                        console_clear_xy(s, x, s->y);
                 }
                 break;
-            default:
+                case 1:
+                    /* clear from beginning of line */
+                    for (x = 0; x <= s->x; x++) {
+                        console_clear_xy(s, x, s->y);
+                    }
+                    break;
+                case 2:
+                    /* clear entire line */
+                    for(x = 0; x < s->width; x++) {
+                        console_clear_xy(s, x, s->y);
+                    }
                 break;
             }
+                break;
+            case 'm':
             console_handle_escape(s);
             break;
+            case 'n':
+                /* report cursor position */
+                /* TODO: send ESC[row;colR */
+                break;
+            case 's':
+                /* save cursor position */
+                s->x_saved = s->x;
+                s->y_saved = s->y;
+                break;
+            case 'u':
+                /* restore cursor position */
+                s->x = s->x_saved;
+                s->y = s->y_saved;
+                break;
+            default:
+#ifdef DEBUG_CONSOLE
+                fprintf(stderr, "unhandled escape character '%c'\n", ch);
+#endif
+                break;
+            }
+            break;
         }
     }
 }
@@ -855,13 +996,17 @@ void console_select(unsigned int index)
     s = consoles[index];
     if (s) {
         active_console = s;
-        if (s->text_console) {
+        if (s->console_type != GRAPHIC_CONSOLE) {
             if (s->g_width != s->ds->width ||
                 s->g_height != s->ds->height) {
+                if (s->console_type == TEXT_CONSOLE_FIXED_SIZE) {
+                    dpy_resize(s->ds, s->g_width, s->g_height);
+                } else {
                 s->g_width = s->ds->width;
                 s->g_height = s->ds->height;
                 text_console_resize(s);
             }
+            }
             console_refresh(s);
         } else {
             vga_hw_invalidate();
@@ -882,16 +1027,6 @@ static int console_puts(CharDriverState *chr, const uint8_t *buf, int len)
     return len;
 }
 
-static void console_chr_add_read_handler(CharDriverState *chr, 
-                                         IOCanRWHandler *fd_can_read, 
-                                         IOReadHandler *fd_read, void *opaque)
-{
-    TextConsole *s = chr->opaque;
-    s->fd_can_read = fd_can_read;
-    s->fd_read = fd_read;
-    s->fd_opaque = opaque;
-}
-
 static void console_send_event(CharDriverState *chr, int event)
 {
     TextConsole *s = chr->opaque;
@@ -912,15 +1047,15 @@ static void kbd_send_chars(void *opaque)
     TextConsole *s = opaque;
     int len;
     uint8_t buf[16];
-    
-    len = s->fd_can_read(s->fd_opaque);
+
+    len = qemu_chr_can_read(s->chr);
     if (len > s->out_fifo.count)
         len = s->out_fifo.count;
     if (len > 0) {
         if (len > sizeof(buf))
             len = sizeof(buf);
         qemu_fifo_read(&s->out_fifo, buf, len);
-        s->fd_read(s->fd_opaque, buf, len);
+        qemu_chr_read(s->chr, buf, len);
     }
     /* characters are pending: we send them a bit later (XXX:
        horrible, should change char device API) */
@@ -937,7 +1072,7 @@ void kbd_put_keysym(int keysym)
     int c;
 
     s = active_console;
-    if (!s || !s->text_console)
+    if (!s || (s->console_type == GRAPHIC_CONSOLE))
         return;
 
     switch(keysym) {
@@ -971,7 +1106,7 @@ void kbd_put_keysym(int keysym)
         } else {
                 *q++ = keysym;
         }
-        if (s->fd_read) {
+        if (s->chr->chr_read) {
             qemu_fifo_write(&s->out_fifo, buf, q - buf);
             kbd_send_chars(s);
         }
@@ -979,7 +1114,7 @@ void kbd_put_keysym(int keysym)
     }
 }
 
-static TextConsole *new_console(DisplayState *ds, int text)
+static TextConsole *new_console(DisplayState *ds, console_type_t console_type)
 {
     TextConsole *s;
     int i;
@@ -990,16 +1125,18 @@ static TextConsole *new_console(DisplayState *ds, int text)
     if (!s) {
         return NULL;
     }
-    if (!active_console || (active_console->text_console && !text))
+    if (!active_console || ((active_console->console_type != GRAPHIC_CONSOLE) &&
+        (console_type == GRAPHIC_CONSOLE))) {
         active_console = s;
+    }
     s->ds = ds;
-    s->text_console = text;
-    if (text) {
+    s->console_type = console_type;
+    if (console_type != GRAPHIC_CONSOLE) {
         consoles[nb_consoles++] = s;
     } else {
         /* HACK: Put graphical consoles before text consoles.  */
         for (i = nb_consoles; i > 0; i--) {
-            if (!consoles[i - 1]->text_console)
+            if (consoles[i - 1]->console_type == GRAPHIC_CONSOLE)
                 break;
             consoles[i] = consoles[i - 1];
         }
@@ -1015,7 +1152,7 @@ TextConsole *graphic_console_init(DisplayState *ds, vga_hw_update_ptr update,
 {
     TextConsole *s;
 
-    s = new_console(ds, 0);
+    s = new_console(ds, GRAPHIC_CONSOLE);
     if (!s)
       return NULL;
     s->hw_update = update;
@@ -1027,38 +1164,40 @@ TextConsole *graphic_console_init(DisplayState *ds, vga_hw_update_ptr update,
 
 int is_graphic_console(void)
 {
-    return !active_console->text_console;
+    return active_console->console_type == GRAPHIC_CONSOLE;
 }
 
-CharDriverState *text_console_init(DisplayState *ds)
+CharDriverState *text_console_init(DisplayState *ds, const char *p)
 {
     CharDriverState *chr;
     TextConsole *s;
     int i,j;
+    unsigned width;
+    unsigned height;
     static int color_inited;
 
     chr = qemu_mallocz(sizeof(CharDriverState));
     if (!chr)
         return NULL;
-    s = new_console(ds, 1);
+    s = new_console(ds, (p == 0) ? TEXT_CONSOLE : TEXT_CONSOLE_FIXED_SIZE);
     if (!s) {
         free(chr);
         return NULL;
     }
     chr->opaque = s;
     chr->chr_write = console_puts;
-    chr->chr_add_read_handler = console_chr_add_read_handler;
     chr->chr_send_event = console_send_event;
 
+    s->chr = chr;
     s->out_fifo.buf = s->out_fifo_buf;
     s->out_fifo.buf_size = sizeof(s->out_fifo_buf);
     s->kbd_timer = qemu_new_timer(rt_clock, kbd_send_chars, s);
-    
+
     if (!color_inited) {
         color_inited = 1;
         for(j = 0; j < 2; j++) {
             for(i = 0; i < 8; i++) {
-                color_table[j][i] = col_expand(s->ds, 
+                color_table[j][i] = col_expand(s->ds,
                         vga_get_color(s->ds, color_table_rgb[j][i]));
             }
         }
@@ -1068,8 +1207,25 @@ CharDriverState *text_console_init(DisplayState *ds)
     s->total_height = DEFAULT_BACKSCROLL;
     s->x = 0;
     s->y = 0;
-    s->g_width = s->ds->width;
-    s->g_height = s->ds->height;
+    width = s->ds->width;
+    height = s->ds->height;
+    if (p != 0) {
+        width = strtoul(p, (char **)&p, 10);
+        if (*p == 'C') {
+            p++;
+            width *= FONT_WIDTH;
+        }
+        if (*p == 'x') {
+            p++;
+            height = strtoul(p, (char **)&p, 10);
+            if (*p == 'C') {
+                p++;
+                height *= FONT_HEIGHT;
+            }
+        }
+    }
+    s->g_width = width;
+    s->g_height = height;
 
     /* Set text attribute defaults */
     s->t_attrib_default.bold = 0;
@@ -1084,5 +1240,7 @@ CharDriverState *text_console_init(DisplayState *ds)
     s->t_attrib = s->t_attrib_default;
     text_console_resize(s);
 
+    qemu_chr_reset(chr);
+
     return chr;
 }