Statistics
| Branch: | Revision:

root / console.c @ 42fc925e

History | View | Annotate | Download (29.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 y_displayed;
125
    int y_base;
126
    TextAttributes t_attrib_default; /* default text attributes */
127
    TextAttributes t_attrib; /* currently active text attributes */
128
    TextCell *cells;
129

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

    
134
    /* kbd read handler */
135
    IOCanRWHandler *fd_can_read; 
136
    IOReadHandler *fd_read;
137
    void *fd_opaque;
138
    /* fifo for key pressed */
139
    QEMUFIFO out_fifo;
140
    uint8_t out_fifo_buf[16];
141
    QEMUTimer *kbd_timer;
142
};
143

    
144
static TextConsole *active_console;
145
static TextConsole *consoles[MAX_CONSOLES];
146
static int nb_consoles = 0;
147

    
148
void vga_hw_update(void)
149
{
150
    if (active_console->hw_update)
151
        active_console->hw_update(active_console->hw);
152
}
153

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

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

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

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

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

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

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

    
271
/***********************************************************/
272
/* basic char display */
273

    
274
#define FONT_HEIGHT 16
275
#define FONT_WIDTH 8
276

    
277
#include "vgafont.h"
278

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

    
286
#ifdef WORDS_BIGENDIAN
287
#define PAT(x) x
288
#else
289
#define PAT(x) cbswap_32(x)
290
#endif
291

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

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

    
318
static uint32_t color_table[2][8];
319

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

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

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

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

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

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

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

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

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

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

    
485
    last_width = s->width;
486
    s->width = s->g_width / FONT_WIDTH;
487
    s->height = s->g_height / FONT_HEIGHT;
488

    
489
    w1 = last_width;
490
    if (s->width < w1)
491
        w1 = s->width;
492

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

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

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

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

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

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

    
563
    if (s != active_console) 
564
        return;
565

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

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

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

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

    
622
    s->y++;
623
    if (s->y >= s->height) {
624
        s->y = s->height - 1;
625

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

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

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

    
755
static void console_putchar(TextConsole *s, int ch)
756
{
757
    TextCell *c;
758
    int y1, i, x;
759

    
760
    switch(s->state) {
761
    case TTY_STATE_NORM:
762
        switch(ch) {
763
        case '\r':  /* carriage return */
764
            s->x = 0;
765
            break;
766
        case '\n':  /* newline */
767
            console_put_lf(s);
768
            break;
769
        case '\b':  /* backspace */
770
            if (s->x > 0) 
771
                s->x--;
772
            break;
773
        case '\t':  /* tabspace */
774
            if (s->x + (8 - (s->x % 8)) > s->width) {
775
                s->x = 0;
776
                console_put_lf(s);
777
            } else {
778
                s->x = s->x + (8 - (s->x % 8));
779
            }
780
            break;
781
        case '\a':  /* alert aka. bell */
782
            /* TODO: has to be implemented */
783
            break;
784
        case 27:    /* esc (introducing an escape sequence) */
785
            s->state = TTY_STATE_ESC;
786
            break;
787
        default:
788
            y1 = (s->y_base + s->y) % s->total_height;
789
            c = &s->cells[y1 * s->width + s->x];
790
            c->ch = ch;
791
            c->t_attrib = s->t_attrib;
792
            update_xy(s, s->x, s->y);
793
            s->x++;
794
            if (s->x >= s->width) {
795
                s->x = 0;
796
                console_put_lf(s);
797
            }
798
            break;
799
        }
800
        break;
801
    case TTY_STATE_ESC: /* check if it is a terminal escape sequence */
802
        if (ch == '[') {
803
            for(i=0;i<MAX_ESC_PARAMS;i++)
804
                s->esc_params[i] = 0;
805
            s->nb_esc_params = 0;
806
            s->state = TTY_STATE_CSI;
807
        } else {
808
            s->state = TTY_STATE_NORM;
809
        }
810
        break;
811
    case TTY_STATE_CSI: /* handle escape sequence parameters */
812
        if (ch >= '0' && ch <= '9') {
813
            if (s->nb_esc_params < MAX_ESC_PARAMS) {
814
                s->esc_params[s->nb_esc_params] = 
815
                    s->esc_params[s->nb_esc_params] * 10 + ch - '0';
816
            }
817
        } else {
818
            s->nb_esc_params++;
819
            if (ch == ';')
820
                break;
821
            s->state = TTY_STATE_NORM;
822
            switch(ch) {
823
            case 'D':
824
                if (s->x > 0)
825
                    s->x--;
826
                break;
827
            case 'C':
828
                if (s->x < (s->width - 1))
829
                    s->x++;
830
                break;
831
            case 'K':
832
                /* clear to eol */
833
                y1 = (s->y_base + s->y) % s->total_height;
834
                for(x = s->x; x < s->width; x++) {
835
                    c = &s->cells[y1 * s->width + x];
836
                    c->ch = ' ';
837
                    c->t_attrib = s->t_attrib_default;
838
                    c++;
839
                    update_xy(s, x, s->y);
840
                }
841
                break;
842
            default:
843
                break;
844
            }
845
            console_handle_escape(s);
846
            break;
847
        }
848
    }
849
}
850

    
851
void console_select(unsigned int index)
852
{
853
    TextConsole *s;
854

    
855
    if (index >= MAX_CONSOLES)
856
        return;
857
    s = consoles[index];
858
    if (s) {
859
        active_console = s;
860
        if (s->text_console) {
861
            if (s->g_width != s->ds->width ||
862
                s->g_height != s->ds->height) {
863
                s->g_width = s->ds->width;
864
                s->g_height = s->ds->height;
865
                text_console_resize(s);
866
            }
867
            console_refresh(s);
868
        } else {
869
            vga_hw_invalidate();
870
        }
871
    }
872
}
873

    
874
static int console_puts(CharDriverState *chr, const uint8_t *buf, int len)
875
{
876
    TextConsole *s = chr->opaque;
877
    int i;
878

    
879
    console_show_cursor(s, 0);
880
    for(i = 0; i < len; i++) {
881
        console_putchar(s, buf[i]);
882
    }
883
    console_show_cursor(s, 1);
884
    return len;
885
}
886

    
887
static void console_chr_add_read_handler(CharDriverState *chr, 
888
                                         IOCanRWHandler *fd_can_read, 
889
                                         IOReadHandler *fd_read, void *opaque)
890
{
891
    TextConsole *s = chr->opaque;
892
    s->fd_can_read = fd_can_read;
893
    s->fd_read = fd_read;
894
    s->fd_opaque = opaque;
895
}
896

    
897
static void console_send_event(CharDriverState *chr, int event)
898
{
899
    TextConsole *s = chr->opaque;
900
    int i;
901

    
902
    if (event == CHR_EVENT_FOCUS) {
903
        for(i = 0; i < nb_consoles; i++) {
904
            if (consoles[i] == s) {
905
                console_select(i);
906
                break;
907
            }
908
        }
909
    }
910
}
911

    
912
static void kbd_send_chars(void *opaque)
913
{
914
    TextConsole *s = opaque;
915
    int len;
916
    uint8_t buf[16];
917
    
918
    len = s->fd_can_read(s->fd_opaque);
919
    if (len > s->out_fifo.count)
920
        len = s->out_fifo.count;
921
    if (len > 0) {
922
        if (len > sizeof(buf))
923
            len = sizeof(buf);
924
        qemu_fifo_read(&s->out_fifo, buf, len);
925
        s->fd_read(s->fd_opaque, buf, len);
926
    }
927
    /* characters are pending: we send them a bit later (XXX:
928
       horrible, should change char device API) */
929
    if (s->out_fifo.count > 0) {
930
        qemu_mod_timer(s->kbd_timer, qemu_get_clock(rt_clock) + 1);
931
    }
932
}
933

    
934
/* called when an ascii key is pressed */
935
void kbd_put_keysym(int keysym)
936
{
937
    TextConsole *s;
938
    uint8_t buf[16], *q;
939
    int c;
940

    
941
    s = active_console;
942
    if (!s || !s->text_console)
943
        return;
944

    
945
    switch(keysym) {
946
    case QEMU_KEY_CTRL_UP:
947
        console_scroll(-1);
948
        break;
949
    case QEMU_KEY_CTRL_DOWN:
950
        console_scroll(1);
951
        break;
952
    case QEMU_KEY_CTRL_PAGEUP:
953
        console_scroll(-10);
954
        break;
955
    case QEMU_KEY_CTRL_PAGEDOWN:
956
        console_scroll(10);
957
        break;
958
    default:
959
        /* convert the QEMU keysym to VT100 key string */
960
        q = buf;
961
        if (keysym >= 0xe100 && keysym <= 0xe11f) {
962
            *q++ = '\033';
963
            *q++ = '[';
964
            c = keysym - 0xe100;
965
            if (c >= 10)
966
                *q++ = '0' + (c / 10);
967
            *q++ = '0' + (c % 10);
968
            *q++ = '~';
969
        } else if (keysym >= 0xe120 && keysym <= 0xe17f) {
970
            *q++ = '\033';
971
            *q++ = '[';
972
            *q++ = keysym & 0xff;
973
        } else {
974
                *q++ = keysym;
975
        }
976
        if (s->fd_read) {
977
            qemu_fifo_write(&s->out_fifo, buf, q - buf);
978
            kbd_send_chars(s);
979
        }
980
        break;
981
    }
982
}
983

    
984
static TextConsole *new_console(DisplayState *ds, int text)
985
{
986
    TextConsole *s;
987
    int i;
988

    
989
    if (nb_consoles >= MAX_CONSOLES)
990
        return NULL;
991
    s = qemu_mallocz(sizeof(TextConsole));
992
    if (!s) {
993
        return NULL;
994
    }
995
    if (!active_console || (active_console->text_console && !text))
996
        active_console = s;
997
    s->ds = ds;
998
    s->text_console = text;
999
    if (text) {
1000
        consoles[nb_consoles++] = s;
1001
    } else {
1002
        /* HACK: Put graphical consoles before text consoles.  */
1003
        for (i = nb_consoles; i > 0; i--) {
1004
            if (!consoles[i - 1]->text_console)
1005
                break;
1006
            consoles[i] = consoles[i - 1];
1007
        }
1008
        consoles[i] = s;
1009
    }
1010
    return s;
1011
}
1012

    
1013
TextConsole *graphic_console_init(DisplayState *ds, vga_hw_update_ptr update,
1014
                                  vga_hw_invalidate_ptr invalidate,
1015
                                  vga_hw_screen_dump_ptr screen_dump,
1016
                                  void *opaque)
1017
{
1018
    TextConsole *s;
1019

    
1020
    s = new_console(ds, 0);
1021
    if (!s)
1022
      return NULL;
1023
    s->hw_update = update;
1024
    s->hw_invalidate = invalidate;
1025
    s->hw_screen_dump = screen_dump;
1026
    s->hw = opaque;
1027
    return s;
1028
}
1029

    
1030
int is_graphic_console(void)
1031
{
1032
    return !active_console->text_console;
1033
}
1034

    
1035
CharDriverState *text_console_init(DisplayState *ds)
1036
{
1037
    CharDriverState *chr;
1038
    TextConsole *s;
1039
    int i,j;
1040
    static int color_inited;
1041

    
1042
    chr = qemu_mallocz(sizeof(CharDriverState));
1043
    if (!chr)
1044
        return NULL;
1045
    s = new_console(ds, 1);
1046
    if (!s) {
1047
        free(chr);
1048
        return NULL;
1049
    }
1050
    chr->opaque = s;
1051
    chr->chr_write = console_puts;
1052
    chr->chr_add_read_handler = console_chr_add_read_handler;
1053
    chr->chr_send_event = console_send_event;
1054

    
1055
    s->out_fifo.buf = s->out_fifo_buf;
1056
    s->out_fifo.buf_size = sizeof(s->out_fifo_buf);
1057
    s->kbd_timer = qemu_new_timer(rt_clock, kbd_send_chars, s);
1058
    
1059
    if (!color_inited) {
1060
        color_inited = 1;
1061
        for(j = 0; j < 2; j++) {
1062
            for(i = 0; i < 8; i++) {
1063
                color_table[j][i] = col_expand(s->ds, 
1064
                        vga_get_color(s->ds, color_table_rgb[j][i]));
1065
            }
1066
        }
1067
    }
1068
    s->y_displayed = 0;
1069
    s->y_base = 0;
1070
    s->total_height = DEFAULT_BACKSCROLL;
1071
    s->x = 0;
1072
    s->y = 0;
1073
    s->g_width = s->ds->width;
1074
    s->g_height = s->ds->height;
1075

    
1076
    /* Set text attribute defaults */
1077
    s->t_attrib_default.bold = 0;
1078
    s->t_attrib_default.uline = 0;
1079
    s->t_attrib_default.blink = 0;
1080
    s->t_attrib_default.invers = 0;
1081
    s->t_attrib_default.unvisible = 0;
1082
    s->t_attrib_default.fgcol = COLOR_WHITE;
1083
    s->t_attrib_default.bgcol = COLOR_BLACK;
1084

    
1085
    /* set current text attributes to default */
1086
    s->t_attrib = s->t_attrib_default;
1087
    text_console_resize(s);
1088

    
1089
    return chr;
1090
}