Statistics
| Branch: | Revision:

root / console.c @ 67f36560

History | View | Annotate | Download (27.4 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
/* ??? This is mis-named.
57
   It is used for both text and graphical consoles.  */
58
struct TextConsole {
59
    int text_console; /* true if text console */
60
    DisplayState *ds;
61
    /* Graphic console state.  */
62
    vga_hw_update_ptr hw_update;
63
    vga_hw_invalidate_ptr hw_invalidate;
64
    vga_hw_screen_dump_ptr hw_screen_dump;
65
    void *hw;
66

    
67
    int g_width, g_height;
68
    int width;
69
    int height;
70
    int total_height;
71
    int backscroll_height;
72
    int x, y;
73
    int y_displayed;
74
    int y_base;
75
    TextAttributes t_attrib_default; /* default text attributes */
76
    TextAttributes t_attrib; /* currently active text attributes */
77
    TextCell *cells;
78

    
79
    enum TTYState state;
80
    int esc_params[MAX_ESC_PARAMS];
81
    int nb_esc_params;
82

    
83
    /* kbd read handler */
84
    IOReadHandler *fd_read;
85
    void *fd_opaque;
86
};
87

    
88
static TextConsole *active_console;
89
static TextConsole *consoles[MAX_CONSOLES];
90
static int nb_consoles = 0;
91

    
92
void vga_hw_update(void)
93
{
94
    if (active_console->hw_update)
95
        active_console->hw_update(active_console->hw);
96
}
97

    
98
void vga_hw_invalidate(void)
99
{
100
    if (active_console->hw_invalidate)
101
        active_console->hw_invalidate(active_console->hw);
102
}
103

    
104
void vga_hw_screen_dump(const char *filename)
105
{
106
    /* There is currently no was of specifying which screen we want to dump,
107
       so always dump the dirst one.  */
108
    if (consoles[0]->hw_screen_dump)
109
        consoles[0]->hw_screen_dump(consoles[0]->hw, filename);
110
}
111

    
112
/* convert a RGBA color to a color index usable in graphic primitives */
113
static unsigned int vga_get_color(DisplayState *ds, unsigned int rgba)
114
{
115
    unsigned int r, g, b, color;
116

    
117
    switch(ds->depth) {
118
#if 0
119
    case 8:
120
        r = (rgba >> 16) & 0xff;
121
        g = (rgba >> 8) & 0xff;
122
        b = (rgba) & 0xff;
123
        color = (rgb_to_index[r] * 6 * 6) + 
124
            (rgb_to_index[g] * 6) + 
125
            (rgb_to_index[b]);
126
        break;
127
#endif
128
    case 15:
129
        r = (rgba >> 16) & 0xff;
130
        g = (rgba >> 8) & 0xff;
131
        b = (rgba) & 0xff;
132
        color = ((r >> 3) << 10) | ((g >> 3) << 5) | (b >> 3);
133
        break;
134
    case 16:
135
        r = (rgba >> 16) & 0xff;
136
        g = (rgba >> 8) & 0xff;
137
        b = (rgba) & 0xff;
138
        color = ((r >> 3) << 11) | ((g >> 2) << 5) | (b >> 3);
139
        break;
140
    case 32:
141
    default:
142
        color = rgba;
143
        break;
144
    }
145
    return color;
146
}
147

    
148
static void vga_fill_rect (DisplayState *ds, 
149
                           int posx, int posy, int width, int height, uint32_t color)
150
{
151
    uint8_t *d, *d1;
152
    int x, y, bpp;
153
    
154
    bpp = (ds->depth + 7) >> 3;
155
    d1 = ds->data + 
156
        ds->linesize * posy + bpp * posx;
157
    for (y = 0; y < height; y++) {
158
        d = d1;
159
        switch(bpp) {
160
        case 1:
161
            for (x = 0; x < width; x++) {
162
                *((uint8_t *)d) = color;
163
                d++;
164
            }
165
            break;
166
        case 2:
167
            for (x = 0; x < width; x++) {
168
                *((uint16_t *)d) = color;
169
                d += 2;
170
            }
171
            break;
172
        case 4:
173
            for (x = 0; x < width; x++) {
174
                *((uint32_t *)d) = color;
175
                d += 4;
176
            }
177
            break;
178
        }
179
        d1 += ds->linesize;
180
    }
181
}
182

    
183
/* copy from (xs, ys) to (xd, yd) a rectangle of size (w, h) */
184
static void vga_bitblt(DisplayState *ds, int xs, int ys, int xd, int yd, int w, int h)
185
{
186
    const uint8_t *s;
187
    uint8_t *d;
188
    int wb, y, bpp;
189

    
190
    bpp = (ds->depth + 7) >> 3;
191
    wb = w * bpp;
192
    if (yd <= ys) {
193
        s = ds->data + 
194
            ds->linesize * ys + bpp * xs;
195
        d = ds->data + 
196
            ds->linesize * yd + bpp * xd;
197
        for (y = 0; y < h; y++) {
198
            memmove(d, s, wb);
199
            d += ds->linesize;
200
            s += ds->linesize;
201
        }
202
    } else {
203
        s = ds->data + 
204
            ds->linesize * (ys + h - 1) + bpp * xs;
205
        d = ds->data + 
206
            ds->linesize * (yd + h - 1) + bpp * xd;
207
       for (y = 0; y < h; y++) {
208
            memmove(d, s, wb);
209
            d -= ds->linesize;
210
            s -= ds->linesize;
211
        }
212
    }
213
}
214

    
215
/***********************************************************/
216
/* basic char display */
217

    
218
#define FONT_HEIGHT 16
219
#define FONT_WIDTH 8
220

    
221
#include "vgafont.h"
222

    
223
#define cbswap_32(__x) \
224
((uint32_t)( \
225
                (((uint32_t)(__x) & (uint32_t)0x000000ffUL) << 24) | \
226
                (((uint32_t)(__x) & (uint32_t)0x0000ff00UL) <<  8) | \
227
                (((uint32_t)(__x) & (uint32_t)0x00ff0000UL) >>  8) | \
228
                (((uint32_t)(__x) & (uint32_t)0xff000000UL) >> 24) ))
229

    
230
#ifdef WORDS_BIGENDIAN
231
#define PAT(x) x
232
#else
233
#define PAT(x) cbswap_32(x)
234
#endif
235

    
236
static const uint32_t dmask16[16] = {
237
    PAT(0x00000000),
238
    PAT(0x000000ff),
239
    PAT(0x0000ff00),
240
    PAT(0x0000ffff),
241
    PAT(0x00ff0000),
242
    PAT(0x00ff00ff),
243
    PAT(0x00ffff00),
244
    PAT(0x00ffffff),
245
    PAT(0xff000000),
246
    PAT(0xff0000ff),
247
    PAT(0xff00ff00),
248
    PAT(0xff00ffff),
249
    PAT(0xffff0000),
250
    PAT(0xffff00ff),
251
    PAT(0xffffff00),
252
    PAT(0xffffffff),
253
};
254

    
255
static const uint32_t dmask4[4] = {
256
    PAT(0x00000000),
257
    PAT(0x0000ffff),
258
    PAT(0xffff0000),
259
    PAT(0xffffffff),
260
};
261

    
262
static uint32_t color_table[2][8];
263

    
264
enum color_names {
265
    COLOR_BLACK   = 0,
266
    COLOR_RED     = 1,
267
    COLOR_GREEN   = 2,
268
    COLOR_YELLOW  = 3,
269
    COLOR_BLUE    = 4,
270
    COLOR_MAGENTA = 5,
271
    COLOR_CYAN    = 6,
272
    COLOR_WHITE   = 7
273
};
274

    
275
static const uint32_t color_table_rgb[2][8] = {
276
    {   /* dark */
277
        RGB(0x00, 0x00, 0x00),  /* black */
278
        RGB(0xaa, 0x00, 0x00),  /* red */
279
        RGB(0x00, 0xaa, 0x00),  /* green */
280
        RGB(0xaa, 0xaa, 0x00),  /* yellow */
281
        RGB(0x00, 0x00, 0xaa),  /* blue */
282
        RGB(0xaa, 0x00, 0xaa),  /* magenta */
283
        RGB(0x00, 0xaa, 0xaa),  /* cyan */
284
        RGB(0xaa, 0xaa, 0xaa),  /* white */
285
    },
286
    {   /* bright */
287
        RGB(0x00, 0x00, 0x00),  /* black */
288
        RGB(0xff, 0x00, 0x00),  /* red */
289
        RGB(0x00, 0xff, 0x00),  /* green */
290
        RGB(0xff, 0xff, 0x00),  /* yellow */
291
        RGB(0x00, 0x00, 0xff),  /* blue */
292
        RGB(0xff, 0x00, 0xff),  /* magenta */
293
        RGB(0x00, 0xff, 0xff),  /* cyan */
294
        RGB(0xff, 0xff, 0xff),  /* white */
295
    }
296
};
297

    
298
static inline unsigned int col_expand(DisplayState *ds, unsigned int col)
299
{
300
    switch(ds->depth) {
301
    case 8:
302
        col |= col << 8;
303
        col |= col << 16;
304
        break;
305
    case 15:
306
    case 16:
307
        col |= col << 16;
308
        break;
309
    default:
310
        break;
311
    }
312

    
313
    return col;
314
}
315
#ifdef DEBUG_CONSOLE
316
static void console_print_text_attributes(TextAttributes *t_attrib, char ch)
317
{
318
    if (t_attrib->bold) {
319
        printf("b");
320
    } else {
321
        printf(" ");
322
    }
323
    if (t_attrib->uline) {
324
        printf("u");
325
    } else {
326
        printf(" ");
327
    }
328
    if (t_attrib->blink) {
329
        printf("l");
330
    } else {
331
        printf(" ");
332
    }
333
    if (t_attrib->invers) {
334
        printf("i");
335
    } else {
336
        printf(" ");
337
    }
338
    if (t_attrib->unvisible) {
339
        printf("n");
340
    } else {
341
        printf(" ");
342
    }
343

    
344
    printf(" fg: %d bg: %d ch:'%2X' '%c'\n", t_attrib->fgcol, t_attrib->bgcol, ch, ch);
345
}
346
#endif
347

    
348
static void vga_putcharxy(DisplayState *ds, int x, int y, int ch, 
349
                          TextAttributes *t_attrib)
350
{
351
    uint8_t *d;
352
    const uint8_t *font_ptr;
353
    unsigned int font_data, linesize, xorcol, bpp;
354
    int i;
355
    unsigned int fgcol, bgcol;
356

    
357
#ifdef DEBUG_CONSOLE
358
    printf("x: %2i y: %2i", x, y);
359
    console_print_text_attributes(t_attrib, ch);
360
#endif
361

    
362
    if (t_attrib->invers) {
363
        bgcol = color_table[t_attrib->bold][t_attrib->fgcol];
364
        fgcol = color_table[t_attrib->bold][t_attrib->bgcol];
365
    } else {
366
        fgcol = color_table[t_attrib->bold][t_attrib->fgcol];
367
        bgcol = color_table[t_attrib->bold][t_attrib->bgcol];
368
    }
369

    
370
    bpp = (ds->depth + 7) >> 3;
371
    d = ds->data + 
372
        ds->linesize * y * FONT_HEIGHT + bpp * x * FONT_WIDTH;
373
    linesize = ds->linesize;
374
    font_ptr = vgafont16 + FONT_HEIGHT * ch;
375
    xorcol = bgcol ^ fgcol;
376
    switch(ds->depth) {
377
    case 8:
378
        for(i = 0; i < FONT_HEIGHT; i++) {
379
            font_data = *font_ptr++;
380
            if (t_attrib->uline
381
                && ((i == FONT_HEIGHT - 2) || (i == FONT_HEIGHT - 3))) {
382
                font_data = 0xFFFF;
383
            }
384
            ((uint32_t *)d)[0] = (dmask16[(font_data >> 4)] & xorcol) ^ bgcol;
385
            ((uint32_t *)d)[1] = (dmask16[(font_data >> 0) & 0xf] & xorcol) ^ bgcol;
386
            d += linesize;
387
        }
388
        break;
389
    case 16:
390
    case 15:
391
        for(i = 0; i < FONT_HEIGHT; i++) {
392
            font_data = *font_ptr++;
393
            if (t_attrib->uline
394
                && ((i == FONT_HEIGHT - 2) || (i == FONT_HEIGHT - 3))) {
395
                font_data = 0xFFFF;
396
            }
397
            ((uint32_t *)d)[0] = (dmask4[(font_data >> 6)] & xorcol) ^ bgcol;
398
            ((uint32_t *)d)[1] = (dmask4[(font_data >> 4) & 3] & xorcol) ^ bgcol;
399
            ((uint32_t *)d)[2] = (dmask4[(font_data >> 2) & 3] & xorcol) ^ bgcol;
400
            ((uint32_t *)d)[3] = (dmask4[(font_data >> 0) & 3] & xorcol) ^ bgcol;
401
            d += linesize;
402
        }
403
        break;
404
    case 32:
405
        for(i = 0; i < FONT_HEIGHT; i++) {
406
            font_data = *font_ptr++;
407
            if (t_attrib->uline && ((i == FONT_HEIGHT - 2) || (i == FONT_HEIGHT - 3))) {
408
                font_data = 0xFFFF;
409
            }
410
            ((uint32_t *)d)[0] = (-((font_data >> 7)) & xorcol) ^ bgcol;
411
            ((uint32_t *)d)[1] = (-((font_data >> 6) & 1) & xorcol) ^ bgcol;
412
            ((uint32_t *)d)[2] = (-((font_data >> 5) & 1) & xorcol) ^ bgcol;
413
            ((uint32_t *)d)[3] = (-((font_data >> 4) & 1) & xorcol) ^ bgcol;
414
            ((uint32_t *)d)[4] = (-((font_data >> 3) & 1) & xorcol) ^ bgcol;
415
            ((uint32_t *)d)[5] = (-((font_data >> 2) & 1) & xorcol) ^ bgcol;
416
            ((uint32_t *)d)[6] = (-((font_data >> 1) & 1) & xorcol) ^ bgcol;
417
            ((uint32_t *)d)[7] = (-((font_data >> 0) & 1) & xorcol) ^ bgcol;
418
            d += linesize;
419
        }
420
        break;
421
    }
422
}
423

    
424
static void text_console_resize(TextConsole *s)
425
{
426
    TextCell *cells, *c, *c1;
427
    int w1, x, y, last_width;
428

    
429
    last_width = s->width;
430
    s->width = s->g_width / FONT_WIDTH;
431
    s->height = s->g_height / FONT_HEIGHT;
432

    
433
    w1 = last_width;
434
    if (s->width < w1)
435
        w1 = s->width;
436

    
437
    cells = qemu_malloc(s->width * s->total_height * sizeof(TextCell));
438
    for(y = 0; y < s->total_height; y++) {
439
        c = &cells[y * s->width];
440
        if (w1 > 0) {
441
            c1 = &s->cells[y * last_width];
442
            for(x = 0; x < w1; x++) {
443
                *c++ = *c1++;
444
            }
445
        }
446
        for(x = w1; x < s->width; x++) {
447
            c->ch = ' ';
448
            c->t_attrib = s->t_attrib_default;
449
            c++;
450
        }
451
    }
452
    free(s->cells);
453
    s->cells = cells;
454
}
455

    
456
static void update_xy(TextConsole *s, int x, int y)
457
{
458
    TextCell *c;
459
    int y1, y2;
460

    
461
    if (s == active_console) {
462
        y1 = (s->y_base + y) % s->total_height;
463
        y2 = y1 - s->y_displayed;
464
        if (y2 < 0)
465
            y2 += s->total_height;
466
        if (y2 < s->height) {
467
            c = &s->cells[y1 * s->width + x];
468
            vga_putcharxy(s->ds, x, y2, c->ch, 
469
                          &(c->t_attrib));
470
            dpy_update(s->ds, x * FONT_WIDTH, y2 * FONT_HEIGHT, 
471
                       FONT_WIDTH, FONT_HEIGHT);
472
        }
473
    }
474
}
475

    
476
static void console_show_cursor(TextConsole *s, int show)
477
{
478
    TextCell *c;
479
    int y, y1;
480

    
481
    if (s == active_console) {
482
        y1 = (s->y_base + s->y) % s->total_height;
483
        y = y1 - s->y_displayed;
484
        if (y < 0)
485
            y += s->total_height;
486
        if (y < s->height) {
487
            c = &s->cells[y1 * s->width + s->x];
488
            if (show) {
489
                TextAttributes t_attrib = s->t_attrib_default;
490
                t_attrib.invers = !(t_attrib.invers); /* invert fg and bg */
491
                vga_putcharxy(s->ds, s->x, y, c->ch, &t_attrib);
492
            } else {
493
                vga_putcharxy(s->ds, s->x, y, c->ch, 
494
                              &(c->t_attrib));
495
            }
496
            dpy_update(s->ds, s->x * FONT_WIDTH, y * FONT_HEIGHT, 
497
                       FONT_WIDTH, FONT_HEIGHT);
498
        }
499
    }
500
}
501

    
502
static void console_refresh(TextConsole *s)
503
{
504
    TextCell *c;
505
    int x, y, y1;
506

    
507
    if (s != active_console) 
508
        return;
509

    
510
    vga_fill_rect(s->ds, 0, 0, s->ds->width, s->ds->height,
511
                  color_table[0][COLOR_BLACK]);
512
    y1 = s->y_displayed;
513
    for(y = 0; y < s->height; y++) {
514
        c = s->cells + y1 * s->width;
515
        for(x = 0; x < s->width; x++) {
516
            vga_putcharxy(s->ds, x, y, c->ch, 
517
                          &(c->t_attrib));
518
            c++;
519
        }
520
        if (++y1 == s->total_height)
521
            y1 = 0;
522
    }
523
    dpy_update(s->ds, 0, 0, s->ds->width, s->ds->height);
524
    console_show_cursor(s, 1);
525
}
526

    
527
static void console_scroll(int ydelta)
528
{
529
    TextConsole *s;
530
    int i, y1;
531
    
532
    s = active_console;
533
    if (!s || !s->text_console)
534
        return;
535

    
536
    if (ydelta > 0) {
537
        for(i = 0; i < ydelta; i++) {
538
            if (s->y_displayed == s->y_base)
539
                break;
540
            if (++s->y_displayed == s->total_height)
541
                s->y_displayed = 0;
542
        }
543
    } else {
544
        ydelta = -ydelta;
545
        i = s->backscroll_height;
546
        if (i > s->total_height - s->height)
547
            i = s->total_height - s->height;
548
        y1 = s->y_base - i;
549
        if (y1 < 0)
550
            y1 += s->total_height;
551
        for(i = 0; i < ydelta; i++) {
552
            if (s->y_displayed == y1)
553
                break;
554
            if (--s->y_displayed < 0)
555
                s->y_displayed = s->total_height - 1;
556
        }
557
    }
558
    console_refresh(s);
559
}
560

    
561
static void console_put_lf(TextConsole *s)
562
{
563
    TextCell *c;
564
    int x, y1;
565

    
566
    s->x = 0;
567
    s->y++;
568
    if (s->y >= s->height) {
569
        s->y = s->height - 1;
570

    
571
        if (s->y_displayed == s->y_base) {
572
            if (++s->y_displayed == s->total_height)
573
                s->y_displayed = 0;
574
        }
575
        if (++s->y_base == s->total_height)
576
            s->y_base = 0;
577
        if (s->backscroll_height < s->total_height)
578
            s->backscroll_height++;
579
        y1 = (s->y_base + s->height - 1) % s->total_height;
580
        c = &s->cells[y1 * s->width];
581
        for(x = 0; x < s->width; x++) {
582
            c->ch = ' ';
583
            c->t_attrib = s->t_attrib_default;
584
            c++;
585
        }
586
        if (s == active_console && s->y_displayed == s->y_base) {
587
            vga_bitblt(s->ds, 0, FONT_HEIGHT, 0, 0, 
588
                       s->width * FONT_WIDTH, 
589
                       (s->height - 1) * FONT_HEIGHT);
590
            vga_fill_rect(s->ds, 0, (s->height - 1) * FONT_HEIGHT,
591
                          s->width * FONT_WIDTH, FONT_HEIGHT, 
592
                          color_table[0][s->t_attrib_default.bgcol]);
593
            dpy_update(s->ds, 0, 0, 
594
                       s->width * FONT_WIDTH, s->height * FONT_HEIGHT);
595
        }
596
    }
597
}
598

    
599
/* Set console attributes depending on the current escape codes.
600
 * NOTE: I know this code is not very efficient (checking every color for it
601
 * self) but it is more readable and better maintainable.
602
 */
603
static void console_handle_escape(TextConsole *s)
604
{
605
    int i;
606

    
607
    if (s->nb_esc_params == 0) { /* ESC[m sets all attributes to default */
608
        s->t_attrib = s->t_attrib_default;
609
        return;
610
    }
611
    for (i=0; i<s->nb_esc_params; i++) {
612
        switch (s->esc_params[i]) {
613
            case 0: /* reset all console attributes to default */
614
                s->t_attrib = s->t_attrib_default;
615
                break;
616
            case 1:
617
                s->t_attrib.bold = 1;
618
                break;
619
            case 4:
620
                s->t_attrib.uline = 1;
621
                break;
622
            case 5:
623
                s->t_attrib.blink = 1;
624
                break;
625
            case 7:
626
                s->t_attrib.invers = 1;
627
                break;
628
            case 8:
629
                s->t_attrib.unvisible = 1;
630
                break;
631
            case 22:
632
                s->t_attrib.bold = 0;
633
                break;
634
            case 24:
635
                s->t_attrib.uline = 0;
636
                break;
637
            case 25:
638
                s->t_attrib.blink = 0;
639
                break;
640
            case 27:
641
                s->t_attrib.invers = 0;
642
                break;
643
            case 28:
644
                s->t_attrib.unvisible = 0;
645
                break;
646
            /* set foreground color */
647
            case 30:
648
                s->t_attrib.fgcol=COLOR_BLACK;
649
                break;
650
            case 31:
651
                s->t_attrib.fgcol=COLOR_RED;
652
                break;
653
            case 32:
654
                s->t_attrib.fgcol=COLOR_GREEN;
655
                break;
656
            case 33:
657
                s->t_attrib.fgcol=COLOR_YELLOW;
658
                break;
659
            case 34:
660
                s->t_attrib.fgcol=COLOR_BLUE;
661
                break;
662
            case 35:
663
                s->t_attrib.fgcol=COLOR_MAGENTA;
664
                break;
665
            case 36:
666
                s->t_attrib.fgcol=COLOR_CYAN;
667
                break;
668
            case 37:
669
                s->t_attrib.fgcol=COLOR_WHITE;
670
                break;
671
            /* set background color */
672
            case 40:
673
                s->t_attrib.bgcol=COLOR_BLACK;
674
                break;
675
            case 41:
676
                s->t_attrib.bgcol=COLOR_RED;
677
                break;
678
            case 42:
679
                s->t_attrib.bgcol=COLOR_GREEN;
680
                break;
681
            case 43:
682
                s->t_attrib.bgcol=COLOR_YELLOW;
683
                break;
684
            case 44:
685
                s->t_attrib.bgcol=COLOR_BLUE;
686
                break;
687
            case 45:
688
                s->t_attrib.bgcol=COLOR_MAGENTA;
689
                break;
690
            case 46:
691
                s->t_attrib.bgcol=COLOR_CYAN;
692
                break;
693
            case 47:
694
                s->t_attrib.bgcol=COLOR_WHITE;
695
                break;
696
        }
697
    }
698
}
699

    
700
static void console_putchar(TextConsole *s, int ch)
701
{
702
    TextCell *c;
703
    int y1, i, x;
704

    
705
    switch(s->state) {
706
    case TTY_STATE_NORM:
707
        switch(ch) {
708
        case '\r':  /* carriage return */
709
            s->x = 0;
710
            break;
711
        case '\n':  /* newline */
712
            console_put_lf(s);
713
            break;
714
        case '\b':  /* backspace */
715
            if(s->x > 0) s->x--;
716
            y1 = (s->y_base + s->y) % s->total_height;
717
            c = &s->cells[y1 * s->width + s->x];
718
            c->ch = ' ';
719
            c->t_attrib = s->t_attrib;
720
            update_xy(s, s->x, s->y);
721
            break;
722
        case '\t':  /* tabspace */
723
            if (s->x + (8 - (s->x % 8)) > s->width) {
724
                console_put_lf(s);
725
            } else {
726
                s->x = s->x + (8 - (s->x % 8));
727
            }
728
            break;
729
        case '\a':  /* alert aka. bell */
730
            /* TODO: has to be implemented */
731
            break;
732
        case 27:    /* esc (introducing an escape sequence) */
733
            s->state = TTY_STATE_ESC;
734
            break;
735
        default:
736
            y1 = (s->y_base + s->y) % s->total_height;
737
            c = &s->cells[y1 * s->width + s->x];
738
            c->ch = ch;
739
            c->t_attrib = s->t_attrib;
740
            update_xy(s, s->x, s->y);
741
            s->x++;
742
            if (s->x >= s->width)
743
                console_put_lf(s);
744
            break;
745
        }
746
        break;
747
    case TTY_STATE_ESC: /* check if it is a terminal escape sequence */
748
        if (ch == '[') {
749
            for(i=0;i<MAX_ESC_PARAMS;i++)
750
                s->esc_params[i] = 0;
751
            s->nb_esc_params = 0;
752
            s->state = TTY_STATE_CSI;
753
        } else {
754
            s->state = TTY_STATE_NORM;
755
        }
756
        break;
757
    case TTY_STATE_CSI: /* handle escape sequence parameters */
758
        if (ch >= '0' && ch <= '9') {
759
            if (s->nb_esc_params < MAX_ESC_PARAMS) {
760
                s->esc_params[s->nb_esc_params] = 
761
                    s->esc_params[s->nb_esc_params] * 10 + ch - '0';
762
            }
763
        } else {
764
            s->nb_esc_params++;
765
            if (ch == ';')
766
                break;
767
            s->state = TTY_STATE_NORM;
768
            switch(ch) {
769
            case 'D':
770
                if (s->x > 0)
771
                    s->x--;
772
                break;
773
            case 'C':
774
                if (s->x < (s->width - 1))
775
                    s->x++;
776
                break;
777
            case 'K':
778
                /* clear to eol */
779
                y1 = (s->y_base + s->y) % s->total_height;
780
                for(x = s->x; x < s->width; x++) {
781
                    c = &s->cells[y1 * s->width + x];
782
                    c->ch = ' ';
783
                    c->t_attrib = s->t_attrib_default;
784
                    c++;
785
                    update_xy(s, x, s->y);
786
                }
787
                break;
788
            default:
789
                break;
790
            }
791
            console_handle_escape(s);
792
            break;
793
        }
794
    }
795
}
796

    
797
void console_select(unsigned int index)
798
{
799
    TextConsole *s;
800

    
801
    if (index >= MAX_CONSOLES)
802
        return;
803
    s = consoles[index];
804
    if (s) {
805
        active_console = s;
806
        if (s->text_console) {
807
            if (s->g_width != s->ds->width ||
808
                s->g_height != s->ds->height) {
809
                s->g_width = s->ds->width;
810
                s->g_height = s->ds->height;
811
                text_console_resize(s);
812
            }
813
            console_refresh(s);
814
        } else {
815
            vga_hw_invalidate();
816
        }
817
    }
818
}
819

    
820
static int console_puts(CharDriverState *chr, const uint8_t *buf, int len)
821
{
822
    TextConsole *s = chr->opaque;
823
    int i;
824

    
825
    console_show_cursor(s, 0);
826
    for(i = 0; i < len; i++) {
827
        console_putchar(s, buf[i]);
828
    }
829
    console_show_cursor(s, 1);
830
    return len;
831
}
832

    
833
static void console_chr_add_read_handler(CharDriverState *chr, 
834
                                         IOCanRWHandler *fd_can_read, 
835
                                         IOReadHandler *fd_read, void *opaque)
836
{
837
    TextConsole *s = chr->opaque;
838
    s->fd_read = fd_read;
839
    s->fd_opaque = opaque;
840
}
841

    
842
static void console_send_event(CharDriverState *chr, int event)
843
{
844
    TextConsole *s = chr->opaque;
845
    int i;
846

    
847
    if (event == CHR_EVENT_FOCUS) {
848
        for(i = 0; i < nb_consoles; i++) {
849
            if (consoles[i] == s) {
850
                console_select(i);
851
                break;
852
            }
853
        }
854
    }
855
}
856

    
857
/* called when an ascii key is pressed */
858
void kbd_put_keysym(int keysym)
859
{
860
    TextConsole *s;
861
    uint8_t buf[16], *q;
862
    int c;
863

    
864
    s = active_console;
865
    if (!s || !s->text_console)
866
        return;
867

    
868
    switch(keysym) {
869
    case QEMU_KEY_CTRL_UP:
870
        console_scroll(-1);
871
        break;
872
    case QEMU_KEY_CTRL_DOWN:
873
        console_scroll(1);
874
        break;
875
    case QEMU_KEY_CTRL_PAGEUP:
876
        console_scroll(-10);
877
        break;
878
    case QEMU_KEY_CTRL_PAGEDOWN:
879
        console_scroll(10);
880
        break;
881
    default:
882
        if (s->fd_read) {
883
            /* convert the QEMU keysym to VT100 key string */
884
            q = buf;
885
            if (keysym >= 0xe100 && keysym <= 0xe11f) {
886
                *q++ = '\033';
887
                *q++ = '[';
888
                c = keysym - 0xe100;
889
                if (c >= 10)
890
                    *q++ = '0' + (c / 10);
891
                *q++ = '0' + (c % 10);
892
                *q++ = '~';
893
            } else if (keysym >= 0xe120 && keysym <= 0xe17f) {
894
                *q++ = '\033';
895
                *q++ = '[';
896
                *q++ = keysym & 0xff;
897
            } else {
898
                *q++ = keysym;
899
            }
900
            s->fd_read(s->fd_opaque, buf, q - buf);
901
        }
902
        break;
903
    }
904
}
905

    
906
static TextConsole *new_console(DisplayState *ds, int text)
907
{
908
    TextConsole *s;
909
    int i;
910

    
911
    if (nb_consoles >= MAX_CONSOLES)
912
        return NULL;
913
    s = qemu_mallocz(sizeof(TextConsole));
914
    if (!s) {
915
        return NULL;
916
    }
917
    if (!active_console || (active_console->text_console && !text))
918
        active_console = s;
919
    s->ds = ds;
920
    s->text_console = text;
921
    if (text) {
922
        consoles[nb_consoles++] = s;
923
    } else {
924
        /* HACK: Put graphical consoles before text consoles.  */
925
        for (i = nb_consoles; i > 0; i--) {
926
            if (!consoles[i - 1]->text_console)
927
                break;
928
            consoles[i] = consoles[i - 1];
929
        }
930
        consoles[i] = s;
931
    }
932
    return s;
933
}
934

    
935
TextConsole *graphic_console_init(DisplayState *ds, vga_hw_update_ptr update,
936
                                  vga_hw_invalidate_ptr invalidate,
937
                                  vga_hw_screen_dump_ptr screen_dump,
938
                                  void *opaque)
939
{
940
    TextConsole *s;
941

    
942
    s = new_console(ds, 0);
943
    if (!s)
944
      return NULL;
945
    s->hw_update = update;
946
    s->hw_invalidate = invalidate;
947
    s->hw_screen_dump = screen_dump;
948
    s->hw = opaque;
949
    return s;
950
}
951

    
952
int is_graphic_console(void)
953
{
954
    return !active_console->text_console;
955
}
956

    
957
CharDriverState *text_console_init(DisplayState *ds)
958
{
959
    CharDriverState *chr;
960
    TextConsole *s;
961
    int i,j;
962
    static int color_inited;
963

    
964
    chr = qemu_mallocz(sizeof(CharDriverState));
965
    if (!chr)
966
        return NULL;
967
    s = new_console(ds, 1);
968
    if (!s) {
969
        free(chr);
970
        return NULL;
971
    }
972
    chr->opaque = s;
973
    chr->chr_write = console_puts;
974
    chr->chr_add_read_handler = console_chr_add_read_handler;
975
    chr->chr_send_event = console_send_event;
976

    
977
    if (!color_inited) {
978
        color_inited = 1;
979
        for(j = 0; j < 2; j++) {
980
            for(i = 0; i < 8; i++) {
981
                color_table[j][i] = col_expand(s->ds, 
982
                        vga_get_color(s->ds, color_table_rgb[j][i]));
983
            }
984
        }
985
    }
986
    s->y_displayed = 0;
987
    s->y_base = 0;
988
    s->total_height = DEFAULT_BACKSCROLL;
989
    s->x = 0;
990
    s->y = 0;
991
    s->g_width = s->ds->width;
992
    s->g_height = s->ds->height;
993

    
994
    /* Set text attribute defaults */
995
    s->t_attrib_default.bold = 0;
996
    s->t_attrib_default.uline = 0;
997
    s->t_attrib_default.blink = 0;
998
    s->t_attrib_default.invers = 0;
999
    s->t_attrib_default.unvisible = 0;
1000
    s->t_attrib_default.fgcol = COLOR_WHITE;
1001
    s->t_attrib_default.bgcol = COLOR_BLACK;
1002

    
1003
    /* set current text attributes to default */
1004
    s->t_attrib = s->t_attrib_default;
1005
    text_console_resize(s);
1006

    
1007
    return chr;
1008
}