Statistics
| Branch: | Revision:

root / ui / console.c @ c78f7137

History | View | Annotate | Download (51.9 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, 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
            DisplaySurface *surface;
1103
            surface = qemu_create_displaysurface(s->g_width, s->g_height);
1104
            dpy_gfx_replace_surface(s, surface);
1105
        }
1106
        if (ds->have_text) {
1107
            dpy_text_resize(s, s->width, s->height);
1108
        }
1109
        if (s->cursor_timer) {
1110
            qemu_mod_timer(s->cursor_timer,
1111
                   qemu_get_clock_ms(rt_clock) + CONSOLE_CURSOR_PERIOD / 2);
1112
        }
1113
        vga_hw_invalidate();
1114
    }
1115
}
1116

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

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

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

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

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

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

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

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

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

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

    
1255
static QemuConsole *new_console(DisplayState *ds, console_type_t console_type)
1256
{
1257
    QemuConsole *s;
1258
    int i;
1259

    
1260
    if (nb_consoles >= MAX_CONSOLES)
1261
        return NULL;
1262
    s = g_malloc0(sizeof(QemuConsole));
1263
    if (!active_console || ((active_console->console_type != GRAPHIC_CONSOLE) &&
1264
        (console_type == GRAPHIC_CONSOLE))) {
1265
        active_console = s;
1266
    }
1267
    s->ds = ds;
1268
    s->console_type = console_type;
1269
    if (console_type != GRAPHIC_CONSOLE) {
1270
        s->index = nb_consoles;
1271
        consoles[nb_consoles++] = s;
1272
    } else {
1273
        /* HACK: Put graphical consoles before text consoles.  */
1274
        for (i = nb_consoles; i > 0; i--) {
1275
            if (consoles[i - 1]->console_type == GRAPHIC_CONSOLE)
1276
                break;
1277
            consoles[i] = consoles[i - 1];
1278
            consoles[i]->index = i;
1279
        }
1280
        s->index = i;
1281
        consoles[i] = s;
1282
        nb_consoles++;
1283
    }
1284
    return s;
1285
}
1286

    
1287
static void qemu_alloc_display(DisplaySurface *surface, int width, int height,
1288
                               int linesize, PixelFormat pf, int newflags)
1289
{
1290
    surface->pf = pf;
1291

    
1292
    qemu_pixman_image_unref(surface->image);
1293
    surface->image = NULL;
1294

    
1295
    surface->format = qemu_pixman_get_format(&pf);
1296
    assert(surface->format != 0);
1297
    surface->image = pixman_image_create_bits(surface->format,
1298
                                              width, height,
1299
                                              NULL, linesize);
1300
    assert(surface->image != NULL);
1301

    
1302
    surface->flags = newflags | QEMU_ALLOCATED_FLAG;
1303
#ifdef HOST_WORDS_BIGENDIAN
1304
    surface->flags |= QEMU_BIG_ENDIAN_FLAG;
1305
#endif
1306
}
1307

    
1308
DisplaySurface *qemu_create_displaysurface(int width, int height)
1309
{
1310
    DisplaySurface *surface = g_new0(DisplaySurface, 1);
1311
    int linesize = width * 4;
1312

    
1313
    trace_displaysurface_create(surface, width, height);
1314
    qemu_alloc_display(surface, width, height, linesize,
1315
                       qemu_default_pixelformat(32), 0);
1316
    return surface;
1317
}
1318

    
1319
DisplaySurface *qemu_create_displaysurface_from(int width, int height, int bpp,
1320
                                                int linesize, uint8_t *data,
1321
                                                bool byteswap)
1322
{
1323
    DisplaySurface *surface = g_new0(DisplaySurface, 1);
1324

    
1325
    trace_displaysurface_create_from(surface, width, height, bpp, byteswap);
1326
    if (byteswap) {
1327
        surface->pf = qemu_different_endianness_pixelformat(bpp);
1328
    } else {
1329
        surface->pf = qemu_default_pixelformat(bpp);
1330
    }
1331

    
1332
    surface->format = qemu_pixman_get_format(&surface->pf);
1333
    assert(surface->format != 0);
1334
    surface->image = pixman_image_create_bits(surface->format,
1335
                                              width, height,
1336
                                              (void *)data, linesize);
1337
    assert(surface->image != NULL);
1338

    
1339
#ifdef HOST_WORDS_BIGENDIAN
1340
    surface->flags = QEMU_BIG_ENDIAN_FLAG;
1341
#endif
1342

    
1343
    return surface;
1344
}
1345

    
1346
void qemu_free_displaysurface(DisplaySurface *surface)
1347
{
1348
    if (surface == NULL) {
1349
        return;
1350
    }
1351
    trace_displaysurface_free(surface);
1352
    qemu_pixman_image_unref(surface->image);
1353
    g_free(surface);
1354
}
1355

    
1356
void register_displaychangelistener(DisplayState *ds,
1357
                                    DisplayChangeListener *dcl)
1358
{
1359
    trace_displaychangelistener_register(dcl, dcl->ops->dpy_name);
1360
    dcl->ds = ds;
1361
    QLIST_INSERT_HEAD(&ds->listeners, dcl, next);
1362
    gui_setup_refresh(ds);
1363
    if (dcl->ops->dpy_gfx_switch) {
1364
        dcl->ops->dpy_gfx_switch(dcl, ds->surface);
1365
    }
1366
}
1367

    
1368
void unregister_displaychangelistener(DisplayChangeListener *dcl)
1369
{
1370
    DisplayState *ds = dcl->ds;
1371
    trace_displaychangelistener_unregister(dcl, dcl->ops->dpy_name);
1372
    QLIST_REMOVE(dcl, next);
1373
    gui_setup_refresh(ds);
1374
}
1375

    
1376
void dpy_gfx_update(QemuConsole *con, int x, int y, int w, int h)
1377
{
1378
    DisplayState *s = con->ds;
1379
    struct DisplayChangeListener *dcl;
1380
    int width = pixman_image_get_width(s->surface->image);
1381
    int height = pixman_image_get_height(s->surface->image);
1382

    
1383
    x = MAX(x, 0);
1384
    y = MAX(y, 0);
1385
    x = MIN(x, width);
1386
    y = MIN(y, height);
1387
    w = MIN(w, width - x);
1388
    h = MIN(h, height - y);
1389

    
1390
    QLIST_FOREACH(dcl, &s->listeners, next) {
1391
        if (dcl->ops->dpy_gfx_update) {
1392
            dcl->ops->dpy_gfx_update(dcl, x, y, w, h);
1393
        }
1394
    }
1395
}
1396

    
1397
void dpy_gfx_replace_surface(QemuConsole *con,
1398
                             DisplaySurface *surface)
1399
{
1400
    DisplayState *s = con->ds;
1401
    DisplaySurface *old_surface = s->surface;
1402
    struct DisplayChangeListener *dcl;
1403

    
1404
    s->surface = surface;
1405
    QLIST_FOREACH(dcl, &s->listeners, next) {
1406
        if (dcl->ops->dpy_gfx_switch) {
1407
            dcl->ops->dpy_gfx_switch(dcl, surface);
1408
        }
1409
    }
1410
    qemu_free_displaysurface(old_surface);
1411
}
1412

    
1413
void dpy_refresh(DisplayState *s)
1414
{
1415
    struct DisplayChangeListener *dcl;
1416
    QLIST_FOREACH(dcl, &s->listeners, next) {
1417
        if (dcl->ops->dpy_refresh) {
1418
            dcl->ops->dpy_refresh(dcl);
1419
        }
1420
    }
1421
}
1422

    
1423
void dpy_gfx_copy(QemuConsole *con, int src_x, int src_y,
1424
                  int dst_x, int dst_y, int w, int h)
1425
{
1426
    DisplayState *s = con->ds;
1427
    struct DisplayChangeListener *dcl;
1428
    QLIST_FOREACH(dcl, &s->listeners, next) {
1429
        if (dcl->ops->dpy_gfx_copy) {
1430
            dcl->ops->dpy_gfx_copy(dcl, src_x, src_y, dst_x, dst_y, w, h);
1431
        } else { /* TODO */
1432
            dcl->ops->dpy_gfx_update(dcl, dst_x, dst_y, w, h);
1433
        }
1434
    }
1435
}
1436

    
1437
void dpy_text_cursor(QemuConsole *con, int x, int y)
1438
{
1439
    DisplayState *s = con->ds;
1440
    struct DisplayChangeListener *dcl;
1441
    QLIST_FOREACH(dcl, &s->listeners, next) {
1442
        if (dcl->ops->dpy_text_cursor) {
1443
            dcl->ops->dpy_text_cursor(dcl, x, y);
1444
        }
1445
    }
1446
}
1447

    
1448
void dpy_text_update(QemuConsole *con, int x, int y, int w, int h)
1449
{
1450
    DisplayState *s = con->ds;
1451
    struct DisplayChangeListener *dcl;
1452
    QLIST_FOREACH(dcl, &s->listeners, next) {
1453
        if (dcl->ops->dpy_text_update) {
1454
            dcl->ops->dpy_text_update(dcl, x, y, w, h);
1455
        }
1456
    }
1457
}
1458

    
1459
void dpy_text_resize(QemuConsole *con, int w, int h)
1460
{
1461
    DisplayState *s = con->ds;
1462
    struct DisplayChangeListener *dcl;
1463
    QLIST_FOREACH(dcl, &s->listeners, next) {
1464
        if (dcl->ops->dpy_text_resize) {
1465
            dcl->ops->dpy_text_resize(dcl, w, h);
1466
        }
1467
    }
1468
}
1469

    
1470
void dpy_mouse_set(QemuConsole *con, int x, int y, int on)
1471
{
1472
    DisplayState *s = con->ds;
1473
    struct DisplayChangeListener *dcl;
1474
    QLIST_FOREACH(dcl, &s->listeners, next) {
1475
        if (dcl->ops->dpy_mouse_set) {
1476
            dcl->ops->dpy_mouse_set(dcl, x, y, on);
1477
        }
1478
    }
1479
}
1480

    
1481
void dpy_cursor_define(QemuConsole *con, QEMUCursor *cursor)
1482
{
1483
    DisplayState *s = con->ds;
1484
    struct DisplayChangeListener *dcl;
1485
    QLIST_FOREACH(dcl, &s->listeners, next) {
1486
        if (dcl->ops->dpy_cursor_define) {
1487
            dcl->ops->dpy_cursor_define(dcl, cursor);
1488
        }
1489
    }
1490
}
1491

    
1492
bool dpy_cursor_define_supported(QemuConsole *con)
1493
{
1494
    DisplayState *s = con->ds;
1495
    struct DisplayChangeListener *dcl;
1496
    QLIST_FOREACH(dcl, &s->listeners, next) {
1497
        if (dcl->ops->dpy_cursor_define) {
1498
            return true;
1499
        }
1500
    }
1501
    return false;
1502
}
1503

    
1504
static void dumb_display_init(void)
1505
{
1506
    DisplayState *ds = g_malloc0(sizeof(DisplayState));
1507
    int width = 640;
1508
    int height = 480;
1509

    
1510
    if (is_fixedsize_console()) {
1511
        width = active_console->g_width;
1512
        height = active_console->g_height;
1513
    }
1514
    ds->surface = qemu_create_displaysurface(width, height);
1515

    
1516
    register_displaystate(ds);
1517
}
1518

    
1519
/***********************************************************/
1520
/* register display */
1521

    
1522
void register_displaystate(DisplayState *ds)
1523
{
1524
    DisplayState **s;
1525
    s = &display_state;
1526
    while (*s != NULL)
1527
        s = &(*s)->next;
1528
    ds->next = NULL;
1529
    *s = ds;
1530
}
1531

    
1532
DisplayState *get_displaystate(void)
1533
{
1534
    if (!display_state) {
1535
        dumb_display_init ();
1536
    }
1537
    return display_state;
1538
}
1539

    
1540
QemuConsole *graphic_console_init(vga_hw_update_ptr update,
1541
                                  vga_hw_invalidate_ptr invalidate,
1542
                                  vga_hw_screen_dump_ptr screen_dump,
1543
                                  vga_hw_text_update_ptr text_update,
1544
                                  void *opaque)
1545
{
1546
    QemuConsole *s;
1547
    DisplayState *ds;
1548

    
1549
    ds = (DisplayState *) g_malloc0(sizeof(DisplayState));
1550
    s = new_console(ds, GRAPHIC_CONSOLE);
1551
    s->hw_update = update;
1552
    s->hw_invalidate = invalidate;
1553
    s->hw_screen_dump = screen_dump;
1554
    s->hw_text_update = text_update;
1555
    s->hw = opaque;
1556

    
1557
    ds->surface = qemu_create_displaysurface(640, 480);
1558

    
1559
    register_displaystate(ds);
1560
    return s;
1561
}
1562

    
1563
int is_graphic_console(void)
1564
{
1565
    return active_console && active_console->console_type == GRAPHIC_CONSOLE;
1566
}
1567

    
1568
int is_fixedsize_console(void)
1569
{
1570
    return active_console && active_console->console_type != TEXT_CONSOLE;
1571
}
1572

    
1573
void console_color_init(DisplayState *ds)
1574
{
1575
    int i, j;
1576
    for (j = 0; j < 2; j++) {
1577
        for (i = 0; i < 8; i++) {
1578
            color_table[j][i] = col_expand(ds,
1579
                   vga_get_color(ds, color_table_rgb[j][i]));
1580
        }
1581
    }
1582
}
1583

    
1584
static void text_console_set_echo(CharDriverState *chr, bool echo)
1585
{
1586
    QemuConsole *s = chr->opaque;
1587

    
1588
    s->echo = echo;
1589
}
1590

    
1591
static void text_console_update_cursor(void *opaque)
1592
{
1593
    QemuConsole *s = opaque;
1594

    
1595
    s->cursor_visible_phase = !s->cursor_visible_phase;
1596
    vga_hw_invalidate();
1597
    qemu_mod_timer(s->cursor_timer,
1598
                   qemu_get_clock_ms(rt_clock) + CONSOLE_CURSOR_PERIOD / 2);
1599
}
1600

    
1601
static void text_console_do_init(CharDriverState *chr, DisplayState *ds)
1602
{
1603
    QemuConsole *s;
1604
    static int color_inited;
1605

    
1606
    s = chr->opaque;
1607

    
1608
    chr->chr_write = console_puts;
1609

    
1610
    s->out_fifo.buf = s->out_fifo_buf;
1611
    s->out_fifo.buf_size = sizeof(s->out_fifo_buf);
1612
    s->kbd_timer = qemu_new_timer_ms(rt_clock, kbd_send_chars, s);
1613
    s->ds = ds;
1614

    
1615
    if (!color_inited) {
1616
        color_inited = 1;
1617
        console_color_init(s->ds);
1618
    }
1619
    s->y_displayed = 0;
1620
    s->y_base = 0;
1621
    s->total_height = DEFAULT_BACKSCROLL;
1622
    s->x = 0;
1623
    s->y = 0;
1624
    if (s->console_type == TEXT_CONSOLE) {
1625
        s->g_width = ds_get_width(s->ds);
1626
        s->g_height = ds_get_height(s->ds);
1627
    }
1628

    
1629
    s->cursor_timer =
1630
        qemu_new_timer_ms(rt_clock, text_console_update_cursor, s);
1631

    
1632
    s->hw_invalidate = text_console_invalidate;
1633
    s->hw_text_update = text_console_update;
1634
    s->hw = s;
1635

    
1636
    /* Set text attribute defaults */
1637
    s->t_attrib_default.bold = 0;
1638
    s->t_attrib_default.uline = 0;
1639
    s->t_attrib_default.blink = 0;
1640
    s->t_attrib_default.invers = 0;
1641
    s->t_attrib_default.unvisible = 0;
1642
    s->t_attrib_default.fgcol = COLOR_WHITE;
1643
    s->t_attrib_default.bgcol = COLOR_BLACK;
1644
    /* set current text attributes to default */
1645
    s->t_attrib = s->t_attrib_default;
1646
    text_console_resize(s);
1647

    
1648
    if (chr->label) {
1649
        char msg[128];
1650
        int len;
1651

    
1652
        s->t_attrib.bgcol = COLOR_BLUE;
1653
        len = snprintf(msg, sizeof(msg), "%s console\r\n", chr->label);
1654
        console_puts(chr, (uint8_t*)msg, len);
1655
        s->t_attrib = s->t_attrib_default;
1656
    }
1657

    
1658
    qemu_chr_generic_open(chr);
1659
    if (chr->init)
1660
        chr->init(chr);
1661
}
1662

    
1663
static CharDriverState *text_console_init(ChardevVC *vc)
1664
{
1665
    CharDriverState *chr;
1666
    QemuConsole *s;
1667
    unsigned width = 0;
1668
    unsigned height = 0;
1669

    
1670
    chr = g_malloc0(sizeof(CharDriverState));
1671

    
1672
    if (vc->has_width) {
1673
        width = vc->width;
1674
    } else if (vc->has_cols) {
1675
        width = vc->cols * FONT_WIDTH;
1676
    }
1677

    
1678
    if (vc->has_height) {
1679
        height = vc->height;
1680
    } else if (vc->has_rows) {
1681
        height = vc->rows * FONT_HEIGHT;
1682
    }
1683

    
1684
    if (width == 0 || height == 0) {
1685
        s = new_console(NULL, TEXT_CONSOLE);
1686
    } else {
1687
        s = new_console(NULL, TEXT_CONSOLE_FIXED_SIZE);
1688
    }
1689

    
1690
    if (!s) {
1691
        g_free(chr);
1692
        return NULL;
1693
    }
1694

    
1695
    s->chr = chr;
1696
    s->g_width = width;
1697
    s->g_height = height;
1698
    chr->opaque = s;
1699
    chr->chr_set_echo = text_console_set_echo;
1700
    return chr;
1701
}
1702

    
1703
static VcHandler *vc_handler = text_console_init;
1704

    
1705
CharDriverState *vc_init(ChardevVC *vc)
1706
{
1707
    return vc_handler(vc);
1708
}
1709

    
1710
void register_vc_handler(VcHandler *handler)
1711
{
1712
    vc_handler = handler;
1713
}
1714

    
1715
void text_consoles_set_display(DisplayState *ds)
1716
{
1717
    int i;
1718

    
1719
    for (i = 0; i < nb_consoles; i++) {
1720
        if (consoles[i]->console_type != GRAPHIC_CONSOLE) {
1721
            text_console_do_init(consoles[i]->chr, ds);
1722
        }
1723
    }
1724
}
1725

    
1726
void qemu_console_resize(QemuConsole *s, int width, int height)
1727
{
1728
    s->g_width = width;
1729
    s->g_height = height;
1730
    if (is_graphic_console()) {
1731
        DisplaySurface *surface;
1732
        surface = qemu_create_displaysurface(width, height);
1733
        dpy_gfx_replace_surface(s, surface);
1734
    }
1735
}
1736

    
1737
void qemu_console_copy(QemuConsole *con, int src_x, int src_y,
1738
                       int dst_x, int dst_y, int w, int h)
1739
{
1740
    if (is_graphic_console()) {
1741
        dpy_gfx_copy(con, src_x, src_y, dst_x, dst_y, w, h);
1742
    }
1743
}
1744

    
1745
DisplaySurface *qemu_console_surface(QemuConsole *console)
1746
{
1747
    return console->ds->surface;
1748
}
1749

    
1750
DisplayState *qemu_console_displaystate(QemuConsole *console)
1751
{
1752
    return console->ds;
1753
}
1754

    
1755
PixelFormat qemu_different_endianness_pixelformat(int bpp)
1756
{
1757
    PixelFormat pf;
1758

    
1759
    memset(&pf, 0x00, sizeof(PixelFormat));
1760

    
1761
    pf.bits_per_pixel = bpp;
1762
    pf.bytes_per_pixel = DIV_ROUND_UP(bpp, 8);
1763
    pf.depth = bpp == 32 ? 24 : bpp;
1764

    
1765
    switch (bpp) {
1766
        case 24:
1767
            pf.rmask = 0x000000FF;
1768
            pf.gmask = 0x0000FF00;
1769
            pf.bmask = 0x00FF0000;
1770
            pf.rmax = 255;
1771
            pf.gmax = 255;
1772
            pf.bmax = 255;
1773
            pf.rshift = 0;
1774
            pf.gshift = 8;
1775
            pf.bshift = 16;
1776
            pf.rbits = 8;
1777
            pf.gbits = 8;
1778
            pf.bbits = 8;
1779
            break;
1780
        case 32:
1781
            pf.rmask = 0x0000FF00;
1782
            pf.gmask = 0x00FF0000;
1783
            pf.bmask = 0xFF000000;
1784
            pf.amask = 0x00000000;
1785
            pf.amax = 255;
1786
            pf.rmax = 255;
1787
            pf.gmax = 255;
1788
            pf.bmax = 255;
1789
            pf.ashift = 0;
1790
            pf.rshift = 8;
1791
            pf.gshift = 16;
1792
            pf.bshift = 24;
1793
            pf.rbits = 8;
1794
            pf.gbits = 8;
1795
            pf.bbits = 8;
1796
            pf.abits = 8;
1797
            break;
1798
        default:
1799
            break;
1800
    }
1801
    return pf;
1802
}
1803

    
1804
PixelFormat qemu_default_pixelformat(int bpp)
1805
{
1806
    PixelFormat pf;
1807

    
1808
    memset(&pf, 0x00, sizeof(PixelFormat));
1809

    
1810
    pf.bits_per_pixel = bpp;
1811
    pf.bytes_per_pixel = DIV_ROUND_UP(bpp, 8);
1812
    pf.depth = bpp == 32 ? 24 : bpp;
1813

    
1814
    switch (bpp) {
1815
        case 15:
1816
            pf.bits_per_pixel = 16;
1817
            pf.rmask = 0x00007c00;
1818
            pf.gmask = 0x000003E0;
1819
            pf.bmask = 0x0000001F;
1820
            pf.rmax = 31;
1821
            pf.gmax = 31;
1822
            pf.bmax = 31;
1823
            pf.rshift = 10;
1824
            pf.gshift = 5;
1825
            pf.bshift = 0;
1826
            pf.rbits = 5;
1827
            pf.gbits = 5;
1828
            pf.bbits = 5;
1829
            break;
1830
        case 16:
1831
            pf.rmask = 0x0000F800;
1832
            pf.gmask = 0x000007E0;
1833
            pf.bmask = 0x0000001F;
1834
            pf.rmax = 31;
1835
            pf.gmax = 63;
1836
            pf.bmax = 31;
1837
            pf.rshift = 11;
1838
            pf.gshift = 5;
1839
            pf.bshift = 0;
1840
            pf.rbits = 5;
1841
            pf.gbits = 6;
1842
            pf.bbits = 5;
1843
            break;
1844
        case 24:
1845
            pf.rmask = 0x00FF0000;
1846
            pf.gmask = 0x0000FF00;
1847
            pf.bmask = 0x000000FF;
1848
            pf.rmax = 255;
1849
            pf.gmax = 255;
1850
            pf.bmax = 255;
1851
            pf.rshift = 16;
1852
            pf.gshift = 8;
1853
            pf.bshift = 0;
1854
            pf.rbits = 8;
1855
            pf.gbits = 8;
1856
            pf.bbits = 8;
1857
            break;
1858
        case 32:
1859
            pf.rmask = 0x00FF0000;
1860
            pf.gmask = 0x0000FF00;
1861
            pf.bmask = 0x000000FF;
1862
            pf.rmax = 255;
1863
            pf.gmax = 255;
1864
            pf.bmax = 255;
1865
            pf.rshift = 16;
1866
            pf.gshift = 8;
1867
            pf.bshift = 0;
1868
            pf.rbits = 8;
1869
            pf.gbits = 8;
1870
            pf.bbits = 8;
1871
            break;
1872
        default:
1873
            break;
1874
    }
1875
    return pf;
1876
}
1877

    
1878
static void qemu_chr_parse_vc(QemuOpts *opts, ChardevBackend *backend,
1879
                              Error **errp)
1880
{
1881
    int val;
1882

    
1883
    backend->vc = g_new0(ChardevVC, 1);
1884

    
1885
    val = qemu_opt_get_number(opts, "width", 0);
1886
    if (val != 0) {
1887
        backend->vc->has_width = true;
1888
        backend->vc->width = val;
1889
    }
1890

    
1891
    val = qemu_opt_get_number(opts, "height", 0);
1892
    if (val != 0) {
1893
        backend->vc->has_height = true;
1894
        backend->vc->height = val;
1895
    }
1896

    
1897
    val = qemu_opt_get_number(opts, "cols", 0);
1898
    if (val != 0) {
1899
        backend->vc->has_cols = true;
1900
        backend->vc->cols = val;
1901
    }
1902

    
1903
    val = qemu_opt_get_number(opts, "rows", 0);
1904
    if (val != 0) {
1905
        backend->vc->has_rows = true;
1906
        backend->vc->rows = val;
1907
    }
1908
}
1909

    
1910
static void register_types(void)
1911
{
1912
    register_char_driver_qapi("vc", CHARDEV_BACKEND_KIND_VC,
1913
                              qemu_chr_parse_vc);
1914
}
1915

    
1916
type_init(register_types);