Annotation of qemu/console.c, revision 1.1.1.3

1.1       root        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: 
1.1.1.2   root       26: //#define DEBUG_CONSOLE
1.1       root       27: #define DEFAULT_BACKSCROLL 512
                     28: #define MAX_CONSOLES 12
                     29: 
1.1.1.3 ! root       30: #define QEMU_RGBA(r, g, b, a) (((a) << 24) | ((r) << 16) | ((g) << 8) | (b))
        !            31: #define QEMU_RGB(r, g, b) QEMU_RGBA(r, g, b, 0xff)
1.1       root       32: 
1.1.1.2   root       33: typedef struct TextAttributes {
                     34:     uint8_t fgcol:4;
                     35:     uint8_t bgcol:4;
                     36:     uint8_t bold:1;
                     37:     uint8_t uline:1;
                     38:     uint8_t blink:1;
                     39:     uint8_t invers:1;
                     40:     uint8_t unvisible:1;
                     41: } TextAttributes;
                     42: 
1.1       root       43: typedef struct TextCell {
                     44:     uint8_t ch;
1.1.1.2   root       45:     TextAttributes t_attrib;
1.1       root       46: } TextCell;
                     47: 
                     48: #define MAX_ESC_PARAMS 3
                     49: 
                     50: enum TTYState {
                     51:     TTY_STATE_NORM,
                     52:     TTY_STATE_ESC,
                     53:     TTY_STATE_CSI,
                     54: };
                     55: 
1.1.1.3 ! root       56: typedef struct QEMUFIFO {
        !            57:     uint8_t *buf;
        !            58:     int buf_size;
        !            59:     int count, wptr, rptr;
        !            60: } QEMUFIFO;
        !            61: 
        !            62: int qemu_fifo_write(QEMUFIFO *f, const uint8_t *buf, int len1)
        !            63: {
        !            64:     int l, len;
        !            65: 
        !            66:     l = f->buf_size - f->count;
        !            67:     if (len1 > l)
        !            68:         len1 = l;
        !            69:     len = len1;
        !            70:     while (len > 0) {
        !            71:         l = f->buf_size - f->wptr;
        !            72:         if (l > len)
        !            73:             l = len;
        !            74:         memcpy(f->buf + f->wptr, buf, l);
        !            75:         f->wptr += l;
        !            76:         if (f->wptr >= f->buf_size)
        !            77:             f->wptr = 0;
        !            78:         buf += l;
        !            79:         len -= l;
        !            80:     }
        !            81:     f->count += len1;
        !            82:     return len1;
        !            83: }
        !            84: 
        !            85: int qemu_fifo_read(QEMUFIFO *f, uint8_t *buf, int len1)
        !            86: {
        !            87:     int l, len;
        !            88: 
        !            89:     if (len1 > f->count)
        !            90:         len1 = f->count;
        !            91:     len = len1;
        !            92:     while (len > 0) {
        !            93:         l = f->buf_size - f->rptr;
        !            94:         if (l > len)
        !            95:             l = len;
        !            96:         memcpy(buf, f->buf + f->rptr, l);
        !            97:         f->rptr += l;
        !            98:         if (f->rptr >= f->buf_size)
        !            99:             f->rptr = 0;
        !           100:         buf += l;
        !           101:         len -= l;
        !           102:     }
        !           103:     f->count -= len1;
        !           104:     return len1;
        !           105: }
        !           106: 
1.1.1.2   root      107: /* ??? This is mis-named.
                    108:    It is used for both text and graphical consoles.  */
1.1       root      109: struct TextConsole {
                    110:     int text_console; /* true if text console */
                    111:     DisplayState *ds;
1.1.1.2   root      112:     /* Graphic console state.  */
                    113:     vga_hw_update_ptr hw_update;
                    114:     vga_hw_invalidate_ptr hw_invalidate;
                    115:     vga_hw_screen_dump_ptr hw_screen_dump;
                    116:     void *hw;
                    117: 
1.1       root      118:     int g_width, g_height;
                    119:     int width;
                    120:     int height;
                    121:     int total_height;
                    122:     int backscroll_height;
                    123:     int x, y;
                    124:     int y_displayed;
                    125:     int y_base;
1.1.1.2   root      126:     TextAttributes t_attrib_default; /* default text attributes */
                    127:     TextAttributes t_attrib; /* currently active text attributes */
1.1       root      128:     TextCell *cells;
                    129: 
                    130:     enum TTYState state;
                    131:     int esc_params[MAX_ESC_PARAMS];
                    132:     int nb_esc_params;
                    133: 
                    134:     /* kbd read handler */
1.1.1.3 ! root      135:     IOCanRWHandler *fd_can_read; 
1.1       root      136:     IOReadHandler *fd_read;
                    137:     void *fd_opaque;
1.1.1.3 ! root      138:     /* fifo for key pressed */
        !           139:     QEMUFIFO out_fifo;
        !           140:     uint8_t out_fifo_buf[16];
        !           141:     QEMUTimer *kbd_timer;
1.1       root      142: };
                    143: 
                    144: static TextConsole *active_console;
                    145: static TextConsole *consoles[MAX_CONSOLES];
                    146: static int nb_consoles = 0;
                    147: 
1.1.1.2   root      148: void vga_hw_update(void)
                    149: {
                    150:     if (active_console->hw_update)
                    151:         active_console->hw_update(active_console->hw);
                    152: }
                    153: 
                    154: void vga_hw_invalidate(void)
                    155: {
                    156:     if (active_console->hw_invalidate)
                    157:         active_console->hw_invalidate(active_console->hw);
                    158: }
                    159: 
                    160: void vga_hw_screen_dump(const char *filename)
                    161: {
                    162:     /* There is currently no was of specifying which screen we want to dump,
                    163:        so always dump the dirst one.  */
                    164:     if (consoles[0]->hw_screen_dump)
                    165:         consoles[0]->hw_screen_dump(consoles[0]->hw, filename);
                    166: }
                    167: 
1.1       root      168: /* convert a RGBA color to a color index usable in graphic primitives */
                    169: static unsigned int vga_get_color(DisplayState *ds, unsigned int rgba)
                    170: {
                    171:     unsigned int r, g, b, color;
                    172: 
                    173:     switch(ds->depth) {
                    174: #if 0
                    175:     case 8:
                    176:         r = (rgba >> 16) & 0xff;
                    177:         g = (rgba >> 8) & 0xff;
                    178:         b = (rgba) & 0xff;
                    179:         color = (rgb_to_index[r] * 6 * 6) + 
                    180:             (rgb_to_index[g] * 6) + 
                    181:             (rgb_to_index[b]);
                    182:         break;
                    183: #endif
                    184:     case 15:
                    185:         r = (rgba >> 16) & 0xff;
                    186:         g = (rgba >> 8) & 0xff;
                    187:         b = (rgba) & 0xff;
                    188:         color = ((r >> 3) << 10) | ((g >> 3) << 5) | (b >> 3);
                    189:         break;
                    190:     case 16:
                    191:         r = (rgba >> 16) & 0xff;
                    192:         g = (rgba >> 8) & 0xff;
                    193:         b = (rgba) & 0xff;
                    194:         color = ((r >> 3) << 11) | ((g >> 2) << 5) | (b >> 3);
                    195:         break;
                    196:     case 32:
                    197:     default:
                    198:         color = rgba;
                    199:         break;
                    200:     }
                    201:     return color;
                    202: }
                    203: 
                    204: static void vga_fill_rect (DisplayState *ds, 
                    205:                            int posx, int posy, int width, int height, uint32_t color)
                    206: {
                    207:     uint8_t *d, *d1;
                    208:     int x, y, bpp;
                    209:     
                    210:     bpp = (ds->depth + 7) >> 3;
                    211:     d1 = ds->data + 
                    212:         ds->linesize * posy + bpp * posx;
                    213:     for (y = 0; y < height; y++) {
                    214:         d = d1;
                    215:         switch(bpp) {
                    216:         case 1:
                    217:             for (x = 0; x < width; x++) {
                    218:                 *((uint8_t *)d) = color;
                    219:                 d++;
                    220:             }
                    221:             break;
                    222:         case 2:
                    223:             for (x = 0; x < width; x++) {
                    224:                 *((uint16_t *)d) = color;
                    225:                 d += 2;
                    226:             }
                    227:             break;
                    228:         case 4:
                    229:             for (x = 0; x < width; x++) {
                    230:                 *((uint32_t *)d) = color;
                    231:                 d += 4;
                    232:             }
                    233:             break;
                    234:         }
                    235:         d1 += ds->linesize;
                    236:     }
                    237: }
                    238: 
                    239: /* copy from (xs, ys) to (xd, yd) a rectangle of size (w, h) */
                    240: static void vga_bitblt(DisplayState *ds, int xs, int ys, int xd, int yd, int w, int h)
                    241: {
                    242:     const uint8_t *s;
                    243:     uint8_t *d;
                    244:     int wb, y, bpp;
                    245: 
                    246:     bpp = (ds->depth + 7) >> 3;
                    247:     wb = w * bpp;
                    248:     if (yd <= ys) {
                    249:         s = ds->data + 
                    250:             ds->linesize * ys + bpp * xs;
                    251:         d = ds->data + 
                    252:             ds->linesize * yd + bpp * xd;
                    253:         for (y = 0; y < h; y++) {
                    254:             memmove(d, s, wb);
                    255:             d += ds->linesize;
                    256:             s += ds->linesize;
                    257:         }
                    258:     } else {
                    259:         s = ds->data + 
                    260:             ds->linesize * (ys + h - 1) + bpp * xs;
                    261:         d = ds->data + 
                    262:             ds->linesize * (yd + h - 1) + bpp * xd;
                    263:        for (y = 0; y < h; y++) {
                    264:             memmove(d, s, wb);
                    265:             d -= ds->linesize;
                    266:             s -= ds->linesize;
                    267:         }
                    268:     }
                    269: }
                    270: 
                    271: /***********************************************************/
                    272: /* basic char display */
                    273: 
                    274: #define FONT_HEIGHT 16
                    275: #define FONT_WIDTH 8
                    276: 
                    277: #include "vgafont.h"
                    278: 
                    279: #define cbswap_32(__x) \
                    280: ((uint32_t)( \
                    281:                (((uint32_t)(__x) & (uint32_t)0x000000ffUL) << 24) | \
                    282:                (((uint32_t)(__x) & (uint32_t)0x0000ff00UL) <<  8) | \
                    283:                (((uint32_t)(__x) & (uint32_t)0x00ff0000UL) >>  8) | \
                    284:                (((uint32_t)(__x) & (uint32_t)0xff000000UL) >> 24) ))
                    285: 
                    286: #ifdef WORDS_BIGENDIAN
                    287: #define PAT(x) x
                    288: #else
                    289: #define PAT(x) cbswap_32(x)
                    290: #endif
                    291: 
                    292: static const uint32_t dmask16[16] = {
                    293:     PAT(0x00000000),
                    294:     PAT(0x000000ff),
                    295:     PAT(0x0000ff00),
                    296:     PAT(0x0000ffff),
                    297:     PAT(0x00ff0000),
                    298:     PAT(0x00ff00ff),
                    299:     PAT(0x00ffff00),
                    300:     PAT(0x00ffffff),
                    301:     PAT(0xff000000),
                    302:     PAT(0xff0000ff),
                    303:     PAT(0xff00ff00),
                    304:     PAT(0xff00ffff),
                    305:     PAT(0xffff0000),
                    306:     PAT(0xffff00ff),
                    307:     PAT(0xffffff00),
                    308:     PAT(0xffffffff),
                    309: };
                    310: 
                    311: static const uint32_t dmask4[4] = {
                    312:     PAT(0x00000000),
                    313:     PAT(0x0000ffff),
                    314:     PAT(0xffff0000),
                    315:     PAT(0xffffffff),
                    316: };
                    317: 
1.1.1.2   root      318: static uint32_t color_table[2][8];
                    319: 
                    320: enum color_names {
                    321:     COLOR_BLACK   = 0,
                    322:     COLOR_RED     = 1,
                    323:     COLOR_GREEN   = 2,
                    324:     COLOR_YELLOW  = 3,
                    325:     COLOR_BLUE    = 4,
                    326:     COLOR_MAGENTA = 5,
                    327:     COLOR_CYAN    = 6,
                    328:     COLOR_WHITE   = 7
                    329: };
1.1       root      330: 
1.1.1.2   root      331: static const uint32_t color_table_rgb[2][8] = {
                    332:     {   /* dark */
1.1.1.3 ! root      333:         QEMU_RGB(0x00, 0x00, 0x00),  /* black */
        !           334:         QEMU_RGB(0xaa, 0x00, 0x00),  /* red */
        !           335:         QEMU_RGB(0x00, 0xaa, 0x00),  /* green */
        !           336:         QEMU_RGB(0xaa, 0xaa, 0x00),  /* yellow */
        !           337:         QEMU_RGB(0x00, 0x00, 0xaa),  /* blue */
        !           338:         QEMU_RGB(0xaa, 0x00, 0xaa),  /* magenta */
        !           339:         QEMU_RGB(0x00, 0xaa, 0xaa),  /* cyan */
        !           340:         QEMU_RGB(0xaa, 0xaa, 0xaa),  /* white */
1.1.1.2   root      341:     },
                    342:     {   /* bright */
1.1.1.3 ! root      343:         QEMU_RGB(0x00, 0x00, 0x00),  /* black */
        !           344:         QEMU_RGB(0xff, 0x00, 0x00),  /* red */
        !           345:         QEMU_RGB(0x00, 0xff, 0x00),  /* green */
        !           346:         QEMU_RGB(0xff, 0xff, 0x00),  /* yellow */
        !           347:         QEMU_RGB(0x00, 0x00, 0xff),  /* blue */
        !           348:         QEMU_RGB(0xff, 0x00, 0xff),  /* magenta */
        !           349:         QEMU_RGB(0x00, 0xff, 0xff),  /* cyan */
        !           350:         QEMU_RGB(0xff, 0xff, 0xff),  /* white */
1.1.1.2   root      351:     }
1.1       root      352: };
                    353: 
                    354: static inline unsigned int col_expand(DisplayState *ds, unsigned int col)
                    355: {
                    356:     switch(ds->depth) {
                    357:     case 8:
                    358:         col |= col << 8;
                    359:         col |= col << 16;
                    360:         break;
                    361:     case 15:
                    362:     case 16:
                    363:         col |= col << 16;
                    364:         break;
                    365:     default:
                    366:         break;
                    367:     }
                    368: 
                    369:     return col;
                    370: }
1.1.1.2   root      371: #ifdef DEBUG_CONSOLE
                    372: static void console_print_text_attributes(TextAttributes *t_attrib, char ch)
                    373: {
                    374:     if (t_attrib->bold) {
                    375:         printf("b");
                    376:     } else {
                    377:         printf(" ");
                    378:     }
                    379:     if (t_attrib->uline) {
                    380:         printf("u");
                    381:     } else {
                    382:         printf(" ");
                    383:     }
                    384:     if (t_attrib->blink) {
                    385:         printf("l");
                    386:     } else {
                    387:         printf(" ");
                    388:     }
                    389:     if (t_attrib->invers) {
                    390:         printf("i");
                    391:     } else {
                    392:         printf(" ");
                    393:     }
                    394:     if (t_attrib->unvisible) {
                    395:         printf("n");
                    396:     } else {
                    397:         printf(" ");
                    398:     }
                    399: 
                    400:     printf(" fg: %d bg: %d ch:'%2X' '%c'\n", t_attrib->fgcol, t_attrib->bgcol, ch, ch);
                    401: }
                    402: #endif
1.1       root      403: 
                    404: static void vga_putcharxy(DisplayState *ds, int x, int y, int ch, 
1.1.1.2   root      405:                           TextAttributes *t_attrib)
1.1       root      406: {
                    407:     uint8_t *d;
                    408:     const uint8_t *font_ptr;
                    409:     unsigned int font_data, linesize, xorcol, bpp;
                    410:     int i;
1.1.1.2   root      411:     unsigned int fgcol, bgcol;
                    412: 
                    413: #ifdef DEBUG_CONSOLE
                    414:     printf("x: %2i y: %2i", x, y);
                    415:     console_print_text_attributes(t_attrib, ch);
                    416: #endif
                    417: 
                    418:     if (t_attrib->invers) {
                    419:         bgcol = color_table[t_attrib->bold][t_attrib->fgcol];
                    420:         fgcol = color_table[t_attrib->bold][t_attrib->bgcol];
                    421:     } else {
                    422:         fgcol = color_table[t_attrib->bold][t_attrib->fgcol];
                    423:         bgcol = color_table[t_attrib->bold][t_attrib->bgcol];
                    424:     }
1.1       root      425: 
                    426:     bpp = (ds->depth + 7) >> 3;
                    427:     d = ds->data + 
                    428:         ds->linesize * y * FONT_HEIGHT + bpp * x * FONT_WIDTH;
                    429:     linesize = ds->linesize;
                    430:     font_ptr = vgafont16 + FONT_HEIGHT * ch;
                    431:     xorcol = bgcol ^ fgcol;
                    432:     switch(ds->depth) {
                    433:     case 8:
                    434:         for(i = 0; i < FONT_HEIGHT; i++) {
                    435:             font_data = *font_ptr++;
1.1.1.2   root      436:             if (t_attrib->uline
                    437:                 && ((i == FONT_HEIGHT - 2) || (i == FONT_HEIGHT - 3))) {
                    438:                 font_data = 0xFFFF;
                    439:             }
1.1       root      440:             ((uint32_t *)d)[0] = (dmask16[(font_data >> 4)] & xorcol) ^ bgcol;
                    441:             ((uint32_t *)d)[1] = (dmask16[(font_data >> 0) & 0xf] & xorcol) ^ bgcol;
                    442:             d += linesize;
                    443:         }
                    444:         break;
                    445:     case 16:
                    446:     case 15:
                    447:         for(i = 0; i < FONT_HEIGHT; i++) {
                    448:             font_data = *font_ptr++;
1.1.1.2   root      449:             if (t_attrib->uline
                    450:                 && ((i == FONT_HEIGHT - 2) || (i == FONT_HEIGHT - 3))) {
                    451:                 font_data = 0xFFFF;
                    452:             }
1.1       root      453:             ((uint32_t *)d)[0] = (dmask4[(font_data >> 6)] & xorcol) ^ bgcol;
                    454:             ((uint32_t *)d)[1] = (dmask4[(font_data >> 4) & 3] & xorcol) ^ bgcol;
                    455:             ((uint32_t *)d)[2] = (dmask4[(font_data >> 2) & 3] & xorcol) ^ bgcol;
                    456:             ((uint32_t *)d)[3] = (dmask4[(font_data >> 0) & 3] & xorcol) ^ bgcol;
                    457:             d += linesize;
                    458:         }
                    459:         break;
                    460:     case 32:
                    461:         for(i = 0; i < FONT_HEIGHT; i++) {
                    462:             font_data = *font_ptr++;
1.1.1.2   root      463:             if (t_attrib->uline && ((i == FONT_HEIGHT - 2) || (i == FONT_HEIGHT - 3))) {
                    464:                 font_data = 0xFFFF;
                    465:             }
1.1       root      466:             ((uint32_t *)d)[0] = (-((font_data >> 7)) & xorcol) ^ bgcol;
                    467:             ((uint32_t *)d)[1] = (-((font_data >> 6) & 1) & xorcol) ^ bgcol;
                    468:             ((uint32_t *)d)[2] = (-((font_data >> 5) & 1) & xorcol) ^ bgcol;
                    469:             ((uint32_t *)d)[3] = (-((font_data >> 4) & 1) & xorcol) ^ bgcol;
                    470:             ((uint32_t *)d)[4] = (-((font_data >> 3) & 1) & xorcol) ^ bgcol;
                    471:             ((uint32_t *)d)[5] = (-((font_data >> 2) & 1) & xorcol) ^ bgcol;
                    472:             ((uint32_t *)d)[6] = (-((font_data >> 1) & 1) & xorcol) ^ bgcol;
                    473:             ((uint32_t *)d)[7] = (-((font_data >> 0) & 1) & xorcol) ^ bgcol;
                    474:             d += linesize;
                    475:         }
                    476:         break;
                    477:     }
                    478: }
                    479: 
                    480: static void text_console_resize(TextConsole *s)
                    481: {
                    482:     TextCell *cells, *c, *c1;
                    483:     int w1, x, y, last_width;
                    484: 
                    485:     last_width = s->width;
                    486:     s->width = s->g_width / FONT_WIDTH;
                    487:     s->height = s->g_height / FONT_HEIGHT;
                    488: 
                    489:     w1 = last_width;
                    490:     if (s->width < w1)
                    491:         w1 = s->width;
                    492: 
                    493:     cells = qemu_malloc(s->width * s->total_height * sizeof(TextCell));
                    494:     for(y = 0; y < s->total_height; y++) {
                    495:         c = &cells[y * s->width];
                    496:         if (w1 > 0) {
                    497:             c1 = &s->cells[y * last_width];
                    498:             for(x = 0; x < w1; x++) {
                    499:                 *c++ = *c1++;
                    500:             }
                    501:         }
                    502:         for(x = w1; x < s->width; x++) {
                    503:             c->ch = ' ';
1.1.1.2   root      504:             c->t_attrib = s->t_attrib_default;
1.1       root      505:             c++;
                    506:         }
                    507:     }
                    508:     free(s->cells);
                    509:     s->cells = cells;
                    510: }
                    511: 
                    512: static void update_xy(TextConsole *s, int x, int y)
                    513: {
                    514:     TextCell *c;
                    515:     int y1, y2;
                    516: 
                    517:     if (s == active_console) {
                    518:         y1 = (s->y_base + y) % s->total_height;
                    519:         y2 = y1 - s->y_displayed;
                    520:         if (y2 < 0)
                    521:             y2 += s->total_height;
                    522:         if (y2 < s->height) {
                    523:             c = &s->cells[y1 * s->width + x];
                    524:             vga_putcharxy(s->ds, x, y2, c->ch, 
1.1.1.2   root      525:                           &(c->t_attrib));
1.1       root      526:             dpy_update(s->ds, x * FONT_WIDTH, y2 * FONT_HEIGHT, 
                    527:                        FONT_WIDTH, FONT_HEIGHT);
                    528:         }
                    529:     }
                    530: }
                    531: 
                    532: static void console_show_cursor(TextConsole *s, int show)
                    533: {
                    534:     TextCell *c;
                    535:     int y, y1;
                    536: 
                    537:     if (s == active_console) {
                    538:         y1 = (s->y_base + s->y) % s->total_height;
                    539:         y = y1 - s->y_displayed;
                    540:         if (y < 0)
                    541:             y += s->total_height;
                    542:         if (y < s->height) {
                    543:             c = &s->cells[y1 * s->width + s->x];
                    544:             if (show) {
1.1.1.2   root      545:                 TextAttributes t_attrib = s->t_attrib_default;
                    546:                 t_attrib.invers = !(t_attrib.invers); /* invert fg and bg */
                    547:                 vga_putcharxy(s->ds, s->x, y, c->ch, &t_attrib);
1.1       root      548:             } else {
                    549:                 vga_putcharxy(s->ds, s->x, y, c->ch, 
1.1.1.2   root      550:                               &(c->t_attrib));
1.1       root      551:             }
                    552:             dpy_update(s->ds, s->x * FONT_WIDTH, y * FONT_HEIGHT, 
                    553:                        FONT_WIDTH, FONT_HEIGHT);
                    554:         }
                    555:     }
                    556: }
                    557: 
                    558: static void console_refresh(TextConsole *s)
                    559: {
                    560:     TextCell *c;
                    561:     int x, y, y1;
                    562: 
                    563:     if (s != active_console) 
                    564:         return;
                    565: 
                    566:     vga_fill_rect(s->ds, 0, 0, s->ds->width, s->ds->height,
1.1.1.2   root      567:                   color_table[0][COLOR_BLACK]);
1.1       root      568:     y1 = s->y_displayed;
                    569:     for(y = 0; y < s->height; y++) {
                    570:         c = s->cells + y1 * s->width;
                    571:         for(x = 0; x < s->width; x++) {
                    572:             vga_putcharxy(s->ds, x, y, c->ch, 
1.1.1.2   root      573:                           &(c->t_attrib));
1.1       root      574:             c++;
                    575:         }
                    576:         if (++y1 == s->total_height)
                    577:             y1 = 0;
                    578:     }
                    579:     dpy_update(s->ds, 0, 0, s->ds->width, s->ds->height);
                    580:     console_show_cursor(s, 1);
                    581: }
                    582: 
                    583: static void console_scroll(int ydelta)
                    584: {
                    585:     TextConsole *s;
                    586:     int i, y1;
                    587:     
                    588:     s = active_console;
                    589:     if (!s || !s->text_console)
                    590:         return;
                    591: 
                    592:     if (ydelta > 0) {
                    593:         for(i = 0; i < ydelta; i++) {
                    594:             if (s->y_displayed == s->y_base)
                    595:                 break;
                    596:             if (++s->y_displayed == s->total_height)
                    597:                 s->y_displayed = 0;
                    598:         }
                    599:     } else {
                    600:         ydelta = -ydelta;
                    601:         i = s->backscroll_height;
                    602:         if (i > s->total_height - s->height)
                    603:             i = s->total_height - s->height;
                    604:         y1 = s->y_base - i;
                    605:         if (y1 < 0)
                    606:             y1 += s->total_height;
                    607:         for(i = 0; i < ydelta; i++) {
                    608:             if (s->y_displayed == y1)
                    609:                 break;
                    610:             if (--s->y_displayed < 0)
                    611:                 s->y_displayed = s->total_height - 1;
                    612:         }
                    613:     }
                    614:     console_refresh(s);
                    615: }
                    616: 
                    617: static void console_put_lf(TextConsole *s)
                    618: {
                    619:     TextCell *c;
                    620:     int x, y1;
                    621: 
                    622:     s->y++;
                    623:     if (s->y >= s->height) {
                    624:         s->y = s->height - 1;
1.1.1.2   root      625: 
1.1       root      626:         if (s->y_displayed == s->y_base) {
                    627:             if (++s->y_displayed == s->total_height)
                    628:                 s->y_displayed = 0;
                    629:         }
                    630:         if (++s->y_base == s->total_height)
                    631:             s->y_base = 0;
                    632:         if (s->backscroll_height < s->total_height)
                    633:             s->backscroll_height++;
                    634:         y1 = (s->y_base + s->height - 1) % s->total_height;
                    635:         c = &s->cells[y1 * s->width];
                    636:         for(x = 0; x < s->width; x++) {
                    637:             c->ch = ' ';
1.1.1.2   root      638:             c->t_attrib = s->t_attrib_default;
1.1       root      639:             c++;
                    640:         }
                    641:         if (s == active_console && s->y_displayed == s->y_base) {
                    642:             vga_bitblt(s->ds, 0, FONT_HEIGHT, 0, 0, 
                    643:                        s->width * FONT_WIDTH, 
                    644:                        (s->height - 1) * FONT_HEIGHT);
                    645:             vga_fill_rect(s->ds, 0, (s->height - 1) * FONT_HEIGHT,
                    646:                           s->width * FONT_WIDTH, FONT_HEIGHT, 
1.1.1.2   root      647:                           color_table[0][s->t_attrib_default.bgcol]);
1.1       root      648:             dpy_update(s->ds, 0, 0, 
                    649:                        s->width * FONT_WIDTH, s->height * FONT_HEIGHT);
                    650:         }
                    651:     }
                    652: }
                    653: 
1.1.1.2   root      654: /* Set console attributes depending on the current escape codes.
                    655:  * NOTE: I know this code is not very efficient (checking every color for it
                    656:  * self) but it is more readable and better maintainable.
                    657:  */
                    658: static void console_handle_escape(TextConsole *s)
                    659: {
                    660:     int i;
                    661: 
                    662:     if (s->nb_esc_params == 0) { /* ESC[m sets all attributes to default */
                    663:         s->t_attrib = s->t_attrib_default;
                    664:         return;
                    665:     }
                    666:     for (i=0; i<s->nb_esc_params; i++) {
                    667:         switch (s->esc_params[i]) {
                    668:             case 0: /* reset all console attributes to default */
                    669:                 s->t_attrib = s->t_attrib_default;
                    670:                 break;
                    671:             case 1:
                    672:                 s->t_attrib.bold = 1;
                    673:                 break;
                    674:             case 4:
                    675:                 s->t_attrib.uline = 1;
                    676:                 break;
                    677:             case 5:
                    678:                 s->t_attrib.blink = 1;
                    679:                 break;
                    680:             case 7:
                    681:                 s->t_attrib.invers = 1;
                    682:                 break;
                    683:             case 8:
                    684:                 s->t_attrib.unvisible = 1;
                    685:                 break;
                    686:             case 22:
                    687:                 s->t_attrib.bold = 0;
                    688:                 break;
                    689:             case 24:
                    690:                 s->t_attrib.uline = 0;
                    691:                 break;
                    692:             case 25:
                    693:                 s->t_attrib.blink = 0;
                    694:                 break;
                    695:             case 27:
                    696:                 s->t_attrib.invers = 0;
                    697:                 break;
                    698:             case 28:
                    699:                 s->t_attrib.unvisible = 0;
                    700:                 break;
                    701:             /* set foreground color */
                    702:             case 30:
                    703:                 s->t_attrib.fgcol=COLOR_BLACK;
                    704:                 break;
                    705:             case 31:
                    706:                 s->t_attrib.fgcol=COLOR_RED;
                    707:                 break;
                    708:             case 32:
                    709:                 s->t_attrib.fgcol=COLOR_GREEN;
                    710:                 break;
                    711:             case 33:
                    712:                 s->t_attrib.fgcol=COLOR_YELLOW;
                    713:                 break;
                    714:             case 34:
                    715:                 s->t_attrib.fgcol=COLOR_BLUE;
                    716:                 break;
                    717:             case 35:
                    718:                 s->t_attrib.fgcol=COLOR_MAGENTA;
                    719:                 break;
                    720:             case 36:
                    721:                 s->t_attrib.fgcol=COLOR_CYAN;
                    722:                 break;
                    723:             case 37:
                    724:                 s->t_attrib.fgcol=COLOR_WHITE;
                    725:                 break;
                    726:             /* set background color */
                    727:             case 40:
                    728:                 s->t_attrib.bgcol=COLOR_BLACK;
                    729:                 break;
                    730:             case 41:
                    731:                 s->t_attrib.bgcol=COLOR_RED;
                    732:                 break;
                    733:             case 42:
                    734:                 s->t_attrib.bgcol=COLOR_GREEN;
                    735:                 break;
                    736:             case 43:
                    737:                 s->t_attrib.bgcol=COLOR_YELLOW;
                    738:                 break;
                    739:             case 44:
                    740:                 s->t_attrib.bgcol=COLOR_BLUE;
                    741:                 break;
                    742:             case 45:
                    743:                 s->t_attrib.bgcol=COLOR_MAGENTA;
                    744:                 break;
                    745:             case 46:
                    746:                 s->t_attrib.bgcol=COLOR_CYAN;
                    747:                 break;
                    748:             case 47:
                    749:                 s->t_attrib.bgcol=COLOR_WHITE;
                    750:                 break;
                    751:         }
                    752:     }
                    753: }
                    754: 
1.1       root      755: static void console_putchar(TextConsole *s, int ch)
                    756: {
                    757:     TextCell *c;
                    758:     int y1, i, x;
                    759: 
                    760:     switch(s->state) {
                    761:     case TTY_STATE_NORM:
                    762:         switch(ch) {
1.1.1.2   root      763:         case '\r':  /* carriage return */
1.1       root      764:             s->x = 0;
                    765:             break;
1.1.1.2   root      766:         case '\n':  /* newline */
1.1       root      767:             console_put_lf(s);
                    768:             break;
1.1.1.2   root      769:         case '\b':  /* backspace */
1.1.1.3 ! root      770:             if (s->x > 0) 
        !           771:                 s->x--;
1.1.1.2   root      772:             break;
                    773:         case '\t':  /* tabspace */
                    774:             if (s->x + (8 - (s->x % 8)) > s->width) {
1.1.1.3 ! root      775:                 s->x = 0;
1.1.1.2   root      776:                 console_put_lf(s);
                    777:             } else {
                    778:                 s->x = s->x + (8 - (s->x % 8));
                    779:             }
                    780:             break;
                    781:         case '\a':  /* alert aka. bell */
                    782:             /* TODO: has to be implemented */
                    783:             break;
                    784:         case 27:    /* esc (introducing an escape sequence) */
1.1       root      785:             s->state = TTY_STATE_ESC;
                    786:             break;
                    787:         default:
                    788:             y1 = (s->y_base + s->y) % s->total_height;
                    789:             c = &s->cells[y1 * s->width + s->x];
                    790:             c->ch = ch;
1.1.1.2   root      791:             c->t_attrib = s->t_attrib;
1.1       root      792:             update_xy(s, s->x, s->y);
                    793:             s->x++;
1.1.1.3 ! root      794:             if (s->x >= s->width) {
        !           795:                 s->x = 0;
1.1       root      796:                 console_put_lf(s);
1.1.1.3 ! root      797:             }
1.1       root      798:             break;
                    799:         }
                    800:         break;
1.1.1.2   root      801:     case TTY_STATE_ESC: /* check if it is a terminal escape sequence */
1.1       root      802:         if (ch == '[') {
                    803:             for(i=0;i<MAX_ESC_PARAMS;i++)
                    804:                 s->esc_params[i] = 0;
                    805:             s->nb_esc_params = 0;
                    806:             s->state = TTY_STATE_CSI;
                    807:         } else {
                    808:             s->state = TTY_STATE_NORM;
                    809:         }
                    810:         break;
1.1.1.2   root      811:     case TTY_STATE_CSI: /* handle escape sequence parameters */
1.1       root      812:         if (ch >= '0' && ch <= '9') {
                    813:             if (s->nb_esc_params < MAX_ESC_PARAMS) {
                    814:                 s->esc_params[s->nb_esc_params] = 
                    815:                     s->esc_params[s->nb_esc_params] * 10 + ch - '0';
                    816:             }
                    817:         } else {
                    818:             s->nb_esc_params++;
                    819:             if (ch == ';')
                    820:                 break;
                    821:             s->state = TTY_STATE_NORM;
                    822:             switch(ch) {
                    823:             case 'D':
                    824:                 if (s->x > 0)
                    825:                     s->x--;
                    826:                 break;
                    827:             case 'C':
                    828:                 if (s->x < (s->width - 1))
                    829:                     s->x++;
                    830:                 break;
                    831:             case 'K':
                    832:                 /* clear to eol */
                    833:                 y1 = (s->y_base + s->y) % s->total_height;
                    834:                 for(x = s->x; x < s->width; x++) {
                    835:                     c = &s->cells[y1 * s->width + x];
                    836:                     c->ch = ' ';
1.1.1.2   root      837:                     c->t_attrib = s->t_attrib_default;
1.1       root      838:                     c++;
                    839:                     update_xy(s, x, s->y);
                    840:                 }
                    841:                 break;
                    842:             default:
                    843:                 break;
                    844:             }
1.1.1.2   root      845:             console_handle_escape(s);
1.1       root      846:             break;
                    847:         }
                    848:     }
                    849: }
                    850: 
                    851: void console_select(unsigned int index)
                    852: {
                    853:     TextConsole *s;
1.1.1.2   root      854: 
1.1       root      855:     if (index >= MAX_CONSOLES)
                    856:         return;
                    857:     s = consoles[index];
                    858:     if (s) {
                    859:         active_console = s;
                    860:         if (s->text_console) {
                    861:             if (s->g_width != s->ds->width ||
                    862:                 s->g_height != s->ds->height) {
1.1.1.2   root      863:                 s->g_width = s->ds->width;
                    864:                 s->g_height = s->ds->height;
1.1       root      865:                 text_console_resize(s);
1.1.1.2   root      866:             }
1.1       root      867:             console_refresh(s);
1.1.1.2   root      868:         } else {
                    869:             vga_hw_invalidate();
1.1       root      870:         }
                    871:     }
                    872: }
                    873: 
                    874: static int console_puts(CharDriverState *chr, const uint8_t *buf, int len)
                    875: {
                    876:     TextConsole *s = chr->opaque;
                    877:     int i;
                    878: 
                    879:     console_show_cursor(s, 0);
                    880:     for(i = 0; i < len; i++) {
                    881:         console_putchar(s, buf[i]);
                    882:     }
                    883:     console_show_cursor(s, 1);
                    884:     return len;
                    885: }
                    886: 
                    887: static void console_chr_add_read_handler(CharDriverState *chr, 
                    888:                                          IOCanRWHandler *fd_can_read, 
                    889:                                          IOReadHandler *fd_read, void *opaque)
                    890: {
                    891:     TextConsole *s = chr->opaque;
1.1.1.3 ! root      892:     s->fd_can_read = fd_can_read;
1.1       root      893:     s->fd_read = fd_read;
                    894:     s->fd_opaque = opaque;
                    895: }
                    896: 
                    897: static void console_send_event(CharDriverState *chr, int event)
                    898: {
                    899:     TextConsole *s = chr->opaque;
                    900:     int i;
                    901: 
                    902:     if (event == CHR_EVENT_FOCUS) {
                    903:         for(i = 0; i < nb_consoles; i++) {
                    904:             if (consoles[i] == s) {
                    905:                 console_select(i);
                    906:                 break;
                    907:             }
                    908:         }
                    909:     }
                    910: }
                    911: 
1.1.1.3 ! root      912: static void kbd_send_chars(void *opaque)
        !           913: {
        !           914:     TextConsole *s = opaque;
        !           915:     int len;
        !           916:     uint8_t buf[16];
        !           917:     
        !           918:     len = s->fd_can_read(s->fd_opaque);
        !           919:     if (len > s->out_fifo.count)
        !           920:         len = s->out_fifo.count;
        !           921:     if (len > 0) {
        !           922:         if (len > sizeof(buf))
        !           923:             len = sizeof(buf);
        !           924:         qemu_fifo_read(&s->out_fifo, buf, len);
        !           925:         s->fd_read(s->fd_opaque, buf, len);
        !           926:     }
        !           927:     /* characters are pending: we send them a bit later (XXX:
        !           928:        horrible, should change char device API) */
        !           929:     if (s->out_fifo.count > 0) {
        !           930:         qemu_mod_timer(s->kbd_timer, qemu_get_clock(rt_clock) + 1);
        !           931:     }
        !           932: }
        !           933: 
1.1       root      934: /* called when an ascii key is pressed */
                    935: void kbd_put_keysym(int keysym)
                    936: {
                    937:     TextConsole *s;
                    938:     uint8_t buf[16], *q;
                    939:     int c;
                    940: 
                    941:     s = active_console;
                    942:     if (!s || !s->text_console)
                    943:         return;
                    944: 
                    945:     switch(keysym) {
                    946:     case QEMU_KEY_CTRL_UP:
                    947:         console_scroll(-1);
                    948:         break;
                    949:     case QEMU_KEY_CTRL_DOWN:
                    950:         console_scroll(1);
                    951:         break;
                    952:     case QEMU_KEY_CTRL_PAGEUP:
                    953:         console_scroll(-10);
                    954:         break;
                    955:     case QEMU_KEY_CTRL_PAGEDOWN:
                    956:         console_scroll(10);
                    957:         break;
                    958:     default:
1.1.1.3 ! root      959:         /* convert the QEMU keysym to VT100 key string */
        !           960:         q = buf;
        !           961:         if (keysym >= 0xe100 && keysym <= 0xe11f) {
        !           962:             *q++ = '\033';
        !           963:             *q++ = '[';
        !           964:             c = keysym - 0xe100;
        !           965:             if (c >= 10)
        !           966:                 *q++ = '0' + (c / 10);
        !           967:             *q++ = '0' + (c % 10);
        !           968:             *q++ = '~';
        !           969:         } else if (keysym >= 0xe120 && keysym <= 0xe17f) {
        !           970:             *q++ = '\033';
        !           971:             *q++ = '[';
        !           972:             *q++ = keysym & 0xff;
        !           973:         } else {
1.1       root      974:                 *q++ = keysym;
1.1.1.3 ! root      975:         }
        !           976:         if (s->fd_read) {
        !           977:             qemu_fifo_write(&s->out_fifo, buf, q - buf);
        !           978:             kbd_send_chars(s);
1.1       root      979:         }
                    980:         break;
                    981:     }
                    982: }
                    983: 
1.1.1.2   root      984: static TextConsole *new_console(DisplayState *ds, int text)
1.1       root      985: {
                    986:     TextConsole *s;
1.1.1.2   root      987:     int i;
1.1       root      988: 
                    989:     if (nb_consoles >= MAX_CONSOLES)
                    990:         return NULL;
                    991:     s = qemu_mallocz(sizeof(TextConsole));
                    992:     if (!s) {
                    993:         return NULL;
                    994:     }
1.1.1.2   root      995:     if (!active_console || (active_console->text_console && !text))
1.1       root      996:         active_console = s;
                    997:     s->ds = ds;
1.1.1.2   root      998:     s->text_console = text;
                    999:     if (text) {
                   1000:         consoles[nb_consoles++] = s;
                   1001:     } else {
                   1002:         /* HACK: Put graphical consoles before text consoles.  */
                   1003:         for (i = nb_consoles; i > 0; i--) {
                   1004:             if (!consoles[i - 1]->text_console)
                   1005:                 break;
                   1006:             consoles[i] = consoles[i - 1];
                   1007:         }
                   1008:         consoles[i] = s;
                   1009:     }
                   1010:     return s;
                   1011: }
                   1012: 
                   1013: TextConsole *graphic_console_init(DisplayState *ds, vga_hw_update_ptr update,
                   1014:                                   vga_hw_invalidate_ptr invalidate,
                   1015:                                   vga_hw_screen_dump_ptr screen_dump,
                   1016:                                   void *opaque)
                   1017: {
                   1018:     TextConsole *s;
                   1019: 
                   1020:     s = new_console(ds, 0);
                   1021:     if (!s)
                   1022:       return NULL;
                   1023:     s->hw_update = update;
                   1024:     s->hw_invalidate = invalidate;
                   1025:     s->hw_screen_dump = screen_dump;
                   1026:     s->hw = opaque;
1.1       root     1027:     return s;
                   1028: }
                   1029: 
1.1.1.2   root     1030: int is_graphic_console(void)
1.1       root     1031: {
1.1.1.2   root     1032:     return !active_console->text_console;
1.1       root     1033: }
                   1034: 
                   1035: CharDriverState *text_console_init(DisplayState *ds)
                   1036: {
                   1037:     CharDriverState *chr;
                   1038:     TextConsole *s;
1.1.1.2   root     1039:     int i,j;
1.1       root     1040:     static int color_inited;
1.1.1.2   root     1041: 
1.1       root     1042:     chr = qemu_mallocz(sizeof(CharDriverState));
                   1043:     if (!chr)
                   1044:         return NULL;
1.1.1.2   root     1045:     s = new_console(ds, 1);
1.1       root     1046:     if (!s) {
                   1047:         free(chr);
                   1048:         return NULL;
                   1049:     }
                   1050:     chr->opaque = s;
                   1051:     chr->chr_write = console_puts;
                   1052:     chr->chr_add_read_handler = console_chr_add_read_handler;
                   1053:     chr->chr_send_event = console_send_event;
                   1054: 
1.1.1.3 ! root     1055:     s->out_fifo.buf = s->out_fifo_buf;
        !          1056:     s->out_fifo.buf_size = sizeof(s->out_fifo_buf);
        !          1057:     s->kbd_timer = qemu_new_timer(rt_clock, kbd_send_chars, s);
        !          1058:     
1.1       root     1059:     if (!color_inited) {
                   1060:         color_inited = 1;
1.1.1.2   root     1061:         for(j = 0; j < 2; j++) {
                   1062:             for(i = 0; i < 8; i++) {
                   1063:                 color_table[j][i] = col_expand(s->ds, 
                   1064:                         vga_get_color(s->ds, color_table_rgb[j][i]));
                   1065:             }
1.1       root     1066:         }
                   1067:     }
                   1068:     s->y_displayed = 0;
                   1069:     s->y_base = 0;
                   1070:     s->total_height = DEFAULT_BACKSCROLL;
                   1071:     s->x = 0;
                   1072:     s->y = 0;
                   1073:     s->g_width = s->ds->width;
                   1074:     s->g_height = s->ds->height;
1.1.1.2   root     1075: 
                   1076:     /* Set text attribute defaults */
                   1077:     s->t_attrib_default.bold = 0;
                   1078:     s->t_attrib_default.uline = 0;
                   1079:     s->t_attrib_default.blink = 0;
                   1080:     s->t_attrib_default.invers = 0;
                   1081:     s->t_attrib_default.unvisible = 0;
                   1082:     s->t_attrib_default.fgcol = COLOR_WHITE;
                   1083:     s->t_attrib_default.bgcol = COLOR_BLACK;
                   1084: 
                   1085:     /* set current text attributes to default */
                   1086:     s->t_attrib = s->t_attrib_default;
1.1       root     1087:     text_console_resize(s);
                   1088: 
                   1089:     return chr;
                   1090: }

unix.superglobalmegacorp.com