Statistics
| Branch: | Revision:

root / console.c @ 60e1b2a6

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

    
28
//#define DEBUG_CONSOLE
29
#define DEFAULT_BACKSCROLL 512
30
#define MAX_CONSOLES 12
31

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

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

    
45
typedef struct TextCell {
46
    uint8_t ch;
47
    TextAttributes t_attrib;
48
} TextCell;
49

    
50
#define MAX_ESC_PARAMS 3
51

    
52
enum TTYState {
53
    TTY_STATE_NORM,
54
    TTY_STATE_ESC,
55
    TTY_STATE_CSI,
56
};
57

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

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

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

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

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

    
109
typedef enum {
110
    GRAPHIC_CONSOLE,
111
    TEXT_CONSOLE,
112
    TEXT_CONSOLE_FIXED_SIZE
113
} console_type_t;
114

    
115
/* ??? This is mis-named.
116
   It is used for both text and graphical consoles.  */
117
struct TextConsole {
118
    int index;
119
    console_type_t console_type;
120
    DisplayState *ds;
121
    /* Graphic console state.  */
122
    vga_hw_update_ptr hw_update;
123
    vga_hw_invalidate_ptr hw_invalidate;
124
    vga_hw_screen_dump_ptr hw_screen_dump;
125
    vga_hw_text_update_ptr hw_text_update;
126
    void *hw;
127

    
128
    int g_width, g_height;
129
    int width;
130
    int height;
131
    int total_height;
132
    int backscroll_height;
133
    int x, y;
134
    int x_saved, y_saved;
135
    int y_displayed;
136
    int y_base;
137
    TextAttributes t_attrib_default; /* default text attributes */
138
    TextAttributes t_attrib; /* currently active text attributes */
139
    TextCell *cells;
140
    int text_x[2], text_y[2], cursor_invalidate;
141
    int echo;
142

    
143
    int update_x0;
144
    int update_y0;
145
    int update_x1;
146
    int update_y1;
147

    
148
    enum TTYState state;
149
    int esc_params[MAX_ESC_PARAMS];
150
    int nb_esc_params;
151

    
152
    CharDriverState *chr;
153
    /* fifo for key pressed */
154
    QEMUFIFO out_fifo;
155
    uint8_t out_fifo_buf[16];
156
    QEMUTimer *kbd_timer;
157
};
158

    
159
static DisplayState *display_state;
160
static TextConsole *active_console;
161
static TextConsole *consoles[MAX_CONSOLES];
162
static int nb_consoles = 0;
163

    
164
void vga_hw_update(void)
165
{
166
    if (active_console && active_console->hw_update)
167
        active_console->hw_update(active_console->hw);
168
}
169

    
170
void vga_hw_invalidate(void)
171
{
172
    if (active_console && active_console->hw_invalidate)
173
        active_console->hw_invalidate(active_console->hw);
174
}
175

    
176
void vga_hw_screen_dump(const char *filename)
177
{
178
    TextConsole *previous_active_console;
179
    bool cswitch;
180

    
181
    previous_active_console = active_console;
182
    cswitch = previous_active_console && previous_active_console->index != 0;
183

    
184
    /* There is currently no way of specifying which screen we want to dump,
185
       so always dump the first one.  */
186
    if (cswitch) {
187
        console_select(0);
188
    }
189
    if (consoles[0] && consoles[0]->hw_screen_dump) {
190
        consoles[0]->hw_screen_dump(consoles[0]->hw, filename, cswitch);
191
    } else {
192
        error_report("screen dump not implemented");
193
    }
194

    
195
    if (cswitch) {
196
        console_select(previous_active_console->index);
197
    }
198
}
199

    
200
void vga_hw_text_update(console_ch_t *chardata)
201
{
202
    if (active_console && active_console->hw_text_update)
203
        active_console->hw_text_update(active_console->hw, chardata);
204
}
205

    
206
/* convert a RGBA color to a color index usable in graphic primitives */
207
static unsigned int vga_get_color(DisplayState *ds, unsigned int rgba)
208
{
209
    unsigned int r, g, b, color;
210

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

    
242
static void vga_fill_rect (DisplayState *ds,
243
                           int posx, int posy, int width, int height, uint32_t color)
244
{
245
    uint8_t *d, *d1;
246
    int x, y, bpp;
247

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

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

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

    
309
/***********************************************************/
310
/* basic char display */
311

    
312
#define FONT_HEIGHT 16
313
#define FONT_WIDTH 8
314

    
315
#include "vgafont.h"
316

    
317
#define cbswap_32(__x) \
318
((uint32_t)( \
319
                (((uint32_t)(__x) & (uint32_t)0x000000ffUL) << 24) | \
320
                (((uint32_t)(__x) & (uint32_t)0x0000ff00UL) <<  8) | \
321
                (((uint32_t)(__x) & (uint32_t)0x00ff0000UL) >>  8) | \
322
                (((uint32_t)(__x) & (uint32_t)0xff000000UL) >> 24) ))
323

    
324
#ifdef HOST_WORDS_BIGENDIAN
325
#define PAT(x) x
326
#else
327
#define PAT(x) cbswap_32(x)
328
#endif
329

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

    
349
static const uint32_t dmask4[4] = {
350
    PAT(0x00000000),
351
    PAT(0x0000ffff),
352
    PAT(0xffff0000),
353
    PAT(0xffffffff),
354
};
355

    
356
static uint32_t color_table[2][8];
357

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

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

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

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

    
440
    printf(" fg: %d bg: %d ch:'%2X' '%c'\n", t_attrib->fgcol, t_attrib->bgcol, ch, ch);
441
}
442
#endif
443

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

    
453
#ifdef DEBUG_CONSOLE
454
    printf("x: %2i y: %2i", x, y);
455
    console_print_text_attributes(t_attrib, ch);
456
#endif
457

    
458
    if (t_attrib->invers) {
459
        bgcol = color_table[t_attrib->bold][t_attrib->fgcol];
460
        fgcol = color_table[t_attrib->bold][t_attrib->bgcol];
461
    } else {
462
        fgcol = color_table[t_attrib->bold][t_attrib->fgcol];
463
        bgcol = color_table[t_attrib->bold][t_attrib->bgcol];
464
    }
465

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

    
520
static void text_console_resize(TextConsole *s)
521
{
522
    TextCell *cells, *c, *c1;
523
    int w1, x, y, last_width;
524

    
525
    last_width = s->width;
526
    s->width = s->g_width / FONT_WIDTH;
527
    s->height = s->g_height / FONT_HEIGHT;
528

    
529
    w1 = last_width;
530
    if (s->width < w1)
531
        w1 = s->width;
532

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

    
552
static inline void text_update_xy(TextConsole *s, int x, int y)
553
{
554
    s->text_x[0] = MIN(s->text_x[0], x);
555
    s->text_x[1] = MAX(s->text_x[1], x);
556
    s->text_y[0] = MIN(s->text_y[0], y);
557
    s->text_y[1] = MAX(s->text_y[1], y);
558
}
559

    
560
static void invalidate_xy(TextConsole *s, int x, int y)
561
{
562
    if (s->update_x0 > x * FONT_WIDTH)
563
        s->update_x0 = x * FONT_WIDTH;
564
    if (s->update_y0 > y * FONT_HEIGHT)
565
        s->update_y0 = y * FONT_HEIGHT;
566
    if (s->update_x1 < (x + 1) * FONT_WIDTH)
567
        s->update_x1 = (x + 1) * FONT_WIDTH;
568
    if (s->update_y1 < (y + 1) * FONT_HEIGHT)
569
        s->update_y1 = (y + 1) * FONT_HEIGHT;
570
}
571

    
572
static void update_xy(TextConsole *s, int x, int y)
573
{
574
    TextCell *c;
575
    int y1, y2;
576

    
577
    if (s == active_console) {
578
        if (!ds_get_bits_per_pixel(s->ds)) {
579
            text_update_xy(s, x, y);
580
            return;
581
        }
582

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

    
596
static void console_show_cursor(TextConsole *s, int show)
597
{
598
    TextCell *c;
599
    int y, y1;
600

    
601
    if (s == active_console) {
602
        int x = s->x;
603

    
604
        if (!ds_get_bits_per_pixel(s->ds)) {
605
            s->cursor_invalidate = 1;
606
            return;
607
        }
608

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

    
630
static void console_refresh(TextConsole *s)
631
{
632
    TextCell *c;
633
    int x, y, y1;
634

    
635
    if (s != active_console)
636
        return;
637
    if (!ds_get_bits_per_pixel(s->ds)) {
638
        s->text_x[0] = 0;
639
        s->text_y[0] = 0;
640
        s->text_x[1] = s->width - 1;
641
        s->text_y[1] = s->height - 1;
642
        s->cursor_invalidate = 1;
643
        return;
644
    }
645

    
646
    vga_fill_rect(s->ds, 0, 0, ds_get_width(s->ds), ds_get_height(s->ds),
647
                  color_table[0][COLOR_BLACK]);
648
    y1 = s->y_displayed;
649
    for(y = 0; y < s->height; y++) {
650
        c = s->cells + y1 * s->width;
651
        for(x = 0; x < s->width; x++) {
652
            vga_putcharxy(s->ds, x, y, c->ch,
653
                          &(c->t_attrib));
654
            c++;
655
        }
656
        if (++y1 == s->total_height)
657
            y1 = 0;
658
    }
659
    console_show_cursor(s, 1);
660
    dpy_update(s->ds, 0, 0, ds_get_width(s->ds), ds_get_height(s->ds));
661
}
662

    
663
static void console_scroll(int ydelta)
664
{
665
    TextConsole *s;
666
    int i, y1;
667

    
668
    s = active_console;
669
    if (!s || (s->console_type == GRAPHIC_CONSOLE))
670
        return;
671

    
672
    if (ydelta > 0) {
673
        for(i = 0; i < ydelta; i++) {
674
            if (s->y_displayed == s->y_base)
675
                break;
676
            if (++s->y_displayed == s->total_height)
677
                s->y_displayed = 0;
678
        }
679
    } else {
680
        ydelta = -ydelta;
681
        i = s->backscroll_height;
682
        if (i > s->total_height - s->height)
683
            i = s->total_height - s->height;
684
        y1 = s->y_base - i;
685
        if (y1 < 0)
686
            y1 += s->total_height;
687
        for(i = 0; i < ydelta; i++) {
688
            if (s->y_displayed == y1)
689
                break;
690
            if (--s->y_displayed < 0)
691
                s->y_displayed = s->total_height - 1;
692
        }
693
    }
694
    console_refresh(s);
695
}
696

    
697
static void console_put_lf(TextConsole *s)
698
{
699
    TextCell *c;
700
    int x, y1;
701

    
702
    s->y++;
703
    if (s->y >= s->height) {
704
        s->y = s->height - 1;
705

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

    
730
            vga_bitblt(s->ds, 0, FONT_HEIGHT, 0, 0,
731
                       s->width * FONT_WIDTH,
732
                       (s->height - 1) * FONT_HEIGHT);
733
            vga_fill_rect(s->ds, 0, (s->height - 1) * FONT_HEIGHT,
734
                          s->width * FONT_WIDTH, FONT_HEIGHT,
735
                          color_table[0][s->t_attrib_default.bgcol]);
736
            s->update_x0 = 0;
737
            s->update_y0 = 0;
738
            s->update_x1 = s->width * FONT_WIDTH;
739
            s->update_y1 = s->height * FONT_HEIGHT;
740
        }
741
    }
742
}
743

    
744
/* Set console attributes depending on the current escape codes.
745
 * NOTE: I know this code is not very efficient (checking every color for it
746
 * self) but it is more readable and better maintainable.
747
 */
748
static void console_handle_escape(TextConsole *s)
749
{
750
    int i;
751

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

    
841
static void console_clear_xy(TextConsole *s, int x, int y)
842
{
843
    int y1 = (s->y_base + y) % s->total_height;
844
    TextCell *c = &s->cells[y1 * s->width + x];
845
    c->ch = ' ';
846
    c->t_attrib = s->t_attrib_default;
847
    update_xy(s, x, y);
848
}
849

    
850
static void console_putchar(TextConsole *s, int ch)
851
{
852
    TextCell *c;
853
    int y1, i;
854
    int x, y;
855

    
856
    switch(s->state) {
857
    case TTY_STATE_NORM:
858
        switch(ch) {
859
        case '\r':  /* carriage return */
860
            s->x = 0;
861
            break;
862
        case '\n':  /* newline */
863
            console_put_lf(s);
864
            break;
865
        case '\b':  /* backspace */
866
            if (s->x > 0)
867
                s->x--;
868
            break;
869
        case '\t':  /* tabspace */
870
            if (s->x + (8 - (s->x % 8)) > s->width) {
871
                s->x = 0;
872
                console_put_lf(s);
873
            } else {
874
                s->x = s->x + (8 - (s->x % 8));
875
            }
876
            break;
877
        case '\a':  /* alert aka. bell */
878
            /* TODO: has to be implemented */
879
            break;
880
        case 14:
881
            /* SI (shift in), character set 0 (ignored) */
882
            break;
883
        case 15:
884
            /* SO (shift out), character set 1 (ignored) */
885
            break;
886
        case 27:    /* esc (introducing an escape sequence) */
887
            s->state = TTY_STATE_ESC;
888
            break;
889
        default:
890
            if (s->x >= s->width) {
891
                /* line wrap */
892
                s->x = 0;
893
                console_put_lf(s);
894
            }
895
            y1 = (s->y_base + s->y) % s->total_height;
896
            c = &s->cells[y1 * s->width + s->x];
897
            c->ch = ch;
898
            c->t_attrib = s->t_attrib;
899
            update_xy(s, s->x, s->y);
900
            s->x++;
901
            break;
902
        }
903
        break;
904
    case TTY_STATE_ESC: /* check if it is a terminal escape sequence */
905
        if (ch == '[') {
906
            for(i=0;i<MAX_ESC_PARAMS;i++)
907
                s->esc_params[i] = 0;
908
            s->nb_esc_params = 0;
909
            s->state = TTY_STATE_CSI;
910
        } else {
911
            s->state = TTY_STATE_NORM;
912
        }
913
        break;
914
    case TTY_STATE_CSI: /* handle escape sequence parameters */
915
        if (ch >= '0' && ch <= '9') {
916
            if (s->nb_esc_params < MAX_ESC_PARAMS) {
917
                s->esc_params[s->nb_esc_params] =
918
                    s->esc_params[s->nb_esc_params] * 10 + ch - '0';
919
            }
920
        } else {
921
            s->nb_esc_params++;
922
            if (ch == ';')
923
                break;
924
#ifdef DEBUG_CONSOLE
925
            fprintf(stderr, "escape sequence CSI%d;%d%c, %d parameters\n",
926
                    s->esc_params[0], s->esc_params[1], ch, s->nb_esc_params);
927
#endif
928
            s->state = TTY_STATE_NORM;
929
            switch(ch) {
930
            case 'A':
931
                /* move cursor up */
932
                if (s->esc_params[0] == 0) {
933
                    s->esc_params[0] = 1;
934
                }
935
                s->y -= s->esc_params[0];
936
                if (s->y < 0) {
937
                    s->y = 0;
938
                }
939
                break;
940
            case 'B':
941
                /* move cursor down */
942
                if (s->esc_params[0] == 0) {
943
                    s->esc_params[0] = 1;
944
                }
945
                s->y += s->esc_params[0];
946
                if (s->y >= s->height) {
947
                    s->y = s->height - 1;
948
                }
949
                break;
950
            case 'C':
951
                /* move cursor right */
952
                if (s->esc_params[0] == 0) {
953
                    s->esc_params[0] = 1;
954
                }
955
                s->x += s->esc_params[0];
956
                if (s->x >= s->width) {
957
                    s->x = s->width - 1;
958
                }
959
                break;
960
            case 'D':
961
                /* move cursor left */
962
                if (s->esc_params[0] == 0) {
963
                    s->esc_params[0] = 1;
964
                }
965
                s->x -= s->esc_params[0];
966
                if (s->x < 0) {
967
                    s->x = 0;
968
                }
969
                break;
970
            case 'G':
971
                /* move cursor to column */
972
                s->x = s->esc_params[0] - 1;
973
                if (s->x < 0) {
974
                    s->x = 0;
975
                }
976
                break;
977
            case 'f':
978
            case 'H':
979
                /* move cursor to row, column */
980
                s->x = s->esc_params[1] - 1;
981
                if (s->x < 0) {
982
                    s->x = 0;
983
                }
984
                s->y = s->esc_params[0] - 1;
985
                if (s->y < 0) {
986
                    s->y = 0;
987
                }
988
                break;
989
            case 'J':
990
                switch (s->esc_params[0]) {
991
                case 0:
992
                    /* clear to end of screen */
993
                    for (y = s->y; y < s->height; y++) {
994
                        for (x = 0; x < s->width; x++) {
995
                            if (y == s->y && x < s->x) {
996
                                continue;
997
                            }
998
                            console_clear_xy(s, x, y);
999
                        }
1000
                    }
1001
                    break;
1002
                case 1:
1003
                    /* clear from beginning of screen */
1004
                    for (y = 0; y <= s->y; y++) {
1005
                        for (x = 0; x < s->width; x++) {
1006
                            if (y == s->y && x > s->x) {
1007
                                break;
1008
                            }
1009
                            console_clear_xy(s, x, y);
1010
                        }
1011
                    }
1012
                    break;
1013
                case 2:
1014
                    /* clear entire screen */
1015
                    for (y = 0; y <= s->height; y++) {
1016
                        for (x = 0; x < s->width; x++) {
1017
                            console_clear_xy(s, x, y);
1018
                        }
1019
                    }
1020
                    break;
1021
                }
1022
                break;
1023
            case 'K':
1024
                switch (s->esc_params[0]) {
1025
                case 0:
1026
                    /* clear to eol */
1027
                    for(x = s->x; x < s->width; x++) {
1028
                        console_clear_xy(s, x, s->y);
1029
                    }
1030
                    break;
1031
                case 1:
1032
                    /* clear from beginning of line */
1033
                    for (x = 0; x <= s->x; x++) {
1034
                        console_clear_xy(s, x, s->y);
1035
                    }
1036
                    break;
1037
                case 2:
1038
                    /* clear entire line */
1039
                    for(x = 0; x < s->width; x++) {
1040
                        console_clear_xy(s, x, s->y);
1041
                    }
1042
                    break;
1043
                }
1044
                break;
1045
            case 'm':
1046
                console_handle_escape(s);
1047
                break;
1048
            case 'n':
1049
                /* report cursor position */
1050
                /* TODO: send ESC[row;colR */
1051
                break;
1052
            case 's':
1053
                /* save cursor position */
1054
                s->x_saved = s->x;
1055
                s->y_saved = s->y;
1056
                break;
1057
            case 'u':
1058
                /* restore cursor position */
1059
                s->x = s->x_saved;
1060
                s->y = s->y_saved;
1061
                break;
1062
            default:
1063
#ifdef DEBUG_CONSOLE
1064
                fprintf(stderr, "unhandled escape character '%c'\n", ch);
1065
#endif
1066
                break;
1067
            }
1068
            break;
1069
        }
1070
    }
1071
}
1072

    
1073
void console_select(unsigned int index)
1074
{
1075
    TextConsole *s;
1076

    
1077
    if (index >= MAX_CONSOLES)
1078
        return;
1079
    if (active_console) {
1080
        active_console->g_width = ds_get_width(active_console->ds);
1081
        active_console->g_height = ds_get_height(active_console->ds);
1082
    }
1083
    s = consoles[index];
1084
    if (s) {
1085
        DisplayState *ds = s->ds;
1086
        active_console = s;
1087
        if (ds_get_bits_per_pixel(s->ds)) {
1088
            ds->surface = qemu_resize_displaysurface(ds, s->g_width, s->g_height);
1089
        } else {
1090
            s->ds->surface->width = s->width;
1091
            s->ds->surface->height = s->height;
1092
        }
1093
        dpy_resize(s->ds);
1094
        vga_hw_invalidate();
1095
    }
1096
}
1097

    
1098
static int console_puts(CharDriverState *chr, const uint8_t *buf, int len)
1099
{
1100
    TextConsole *s = chr->opaque;
1101
    int i;
1102

    
1103
    s->update_x0 = s->width * FONT_WIDTH;
1104
    s->update_y0 = s->height * FONT_HEIGHT;
1105
    s->update_x1 = 0;
1106
    s->update_y1 = 0;
1107
    console_show_cursor(s, 0);
1108
    for(i = 0; i < len; i++) {
1109
        console_putchar(s, buf[i]);
1110
    }
1111
    console_show_cursor(s, 1);
1112
    if (ds_get_bits_per_pixel(s->ds) && s->update_x0 < s->update_x1) {
1113
        dpy_update(s->ds, s->update_x0, s->update_y0,
1114
                   s->update_x1 - s->update_x0,
1115
                   s->update_y1 - s->update_y0);
1116
    }
1117
    return len;
1118
}
1119

    
1120
static void kbd_send_chars(void *opaque)
1121
{
1122
    TextConsole *s = opaque;
1123
    int len;
1124
    uint8_t buf[16];
1125

    
1126
    len = qemu_chr_be_can_write(s->chr);
1127
    if (len > s->out_fifo.count)
1128
        len = s->out_fifo.count;
1129
    if (len > 0) {
1130
        if (len > sizeof(buf))
1131
            len = sizeof(buf);
1132
        qemu_fifo_read(&s->out_fifo, buf, len);
1133
        qemu_chr_be_write(s->chr, buf, len);
1134
    }
1135
    /* characters are pending: we send them a bit later (XXX:
1136
       horrible, should change char device API) */
1137
    if (s->out_fifo.count > 0) {
1138
        qemu_mod_timer(s->kbd_timer, qemu_get_clock_ms(rt_clock) + 1);
1139
    }
1140
}
1141

    
1142
/* called when an ascii key is pressed */
1143
void kbd_put_keysym(int keysym)
1144
{
1145
    TextConsole *s;
1146
    uint8_t buf[16], *q;
1147
    int c;
1148

    
1149
    s = active_console;
1150
    if (!s || (s->console_type == GRAPHIC_CONSOLE))
1151
        return;
1152

    
1153
    switch(keysym) {
1154
    case QEMU_KEY_CTRL_UP:
1155
        console_scroll(-1);
1156
        break;
1157
    case QEMU_KEY_CTRL_DOWN:
1158
        console_scroll(1);
1159
        break;
1160
    case QEMU_KEY_CTRL_PAGEUP:
1161
        console_scroll(-10);
1162
        break;
1163
    case QEMU_KEY_CTRL_PAGEDOWN:
1164
        console_scroll(10);
1165
        break;
1166
    default:
1167
        /* convert the QEMU keysym to VT100 key string */
1168
        q = buf;
1169
        if (keysym >= 0xe100 && keysym <= 0xe11f) {
1170
            *q++ = '\033';
1171
            *q++ = '[';
1172
            c = keysym - 0xe100;
1173
            if (c >= 10)
1174
                *q++ = '0' + (c / 10);
1175
            *q++ = '0' + (c % 10);
1176
            *q++ = '~';
1177
        } else if (keysym >= 0xe120 && keysym <= 0xe17f) {
1178
            *q++ = '\033';
1179
            *q++ = '[';
1180
            *q++ = keysym & 0xff;
1181
        } else if (s->echo && (keysym == '\r' || keysym == '\n')) {
1182
            console_puts(s->chr, (const uint8_t *) "\r", 1);
1183
            *q++ = '\n';
1184
        } else {
1185
            *q++ = keysym;
1186
        }
1187
        if (s->echo) {
1188
            console_puts(s->chr, buf, q - buf);
1189
        }
1190
        if (s->chr->chr_read) {
1191
            qemu_fifo_write(&s->out_fifo, buf, q - buf);
1192
            kbd_send_chars(s);
1193
        }
1194
        break;
1195
    }
1196
}
1197

    
1198
static void text_console_invalidate(void *opaque)
1199
{
1200
    TextConsole *s = (TextConsole *) opaque;
1201
    if (!ds_get_bits_per_pixel(s->ds) && s->console_type == TEXT_CONSOLE) {
1202
        s->g_width = ds_get_width(s->ds);
1203
        s->g_height = ds_get_height(s->ds);
1204
        text_console_resize(s);
1205
    }
1206
    console_refresh(s);
1207
}
1208

    
1209
static void text_console_update(void *opaque, console_ch_t *chardata)
1210
{
1211
    TextConsole *s = (TextConsole *) opaque;
1212
    int i, j, src;
1213

    
1214
    if (s->text_x[0] <= s->text_x[1]) {
1215
        src = (s->y_base + s->text_y[0]) * s->width;
1216
        chardata += s->text_y[0] * s->width;
1217
        for (i = s->text_y[0]; i <= s->text_y[1]; i ++)
1218
            for (j = 0; j < s->width; j ++, src ++)
1219
                console_write_ch(chardata ++, s->cells[src].ch |
1220
                                (s->cells[src].t_attrib.fgcol << 12) |
1221
                                (s->cells[src].t_attrib.bgcol << 8) |
1222
                                (s->cells[src].t_attrib.bold << 21));
1223
        dpy_update(s->ds, s->text_x[0], s->text_y[0],
1224
                   s->text_x[1] - s->text_x[0], i - s->text_y[0]);
1225
        s->text_x[0] = s->width;
1226
        s->text_y[0] = s->height;
1227
        s->text_x[1] = 0;
1228
        s->text_y[1] = 0;
1229
    }
1230
    if (s->cursor_invalidate) {
1231
        dpy_cursor(s->ds, s->x, s->y);
1232
        s->cursor_invalidate = 0;
1233
    }
1234
}
1235

    
1236
static TextConsole *get_graphic_console(DisplayState *ds)
1237
{
1238
    int i;
1239
    TextConsole *s;
1240
    for (i = 0; i < nb_consoles; i++) {
1241
        s = consoles[i];
1242
        if (s->console_type == GRAPHIC_CONSOLE && s->ds == ds)
1243
            return s;
1244
    }
1245
    return NULL;
1246
}
1247

    
1248
static TextConsole *new_console(DisplayState *ds, console_type_t console_type)
1249
{
1250
    TextConsole *s;
1251
    int i;
1252

    
1253
    if (nb_consoles >= MAX_CONSOLES)
1254
        return NULL;
1255
    s = g_malloc0(sizeof(TextConsole));
1256
    if (!active_console || ((active_console->console_type != GRAPHIC_CONSOLE) &&
1257
        (console_type == GRAPHIC_CONSOLE))) {
1258
        active_console = s;
1259
    }
1260
    s->ds = ds;
1261
    s->console_type = console_type;
1262
    if (console_type != GRAPHIC_CONSOLE) {
1263
        s->index = nb_consoles;
1264
        consoles[nb_consoles++] = s;
1265
    } else {
1266
        /* HACK: Put graphical consoles before text consoles.  */
1267
        for (i = nb_consoles; i > 0; i--) {
1268
            if (consoles[i - 1]->console_type == GRAPHIC_CONSOLE)
1269
                break;
1270
            consoles[i] = consoles[i - 1];
1271
            consoles[i]->index = i;
1272
        }
1273
        s->index = i;
1274
        consoles[i] = s;
1275
        nb_consoles++;
1276
    }
1277
    return s;
1278
}
1279

    
1280
static DisplaySurface* defaultallocator_create_displaysurface(int width, int height)
1281
{
1282
    DisplaySurface *surface = (DisplaySurface*) g_malloc0(sizeof(DisplaySurface));
1283

    
1284
    int linesize = width * 4;
1285
    qemu_alloc_display(surface, width, height, linesize,
1286
                       qemu_default_pixelformat(32), 0);
1287
    return surface;
1288
}
1289

    
1290
static DisplaySurface* defaultallocator_resize_displaysurface(DisplaySurface *surface,
1291
                                          int width, int height)
1292
{
1293
    int linesize = width * 4;
1294
    qemu_alloc_display(surface, width, height, linesize,
1295
                       qemu_default_pixelformat(32), 0);
1296
    return surface;
1297
}
1298

    
1299
void qemu_alloc_display(DisplaySurface *surface, int width, int height,
1300
                        int linesize, PixelFormat pf, int newflags)
1301
{
1302
    void *data;
1303
    surface->width = width;
1304
    surface->height = height;
1305
    surface->linesize = linesize;
1306
    surface->pf = pf;
1307
    if (surface->flags & QEMU_ALLOCATED_FLAG) {
1308
        data = g_realloc(surface->data,
1309
                            surface->linesize * surface->height);
1310
    } else {
1311
        data = g_malloc(surface->linesize * surface->height);
1312
    }
1313
    surface->data = (uint8_t *)data;
1314
    surface->flags = newflags | QEMU_ALLOCATED_FLAG;
1315
#ifdef HOST_WORDS_BIGENDIAN
1316
    surface->flags |= QEMU_BIG_ENDIAN_FLAG;
1317
#endif
1318
}
1319

    
1320
DisplaySurface* qemu_create_displaysurface_from(int width, int height, int bpp,
1321
                                              int linesize, uint8_t *data)
1322
{
1323
    DisplaySurface *surface = (DisplaySurface*) g_malloc0(sizeof(DisplaySurface));
1324

    
1325
    surface->width = width;
1326
    surface->height = height;
1327
    surface->linesize = linesize;
1328
    surface->pf = qemu_default_pixelformat(bpp);
1329
#ifdef HOST_WORDS_BIGENDIAN
1330
    surface->flags = QEMU_BIG_ENDIAN_FLAG;
1331
#endif
1332
    surface->data = data;
1333

    
1334
    return surface;
1335
}
1336

    
1337
static void defaultallocator_free_displaysurface(DisplaySurface *surface)
1338
{
1339
    if (surface == NULL)
1340
        return;
1341
    if (surface->flags & QEMU_ALLOCATED_FLAG)
1342
        g_free(surface->data);
1343
    g_free(surface);
1344
}
1345

    
1346
static struct DisplayAllocator default_allocator = {
1347
    defaultallocator_create_displaysurface,
1348
    defaultallocator_resize_displaysurface,
1349
    defaultallocator_free_displaysurface
1350
};
1351

    
1352
static void dumb_display_init(void)
1353
{
1354
    DisplayState *ds = g_malloc0(sizeof(DisplayState));
1355
    int width = 640;
1356
    int height = 480;
1357

    
1358
    ds->allocator = &default_allocator;
1359
    if (is_fixedsize_console()) {
1360
        width = active_console->g_width;
1361
        height = active_console->g_height;
1362
    }
1363
    ds->surface = qemu_create_displaysurface(ds, width, height);
1364
    register_displaystate(ds);
1365
}
1366

    
1367
/***********************************************************/
1368
/* register display */
1369

    
1370
void register_displaystate(DisplayState *ds)
1371
{
1372
    DisplayState **s;
1373
    s = &display_state;
1374
    while (*s != NULL)
1375
        s = &(*s)->next;
1376
    ds->next = NULL;
1377
    *s = ds;
1378
}
1379

    
1380
DisplayState *get_displaystate(void)
1381
{
1382
    if (!display_state) {
1383
        dumb_display_init ();
1384
    }
1385
    return display_state;
1386
}
1387

    
1388
DisplayAllocator *register_displayallocator(DisplayState *ds, DisplayAllocator *da)
1389
{
1390
    if(ds->allocator ==  &default_allocator) {
1391
        DisplaySurface *surf;
1392
        surf = da->create_displaysurface(ds_get_width(ds), ds_get_height(ds));
1393
        defaultallocator_free_displaysurface(ds->surface);
1394
        ds->surface = surf;
1395
        ds->allocator = da;
1396
    }
1397
    return ds->allocator;
1398
}
1399

    
1400
DisplayState *graphic_console_init(vga_hw_update_ptr update,
1401
                                   vga_hw_invalidate_ptr invalidate,
1402
                                   vga_hw_screen_dump_ptr screen_dump,
1403
                                   vga_hw_text_update_ptr text_update,
1404
                                   void *opaque)
1405
{
1406
    TextConsole *s;
1407
    DisplayState *ds;
1408

    
1409
    ds = (DisplayState *) g_malloc0(sizeof(DisplayState));
1410
    ds->allocator = &default_allocator; 
1411
    ds->surface = qemu_create_displaysurface(ds, 640, 480);
1412

    
1413
    s = new_console(ds, GRAPHIC_CONSOLE);
1414
    if (s == NULL) {
1415
        qemu_free_displaysurface(ds);
1416
        g_free(ds);
1417
        return NULL;
1418
    }
1419
    s->hw_update = update;
1420
    s->hw_invalidate = invalidate;
1421
    s->hw_screen_dump = screen_dump;
1422
    s->hw_text_update = text_update;
1423
    s->hw = opaque;
1424

    
1425
    register_displaystate(ds);
1426
    return ds;
1427
}
1428

    
1429
int is_graphic_console(void)
1430
{
1431
    return active_console && active_console->console_type == GRAPHIC_CONSOLE;
1432
}
1433

    
1434
int is_fixedsize_console(void)
1435
{
1436
    return active_console && active_console->console_type != TEXT_CONSOLE;
1437
}
1438

    
1439
void console_color_init(DisplayState *ds)
1440
{
1441
    int i, j;
1442
    for (j = 0; j < 2; j++) {
1443
        for (i = 0; i < 8; i++) {
1444
            color_table[j][i] = col_expand(ds,
1445
                   vga_get_color(ds, color_table_rgb[j][i]));
1446
        }
1447
    }
1448
}
1449

    
1450
static void text_console_set_echo(CharDriverState *chr, bool echo)
1451
{
1452
    TextConsole *s = chr->opaque;
1453

    
1454
    s->echo = echo;
1455
}
1456

    
1457
static void text_console_do_init(CharDriverState *chr, DisplayState *ds)
1458
{
1459
    TextConsole *s;
1460
    static int color_inited;
1461

    
1462
    s = chr->opaque;
1463

    
1464
    chr->chr_write = console_puts;
1465

    
1466
    s->out_fifo.buf = s->out_fifo_buf;
1467
    s->out_fifo.buf_size = sizeof(s->out_fifo_buf);
1468
    s->kbd_timer = qemu_new_timer_ms(rt_clock, kbd_send_chars, s);
1469
    s->ds = ds;
1470

    
1471
    if (!color_inited) {
1472
        color_inited = 1;
1473
        console_color_init(s->ds);
1474
    }
1475
    s->y_displayed = 0;
1476
    s->y_base = 0;
1477
    s->total_height = DEFAULT_BACKSCROLL;
1478
    s->x = 0;
1479
    s->y = 0;
1480
    if (s->console_type == TEXT_CONSOLE) {
1481
        s->g_width = ds_get_width(s->ds);
1482
        s->g_height = ds_get_height(s->ds);
1483
    }
1484

    
1485
    s->hw_invalidate = text_console_invalidate;
1486
    s->hw_text_update = text_console_update;
1487
    s->hw = s;
1488

    
1489
    /* Set text attribute defaults */
1490
    s->t_attrib_default.bold = 0;
1491
    s->t_attrib_default.uline = 0;
1492
    s->t_attrib_default.blink = 0;
1493
    s->t_attrib_default.invers = 0;
1494
    s->t_attrib_default.unvisible = 0;
1495
    s->t_attrib_default.fgcol = COLOR_WHITE;
1496
    s->t_attrib_default.bgcol = COLOR_BLACK;
1497
    /* set current text attributes to default */
1498
    s->t_attrib = s->t_attrib_default;
1499
    text_console_resize(s);
1500

    
1501
    if (chr->label) {
1502
        char msg[128];
1503
        int len;
1504

    
1505
        s->t_attrib.bgcol = COLOR_BLUE;
1506
        len = snprintf(msg, sizeof(msg), "%s console\r\n", chr->label);
1507
        console_puts(chr, (uint8_t*)msg, len);
1508
        s->t_attrib = s->t_attrib_default;
1509
    }
1510

    
1511
    qemu_chr_generic_open(chr);
1512
    if (chr->init)
1513
        chr->init(chr);
1514
}
1515

    
1516
CharDriverState *text_console_init(QemuOpts *opts)
1517
{
1518
    CharDriverState *chr;
1519
    TextConsole *s;
1520
    unsigned width;
1521
    unsigned height;
1522

    
1523
    chr = g_malloc0(sizeof(CharDriverState));
1524

    
1525
    width = qemu_opt_get_number(opts, "width", 0);
1526
    if (width == 0)
1527
        width = qemu_opt_get_number(opts, "cols", 0) * FONT_WIDTH;
1528

    
1529
    height = qemu_opt_get_number(opts, "height", 0);
1530
    if (height == 0)
1531
        height = qemu_opt_get_number(opts, "rows", 0) * FONT_HEIGHT;
1532

    
1533
    if (width == 0 || height == 0) {
1534
        s = new_console(NULL, TEXT_CONSOLE);
1535
    } else {
1536
        s = new_console(NULL, TEXT_CONSOLE_FIXED_SIZE);
1537
    }
1538

    
1539
    if (!s) {
1540
        g_free(chr);
1541
        return NULL;
1542
    }
1543

    
1544
    s->chr = chr;
1545
    s->g_width = width;
1546
    s->g_height = height;
1547
    chr->opaque = s;
1548
    chr->chr_set_echo = text_console_set_echo;
1549
    return chr;
1550
}
1551

    
1552
void text_consoles_set_display(DisplayState *ds)
1553
{
1554
    int i;
1555

    
1556
    for (i = 0; i < nb_consoles; i++) {
1557
        if (consoles[i]->console_type != GRAPHIC_CONSOLE) {
1558
            text_console_do_init(consoles[i]->chr, ds);
1559
        }
1560
    }
1561
}
1562

    
1563
void qemu_console_resize(DisplayState *ds, int width, int height)
1564
{
1565
    TextConsole *s = get_graphic_console(ds);
1566
    if (!s) return;
1567

    
1568
    s->g_width = width;
1569
    s->g_height = height;
1570
    if (is_graphic_console()) {
1571
        ds->surface = qemu_resize_displaysurface(ds, width, height);
1572
        dpy_resize(ds);
1573
    }
1574
}
1575

    
1576
void qemu_console_copy(DisplayState *ds, int src_x, int src_y,
1577
                       int dst_x, int dst_y, int w, int h)
1578
{
1579
    if (is_graphic_console()) {
1580
        dpy_copy(ds, src_x, src_y, dst_x, dst_y, w, h);
1581
    }
1582
}
1583

    
1584
PixelFormat qemu_different_endianness_pixelformat(int bpp)
1585
{
1586
    PixelFormat pf;
1587

    
1588
    memset(&pf, 0x00, sizeof(PixelFormat));
1589

    
1590
    pf.bits_per_pixel = bpp;
1591
    pf.bytes_per_pixel = bpp / 8;
1592
    pf.depth = bpp == 32 ? 24 : bpp;
1593

    
1594
    switch (bpp) {
1595
        case 24:
1596
            pf.rmask = 0x000000FF;
1597
            pf.gmask = 0x0000FF00;
1598
            pf.bmask = 0x00FF0000;
1599
            pf.rmax = 255;
1600
            pf.gmax = 255;
1601
            pf.bmax = 255;
1602
            pf.rshift = 0;
1603
            pf.gshift = 8;
1604
            pf.bshift = 16;
1605
            pf.rbits = 8;
1606
            pf.gbits = 8;
1607
            pf.bbits = 8;
1608
            break;
1609
        case 32:
1610
            pf.rmask = 0x0000FF00;
1611
            pf.gmask = 0x00FF0000;
1612
            pf.bmask = 0xFF000000;
1613
            pf.amask = 0x00000000;
1614
            pf.amax = 255;
1615
            pf.rmax = 255;
1616
            pf.gmax = 255;
1617
            pf.bmax = 255;
1618
            pf.ashift = 0;
1619
            pf.rshift = 8;
1620
            pf.gshift = 16;
1621
            pf.bshift = 24;
1622
            pf.rbits = 8;
1623
            pf.gbits = 8;
1624
            pf.bbits = 8;
1625
            pf.abits = 8;
1626
            break;
1627
        default:
1628
            break;
1629
    }
1630
    return pf;
1631
}
1632

    
1633
PixelFormat qemu_default_pixelformat(int bpp)
1634
{
1635
    PixelFormat pf;
1636

    
1637
    memset(&pf, 0x00, sizeof(PixelFormat));
1638

    
1639
    pf.bits_per_pixel = bpp;
1640
    pf.bytes_per_pixel = bpp / 8;
1641
    pf.depth = bpp == 32 ? 24 : bpp;
1642

    
1643
    switch (bpp) {
1644
        case 15:
1645
            pf.bits_per_pixel = 16;
1646
            pf.bytes_per_pixel = 2;
1647
            pf.rmask = 0x00007c00;
1648
            pf.gmask = 0x000003E0;
1649
            pf.bmask = 0x0000001F;
1650
            pf.rmax = 31;
1651
            pf.gmax = 31;
1652
            pf.bmax = 31;
1653
            pf.rshift = 10;
1654
            pf.gshift = 5;
1655
            pf.bshift = 0;
1656
            pf.rbits = 5;
1657
            pf.gbits = 5;
1658
            pf.bbits = 5;
1659
            break;
1660
        case 16:
1661
            pf.rmask = 0x0000F800;
1662
            pf.gmask = 0x000007E0;
1663
            pf.bmask = 0x0000001F;
1664
            pf.rmax = 31;
1665
            pf.gmax = 63;
1666
            pf.bmax = 31;
1667
            pf.rshift = 11;
1668
            pf.gshift = 5;
1669
            pf.bshift = 0;
1670
            pf.rbits = 5;
1671
            pf.gbits = 6;
1672
            pf.bbits = 5;
1673
            break;
1674
        case 24:
1675
            pf.rmask = 0x00FF0000;
1676
            pf.gmask = 0x0000FF00;
1677
            pf.bmask = 0x000000FF;
1678
            pf.rmax = 255;
1679
            pf.gmax = 255;
1680
            pf.bmax = 255;
1681
            pf.rshift = 16;
1682
            pf.gshift = 8;
1683
            pf.bshift = 0;
1684
            pf.rbits = 8;
1685
            pf.gbits = 8;
1686
            pf.bbits = 8;
1687
            break;
1688
        case 32:
1689
            pf.rmask = 0x00FF0000;
1690
            pf.gmask = 0x0000FF00;
1691
            pf.bmask = 0x000000FF;
1692
            pf.amax = 255;
1693
            pf.rmax = 255;
1694
            pf.gmax = 255;
1695
            pf.bmax = 255;
1696
            pf.ashift = 24;
1697
            pf.rshift = 16;
1698
            pf.gshift = 8;
1699
            pf.bshift = 0;
1700
            pf.rbits = 8;
1701
            pf.gbits = 8;
1702
            pf.bbits = 8;
1703
            pf.abits = 8;
1704
            break;
1705
        default:
1706
            break;
1707
    }
1708
    return pf;
1709
}