Commit e7f0ad58c12b907ace1b263f06f2a2bdecfbde9f

Authored by bellard
1 parent 82c643ff

virtual console


git-svn-id: svn://svn.savannah.nongnu.org/qemu/trunk@1024 c046a42c-6fe2-441c-8c8c-71466251a162
Showing 1 changed file with 711 additions and 0 deletions
console.c 0 → 100644
  1 +/*
  2 + * QEMU graphical console
  3 + *
  4 + * Copyright (c) 2004 Fabrice Bellard
  5 + *
  6 + * Permission is hereby granted, free of charge, to any person obtaining a copy
  7 + * of this software and associated documentation files (the "Software"), to deal
  8 + * in the Software without restriction, including without limitation the rights
  9 + * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
  10 + * copies of the Software, and to permit persons to whom the Software is
  11 + * furnished to do so, subject to the following conditions:
  12 + *
  13 + * The above copyright notice and this permission notice shall be included in
  14 + * all copies or substantial portions of the Software.
  15 + *
  16 + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  17 + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  18 + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
  19 + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  20 + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
  21 + * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
  22 + * THE SOFTWARE.
  23 + */
  24 +#include "vl.h"
  25 +
  26 +#define DEFAULT_BACKSCROLL 512
  27 +#define MAX_CONSOLES 12
  28 +
  29 +#define RGBA(r, g, b, a) (((a) << 24) | ((r) << 16) | ((g) << 8) | (b))
  30 +#define RGB(r, g, b) RGBA(r, g, b, 0xff)
  31 +
  32 +typedef struct TextCell {
  33 + uint8_t ch;
  34 + uint8_t bgcol:4;
  35 + uint8_t fgcol:4;
  36 +} TextCell;
  37 +
  38 +#define MAX_ESC_PARAMS 3
  39 +
  40 +enum TTYState {
  41 + TTY_STATE_NORM,
  42 + TTY_STATE_ESC,
  43 + TTY_STATE_CSI,
  44 +};
  45 +
  46 +struct TextConsole {
  47 + int text_console; /* true if text console */
  48 + DisplayState *ds;
  49 + int g_width, g_height;
  50 + int width;
  51 + int height;
  52 + int total_height;
  53 + int backscroll_height;
  54 + int fgcol;
  55 + int bgcol;
  56 + int x, y;
  57 + int y_displayed;
  58 + int y_base;
  59 + TextCell *cells;
  60 +
  61 + enum TTYState state;
  62 + int esc_params[MAX_ESC_PARAMS];
  63 + int nb_esc_params;
  64 +
  65 + /* kbd read handler */
  66 + IOReadHandler *fd_read;
  67 + void *fd_opaque;
  68 +};
  69 +
  70 +static TextConsole *active_console;
  71 +static TextConsole *consoles[MAX_CONSOLES];
  72 +static int nb_consoles = 0;
  73 +
  74 +/* convert a RGBA color to a color index usable in graphic primitives */
  75 +static unsigned int vga_get_color(DisplayState *ds, unsigned int rgba)
  76 +{
  77 + unsigned int r, g, b, color;
  78 +
  79 + switch(ds->depth) {
  80 +#if 0
  81 + case 8:
  82 + r = (rgba >> 16) & 0xff;
  83 + g = (rgba >> 8) & 0xff;
  84 + b = (rgba) & 0xff;
  85 + color = (rgb_to_index[r] * 6 * 6) +
  86 + (rgb_to_index[g] * 6) +
  87 + (rgb_to_index[b]);
  88 + break;
  89 +#endif
  90 + case 15:
  91 + r = (rgba >> 16) & 0xff;
  92 + g = (rgba >> 8) & 0xff;
  93 + b = (rgba) & 0xff;
  94 + color = ((r >> 3) << 10) | ((g >> 3) << 5) | (b >> 3);
  95 + break;
  96 + case 16:
  97 + r = (rgba >> 16) & 0xff;
  98 + g = (rgba >> 8) & 0xff;
  99 + b = (rgba) & 0xff;
  100 + color = ((r >> 3) << 11) | ((g >> 2) << 5) | (b >> 3);
  101 + break;
  102 + case 32:
  103 + default:
  104 + color = rgba;
  105 + break;
  106 + }
  107 + return color;
  108 +}
  109 +
  110 +static void vga_fill_rect (DisplayState *ds,
  111 + int posx, int posy, int width, int height, uint32_t color)
  112 +{
  113 + uint8_t *d, *d1;
  114 + int x, y, bpp;
  115 +
  116 + bpp = (ds->depth + 7) >> 3;
  117 + d1 = ds->data +
  118 + ds->linesize * posy + bpp * posx;
  119 + for (y = 0; y < height; y++) {
  120 + d = d1;
  121 + switch(bpp) {
  122 + case 1:
  123 + for (x = 0; x < width; x++) {
  124 + *((uint8_t *)d) = color;
  125 + d++;
  126 + }
  127 + break;
  128 + case 2:
  129 + for (x = 0; x < width; x++) {
  130 + *((uint16_t *)d) = color;
  131 + d += 2;
  132 + }
  133 + break;
  134 + case 4:
  135 + for (x = 0; x < width; x++) {
  136 + *((uint32_t *)d) = color;
  137 + d += 4;
  138 + }
  139 + break;
  140 + }
  141 + d1 += ds->linesize;
  142 + }
  143 +}
  144 +
  145 +/* copy from (xs, ys) to (xd, yd) a rectangle of size (w, h) */
  146 +static void vga_bitblt(DisplayState *ds, int xs, int ys, int xd, int yd, int w, int h)
  147 +{
  148 + const uint8_t *s;
  149 + uint8_t *d;
  150 + int wb, y, bpp;
  151 +
  152 + bpp = (ds->depth + 7) >> 3;
  153 + wb = w * bpp;
  154 + if (yd <= ys) {
  155 + s = ds->data +
  156 + ds->linesize * ys + bpp * xs;
  157 + d = ds->data +
  158 + ds->linesize * yd + bpp * xd;
  159 + for (y = 0; y < h; y++) {
  160 + memmove(d, s, wb);
  161 + d += ds->linesize;
  162 + s += ds->linesize;
  163 + }
  164 + } else {
  165 + s = ds->data +
  166 + ds->linesize * (ys + h - 1) + bpp * xs;
  167 + d = ds->data +
  168 + ds->linesize * (yd + h - 1) + bpp * xd;
  169 + for (y = 0; y < h; y++) {
  170 + memmove(d, s, wb);
  171 + d -= ds->linesize;
  172 + s -= ds->linesize;
  173 + }
  174 + }
  175 +}
  176 +
  177 +/***********************************************************/
  178 +/* basic char display */
  179 +
  180 +#define FONT_HEIGHT 16
  181 +#define FONT_WIDTH 8
  182 +
  183 +#include "vgafont.h"
  184 +
  185 +#define cbswap_32(__x) \
  186 +((uint32_t)( \
  187 + (((uint32_t)(__x) & (uint32_t)0x000000ffUL) << 24) | \
  188 + (((uint32_t)(__x) & (uint32_t)0x0000ff00UL) << 8) | \
  189 + (((uint32_t)(__x) & (uint32_t)0x00ff0000UL) >> 8) | \
  190 + (((uint32_t)(__x) & (uint32_t)0xff000000UL) >> 24) ))
  191 +
  192 +#ifdef WORDS_BIGENDIAN
  193 +#define PAT(x) x
  194 +#else
  195 +#define PAT(x) cbswap_32(x)
  196 +#endif
  197 +
  198 +static const uint32_t dmask16[16] = {
  199 + PAT(0x00000000),
  200 + PAT(0x000000ff),
  201 + PAT(0x0000ff00),
  202 + PAT(0x0000ffff),
  203 + PAT(0x00ff0000),
  204 + PAT(0x00ff00ff),
  205 + PAT(0x00ffff00),
  206 + PAT(0x00ffffff),
  207 + PAT(0xff000000),
  208 + PAT(0xff0000ff),
  209 + PAT(0xff00ff00),
  210 + PAT(0xff00ffff),
  211 + PAT(0xffff0000),
  212 + PAT(0xffff00ff),
  213 + PAT(0xffffff00),
  214 + PAT(0xffffffff),
  215 +};
  216 +
  217 +static const uint32_t dmask4[4] = {
  218 + PAT(0x00000000),
  219 + PAT(0x0000ffff),
  220 + PAT(0xffff0000),
  221 + PAT(0xffffffff),
  222 +};
  223 +
  224 +static uint32_t color_table[8];
  225 +
  226 +static const uint32_t color_table_rgb[8] = {
  227 + RGB(0x00, 0x00, 0x00),
  228 + RGB(0xff, 0x00, 0x00),
  229 + RGB(0x00, 0xff, 0x00),
  230 + RGB(0xff, 0xff, 0x00),
  231 + RGB(0x00, 0x00, 0xff),
  232 + RGB(0xff, 0x00, 0xff),
  233 + RGB(0x00, 0xff, 0xff),
  234 + RGB(0xff, 0xff, 0xff),
  235 +};
  236 +
  237 +static inline unsigned int col_expand(DisplayState *ds, unsigned int col)
  238 +{
  239 + switch(ds->depth) {
  240 + case 8:
  241 + col |= col << 8;
  242 + col |= col << 16;
  243 + break;
  244 + case 15:
  245 + case 16:
  246 + col |= col << 16;
  247 + break;
  248 + default:
  249 + break;
  250 + }
  251 +
  252 + return col;
  253 +}
  254 +
  255 +static void vga_putcharxy(DisplayState *ds, int x, int y, int ch,
  256 + unsigned int fgcol, unsigned int bgcol)
  257 +{
  258 + uint8_t *d;
  259 + const uint8_t *font_ptr;
  260 + unsigned int font_data, linesize, xorcol, bpp;
  261 + int i;
  262 +
  263 + bpp = (ds->depth + 7) >> 3;
  264 + d = ds->data +
  265 + ds->linesize * y * FONT_HEIGHT + bpp * x * FONT_WIDTH;
  266 + linesize = ds->linesize;
  267 + font_ptr = vgafont16 + FONT_HEIGHT * ch;
  268 + xorcol = bgcol ^ fgcol;
  269 + switch(ds->depth) {
  270 + case 8:
  271 + for(i = 0; i < FONT_HEIGHT; i++) {
  272 + font_data = *font_ptr++;
  273 + ((uint32_t *)d)[0] = (dmask16[(font_data >> 4)] & xorcol) ^ bgcol;
  274 + ((uint32_t *)d)[1] = (dmask16[(font_data >> 0) & 0xf] & xorcol) ^ bgcol;
  275 + d += linesize;
  276 + }
  277 + break;
  278 + case 16:
  279 + case 15:
  280 + for(i = 0; i < FONT_HEIGHT; i++) {
  281 + font_data = *font_ptr++;
  282 + ((uint32_t *)d)[0] = (dmask4[(font_data >> 6)] & xorcol) ^ bgcol;
  283 + ((uint32_t *)d)[1] = (dmask4[(font_data >> 4) & 3] & xorcol) ^ bgcol;
  284 + ((uint32_t *)d)[2] = (dmask4[(font_data >> 2) & 3] & xorcol) ^ bgcol;
  285 + ((uint32_t *)d)[3] = (dmask4[(font_data >> 0) & 3] & xorcol) ^ bgcol;
  286 + d += linesize;
  287 + }
  288 + break;
  289 + case 32:
  290 + for(i = 0; i < FONT_HEIGHT; i++) {
  291 + font_data = *font_ptr++;
  292 + ((uint32_t *)d)[0] = (-((font_data >> 7)) & xorcol) ^ bgcol;
  293 + ((uint32_t *)d)[1] = (-((font_data >> 6) & 1) & xorcol) ^ bgcol;
  294 + ((uint32_t *)d)[2] = (-((font_data >> 5) & 1) & xorcol) ^ bgcol;
  295 + ((uint32_t *)d)[3] = (-((font_data >> 4) & 1) & xorcol) ^ bgcol;
  296 + ((uint32_t *)d)[4] = (-((font_data >> 3) & 1) & xorcol) ^ bgcol;
  297 + ((uint32_t *)d)[5] = (-((font_data >> 2) & 1) & xorcol) ^ bgcol;
  298 + ((uint32_t *)d)[6] = (-((font_data >> 1) & 1) & xorcol) ^ bgcol;
  299 + ((uint32_t *)d)[7] = (-((font_data >> 0) & 1) & xorcol) ^ bgcol;
  300 + d += linesize;
  301 + }
  302 + break;
  303 + }
  304 +}
  305 +
  306 +static void text_console_resize(TextConsole *s)
  307 +{
  308 + TextCell *cells, *c, *c1;
  309 + int w1, x, y, last_width;
  310 +
  311 + last_width = s->width;
  312 + s->width = s->g_width / FONT_WIDTH;
  313 + s->height = s->g_height / FONT_HEIGHT;
  314 +
  315 + w1 = last_width;
  316 + if (s->width < w1)
  317 + w1 = s->width;
  318 +
  319 + cells = qemu_malloc(s->width * s->total_height * sizeof(TextCell));
  320 + for(y = 0; y < s->total_height; y++) {
  321 + c = &cells[y * s->width];
  322 + if (w1 > 0) {
  323 + c1 = &s->cells[y * last_width];
  324 + for(x = 0; x < w1; x++) {
  325 + *c++ = *c1++;
  326 + }
  327 + }
  328 + for(x = w1; x < s->width; x++) {
  329 + c->ch = ' ';
  330 + c->fgcol = 7;
  331 + c->bgcol = 0;
  332 + c++;
  333 + }
  334 + }
  335 + free(s->cells);
  336 + s->cells = cells;
  337 +}
  338 +
  339 +static void update_xy(TextConsole *s, int x, int y)
  340 +{
  341 + TextCell *c;
  342 + int y1, y2;
  343 +
  344 + if (s == active_console) {
  345 + y1 = (s->y_base + y) % s->total_height;
  346 + y2 = y1 - s->y_displayed;
  347 + if (y2 < 0)
  348 + y2 += s->total_height;
  349 + if (y2 < s->height) {
  350 + c = &s->cells[y1 * s->width + x];
  351 + vga_putcharxy(s->ds, x, y2, c->ch,
  352 + color_table[c->fgcol], color_table[c->bgcol]);
  353 + dpy_update(s->ds, x * FONT_WIDTH, y2 * FONT_HEIGHT,
  354 + FONT_WIDTH, FONT_HEIGHT);
  355 + }
  356 + }
  357 +}
  358 +
  359 +static void console_show_cursor(TextConsole *s, int show)
  360 +{
  361 + TextCell *c;
  362 + int y, y1;
  363 +
  364 + if (s == active_console) {
  365 + y1 = (s->y_base + s->y) % s->total_height;
  366 + y = y1 - s->y_displayed;
  367 + if (y < 0)
  368 + y += s->total_height;
  369 + if (y < s->height) {
  370 + c = &s->cells[y1 * s->width + s->x];
  371 + if (show) {
  372 + vga_putcharxy(s->ds, s->x, y, c->ch,
  373 + color_table[0], color_table[7]);
  374 + } else {
  375 + vga_putcharxy(s->ds, s->x, y, c->ch,
  376 + color_table[c->fgcol], color_table[c->bgcol]);
  377 + }
  378 + dpy_update(s->ds, s->x * FONT_WIDTH, y * FONT_HEIGHT,
  379 + FONT_WIDTH, FONT_HEIGHT);
  380 + }
  381 + }
  382 +}
  383 +
  384 +static void console_refresh(TextConsole *s)
  385 +{
  386 + TextCell *c;
  387 + int x, y, y1;
  388 +
  389 + if (s != active_console)
  390 + return;
  391 +
  392 + vga_fill_rect(s->ds, 0, 0, s->ds->width, s->ds->height,
  393 + color_table[0]);
  394 + y1 = s->y_displayed;
  395 + for(y = 0; y < s->height; y++) {
  396 + c = s->cells + y1 * s->width;
  397 + for(x = 0; x < s->width; x++) {
  398 + vga_putcharxy(s->ds, x, y, c->ch,
  399 + color_table[c->fgcol], color_table[c->bgcol]);
  400 + c++;
  401 + }
  402 + if (++y1 == s->total_height)
  403 + y1 = 0;
  404 + }
  405 + dpy_update(s->ds, 0, 0, s->ds->width, s->ds->height);
  406 + console_show_cursor(s, 1);
  407 +}
  408 +
  409 +static void console_scroll(int ydelta)
  410 +{
  411 + TextConsole *s;
  412 + int i, y1;
  413 +
  414 + s = active_console;
  415 + if (!s || !s->text_console)
  416 + return;
  417 +
  418 + if (ydelta > 0) {
  419 + for(i = 0; i < ydelta; i++) {
  420 + if (s->y_displayed == s->y_base)
  421 + break;
  422 + if (++s->y_displayed == s->total_height)
  423 + s->y_displayed = 0;
  424 + }
  425 + } else {
  426 + ydelta = -ydelta;
  427 + i = s->backscroll_height;
  428 + if (i > s->total_height - s->height)
  429 + i = s->total_height - s->height;
  430 + y1 = s->y_base - i;
  431 + if (y1 < 0)
  432 + y1 += s->total_height;
  433 + for(i = 0; i < ydelta; i++) {
  434 + if (s->y_displayed == y1)
  435 + break;
  436 + if (--s->y_displayed < 0)
  437 + s->y_displayed = s->total_height - 1;
  438 + }
  439 + }
  440 + console_refresh(s);
  441 +}
  442 +
  443 +static void console_put_lf(TextConsole *s)
  444 +{
  445 + TextCell *c;
  446 + int x, y1;
  447 +
  448 + s->x = 0;
  449 + s->y++;
  450 + if (s->y >= s->height) {
  451 + s->y = s->height - 1;
  452 +
  453 + if (s->y_displayed == s->y_base) {
  454 + if (++s->y_displayed == s->total_height)
  455 + s->y_displayed = 0;
  456 + }
  457 + if (++s->y_base == s->total_height)
  458 + s->y_base = 0;
  459 + if (s->backscroll_height < s->total_height)
  460 + s->backscroll_height++;
  461 + y1 = (s->y_base + s->height - 1) % s->total_height;
  462 + c = &s->cells[y1 * s->width];
  463 + for(x = 0; x < s->width; x++) {
  464 + c->ch = ' ';
  465 + c->fgcol = s->fgcol;
  466 + c->bgcol = s->bgcol;
  467 + c++;
  468 + }
  469 + if (s == active_console && s->y_displayed == s->y_base) {
  470 + vga_bitblt(s->ds, 0, FONT_HEIGHT, 0, 0,
  471 + s->width * FONT_WIDTH,
  472 + (s->height - 1) * FONT_HEIGHT);
  473 + vga_fill_rect(s->ds, 0, (s->height - 1) * FONT_HEIGHT,
  474 + s->width * FONT_WIDTH, FONT_HEIGHT,
  475 + color_table[s->bgcol]);
  476 + dpy_update(s->ds, 0, 0,
  477 + s->width * FONT_WIDTH, s->height * FONT_HEIGHT);
  478 + }
  479 + }
  480 +}
  481 +
  482 +static void console_putchar(TextConsole *s, int ch)
  483 +{
  484 + TextCell *c;
  485 + int y1, i, x;
  486 +
  487 + switch(s->state) {
  488 + case TTY_STATE_NORM:
  489 + switch(ch) {
  490 + case '\r':
  491 + s->x = 0;
  492 + break;
  493 + case '\n':
  494 + console_put_lf(s);
  495 + break;
  496 + case 27:
  497 + s->state = TTY_STATE_ESC;
  498 + break;
  499 + default:
  500 + y1 = (s->y_base + s->y) % s->total_height;
  501 + c = &s->cells[y1 * s->width + s->x];
  502 + c->ch = ch;
  503 + c->fgcol = s->fgcol;
  504 + c->bgcol = s->bgcol;
  505 + update_xy(s, s->x, s->y);
  506 + s->x++;
  507 + if (s->x >= s->width)
  508 + console_put_lf(s);
  509 + break;
  510 + }
  511 + break;
  512 + case TTY_STATE_ESC:
  513 + if (ch == '[') {
  514 + for(i=0;i<MAX_ESC_PARAMS;i++)
  515 + s->esc_params[i] = 0;
  516 + s->nb_esc_params = 0;
  517 + s->state = TTY_STATE_CSI;
  518 + } else {
  519 + s->state = TTY_STATE_NORM;
  520 + }
  521 + break;
  522 + case TTY_STATE_CSI:
  523 + if (ch >= '0' && ch <= '9') {
  524 + if (s->nb_esc_params < MAX_ESC_PARAMS) {
  525 + s->esc_params[s->nb_esc_params] =
  526 + s->esc_params[s->nb_esc_params] * 10 + ch - '0';
  527 + }
  528 + } else {
  529 + s->nb_esc_params++;
  530 + if (ch == ';')
  531 + break;
  532 + s->state = TTY_STATE_NORM;
  533 + switch(ch) {
  534 + case 'D':
  535 + if (s->x > 0)
  536 + s->x--;
  537 + break;
  538 + case 'C':
  539 + if (s->x < (s->width - 1))
  540 + s->x++;
  541 + break;
  542 + case 'K':
  543 + /* clear to eol */
  544 + y1 = (s->y_base + s->y) % s->total_height;
  545 + for(x = s->x; x < s->width; x++) {
  546 + c = &s->cells[y1 * s->width + x];
  547 + c->ch = ' ';
  548 + c->fgcol = s->fgcol;
  549 + c->bgcol = s->bgcol;
  550 + c++;
  551 + update_xy(s, x, s->y);
  552 + }
  553 + break;
  554 + default:
  555 + break;
  556 + }
  557 + break;
  558 + }
  559 + }
  560 +}
  561 +
  562 +void console_select(unsigned int index)
  563 +{
  564 + TextConsole *s;
  565 +
  566 + if (index >= MAX_CONSOLES)
  567 + return;
  568 + s = consoles[index];
  569 + if (s) {
  570 + active_console = s;
  571 + if (s->text_console) {
  572 + if (s->g_width != s->ds->width ||
  573 + s->g_height != s->ds->height)
  574 + text_console_resize(s);
  575 + console_refresh(s);
  576 + }
  577 + }
  578 +}
  579 +
  580 +static int console_puts(CharDriverState *chr, const uint8_t *buf, int len)
  581 +{
  582 + TextConsole *s = chr->opaque;
  583 + int i;
  584 +
  585 + console_show_cursor(s, 0);
  586 + for(i = 0; i < len; i++) {
  587 + console_putchar(s, buf[i]);
  588 + }
  589 + console_show_cursor(s, 1);
  590 + return len;
  591 +}
  592 +
  593 +static void console_chr_add_read_handler(CharDriverState *chr,
  594 + IOCanRWHandler *fd_can_read,
  595 + IOReadHandler *fd_read, void *opaque)
  596 +{
  597 + TextConsole *s = chr->opaque;
  598 + s->fd_read = fd_read;
  599 + s->fd_opaque = opaque;
  600 +}
  601 +
  602 +/* called when an ascii key is pressed */
  603 +void kbd_put_keysym(int keysym)
  604 +{
  605 + TextConsole *s;
  606 + uint8_t buf[16], *q;
  607 + int c;
  608 +
  609 + s = active_console;
  610 + if (!s || !s->text_console)
  611 + return;
  612 +
  613 + switch(keysym) {
  614 + case QEMU_KEY_CTRL_UP:
  615 + console_scroll(-1);
  616 + break;
  617 + case QEMU_KEY_CTRL_DOWN:
  618 + console_scroll(1);
  619 + break;
  620 + case QEMU_KEY_CTRL_PAGEUP:
  621 + console_scroll(-10);
  622 + break;
  623 + case QEMU_KEY_CTRL_PAGEDOWN:
  624 + console_scroll(10);
  625 + break;
  626 + default:
  627 + if (s->fd_read) {
  628 + /* convert the QEMU keysym to VT100 key string */
  629 + q = buf;
  630 + if (keysym >= 0xe100 && keysym <= 0xe11f) {
  631 + *q++ = '\033';
  632 + *q++ = '[';
  633 + c = keysym - 0xe100;
  634 + if (c >= 10)
  635 + *q++ = '0' + (c / 10);
  636 + *q++ = '0' + (c % 10);
  637 + *q++ = '~';
  638 + } else if (keysym >= 0xe120 && keysym <= 0xe17f) {
  639 + *q++ = '\033';
  640 + *q++ = '[';
  641 + *q++ = keysym & 0xff;
  642 + } else {
  643 + *q++ = keysym;
  644 + }
  645 + s->fd_read(s->fd_opaque, buf, q - buf);
  646 + }
  647 + break;
  648 + }
  649 +}
  650 +
  651 +TextConsole *graphic_console_init(DisplayState *ds)
  652 +{
  653 + TextConsole *s;
  654 +
  655 + if (nb_consoles >= MAX_CONSOLES)
  656 + return NULL;
  657 + s = qemu_mallocz(sizeof(TextConsole));
  658 + if (!s) {
  659 + return NULL;
  660 + }
  661 + if (!active_console)
  662 + active_console = s;
  663 + s->ds = ds;
  664 + consoles[nb_consoles++] = s;
  665 + return s;
  666 +}
  667 +
  668 +int is_active_console(TextConsole *s)
  669 +{
  670 + return s == active_console;
  671 +}
  672 +
  673 +CharDriverState *text_console_init(DisplayState *ds)
  674 +{
  675 + CharDriverState *chr;
  676 + TextConsole *s;
  677 + int i;
  678 + static int color_inited;
  679 +
  680 + chr = qemu_mallocz(sizeof(CharDriverState));
  681 + if (!chr)
  682 + return NULL;
  683 + s = graphic_console_init(ds);
  684 + if (!s) {
  685 + free(chr);
  686 + return NULL;
  687 + }
  688 + s->text_console = 1;
  689 + chr->opaque = s;
  690 + chr->chr_write = console_puts;
  691 + chr->chr_add_read_handler = console_chr_add_read_handler;
  692 + if (!color_inited) {
  693 + color_inited = 1;
  694 + for(i = 0; i < 8; i++) {
  695 + color_table[i] = col_expand(s->ds,
  696 + vga_get_color(s->ds, color_table_rgb[i]));
  697 + }
  698 + }
  699 + s->y_displayed = 0;
  700 + s->y_base = 0;
  701 + s->total_height = DEFAULT_BACKSCROLL;
  702 + s->x = 0;
  703 + s->y = 0;
  704 + s->fgcol = 7;
  705 + s->bgcol = 0;
  706 + s->g_width = s->ds->width;
  707 + s->g_height = s->ds->height;
  708 + text_console_resize(s);
  709 +
  710 + return chr;
  711 +}
... ...