Statistics
| Branch: | Revision:

root / console.c @ e15d7371

History | View | Annotate | Download (29.1 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
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
        RGB(0x00, 0x00, 0x00),  /* black */
334
        RGB(0xaa, 0x00, 0x00),  /* red */
335
        RGB(0x00, 0xaa, 0x00),  /* green */
336
        RGB(0xaa, 0xaa, 0x00),  /* yellow */
337
        RGB(0x00, 0x00, 0xaa),  /* blue */
338
        RGB(0xaa, 0x00, 0xaa),  /* magenta */
339
        RGB(0x00, 0xaa, 0xaa),  /* cyan */
340
        RGB(0xaa, 0xaa, 0xaa),  /* white */
341
    },
342
    {   /* bright */
343
        RGB(0x00, 0x00, 0x00),  /* black */
344
        RGB(0xff, 0x00, 0x00),  /* red */
345
        RGB(0x00, 0xff, 0x00),  /* green */
346
        RGB(0xff, 0xff, 0x00),  /* yellow */
347
        RGB(0x00, 0x00, 0xff),  /* blue */
348
        RGB(0xff, 0x00, 0xff),  /* magenta */
349
        RGB(0x00, 0xff, 0xff),  /* cyan */
350
        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->x = 0;
623
    s->y++;
624
    if (s->y >= s->height) {
625
        s->y = s->height - 1;
626

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

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

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

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

    
761
    switch(s->state) {
762
    case TTY_STATE_NORM:
763
        switch(ch) {
764
        case '\r':  /* carriage return */
765
            s->x = 0;
766
            break;
767
        case '\n':  /* newline */
768
            console_put_lf(s);
769
            break;
770
        case '\b':  /* backspace */
771
            if (s->x > 0) 
772
                s->x--;
773
            break;
774
        case '\t':  /* tabspace */
775
            if (s->x + (8 - (s->x % 8)) > s->width) {
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
                console_put_lf(s);
796
            break;
797
        }
798
        break;
799
    case TTY_STATE_ESC: /* check if it is a terminal escape sequence */
800
        if (ch == '[') {
801
            for(i=0;i<MAX_ESC_PARAMS;i++)
802
                s->esc_params[i] = 0;
803
            s->nb_esc_params = 0;
804
            s->state = TTY_STATE_CSI;
805
        } else {
806
            s->state = TTY_STATE_NORM;
807
        }
808
        break;
809
    case TTY_STATE_CSI: /* handle escape sequence parameters */
810
        if (ch >= '0' && ch <= '9') {
811
            if (s->nb_esc_params < MAX_ESC_PARAMS) {
812
                s->esc_params[s->nb_esc_params] = 
813
                    s->esc_params[s->nb_esc_params] * 10 + ch - '0';
814
            }
815
        } else {
816
            s->nb_esc_params++;
817
            if (ch == ';')
818
                break;
819
            s->state = TTY_STATE_NORM;
820
            switch(ch) {
821
            case 'D':
822
                if (s->x > 0)
823
                    s->x--;
824
                break;
825
            case 'C':
826
                if (s->x < (s->width - 1))
827
                    s->x++;
828
                break;
829
            case 'K':
830
                /* clear to eol */
831
                y1 = (s->y_base + s->y) % s->total_height;
832
                for(x = s->x; x < s->width; x++) {
833
                    c = &s->cells[y1 * s->width + x];
834
                    c->ch = ' ';
835
                    c->t_attrib = s->t_attrib_default;
836
                    c++;
837
                    update_xy(s, x, s->y);
838
                }
839
                break;
840
            default:
841
                break;
842
            }
843
            console_handle_escape(s);
844
            break;
845
        }
846
    }
847
}
848

    
849
void console_select(unsigned int index)
850
{
851
    TextConsole *s;
852

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

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

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

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

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

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

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

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

    
939
    s = active_console;
940
    if (!s || !s->text_console)
941
        return;
942

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

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

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

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

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

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

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

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

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

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

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

    
1087
    return chr;
1088
}