Statistics
| Branch: | Revision:

root / console.c @ 6d6f7c28

History | View | Annotate | Download (25.7 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 RGBA(r, g, b, a) (((a) << 24) | ((r) << 16) | ((g) << 8) | (b))
31
#define RGB(r, g, b) 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

    
57
struct TextConsole {
58
    int text_console; /* true if text console */
59
    DisplayState *ds;
60
    int g_width, g_height;
61
    int width;
62
    int height;
63
    int total_height;
64
    int backscroll_height;
65
    int x, y;
66
    int y_displayed;
67
    int y_base;
68
    TextAttributes t_attrib_default; /* default text attributes */
69
    TextAttributes t_attrib; /* currently active text attributes */
70
    TextCell *cells;
71

    
72
    enum TTYState state;
73
    int esc_params[MAX_ESC_PARAMS];
74
    int nb_esc_params;
75

    
76
    /* kbd read handler */
77
    IOReadHandler *fd_read;
78
    void *fd_opaque;
79
};
80

    
81
static TextConsole *active_console;
82
static TextConsole *consoles[MAX_CONSOLES];
83
static int nb_consoles = 0;
84

    
85
/* convert a RGBA color to a color index usable in graphic primitives */
86
static unsigned int vga_get_color(DisplayState *ds, unsigned int rgba)
87
{
88
    unsigned int r, g, b, color;
89

    
90
    switch(ds->depth) {
91
#if 0
92
    case 8:
93
        r = (rgba >> 16) & 0xff;
94
        g = (rgba >> 8) & 0xff;
95
        b = (rgba) & 0xff;
96
        color = (rgb_to_index[r] * 6 * 6) + 
97
            (rgb_to_index[g] * 6) + 
98
            (rgb_to_index[b]);
99
        break;
100
#endif
101
    case 15:
102
        r = (rgba >> 16) & 0xff;
103
        g = (rgba >> 8) & 0xff;
104
        b = (rgba) & 0xff;
105
        color = ((r >> 3) << 10) | ((g >> 3) << 5) | (b >> 3);
106
        break;
107
    case 16:
108
        r = (rgba >> 16) & 0xff;
109
        g = (rgba >> 8) & 0xff;
110
        b = (rgba) & 0xff;
111
        color = ((r >> 3) << 11) | ((g >> 2) << 5) | (b >> 3);
112
        break;
113
    case 32:
114
    default:
115
        color = rgba;
116
        break;
117
    }
118
    return color;
119
}
120

    
121
static void vga_fill_rect (DisplayState *ds, 
122
                           int posx, int posy, int width, int height, uint32_t color)
123
{
124
    uint8_t *d, *d1;
125
    int x, y, bpp;
126
    
127
    bpp = (ds->depth + 7) >> 3;
128
    d1 = ds->data + 
129
        ds->linesize * posy + bpp * posx;
130
    for (y = 0; y < height; y++) {
131
        d = d1;
132
        switch(bpp) {
133
        case 1:
134
            for (x = 0; x < width; x++) {
135
                *((uint8_t *)d) = color;
136
                d++;
137
            }
138
            break;
139
        case 2:
140
            for (x = 0; x < width; x++) {
141
                *((uint16_t *)d) = color;
142
                d += 2;
143
            }
144
            break;
145
        case 4:
146
            for (x = 0; x < width; x++) {
147
                *((uint32_t *)d) = color;
148
                d += 4;
149
            }
150
            break;
151
        }
152
        d1 += ds->linesize;
153
    }
154
}
155

    
156
/* copy from (xs, ys) to (xd, yd) a rectangle of size (w, h) */
157
static void vga_bitblt(DisplayState *ds, int xs, int ys, int xd, int yd, int w, int h)
158
{
159
    const uint8_t *s;
160
    uint8_t *d;
161
    int wb, y, bpp;
162

    
163
    bpp = (ds->depth + 7) >> 3;
164
    wb = w * bpp;
165
    if (yd <= ys) {
166
        s = ds->data + 
167
            ds->linesize * ys + bpp * xs;
168
        d = ds->data + 
169
            ds->linesize * yd + bpp * xd;
170
        for (y = 0; y < h; y++) {
171
            memmove(d, s, wb);
172
            d += ds->linesize;
173
            s += ds->linesize;
174
        }
175
    } else {
176
        s = ds->data + 
177
            ds->linesize * (ys + h - 1) + bpp * xs;
178
        d = ds->data + 
179
            ds->linesize * (yd + h - 1) + bpp * xd;
180
       for (y = 0; y < h; y++) {
181
            memmove(d, s, wb);
182
            d -= ds->linesize;
183
            s -= ds->linesize;
184
        }
185
    }
186
}
187

    
188
/***********************************************************/
189
/* basic char display */
190

    
191
#define FONT_HEIGHT 16
192
#define FONT_WIDTH 8
193

    
194
#include "vgafont.h"
195

    
196
#define cbswap_32(__x) \
197
((uint32_t)( \
198
                (((uint32_t)(__x) & (uint32_t)0x000000ffUL) << 24) | \
199
                (((uint32_t)(__x) & (uint32_t)0x0000ff00UL) <<  8) | \
200
                (((uint32_t)(__x) & (uint32_t)0x00ff0000UL) >>  8) | \
201
                (((uint32_t)(__x) & (uint32_t)0xff000000UL) >> 24) ))
202

    
203
#ifdef WORDS_BIGENDIAN
204
#define PAT(x) x
205
#else
206
#define PAT(x) cbswap_32(x)
207
#endif
208

    
209
static const uint32_t dmask16[16] = {
210
    PAT(0x00000000),
211
    PAT(0x000000ff),
212
    PAT(0x0000ff00),
213
    PAT(0x0000ffff),
214
    PAT(0x00ff0000),
215
    PAT(0x00ff00ff),
216
    PAT(0x00ffff00),
217
    PAT(0x00ffffff),
218
    PAT(0xff000000),
219
    PAT(0xff0000ff),
220
    PAT(0xff00ff00),
221
    PAT(0xff00ffff),
222
    PAT(0xffff0000),
223
    PAT(0xffff00ff),
224
    PAT(0xffffff00),
225
    PAT(0xffffffff),
226
};
227

    
228
static const uint32_t dmask4[4] = {
229
    PAT(0x00000000),
230
    PAT(0x0000ffff),
231
    PAT(0xffff0000),
232
    PAT(0xffffffff),
233
};
234

    
235
static uint32_t color_table[2][8];
236

    
237
enum color_names {
238
    COLOR_BLACK   = 0,
239
    COLOR_RED     = 1,
240
    COLOR_GREEN   = 2,
241
    COLOR_YELLOW  = 3,
242
    COLOR_BLUE    = 4,
243
    COLOR_MAGENTA = 5,
244
    COLOR_CYAN    = 6,
245
    COLOR_WHITE   = 7
246
};
247

    
248
static const uint32_t color_table_rgb[2][8] = {
249
    {   /* dark */
250
        RGB(0x00, 0x00, 0x00),  /* black */
251
        RGB(0xaa, 0x00, 0x00),  /* red */
252
        RGB(0x00, 0xaa, 0x00),  /* green */
253
        RGB(0xaa, 0xaa, 0x00),  /* yellow */
254
        RGB(0x00, 0x00, 0xaa),  /* blue */
255
        RGB(0xaa, 0x00, 0xaa),  /* magenta */
256
        RGB(0x00, 0xaa, 0xaa),  /* cyan */
257
        RGB(0xaa, 0xaa, 0xaa),  /* white */
258
    },
259
    {   /* bright */
260
        RGB(0x00, 0x00, 0x00),  /* black */
261
        RGB(0xff, 0x00, 0x00),  /* red */
262
        RGB(0x00, 0xff, 0x00),  /* green */
263
        RGB(0xff, 0xff, 0x00),  /* yellow */
264
        RGB(0x00, 0x00, 0xff),  /* blue */
265
        RGB(0xff, 0x00, 0xff),  /* magenta */
266
        RGB(0x00, 0xff, 0xff),  /* cyan */
267
        RGB(0xff, 0xff, 0xff),  /* white */
268
    }
269
};
270

    
271
static inline unsigned int col_expand(DisplayState *ds, unsigned int col)
272
{
273
    switch(ds->depth) {
274
    case 8:
275
        col |= col << 8;
276
        col |= col << 16;
277
        break;
278
    case 15:
279
    case 16:
280
        col |= col << 16;
281
        break;
282
    default:
283
        break;
284
    }
285

    
286
    return col;
287
}
288
#ifdef DEBUG_CONSOLE
289
static void console_print_text_attributes(TextAttributes *t_attrib, char ch)
290
{
291
    if (t_attrib->bold) {
292
        printf("b");
293
    } else {
294
        printf(" ");
295
    }
296
    if (t_attrib->uline) {
297
        printf("u");
298
    } else {
299
        printf(" ");
300
    }
301
    if (t_attrib->blink) {
302
        printf("l");
303
    } else {
304
        printf(" ");
305
    }
306
    if (t_attrib->invers) {
307
        printf("i");
308
    } else {
309
        printf(" ");
310
    }
311
    if (t_attrib->unvisible) {
312
        printf("n");
313
    } else {
314
        printf(" ");
315
    }
316

    
317
    printf(" fg: %d bg: %d ch:'%2X' '%c'\n", t_attrib->fgcol, t_attrib->bgcol, ch, ch);
318
}
319
#endif
320

    
321
static void vga_putcharxy(DisplayState *ds, int x, int y, int ch, 
322
                          TextAttributes *t_attrib)
323
{
324
    uint8_t *d;
325
    const uint8_t *font_ptr;
326
    unsigned int font_data, linesize, xorcol, bpp;
327
    int i;
328
    unsigned int fgcol, bgcol;
329

    
330
#ifdef DEBUG_CONSOLE
331
    printf("x: %2i y: %2i", x, y);
332
    console_print_text_attributes(t_attrib, ch);
333
#endif
334

    
335
    if (t_attrib->invers) {
336
        bgcol = color_table[t_attrib->bold][t_attrib->fgcol];
337
        fgcol = color_table[t_attrib->bold][t_attrib->bgcol];
338
    } else {
339
        fgcol = color_table[t_attrib->bold][t_attrib->fgcol];
340
        bgcol = color_table[t_attrib->bold][t_attrib->bgcol];
341
    }
342

    
343
    bpp = (ds->depth + 7) >> 3;
344
    d = ds->data + 
345
        ds->linesize * y * FONT_HEIGHT + bpp * x * FONT_WIDTH;
346
    linesize = ds->linesize;
347
    font_ptr = vgafont16 + FONT_HEIGHT * ch;
348
    xorcol = bgcol ^ fgcol;
349
    switch(ds->depth) {
350
    case 8:
351
        for(i = 0; i < FONT_HEIGHT; i++) {
352
            font_data = *font_ptr++;
353
            if (t_attrib->uline
354
                && ((i == FONT_HEIGHT - 2) || (i == FONT_HEIGHT - 3))) {
355
                font_data = 0xFFFF;
356
            }
357
            ((uint32_t *)d)[0] = (dmask16[(font_data >> 4)] & xorcol) ^ bgcol;
358
            ((uint32_t *)d)[1] = (dmask16[(font_data >> 0) & 0xf] & xorcol) ^ bgcol;
359
            d += linesize;
360
        }
361
        break;
362
    case 16:
363
    case 15:
364
        for(i = 0; i < FONT_HEIGHT; i++) {
365
            font_data = *font_ptr++;
366
            if (t_attrib->uline
367
                && ((i == FONT_HEIGHT - 2) || (i == FONT_HEIGHT - 3))) {
368
                font_data = 0xFFFF;
369
            }
370
            ((uint32_t *)d)[0] = (dmask4[(font_data >> 6)] & xorcol) ^ bgcol;
371
            ((uint32_t *)d)[1] = (dmask4[(font_data >> 4) & 3] & xorcol) ^ bgcol;
372
            ((uint32_t *)d)[2] = (dmask4[(font_data >> 2) & 3] & xorcol) ^ bgcol;
373
            ((uint32_t *)d)[3] = (dmask4[(font_data >> 0) & 3] & xorcol) ^ bgcol;
374
            d += linesize;
375
        }
376
        break;
377
    case 32:
378
        for(i = 0; i < FONT_HEIGHT; i++) {
379
            font_data = *font_ptr++;
380
            if (t_attrib->uline && ((i == FONT_HEIGHT - 2) || (i == FONT_HEIGHT - 3))) {
381
                font_data = 0xFFFF;
382
            }
383
            ((uint32_t *)d)[0] = (-((font_data >> 7)) & xorcol) ^ bgcol;
384
            ((uint32_t *)d)[1] = (-((font_data >> 6) & 1) & xorcol) ^ bgcol;
385
            ((uint32_t *)d)[2] = (-((font_data >> 5) & 1) & xorcol) ^ bgcol;
386
            ((uint32_t *)d)[3] = (-((font_data >> 4) & 1) & xorcol) ^ bgcol;
387
            ((uint32_t *)d)[4] = (-((font_data >> 3) & 1) & xorcol) ^ bgcol;
388
            ((uint32_t *)d)[5] = (-((font_data >> 2) & 1) & xorcol) ^ bgcol;
389
            ((uint32_t *)d)[6] = (-((font_data >> 1) & 1) & xorcol) ^ bgcol;
390
            ((uint32_t *)d)[7] = (-((font_data >> 0) & 1) & xorcol) ^ bgcol;
391
            d += linesize;
392
        }
393
        break;
394
    }
395
}
396

    
397
static void text_console_resize(TextConsole *s)
398
{
399
    TextCell *cells, *c, *c1;
400
    int w1, x, y, last_width;
401

    
402
    last_width = s->width;
403
    s->width = s->g_width / FONT_WIDTH;
404
    s->height = s->g_height / FONT_HEIGHT;
405

    
406
    w1 = last_width;
407
    if (s->width < w1)
408
        w1 = s->width;
409

    
410
    cells = qemu_malloc(s->width * s->total_height * sizeof(TextCell));
411
    for(y = 0; y < s->total_height; y++) {
412
        c = &cells[y * s->width];
413
        if (w1 > 0) {
414
            c1 = &s->cells[y * last_width];
415
            for(x = 0; x < w1; x++) {
416
                *c++ = *c1++;
417
            }
418
        }
419
        for(x = w1; x < s->width; x++) {
420
            c->ch = ' ';
421
            c->t_attrib = s->t_attrib_default;
422
            c++;
423
        }
424
    }
425
    free(s->cells);
426
    s->cells = cells;
427
}
428

    
429
static void update_xy(TextConsole *s, int x, int y)
430
{
431
    TextCell *c;
432
    int y1, y2;
433

    
434
    if (s == active_console) {
435
        y1 = (s->y_base + y) % s->total_height;
436
        y2 = y1 - s->y_displayed;
437
        if (y2 < 0)
438
            y2 += s->total_height;
439
        if (y2 < s->height) {
440
            c = &s->cells[y1 * s->width + x];
441
            vga_putcharxy(s->ds, x, y2, c->ch, 
442
                          &(c->t_attrib));
443
            dpy_update(s->ds, x * FONT_WIDTH, y2 * FONT_HEIGHT, 
444
                       FONT_WIDTH, FONT_HEIGHT);
445
        }
446
    }
447
}
448

    
449
static void console_show_cursor(TextConsole *s, int show)
450
{
451
    TextCell *c;
452
    int y, y1;
453

    
454
    if (s == active_console) {
455
        y1 = (s->y_base + s->y) % s->total_height;
456
        y = y1 - s->y_displayed;
457
        if (y < 0)
458
            y += s->total_height;
459
        if (y < s->height) {
460
            c = &s->cells[y1 * s->width + s->x];
461
            if (show) {
462
                TextAttributes t_attrib = s->t_attrib_default;
463
                t_attrib.invers = !(t_attrib.invers); /* invert fg and bg */
464
                vga_putcharxy(s->ds, s->x, y, c->ch, &t_attrib);
465
            } else {
466
                vga_putcharxy(s->ds, s->x, y, c->ch, 
467
                              &(c->t_attrib));
468
            }
469
            dpy_update(s->ds, s->x * FONT_WIDTH, y * FONT_HEIGHT, 
470
                       FONT_WIDTH, FONT_HEIGHT);
471
        }
472
    }
473
}
474

    
475
static void console_refresh(TextConsole *s)
476
{
477
    TextCell *c;
478
    int x, y, y1;
479

    
480
    if (s != active_console) 
481
        return;
482

    
483
    vga_fill_rect(s->ds, 0, 0, s->ds->width, s->ds->height,
484
                  color_table[0][COLOR_BLACK]);
485
    y1 = s->y_displayed;
486
    for(y = 0; y < s->height; y++) {
487
        c = s->cells + y1 * s->width;
488
        for(x = 0; x < s->width; x++) {
489
            vga_putcharxy(s->ds, x, y, c->ch, 
490
                          &(c->t_attrib));
491
            c++;
492
        }
493
        if (++y1 == s->total_height)
494
            y1 = 0;
495
    }
496
    dpy_update(s->ds, 0, 0, s->ds->width, s->ds->height);
497
    console_show_cursor(s, 1);
498
}
499

    
500
static void console_scroll(int ydelta)
501
{
502
    TextConsole *s;
503
    int i, y1;
504
    
505
    s = active_console;
506
    if (!s || !s->text_console)
507
        return;
508

    
509
    if (ydelta > 0) {
510
        for(i = 0; i < ydelta; i++) {
511
            if (s->y_displayed == s->y_base)
512
                break;
513
            if (++s->y_displayed == s->total_height)
514
                s->y_displayed = 0;
515
        }
516
    } else {
517
        ydelta = -ydelta;
518
        i = s->backscroll_height;
519
        if (i > s->total_height - s->height)
520
            i = s->total_height - s->height;
521
        y1 = s->y_base - i;
522
        if (y1 < 0)
523
            y1 += s->total_height;
524
        for(i = 0; i < ydelta; i++) {
525
            if (s->y_displayed == y1)
526
                break;
527
            if (--s->y_displayed < 0)
528
                s->y_displayed = s->total_height - 1;
529
        }
530
    }
531
    console_refresh(s);
532
}
533

    
534
static void console_put_lf(TextConsole *s)
535
{
536
    TextCell *c;
537
    int x, y1;
538

    
539
    s->x = 0;
540
    s->y++;
541
    if (s->y >= s->height) {
542
        s->y = s->height - 1;
543

    
544
        if (s->y_displayed == s->y_base) {
545
            if (++s->y_displayed == s->total_height)
546
                s->y_displayed = 0;
547
        }
548
        if (++s->y_base == s->total_height)
549
            s->y_base = 0;
550
        if (s->backscroll_height < s->total_height)
551
            s->backscroll_height++;
552
        y1 = (s->y_base + s->height - 1) % s->total_height;
553
        c = &s->cells[y1 * s->width];
554
        for(x = 0; x < s->width; x++) {
555
            c->ch = ' ';
556
            c->t_attrib = s->t_attrib_default;
557
            c++;
558
        }
559
        if (s == active_console && s->y_displayed == s->y_base) {
560
            vga_bitblt(s->ds, 0, FONT_HEIGHT, 0, 0, 
561
                       s->width * FONT_WIDTH, 
562
                       (s->height - 1) * FONT_HEIGHT);
563
            vga_fill_rect(s->ds, 0, (s->height - 1) * FONT_HEIGHT,
564
                          s->width * FONT_WIDTH, FONT_HEIGHT, 
565
                          color_table[0][s->t_attrib_default.bgcol]);
566
            dpy_update(s->ds, 0, 0, 
567
                       s->width * FONT_WIDTH, s->height * FONT_HEIGHT);
568
        }
569
    }
570
}
571

    
572
/* Set console attributes depending on the current escape codes.
573
 * NOTE: I know this code is not very efficient (checking every color for it
574
 * self) but it is more readable and better maintainable.
575
 */
576
static void console_handle_escape(TextConsole *s)
577
{
578
    int i;
579

    
580
    if (s->nb_esc_params == 0) { /* ESC[m sets all attributes to default */
581
        s->t_attrib = s->t_attrib_default;
582
        return;
583
    }
584
    for (i=0; i<s->nb_esc_params; i++) {
585
        switch (s->esc_params[i]) {
586
            case 0: /* reset all console attributes to default */
587
                s->t_attrib = s->t_attrib_default;
588
                break;
589
            case 1:
590
                s->t_attrib.bold = 1;
591
                break;
592
            case 4:
593
                s->t_attrib.uline = 1;
594
                break;
595
            case 5:
596
                s->t_attrib.blink = 1;
597
                break;
598
            case 7:
599
                s->t_attrib.invers = 1;
600
                break;
601
            case 8:
602
                s->t_attrib.unvisible = 1;
603
                break;
604
            case 22:
605
                s->t_attrib.bold = 0;
606
                break;
607
            case 24:
608
                s->t_attrib.uline = 0;
609
                break;
610
            case 25:
611
                s->t_attrib.blink = 0;
612
                break;
613
            case 27:
614
                s->t_attrib.invers = 0;
615
                break;
616
            case 28:
617
                s->t_attrib.unvisible = 0;
618
                break;
619
            /* set foreground color */
620
            case 30:
621
                s->t_attrib.fgcol=COLOR_BLACK;
622
                break;
623
            case 31:
624
                s->t_attrib.fgcol=COLOR_RED;
625
                break;
626
            case 32:
627
                s->t_attrib.fgcol=COLOR_GREEN;
628
                break;
629
            case 33:
630
                s->t_attrib.fgcol=COLOR_YELLOW;
631
                break;
632
            case 34:
633
                s->t_attrib.fgcol=COLOR_BLUE;
634
                break;
635
            case 35:
636
                s->t_attrib.fgcol=COLOR_MAGENTA;
637
                break;
638
            case 36:
639
                s->t_attrib.fgcol=COLOR_CYAN;
640
                break;
641
            case 37:
642
                s->t_attrib.fgcol=COLOR_WHITE;
643
                break;
644
            /* set background color */
645
            case 40:
646
                s->t_attrib.bgcol=COLOR_BLACK;
647
                break;
648
            case 41:
649
                s->t_attrib.bgcol=COLOR_RED;
650
                break;
651
            case 42:
652
                s->t_attrib.bgcol=COLOR_GREEN;
653
                break;
654
            case 43:
655
                s->t_attrib.bgcol=COLOR_YELLOW;
656
                break;
657
            case 44:
658
                s->t_attrib.bgcol=COLOR_BLUE;
659
                break;
660
            case 45:
661
                s->t_attrib.bgcol=COLOR_MAGENTA;
662
                break;
663
            case 46:
664
                s->t_attrib.bgcol=COLOR_CYAN;
665
                break;
666
            case 47:
667
                s->t_attrib.bgcol=COLOR_WHITE;
668
                break;
669
        }
670
    }
671
}
672

    
673
static void console_putchar(TextConsole *s, int ch)
674
{
675
    TextCell *c;
676
    int y1, i, x;
677

    
678
    switch(s->state) {
679
    case TTY_STATE_NORM:
680
        switch(ch) {
681
        case '\r':  /* carriage return */
682
            s->x = 0;
683
            break;
684
        case '\n':  /* newline */
685
            console_put_lf(s);
686
            break;
687
        case '\b':  /* backspace */
688
            if(s->x > 0) s->x--;
689
            y1 = (s->y_base + s->y) % s->total_height;
690
            c = &s->cells[y1 * s->width + s->x];
691
            c->ch = ' ';
692
            c->t_attrib = s->t_attrib;
693
            update_xy(s, s->x, s->y);
694
            break;
695
        case '\t':  /* tabspace */
696
            if (s->x + (8 - (s->x % 8)) > s->width) {
697
                console_put_lf(s);
698
            } else {
699
                s->x = s->x + (8 - (s->x % 8));
700
            }
701
            break;
702
        case '\a':  /* alert aka. bell */
703
            /* TODO: has to be implemented */
704
            break;
705
        case 27:    /* esc (introducing an escape sequence) */
706
            s->state = TTY_STATE_ESC;
707
            break;
708
        default:
709
            y1 = (s->y_base + s->y) % s->total_height;
710
            c = &s->cells[y1 * s->width + s->x];
711
            c->ch = ch;
712
            c->t_attrib = s->t_attrib;
713
            update_xy(s, s->x, s->y);
714
            s->x++;
715
            if (s->x >= s->width)
716
                console_put_lf(s);
717
            break;
718
        }
719
        break;
720
    case TTY_STATE_ESC: /* check if it is a terminal escape sequence */
721
        if (ch == '[') {
722
            for(i=0;i<MAX_ESC_PARAMS;i++)
723
                s->esc_params[i] = 0;
724
            s->nb_esc_params = 0;
725
            s->state = TTY_STATE_CSI;
726
        } else {
727
            s->state = TTY_STATE_NORM;
728
        }
729
        break;
730
    case TTY_STATE_CSI: /* handle escape sequence parameters */
731
        if (ch >= '0' && ch <= '9') {
732
            if (s->nb_esc_params < MAX_ESC_PARAMS) {
733
                s->esc_params[s->nb_esc_params] = 
734
                    s->esc_params[s->nb_esc_params] * 10 + ch - '0';
735
            }
736
        } else {
737
            s->nb_esc_params++;
738
            if (ch == ';')
739
                break;
740
            s->state = TTY_STATE_NORM;
741
            switch(ch) {
742
            case 'D':
743
                if (s->x > 0)
744
                    s->x--;
745
                break;
746
            case 'C':
747
                if (s->x < (s->width - 1))
748
                    s->x++;
749
                break;
750
            case 'K':
751
                /* clear to eol */
752
                y1 = (s->y_base + s->y) % s->total_height;
753
                for(x = s->x; x < s->width; x++) {
754
                    c = &s->cells[y1 * s->width + x];
755
                    c->ch = ' ';
756
                    c->t_attrib = s->t_attrib_default;
757
                    c++;
758
                    update_xy(s, x, s->y);
759
                }
760
                break;
761
            default:
762
                break;
763
            }
764
            console_handle_escape(s);
765
            break;
766
        }
767
    }
768
}
769

    
770
void console_select(unsigned int index)
771
{
772
    TextConsole *s;
773

    
774
    if (index >= MAX_CONSOLES)
775
        return;
776
    s = consoles[index];
777
    if (s) {
778
        active_console = s;
779
        if (s->text_console) {
780
            if (s->g_width != s->ds->width ||
781
                s->g_height != s->ds->height) {
782
                s->g_width = s->ds->width;
783
                s->g_height = s->ds->height;
784
                text_console_resize(s);
785
        }
786
            console_refresh(s);
787
        }
788
    }
789
}
790

    
791
static int console_puts(CharDriverState *chr, const uint8_t *buf, int len)
792
{
793
    TextConsole *s = chr->opaque;
794
    int i;
795

    
796
    console_show_cursor(s, 0);
797
    for(i = 0; i < len; i++) {
798
        console_putchar(s, buf[i]);
799
    }
800
    console_show_cursor(s, 1);
801
    return len;
802
}
803

    
804
static void console_chr_add_read_handler(CharDriverState *chr, 
805
                                         IOCanRWHandler *fd_can_read, 
806
                                         IOReadHandler *fd_read, void *opaque)
807
{
808
    TextConsole *s = chr->opaque;
809
    s->fd_read = fd_read;
810
    s->fd_opaque = opaque;
811
}
812

    
813
static void console_send_event(CharDriverState *chr, int event)
814
{
815
    TextConsole *s = chr->opaque;
816
    int i;
817

    
818
    if (event == CHR_EVENT_FOCUS) {
819
        for(i = 0; i < nb_consoles; i++) {
820
            if (consoles[i] == s) {
821
                console_select(i);
822
                break;
823
            }
824
        }
825
    }
826
}
827

    
828
/* called when an ascii key is pressed */
829
void kbd_put_keysym(int keysym)
830
{
831
    TextConsole *s;
832
    uint8_t buf[16], *q;
833
    int c;
834

    
835
    s = active_console;
836
    if (!s || !s->text_console)
837
        return;
838

    
839
    switch(keysym) {
840
    case QEMU_KEY_CTRL_UP:
841
        console_scroll(-1);
842
        break;
843
    case QEMU_KEY_CTRL_DOWN:
844
        console_scroll(1);
845
        break;
846
    case QEMU_KEY_CTRL_PAGEUP:
847
        console_scroll(-10);
848
        break;
849
    case QEMU_KEY_CTRL_PAGEDOWN:
850
        console_scroll(10);
851
        break;
852
    default:
853
        if (s->fd_read) {
854
            /* convert the QEMU keysym to VT100 key string */
855
            q = buf;
856
            if (keysym >= 0xe100 && keysym <= 0xe11f) {
857
                *q++ = '\033';
858
                *q++ = '[';
859
                c = keysym - 0xe100;
860
                if (c >= 10)
861
                    *q++ = '0' + (c / 10);
862
                *q++ = '0' + (c % 10);
863
                *q++ = '~';
864
            } else if (keysym >= 0xe120 && keysym <= 0xe17f) {
865
                *q++ = '\033';
866
                *q++ = '[';
867
                *q++ = keysym & 0xff;
868
            } else {
869
                *q++ = keysym;
870
            }
871
            s->fd_read(s->fd_opaque, buf, q - buf);
872
        }
873
        break;
874
    }
875
}
876

    
877
TextConsole *graphic_console_init(DisplayState *ds)
878
{
879
    TextConsole *s;
880

    
881
    if (nb_consoles >= MAX_CONSOLES)
882
        return NULL;
883
    s = qemu_mallocz(sizeof(TextConsole));
884
    if (!s) {
885
        return NULL;
886
    }
887
    if (!active_console)
888
        active_console = s;
889
    s->ds = ds;
890
    consoles[nb_consoles++] = s;
891
    return s;
892
}
893

    
894
int is_active_console(TextConsole *s)
895
{
896
    return s == active_console;
897
}
898

    
899
CharDriverState *text_console_init(DisplayState *ds)
900
{
901
    CharDriverState *chr;
902
    TextConsole *s;
903
    int i,j;
904
    static int color_inited;
905

    
906
    chr = qemu_mallocz(sizeof(CharDriverState));
907
    if (!chr)
908
        return NULL;
909
    s = graphic_console_init(ds);
910
    if (!s) {
911
        free(chr);
912
        return NULL;
913
    }
914
    s->text_console = 1;
915
    chr->opaque = s;
916
    chr->chr_write = console_puts;
917
    chr->chr_add_read_handler = console_chr_add_read_handler;
918
    chr->chr_send_event = console_send_event;
919

    
920
    if (!color_inited) {
921
        color_inited = 1;
922
        for(j = 0; j < 2; j++) {
923
            for(i = 0; i < 8; i++) {
924
                color_table[j][i] = col_expand(s->ds, 
925
                        vga_get_color(s->ds, color_table_rgb[j][i]));
926
            }
927
        }
928
    }
929
    s->y_displayed = 0;
930
    s->y_base = 0;
931
    s->total_height = DEFAULT_BACKSCROLL;
932
    s->x = 0;
933
    s->y = 0;
934
    s->g_width = s->ds->width;
935
    s->g_height = s->ds->height;
936

    
937
    /* Set text attribute defaults */
938
    s->t_attrib_default.bold = 0;
939
    s->t_attrib_default.uline = 0;
940
    s->t_attrib_default.blink = 0;
941
    s->t_attrib_default.invers = 0;
942
    s->t_attrib_default.unvisible = 0;
943
    s->t_attrib_default.fgcol = COLOR_WHITE;
944
    s->t_attrib_default.bgcol = COLOR_BLACK;
945

    
946
    /* set current text attributes to default */
947
    s->t_attrib = s->t_attrib_default;
948
    text_console_resize(s);
949

    
950
    return chr;
951
}