Statistics
| Branch: | Revision:

root / ui / console.c @ c69b30e8

History | View | Annotate | Download (47.7 kB)

1
/*
2
 * QEMU graphical console
3
 *
4
 * Copyright (c) 2004 Fabrice Bellard
5
 *
6
 * Permission is hereby granted, free of charge, to any person obtaining a copy
7
 * of this software and associated documentation files (the "Software"), to deal
8
 * in the Software without restriction, including without limitation the rights
9
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10
 * copies of the Software, and to permit persons to whom the Software is
11
 * furnished to do so, subject to the following conditions:
12
 *
13
 * The above copyright notice and this permission notice shall be included in
14
 * all copies or substantial portions of the Software.
15
 *
16
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22
 * THE SOFTWARE.
23
 */
24
#include "qemu-common.h"
25
#include "ui/console.h"
26
#include "qemu/timer.h"
27
#include "qmp-commands.h"
28
#include "char/char.h"
29

    
30
//#define DEBUG_CONSOLE
31
#define DEFAULT_BACKSCROLL 512
32
#define MAX_CONSOLES 12
33
#define CONSOLE_CURSOR_PERIOD 500
34

    
35
#define QEMU_RGBA(r, g, b, a) (((a) << 24) | ((r) << 16) | ((g) << 8) | (b))
36
#define QEMU_RGB(r, g, b) QEMU_RGBA(r, g, b, 0xff)
37

    
38
typedef struct TextAttributes {
39
    uint8_t fgcol:4;
40
    uint8_t bgcol:4;
41
    uint8_t bold:1;
42
    uint8_t uline:1;
43
    uint8_t blink:1;
44
    uint8_t invers:1;
45
    uint8_t unvisible:1;
46
} TextAttributes;
47

    
48
typedef struct TextCell {
49
    uint8_t ch;
50
    TextAttributes t_attrib;
51
} TextCell;
52

    
53
#define MAX_ESC_PARAMS 3
54

    
55
enum TTYState {
56
    TTY_STATE_NORM,
57
    TTY_STATE_ESC,
58
    TTY_STATE_CSI,
59
};
60

    
61
typedef struct QEMUFIFO {
62
    uint8_t *buf;
63
    int buf_size;
64
    int count, wptr, rptr;
65
} QEMUFIFO;
66

    
67
static int qemu_fifo_write(QEMUFIFO *f, const uint8_t *buf, int len1)
68
{
69
    int l, len;
70

    
71
    l = f->buf_size - f->count;
72
    if (len1 > l)
73
        len1 = l;
74
    len = len1;
75
    while (len > 0) {
76
        l = f->buf_size - f->wptr;
77
        if (l > len)
78
            l = len;
79
        memcpy(f->buf + f->wptr, buf, l);
80
        f->wptr += l;
81
        if (f->wptr >= f->buf_size)
82
            f->wptr = 0;
83
        buf += l;
84
        len -= l;
85
    }
86
    f->count += len1;
87
    return len1;
88
}
89

    
90
static int qemu_fifo_read(QEMUFIFO *f, uint8_t *buf, int len1)
91
{
92
    int l, len;
93

    
94
    if (len1 > f->count)
95
        len1 = f->count;
96
    len = len1;
97
    while (len > 0) {
98
        l = f->buf_size - f->rptr;
99
        if (l > len)
100
            l = len;
101
        memcpy(buf, f->buf + f->rptr, l);
102
        f->rptr += l;
103
        if (f->rptr >= f->buf_size)
104
            f->rptr = 0;
105
        buf += l;
106
        len -= l;
107
    }
108
    f->count -= len1;
109
    return len1;
110
}
111

    
112
typedef enum {
113
    GRAPHIC_CONSOLE,
114
    TEXT_CONSOLE,
115
    TEXT_CONSOLE_FIXED_SIZE
116
} console_type_t;
117

    
118
struct QemuConsole {
119
    int index;
120
    console_type_t console_type;
121
    DisplayState *ds;
122

    
123
    /* Graphic console state.  */
124
    vga_hw_update_ptr hw_update;
125
    vga_hw_invalidate_ptr hw_invalidate;
126
    vga_hw_screen_dump_ptr hw_screen_dump;
127
    vga_hw_text_update_ptr hw_text_update;
128
    void *hw;
129
    int g_width, g_height;
130

    
131
    /* Text console state */
132
    int width;
133
    int height;
134
    int total_height;
135
    int backscroll_height;
136
    int x, y;
137
    int x_saved, y_saved;
138
    int y_displayed;
139
    int y_base;
140
    TextAttributes t_attrib_default; /* default text attributes */
141
    TextAttributes t_attrib; /* currently active text attributes */
142
    TextCell *cells;
143
    int text_x[2], text_y[2], cursor_invalidate;
144
    int echo;
145
    bool cursor_visible_phase;
146
    QEMUTimer *cursor_timer;
147

    
148
    int update_x0;
149
    int update_y0;
150
    int update_x1;
151
    int update_y1;
152

    
153
    enum TTYState state;
154
    int esc_params[MAX_ESC_PARAMS];
155
    int nb_esc_params;
156

    
157
    CharDriverState *chr;
158
    /* fifo for key pressed */
159
    QEMUFIFO out_fifo;
160
    uint8_t out_fifo_buf[16];
161
    QEMUTimer *kbd_timer;
162
};
163

    
164
static DisplayState *display_state;
165
static QemuConsole *active_console;
166
static QemuConsole *consoles[MAX_CONSOLES];
167
static int nb_consoles = 0;
168

    
169
void vga_hw_update(void)
170
{
171
    if (active_console && active_console->hw_update)
172
        active_console->hw_update(active_console->hw);
173
}
174

    
175
void vga_hw_invalidate(void)
176
{
177
    if (active_console && active_console->hw_invalidate)
178
        active_console->hw_invalidate(active_console->hw);
179
}
180

    
181
void qmp_screendump(const char *filename, Error **errp)
182
{
183
    QemuConsole *previous_active_console;
184
    bool cswitch;
185

    
186
    previous_active_console = active_console;
187
    cswitch = previous_active_console && previous_active_console->index != 0;
188

    
189
    /* There is currently no way of specifying which screen we want to dump,
190
       so always dump the first one.  */
191
    if (cswitch) {
192
        console_select(0);
193
    }
194
    if (consoles[0] && consoles[0]->hw_screen_dump) {
195
        consoles[0]->hw_screen_dump(consoles[0]->hw, filename, cswitch, errp);
196
    } else {
197
        error_setg(errp, "device doesn't support screendump");
198
    }
199

    
200
    if (cswitch) {
201
        console_select(previous_active_console->index);
202
    }
203
}
204

    
205
void vga_hw_text_update(console_ch_t *chardata)
206
{
207
    if (active_console && active_console->hw_text_update)
208
        active_console->hw_text_update(active_console->hw, chardata);
209
}
210

    
211
/* convert a RGBA color to a color index usable in graphic primitives */
212
static unsigned int vga_get_color(DisplayState *ds, unsigned int rgba)
213
{
214
    unsigned int r, g, b, color;
215

    
216
    switch(ds_get_bits_per_pixel(ds)) {
217
#if 0
218
    case 8:
219
        r = (rgba >> 16) & 0xff;
220
        g = (rgba >> 8) & 0xff;
221
        b = (rgba) & 0xff;
222
        color = (rgb_to_index[r] * 6 * 6) +
223
            (rgb_to_index[g] * 6) +
224
            (rgb_to_index[b]);
225
        break;
226
#endif
227
    case 15:
228
        r = (rgba >> 16) & 0xff;
229
        g = (rgba >> 8) & 0xff;
230
        b = (rgba) & 0xff;
231
        color = ((r >> 3) << 10) | ((g >> 3) << 5) | (b >> 3);
232
        break;
233
    case 16:
234
        r = (rgba >> 16) & 0xff;
235
        g = (rgba >> 8) & 0xff;
236
        b = (rgba) & 0xff;
237
        color = ((r >> 3) << 11) | ((g >> 2) << 5) | (b >> 3);
238
        break;
239
    case 32:
240
    default:
241
        color = rgba;
242
        break;
243
    }
244
    return color;
245
}
246

    
247
static void vga_fill_rect (DisplayState *ds,
248
                           int posx, int posy, int width, int height, uint32_t color)
249
{
250
    uint8_t *d, *d1;
251
    int x, y, bpp;
252

    
253
    bpp = (ds_get_bits_per_pixel(ds) + 7) >> 3;
254
    d1 = ds_get_data(ds) +
255
        ds_get_linesize(ds) * posy + bpp * posx;
256
    for (y = 0; y < height; y++) {
257
        d = d1;
258
        switch(bpp) {
259
        case 1:
260
            for (x = 0; x < width; x++) {
261
                *((uint8_t *)d) = color;
262
                d++;
263
            }
264
            break;
265
        case 2:
266
            for (x = 0; x < width; x++) {
267
                *((uint16_t *)d) = color;
268
                d += 2;
269
            }
270
            break;
271
        case 4:
272
            for (x = 0; x < width; x++) {
273
                *((uint32_t *)d) = color;
274
                d += 4;
275
            }
276
            break;
277
        }
278
        d1 += ds_get_linesize(ds);
279
    }
280
}
281

    
282
/* copy from (xs, ys) to (xd, yd) a rectangle of size (w, h) */
283
static void vga_bitblt(DisplayState *ds, int xs, int ys, int xd, int yd, int w, int h)
284
{
285
    const uint8_t *s;
286
    uint8_t *d;
287
    int wb, y, bpp;
288

    
289
    bpp = (ds_get_bits_per_pixel(ds) + 7) >> 3;
290
    wb = w * bpp;
291
    if (yd <= ys) {
292
        s = ds_get_data(ds) +
293
            ds_get_linesize(ds) * ys + bpp * xs;
294
        d = ds_get_data(ds) +
295
            ds_get_linesize(ds) * yd + bpp * xd;
296
        for (y = 0; y < h; y++) {
297
            memmove(d, s, wb);
298
            d += ds_get_linesize(ds);
299
            s += ds_get_linesize(ds);
300
        }
301
    } else {
302
        s = ds_get_data(ds) +
303
            ds_get_linesize(ds) * (ys + h - 1) + bpp * xs;
304
        d = ds_get_data(ds) +
305
            ds_get_linesize(ds) * (yd + h - 1) + bpp * xd;
306
       for (y = 0; y < h; y++) {
307
            memmove(d, s, wb);
308
            d -= ds_get_linesize(ds);
309
            s -= ds_get_linesize(ds);
310
        }
311
    }
312
}
313

    
314
/***********************************************************/
315
/* basic char display */
316

    
317
#define FONT_HEIGHT 16
318
#define FONT_WIDTH 8
319

    
320
#include "vgafont.h"
321

    
322
#define cbswap_32(__x) \
323
((uint32_t)( \
324
                (((uint32_t)(__x) & (uint32_t)0x000000ffUL) << 24) | \
325
                (((uint32_t)(__x) & (uint32_t)0x0000ff00UL) <<  8) | \
326
                (((uint32_t)(__x) & (uint32_t)0x00ff0000UL) >>  8) | \
327
                (((uint32_t)(__x) & (uint32_t)0xff000000UL) >> 24) ))
328

    
329
#ifdef HOST_WORDS_BIGENDIAN
330
#define PAT(x) x
331
#else
332
#define PAT(x) cbswap_32(x)
333
#endif
334

    
335
static const uint32_t dmask16[16] = {
336
    PAT(0x00000000),
337
    PAT(0x000000ff),
338
    PAT(0x0000ff00),
339
    PAT(0x0000ffff),
340
    PAT(0x00ff0000),
341
    PAT(0x00ff00ff),
342
    PAT(0x00ffff00),
343
    PAT(0x00ffffff),
344
    PAT(0xff000000),
345
    PAT(0xff0000ff),
346
    PAT(0xff00ff00),
347
    PAT(0xff00ffff),
348
    PAT(0xffff0000),
349
    PAT(0xffff00ff),
350
    PAT(0xffffff00),
351
    PAT(0xffffffff),
352
};
353

    
354
static const uint32_t dmask4[4] = {
355
    PAT(0x00000000),
356
    PAT(0x0000ffff),
357
    PAT(0xffff0000),
358
    PAT(0xffffffff),
359
};
360

    
361
static uint32_t color_table[2][8];
362

    
363
#ifndef CONFIG_CURSES
364
enum color_names {
365
    COLOR_BLACK   = 0,
366
    COLOR_RED     = 1,
367
    COLOR_GREEN   = 2,
368
    COLOR_YELLOW  = 3,
369
    COLOR_BLUE    = 4,
370
    COLOR_MAGENTA = 5,
371
    COLOR_CYAN    = 6,
372
    COLOR_WHITE   = 7
373
};
374
#endif
375

    
376
static const uint32_t color_table_rgb[2][8] = {
377
    {   /* dark */
378
        QEMU_RGB(0x00, 0x00, 0x00),  /* black */
379
        QEMU_RGB(0xaa, 0x00, 0x00),  /* red */
380
        QEMU_RGB(0x00, 0xaa, 0x00),  /* green */
381
        QEMU_RGB(0xaa, 0xaa, 0x00),  /* yellow */
382
        QEMU_RGB(0x00, 0x00, 0xaa),  /* blue */
383
        QEMU_RGB(0xaa, 0x00, 0xaa),  /* magenta */
384
        QEMU_RGB(0x00, 0xaa, 0xaa),  /* cyan */
385
        QEMU_RGB(0xaa, 0xaa, 0xaa),  /* white */
386
    },
387
    {   /* bright */
388
        QEMU_RGB(0x00, 0x00, 0x00),  /* black */
389
        QEMU_RGB(0xff, 0x00, 0x00),  /* red */
390
        QEMU_RGB(0x00, 0xff, 0x00),  /* green */
391
        QEMU_RGB(0xff, 0xff, 0x00),  /* yellow */
392
        QEMU_RGB(0x00, 0x00, 0xff),  /* blue */
393
        QEMU_RGB(0xff, 0x00, 0xff),  /* magenta */
394
        QEMU_RGB(0x00, 0xff, 0xff),  /* cyan */
395
        QEMU_RGB(0xff, 0xff, 0xff),  /* white */
396
    }
397
};
398

    
399
static inline unsigned int col_expand(DisplayState *ds, unsigned int col)
400
{
401
    switch(ds_get_bits_per_pixel(ds)) {
402
    case 8:
403
        col |= col << 8;
404
        col |= col << 16;
405
        break;
406
    case 15:
407
    case 16:
408
        col |= col << 16;
409
        break;
410
    default:
411
        break;
412
    }
413

    
414
    return col;
415
}
416
#ifdef DEBUG_CONSOLE
417
static void console_print_text_attributes(TextAttributes *t_attrib, char ch)
418
{
419
    if (t_attrib->bold) {
420
        printf("b");
421
    } else {
422
        printf(" ");
423
    }
424
    if (t_attrib->uline) {
425
        printf("u");
426
    } else {
427
        printf(" ");
428
    }
429
    if (t_attrib->blink) {
430
        printf("l");
431
    } else {
432
        printf(" ");
433
    }
434
    if (t_attrib->invers) {
435
        printf("i");
436
    } else {
437
        printf(" ");
438
    }
439
    if (t_attrib->unvisible) {
440
        printf("n");
441
    } else {
442
        printf(" ");
443
    }
444

    
445
    printf(" fg: %d bg: %d ch:'%2X' '%c'\n", t_attrib->fgcol, t_attrib->bgcol, ch, ch);
446
}
447
#endif
448

    
449
static void vga_putcharxy(DisplayState *ds, int x, int y, int ch,
450
                          TextAttributes *t_attrib)
451
{
452
    uint8_t *d;
453
    const uint8_t *font_ptr;
454
    unsigned int font_data, linesize, xorcol, bpp;
455
    int i;
456
    unsigned int fgcol, bgcol;
457

    
458
#ifdef DEBUG_CONSOLE
459
    printf("x: %2i y: %2i", x, y);
460
    console_print_text_attributes(t_attrib, ch);
461
#endif
462

    
463
    if (t_attrib->invers) {
464
        bgcol = color_table[t_attrib->bold][t_attrib->fgcol];
465
        fgcol = color_table[t_attrib->bold][t_attrib->bgcol];
466
    } else {
467
        fgcol = color_table[t_attrib->bold][t_attrib->fgcol];
468
        bgcol = color_table[t_attrib->bold][t_attrib->bgcol];
469
    }
470

    
471
    bpp = (ds_get_bits_per_pixel(ds) + 7) >> 3;
472
    d = ds_get_data(ds) +
473
        ds_get_linesize(ds) * y * FONT_HEIGHT + bpp * x * FONT_WIDTH;
474
    linesize = ds_get_linesize(ds);
475
    font_ptr = vgafont16 + FONT_HEIGHT * ch;
476
    xorcol = bgcol ^ fgcol;
477
    switch(ds_get_bits_per_pixel(ds)) {
478
    case 8:
479
        for(i = 0; i < FONT_HEIGHT; i++) {
480
            font_data = *font_ptr++;
481
            if (t_attrib->uline
482
                && ((i == FONT_HEIGHT - 2) || (i == FONT_HEIGHT - 3))) {
483
                font_data = 0xFF;
484
            }
485
            ((uint32_t *)d)[0] = (dmask16[(font_data >> 4)] & xorcol) ^ bgcol;
486
            ((uint32_t *)d)[1] = (dmask16[(font_data >> 0) & 0xf] & xorcol) ^ bgcol;
487
            d += linesize;
488
        }
489
        break;
490
    case 16:
491
    case 15:
492
        for(i = 0; i < FONT_HEIGHT; i++) {
493
            font_data = *font_ptr++;
494
            if (t_attrib->uline
495
                && ((i == FONT_HEIGHT - 2) || (i == FONT_HEIGHT - 3))) {
496
                font_data = 0xFF;
497
            }
498
            ((uint32_t *)d)[0] = (dmask4[(font_data >> 6)] & xorcol) ^ bgcol;
499
            ((uint32_t *)d)[1] = (dmask4[(font_data >> 4) & 3] & xorcol) ^ bgcol;
500
            ((uint32_t *)d)[2] = (dmask4[(font_data >> 2) & 3] & xorcol) ^ bgcol;
501
            ((uint32_t *)d)[3] = (dmask4[(font_data >> 0) & 3] & xorcol) ^ bgcol;
502
            d += linesize;
503
        }
504
        break;
505
    case 32:
506
        for(i = 0; i < FONT_HEIGHT; i++) {
507
            font_data = *font_ptr++;
508
            if (t_attrib->uline && ((i == FONT_HEIGHT - 2) || (i == FONT_HEIGHT - 3))) {
509
                font_data = 0xFF;
510
            }
511
            ((uint32_t *)d)[0] = (-((font_data >> 7)) & xorcol) ^ bgcol;
512
            ((uint32_t *)d)[1] = (-((font_data >> 6) & 1) & xorcol) ^ bgcol;
513
            ((uint32_t *)d)[2] = (-((font_data >> 5) & 1) & xorcol) ^ bgcol;
514
            ((uint32_t *)d)[3] = (-((font_data >> 4) & 1) & xorcol) ^ bgcol;
515
            ((uint32_t *)d)[4] = (-((font_data >> 3) & 1) & xorcol) ^ bgcol;
516
            ((uint32_t *)d)[5] = (-((font_data >> 2) & 1) & xorcol) ^ bgcol;
517
            ((uint32_t *)d)[6] = (-((font_data >> 1) & 1) & xorcol) ^ bgcol;
518
            ((uint32_t *)d)[7] = (-((font_data >> 0) & 1) & xorcol) ^ bgcol;
519
            d += linesize;
520
        }
521
        break;
522
    }
523
}
524

    
525
static void text_console_resize(QemuConsole *s)
526
{
527
    TextCell *cells, *c, *c1;
528
    int w1, x, y, last_width;
529

    
530
    last_width = s->width;
531
    s->width = s->g_width / FONT_WIDTH;
532
    s->height = s->g_height / FONT_HEIGHT;
533

    
534
    w1 = last_width;
535
    if (s->width < w1)
536
        w1 = s->width;
537

    
538
    cells = g_malloc(s->width * s->total_height * sizeof(TextCell));
539
    for(y = 0; y < s->total_height; y++) {
540
        c = &cells[y * s->width];
541
        if (w1 > 0) {
542
            c1 = &s->cells[y * last_width];
543
            for(x = 0; x < w1; x++) {
544
                *c++ = *c1++;
545
            }
546
        }
547
        for(x = w1; x < s->width; x++) {
548
            c->ch = ' ';
549
            c->t_attrib = s->t_attrib_default;
550
            c++;
551
        }
552
    }
553
    g_free(s->cells);
554
    s->cells = cells;
555
}
556

    
557
static inline void text_update_xy(QemuConsole *s, int x, int y)
558
{
559
    s->text_x[0] = MIN(s->text_x[0], x);
560
    s->text_x[1] = MAX(s->text_x[1], x);
561
    s->text_y[0] = MIN(s->text_y[0], y);
562
    s->text_y[1] = MAX(s->text_y[1], y);
563
}
564

    
565
static void invalidate_xy(QemuConsole *s, int x, int y)
566
{
567
    if (s->update_x0 > x * FONT_WIDTH)
568
        s->update_x0 = x * FONT_WIDTH;
569
    if (s->update_y0 > y * FONT_HEIGHT)
570
        s->update_y0 = y * FONT_HEIGHT;
571
    if (s->update_x1 < (x + 1) * FONT_WIDTH)
572
        s->update_x1 = (x + 1) * FONT_WIDTH;
573
    if (s->update_y1 < (y + 1) * FONT_HEIGHT)
574
        s->update_y1 = (y + 1) * FONT_HEIGHT;
575
}
576

    
577
static void update_xy(QemuConsole *s, int x, int y)
578
{
579
    TextCell *c;
580
    int y1, y2;
581

    
582
    if (s == active_console) {
583
        if (!ds_get_bits_per_pixel(s->ds)) {
584
            text_update_xy(s, x, y);
585
            return;
586
        }
587

    
588
        y1 = (s->y_base + y) % s->total_height;
589
        y2 = y1 - s->y_displayed;
590
        if (y2 < 0)
591
            y2 += s->total_height;
592
        if (y2 < s->height) {
593
            c = &s->cells[y1 * s->width + x];
594
            vga_putcharxy(s->ds, x, y2, c->ch,
595
                          &(c->t_attrib));
596
            invalidate_xy(s, x, y2);
597
        }
598
    }
599
}
600

    
601
static void console_show_cursor(QemuConsole *s, int show)
602
{
603
    TextCell *c;
604
    int y, y1;
605

    
606
    if (s == active_console) {
607
        int x = s->x;
608

    
609
        if (!ds_get_bits_per_pixel(s->ds)) {
610
            s->cursor_invalidate = 1;
611
            return;
612
        }
613

    
614
        if (x >= s->width) {
615
            x = s->width - 1;
616
        }
617
        y1 = (s->y_base + s->y) % s->total_height;
618
        y = y1 - s->y_displayed;
619
        if (y < 0)
620
            y += s->total_height;
621
        if (y < s->height) {
622
            c = &s->cells[y1 * s->width + x];
623
            if (show && s->cursor_visible_phase) {
624
                TextAttributes t_attrib = s->t_attrib_default;
625
                t_attrib.invers = !(t_attrib.invers); /* invert fg and bg */
626
                vga_putcharxy(s->ds, x, y, c->ch, &t_attrib);
627
            } else {
628
                vga_putcharxy(s->ds, x, y, c->ch, &(c->t_attrib));
629
            }
630
            invalidate_xy(s, x, y);
631
        }
632
    }
633
}
634

    
635
static void console_refresh(QemuConsole *s)
636
{
637
    TextCell *c;
638
    int x, y, y1;
639

    
640
    if (s != active_console)
641
        return;
642

    
643
    if (s->ds->have_text) {
644
        s->text_x[0] = 0;
645
        s->text_y[0] = 0;
646
        s->text_x[1] = s->width - 1;
647
        s->text_y[1] = s->height - 1;
648
        s->cursor_invalidate = 1;
649
    }
650

    
651
    if (s->ds->have_gfx) {
652
        vga_fill_rect(s->ds, 0, 0, ds_get_width(s->ds), ds_get_height(s->ds),
653
                      color_table[0][COLOR_BLACK]);
654
        y1 = s->y_displayed;
655
        for (y = 0; y < s->height; y++) {
656
            c = s->cells + y1 * s->width;
657
            for (x = 0; x < s->width; x++) {
658
                vga_putcharxy(s->ds, x, y, c->ch,
659
                              &(c->t_attrib));
660
                c++;
661
            }
662
            if (++y1 == s->total_height) {
663
                y1 = 0;
664
            }
665
        }
666
        console_show_cursor(s, 1);
667
        dpy_gfx_update(s->ds, 0, 0, ds_get_width(s->ds), ds_get_height(s->ds));
668
    }
669
}
670

    
671
static void console_scroll(int ydelta)
672
{
673
    QemuConsole *s;
674
    int i, y1;
675

    
676
    s = active_console;
677
    if (!s || (s->console_type == GRAPHIC_CONSOLE))
678
        return;
679

    
680
    if (ydelta > 0) {
681
        for(i = 0; i < ydelta; i++) {
682
            if (s->y_displayed == s->y_base)
683
                break;
684
            if (++s->y_displayed == s->total_height)
685
                s->y_displayed = 0;
686
        }
687
    } else {
688
        ydelta = -ydelta;
689
        i = s->backscroll_height;
690
        if (i > s->total_height - s->height)
691
            i = s->total_height - s->height;
692
        y1 = s->y_base - i;
693
        if (y1 < 0)
694
            y1 += s->total_height;
695
        for(i = 0; i < ydelta; i++) {
696
            if (s->y_displayed == y1)
697
                break;
698
            if (--s->y_displayed < 0)
699
                s->y_displayed = s->total_height - 1;
700
        }
701
    }
702
    console_refresh(s);
703
}
704

    
705
static void console_put_lf(QemuConsole *s)
706
{
707
    TextCell *c;
708
    int x, y1;
709

    
710
    s->y++;
711
    if (s->y >= s->height) {
712
        s->y = s->height - 1;
713

    
714
        if (s->y_displayed == s->y_base) {
715
            if (++s->y_displayed == s->total_height)
716
                s->y_displayed = 0;
717
        }
718
        if (++s->y_base == s->total_height)
719
            s->y_base = 0;
720
        if (s->backscroll_height < s->total_height)
721
            s->backscroll_height++;
722
        y1 = (s->y_base + s->height - 1) % s->total_height;
723
        c = &s->cells[y1 * s->width];
724
        for(x = 0; x < s->width; x++) {
725
            c->ch = ' ';
726
            c->t_attrib = s->t_attrib_default;
727
            c++;
728
        }
729
        if (s == active_console && s->y_displayed == s->y_base) {
730
            if (!ds_get_bits_per_pixel(s->ds)) {
731
                s->text_x[0] = 0;
732
                s->text_y[0] = 0;
733
                s->text_x[1] = s->width - 1;
734
                s->text_y[1] = s->height - 1;
735
                return;
736
            }
737

    
738
            vga_bitblt(s->ds, 0, FONT_HEIGHT, 0, 0,
739
                       s->width * FONT_WIDTH,
740
                       (s->height - 1) * FONT_HEIGHT);
741
            vga_fill_rect(s->ds, 0, (s->height - 1) * FONT_HEIGHT,
742
                          s->width * FONT_WIDTH, FONT_HEIGHT,
743
                          color_table[0][s->t_attrib_default.bgcol]);
744
            s->update_x0 = 0;
745
            s->update_y0 = 0;
746
            s->update_x1 = s->width * FONT_WIDTH;
747
            s->update_y1 = s->height * FONT_HEIGHT;
748
        }
749
    }
750
}
751

    
752
/* Set console attributes depending on the current escape codes.
753
 * NOTE: I know this code is not very efficient (checking every color for it
754
 * self) but it is more readable and better maintainable.
755
 */
756
static void console_handle_escape(QemuConsole *s)
757
{
758
    int i;
759

    
760
    for (i=0; i<s->nb_esc_params; i++) {
761
        switch (s->esc_params[i]) {
762
            case 0: /* reset all console attributes to default */
763
                s->t_attrib = s->t_attrib_default;
764
                break;
765
            case 1:
766
                s->t_attrib.bold = 1;
767
                break;
768
            case 4:
769
                s->t_attrib.uline = 1;
770
                break;
771
            case 5:
772
                s->t_attrib.blink = 1;
773
                break;
774
            case 7:
775
                s->t_attrib.invers = 1;
776
                break;
777
            case 8:
778
                s->t_attrib.unvisible = 1;
779
                break;
780
            case 22:
781
                s->t_attrib.bold = 0;
782
                break;
783
            case 24:
784
                s->t_attrib.uline = 0;
785
                break;
786
            case 25:
787
                s->t_attrib.blink = 0;
788
                break;
789
            case 27:
790
                s->t_attrib.invers = 0;
791
                break;
792
            case 28:
793
                s->t_attrib.unvisible = 0;
794
                break;
795
            /* set foreground color */
796
            case 30:
797
                s->t_attrib.fgcol=COLOR_BLACK;
798
                break;
799
            case 31:
800
                s->t_attrib.fgcol=COLOR_RED;
801
                break;
802
            case 32:
803
                s->t_attrib.fgcol=COLOR_GREEN;
804
                break;
805
            case 33:
806
                s->t_attrib.fgcol=COLOR_YELLOW;
807
                break;
808
            case 34:
809
                s->t_attrib.fgcol=COLOR_BLUE;
810
                break;
811
            case 35:
812
                s->t_attrib.fgcol=COLOR_MAGENTA;
813
                break;
814
            case 36:
815
                s->t_attrib.fgcol=COLOR_CYAN;
816
                break;
817
            case 37:
818
                s->t_attrib.fgcol=COLOR_WHITE;
819
                break;
820
            /* set background color */
821
            case 40:
822
                s->t_attrib.bgcol=COLOR_BLACK;
823
                break;
824
            case 41:
825
                s->t_attrib.bgcol=COLOR_RED;
826
                break;
827
            case 42:
828
                s->t_attrib.bgcol=COLOR_GREEN;
829
                break;
830
            case 43:
831
                s->t_attrib.bgcol=COLOR_YELLOW;
832
                break;
833
            case 44:
834
                s->t_attrib.bgcol=COLOR_BLUE;
835
                break;
836
            case 45:
837
                s->t_attrib.bgcol=COLOR_MAGENTA;
838
                break;
839
            case 46:
840
                s->t_attrib.bgcol=COLOR_CYAN;
841
                break;
842
            case 47:
843
                s->t_attrib.bgcol=COLOR_WHITE;
844
                break;
845
        }
846
    }
847
}
848

    
849
static void console_clear_xy(QemuConsole *s, int x, int y)
850
{
851
    int y1 = (s->y_base + y) % s->total_height;
852
    TextCell *c = &s->cells[y1 * s->width + x];
853
    c->ch = ' ';
854
    c->t_attrib = s->t_attrib_default;
855
    update_xy(s, x, y);
856
}
857

    
858
/* set cursor, checking bounds */
859
static void set_cursor(QemuConsole *s, int x, int y)
860
{
861
    if (x < 0) {
862
        x = 0;
863
    }
864
    if (y < 0) {
865
        y = 0;
866
    }
867
    if (y >= s->height) {
868
        y = s->height - 1;
869
    }
870
    if (x >= s->width) {
871
        x = s->width - 1;
872
    }
873

    
874
    s->x = x;
875
    s->y = y;
876
}
877

    
878
static void console_putchar(QemuConsole *s, int ch)
879
{
880
    TextCell *c;
881
    int y1, i;
882
    int x, y;
883

    
884
    switch(s->state) {
885
    case TTY_STATE_NORM:
886
        switch(ch) {
887
        case '\r':  /* carriage return */
888
            s->x = 0;
889
            break;
890
        case '\n':  /* newline */
891
            console_put_lf(s);
892
            break;
893
        case '\b':  /* backspace */
894
            if (s->x > 0)
895
                s->x--;
896
            break;
897
        case '\t':  /* tabspace */
898
            if (s->x + (8 - (s->x % 8)) > s->width) {
899
                s->x = 0;
900
                console_put_lf(s);
901
            } else {
902
                s->x = s->x + (8 - (s->x % 8));
903
            }
904
            break;
905
        case '\a':  /* alert aka. bell */
906
            /* TODO: has to be implemented */
907
            break;
908
        case 14:
909
            /* SI (shift in), character set 0 (ignored) */
910
            break;
911
        case 15:
912
            /* SO (shift out), character set 1 (ignored) */
913
            break;
914
        case 27:    /* esc (introducing an escape sequence) */
915
            s->state = TTY_STATE_ESC;
916
            break;
917
        default:
918
            if (s->x >= s->width) {
919
                /* line wrap */
920
                s->x = 0;
921
                console_put_lf(s);
922
            }
923
            y1 = (s->y_base + s->y) % s->total_height;
924
            c = &s->cells[y1 * s->width + s->x];
925
            c->ch = ch;
926
            c->t_attrib = s->t_attrib;
927
            update_xy(s, s->x, s->y);
928
            s->x++;
929
            break;
930
        }
931
        break;
932
    case TTY_STATE_ESC: /* check if it is a terminal escape sequence */
933
        if (ch == '[') {
934
            for(i=0;i<MAX_ESC_PARAMS;i++)
935
                s->esc_params[i] = 0;
936
            s->nb_esc_params = 0;
937
            s->state = TTY_STATE_CSI;
938
        } else {
939
            s->state = TTY_STATE_NORM;
940
        }
941
        break;
942
    case TTY_STATE_CSI: /* handle escape sequence parameters */
943
        if (ch >= '0' && ch <= '9') {
944
            if (s->nb_esc_params < MAX_ESC_PARAMS) {
945
                int *param = &s->esc_params[s->nb_esc_params];
946
                int digit = (ch - '0');
947

    
948
                *param = (*param <= (INT_MAX - digit) / 10) ?
949
                         *param * 10 + digit : INT_MAX;
950
            }
951
        } else {
952
            if (s->nb_esc_params < MAX_ESC_PARAMS)
953
                s->nb_esc_params++;
954
            if (ch == ';')
955
                break;
956
#ifdef DEBUG_CONSOLE
957
            fprintf(stderr, "escape sequence CSI%d;%d%c, %d parameters\n",
958
                    s->esc_params[0], s->esc_params[1], ch, s->nb_esc_params);
959
#endif
960
            s->state = TTY_STATE_NORM;
961
            switch(ch) {
962
            case 'A':
963
                /* move cursor up */
964
                if (s->esc_params[0] == 0) {
965
                    s->esc_params[0] = 1;
966
                }
967
                set_cursor(s, s->x, s->y - s->esc_params[0]);
968
                break;
969
            case 'B':
970
                /* move cursor down */
971
                if (s->esc_params[0] == 0) {
972
                    s->esc_params[0] = 1;
973
                }
974
                set_cursor(s, s->x, s->y + s->esc_params[0]);
975
                break;
976
            case 'C':
977
                /* move cursor right */
978
                if (s->esc_params[0] == 0) {
979
                    s->esc_params[0] = 1;
980
                }
981
                set_cursor(s, s->x + s->esc_params[0], s->y);
982
                break;
983
            case 'D':
984
                /* move cursor left */
985
                if (s->esc_params[0] == 0) {
986
                    s->esc_params[0] = 1;
987
                }
988
                set_cursor(s, s->x - s->esc_params[0], s->y);
989
                break;
990
            case 'G':
991
                /* move cursor to column */
992
                set_cursor(s, s->esc_params[0] - 1, s->y);
993
                break;
994
            case 'f':
995
            case 'H':
996
                /* move cursor to row, column */
997
                set_cursor(s, s->esc_params[1] - 1, s->esc_params[0] - 1);
998
                break;
999
            case 'J':
1000
                switch (s->esc_params[0]) {
1001
                case 0:
1002
                    /* clear to end of screen */
1003
                    for (y = s->y; y < s->height; y++) {
1004
                        for (x = 0; x < s->width; x++) {
1005
                            if (y == s->y && x < s->x) {
1006
                                continue;
1007
                            }
1008
                            console_clear_xy(s, x, y);
1009
                        }
1010
                    }
1011
                    break;
1012
                case 1:
1013
                    /* clear from beginning of screen */
1014
                    for (y = 0; y <= s->y; y++) {
1015
                        for (x = 0; x < s->width; x++) {
1016
                            if (y == s->y && x > s->x) {
1017
                                break;
1018
                            }
1019
                            console_clear_xy(s, x, y);
1020
                        }
1021
                    }
1022
                    break;
1023
                case 2:
1024
                    /* clear entire screen */
1025
                    for (y = 0; y <= s->height; y++) {
1026
                        for (x = 0; x < s->width; x++) {
1027
                            console_clear_xy(s, x, y);
1028
                        }
1029
                    }
1030
                    break;
1031
                }
1032
                break;
1033
            case 'K':
1034
                switch (s->esc_params[0]) {
1035
                case 0:
1036
                    /* clear to eol */
1037
                    for(x = s->x; x < s->width; x++) {
1038
                        console_clear_xy(s, x, s->y);
1039
                    }
1040
                    break;
1041
                case 1:
1042
                    /* clear from beginning of line */
1043
                    for (x = 0; x <= s->x; x++) {
1044
                        console_clear_xy(s, x, s->y);
1045
                    }
1046
                    break;
1047
                case 2:
1048
                    /* clear entire line */
1049
                    for(x = 0; x < s->width; x++) {
1050
                        console_clear_xy(s, x, s->y);
1051
                    }
1052
                    break;
1053
                }
1054
                break;
1055
            case 'm':
1056
                console_handle_escape(s);
1057
                break;
1058
            case 'n':
1059
                /* report cursor position */
1060
                /* TODO: send ESC[row;colR */
1061
                break;
1062
            case 's':
1063
                /* save cursor position */
1064
                s->x_saved = s->x;
1065
                s->y_saved = s->y;
1066
                break;
1067
            case 'u':
1068
                /* restore cursor position */
1069
                s->x = s->x_saved;
1070
                s->y = s->y_saved;
1071
                break;
1072
            default:
1073
#ifdef DEBUG_CONSOLE
1074
                fprintf(stderr, "unhandled escape character '%c'\n", ch);
1075
#endif
1076
                break;
1077
            }
1078
            break;
1079
        }
1080
    }
1081
}
1082

    
1083
void console_select(unsigned int index)
1084
{
1085
    QemuConsole *s;
1086

    
1087
    if (index >= MAX_CONSOLES)
1088
        return;
1089
    if (active_console) {
1090
        active_console->g_width = ds_get_width(active_console->ds);
1091
        active_console->g_height = ds_get_height(active_console->ds);
1092
    }
1093
    s = consoles[index];
1094
    if (s) {
1095
        DisplayState *ds = s->ds;
1096

    
1097
        if (active_console && active_console->cursor_timer) {
1098
            qemu_del_timer(active_console->cursor_timer);
1099
        }
1100
        active_console = s;
1101
        if (ds->have_gfx) {
1102
            ds->surface = qemu_resize_displaysurface(ds, s->g_width, s->g_height);
1103
            dpy_gfx_resize(ds);
1104
        }
1105
        if (ds->have_text) {
1106
            dpy_text_resize(ds, s->width, s->height);
1107
        }
1108
        if (s->cursor_timer) {
1109
            qemu_mod_timer(s->cursor_timer,
1110
                   qemu_get_clock_ms(rt_clock) + CONSOLE_CURSOR_PERIOD / 2);
1111
        }
1112
        vga_hw_invalidate();
1113
    }
1114
}
1115

    
1116
static int console_puts(CharDriverState *chr, const uint8_t *buf, int len)
1117
{
1118
    QemuConsole *s = chr->opaque;
1119
    int i;
1120

    
1121
    s->update_x0 = s->width * FONT_WIDTH;
1122
    s->update_y0 = s->height * FONT_HEIGHT;
1123
    s->update_x1 = 0;
1124
    s->update_y1 = 0;
1125
    console_show_cursor(s, 0);
1126
    for(i = 0; i < len; i++) {
1127
        console_putchar(s, buf[i]);
1128
    }
1129
    console_show_cursor(s, 1);
1130
    if (s->ds->have_gfx && s->update_x0 < s->update_x1) {
1131
        dpy_gfx_update(s->ds, s->update_x0, s->update_y0,
1132
                       s->update_x1 - s->update_x0,
1133
                       s->update_y1 - s->update_y0);
1134
    }
1135
    return len;
1136
}
1137

    
1138
static void kbd_send_chars(void *opaque)
1139
{
1140
    QemuConsole *s = opaque;
1141
    int len;
1142
    uint8_t buf[16];
1143

    
1144
    len = qemu_chr_be_can_write(s->chr);
1145
    if (len > s->out_fifo.count)
1146
        len = s->out_fifo.count;
1147
    if (len > 0) {
1148
        if (len > sizeof(buf))
1149
            len = sizeof(buf);
1150
        qemu_fifo_read(&s->out_fifo, buf, len);
1151
        qemu_chr_be_write(s->chr, buf, len);
1152
    }
1153
    /* characters are pending: we send them a bit later (XXX:
1154
       horrible, should change char device API) */
1155
    if (s->out_fifo.count > 0) {
1156
        qemu_mod_timer(s->kbd_timer, qemu_get_clock_ms(rt_clock) + 1);
1157
    }
1158
}
1159

    
1160
/* called when an ascii key is pressed */
1161
void kbd_put_keysym(int keysym)
1162
{
1163
    QemuConsole *s;
1164
    uint8_t buf[16], *q;
1165
    int c;
1166

    
1167
    s = active_console;
1168
    if (!s || (s->console_type == GRAPHIC_CONSOLE))
1169
        return;
1170

    
1171
    switch(keysym) {
1172
    case QEMU_KEY_CTRL_UP:
1173
        console_scroll(-1);
1174
        break;
1175
    case QEMU_KEY_CTRL_DOWN:
1176
        console_scroll(1);
1177
        break;
1178
    case QEMU_KEY_CTRL_PAGEUP:
1179
        console_scroll(-10);
1180
        break;
1181
    case QEMU_KEY_CTRL_PAGEDOWN:
1182
        console_scroll(10);
1183
        break;
1184
    default:
1185
        /* convert the QEMU keysym to VT100 key string */
1186
        q = buf;
1187
        if (keysym >= 0xe100 && keysym <= 0xe11f) {
1188
            *q++ = '\033';
1189
            *q++ = '[';
1190
            c = keysym - 0xe100;
1191
            if (c >= 10)
1192
                *q++ = '0' + (c / 10);
1193
            *q++ = '0' + (c % 10);
1194
            *q++ = '~';
1195
        } else if (keysym >= 0xe120 && keysym <= 0xe17f) {
1196
            *q++ = '\033';
1197
            *q++ = '[';
1198
            *q++ = keysym & 0xff;
1199
        } else if (s->echo && (keysym == '\r' || keysym == '\n')) {
1200
            console_puts(s->chr, (const uint8_t *) "\r", 1);
1201
            *q++ = '\n';
1202
        } else {
1203
            *q++ = keysym;
1204
        }
1205
        if (s->echo) {
1206
            console_puts(s->chr, buf, q - buf);
1207
        }
1208
        if (s->chr->chr_read) {
1209
            qemu_fifo_write(&s->out_fifo, buf, q - buf);
1210
            kbd_send_chars(s);
1211
        }
1212
        break;
1213
    }
1214
}
1215

    
1216
static void text_console_invalidate(void *opaque)
1217
{
1218
    QemuConsole *s = (QemuConsole *) opaque;
1219
    if (!ds_get_bits_per_pixel(s->ds) && s->console_type == TEXT_CONSOLE) {
1220
        s->g_width = ds_get_width(s->ds);
1221
        s->g_height = ds_get_height(s->ds);
1222
        text_console_resize(s);
1223
    }
1224
    console_refresh(s);
1225
}
1226

    
1227
static void text_console_update(void *opaque, console_ch_t *chardata)
1228
{
1229
    QemuConsole *s = (QemuConsole *) opaque;
1230
    int i, j, src;
1231

    
1232
    if (s->text_x[0] <= s->text_x[1]) {
1233
        src = (s->y_base + s->text_y[0]) * s->width;
1234
        chardata += s->text_y[0] * s->width;
1235
        for (i = s->text_y[0]; i <= s->text_y[1]; i ++)
1236
            for (j = 0; j < s->width; j ++, src ++)
1237
                console_write_ch(chardata ++, s->cells[src].ch |
1238
                                (s->cells[src].t_attrib.fgcol << 12) |
1239
                                (s->cells[src].t_attrib.bgcol << 8) |
1240
                                (s->cells[src].t_attrib.bold << 21));
1241
        dpy_text_update(s->ds, s->text_x[0], s->text_y[0],
1242
                        s->text_x[1] - s->text_x[0], i - s->text_y[0]);
1243
        s->text_x[0] = s->width;
1244
        s->text_y[0] = s->height;
1245
        s->text_x[1] = 0;
1246
        s->text_y[1] = 0;
1247
    }
1248
    if (s->cursor_invalidate) {
1249
        dpy_text_cursor(s->ds, s->x, s->y);
1250
        s->cursor_invalidate = 0;
1251
    }
1252
}
1253

    
1254
static QemuConsole *get_graphic_console(DisplayState *ds)
1255
{
1256
    int i;
1257
    QemuConsole *s;
1258
    for (i = 0; i < nb_consoles; i++) {
1259
        s = consoles[i];
1260
        if (s->console_type == GRAPHIC_CONSOLE && s->ds == ds)
1261
            return s;
1262
    }
1263
    return NULL;
1264
}
1265

    
1266
static QemuConsole *new_console(DisplayState *ds, console_type_t console_type)
1267
{
1268
    QemuConsole *s;
1269
    int i;
1270

    
1271
    if (nb_consoles >= MAX_CONSOLES)
1272
        return NULL;
1273
    s = g_malloc0(sizeof(QemuConsole));
1274
    if (!active_console || ((active_console->console_type != GRAPHIC_CONSOLE) &&
1275
        (console_type == GRAPHIC_CONSOLE))) {
1276
        active_console = s;
1277
    }
1278
    s->ds = ds;
1279
    s->console_type = console_type;
1280
    if (console_type != GRAPHIC_CONSOLE) {
1281
        s->index = nb_consoles;
1282
        consoles[nb_consoles++] = s;
1283
    } else {
1284
        /* HACK: Put graphical consoles before text consoles.  */
1285
        for (i = nb_consoles; i > 0; i--) {
1286
            if (consoles[i - 1]->console_type == GRAPHIC_CONSOLE)
1287
                break;
1288
            consoles[i] = consoles[i - 1];
1289
            consoles[i]->index = i;
1290
        }
1291
        s->index = i;
1292
        consoles[i] = s;
1293
        nb_consoles++;
1294
    }
1295
    return s;
1296
}
1297

    
1298
static void qemu_alloc_display(DisplaySurface *surface, int width, int height,
1299
                               int linesize, PixelFormat pf, int newflags)
1300
{
1301
    surface->pf = pf;
1302

    
1303
    qemu_pixman_image_unref(surface->image);
1304
    surface->image = NULL;
1305

    
1306
    surface->format = qemu_pixman_get_format(&pf);
1307
    assert(surface->format != 0);
1308
    surface->image = pixman_image_create_bits(surface->format,
1309
                                              width, height,
1310
                                              NULL, linesize);
1311
    assert(surface->image != NULL);
1312

    
1313
    surface->flags = newflags | QEMU_ALLOCATED_FLAG;
1314
#ifdef HOST_WORDS_BIGENDIAN
1315
    surface->flags |= QEMU_BIG_ENDIAN_FLAG;
1316
#endif
1317
}
1318

    
1319
DisplaySurface *qemu_create_displaysurface(DisplayState *ds,
1320
                                           int width, int height)
1321
{
1322
    DisplaySurface *surface = g_new0(DisplaySurface, 1);
1323

    
1324
    int linesize = width * 4;
1325
    qemu_alloc_display(surface, width, height, linesize,
1326
                       qemu_default_pixelformat(32), 0);
1327
    return surface;
1328
}
1329

    
1330
DisplaySurface *qemu_resize_displaysurface(DisplayState *ds,
1331
                                           int width, int height)
1332
{
1333
    int linesize = width * 4;
1334

    
1335
    trace_displaysurface_resize(ds, ds->surface, width, height);
1336
    qemu_alloc_display(ds->surface, width, height, linesize,
1337
                       qemu_default_pixelformat(32), 0);
1338
    return ds->surface;
1339
}
1340

    
1341
DisplaySurface *qemu_create_displaysurface_from(int width, int height, int bpp,
1342
                                                int linesize, uint8_t *data,
1343
                                                bool byteswap)
1344
{
1345
    DisplaySurface *surface = g_new0(DisplaySurface, 1);
1346

    
1347
    if (byteswap) {
1348
        surface->pf = qemu_different_endianness_pixelformat(bpp);
1349
    } else {
1350
        surface->pf = qemu_default_pixelformat(bpp);
1351
    }
1352

    
1353
    surface->format = qemu_pixman_get_format(&surface->pf);
1354
    assert(surface->format != 0);
1355
    surface->image = pixman_image_create_bits(surface->format,
1356
                                              width, height,
1357
                                              (void *)data, linesize);
1358
    assert(surface->image != NULL);
1359

    
1360
#ifdef HOST_WORDS_BIGENDIAN
1361
    surface->flags = QEMU_BIG_ENDIAN_FLAG;
1362
#endif
1363

    
1364
    return surface;
1365
}
1366

    
1367
void qemu_free_displaysurface(DisplayState *ds)
1368
{
1369
    trace_displaysurface_free(ds, ds->surface);
1370
    if (ds->surface == NULL) {
1371
        return;
1372
    }
1373
    qemu_pixman_image_unref(ds->surface->image);
1374
    g_free(ds->surface);
1375
}
1376

    
1377
static void dumb_display_init(void)
1378
{
1379
    DisplayState *ds = g_malloc0(sizeof(DisplayState));
1380
    int width = 640;
1381
    int height = 480;
1382

    
1383
    if (is_fixedsize_console()) {
1384
        width = active_console->g_width;
1385
        height = active_console->g_height;
1386
    }
1387
    ds->surface = qemu_create_displaysurface(ds, width, height);
1388
    register_displaystate(ds);
1389
}
1390

    
1391
/***********************************************************/
1392
/* register display */
1393

    
1394
void register_displaystate(DisplayState *ds)
1395
{
1396
    DisplayState **s;
1397
    s = &display_state;
1398
    while (*s != NULL)
1399
        s = &(*s)->next;
1400
    ds->next = NULL;
1401
    *s = ds;
1402
}
1403

    
1404
DisplayState *get_displaystate(void)
1405
{
1406
    if (!display_state) {
1407
        dumb_display_init ();
1408
    }
1409
    return display_state;
1410
}
1411

    
1412
DisplayState *graphic_console_init(vga_hw_update_ptr update,
1413
                                   vga_hw_invalidate_ptr invalidate,
1414
                                   vga_hw_screen_dump_ptr screen_dump,
1415
                                   vga_hw_text_update_ptr text_update,
1416
                                   void *opaque)
1417
{
1418
    QemuConsole *s;
1419
    DisplayState *ds;
1420

    
1421
    ds = (DisplayState *) g_malloc0(sizeof(DisplayState));
1422
    ds->surface = qemu_create_displaysurface(ds, 640, 480);
1423

    
1424
    s = new_console(ds, GRAPHIC_CONSOLE);
1425
    if (s == NULL) {
1426
        qemu_free_displaysurface(ds);
1427
        g_free(ds);
1428
        return NULL;
1429
    }
1430
    s->hw_update = update;
1431
    s->hw_invalidate = invalidate;
1432
    s->hw_screen_dump = screen_dump;
1433
    s->hw_text_update = text_update;
1434
    s->hw = opaque;
1435

    
1436
    register_displaystate(ds);
1437
    return ds;
1438
}
1439

    
1440
int is_graphic_console(void)
1441
{
1442
    return active_console && active_console->console_type == GRAPHIC_CONSOLE;
1443
}
1444

    
1445
int is_fixedsize_console(void)
1446
{
1447
    return active_console && active_console->console_type != TEXT_CONSOLE;
1448
}
1449

    
1450
void console_color_init(DisplayState *ds)
1451
{
1452
    int i, j;
1453
    for (j = 0; j < 2; j++) {
1454
        for (i = 0; i < 8; i++) {
1455
            color_table[j][i] = col_expand(ds,
1456
                   vga_get_color(ds, color_table_rgb[j][i]));
1457
        }
1458
    }
1459
}
1460

    
1461
static void text_console_set_echo(CharDriverState *chr, bool echo)
1462
{
1463
    QemuConsole *s = chr->opaque;
1464

    
1465
    s->echo = echo;
1466
}
1467

    
1468
static void text_console_update_cursor(void *opaque)
1469
{
1470
    QemuConsole *s = opaque;
1471

    
1472
    s->cursor_visible_phase = !s->cursor_visible_phase;
1473
    vga_hw_invalidate();
1474
    qemu_mod_timer(s->cursor_timer,
1475
                   qemu_get_clock_ms(rt_clock) + CONSOLE_CURSOR_PERIOD / 2);
1476
}
1477

    
1478
static void text_console_do_init(CharDriverState *chr, DisplayState *ds)
1479
{
1480
    QemuConsole *s;
1481
    static int color_inited;
1482

    
1483
    s = chr->opaque;
1484

    
1485
    chr->chr_write = console_puts;
1486

    
1487
    s->out_fifo.buf = s->out_fifo_buf;
1488
    s->out_fifo.buf_size = sizeof(s->out_fifo_buf);
1489
    s->kbd_timer = qemu_new_timer_ms(rt_clock, kbd_send_chars, s);
1490
    s->ds = ds;
1491

    
1492
    if (!color_inited) {
1493
        color_inited = 1;
1494
        console_color_init(s->ds);
1495
    }
1496
    s->y_displayed = 0;
1497
    s->y_base = 0;
1498
    s->total_height = DEFAULT_BACKSCROLL;
1499
    s->x = 0;
1500
    s->y = 0;
1501
    if (s->console_type == TEXT_CONSOLE) {
1502
        s->g_width = ds_get_width(s->ds);
1503
        s->g_height = ds_get_height(s->ds);
1504
    }
1505

    
1506
    s->cursor_timer =
1507
        qemu_new_timer_ms(rt_clock, text_console_update_cursor, s);
1508

    
1509
    s->hw_invalidate = text_console_invalidate;
1510
    s->hw_text_update = text_console_update;
1511
    s->hw = s;
1512

    
1513
    /* Set text attribute defaults */
1514
    s->t_attrib_default.bold = 0;
1515
    s->t_attrib_default.uline = 0;
1516
    s->t_attrib_default.blink = 0;
1517
    s->t_attrib_default.invers = 0;
1518
    s->t_attrib_default.unvisible = 0;
1519
    s->t_attrib_default.fgcol = COLOR_WHITE;
1520
    s->t_attrib_default.bgcol = COLOR_BLACK;
1521
    /* set current text attributes to default */
1522
    s->t_attrib = s->t_attrib_default;
1523
    text_console_resize(s);
1524

    
1525
    if (chr->label) {
1526
        char msg[128];
1527
        int len;
1528

    
1529
        s->t_attrib.bgcol = COLOR_BLUE;
1530
        len = snprintf(msg, sizeof(msg), "%s console\r\n", chr->label);
1531
        console_puts(chr, (uint8_t*)msg, len);
1532
        s->t_attrib = s->t_attrib_default;
1533
    }
1534

    
1535
    qemu_chr_generic_open(chr);
1536
    if (chr->init)
1537
        chr->init(chr);
1538
}
1539

    
1540
static CharDriverState *text_console_init(QemuOpts *opts)
1541
{
1542
    CharDriverState *chr;
1543
    QemuConsole *s;
1544
    unsigned width;
1545
    unsigned height;
1546

    
1547
    chr = g_malloc0(sizeof(CharDriverState));
1548

    
1549
    width = qemu_opt_get_number(opts, "width", 0);
1550
    if (width == 0)
1551
        width = qemu_opt_get_number(opts, "cols", 0) * FONT_WIDTH;
1552

    
1553
    height = qemu_opt_get_number(opts, "height", 0);
1554
    if (height == 0)
1555
        height = qemu_opt_get_number(opts, "rows", 0) * FONT_HEIGHT;
1556

    
1557
    if (width == 0 || height == 0) {
1558
        s = new_console(NULL, TEXT_CONSOLE);
1559
    } else {
1560
        s = new_console(NULL, TEXT_CONSOLE_FIXED_SIZE);
1561
    }
1562

    
1563
    if (!s) {
1564
        g_free(chr);
1565
        return NULL;
1566
    }
1567

    
1568
    s->chr = chr;
1569
    s->g_width = width;
1570
    s->g_height = height;
1571
    chr->opaque = s;
1572
    chr->chr_set_echo = text_console_set_echo;
1573
    return chr;
1574
}
1575

    
1576
static VcHandler *vc_handler = text_console_init;
1577

    
1578
CharDriverState *vc_init(QemuOpts *opts)
1579
{
1580
    return vc_handler(opts);
1581
}
1582

    
1583
void register_vc_handler(VcHandler *handler)
1584
{
1585
    vc_handler = handler;
1586
}
1587

    
1588
void text_consoles_set_display(DisplayState *ds)
1589
{
1590
    int i;
1591

    
1592
    for (i = 0; i < nb_consoles; i++) {
1593
        if (consoles[i]->console_type != GRAPHIC_CONSOLE) {
1594
            text_console_do_init(consoles[i]->chr, ds);
1595
        }
1596
    }
1597
}
1598

    
1599
void qemu_console_resize(DisplayState *ds, int width, int height)
1600
{
1601
    QemuConsole *s = get_graphic_console(ds);
1602
    if (!s) return;
1603

    
1604
    s->g_width = width;
1605
    s->g_height = height;
1606
    if (is_graphic_console()) {
1607
        ds->surface = qemu_resize_displaysurface(ds, width, height);
1608
        dpy_gfx_resize(ds);
1609
    }
1610
}
1611

    
1612
void qemu_console_copy(DisplayState *ds, int src_x, int src_y,
1613
                       int dst_x, int dst_y, int w, int h)
1614
{
1615
    if (is_graphic_console()) {
1616
        dpy_gfx_copy(ds, src_x, src_y, dst_x, dst_y, w, h);
1617
    }
1618
}
1619

    
1620
PixelFormat qemu_different_endianness_pixelformat(int bpp)
1621
{
1622
    PixelFormat pf;
1623

    
1624
    memset(&pf, 0x00, sizeof(PixelFormat));
1625

    
1626
    pf.bits_per_pixel = bpp;
1627
    pf.bytes_per_pixel = DIV_ROUND_UP(bpp, 8);
1628
    pf.depth = bpp == 32 ? 24 : bpp;
1629

    
1630
    switch (bpp) {
1631
        case 24:
1632
            pf.rmask = 0x000000FF;
1633
            pf.gmask = 0x0000FF00;
1634
            pf.bmask = 0x00FF0000;
1635
            pf.rmax = 255;
1636
            pf.gmax = 255;
1637
            pf.bmax = 255;
1638
            pf.rshift = 0;
1639
            pf.gshift = 8;
1640
            pf.bshift = 16;
1641
            pf.rbits = 8;
1642
            pf.gbits = 8;
1643
            pf.bbits = 8;
1644
            break;
1645
        case 32:
1646
            pf.rmask = 0x0000FF00;
1647
            pf.gmask = 0x00FF0000;
1648
            pf.bmask = 0xFF000000;
1649
            pf.amask = 0x00000000;
1650
            pf.amax = 255;
1651
            pf.rmax = 255;
1652
            pf.gmax = 255;
1653
            pf.bmax = 255;
1654
            pf.ashift = 0;
1655
            pf.rshift = 8;
1656
            pf.gshift = 16;
1657
            pf.bshift = 24;
1658
            pf.rbits = 8;
1659
            pf.gbits = 8;
1660
            pf.bbits = 8;
1661
            pf.abits = 8;
1662
            break;
1663
        default:
1664
            break;
1665
    }
1666
    return pf;
1667
}
1668

    
1669
PixelFormat qemu_default_pixelformat(int bpp)
1670
{
1671
    PixelFormat pf;
1672

    
1673
    memset(&pf, 0x00, sizeof(PixelFormat));
1674

    
1675
    pf.bits_per_pixel = bpp;
1676
    pf.bytes_per_pixel = DIV_ROUND_UP(bpp, 8);
1677
    pf.depth = bpp == 32 ? 24 : bpp;
1678

    
1679
    switch (bpp) {
1680
        case 15:
1681
            pf.bits_per_pixel = 16;
1682
            pf.rmask = 0x00007c00;
1683
            pf.gmask = 0x000003E0;
1684
            pf.bmask = 0x0000001F;
1685
            pf.rmax = 31;
1686
            pf.gmax = 31;
1687
            pf.bmax = 31;
1688
            pf.rshift = 10;
1689
            pf.gshift = 5;
1690
            pf.bshift = 0;
1691
            pf.rbits = 5;
1692
            pf.gbits = 5;
1693
            pf.bbits = 5;
1694
            break;
1695
        case 16:
1696
            pf.rmask = 0x0000F800;
1697
            pf.gmask = 0x000007E0;
1698
            pf.bmask = 0x0000001F;
1699
            pf.rmax = 31;
1700
            pf.gmax = 63;
1701
            pf.bmax = 31;
1702
            pf.rshift = 11;
1703
            pf.gshift = 5;
1704
            pf.bshift = 0;
1705
            pf.rbits = 5;
1706
            pf.gbits = 6;
1707
            pf.bbits = 5;
1708
            break;
1709
        case 24:
1710
            pf.rmask = 0x00FF0000;
1711
            pf.gmask = 0x0000FF00;
1712
            pf.bmask = 0x000000FF;
1713
            pf.rmax = 255;
1714
            pf.gmax = 255;
1715
            pf.bmax = 255;
1716
            pf.rshift = 16;
1717
            pf.gshift = 8;
1718
            pf.bshift = 0;
1719
            pf.rbits = 8;
1720
            pf.gbits = 8;
1721
            pf.bbits = 8;
1722
            break;
1723
        case 32:
1724
            pf.rmask = 0x00FF0000;
1725
            pf.gmask = 0x0000FF00;
1726
            pf.bmask = 0x000000FF;
1727
            pf.rmax = 255;
1728
            pf.gmax = 255;
1729
            pf.bmax = 255;
1730
            pf.rshift = 16;
1731
            pf.gshift = 8;
1732
            pf.bshift = 0;
1733
            pf.rbits = 8;
1734
            pf.gbits = 8;
1735
            pf.bbits = 8;
1736
            break;
1737
        default:
1738
            break;
1739
    }
1740
    return pf;
1741
}
1742

    
1743
static void register_types(void)
1744
{
1745
    register_char_driver("vc", vc_init);
1746
}
1747

    
1748
type_init(register_types);