Statistics
| Branch: | Revision:

root / console.c @ 09bbb0ae

History | View | Annotate | Download (47.5 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 "console.h"
26
#include "qemu-timer.h"
27
#include "qmp-commands.h"
28

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

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

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

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

    
52
#define MAX_ESC_PARAMS 3
53

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
313
/***********************************************************/
314
/* basic char display */
315

    
316
#define FONT_HEIGHT 16
317
#define FONT_WIDTH 8
318

    
319
#include "vgafont.h"
320

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
1305
    qemu_pixman_image_unref(surface->image);
1306
    surface->image = NULL;
1307
    surface->data = NULL;
1308

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

    
1316
    surface->data = (uint8_t *)pixman_image_get_data(surface->image);
1317
    surface->flags = newflags | QEMU_ALLOCATED_FLAG;
1318
#ifdef HOST_WORDS_BIGENDIAN
1319
    surface->flags |= QEMU_BIG_ENDIAN_FLAG;
1320
#endif
1321
}
1322

    
1323
DisplaySurface *qemu_create_displaysurface(DisplayState *ds,
1324
                                           int width, int height)
1325
{
1326
    DisplaySurface *surface = g_new0(DisplaySurface, 1);
1327

    
1328
    int linesize = width * 4;
1329
    qemu_alloc_display(surface, width, height, linesize,
1330
                       qemu_default_pixelformat(32), 0);
1331
    return surface;
1332
}
1333

    
1334
DisplaySurface *qemu_resize_displaysurface(DisplayState *ds,
1335
                                           int width, int height)
1336
{
1337
    int linesize = width * 4;
1338

    
1339
    trace_displaysurface_resize(ds, ds->surface, width, height);
1340
    qemu_alloc_display(ds->surface, width, height, linesize,
1341
                       qemu_default_pixelformat(32), 0);
1342
    return ds->surface;
1343
}
1344

    
1345
DisplaySurface *qemu_create_displaysurface_from(int width, int height, int bpp,
1346
                                                int linesize, uint8_t *data)
1347
{
1348
    DisplaySurface *surface = g_new0(DisplaySurface, 1);
1349

    
1350
    surface->width = width;
1351
    surface->height = height;
1352
    surface->linesize = linesize;
1353
    surface->pf = qemu_default_pixelformat(bpp);
1354

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

    
1362
#ifdef HOST_WORDS_BIGENDIAN
1363
    surface->flags = QEMU_BIG_ENDIAN_FLAG;
1364
#endif
1365
    surface->data = data;
1366

    
1367
    return surface;
1368
}
1369

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

    
1380
static void dumb_display_init(void)
1381
{
1382
    DisplayState *ds = g_malloc0(sizeof(DisplayState));
1383
    int width = 640;
1384
    int height = 480;
1385

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

    
1394
/***********************************************************/
1395
/* register display */
1396

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

    
1407
DisplayState *get_displaystate(void)
1408
{
1409
    if (!display_state) {
1410
        dumb_display_init ();
1411
    }
1412
    return display_state;
1413
}
1414

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

    
1424
    ds = (DisplayState *) g_malloc0(sizeof(DisplayState));
1425
    ds->surface = qemu_create_displaysurface(ds, 640, 480);
1426

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

    
1439
    register_displaystate(ds);
1440
    return ds;
1441
}
1442

    
1443
int is_graphic_console(void)
1444
{
1445
    return active_console && active_console->console_type == GRAPHIC_CONSOLE;
1446
}
1447

    
1448
int is_fixedsize_console(void)
1449
{
1450
    return active_console && active_console->console_type != TEXT_CONSOLE;
1451
}
1452

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

    
1464
static void text_console_set_echo(CharDriverState *chr, bool echo)
1465
{
1466
    QemuConsole *s = chr->opaque;
1467

    
1468
    s->echo = echo;
1469
}
1470

    
1471
static void text_console_update_cursor(void *opaque)
1472
{
1473
    QemuConsole *s = opaque;
1474

    
1475
    s->cursor_visible_phase = !s->cursor_visible_phase;
1476
    vga_hw_invalidate();
1477
    qemu_mod_timer(s->cursor_timer,
1478
                   qemu_get_clock_ms(rt_clock) + CONSOLE_CURSOR_PERIOD / 2);
1479
}
1480

    
1481
static void text_console_do_init(CharDriverState *chr, DisplayState *ds)
1482
{
1483
    QemuConsole *s;
1484
    static int color_inited;
1485

    
1486
    s = chr->opaque;
1487

    
1488
    chr->chr_write = console_puts;
1489

    
1490
    s->out_fifo.buf = s->out_fifo_buf;
1491
    s->out_fifo.buf_size = sizeof(s->out_fifo_buf);
1492
    s->kbd_timer = qemu_new_timer_ms(rt_clock, kbd_send_chars, s);
1493
    s->ds = ds;
1494

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

    
1509
    s->cursor_timer =
1510
        qemu_new_timer_ms(rt_clock, text_console_update_cursor, s);
1511

    
1512
    s->hw_invalidate = text_console_invalidate;
1513
    s->hw_text_update = text_console_update;
1514
    s->hw = s;
1515

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

    
1528
    if (chr->label) {
1529
        char msg[128];
1530
        int len;
1531

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

    
1538
    qemu_chr_generic_open(chr);
1539
    if (chr->init)
1540
        chr->init(chr);
1541
}
1542

    
1543
CharDriverState *text_console_init(QemuOpts *opts)
1544
{
1545
    CharDriverState *chr;
1546
    QemuConsole *s;
1547
    unsigned width;
1548
    unsigned height;
1549

    
1550
    chr = g_malloc0(sizeof(CharDriverState));
1551

    
1552
    width = qemu_opt_get_number(opts, "width", 0);
1553
    if (width == 0)
1554
        width = qemu_opt_get_number(opts, "cols", 0) * FONT_WIDTH;
1555

    
1556
    height = qemu_opt_get_number(opts, "height", 0);
1557
    if (height == 0)
1558
        height = qemu_opt_get_number(opts, "rows", 0) * FONT_HEIGHT;
1559

    
1560
    if (width == 0 || height == 0) {
1561
        s = new_console(NULL, TEXT_CONSOLE);
1562
    } else {
1563
        s = new_console(NULL, TEXT_CONSOLE_FIXED_SIZE);
1564
    }
1565

    
1566
    if (!s) {
1567
        g_free(chr);
1568
        return NULL;
1569
    }
1570

    
1571
    s->chr = chr;
1572
    s->g_width = width;
1573
    s->g_height = height;
1574
    chr->opaque = s;
1575
    chr->chr_set_echo = text_console_set_echo;
1576
    return chr;
1577
}
1578

    
1579
void text_consoles_set_display(DisplayState *ds)
1580
{
1581
    int i;
1582

    
1583
    for (i = 0; i < nb_consoles; i++) {
1584
        if (consoles[i]->console_type != GRAPHIC_CONSOLE) {
1585
            text_console_do_init(consoles[i]->chr, ds);
1586
        }
1587
    }
1588
}
1589

    
1590
void qemu_console_resize(DisplayState *ds, int width, int height)
1591
{
1592
    QemuConsole *s = get_graphic_console(ds);
1593
    if (!s) return;
1594

    
1595
    s->g_width = width;
1596
    s->g_height = height;
1597
    if (is_graphic_console()) {
1598
        ds->surface = qemu_resize_displaysurface(ds, width, height);
1599
        dpy_gfx_resize(ds);
1600
    }
1601
}
1602

    
1603
void qemu_console_copy(DisplayState *ds, int src_x, int src_y,
1604
                       int dst_x, int dst_y, int w, int h)
1605
{
1606
    if (is_graphic_console()) {
1607
        dpy_gfx_copy(ds, src_x, src_y, dst_x, dst_y, w, h);
1608
    }
1609
}
1610

    
1611
PixelFormat qemu_different_endianness_pixelformat(int bpp)
1612
{
1613
    PixelFormat pf;
1614

    
1615
    memset(&pf, 0x00, sizeof(PixelFormat));
1616

    
1617
    pf.bits_per_pixel = bpp;
1618
    pf.bytes_per_pixel = DIV_ROUND_UP(bpp, 8);
1619
    pf.depth = bpp == 32 ? 24 : bpp;
1620

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

    
1660
PixelFormat qemu_default_pixelformat(int bpp)
1661
{
1662
    PixelFormat pf;
1663

    
1664
    memset(&pf, 0x00, sizeof(PixelFormat));
1665

    
1666
    pf.bits_per_pixel = bpp;
1667
    pf.bytes_per_pixel = DIV_ROUND_UP(bpp, 8);
1668
    pf.depth = bpp == 32 ? 24 : bpp;
1669

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