File:  [Qemu by Fabrice Bellard] / qemu / console.c
Revision 1.1.1.6 (vendor branch): download - view: text, annotated - select for diffs
Tue Apr 24 16:50:31 2018 UTC (3 years, 2 months ago) by root
Branches: qemu, MAIN
CVS tags: qemu0105, qemu0104, qemu0103, qemu0102, qemu0101, qemu0100, HEAD
qemu 0.10.0

    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 "qemu-common.h"
   25: #include "console.h"
   26: #include "qemu-timer.h"
   27: 
   28: //#define DEBUG_CONSOLE
   29: #define DEFAULT_BACKSCROLL 512
   30: #define MAX_CONSOLES 12
   31: #define DEFAULT_MONITOR_SIZE "800x600"
   32: 
   33: #define QEMU_RGBA(r, g, b, a) (((a) << 24) | ((r) << 16) | ((g) << 8) | (b))
   34: #define QEMU_RGB(r, g, b) QEMU_RGBA(r, g, b, 0xff)
   35: 
   36: typedef struct TextAttributes {
   37:     uint8_t fgcol:4;
   38:     uint8_t bgcol:4;
   39:     uint8_t bold:1;
   40:     uint8_t uline:1;
   41:     uint8_t blink:1;
   42:     uint8_t invers:1;
   43:     uint8_t unvisible:1;
   44: } TextAttributes;
   45: 
   46: typedef struct TextCell {
   47:     uint8_t ch;
   48:     TextAttributes t_attrib;
   49: } TextCell;
   50: 
   51: #define MAX_ESC_PARAMS 3
   52: 
   53: enum TTYState {
   54:     TTY_STATE_NORM,
   55:     TTY_STATE_ESC,
   56:     TTY_STATE_CSI,
   57: };
   58: 
   59: typedef struct QEMUFIFO {
   60:     uint8_t *buf;
   61:     int buf_size;
   62:     int count, wptr, rptr;
   63: } QEMUFIFO;
   64: 
   65: static int qemu_fifo_write(QEMUFIFO *f, const uint8_t *buf, int len1)
   66: {
   67:     int l, len;
   68: 
   69:     l = f->buf_size - f->count;
   70:     if (len1 > l)
   71:         len1 = l;
   72:     len = len1;
   73:     while (len > 0) {
   74:         l = f->buf_size - f->wptr;
   75:         if (l > len)
   76:             l = len;
   77:         memcpy(f->buf + f->wptr, buf, l);
   78:         f->wptr += l;
   79:         if (f->wptr >= f->buf_size)
   80:             f->wptr = 0;
   81:         buf += l;
   82:         len -= l;
   83:     }
   84:     f->count += len1;
   85:     return len1;
   86: }
   87: 
   88: static int qemu_fifo_read(QEMUFIFO *f, uint8_t *buf, int len1)
   89: {
   90:     int l, len;
   91: 
   92:     if (len1 > f->count)
   93:         len1 = f->count;
   94:     len = len1;
   95:     while (len > 0) {
   96:         l = f->buf_size - f->rptr;
   97:         if (l > len)
   98:             l = len;
   99:         memcpy(buf, f->buf + f->rptr, l);
  100:         f->rptr += l;
  101:         if (f->rptr >= f->buf_size)
  102:             f->rptr = 0;
  103:         buf += l;
  104:         len -= l;
  105:     }
  106:     f->count -= len1;
  107:     return len1;
  108: }
  109: 
  110: typedef enum {
  111:     GRAPHIC_CONSOLE,
  112:     TEXT_CONSOLE,
  113:     TEXT_CONSOLE_FIXED_SIZE
  114: } console_type_t;
  115: 
  116: /* ??? This is mis-named.
  117:    It is used for both text and graphical consoles.  */
  118: struct TextConsole {
  119:     console_type_t console_type;
  120:     DisplayState *ds;
  121:     /* Graphic console state.  */
  122:     vga_hw_update_ptr hw_update;
  123:     vga_hw_invalidate_ptr hw_invalidate;
  124:     vga_hw_screen_dump_ptr hw_screen_dump;
  125:     vga_hw_text_update_ptr hw_text_update;
  126:     void *hw;
  127: 
  128:     int g_width, g_height;
  129:     int width;
  130:     int height;
  131:     int total_height;
  132:     int backscroll_height;
  133:     int x, y;
  134:     int x_saved, y_saved;
  135:     int y_displayed;
  136:     int y_base;
  137:     TextAttributes t_attrib_default; /* default text attributes */
  138:     TextAttributes t_attrib; /* currently active text attributes */
  139:     TextCell *cells;
  140:     int text_x[2], text_y[2], cursor_invalidate;
  141: 
  142:     int update_x0;
  143:     int update_y0;
  144:     int update_x1;
  145:     int update_y1;
  146: 
  147:     enum TTYState state;
  148:     int esc_params[MAX_ESC_PARAMS];
  149:     int nb_esc_params;
  150: 
  151:     CharDriverState *chr;
  152:     /* fifo for key pressed */
  153:     QEMUFIFO out_fifo;
  154:     uint8_t out_fifo_buf[16];
  155:     QEMUTimer *kbd_timer;
  156: };
  157: 
  158: static TextConsole *active_console;
  159: static TextConsole *consoles[MAX_CONSOLES];
  160: static int nb_consoles = 0;
  161: 
  162: void vga_hw_update(void)
  163: {
  164:     if (active_console && active_console->hw_update)
  165:         active_console->hw_update(active_console->hw);
  166: }
  167: 
  168: void vga_hw_invalidate(void)
  169: {
  170:     if (active_console->hw_invalidate)
  171:         active_console->hw_invalidate(active_console->hw);
  172: }
  173: 
  174: void vga_hw_screen_dump(const char *filename)
  175: {
  176:     TextConsole *previous_active_console;
  177: 
  178:     previous_active_console = active_console;
  179:     active_console = consoles[0];
  180:     /* There is currently no way of specifying which screen we want to dump,
  181:        so always dump the first one.  */
  182:     if (consoles[0]->hw_screen_dump)
  183:         consoles[0]->hw_screen_dump(consoles[0]->hw, filename);
  184:     active_console = previous_active_console;
  185: }
  186: 
  187: void vga_hw_text_update(console_ch_t *chardata)
  188: {
  189:     if (active_console && active_console->hw_text_update)
  190:         active_console->hw_text_update(active_console->hw, chardata);
  191: }
  192: 
  193: /* convert a RGBA color to a color index usable in graphic primitives */
  194: static unsigned int vga_get_color(DisplayState *ds, unsigned int rgba)
  195: {
  196:     unsigned int r, g, b, color;
  197: 
  198:     switch(ds_get_bits_per_pixel(ds)) {
  199: #if 0
  200:     case 8:
  201:         r = (rgba >> 16) & 0xff;
  202:         g = (rgba >> 8) & 0xff;
  203:         b = (rgba) & 0xff;
  204:         color = (rgb_to_index[r] * 6 * 6) +
  205:             (rgb_to_index[g] * 6) +
  206:             (rgb_to_index[b]);
  207:         break;
  208: #endif
  209:     case 15:
  210:         r = (rgba >> 16) & 0xff;
  211:         g = (rgba >> 8) & 0xff;
  212:         b = (rgba) & 0xff;
  213:         color = ((r >> 3) << 10) | ((g >> 3) << 5) | (b >> 3);
  214:         break;
  215:     case 16:
  216:         r = (rgba >> 16) & 0xff;
  217:         g = (rgba >> 8) & 0xff;
  218:         b = (rgba) & 0xff;
  219:         color = ((r >> 3) << 11) | ((g >> 2) << 5) | (b >> 3);
  220:         break;
  221:     case 32:
  222:     default:
  223:         color = rgba;
  224:         break;
  225:     }
  226:     return color;
  227: }
  228: 
  229: static void vga_fill_rect (DisplayState *ds,
  230:                            int posx, int posy, int width, int height, uint32_t color)
  231: {
  232:     uint8_t *d, *d1;
  233:     int x, y, bpp;
  234: 
  235:     bpp = (ds_get_bits_per_pixel(ds) + 7) >> 3;
  236:     d1 = ds_get_data(ds) +
  237:         ds_get_linesize(ds) * posy + bpp * posx;
  238:     for (y = 0; y < height; y++) {
  239:         d = d1;
  240:         switch(bpp) {
  241:         case 1:
  242:             for (x = 0; x < width; x++) {
  243:                 *((uint8_t *)d) = color;
  244:                 d++;
  245:             }
  246:             break;
  247:         case 2:
  248:             for (x = 0; x < width; x++) {
  249:                 *((uint16_t *)d) = color;
  250:                 d += 2;
  251:             }
  252:             break;
  253:         case 4:
  254:             for (x = 0; x < width; x++) {
  255:                 *((uint32_t *)d) = color;
  256:                 d += 4;
  257:             }
  258:             break;
  259:         }
  260:         d1 += ds_get_linesize(ds);
  261:     }
  262: }
  263: 
  264: /* copy from (xs, ys) to (xd, yd) a rectangle of size (w, h) */
  265: static void vga_bitblt(DisplayState *ds, int xs, int ys, int xd, int yd, int w, int h)
  266: {
  267:     const uint8_t *s;
  268:     uint8_t *d;
  269:     int wb, y, bpp;
  270: 
  271:     bpp = (ds_get_bits_per_pixel(ds) + 7) >> 3;
  272:     wb = w * bpp;
  273:     if (yd <= ys) {
  274:         s = ds_get_data(ds) +
  275:             ds_get_linesize(ds) * ys + bpp * xs;
  276:         d = ds_get_data(ds) +
  277:             ds_get_linesize(ds) * yd + bpp * xd;
  278:         for (y = 0; y < h; y++) {
  279:             memmove(d, s, wb);
  280:             d += ds_get_linesize(ds);
  281:             s += ds_get_linesize(ds);
  282:         }
  283:     } else {
  284:         s = ds_get_data(ds) +
  285:             ds_get_linesize(ds) * (ys + h - 1) + bpp * xs;
  286:         d = ds_get_data(ds) +
  287:             ds_get_linesize(ds) * (yd + h - 1) + bpp * xd;
  288:        for (y = 0; y < h; y++) {
  289:             memmove(d, s, wb);
  290:             d -= ds_get_linesize(ds);
  291:             s -= ds_get_linesize(ds);
  292:         }
  293:     }
  294: }
  295: 
  296: /***********************************************************/
  297: /* basic char display */
  298: 
  299: #define FONT_HEIGHT 16
  300: #define FONT_WIDTH 8
  301: 
  302: #include "vgafont.h"
  303: 
  304: #define cbswap_32(__x) \
  305: ((uint32_t)( \
  306: 		(((uint32_t)(__x) & (uint32_t)0x000000ffUL) << 24) | \
  307: 		(((uint32_t)(__x) & (uint32_t)0x0000ff00UL) <<  8) | \
  308: 		(((uint32_t)(__x) & (uint32_t)0x00ff0000UL) >>  8) | \
  309: 		(((uint32_t)(__x) & (uint32_t)0xff000000UL) >> 24) ))
  310: 
  311: #ifdef WORDS_BIGENDIAN
  312: #define PAT(x) x
  313: #else
  314: #define PAT(x) cbswap_32(x)
  315: #endif
  316: 
  317: static const uint32_t dmask16[16] = {
  318:     PAT(0x00000000),
  319:     PAT(0x000000ff),
  320:     PAT(0x0000ff00),
  321:     PAT(0x0000ffff),
  322:     PAT(0x00ff0000),
  323:     PAT(0x00ff00ff),
  324:     PAT(0x00ffff00),
  325:     PAT(0x00ffffff),
  326:     PAT(0xff000000),
  327:     PAT(0xff0000ff),
  328:     PAT(0xff00ff00),
  329:     PAT(0xff00ffff),
  330:     PAT(0xffff0000),
  331:     PAT(0xffff00ff),
  332:     PAT(0xffffff00),
  333:     PAT(0xffffffff),
  334: };
  335: 
  336: static const uint32_t dmask4[4] = {
  337:     PAT(0x00000000),
  338:     PAT(0x0000ffff),
  339:     PAT(0xffff0000),
  340:     PAT(0xffffffff),
  341: };
  342: 
  343: static uint32_t color_table[2][8];
  344: 
  345: enum color_names {
  346:     COLOR_BLACK   = 0,
  347:     COLOR_RED     = 1,
  348:     COLOR_GREEN   = 2,
  349:     COLOR_YELLOW  = 3,
  350:     COLOR_BLUE    = 4,
  351:     COLOR_MAGENTA = 5,
  352:     COLOR_CYAN    = 6,
  353:     COLOR_WHITE   = 7
  354: };
  355: 
  356: static const uint32_t color_table_rgb[2][8] = {
  357:     {   /* dark */
  358:         QEMU_RGB(0x00, 0x00, 0x00),  /* black */
  359:         QEMU_RGB(0xaa, 0x00, 0x00),  /* red */
  360:         QEMU_RGB(0x00, 0xaa, 0x00),  /* green */
  361:         QEMU_RGB(0xaa, 0xaa, 0x00),  /* yellow */
  362:         QEMU_RGB(0x00, 0x00, 0xaa),  /* blue */
  363:         QEMU_RGB(0xaa, 0x00, 0xaa),  /* magenta */
  364:         QEMU_RGB(0x00, 0xaa, 0xaa),  /* cyan */
  365:         QEMU_RGB(0xaa, 0xaa, 0xaa),  /* white */
  366:     },
  367:     {   /* bright */
  368:         QEMU_RGB(0x00, 0x00, 0x00),  /* black */
  369:         QEMU_RGB(0xff, 0x00, 0x00),  /* red */
  370:         QEMU_RGB(0x00, 0xff, 0x00),  /* green */
  371:         QEMU_RGB(0xff, 0xff, 0x00),  /* yellow */
  372:         QEMU_RGB(0x00, 0x00, 0xff),  /* blue */
  373:         QEMU_RGB(0xff, 0x00, 0xff),  /* magenta */
  374:         QEMU_RGB(0x00, 0xff, 0xff),  /* cyan */
  375:         QEMU_RGB(0xff, 0xff, 0xff),  /* white */
  376:     }
  377: };
  378: 
  379: static inline unsigned int col_expand(DisplayState *ds, unsigned int col)
  380: {
  381:     switch(ds_get_bits_per_pixel(ds)) {
  382:     case 8:
  383:         col |= col << 8;
  384:         col |= col << 16;
  385:         break;
  386:     case 15:
  387:     case 16:
  388:         col |= col << 16;
  389:         break;
  390:     default:
  391:         break;
  392:     }
  393: 
  394:     return col;
  395: }
  396: #ifdef DEBUG_CONSOLE
  397: static void console_print_text_attributes(TextAttributes *t_attrib, char ch)
  398: {
  399:     if (t_attrib->bold) {
  400:         printf("b");
  401:     } else {
  402:         printf(" ");
  403:     }
  404:     if (t_attrib->uline) {
  405:         printf("u");
  406:     } else {
  407:         printf(" ");
  408:     }
  409:     if (t_attrib->blink) {
  410:         printf("l");
  411:     } else {
  412:         printf(" ");
  413:     }
  414:     if (t_attrib->invers) {
  415:         printf("i");
  416:     } else {
  417:         printf(" ");
  418:     }
  419:     if (t_attrib->unvisible) {
  420:         printf("n");
  421:     } else {
  422:         printf(" ");
  423:     }
  424: 
  425:     printf(" fg: %d bg: %d ch:'%2X' '%c'\n", t_attrib->fgcol, t_attrib->bgcol, ch, ch);
  426: }
  427: #endif
  428: 
  429: static void vga_putcharxy(DisplayState *ds, int x, int y, int ch,
  430:                           TextAttributes *t_attrib)
  431: {
  432:     uint8_t *d;
  433:     const uint8_t *font_ptr;
  434:     unsigned int font_data, linesize, xorcol, bpp;
  435:     int i;
  436:     unsigned int fgcol, bgcol;
  437: 
  438: #ifdef DEBUG_CONSOLE
  439:     printf("x: %2i y: %2i", x, y);
  440:     console_print_text_attributes(t_attrib, ch);
  441: #endif
  442: 
  443:     if (t_attrib->invers) {
  444:         bgcol = color_table[t_attrib->bold][t_attrib->fgcol];
  445:         fgcol = color_table[t_attrib->bold][t_attrib->bgcol];
  446:     } else {
  447:         fgcol = color_table[t_attrib->bold][t_attrib->fgcol];
  448:         bgcol = color_table[t_attrib->bold][t_attrib->bgcol];
  449:     }
  450: 
  451:     bpp = (ds_get_bits_per_pixel(ds) + 7) >> 3;
  452:     d = ds_get_data(ds) +
  453:         ds_get_linesize(ds) * y * FONT_HEIGHT + bpp * x * FONT_WIDTH;
  454:     linesize = ds_get_linesize(ds);
  455:     font_ptr = vgafont16 + FONT_HEIGHT * ch;
  456:     xorcol = bgcol ^ fgcol;
  457:     switch(ds_get_bits_per_pixel(ds)) {
  458:     case 8:
  459:         for(i = 0; i < FONT_HEIGHT; i++) {
  460:             font_data = *font_ptr++;
  461:             if (t_attrib->uline
  462:                 && ((i == FONT_HEIGHT - 2) || (i == FONT_HEIGHT - 3))) {
  463:                 font_data = 0xFFFF;
  464:             }
  465:             ((uint32_t *)d)[0] = (dmask16[(font_data >> 4)] & xorcol) ^ bgcol;
  466:             ((uint32_t *)d)[1] = (dmask16[(font_data >> 0) & 0xf] & xorcol) ^ bgcol;
  467:             d += linesize;
  468:         }
  469:         break;
  470:     case 16:
  471:     case 15:
  472:         for(i = 0; i < FONT_HEIGHT; i++) {
  473:             font_data = *font_ptr++;
  474:             if (t_attrib->uline
  475:                 && ((i == FONT_HEIGHT - 2) || (i == FONT_HEIGHT - 3))) {
  476:                 font_data = 0xFFFF;
  477:             }
  478:             ((uint32_t *)d)[0] = (dmask4[(font_data >> 6)] & xorcol) ^ bgcol;
  479:             ((uint32_t *)d)[1] = (dmask4[(font_data >> 4) & 3] & xorcol) ^ bgcol;
  480:             ((uint32_t *)d)[2] = (dmask4[(font_data >> 2) & 3] & xorcol) ^ bgcol;
  481:             ((uint32_t *)d)[3] = (dmask4[(font_data >> 0) & 3] & xorcol) ^ bgcol;
  482:             d += linesize;
  483:         }
  484:         break;
  485:     case 32:
  486:         for(i = 0; i < FONT_HEIGHT; i++) {
  487:             font_data = *font_ptr++;
  488:             if (t_attrib->uline && ((i == FONT_HEIGHT - 2) || (i == FONT_HEIGHT - 3))) {
  489:                 font_data = 0xFFFF;
  490:             }
  491:             ((uint32_t *)d)[0] = (-((font_data >> 7)) & xorcol) ^ bgcol;
  492:             ((uint32_t *)d)[1] = (-((font_data >> 6) & 1) & xorcol) ^ bgcol;
  493:             ((uint32_t *)d)[2] = (-((font_data >> 5) & 1) & xorcol) ^ bgcol;
  494:             ((uint32_t *)d)[3] = (-((font_data >> 4) & 1) & xorcol) ^ bgcol;
  495:             ((uint32_t *)d)[4] = (-((font_data >> 3) & 1) & xorcol) ^ bgcol;
  496:             ((uint32_t *)d)[5] = (-((font_data >> 2) & 1) & xorcol) ^ bgcol;
  497:             ((uint32_t *)d)[6] = (-((font_data >> 1) & 1) & xorcol) ^ bgcol;
  498:             ((uint32_t *)d)[7] = (-((font_data >> 0) & 1) & xorcol) ^ bgcol;
  499:             d += linesize;
  500:         }
  501:         break;
  502:     }
  503: }
  504: 
  505: static void text_console_resize(TextConsole *s)
  506: {
  507:     TextCell *cells, *c, *c1;
  508:     int w1, x, y, last_width;
  509: 
  510:     last_width = s->width;
  511:     s->width = s->g_width / FONT_WIDTH;
  512:     s->height = s->g_height / FONT_HEIGHT;
  513: 
  514:     w1 = last_width;
  515:     if (s->width < w1)
  516:         w1 = s->width;
  517: 
  518:     cells = qemu_malloc(s->width * s->total_height * sizeof(TextCell));
  519:     for(y = 0; y < s->total_height; y++) {
  520:         c = &cells[y * s->width];
  521:         if (w1 > 0) {
  522:             c1 = &s->cells[y * last_width];
  523:             for(x = 0; x < w1; x++) {
  524:                 *c++ = *c1++;
  525:             }
  526:         }
  527:         for(x = w1; x < s->width; x++) {
  528:             c->ch = ' ';
  529:             c->t_attrib = s->t_attrib_default;
  530:             c++;
  531:         }
  532:     }
  533:     qemu_free(s->cells);
  534:     s->cells = cells;
  535: }
  536: 
  537: static inline void text_update_xy(TextConsole *s, int x, int y)
  538: {
  539:     s->text_x[0] = MIN(s->text_x[0], x);
  540:     s->text_x[1] = MAX(s->text_x[1], x);
  541:     s->text_y[0] = MIN(s->text_y[0], y);
  542:     s->text_y[1] = MAX(s->text_y[1], y);
  543: }
  544: 
  545: static void invalidate_xy(TextConsole *s, int x, int y)
  546: {
  547:     if (s->update_x0 > x * FONT_WIDTH)
  548:         s->update_x0 = x * FONT_WIDTH;
  549:     if (s->update_y0 > y * FONT_HEIGHT)
  550:         s->update_y0 = y * FONT_HEIGHT;
  551:     if (s->update_x1 < (x + 1) * FONT_WIDTH)
  552:         s->update_x1 = (x + 1) * FONT_WIDTH;
  553:     if (s->update_y1 < (y + 1) * FONT_HEIGHT)
  554:         s->update_y1 = (y + 1) * FONT_HEIGHT;
  555: }
  556: 
  557: static void update_xy(TextConsole *s, int x, int y)
  558: {
  559:     TextCell *c;
  560:     int y1, y2;
  561: 
  562:     if (s == active_console) {
  563:         if (!ds_get_bits_per_pixel(s->ds)) {
  564:             text_update_xy(s, x, y);
  565:             return;
  566:         }
  567: 
  568:         y1 = (s->y_base + y) % s->total_height;
  569:         y2 = y1 - s->y_displayed;
  570:         if (y2 < 0)
  571:             y2 += s->total_height;
  572:         if (y2 < s->height) {
  573:             c = &s->cells[y1 * s->width + x];
  574:             vga_putcharxy(s->ds, x, y2, c->ch,
  575:                           &(c->t_attrib));
  576:             invalidate_xy(s, x, y2);
  577:         }
  578:     }
  579: }
  580: 
  581: static void console_show_cursor(TextConsole *s, int show)
  582: {
  583:     TextCell *c;
  584:     int y, y1;
  585: 
  586:     if (s == active_console) {
  587:         int x = s->x;
  588: 
  589:         if (!ds_get_bits_per_pixel(s->ds)) {
  590:             s->cursor_invalidate = 1;
  591:             return;
  592:         }
  593: 
  594:         if (x >= s->width) {
  595:             x = s->width - 1;
  596:         }
  597:         y1 = (s->y_base + s->y) % s->total_height;
  598:         y = y1 - s->y_displayed;
  599:         if (y < 0)
  600:             y += s->total_height;
  601:         if (y < s->height) {
  602:             c = &s->cells[y1 * s->width + x];
  603:             if (show) {
  604:                 TextAttributes t_attrib = s->t_attrib_default;
  605:                 t_attrib.invers = !(t_attrib.invers); /* invert fg and bg */
  606:                 vga_putcharxy(s->ds, x, y, c->ch, &t_attrib);
  607:             } else {
  608:                 vga_putcharxy(s->ds, x, y, c->ch, &(c->t_attrib));
  609:             }
  610:             invalidate_xy(s, x, y);
  611:         }
  612:     }
  613: }
  614: 
  615: static void console_refresh(TextConsole *s)
  616: {
  617:     TextCell *c;
  618:     int x, y, y1;
  619: 
  620:     if (s != active_console)
  621:         return;
  622:     if (!ds_get_bits_per_pixel(s->ds)) {
  623:         s->text_x[0] = 0;
  624:         s->text_y[0] = 0;
  625:         s->text_x[1] = s->width - 1;
  626:         s->text_y[1] = s->height - 1;
  627:         s->cursor_invalidate = 1;
  628:         return;
  629:     }
  630: 
  631:     vga_fill_rect(s->ds, 0, 0, ds_get_width(s->ds), ds_get_height(s->ds),
  632:                   color_table[0][COLOR_BLACK]);
  633:     y1 = s->y_displayed;
  634:     for(y = 0; y < s->height; y++) {
  635:         c = s->cells + y1 * s->width;
  636:         for(x = 0; x < s->width; x++) {
  637:             vga_putcharxy(s->ds, x, y, c->ch,
  638:                           &(c->t_attrib));
  639:             c++;
  640:         }
  641:         if (++y1 == s->total_height)
  642:             y1 = 0;
  643:     }
  644:     console_show_cursor(s, 1);
  645:     dpy_update(s->ds, 0, 0, ds_get_width(s->ds), ds_get_height(s->ds));
  646: }
  647: 
  648: static void console_scroll(int ydelta)
  649: {
  650:     TextConsole *s;
  651:     int i, y1;
  652: 
  653:     s = active_console;
  654:     if (!s || (s->console_type == GRAPHIC_CONSOLE))
  655:         return;
  656: 
  657:     if (ydelta > 0) {
  658:         for(i = 0; i < ydelta; i++) {
  659:             if (s->y_displayed == s->y_base)
  660:                 break;
  661:             if (++s->y_displayed == s->total_height)
  662:                 s->y_displayed = 0;
  663:         }
  664:     } else {
  665:         ydelta = -ydelta;
  666:         i = s->backscroll_height;
  667:         if (i > s->total_height - s->height)
  668:             i = s->total_height - s->height;
  669:         y1 = s->y_base - i;
  670:         if (y1 < 0)
  671:             y1 += s->total_height;
  672:         for(i = 0; i < ydelta; i++) {
  673:             if (s->y_displayed == y1)
  674:                 break;
  675:             if (--s->y_displayed < 0)
  676:                 s->y_displayed = s->total_height - 1;
  677:         }
  678:     }
  679:     console_refresh(s);
  680: }
  681: 
  682: static void console_put_lf(TextConsole *s)
  683: {
  684:     TextCell *c;
  685:     int x, y1;
  686: 
  687:     s->y++;
  688:     if (s->y >= s->height) {
  689:         s->y = s->height - 1;
  690: 
  691:         if (s->y_displayed == s->y_base) {
  692:             if (++s->y_displayed == s->total_height)
  693:                 s->y_displayed = 0;
  694:         }
  695:         if (++s->y_base == s->total_height)
  696:             s->y_base = 0;
  697:         if (s->backscroll_height < s->total_height)
  698:             s->backscroll_height++;
  699:         y1 = (s->y_base + s->height - 1) % s->total_height;
  700:         c = &s->cells[y1 * s->width];
  701:         for(x = 0; x < s->width; x++) {
  702:             c->ch = ' ';
  703:             c->t_attrib = s->t_attrib_default;
  704:             c++;
  705:         }
  706:         if (s == active_console && s->y_displayed == s->y_base) {
  707:             if (!ds_get_bits_per_pixel(s->ds)) {
  708:                 s->text_x[0] = 0;
  709:                 s->text_y[0] = 0;
  710:                 s->text_x[1] = s->width - 1;
  711:                 s->text_y[1] = s->height - 1;
  712:                 return;
  713:             }
  714: 
  715:             vga_bitblt(s->ds, 0, FONT_HEIGHT, 0, 0,
  716:                        s->width * FONT_WIDTH,
  717:                        (s->height - 1) * FONT_HEIGHT);
  718:             vga_fill_rect(s->ds, 0, (s->height - 1) * FONT_HEIGHT,
  719:                           s->width * FONT_WIDTH, FONT_HEIGHT,
  720:                           color_table[0][s->t_attrib_default.bgcol]);
  721:             s->update_x0 = 0;
  722:             s->update_y0 = 0;
  723:             s->update_x1 = s->width * FONT_WIDTH;
  724:             s->update_y1 = s->height * FONT_HEIGHT;
  725:         }
  726:     }
  727: }
  728: 
  729: /* Set console attributes depending on the current escape codes.
  730:  * NOTE: I know this code is not very efficient (checking every color for it
  731:  * self) but it is more readable and better maintainable.
  732:  */
  733: static void console_handle_escape(TextConsole *s)
  734: {
  735:     int i;
  736: 
  737:     for (i=0; i<s->nb_esc_params; i++) {
  738:         switch (s->esc_params[i]) {
  739:             case 0: /* reset all console attributes to default */
  740:                 s->t_attrib = s->t_attrib_default;
  741:                 break;
  742:             case 1:
  743:                 s->t_attrib.bold = 1;
  744:                 break;
  745:             case 4:
  746:                 s->t_attrib.uline = 1;
  747:                 break;
  748:             case 5:
  749:                 s->t_attrib.blink = 1;
  750:                 break;
  751:             case 7:
  752:                 s->t_attrib.invers = 1;
  753:                 break;
  754:             case 8:
  755:                 s->t_attrib.unvisible = 1;
  756:                 break;
  757:             case 22:
  758:                 s->t_attrib.bold = 0;
  759:                 break;
  760:             case 24:
  761:                 s->t_attrib.uline = 0;
  762:                 break;
  763:             case 25:
  764:                 s->t_attrib.blink = 0;
  765:                 break;
  766:             case 27:
  767:                 s->t_attrib.invers = 0;
  768:                 break;
  769:             case 28:
  770:                 s->t_attrib.unvisible = 0;
  771:                 break;
  772:             /* set foreground color */
  773:             case 30:
  774:                 s->t_attrib.fgcol=COLOR_BLACK;
  775:                 break;
  776:             case 31:
  777:                 s->t_attrib.fgcol=COLOR_RED;
  778:                 break;
  779:             case 32:
  780:                 s->t_attrib.fgcol=COLOR_GREEN;
  781:                 break;
  782:             case 33:
  783:                 s->t_attrib.fgcol=COLOR_YELLOW;
  784:                 break;
  785:             case 34:
  786:                 s->t_attrib.fgcol=COLOR_BLUE;
  787:                 break;
  788:             case 35:
  789:                 s->t_attrib.fgcol=COLOR_MAGENTA;
  790:                 break;
  791:             case 36:
  792:                 s->t_attrib.fgcol=COLOR_CYAN;
  793:                 break;
  794:             case 37:
  795:                 s->t_attrib.fgcol=COLOR_WHITE;
  796:                 break;
  797:             /* set background color */
  798:             case 40:
  799:                 s->t_attrib.bgcol=COLOR_BLACK;
  800:                 break;
  801:             case 41:
  802:                 s->t_attrib.bgcol=COLOR_RED;
  803:                 break;
  804:             case 42:
  805:                 s->t_attrib.bgcol=COLOR_GREEN;
  806:                 break;
  807:             case 43:
  808:                 s->t_attrib.bgcol=COLOR_YELLOW;
  809:                 break;
  810:             case 44:
  811:                 s->t_attrib.bgcol=COLOR_BLUE;
  812:                 break;
  813:             case 45:
  814:                 s->t_attrib.bgcol=COLOR_MAGENTA;
  815:                 break;
  816:             case 46:
  817:                 s->t_attrib.bgcol=COLOR_CYAN;
  818:                 break;
  819:             case 47:
  820:                 s->t_attrib.bgcol=COLOR_WHITE;
  821:                 break;
  822:         }
  823:     }
  824: }
  825: 
  826: static void console_clear_xy(TextConsole *s, int x, int y)
  827: {
  828:     int y1 = (s->y_base + y) % s->total_height;
  829:     TextCell *c = &s->cells[y1 * s->width + x];
  830:     c->ch = ' ';
  831:     c->t_attrib = s->t_attrib_default;
  832:     c++;
  833:     update_xy(s, x, y);
  834: }
  835: 
  836: static void console_putchar(TextConsole *s, int ch)
  837: {
  838:     TextCell *c;
  839:     int y1, i;
  840:     int x, y;
  841: 
  842:     switch(s->state) {
  843:     case TTY_STATE_NORM:
  844:         switch(ch) {
  845:         case '\r':  /* carriage return */
  846:             s->x = 0;
  847:             break;
  848:         case '\n':  /* newline */
  849:             console_put_lf(s);
  850:             break;
  851:         case '\b':  /* backspace */
  852:             if (s->x > 0)
  853:                 s->x--;
  854:             break;
  855:         case '\t':  /* tabspace */
  856:             if (s->x + (8 - (s->x % 8)) > s->width) {
  857:                 s->x = 0;
  858:                 console_put_lf(s);
  859:             } else {
  860:                 s->x = s->x + (8 - (s->x % 8));
  861:             }
  862:             break;
  863:         case '\a':  /* alert aka. bell */
  864:             /* TODO: has to be implemented */
  865:             break;
  866:         case 14:
  867:             /* SI (shift in), character set 0 (ignored) */
  868:             break;
  869:         case 15:
  870:             /* SO (shift out), character set 1 (ignored) */
  871:             break;
  872:         case 27:    /* esc (introducing an escape sequence) */
  873:             s->state = TTY_STATE_ESC;
  874:             break;
  875:         default:
  876:             if (s->x >= s->width) {
  877:                 /* line wrap */
  878:                 s->x = 0;
  879:                 console_put_lf(s);
  880:             }
  881:             y1 = (s->y_base + s->y) % s->total_height;
  882:             c = &s->cells[y1 * s->width + s->x];
  883:             c->ch = ch;
  884:             c->t_attrib = s->t_attrib;
  885:             update_xy(s, s->x, s->y);
  886:             s->x++;
  887:             break;
  888:         }
  889:         break;
  890:     case TTY_STATE_ESC: /* check if it is a terminal escape sequence */
  891:         if (ch == '[') {
  892:             for(i=0;i<MAX_ESC_PARAMS;i++)
  893:                 s->esc_params[i] = 0;
  894:             s->nb_esc_params = 0;
  895:             s->state = TTY_STATE_CSI;
  896:         } else {
  897:             s->state = TTY_STATE_NORM;
  898:         }
  899:         break;
  900:     case TTY_STATE_CSI: /* handle escape sequence parameters */
  901:         if (ch >= '0' && ch <= '9') {
  902:             if (s->nb_esc_params < MAX_ESC_PARAMS) {
  903:                 s->esc_params[s->nb_esc_params] =
  904:                     s->esc_params[s->nb_esc_params] * 10 + ch - '0';
  905:             }
  906:         } else {
  907:             s->nb_esc_params++;
  908:             if (ch == ';')
  909:                 break;
  910: #ifdef DEBUG_CONSOLE
  911:             fprintf(stderr, "escape sequence CSI%d;%d%c, %d parameters\n",
  912:                     s->esc_params[0], s->esc_params[1], ch, s->nb_esc_params);
  913: #endif
  914:             s->state = TTY_STATE_NORM;
  915:             switch(ch) {
  916:             case 'A':
  917:                 /* move cursor up */
  918:                 if (s->esc_params[0] == 0) {
  919:                     s->esc_params[0] = 1;
  920:                 }
  921:                 s->y -= s->esc_params[0];
  922:                 if (s->y < 0) {
  923:                     s->y = 0;
  924:                 }
  925:                 break;
  926:             case 'B':
  927:                 /* move cursor down */
  928:                 if (s->esc_params[0] == 0) {
  929:                     s->esc_params[0] = 1;
  930:                 }
  931:                 s->y += s->esc_params[0];
  932:                 if (s->y >= s->height) {
  933:                     s->y = s->height - 1;
  934:                 }
  935:                 break;
  936:             case 'C':
  937:                 /* move cursor right */
  938:                 if (s->esc_params[0] == 0) {
  939:                     s->esc_params[0] = 1;
  940:                 }
  941:                 s->x += s->esc_params[0];
  942:                 if (s->x >= s->width) {
  943:                     s->x = s->width - 1;
  944:                 }
  945:                 break;
  946:             case 'D':
  947:                 /* move cursor left */
  948:                 if (s->esc_params[0] == 0) {
  949:                     s->esc_params[0] = 1;
  950:                 }
  951:                 s->x -= s->esc_params[0];
  952:                 if (s->x < 0) {
  953:                     s->x = 0;
  954:                 }
  955:                 break;
  956:             case 'G':
  957:                 /* move cursor to column */
  958:                 s->x = s->esc_params[0] - 1;
  959:                 if (s->x < 0) {
  960:                     s->x = 0;
  961:                 }
  962:                 break;
  963:             case 'f':
  964:             case 'H':
  965:                 /* move cursor to row, column */
  966:                 s->x = s->esc_params[1] - 1;
  967:                 if (s->x < 0) {
  968:                     s->x = 0;
  969:                 }
  970:                 s->y = s->esc_params[0] - 1;
  971:                 if (s->y < 0) {
  972:                     s->y = 0;
  973:                 }
  974:                 break;
  975:             case 'J':
  976:                 switch (s->esc_params[0]) {
  977:                 case 0:
  978:                     /* clear to end of screen */
  979:                     for (y = s->y; y < s->height; y++) {
  980:                         for (x = 0; x < s->width; x++) {
  981:                             if (y == s->y && x < s->x) {
  982:                                 continue;
  983:                             }
  984:                             console_clear_xy(s, x, y);
  985:                         }
  986:                     }
  987:                     break;
  988:                 case 1:
  989:                     /* clear from beginning of screen */
  990:                     for (y = 0; y <= s->y; y++) {
  991:                         for (x = 0; x < s->width; x++) {
  992:                             if (y == s->y && x > s->x) {
  993:                                 break;
  994:                             }
  995:                             console_clear_xy(s, x, y);
  996:                         }
  997:                     }
  998:                     break;
  999:                 case 2:
 1000:                     /* clear entire screen */
 1001:                     for (y = 0; y <= s->height; y++) {
 1002:                         for (x = 0; x < s->width; x++) {
 1003:                             console_clear_xy(s, x, y);
 1004:                         }
 1005:                     }
 1006:                 break;
 1007:                 }
 1008:             case 'K':
 1009:                 switch (s->esc_params[0]) {
 1010:                 case 0:
 1011:                 /* clear to eol */
 1012:                 for(x = s->x; x < s->width; x++) {
 1013:                         console_clear_xy(s, x, s->y);
 1014:                 }
 1015:                 break;
 1016:                 case 1:
 1017:                     /* clear from beginning of line */
 1018:                     for (x = 0; x <= s->x; x++) {
 1019:                         console_clear_xy(s, x, s->y);
 1020:                     }
 1021:                     break;
 1022:                 case 2:
 1023:                     /* clear entire line */
 1024:                     for(x = 0; x < s->width; x++) {
 1025:                         console_clear_xy(s, x, s->y);
 1026:                     }
 1027:                 break;
 1028:             }
 1029:                 break;
 1030:             case 'm':
 1031:             console_handle_escape(s);
 1032:             break;
 1033:             case 'n':
 1034:                 /* report cursor position */
 1035:                 /* TODO: send ESC[row;colR */
 1036:                 break;
 1037:             case 's':
 1038:                 /* save cursor position */
 1039:                 s->x_saved = s->x;
 1040:                 s->y_saved = s->y;
 1041:                 break;
 1042:             case 'u':
 1043:                 /* restore cursor position */
 1044:                 s->x = s->x_saved;
 1045:                 s->y = s->y_saved;
 1046:                 break;
 1047:             default:
 1048: #ifdef DEBUG_CONSOLE
 1049:                 fprintf(stderr, "unhandled escape character '%c'\n", ch);
 1050: #endif
 1051:                 break;
 1052:             }
 1053:             break;
 1054:         }
 1055:     }
 1056: }
 1057: 
 1058: void console_select(unsigned int index)
 1059: {
 1060:     TextConsole *s;
 1061: 
 1062:     if (index >= MAX_CONSOLES)
 1063:         return;
 1064:     active_console->g_width = ds_get_width(active_console->ds);
 1065:     active_console->g_height = ds_get_height(active_console->ds);
 1066:     s = consoles[index];
 1067:     if (s) {
 1068:         DisplayState *ds = s->ds;
 1069:         active_console = s;
 1070:         if (ds_get_bits_per_pixel(s->ds)) {
 1071:             ds->surface = qemu_resize_displaysurface(ds->surface, s->g_width,
 1072:                     s->g_height, 32, 4 * s->g_width);
 1073:         } else {
 1074:             s->ds->surface->width = s->width;
 1075:             s->ds->surface->height = s->height;
 1076:         }
 1077:         dpy_resize(s->ds);
 1078:         vga_hw_invalidate();
 1079:     }
 1080: }
 1081: 
 1082: static int console_puts(CharDriverState *chr, const uint8_t *buf, int len)
 1083: {
 1084:     TextConsole *s = chr->opaque;
 1085:     int i;
 1086: 
 1087:     s->update_x0 = s->width * FONT_WIDTH;
 1088:     s->update_y0 = s->height * FONT_HEIGHT;
 1089:     s->update_x1 = 0;
 1090:     s->update_y1 = 0;
 1091:     console_show_cursor(s, 0);
 1092:     for(i = 0; i < len; i++) {
 1093:         console_putchar(s, buf[i]);
 1094:     }
 1095:     console_show_cursor(s, 1);
 1096:     if (ds_get_bits_per_pixel(s->ds) && s->update_x0 < s->update_x1) {
 1097:         dpy_update(s->ds, s->update_x0, s->update_y0,
 1098:                    s->update_x1 - s->update_x0,
 1099:                    s->update_y1 - s->update_y0);
 1100:     }
 1101:     return len;
 1102: }
 1103: 
 1104: static void console_send_event(CharDriverState *chr, int event)
 1105: {
 1106:     TextConsole *s = chr->opaque;
 1107:     int i;
 1108: 
 1109:     if (event == CHR_EVENT_FOCUS) {
 1110:         for(i = 0; i < nb_consoles; i++) {
 1111:             if (consoles[i] == s) {
 1112:                 console_select(i);
 1113:                 break;
 1114:             }
 1115:         }
 1116:     }
 1117: }
 1118: 
 1119: static void kbd_send_chars(void *opaque)
 1120: {
 1121:     TextConsole *s = opaque;
 1122:     int len;
 1123:     uint8_t buf[16];
 1124: 
 1125:     len = qemu_chr_can_read(s->chr);
 1126:     if (len > s->out_fifo.count)
 1127:         len = s->out_fifo.count;
 1128:     if (len > 0) {
 1129:         if (len > sizeof(buf))
 1130:             len = sizeof(buf);
 1131:         qemu_fifo_read(&s->out_fifo, buf, len);
 1132:         qemu_chr_read(s->chr, buf, len);
 1133:     }
 1134:     /* characters are pending: we send them a bit later (XXX:
 1135:        horrible, should change char device API) */
 1136:     if (s->out_fifo.count > 0) {
 1137:         qemu_mod_timer(s->kbd_timer, qemu_get_clock(rt_clock) + 1);
 1138:     }
 1139: }
 1140: 
 1141: /* called when an ascii key is pressed */
 1142: void kbd_put_keysym(int keysym)
 1143: {
 1144:     TextConsole *s;
 1145:     uint8_t buf[16], *q;
 1146:     int c;
 1147: 
 1148:     s = active_console;
 1149:     if (!s || (s->console_type == GRAPHIC_CONSOLE))
 1150:         return;
 1151: 
 1152:     switch(keysym) {
 1153:     case QEMU_KEY_CTRL_UP:
 1154:         console_scroll(-1);
 1155:         break;
 1156:     case QEMU_KEY_CTRL_DOWN:
 1157:         console_scroll(1);
 1158:         break;
 1159:     case QEMU_KEY_CTRL_PAGEUP:
 1160:         console_scroll(-10);
 1161:         break;
 1162:     case QEMU_KEY_CTRL_PAGEDOWN:
 1163:         console_scroll(10);
 1164:         break;
 1165:     default:
 1166:         /* convert the QEMU keysym to VT100 key string */
 1167:         q = buf;
 1168:         if (keysym >= 0xe100 && keysym <= 0xe11f) {
 1169:             *q++ = '\033';
 1170:             *q++ = '[';
 1171:             c = keysym - 0xe100;
 1172:             if (c >= 10)
 1173:                 *q++ = '0' + (c / 10);
 1174:             *q++ = '0' + (c % 10);
 1175:             *q++ = '~';
 1176:         } else if (keysym >= 0xe120 && keysym <= 0xe17f) {
 1177:             *q++ = '\033';
 1178:             *q++ = '[';
 1179:             *q++ = keysym & 0xff;
 1180:         } else {
 1181:                 *q++ = keysym;
 1182:         }
 1183:         if (s->chr->chr_read) {
 1184:             qemu_fifo_write(&s->out_fifo, buf, q - buf);
 1185:             kbd_send_chars(s);
 1186:         }
 1187:         break;
 1188:     }
 1189: }
 1190: 
 1191: static void text_console_invalidate(void *opaque)
 1192: {
 1193:     TextConsole *s = (TextConsole *) opaque;
 1194:     if (!ds_get_bits_per_pixel(s->ds) && s->console_type == TEXT_CONSOLE) {
 1195:         s->g_width = ds_get_width(s->ds);
 1196:         s->g_height = ds_get_height(s->ds);
 1197:         text_console_resize(s);
 1198:     }
 1199:     console_refresh(s);
 1200: }
 1201: 
 1202: static void text_console_update(void *opaque, console_ch_t *chardata)
 1203: {
 1204:     TextConsole *s = (TextConsole *) opaque;
 1205:     int i, j, src;
 1206: 
 1207:     if (s->text_x[0] <= s->text_x[1]) {
 1208:         src = (s->y_base + s->text_y[0]) * s->width;
 1209:         chardata += s->text_y[0] * s->width;
 1210:         for (i = s->text_y[0]; i <= s->text_y[1]; i ++)
 1211:             for (j = 0; j < s->width; j ++, src ++)
 1212:                 console_write_ch(chardata ++, s->cells[src].ch |
 1213:                                 (s->cells[src].t_attrib.fgcol << 12) |
 1214:                                 (s->cells[src].t_attrib.bgcol << 8) |
 1215:                                 (s->cells[src].t_attrib.bold << 21));
 1216:         dpy_update(s->ds, s->text_x[0], s->text_y[0],
 1217:                    s->text_x[1] - s->text_x[0], i - s->text_y[0]);
 1218:         s->text_x[0] = s->width;
 1219:         s->text_y[0] = s->height;
 1220:         s->text_x[1] = 0;
 1221:         s->text_y[1] = 0;
 1222:     }
 1223:     if (s->cursor_invalidate) {
 1224:         dpy_cursor(s->ds, s->x, s->y);
 1225:         s->cursor_invalidate = 0;
 1226:     }
 1227: }
 1228: 
 1229: static TextConsole *get_graphic_console(DisplayState *ds)
 1230: {
 1231:     int i;
 1232:     TextConsole *s;
 1233:     for (i = 0; i < nb_consoles; i++) {
 1234:         s = consoles[i];
 1235:         if (s->console_type == GRAPHIC_CONSOLE && s->ds == ds)
 1236:             return s;
 1237:     }
 1238:     return NULL;
 1239: }
 1240: 
 1241: static TextConsole *new_console(DisplayState *ds, console_type_t console_type)
 1242: {
 1243:     TextConsole *s;
 1244:     int i;
 1245: 
 1246:     if (nb_consoles >= MAX_CONSOLES)
 1247:         return NULL;
 1248:     s = qemu_mallocz(sizeof(TextConsole));
 1249:     if (!active_console || ((active_console->console_type != GRAPHIC_CONSOLE) &&
 1250:         (console_type == GRAPHIC_CONSOLE))) {
 1251:         active_console = s;
 1252:     }
 1253:     s->ds = ds;
 1254:     s->console_type = console_type;
 1255:     if (console_type != GRAPHIC_CONSOLE) {
 1256:         consoles[nb_consoles++] = s;
 1257:     } else {
 1258:         /* HACK: Put graphical consoles before text consoles.  */
 1259:         for (i = nb_consoles; i > 0; i--) {
 1260:             if (consoles[i - 1]->console_type == GRAPHIC_CONSOLE)
 1261:                 break;
 1262:             consoles[i] = consoles[i - 1];
 1263:         }
 1264:         consoles[i] = s;
 1265:         nb_consoles++;
 1266:     }
 1267:     return s;
 1268: }
 1269: 
 1270: DisplayState *graphic_console_init(vga_hw_update_ptr update,
 1271:                                    vga_hw_invalidate_ptr invalidate,
 1272:                                    vga_hw_screen_dump_ptr screen_dump,
 1273:                                    vga_hw_text_update_ptr text_update,
 1274:                                    void *opaque)
 1275: {
 1276:     TextConsole *s;
 1277:     DisplayState *ds;
 1278: 
 1279:     ds = (DisplayState *) qemu_mallocz(sizeof(DisplayState));
 1280:     ds->surface = qemu_create_displaysurface(640, 480, 32, 640 * 4);
 1281: 
 1282:     s = new_console(ds, GRAPHIC_CONSOLE);
 1283:     if (s == NULL) {
 1284:         qemu_free_displaysurface(ds->surface);
 1285:         qemu_free(ds);
 1286:         return NULL;
 1287:     }
 1288:     s->hw_update = update;
 1289:     s->hw_invalidate = invalidate;
 1290:     s->hw_screen_dump = screen_dump;
 1291:     s->hw_text_update = text_update;
 1292:     s->hw = opaque;
 1293: 
 1294:     register_displaystate(ds);
 1295:     return ds;
 1296: }
 1297: 
 1298: int is_graphic_console(void)
 1299: {
 1300:     return active_console && active_console->console_type == GRAPHIC_CONSOLE;
 1301: }
 1302: 
 1303: int is_fixedsize_console(void)
 1304: {
 1305:     return active_console && active_console->console_type != TEXT_CONSOLE;
 1306: }
 1307: 
 1308: void console_color_init(DisplayState *ds)
 1309: {
 1310:     int i, j;
 1311:     for (j = 0; j < 2; j++) {
 1312:         for (i = 0; i < 8; i++) {
 1313:             color_table[j][i] = col_expand(ds,
 1314:                    vga_get_color(ds, color_table_rgb[j][i]));
 1315:         }
 1316:     }
 1317: }
 1318: 
 1319: static int n_text_consoles;
 1320: static CharDriverState *text_consoles[128];
 1321: static char *text_console_strs[128];
 1322: 
 1323: static void text_console_do_init(CharDriverState *chr, DisplayState *ds, const char *p)
 1324: {
 1325:     TextConsole *s;
 1326:     unsigned width;
 1327:     unsigned height;
 1328:     static int color_inited;
 1329: 
 1330:     s = new_console(ds, (p == 0) ? TEXT_CONSOLE : TEXT_CONSOLE_FIXED_SIZE);
 1331:     if (!s) {
 1332:         free(chr);
 1333:         return;
 1334:     }
 1335:     chr->opaque = s;
 1336:     chr->chr_write = console_puts;
 1337:     chr->chr_send_event = console_send_event;
 1338: 
 1339:     s->chr = chr;
 1340:     s->out_fifo.buf = s->out_fifo_buf;
 1341:     s->out_fifo.buf_size = sizeof(s->out_fifo_buf);
 1342:     s->kbd_timer = qemu_new_timer(rt_clock, kbd_send_chars, s);
 1343:     s->ds = ds;
 1344: 
 1345:     if (!color_inited) {
 1346:         color_inited = 1;
 1347:         console_color_init(s->ds);
 1348:     }
 1349:     s->y_displayed = 0;
 1350:     s->y_base = 0;
 1351:     s->total_height = DEFAULT_BACKSCROLL;
 1352:     s->x = 0;
 1353:     s->y = 0;
 1354:     width = ds_get_width(s->ds);
 1355:     height = ds_get_height(s->ds);
 1356:     if (p != 0) {
 1357:         width = strtoul(p, (char **)&p, 10);
 1358:         if (*p == 'C') {
 1359:             p++;
 1360:             width *= FONT_WIDTH;
 1361:         }
 1362:         if (*p == 'x') {
 1363:             p++;
 1364:             height = strtoul(p, (char **)&p, 10);
 1365:             if (*p == 'C') {
 1366:                 p++;
 1367:                 height *= FONT_HEIGHT;
 1368:             }
 1369:         }
 1370:     }
 1371:     s->g_width = width;
 1372:     s->g_height = height;
 1373: 
 1374:     s->hw_invalidate = text_console_invalidate;
 1375:     s->hw_text_update = text_console_update;
 1376:     s->hw = s;
 1377: 
 1378:     /* Set text attribute defaults */
 1379:     s->t_attrib_default.bold = 0;
 1380:     s->t_attrib_default.uline = 0;
 1381:     s->t_attrib_default.blink = 0;
 1382:     s->t_attrib_default.invers = 0;
 1383:     s->t_attrib_default.unvisible = 0;
 1384:     s->t_attrib_default.fgcol = COLOR_WHITE;
 1385:     s->t_attrib_default.bgcol = COLOR_BLACK;
 1386:     /* set current text attributes to default */
 1387:     s->t_attrib = s->t_attrib_default;
 1388:     text_console_resize(s);
 1389: 
 1390:     qemu_chr_reset(chr);
 1391:     if (chr->init)
 1392:         chr->init(chr);
 1393: }
 1394: 
 1395: CharDriverState *text_console_init(const char *p)
 1396: {
 1397:     CharDriverState *chr;
 1398: 
 1399:     chr = qemu_mallocz(sizeof(CharDriverState));
 1400: 
 1401:     if (n_text_consoles == 128) {
 1402:         fprintf(stderr, "Too many text consoles\n");
 1403:         exit(1);
 1404:     }
 1405:     text_consoles[n_text_consoles] = chr;
 1406:     text_console_strs[n_text_consoles] = p ? qemu_strdup(p) : NULL;
 1407:     n_text_consoles++;
 1408: 
 1409:     return chr;
 1410: }
 1411: 
 1412: void text_consoles_set_display(DisplayState *ds)
 1413: {
 1414:     int i;
 1415: 
 1416:     for (i = 0; i < n_text_consoles; i++) {
 1417:         text_console_do_init(text_consoles[i], ds, text_console_strs[i]);
 1418:         qemu_free(text_console_strs[i]);
 1419:     }
 1420: 
 1421:     n_text_consoles = 0;
 1422: }
 1423: 
 1424: void qemu_console_resize(DisplayState *ds, int width, int height)
 1425: {
 1426:     TextConsole *s = get_graphic_console(ds);
 1427:     if (!s) return;
 1428: 
 1429:     s->g_width = width;
 1430:     s->g_height = height;
 1431:     if (is_graphic_console()) {
 1432:         ds->surface = qemu_resize_displaysurface(ds->surface, width, height, 32, 4 * width);
 1433:         dpy_resize(ds);
 1434:     }
 1435: }
 1436: 
 1437: void qemu_console_copy(DisplayState *ds, int src_x, int src_y,
 1438:                        int dst_x, int dst_y, int w, int h)
 1439: {
 1440:     if (is_graphic_console()) {
 1441:         dpy_copy(ds, src_x, src_y, dst_x, dst_y, w, h);
 1442:     }
 1443: }
 1444: 
 1445: PixelFormat qemu_different_endianness_pixelformat(int bpp)
 1446: {
 1447:     PixelFormat pf;
 1448: 
 1449:     memset(&pf, 0x00, sizeof(PixelFormat));
 1450: 
 1451:     pf.bits_per_pixel = bpp;
 1452:     pf.bytes_per_pixel = bpp / 8;
 1453:     pf.depth = bpp == 32 ? 24 : bpp;
 1454: 
 1455:     switch (bpp) {
 1456:         case 24:
 1457:             pf.rmask = 0x000000FF;
 1458:             pf.gmask = 0x0000FF00;
 1459:             pf.bmask = 0x00FF0000;
 1460:             pf.rmax = 255;
 1461:             pf.gmax = 255;
 1462:             pf.bmax = 255;
 1463:             pf.rshift = 0;
 1464:             pf.gshift = 8;
 1465:             pf.bshift = 16;
 1466:             pf.rbits = 8;
 1467:             pf.gbits = 8;
 1468:             pf.bbits = 8;
 1469:             break;
 1470:         case 32:
 1471:             pf.rmask = 0x0000FF00;
 1472:             pf.gmask = 0x00FF0000;
 1473:             pf.bmask = 0xFF000000;
 1474:             pf.amask = 0x00000000;
 1475:             pf.amax = 255;
 1476:             pf.rmax = 255;
 1477:             pf.gmax = 255;
 1478:             pf.bmax = 255;
 1479:             pf.ashift = 0;
 1480:             pf.rshift = 8;
 1481:             pf.gshift = 16;
 1482:             pf.bshift = 24;
 1483:             pf.rbits = 8;
 1484:             pf.gbits = 8;
 1485:             pf.bbits = 8;
 1486:             pf.abits = 8;
 1487:             break;
 1488:         default:
 1489:             break;
 1490:     }
 1491:     return pf;
 1492: }
 1493: 
 1494: PixelFormat qemu_default_pixelformat(int bpp)
 1495: {
 1496:     PixelFormat pf;
 1497: 
 1498:     memset(&pf, 0x00, sizeof(PixelFormat));
 1499: 
 1500:     pf.bits_per_pixel = bpp;
 1501:     pf.bytes_per_pixel = bpp / 8;
 1502:     pf.depth = bpp == 32 ? 24 : bpp;
 1503: 
 1504:     switch (bpp) {
 1505:         case 16:
 1506:             pf.rmask = 0x0000F800;
 1507:             pf.gmask = 0x000007E0;
 1508:             pf.bmask = 0x0000001F;
 1509:             pf.rmax = 31;
 1510:             pf.gmax = 63;
 1511:             pf.bmax = 31;
 1512:             pf.rshift = 11;
 1513:             pf.gshift = 5;
 1514:             pf.bshift = 0;
 1515:             pf.rbits = 5;
 1516:             pf.gbits = 6;
 1517:             pf.bbits = 5;
 1518:             break;
 1519:         case 24:
 1520:             pf.rmask = 0x00FF0000;
 1521:             pf.gmask = 0x0000FF00;
 1522:             pf.bmask = 0x000000FF;
 1523:             pf.rmax = 255;
 1524:             pf.gmax = 255;
 1525:             pf.bmax = 255;
 1526:             pf.rshift = 16;
 1527:             pf.gshift = 8;
 1528:             pf.bshift = 0;
 1529:             pf.rbits = 8;
 1530:             pf.gbits = 8;
 1531:             pf.bbits = 8;
 1532:         case 32:
 1533:             pf.rmask = 0x00FF0000;
 1534:             pf.gmask = 0x0000FF00;
 1535:             pf.bmask = 0x000000FF;
 1536:             pf.amax = 255;
 1537:             pf.rmax = 255;
 1538:             pf.gmax = 255;
 1539:             pf.bmax = 255;
 1540:             pf.ashift = 24;
 1541:             pf.rshift = 16;
 1542:             pf.gshift = 8;
 1543:             pf.bshift = 0;
 1544:             pf.rbits = 8;
 1545:             pf.gbits = 8;
 1546:             pf.bbits = 8;
 1547:             pf.abits = 8;
 1548:             break;
 1549:         default:
 1550:             break;
 1551:     }
 1552:     return pf;
 1553: }
 1554: 
 1555: DisplaySurface* qemu_create_displaysurface(int width, int height, int bpp, int linesize)
 1556: {
 1557:     DisplaySurface *surface = (DisplaySurface*) qemu_mallocz(sizeof(DisplaySurface));
 1558: 
 1559:     surface->width = width;
 1560:     surface->height = height;
 1561:     surface->linesize = linesize;
 1562:     surface->pf = qemu_default_pixelformat(bpp);
 1563: #ifdef WORDS_BIGENDIAN
 1564:     surface->flags = QEMU_ALLOCATED_FLAG | QEMU_BIG_ENDIAN_FLAG;
 1565: #else
 1566:     surface->flags = QEMU_ALLOCATED_FLAG;
 1567: #endif
 1568:     surface->data = (uint8_t*) qemu_mallocz(surface->linesize * surface->height);
 1569: 
 1570:     return surface;
 1571: }
 1572: 
 1573: DisplaySurface* qemu_resize_displaysurface(DisplaySurface *surface,
 1574:                                           int width, int height, int bpp, int linesize)
 1575: {
 1576:     surface->width = width;
 1577:     surface->height = height;
 1578:     surface->linesize = linesize;
 1579:     surface->pf = qemu_default_pixelformat(bpp);
 1580:     if (surface->flags & QEMU_ALLOCATED_FLAG)
 1581:         surface->data = (uint8_t*) qemu_realloc(surface->data, surface->linesize * surface->height);
 1582:     else
 1583:         surface->data = (uint8_t*) qemu_malloc(surface->linesize * surface->height);
 1584: #ifdef WORDS_BIGENDIAN
 1585:     surface->flags = QEMU_ALLOCATED_FLAG | QEMU_BIG_ENDIAN_FLAG;
 1586: #else
 1587:     surface->flags = QEMU_ALLOCATED_FLAG;
 1588: #endif
 1589: 
 1590:     return surface;
 1591: }
 1592: 
 1593: DisplaySurface* qemu_create_displaysurface_from(int width, int height, int bpp,
 1594:                                               int linesize, uint8_t *data)
 1595: {
 1596:     DisplaySurface *surface = (DisplaySurface*) qemu_mallocz(sizeof(DisplaySurface));
 1597: 
 1598:     surface->width = width;
 1599:     surface->height = height;
 1600:     surface->linesize = linesize;
 1601:     surface->pf = qemu_default_pixelformat(bpp);
 1602: #ifdef WORDS_BIGENDIAN
 1603:     surface->flags = QEMU_BIG_ENDIAN_FLAG;
 1604: #endif
 1605:     surface->data = data;
 1606: 
 1607:     return surface;
 1608: }
 1609: 
 1610: void qemu_free_displaysurface(DisplaySurface *surface)
 1611: {
 1612:     if (surface == NULL)
 1613:         return;
 1614:     if (surface->flags & QEMU_ALLOCATED_FLAG)
 1615:         qemu_free(surface->data);
 1616:     qemu_free(surface);
 1617: }

unix.superglobalmegacorp.com