Statistics
| Branch: | Revision:

root / console.c @ 9596ebb7

History | View | Annotate | Download (34.2 kB)

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
        }
564
    }
565
}
566

    
567
static void console_refresh(TextConsole *s)
568
{
569
    TextCell *c;
570
    int x, y, y1;
571

    
572
    if (s != active_console)
573
        return;
574

    
575
    vga_fill_rect(s->ds, 0, 0, s->ds->width, s->ds->height,
576
                  color_table[0][COLOR_BLACK]);
577
    y1 = s->y_displayed;
578
    for(y = 0; y < s->height; y++) {
579
        c = s->cells + y1 * s->width;
580
        for(x = 0; x < s->width; x++) {
581
            vga_putcharxy(s->ds, x, y, c->ch,
582
                          &(c->t_attrib));
583
            c++;
584
        }
585
        if (++y1 == s->total_height)
586
            y1 = 0;
587
    }
588
    dpy_update(s->ds, 0, 0, s->ds->width, s->ds->height);
589
    console_show_cursor(s, 1);
590
}
591

    
592
static void console_scroll(int ydelta)
593
{
594
    TextConsole *s;
595
    int i, y1;
596

    
597
    s = active_console;
598
    if (!s || (s->console_type == GRAPHIC_CONSOLE))
599
        return;
600

    
601
    if (ydelta > 0) {
602
        for(i = 0; i < ydelta; i++) {
603
            if (s->y_displayed == s->y_base)
604
                break;
605
            if (++s->y_displayed == s->total_height)
606
                s->y_displayed = 0;
607
        }
608
    } else {
609
        ydelta = -ydelta;
610
        i = s->backscroll_height;
611
        if (i > s->total_height - s->height)
612
            i = s->total_height - s->height;
613
        y1 = s->y_base - i;
614
        if (y1 < 0)
615
            y1 += s->total_height;
616
        for(i = 0; i < ydelta; i++) {
617
            if (s->y_displayed == y1)
618
                break;
619
            if (--s->y_displayed < 0)
620
                s->y_displayed = s->total_height - 1;
621
        }
622
    }
623
    console_refresh(s);
624
}
625

    
626
static void console_put_lf(TextConsole *s)
627
{
628
    TextCell *c;
629
    int x, y1;
630

    
631
    s->y++;
632
    if (s->y >= s->height) {
633
        s->y = s->height - 1;
634

    
635
        if (s->y_displayed == s->y_base) {
636
            if (++s->y_displayed == s->total_height)
637
                s->y_displayed = 0;
638
        }
639
        if (++s->y_base == s->total_height)
640
            s->y_base = 0;
641
        if (s->backscroll_height < s->total_height)
642
            s->backscroll_height++;
643
        y1 = (s->y_base + s->height - 1) % s->total_height;
644
        c = &s->cells[y1 * s->width];
645
        for(x = 0; x < s->width; x++) {
646
            c->ch = ' ';
647
            c->t_attrib = s->t_attrib_default;
648
            c++;
649
        }
650
        if (s == active_console && s->y_displayed == s->y_base) {
651
            vga_bitblt(s->ds, 0, FONT_HEIGHT, 0, 0,
652
                       s->width * FONT_WIDTH,
653
                       (s->height - 1) * FONT_HEIGHT);
654
            vga_fill_rect(s->ds, 0, (s->height - 1) * FONT_HEIGHT,
655
                          s->width * FONT_WIDTH, FONT_HEIGHT,
656
                          color_table[0][s->t_attrib_default.bgcol]);
657
            dpy_update(s->ds, 0, 0,
658
                       s->width * FONT_WIDTH, s->height * FONT_HEIGHT);
659
        }
660
    }
661
}
662

    
663
/* Set console attributes depending on the current escape codes.
664
 * NOTE: I know this code is not very efficient (checking every color for it
665
 * self) but it is more readable and better maintainable.
666
 */
667
static void console_handle_escape(TextConsole *s)
668
{
669
    int i;
670

    
671
    for (i=0; i<s->nb_esc_params; i++) {
672
        switch (s->esc_params[i]) {
673
            case 0: /* reset all console attributes to default */
674
                s->t_attrib = s->t_attrib_default;
675
                break;
676
            case 1:
677
                s->t_attrib.bold = 1;
678
                break;
679
            case 4:
680
                s->t_attrib.uline = 1;
681
                break;
682
            case 5:
683
                s->t_attrib.blink = 1;
684
                break;
685
            case 7:
686
                s->t_attrib.invers = 1;
687
                break;
688
            case 8:
689
                s->t_attrib.unvisible = 1;
690
                break;
691
            case 22:
692
                s->t_attrib.bold = 0;
693
                break;
694
            case 24:
695
                s->t_attrib.uline = 0;
696
                break;
697
            case 25:
698
                s->t_attrib.blink = 0;
699
                break;
700
            case 27:
701
                s->t_attrib.invers = 0;
702
                break;
703
            case 28:
704
                s->t_attrib.unvisible = 0;
705
                break;
706
            /* set foreground color */
707
            case 30:
708
                s->t_attrib.fgcol=COLOR_BLACK;
709
                break;
710
            case 31:
711
                s->t_attrib.fgcol=COLOR_RED;
712
                break;
713
            case 32:
714
                s->t_attrib.fgcol=COLOR_GREEN;
715
                break;
716
            case 33:
717
                s->t_attrib.fgcol=COLOR_YELLOW;
718
                break;
719
            case 34:
720
                s->t_attrib.fgcol=COLOR_BLUE;
721
                break;
722
            case 35:
723
                s->t_attrib.fgcol=COLOR_MAGENTA;
724
                break;
725
            case 36:
726
                s->t_attrib.fgcol=COLOR_CYAN;
727
                break;
728
            case 37:
729
                s->t_attrib.fgcol=COLOR_WHITE;
730
                break;
731
            /* set background color */
732
            case 40:
733
                s->t_attrib.bgcol=COLOR_BLACK;
734
                break;
735
            case 41:
736
                s->t_attrib.bgcol=COLOR_RED;
737
                break;
738
            case 42:
739
                s->t_attrib.bgcol=COLOR_GREEN;
740
                break;
741
            case 43:
742
                s->t_attrib.bgcol=COLOR_YELLOW;
743
                break;
744
            case 44:
745
                s->t_attrib.bgcol=COLOR_BLUE;
746
                break;
747
            case 45:
748
                s->t_attrib.bgcol=COLOR_MAGENTA;
749
                break;
750
            case 46:
751
                s->t_attrib.bgcol=COLOR_CYAN;
752
                break;
753
            case 47:
754
                s->t_attrib.bgcol=COLOR_WHITE;
755
                break;
756
        }
757
    }
758
}
759

    
760
static void console_clear_xy(TextConsole *s, int x, int y)
761
{
762
    int y1 = (s->y_base + y) % s->total_height;
763
    TextCell *c = &s->cells[y1 * s->width + x];
764
    c->ch = ' ';
765
    c->t_attrib = s->t_attrib_default;
766
    c++;
767
    update_xy(s, x, y);
768
}
769

    
770
static void console_putchar(TextConsole *s, int ch)
771
{
772
    TextCell *c;
773
    int y1, i;
774
    int x, y;
775

    
776
    switch(s->state) {
777
    case TTY_STATE_NORM:
778
        switch(ch) {
779
        case '\r':  /* carriage return */
780
            s->x = 0;
781
            break;
782
        case '\n':  /* newline */
783
            console_put_lf(s);
784
            break;
785
        case '\b':  /* backspace */
786
            if (s->x > 0)
787
                s->x--;
788
            break;
789
        case '\t':  /* tabspace */
790
            if (s->x + (8 - (s->x % 8)) > s->width) {
791
                s->x = 0;
792
                console_put_lf(s);
793
            } else {
794
                s->x = s->x + (8 - (s->x % 8));
795
            }
796
            break;
797
        case '\a':  /* alert aka. bell */
798
            /* TODO: has to be implemented */
799
            break;
800
        case 14:
801
            /* SI (shift in), character set 0 (ignored) */
802
            break;
803
        case 15:
804
            /* SO (shift out), character set 1 (ignored) */
805
            break;
806
        case 27:    /* esc (introducing an escape sequence) */
807
            s->state = TTY_STATE_ESC;
808
            break;
809
        default:
810
            if (s->x >= s->width) {
811
                /* line wrap */
812
                s->x = 0;
813
                console_put_lf(s);
814
            }
815
            y1 = (s->y_base + s->y) % s->total_height;
816
            c = &s->cells[y1 * s->width + s->x];
817
            c->ch = ch;
818
            c->t_attrib = s->t_attrib;
819
            update_xy(s, s->x, s->y);
820
            s->x++;
821
            break;
822
        }
823
        break;
824
    case TTY_STATE_ESC: /* check if it is a terminal escape sequence */
825
        if (ch == '[') {
826
            for(i=0;i<MAX_ESC_PARAMS;i++)
827
                s->esc_params[i] = 0;
828
            s->nb_esc_params = 0;
829
            s->state = TTY_STATE_CSI;
830
        } else {
831
            s->state = TTY_STATE_NORM;
832
        }
833
        break;
834
    case TTY_STATE_CSI: /* handle escape sequence parameters */
835
        if (ch >= '0' && ch <= '9') {
836
            if (s->nb_esc_params < MAX_ESC_PARAMS) {
837
                s->esc_params[s->nb_esc_params] =
838
                    s->esc_params[s->nb_esc_params] * 10 + ch - '0';
839
            }
840
        } else {
841
            s->nb_esc_params++;
842
            if (ch == ';')
843
                break;
844
#ifdef DEBUG_CONSOLE
845
            fprintf(stderr, "escape sequence CSI%d;%d%c, %d parameters\n",
846
                    s->esc_params[0], s->esc_params[1], ch, s->nb_esc_params);
847
#endif
848
            s->state = TTY_STATE_NORM;
849
            switch(ch) {
850
            case 'A':
851
                /* move cursor up */
852
                if (s->esc_params[0] == 0) {
853
                    s->esc_params[0] = 1;
854
                }
855
                s->y -= s->esc_params[0];
856
                if (s->y < 0) {
857
                    s->y = 0;
858
                }
859
                break;
860
            case 'B':
861
                /* move cursor down */
862
                if (s->esc_params[0] == 0) {
863
                    s->esc_params[0] = 1;
864
                }
865
                s->y += s->esc_params[0];
866
                if (s->y >= s->height) {
867
                    s->y = s->height - 1;
868
                }
869
                break;
870
            case 'C':
871
                /* move cursor right */
872
                if (s->esc_params[0] == 0) {
873
                    s->esc_params[0] = 1;
874
                }
875
                s->x += s->esc_params[0];
876
                if (s->x >= s->width) {
877
                    s->x = s->width - 1;
878
                }
879
                break;
880
            case 'D':
881
                /* move cursor left */
882
                if (s->esc_params[0] == 0) {
883
                    s->esc_params[0] = 1;
884
                }
885
                s->x -= s->esc_params[0];
886
                if (s->x < 0) {
887
                    s->x = 0;
888
                }
889
                break;
890
            case 'G':
891
                /* move cursor to column */
892
                s->x = s->esc_params[0] - 1;
893
                if (s->x < 0) {
894
                    s->x = 0;
895
                }
896
                break;
897
            case 'f':
898
            case 'H':
899
                /* move cursor to row, column */
900
                s->x = s->esc_params[1] - 1;
901
                if (s->x < 0) {
902
                    s->x = 0;
903
                }
904
                s->y = s->esc_params[0] - 1;
905
                if (s->y < 0) {
906
                    s->y = 0;
907
                }
908
                break;
909
            case 'J':
910
                switch (s->esc_params[0]) {
911
                case 0:
912
                    /* clear to end of screen */
913
                    for (y = s->y; y < s->height; y++) {
914
                        for (x = 0; x < s->width; x++) {
915
                            if (y == s->y && x < s->x) {
916
                                continue;
917
                            }
918
                            console_clear_xy(s, x, y);
919
                        }
920
                    }
921
                    break;
922
                case 1:
923
                    /* clear from beginning of screen */
924
                    for (y = 0; y <= s->y; y++) {
925
                        for (x = 0; x < s->width; x++) {
926
                            if (y == s->y && x > s->x) {
927
                                break;
928
                            }
929
                            console_clear_xy(s, x, y);
930
                        }
931
                    }
932
                    break;
933
                case 2:
934
                    /* clear entire screen */
935
                    for (y = 0; y <= s->height; y++) {
936
                        for (x = 0; x < s->width; x++) {
937
                            console_clear_xy(s, x, y);
938
                        }
939
                    }
940
                break;
941
                }
942
            case 'K':
943
                switch (s->esc_params[0]) {
944
                case 0:
945
                /* clear to eol */
946
                for(x = s->x; x < s->width; x++) {
947
                        console_clear_xy(s, x, s->y);
948
                }
949
                break;
950
                case 1:
951
                    /* clear from beginning of line */
952
                    for (x = 0; x <= s->x; x++) {
953
                        console_clear_xy(s, x, s->y);
954
                    }
955
                    break;
956
                case 2:
957
                    /* clear entire line */
958
                    for(x = 0; x < s->width; x++) {
959
                        console_clear_xy(s, x, s->y);
960
                    }
961
                break;
962
            }
963
                break;
964
            case 'm':
965
            console_handle_escape(s);
966
            break;
967
            case 'n':
968
                /* report cursor position */
969
                /* TODO: send ESC[row;colR */
970
                break;
971
            case 's':
972
                /* save cursor position */
973
                s->x_saved = s->x;
974
                s->y_saved = s->y;
975
                break;
976
            case 'u':
977
                /* restore cursor position */
978
                s->x = s->x_saved;
979
                s->y = s->y_saved;
980
                break;
981
            default:
982
#ifdef DEBUG_CONSOLE
983
                fprintf(stderr, "unhandled escape character '%c'\n", ch);
984
#endif
985
                break;
986
            }
987
            break;
988
        }
989
    }
990
}
991

    
992
void console_select(unsigned int index)
993
{
994
    TextConsole *s;
995

    
996
    if (index >= MAX_CONSOLES)
997
        return;
998
    s = consoles[index];
999
    if (s) {
1000
        active_console = s;
1001
        if (s->console_type != GRAPHIC_CONSOLE) {
1002
            if (s->g_width != s->ds->width ||
1003
                s->g_height != s->ds->height) {
1004
                if (s->console_type == TEXT_CONSOLE_FIXED_SIZE) {
1005
                    dpy_resize(s->ds, s->g_width, s->g_height);
1006
                } else {
1007
                s->g_width = s->ds->width;
1008
                s->g_height = s->ds->height;
1009
                text_console_resize(s);
1010
            }
1011
            }
1012
            console_refresh(s);
1013
        } else {
1014
            vga_hw_invalidate();
1015
        }
1016
    }
1017
}
1018

    
1019
static int console_puts(CharDriverState *chr, const uint8_t *buf, int len)
1020
{
1021
    TextConsole *s = chr->opaque;
1022
    int i;
1023

    
1024
    console_show_cursor(s, 0);
1025
    for(i = 0; i < len; i++) {
1026
        console_putchar(s, buf[i]);
1027
    }
1028
    console_show_cursor(s, 1);
1029
    return len;
1030
}
1031

    
1032
static void console_send_event(CharDriverState *chr, int event)
1033
{
1034
    TextConsole *s = chr->opaque;
1035
    int i;
1036

    
1037
    if (event == CHR_EVENT_FOCUS) {
1038
        for(i = 0; i < nb_consoles; i++) {
1039
            if (consoles[i] == s) {
1040
                console_select(i);
1041
                break;
1042
            }
1043
        }
1044
    }
1045
}
1046

    
1047
static void kbd_send_chars(void *opaque)
1048
{
1049
    TextConsole *s = opaque;
1050
    int len;
1051
    uint8_t buf[16];
1052

    
1053
    len = qemu_chr_can_read(s->chr);
1054
    if (len > s->out_fifo.count)
1055
        len = s->out_fifo.count;
1056
    if (len > 0) {
1057
        if (len > sizeof(buf))
1058
            len = sizeof(buf);
1059
        qemu_fifo_read(&s->out_fifo, buf, len);
1060
        qemu_chr_read(s->chr, buf, len);
1061
    }
1062
    /* characters are pending: we send them a bit later (XXX:
1063
       horrible, should change char device API) */
1064
    if (s->out_fifo.count > 0) {
1065
        qemu_mod_timer(s->kbd_timer, qemu_get_clock(rt_clock) + 1);
1066
    }
1067
}
1068

    
1069
/* called when an ascii key is pressed */
1070
void kbd_put_keysym(int keysym)
1071
{
1072
    TextConsole *s;
1073
    uint8_t buf[16], *q;
1074
    int c;
1075

    
1076
    s = active_console;
1077
    if (!s || (s->console_type == GRAPHIC_CONSOLE))
1078
        return;
1079

    
1080
    switch(keysym) {
1081
    case QEMU_KEY_CTRL_UP:
1082
        console_scroll(-1);
1083
        break;
1084
    case QEMU_KEY_CTRL_DOWN:
1085
        console_scroll(1);
1086
        break;
1087
    case QEMU_KEY_CTRL_PAGEUP:
1088
        console_scroll(-10);
1089
        break;
1090
    case QEMU_KEY_CTRL_PAGEDOWN:
1091
        console_scroll(10);
1092
        break;
1093
    default:
1094
        /* convert the QEMU keysym to VT100 key string */
1095
        q = buf;
1096
        if (keysym >= 0xe100 && keysym <= 0xe11f) {
1097
            *q++ = '\033';
1098
            *q++ = '[';
1099
            c = keysym - 0xe100;
1100
            if (c >= 10)
1101
                *q++ = '0' + (c / 10);
1102
            *q++ = '0' + (c % 10);
1103
            *q++ = '~';
1104
        } else if (keysym >= 0xe120 && keysym <= 0xe17f) {
1105
            *q++ = '\033';
1106
            *q++ = '[';
1107
            *q++ = keysym & 0xff;
1108
        } else {
1109
                *q++ = keysym;
1110
        }
1111
        if (s->chr->chr_read) {
1112
            qemu_fifo_write(&s->out_fifo, buf, q - buf);
1113
            kbd_send_chars(s);
1114
        }
1115
        break;
1116
    }
1117
}
1118

    
1119
static TextConsole *new_console(DisplayState *ds, console_type_t console_type)
1120
{
1121
    TextConsole *s;
1122
    int i;
1123

    
1124
    if (nb_consoles >= MAX_CONSOLES)
1125
        return NULL;
1126
    s = qemu_mallocz(sizeof(TextConsole));
1127
    if (!s) {
1128
        return NULL;
1129
    }
1130
    if (!active_console || ((active_console->console_type != GRAPHIC_CONSOLE) &&
1131
        (console_type == GRAPHIC_CONSOLE))) {
1132
        active_console = s;
1133
    }
1134
    s->ds = ds;
1135
    s->console_type = console_type;
1136
    if (console_type != GRAPHIC_CONSOLE) {
1137
        consoles[nb_consoles++] = s;
1138
    } else {
1139
        /* HACK: Put graphical consoles before text consoles.  */
1140
        for (i = nb_consoles; i > 0; i--) {
1141
            if (consoles[i - 1]->console_type == GRAPHIC_CONSOLE)
1142
                break;
1143
            consoles[i] = consoles[i - 1];
1144
        }
1145
        consoles[i] = s;
1146
    }
1147
    return s;
1148
}
1149

    
1150
TextConsole *graphic_console_init(DisplayState *ds, vga_hw_update_ptr update,
1151
                                  vga_hw_invalidate_ptr invalidate,
1152
                                  vga_hw_screen_dump_ptr screen_dump,
1153
                                  void *opaque)
1154
{
1155
    TextConsole *s;
1156

    
1157
    s = new_console(ds, GRAPHIC_CONSOLE);
1158
    if (!s)
1159
      return NULL;
1160
    s->hw_update = update;
1161
    s->hw_invalidate = invalidate;
1162
    s->hw_screen_dump = screen_dump;
1163
    s->hw = opaque;
1164
    return s;
1165
}
1166

    
1167
int is_graphic_console(void)
1168
{
1169
    return active_console->console_type == GRAPHIC_CONSOLE;
1170
}
1171

    
1172
void console_color_init(DisplayState *ds)
1173
{
1174
    int i, j;
1175
    for (j = 0; j < 2; j++) {
1176
        for (i = 0; i < 8; i++) {
1177
            color_table[j][i] = col_expand(ds, 
1178
                   vga_get_color(ds, color_table_rgb[j][i]));
1179
        }
1180
    }
1181
}
1182

    
1183
CharDriverState *text_console_init(DisplayState *ds, const char *p)
1184
{
1185
    CharDriverState *chr;
1186
    TextConsole *s;
1187
    unsigned width;
1188
    unsigned height;
1189
    static int color_inited;
1190

    
1191
    chr = qemu_mallocz(sizeof(CharDriverState));
1192
    if (!chr)
1193
        return NULL;
1194
    s = new_console(ds, (p == 0) ? TEXT_CONSOLE : TEXT_CONSOLE_FIXED_SIZE);
1195
    if (!s) {
1196
        free(chr);
1197
        return NULL;
1198
    }
1199
    chr->opaque = s;
1200
    chr->chr_write = console_puts;
1201
    chr->chr_send_event = console_send_event;
1202

    
1203
    s->chr = chr;
1204
    s->out_fifo.buf = s->out_fifo_buf;
1205
    s->out_fifo.buf_size = sizeof(s->out_fifo_buf);
1206
    s->kbd_timer = qemu_new_timer(rt_clock, kbd_send_chars, s);
1207

    
1208
    if (!color_inited) {
1209
        color_inited = 1;
1210
        console_color_init(s->ds);
1211
    }
1212
    s->y_displayed = 0;
1213
    s->y_base = 0;
1214
    s->total_height = DEFAULT_BACKSCROLL;
1215
    s->x = 0;
1216
    s->y = 0;
1217
    width = s->ds->width;
1218
    height = s->ds->height;
1219
    if (p != 0) {
1220
        width = strtoul(p, (char **)&p, 10);
1221
        if (*p == 'C') {
1222
            p++;
1223
            width *= FONT_WIDTH;
1224
        }
1225
        if (*p == 'x') {
1226
            p++;
1227
            height = strtoul(p, (char **)&p, 10);
1228
            if (*p == 'C') {
1229
                p++;
1230
                height *= FONT_HEIGHT;
1231
            }
1232
        }
1233
    }
1234
    s->g_width = width;
1235
    s->g_height = height;
1236

    
1237
    /* Set text attribute defaults */
1238
    s->t_attrib_default.bold = 0;
1239
    s->t_attrib_default.uline = 0;
1240
    s->t_attrib_default.blink = 0;
1241
    s->t_attrib_default.invers = 0;
1242
    s->t_attrib_default.unvisible = 0;
1243
    s->t_attrib_default.fgcol = COLOR_WHITE;
1244
    s->t_attrib_default.bgcol = COLOR_BLACK;
1245

    
1246
    /* set current text attributes to default */
1247
    s->t_attrib = s->t_attrib_default;
1248
    text_console_resize(s);
1249

    
1250
    qemu_chr_reset(chr);
1251

    
1252
    return chr;
1253
}