(linenum→info "unix/slp.c:2238")

qemu/0.9.1/console.c

    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: 
   32: #define QEMU_RGBA(r, g, b, a) (((a) << 24) | ((r) << 16) | ((g) << 8) | (b))
   33: #define QEMU_RGB(r, g, b) QEMU_RGBA(r, g, b, 0xff)
   34: 
   35: typedef struct TextAttributes {
   36:     uint8_t fgcol:4;
   37:     uint8_t bgcol:4;
   38:     uint8_t bold:1;
   39:     uint8_t uline:1;
   40:     uint8_t blink:1;
   41:     uint8_t invers:1;
   42:     uint8_t unvisible:1;
   43: } TextAttributes;
   44: 
   45: typedef struct TextCell {
   46:     uint8_t ch;
   47:     TextAttributes t_attrib;
   48: } TextCell;
   49: 
   50: #define MAX_ESC_PARAMS 3
   51: 
   52: enum TTYState {
   53:     TTY_STATE_NORM,
   54:     TTY_STATE_ESC,
   55:     TTY_STATE_CSI,
   56: };
   57: 
   58: typedef struct QEMUFIFO {
   59:     uint8_t *buf;
   60:     int buf_size;
   61:     int count, wptr, rptr;
   62: } QEMUFIFO;
   63: 
   64: static int qemu_fifo_write(QEMUFIFO *f, const uint8_t *buf, int len1)
   65: {
   66:     int l, len;
   67: 
   68:     l = f->buf_size - f->count;
   69:     if (len1 > l)
   70:         len1 = l;
   71:     len = len1;
   72:     while (len > 0) {
   73:         l = f->buf_size - f->wptr;
   74:         if (l > len)
   75:             l = len;
   76:         memcpy(f->buf + f->wptr, buf, l);
   77:         f->wptr += l;
   78:         if (f->wptr >= f->buf_size)
   79:             f->wptr = 0;
   80:         buf += l;
   81:         len -= l;
   82:     }
   83:     f->count += len1;
   84:     return len1;
   85: }
   86: 
   87: static int qemu_fifo_read(QEMUFIFO *f, uint8_t *buf, int len1)
   88: {
   89:     int l, len;
   90: 
   91:     if (len1 > f->count)
   92:         len1 = f->count;
   93:     len = len1;
   94:     while (len > 0) {
   95:         l = f->buf_size - f->rptr;
   96:         if (l > len)
   97:             l = len;
   98:         memcpy(buf, f->buf + f->rptr, l);
   99:         f->rptr += l;
  100:         if (f->rptr >= f->buf_size)
  101:             f->rptr = 0;
  102:         buf += l;
  103:         len -= l;
  104:     }
  105:     f->count -= len1;
  106:     return len1;
  107: }
  108: 
  109: typedef enum {
  110:     GRAPHIC_CONSOLE,
  111:     TEXT_CONSOLE,
  112:     TEXT_CONSOLE_FIXED_SIZE
  113: } console_type_t;
  114: 
  115: /* ??? This is mis-named.
  116:    It is used for both text and graphical consoles.  */
  117: struct TextConsole {
  118:     console_type_t console_type;
  119:     DisplayState *ds;
  120:     /* Graphic console state.  */
  121:     vga_hw_update_ptr hw_update;
  122:     vga_hw_invalidate_ptr hw_invalidate;
  123:     vga_hw_screen_dump_ptr hw_screen_dump;
  124:     void *hw;
  125: 
  126:     int g_width, g_height;
  127:     int width;
  128:     int height;
  129:     int total_height;
  130:     int backscroll_height;
  131:     int x, y;
  132:     int x_saved, y_saved;
  133:     int y_displayed;
  134:     int y_base;
  135:     TextAttributes t_attrib_default; /* default text attributes */
  136:     TextAttributes t_attrib; /* currently active text attributes */
  137:     TextCell *cells;
  138: 
  139:     enum TTYState state;
  140:     int esc_params[MAX_ESC_PARAMS];
  141:     int nb_esc_params;
  142: 
  143:     CharDriverState *chr;
  144:     /* fifo for key pressed */
  145:     QEMUFIFO out_fifo;
  146:     uint8_t out_fifo_buf[16];
  147:     QEMUTimer *kbd_timer;
  148: };
  149: 
  150: static TextConsole *active_console;
  151: static TextConsole *consoles[MAX_CONSOLES];
  152: static int nb_consoles = 0;
  153: 
  154: void vga_hw_update(void)
  155: {
  156:     if (active_console && active_console->hw_update)
  157:         active_console->hw_update(active_console->hw);
  158: }
  159: 
  160: void vga_hw_invalidate(void)
  161: {
  162:     if (active_console->hw_invalidate)
  163:         active_console->hw_invalidate(active_console->hw);
  164: }
  165: 
  166: void vga_hw_screen_dump(const char *filename)
  167: {
  168:     /* There is currently no was of specifying which screen we want to dump,
  169:        so always dump the dirst one.  */
  170:     if (consoles[0]->hw_screen_dump)
  171:         consoles[0]->hw_screen_dump(consoles[0]->hw, filename);
  172: }
  173: 
  174: /* convert a RGBA color to a color index usable in graphic primitives */
  175: static unsigned int vga_get_color(DisplayState *ds, unsigned int rgba)
  176: {
  177:     unsigned int r, g, b, color;
  178: 
  179:     switch(ds->depth) {
  180: #if 0
  181:     case 8:
  182:         r = (rgba >> 16) & 0xff;
  183:         g = (rgba >> 8) & 0xff;
  184:         b = (rgba) & 0xff;
  185:         color = (rgb_to_index[r] * 6 * 6) +
  186:             (rgb_to_index[g] * 6) +
  187:             (rgb_to_index[b]);
  188:         break;
  189: #endif
  190:     case 15:
  191:         r = (rgba >> 16) & 0xff;
  192:         g = (rgba >> 8) & 0xff;
  193:         b = (rgba) & 0xff;
  194:         color = ((r >> 3) << 10) | ((g >> 3) << 5) | (b >> 3);
  195:         break;
  196:     case 16:
  197:         r = (rgba >> 16) & 0xff;
  198:         g = (rgba >> 8) & 0xff;
  199:         b = (rgba) & 0xff;
  200:         color = ((r >> 3) << 11) | ((g >> 2) << 5) | (b >> 3);
  201:         break;
  202:     case 32:
  203:     default:
  204:         color = rgba;
  205:         break;
  206:     }
  207:     return color;
  208: }
  209: 
  210: static void vga_fill_rect (DisplayState *ds,
  211:                            int posx, int posy, int width, int height, uint32_t color)
  212: {
  213:     uint8_t *d, *d1;
  214:     int x, y, bpp;
  215: 
  216:     bpp = (ds->depth + 7) >> 3;
  217:     d1 = ds->data +
  218:         ds->linesize * posy + bpp * posx;
  219:     for (y = 0; y < height; y++) {
  220:         d = d1;
  221:         switch(bpp) {
  222:         case 1:
  223:             for (x = 0; x < width; x++) {
  224:                 *((uint8_t *)d) = color;
  225:                 d++;
  226:             }
  227:             break;
  228:         case 2:
  229:             for (x = 0; x < width; x++) {
  230:                 *((uint16_t *)d) = color;
  231:                 d += 2;
  232:             }
  233:             break;
  234:         case 4:
  235:             for (x = 0; x < width; x++) {
  236:                 *((uint32_t *)d) = color;
  237:                 d += 4;
  238:             }
  239:             break;
  240:         }
  241:         d1 += ds->linesize;
  242:     }
  243: }
  244: 
  245: /* copy from (xs, ys) to (xd, yd) a rectangle of size (w, h) */
  246: static void vga_bitblt(DisplayState *ds, int xs, int ys, int xd, int yd, int w, int h)
  247: {
  248:     const uint8_t *s;
  249:     uint8_t *d;
  250:     int wb, y, bpp;
  251: 
  252:     bpp = (ds->depth + 7) >> 3;
  253:     wb = w * bpp;
  254:     if (yd <= ys) {
  255:         s = ds->data +
  256:             ds->linesize * ys + bpp * xs;
  257:         d = ds->data +
  258:             ds->linesize * yd + bpp * xd;
  259:         for (y = 0; y < h; y++) {
  260:             memmove(d, s, wb);
  261:             d += ds->linesize;
  262:             s += ds->linesize;
  263:         }
  264:     } else {
  265:         s = ds->data +
  266:             ds->linesize * (ys + h - 1) + bpp * xs;
  267:         d = ds->data +
  268:             ds->linesize * (yd + h - 1) + bpp * xd;
  269:        for (y = 0; y < h; y++) {
  270:             memmove(d, s, wb);
  271:             d -= ds->linesize;
  272:             s -= ds->linesize;
  273:         }
  274:     }
  275: }
  276: 
  277: /***********************************************************/
  278: /* basic char display */
  279: 
  280: #define FONT_HEIGHT 16
  281: #define FONT_WIDTH 8
  282: 
  283: #include "vgafont.h"
  284: 
  285: #define cbswap_32(__x) \
  286: ((uint32_t)( \
  287:                 (((uint32_t)(__x) & (uint32_t)0x000000ffUL) << 24) | \
  288:                 (((uint32_t)(__x) & (uint32_t)0x0000ff00UL) <<  8) | \
  289:                 (((uint32_t)(__x) & (uint32_t)0x00ff0000UL) >>  8) | \
  290:                 (((uint32_t)(__x) & (uint32_t)0xff000000UL) >> 24) ))
  291: 
  292: #ifdef WORDS_BIGENDIAN
  293: #define PAT(x) x
  294: #else
  295: #define PAT(x) cbswap_32(x)
  296: #endif
  297: 
  298: static const uint32_t dmask16[16] = {
  299:     PAT(0x00000000),
  300:     PAT(0x000000ff),
  301:     PAT(0x0000ff00),
  302:     PAT(0x0000ffff),
  303:     PAT(0x00ff0000),
  304:     PAT(0x00ff00ff),
  305:     PAT(0x00ffff00),
  306:     PAT(0x00ffffff),
  307:     PAT(0xff000000),
  308:     PAT(0xff0000ff),
  309:     PAT(0xff00ff00),
  310:     PAT(0xff00ffff),
  311:     PAT(0xffff0000),
  312:     PAT(0xffff00ff),
  313:     PAT(0xffffff00),
  314:     PAT(0xffffffff),
  315: };
  316: 
  317: static const uint32_t dmask4[4] = {
  318:     PAT(0x00000000),
  319:     PAT(0x0000ffff),
  320:     PAT(0xffff0000),
  321:     PAT(0xffffffff),
  322: };
  323: 
  324: static uint32_t color_table[2][8];
  325: 
  326: enum color_names {
  327:     COLOR_BLACK   = 0,
  328:     COLOR_RED     = 1,
  329:     COLOR_GREEN   = 2,
  330:     COLOR_YELLOW  = 3,
  331:     COLOR_BLUE    = 4,
  332:     COLOR_MAGENTA = 5,
  333:     COLOR_CYAN    = 6,
  334:     COLOR_WHITE   = 7
  335: };
  336: 
  337: static const uint32_t color_table_rgb[2][8] = {
  338:     {   /* dark */
  339:         QEMU_RGB(0x00, 0x00, 0x00),  /* black */
  340:         QEMU_RGB(0xaa, 0x00, 0x00),  /* red */
  341:         QEMU_RGB(0x00, 0xaa, 0x00),  /* green */
  342:         QEMU_RGB(0xaa, 0xaa, 0x00),  /* yellow */
  343:         QEMU_RGB(0x00, 0x00, 0xaa),  /* blue */
  344:         QEMU_RGB(0xaa, 0x00, 0xaa),  /* magenta */
  345:         QEMU_RGB(0x00, 0xaa, 0xaa),  /* cyan */
  346:         QEMU_RGB(0xaa, 0xaa, 0xaa),  /* white */
  347:     },
  348:     {   /* bright */
  349:         QEMU_RGB(0x00, 0x00, 0x00),  /* black */
  350:         QEMU_RGB(0xff, 0x00, 0x00),  /* red */
  351:         QEMU_RGB(0x00, 0xff, 0x00),  /* green */
  352:         QEMU_RGB(0xff, 0xff, 0x00),  /* yellow */
  353:         QEMU_RGB(0x00, 0x00, 0xff),  /* blue */
  354:         QEMU_RGB(0xff, 0x00, 0xff),  /* magenta */
  355:         QEMU_RGB(0x00, 0xff, 0xff),  /* cyan */
  356:         QEMU_RGB(0xff, 0xff, 0xff),  /* white */
  357:     }
  358: };
  359: 
  360: static inline unsigned int col_expand(DisplayState *ds, unsigned int col)
  361: {
  362:     switch(ds->depth) {
  363:     case 8:
  364:         col |= col << 8;
  365:         col |= col << 16;
  366:         break;
  367:     case 15:
  368:     case 16:
  369:         col |= col << 16;
  370:         break;
  371:     default:
  372:         break;
  373:     }
  374: 
  375:     return col;
  376: }
  377: #ifdef DEBUG_CONSOLE
  378: static void console_print_text_attributes(TextAttributes *t_attrib, char ch)
  379: {
  380:     if (t_attrib->bold) {
  381:         printf("b");
  382:     } else {
  383:         printf(" ");
  384:     }
  385:     if (t_attrib->uline) {
  386:         printf("u");
  387:     } else {
  388:         printf(" ");
  389:     }
  390:     if (t_attrib->blink) {
  391:         printf("l");
  392:     } else {
  393:         printf(" ");
  394:     }
  395:     if (t_attrib->invers) {
  396:         printf("i");
  397:     } else {
  398:         printf(" ");
  399:     }
  400:     if (t_attrib->unvisible) {
  401:         printf("n");
  402:     } else {
  403:         printf(" ");
  404:     }
  405: 
  406:     printf(" fg: %d bg: %d ch:'%2X' '%c'\n", t_attrib->fgcol, t_attrib->bgcol, ch, ch);
  407: }
  408: #endif
  409: 
  410: static void vga_putcharxy(DisplayState *ds, int x, int y, int ch,
  411:                           TextAttributes *t_attrib)
  412: {
  413:     uint8_t *d;
  414:     const uint8_t *font_ptr;
  415:     unsigned int font_data, linesize, xorcol, bpp;
  416:     int i;
  417:     unsigned int fgcol, bgcol;
  418: 
  419: #ifdef DEBUG_CONSOLE
  420:     printf("x: %2i y: %2i", x, y);
  421:     console_print_text_attributes(t_attrib, ch);
  422: #endif
  423: 
  424:     if (t_attrib->invers) {
  425:         bgcol = color_table[t_attrib->bold][t_attrib->fgcol];
  426:         fgcol = color_table[t_attrib->bold][t_attrib->bgcol];
  427:     } else {
  428:         fgcol = color_table[t_attrib->bold][t_attrib->fgcol];
  429:         bgcol = color_table[t_attrib->bold][t_attrib->bgcol];
  430:     }
  431: 
  432:     bpp = (ds->depth + 7) >> 3;
  433:     d = ds->data +
  434:         ds->linesize * y * FONT_HEIGHT + bpp * x * FONT_WIDTH;
  435:     linesize = ds->linesize;
  436:     font_ptr = vgafont16 + FONT_HEIGHT * ch;
  437:     xorcol = bgcol ^ fgcol;
  438:     switch(ds->depth) {
  439:     case 8:
  440:         for(i = 0; i < FONT_HEIGHT; i++) {
  441:             font_data = *font_ptr++;
  442:             if (t_attrib->uline
  443:                 && ((i == FONT_HEIGHT - 2) || (i == FONT_HEIGHT - 3))) {
  444:                 font_data = 0xFFFF;
  445:             }
  446:             ((uint32_t *)d)[0] = (dmask16[(font_data >> 4)] & xorcol) ^ bgcol;
  447:             ((uint32_t *)d)[1] = (dmask16[(font_data >> 0) & 0xf] & xorcol) ^ bgcol;
  448:             d += linesize;
  449:         }
  450:         break;
  451:     case 16:
  452:     case 15:
  453:         for(i = 0; i < FONT_HEIGHT; i++) {
  454:             font_data = *font_ptr++;
  455:             if (t_attrib->uline
  456:                 && ((i == FONT_HEIGHT - 2) || (i == FONT_HEIGHT - 3))) {
  457:                 font_data = 0xFFFF;
  458:             }
  459:             ((uint32_t *)d)[0] = (dmask4[(font_data >> 6)] & xorcol) ^ bgcol;
  460:             ((uint32_t *)d)[1] = (dmask4[(font_data >> 4) & 3] & xorcol) ^ bgcol;
  461:             ((uint32_t *)d)[2] = (dmask4[(font_data >> 2) & 3] & xorcol) ^ bgcol;
  462:             ((uint32_t *)d)[3] = (dmask4[(font_data >> 0) & 3] & xorcol) ^ bgcol;
  463:             d += linesize;
  464:         }
  465:         break;
  466:     case 32:
  467:         for(i = 0; i < FONT_HEIGHT; i++) {
  468:             font_data = *font_ptr++;
  469:             if (t_attrib->uline && ((i == FONT_HEIGHT - 2) || (i == FONT_HEIGHT - 3))) {
  470:                 font_data = 0xFFFF;
  471:             }
  472:             ((uint32_t *)d)[0] = (-((font_data >> 7)) & xorcol) ^ bgcol;
  473:             ((uint32_t *)d)[1] = (-((font_data >> 6) & 1) & xorcol) ^ bgcol;
  474:             ((uint32_t *)d)[2] = (-((font_data >> 5) & 1) & xorcol) ^ bgcol;
  475:             ((uint32_t *)d)[3] = (-((font_data >> 4) & 1) & xorcol) ^ bgcol;
  476:             ((uint32_t *)d)[4] = (-((font_data >> 3) & 1) & xorcol) ^ bgcol;
  477:             ((uint32_t *)d)[5] = (-((font_data >> 2) & 1) & xorcol) ^ bgcol;
  478:             ((uint32_t *)d)[6] = (-((font_data >> 1) & 1) & xorcol) ^ bgcol;
  479:             ((uint32_t *)d)[7] = (-((font_data >> 0) & 1) & xorcol) ^ bgcol;
  480:             d += linesize;
  481:         }
  482:         break;
  483:     }
  484: }
  485: 
  486: static void text_console_resize(TextConsole *s)
  487: {
  488:     TextCell *cells, *c, *c1;
  489:     int w1, x, y, last_width;
  490: 
  491:     last_width = s->width;
  492:     s->width = s->g_width / FONT_WIDTH;
  493:     s->height = s->g_height / FONT_HEIGHT;
  494: 
  495:     w1 = last_width;
  496:     if (s->width < w1)
  497:         w1 = s->width;
  498: 
  499:     cells = qemu_malloc(s->width * s->total_height * sizeof(TextCell));
  500:     for(y = 0; y < s->total_height; y++) {
  501:         c = &cells[y * s->width];
  502:         if (w1 > 0) {
  503:             c1 = &s->cells[y * last_width];
  504:             for(x = 0; x < w1; x++) {
  505:                 *c++ = *c1++;
  506:             }
  507:         }
  508:         for(x = w1; x < s->width; x++) {
  509:             c->ch = ' ';
  510:             c->t_attrib = s->t_attrib_default;
  511:             c++;
  512:         }
  513:     }
  514:     qemu_free(s->cells);
  515:     s->cells = cells;
  516: }
  517: 
  518: static void update_xy(TextConsole *s, int x, int y)
  519: {
  520:     TextCell *c;
  521:     int y1, y2;
  522: 
  523:     if (s == active_console) {
  524:         y1 = (s->y_base + y) % s->total_height;
  525:         y2 = y1 - s->y_displayed;
  526:         if (y2 < 0)
  527:             y2 += s->total_height;
  528:         if (y2 < s->height) {
  529:             c = &s->cells[y1 * s->width + x];
  530:             vga_putcharxy(s->ds, x, y2, c->ch,
  531:                           &(c->t_attrib));
  532:             dpy_update(s->ds, x * FONT_WIDTH, y2 * FONT_HEIGHT,
  533:                        FONT_WIDTH, FONT_HEIGHT);
  534:         }
  535:     }
  536: }
  537: 
  538: static void console_show_cursor(TextConsole *s, int show)
  539: {
  540:     TextCell *c;
  541:     int y, y1;
  542: 
  543:     if (s == active_console) {
  544:         int x = s->x;
  545:         if (x >= s->width) {
  546:             x = s->width - 1;
  547:         }
  548:         y1 = (s->y_base + s->y) % s->total_height;
  549:         y = y1 - s->y_displayed;
  550:         if (y < 0)
  551:             y += s->total_height;
  552:         if (y < s->height) {
  553:             c = &s->cells[y1 * s->width + x];
  554:             if (show) {
  555:                 TextAttributes t_attrib = s->t_attrib_default;
  556:                 t_attrib.invers = !(t_attrib.invers); /* invert fg and bg */
  557:                 vga_putcharxy(s->ds, x, y, c->ch, &t_attrib);
  558:             } else {
  559:                 vga_putcharxy(s->ds, x, y, c->ch, &(c->t_attrib));
  560:             }
  561:             dpy_update(s->ds, x * FONT_WIDTH, y * FONT_HEIGHT,
  562:                        FONT_WIDTH, FONT_HEIGHT);
  563:         }
  5