Statistics
| Branch: | Revision:

root / console.c @ e5b0bc44

History | View | Annotate | Download (33.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 "vl.h"
25

    
26
//#define DEBUG_CONSOLE
27
#define DEFAULT_BACKSCROLL 512
28
#define MAX_CONSOLES 12
29

    
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)
32

    
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

    
43
typedef struct TextCell {
44
    uint8_t ch;
45
    TextAttributes t_attrib;
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

    
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

    
107
/* ??? This is mis-named.
108
   It is used for both text and graphical consoles.  */
109
struct TextConsole {
110
    int text_console; /* true if text console */
111
    DisplayState *ds;
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

    
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 x_saved, y_saved;
125
    int y_displayed;
126
    int y_base;
127
    TextAttributes t_attrib_default; /* default text attributes */
128
    TextAttributes t_attrib; /* currently active text attributes */
129
    TextCell *cells;
130

    
131
    enum TTYState state;
132
    int esc_params[MAX_ESC_PARAMS];
133
    int nb_esc_params;
134

    
135
    CharDriverState *chr;
136
    /* fifo for key pressed */
137
    QEMUFIFO out_fifo;
138
    uint8_t out_fifo_buf[16];
139
    QEMUTimer *kbd_timer;
140
};
141

    
142
static TextConsole *active_console;
143
static TextConsole *consoles[MAX_CONSOLES];
144
static int nb_consoles = 0;
145

    
146
void vga_hw_update(void)
147
{
148
    if (active_console && active_console->hw_update)
149
        active_console->hw_update(active_console->hw);
150
}
151

    
152
void vga_hw_invalidate(void)
153
{
154
    if (active_console->hw_invalidate)
155
        active_console->hw_invalidate(active_console->hw);
156
}
157

    
158
void vga_hw_screen_dump(const char *filename)
159
{
160
    /* There is currently no was of specifying which screen we want to dump,
161
       so always dump the dirst one.  */
162
    if (consoles[0]->hw_screen_dump)
163
        consoles[0]->hw_screen_dump(consoles[0]->hw, filename);
164
}
165

    
166
/* convert a RGBA color to a color index usable in graphic primitives */
167
static unsigned int vga_get_color(DisplayState *ds, unsigned int rgba)
168
{
169
    unsigned int r, g, b, color;
170

    
171
    switch(ds->depth) {
172
#if 0
173
    case 8:
174
        r = (rgba >> 16) & 0xff;
175
        g = (rgba >> 8) & 0xff;
176
        b = (rgba) & 0xff;
177
        color = (rgb_to_index[r] * 6 * 6) + 
178
            (rgb_to_index[g] * 6) + 
179
            (rgb_to_index[b]);
180
        break;
181
#endif
182
    case 15:
183
        r = (rgba >> 16) & 0xff;
184
        g = (rgba >> 8) & 0xff;
185
        b = (rgba) & 0xff;
186
        color = ((r >> 3) << 10) | ((g >> 3) << 5) | (b >> 3);
187
        break;
188
    case 16:
189
        r = (rgba >> 16) & 0xff;
190
        g = (rgba >> 8) & 0xff;
191
        b = (rgba) & 0xff;
192
        color = ((r >> 3) << 11) | ((g >> 2) << 5) | (b >> 3);
193
        break;
194
    case 32:
195
    default:
196
        color = rgba;
197
        break;
198
    }
199
    return color;
200
}
201

    
202
static void vga_fill_rect (DisplayState *ds, 
203
                           int posx, int posy, int width, int height, uint32_t color)
204
{
205
    uint8_t *d, *d1;
206
    int x, y, bpp;
207
    
208
    bpp = (ds->depth + 7) >> 3;
209
    d1 = ds->data + 
210
        ds->linesize * posy + bpp * posx;
211
    for (y = 0; y < height; y++) {
212
        d = d1;
213
        switch(bpp) {
214
        case 1:
215
            for (x = 0; x < width; x++) {
216
                *((uint8_t *)d) = color;
217
                d++;
218
            }
219
            break;
220
        case 2:
221
            for (x = 0; x < width; x++) {
222
                *((uint16_t *)d) = color;
223
                d += 2;
224
            }
225
            break;
226
        case 4:
227
            for (x = 0; x < width; x++) {
228
                *((uint32_t *)d) = color;
229
                d += 4;
230
            }
231
            break;
232
        }
233
        d1 += ds->linesize;
234
    }
235
}
236

    
237
/* copy from (xs, ys) to (xd, yd) a rectangle of size (w, h) */
238
static void vga_bitblt(DisplayState *ds, int xs, int ys, int xd, int yd, int w, int h)
239
{
240
    const uint8_t *s;
241
    uint8_t *d;
242
    int wb, y, bpp;
243

    
244
    bpp = (ds->depth + 7) >> 3;
245
    wb = w * bpp;
246
    if (yd <= ys) {
247
        s = ds->data + 
248
            ds->linesize * ys + bpp * xs;
249
        d = ds->data + 
250
            ds->linesize * yd + bpp * xd;
251
        for (y = 0; y < h; y++) {
252
            memmove(d, s, wb);
253
            d += ds->linesize;
254
            s += ds->linesize;
255
        }
256
    } else {
257
        s = ds->data + 
258
            ds->linesize * (ys + h - 1) + bpp * xs;
259
        d = ds->data + 
260
            ds->linesize * (yd + h - 1) + bpp * xd;
261
       for (y = 0; y < h; y++) {
262
            memmove(d, s, wb);
263
            d -= ds->linesize;
264
            s -= ds->linesize;
265
        }
266
    }
267
}
268

    
269
/***********************************************************/
270
/* basic char display */
271

    
272
#define FONT_HEIGHT 16
273
#define FONT_WIDTH 8
274

    
275
#include "vgafont.h"
276

    
277
#define cbswap_32(__x) \
278
((uint32_t)( \
279
                (((uint32_t)(__x) & (uint32_t)0x000000ffUL) << 24) | \
280
                (((uint32_t)(__x) & (uint32_t)0x0000ff00UL) <<  8) | \
281
                (((uint32_t)(__x) & (uint32_t)0x00ff0000UL) >>  8) | \
282
                (((uint32_t)(__x) & (uint32_t)0xff000000UL) >> 24) ))
283

    
284
#ifdef WORDS_BIGENDIAN
285
#define PAT(x) x
286
#else
287
#define PAT(x) cbswap_32(x)
288
#endif
289

    
290
static const uint32_t dmask16[16] = {
291
    PAT(0x00000000),
292
    PAT(0x000000ff),
293
    PAT(0x0000ff00),
294
    PAT(0x0000ffff),
295
    PAT(0x00ff0000),
296
    PAT(0x00ff00ff),
297
    PAT(0x00ffff00),
298
    PAT(0x00ffffff),
299
    PAT(0xff000000),
300
    PAT(0xff0000ff),
301
    PAT(0xff00ff00),
302
    PAT(0xff00ffff),
303
    PAT(0xffff0000),
304
    PAT(0xffff00ff),
305
    PAT(0xffffff00),
306
    PAT(0xffffffff),
307
};
308

    
309
static const uint32_t dmask4[4] = {
310
    PAT(0x00000000),
311
    PAT(0x0000ffff),
312
    PAT(0xffff0000),
313
    PAT(0xffffffff),
314
};
315

    
316
static uint32_t color_table[2][8];
317

    
318
enum color_names {
319
    COLOR_BLACK   = 0,
320
    COLOR_RED     = 1,
321
    COLOR_GREEN   = 2,
322
    COLOR_YELLOW  = 3,
323
    COLOR_BLUE    = 4,
324
    COLOR_MAGENTA = 5,
325
    COLOR_CYAN    = 6,
326
    COLOR_WHITE   = 7
327
};
328

    
329
static const uint32_t color_table_rgb[2][8] = {
330
    {   /* dark */
331
        QEMU_RGB(0x00, 0x00, 0x00),  /* black */
332
        QEMU_RGB(0xaa, 0x00, 0x00),  /* red */
333
        QEMU_RGB(0x00, 0xaa, 0x00),  /* green */
334
        QEMU_RGB(0xaa, 0xaa, 0x00),  /* yellow */
335
        QEMU_RGB(0x00, 0x00, 0xaa),  /* blue */
336
        QEMU_RGB(0xaa, 0x00, 0xaa),  /* magenta */
337
        QEMU_RGB(0x00, 0xaa, 0xaa),  /* cyan */
338
        QEMU_RGB(0xaa, 0xaa, 0xaa),  /* white */
339
    },
340
    {   /* bright */
341
        QEMU_RGB(0x00, 0x00, 0x00),  /* black */
342
        QEMU_RGB(0xff, 0x00, 0x00),  /* red */
343
        QEMU_RGB(0x00, 0xff, 0x00),  /* green */
344
        QEMU_RGB(0xff, 0xff, 0x00),  /* yellow */
345
        QEMU_RGB(0x00, 0x00, 0xff),  /* blue */
346
        QEMU_RGB(0xff, 0x00, 0xff),  /* magenta */
347
        QEMU_RGB(0x00, 0xff, 0xff),  /* cyan */
348
        QEMU_RGB(0xff, 0xff, 0xff),  /* white */
349
    }
350
};
351

    
352
static inline unsigned int col_expand(DisplayState *ds, unsigned int col)
353
{
354
    switch(ds->depth) {
355
    case 8:
356
        col |= col << 8;
357
        col |= col << 16;
358
        break;
359
    case 15:
360
    case 16:
361
        col |= col << 16;
362
        break;
363
    default:
364
        break;
365
    }
366

    
367
    return col;
368
}
369
#ifdef DEBUG_CONSOLE
370
static void console_print_text_attributes(TextAttributes *t_attrib, char ch)
371
{
372
    if (t_attrib->bold) {
373
        printf("b");
374
    } else {
375
        printf(" ");
376
    }
377
    if (t_attrib->uline) {
378
        printf("u");
379
    } else {
380
        printf(" ");
381
    }
382
    if (t_attrib->blink) {
383
        printf("l");
384
    } else {
385
        printf(" ");
386
    }
387
    if (t_attrib->invers) {
388
        printf("i");
389
    } else {
390
        printf(" ");
391
    }
392
    if (t_attrib->unvisible) {
393
        printf("n");
394
    } else {
395
        printf(" ");
396
    }
397

    
398
    printf(" fg: %d bg: %d ch:'%2X' '%c'\n", t_attrib->fgcol, t_attrib->bgcol, ch, ch);
399
}
400
#endif
401

    
402
static void vga_putcharxy(DisplayState *ds, int x, int y, int ch, 
403
                          TextAttributes *t_attrib)
404
{
405
    uint8_t *d;
406
    const uint8_t *font_ptr;
407
    unsigned int font_data, linesize, xorcol, bpp;
408
    int i;
409
    unsigned int fgcol, bgcol;
410

    
411
#ifdef DEBUG_CONSOLE
412
    printf("x: %2i y: %2i", x, y);
413
    console_print_text_attributes(t_attrib, ch);
414
#endif
415

    
416
    if (t_attrib->invers) {
417
        bgcol = color_table[t_attrib->bold][t_attrib->fgcol];
418
        fgcol = color_table[t_attrib->bold][t_attrib->bgcol];
419
    } else {
420
        fgcol = color_table[t_attrib->bold][t_attrib->fgcol];
421
        bgcol = color_table[t_attrib->bold][t_attrib->bgcol];
422
    }
423

    
424
    bpp = (ds->depth + 7) >> 3;
425
    d = ds->data + 
426
        ds->linesize * y * FONT_HEIGHT + bpp * x * FONT_WIDTH;
427
    linesize = ds->linesize;
428
    font_ptr = vgafont16 + FONT_HEIGHT * ch;
429
    xorcol = bgcol ^ fgcol;
430
    switch(ds->depth) {
431
    case 8:
432
        for(i = 0; i < FONT_HEIGHT; i++) {
433
            font_data = *font_ptr++;
434
            if (t_attrib->uline
435
                && ((i == FONT_HEIGHT - 2) || (i == FONT_HEIGHT - 3))) {
436
                font_data = 0xFFFF;
437
            }
438
            ((uint32_t *)d)[0] = (dmask16[(font_data >> 4)] & xorcol) ^ bgcol;
439
            ((uint32_t *)d)[1] = (dmask16[(font_data >> 0) & 0xf] & xorcol) ^ bgcol;
440
            d += linesize;
441
        }
442
        break;
443
    case 16:
444
    case 15:
445
        for(i = 0; i < FONT_HEIGHT; i++) {
446
            font_data = *font_ptr++;
447
            if (t_attrib->uline
448
                && ((i == FONT_HEIGHT - 2) || (i == FONT_HEIGHT - 3))) {
449
                font_data = 0xFFFF;
450
            }
451
            ((uint32_t *)d)[0] = (dmask4[(font_data >> 6)] & xorcol) ^ bgcol;
452
            ((uint32_t *)d)[1] = (dmask4[(font_data >> 4) & 3] & xorcol) ^ bgcol;
453
            ((uint32_t *)d)[2] = (dmask4[(font_data >> 2) & 3] & xorcol) ^ bgcol;
454
            ((uint32_t *)d)[3] = (dmask4[(font_data >> 0) & 3] & xorcol) ^ bgcol;
455
            d += linesize;
456
        }
457
        break;
458
    case 32:
459
        for(i = 0; i < FONT_HEIGHT; i++) {
460
            font_data = *font_ptr++;
461
            if (t_attrib->uline && ((i == FONT_HEIGHT - 2) || (i == FONT_HEIGHT - 3))) {
462
                font_data = 0xFFFF;
463
            }
464
            ((uint32_t *)d)[0] = (-((font_data >> 7)) & xorcol) ^ bgcol;
465
            ((uint32_t *)d)[1] = (-((font_data >> 6) & 1) & xorcol) ^ bgcol;
466
            ((uint32_t *)d)[2] = (-((font_data >> 5) & 1) & xorcol) ^ bgcol;
467
            ((uint32_t *)d)[3] = (-((font_data >> 4) & 1) & xorcol) ^ bgcol;
468
            ((uint32_t *)d)[4] = (-((font_data >> 3) & 1) & xorcol) ^ bgcol;
469
            ((uint32_t *)d)[5] = (-((font_data >> 2) & 1) & xorcol) ^ bgcol;
470
            ((uint32_t *)d)[6] = (-((font_data >> 1) & 1) & xorcol) ^ bgcol;
471
            ((uint32_t *)d)[7] = (-((font_data >> 0) & 1) & xorcol) ^ bgcol;
472
            d += linesize;
473
        }
474
        break;
475
    }
476
}
477

    
478
static void text_console_resize(TextConsole *s)
479
{
480
    TextCell *cells, *c, *c1;
481
    int w1, x, y, last_width;
482

    
483
    last_width = s->width;
484
    s->width = s->g_width / FONT_WIDTH;
485
    s->height = s->g_height / FONT_HEIGHT;
486

    
487
    w1 = last_width;
488
    if (s->width < w1)
489
        w1 = s->width;
490

    
491
    cells = qemu_malloc(s->width * s->total_height * sizeof(TextCell));
492
    for(y = 0; y < s->total_height; y++) {
493
        c = &cells[y * s->width];
494
        if (w1 > 0) {
495
            c1 = &s->cells[y * last_width];
496
            for(x = 0; x < w1; x++) {
497
                *c++ = *c1++;
498
            }
499
        }
500
        for(x = w1; x < s->width; x++) {
501
            c->ch = ' ';
502
            c->t_attrib = s->t_attrib_default;
503
            c++;
504
        }
505
    }
506
    free(s->cells);
507
    s->cells = cells;
508
}
509

    
510
static void update_xy(TextConsole *s, int x, int y)
511
{
512
    TextCell *c;
513
    int y1, y2;
514

    
515
    if (s == active_console) {
516
        y1 = (s->y_base + y) % s->total_height;
517
        y2 = y1 - s->y_displayed;
518
        if (y2 < 0)
519
            y2 += s->total_height;
520
        if (y2 < s->height) {
521
            c = &s->cells[y1 * s->width + x];
522
            vga_putcharxy(s->ds, x, y2, c->ch, 
523
                          &(c->t_attrib));
524
            dpy_update(s->ds, x * FONT_WIDTH, y2 * FONT_HEIGHT, 
525
                       FONT_WIDTH, FONT_HEIGHT);
526
        }
527
    }
528
}
529

    
530
static void console_show_cursor(TextConsole *s, int show)
531
{
532
    TextCell *c;
533
    int y, y1;
534

    
535
    if (s == active_console) {
536
        y1 = (s->y_base + s->y) % s->total_height;
537
        y = y1 - s->y_displayed;
538
        if (y < 0)
539
            y += s->total_height;
540
        if (y < s->height) {
541
            c = &s->cells[y1 * s->width + s->x];
542
            if (show) {
543
                TextAttributes t_attrib = s->t_attrib_default;
544
                t_attrib.invers = !(t_attrib.invers); /* invert fg and bg */
545
                vga_putcharxy(s->ds, s->x, y, c->ch, &t_attrib);
546
            } else {
547
                vga_putcharxy(s->ds, s->x, y, c->ch, 
548
                              &(c->t_attrib));
549
            }
550
            dpy_update(s->ds, s->x * FONT_WIDTH, y * FONT_HEIGHT, 
551
                       FONT_WIDTH, FONT_HEIGHT);
552
        }
553
    }
554
}
555

    
556
static void console_refresh(TextConsole *s)
557
{
558
    TextCell *c;
559
    int x, y, y1;
560

    
561
    if (s != active_console) 
562
        return;
563

    
564
    vga_fill_rect(s->ds, 0, 0, s->ds->width, s->ds->height,
565
                  color_table[0][COLOR_BLACK]);
566
    y1 = s->y_displayed;
567
    for(y = 0; y < s->height; y++) {
568
        c = s->cells + y1 * s->width;
569
        for(x = 0; x < s->width; x++) {
570
            vga_putcharxy(s->ds, x, y, c->ch, 
571
                          &(c->t_attrib));
572
            c++;
573
        }
574
        if (++y1 == s->total_height)
575
            y1 = 0;
576
    }
577
    dpy_update(s->ds, 0, 0, s->ds->width, s->ds->height);
578
    console_show_cursor(s, 1);
579
}
580

    
581
static void console_scroll(int ydelta)
582
{
583
    TextConsole *s;
584
    int i, y1;
585
    
586
    s = active_console;
587
    if (!s || !s->text_console)
588
        return;
589

    
590
    if (ydelta > 0) {
591
        for(i = 0; i < ydelta; i++) {
592
            if (s->y_displayed == s->y_base)
593
                break;
594
            if (++s->y_displayed == s->total_height)
595
                s->y_displayed = 0;
596
        }
597
    } else {
598
        ydelta = -ydelta;
599
        i = s->backscroll_height;
600
        if (i > s->total_height - s->height)
601
            i = s->total_height - s->height;
602
        y1 = s->y_base - i;
603
        if (y1 < 0)
604
            y1 += s->total_height;
605
        for(i = 0; i < ydelta; i++) {
606
            if (s->y_displayed == y1)
607
                break;
608
            if (--s->y_displayed < 0)
609
                s->y_displayed = s->total_height - 1;
610
        }
611
    }
612
    console_refresh(s);
613
}
614

    
615
static void console_put_lf(TextConsole *s)
616
{
617
    TextCell *c;
618
    int x, y1;
619

    
620
    s->y++;
621
    if (s->y >= s->height) {
622
        s->y = s->height - 1;
623

    
624
        if (s->y_displayed == s->y_base) {
625
            if (++s->y_displayed == s->total_height)
626
                s->y_displayed = 0;
627
        }
628
        if (++s->y_base == s->total_height)
629
            s->y_base = 0;
630
        if (s->backscroll_height < s->total_height)
631
            s->backscroll_height++;
632
        y1 = (s->y_base + s->height - 1) % s->total_height;
633
        c = &s->cells[y1 * s->width];
634
        for(x = 0; x < s->width; x++) {
635
            c->ch = ' ';
636
            c->t_attrib = s->t_attrib_default;
637
            c++;
638
        }
639
        if (s == active_console && s->y_displayed == s->y_base) {
640
            vga_bitblt(s->ds, 0, FONT_HEIGHT, 0, 0, 
641
                       s->width * FONT_WIDTH, 
642
                       (s->height - 1) * FONT_HEIGHT);
643
            vga_fill_rect(s->ds, 0, (s->height - 1) * FONT_HEIGHT,
644
                          s->width * FONT_WIDTH, FONT_HEIGHT, 
645
                          color_table[0][s->t_attrib_default.bgcol]);
646
            dpy_update(s->ds, 0, 0, 
647
                       s->width * FONT_WIDTH, s->height * FONT_HEIGHT);
648
        }
649
    }
650
}
651

    
652
/* Set console attributes depending on the current escape codes.
653
 * NOTE: I know this code is not very efficient (checking every color for it
654
 * self) but it is more readable and better maintainable.
655
 */
656
static void console_handle_escape(TextConsole *s)
657
{
658
    int i;
659

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

    
749
static void console_clear_xy(TextConsole *s, int x, int y)
750
{
751
    int y1 = (s->y_base + y) % s->total_height;
752
    TextCell *c = &s->cells[y1 * s->width + x];
753
    c->ch = ' ';
754
    c->t_attrib = s->t_attrib_default;
755
    c++;
756
    update_xy(s, x, y);
757
}
758

    
759
static void console_putchar(TextConsole *s, int ch)
760
{
761
    TextCell *c;
762
    int y1, i;
763
    int x, y;
764

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

    
985
void console_select(unsigned int index)
986
{
987
    TextConsole *s;
988

    
989
    if (index >= MAX_CONSOLES)
990
        return;
991
    s = consoles[index];
992
    if (s) {
993
        active_console = s;
994
        if (s->text_console) {
995
            if (s->g_width != s->ds->width ||
996
                s->g_height != s->ds->height) {
997
                s->g_width = s->ds->width;
998
                s->g_height = s->ds->height;
999
                text_console_resize(s);
1000
            }
1001
            console_refresh(s);
1002
        } else {
1003
            vga_hw_invalidate();
1004
        }
1005
    }
1006
}
1007

    
1008
static int console_puts(CharDriverState *chr, const uint8_t *buf, int len)
1009
{
1010
    TextConsole *s = chr->opaque;
1011
    int i;
1012

    
1013
    console_show_cursor(s, 0);
1014
    for(i = 0; i < len; i++) {
1015
        console_putchar(s, buf[i]);
1016
    }
1017
    console_show_cursor(s, 1);
1018
    return len;
1019
}
1020

    
1021
static void console_send_event(CharDriverState *chr, int event)
1022
{
1023
    TextConsole *s = chr->opaque;
1024
    int i;
1025

    
1026
    if (event == CHR_EVENT_FOCUS) {
1027
        for(i = 0; i < nb_consoles; i++) {
1028
            if (consoles[i] == s) {
1029
                console_select(i);
1030
                break;
1031
            }
1032
        }
1033
    }
1034
}
1035

    
1036
static void kbd_send_chars(void *opaque)
1037
{
1038
    TextConsole *s = opaque;
1039
    int len;
1040
    uint8_t buf[16];
1041
    
1042
    len = qemu_chr_can_read(s->chr);
1043
    if (len > s->out_fifo.count)
1044
        len = s->out_fifo.count;
1045
    if (len > 0) {
1046
        if (len > sizeof(buf))
1047
            len = sizeof(buf);
1048
        qemu_fifo_read(&s->out_fifo, buf, len);
1049
        qemu_chr_read(s->chr, buf, len);
1050
    }
1051
    /* characters are pending: we send them a bit later (XXX:
1052
       horrible, should change char device API) */
1053
    if (s->out_fifo.count > 0) {
1054
        qemu_mod_timer(s->kbd_timer, qemu_get_clock(rt_clock) + 1);
1055
    }
1056
}
1057

    
1058
/* called when an ascii key is pressed */
1059
void kbd_put_keysym(int keysym)
1060
{
1061
    TextConsole *s;
1062
    uint8_t buf[16], *q;
1063
    int c;
1064

    
1065
    s = active_console;
1066
    if (!s || !s->text_console)
1067
        return;
1068

    
1069
    switch(keysym) {
1070
    case QEMU_KEY_CTRL_UP:
1071
        console_scroll(-1);
1072
        break;
1073
    case QEMU_KEY_CTRL_DOWN:
1074
        console_scroll(1);
1075
        break;
1076
    case QEMU_KEY_CTRL_PAGEUP:
1077
        console_scroll(-10);
1078
        break;
1079
    case QEMU_KEY_CTRL_PAGEDOWN:
1080
        console_scroll(10);
1081
        break;
1082
    default:
1083
        /* convert the QEMU keysym to VT100 key string */
1084
        q = buf;
1085
        if (keysym >= 0xe100 && keysym <= 0xe11f) {
1086
            *q++ = '\033';
1087
            *q++ = '[';
1088
            c = keysym - 0xe100;
1089
            if (c >= 10)
1090
                *q++ = '0' + (c / 10);
1091
            *q++ = '0' + (c % 10);
1092
            *q++ = '~';
1093
        } else if (keysym >= 0xe120 && keysym <= 0xe17f) {
1094
            *q++ = '\033';
1095
            *q++ = '[';
1096
            *q++ = keysym & 0xff;
1097
        } else {
1098
                *q++ = keysym;
1099
        }
1100
        if (s->chr->chr_read) {
1101
            qemu_fifo_write(&s->out_fifo, buf, q - buf);
1102
            kbd_send_chars(s);
1103
        }
1104
        break;
1105
    }
1106
}
1107

    
1108
static TextConsole *new_console(DisplayState *ds, int text)
1109
{
1110
    TextConsole *s;
1111
    int i;
1112

    
1113
    if (nb_consoles >= MAX_CONSOLES)
1114
        return NULL;
1115
    s = qemu_mallocz(sizeof(TextConsole));
1116
    if (!s) {
1117
        return NULL;
1118
    }
1119
    if (!active_console || (active_console->text_console && !text))
1120
        active_console = s;
1121
    s->ds = ds;
1122
    s->text_console = text;
1123
    if (text) {
1124
        consoles[nb_consoles++] = s;
1125
    } else {
1126
        /* HACK: Put graphical consoles before text consoles.  */
1127
        for (i = nb_consoles; i > 0; i--) {
1128
            if (!consoles[i - 1]->text_console)
1129
                break;
1130
            consoles[i] = consoles[i - 1];
1131
        }
1132
        consoles[i] = s;
1133
    }
1134
    return s;
1135
}
1136

    
1137
TextConsole *graphic_console_init(DisplayState *ds, vga_hw_update_ptr update,
1138
                                  vga_hw_invalidate_ptr invalidate,
1139
                                  vga_hw_screen_dump_ptr screen_dump,
1140
                                  void *opaque)
1141
{
1142
    TextConsole *s;
1143

    
1144
    s = new_console(ds, 0);
1145
    if (!s)
1146
      return NULL;
1147
    s->hw_update = update;
1148
    s->hw_invalidate = invalidate;
1149
    s->hw_screen_dump = screen_dump;
1150
    s->hw = opaque;
1151
    return s;
1152
}
1153

    
1154
int is_graphic_console(void)
1155
{
1156
    return !active_console->text_console;
1157
}
1158

    
1159
CharDriverState *text_console_init(DisplayState *ds)
1160
{
1161
    CharDriverState *chr;
1162
    TextConsole *s;
1163
    int i,j;
1164
    static int color_inited;
1165

    
1166
    chr = qemu_mallocz(sizeof(CharDriverState));
1167
    if (!chr)
1168
        return NULL;
1169
    s = new_console(ds, 1);
1170
    if (!s) {
1171
        free(chr);
1172
        return NULL;
1173
    }
1174
    chr->opaque = s;
1175
    chr->chr_write = console_puts;
1176
    chr->chr_send_event = console_send_event;
1177

    
1178
    s->chr = chr;
1179
    s->out_fifo.buf = s->out_fifo_buf;
1180
    s->out_fifo.buf_size = sizeof(s->out_fifo_buf);
1181
    s->kbd_timer = qemu_new_timer(rt_clock, kbd_send_chars, s);
1182
    
1183
    if (!color_inited) {
1184
        color_inited = 1;
1185
        for(j = 0; j < 2; j++) {
1186
            for(i = 0; i < 8; i++) {
1187
                color_table[j][i] = col_expand(s->ds, 
1188
                        vga_get_color(s->ds, color_table_rgb[j][i]));
1189
            }
1190
        }
1191
    }
1192
    s->y_displayed = 0;
1193
    s->y_base = 0;
1194
    s->total_height = DEFAULT_BACKSCROLL;
1195
    s->x = 0;
1196
    s->y = 0;
1197
    s->g_width = s->ds->width;
1198
    s->g_height = s->ds->height;
1199

    
1200
    /* Set text attribute defaults */
1201
    s->t_attrib_default.bold = 0;
1202
    s->t_attrib_default.uline = 0;
1203
    s->t_attrib_default.blink = 0;
1204
    s->t_attrib_default.invers = 0;
1205
    s->t_attrib_default.unvisible = 0;
1206
    s->t_attrib_default.fgcol = COLOR_WHITE;
1207
    s->t_attrib_default.bgcol = COLOR_BLACK;
1208

    
1209
    /* set current text attributes to default */
1210
    s->t_attrib = s->t_attrib_default;
1211
    text_console_resize(s);
1212

    
1213
    qemu_chr_reset(chr);
1214

    
1215
    return chr;
1216
}