Statistics
| Branch: | Revision:

root / console.c @ 16735102

History | View | Annotate | Download (46.8 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

    
180
    previous_active_console = active_console;
181

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

    
191
    if (previous_active_console) {
192
        console_select(previous_active_console->index);
193
    }
194
}
195

    
196
void vga_hw_text_update(console_ch_t *chardata)
197
{
198
    if (active_console && active_console->hw_text_update)
199
        active_console->hw_text_update(active_console->hw, chardata);
200
}
201

    
202
/* convert a RGBA color to a color index usable in graphic primitives */
203
static unsigned int vga_get_color(DisplayState *ds, unsigned int rgba)
204
{
205
    unsigned int r, g, b, color;
206

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

    
238
static void vga_fill_rect (DisplayState *ds,
239
                           int posx, int posy, int width, int height, uint32_t color)
240
{
241
    uint8_t *d, *d1;
242
    int x, y, bpp;
243

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

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

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

    
305
/***********************************************************/
306
/* basic char display */
307

    
308
#define FONT_HEIGHT 16
309
#define FONT_WIDTH 8
310

    
311
#include "vgafont.h"
312

    
313
#define cbswap_32(__x) \
314
((uint32_t)( \
315
                (((uint32_t)(__x) & (uint32_t)0x000000ffUL) << 24) | \
316
                (((uint32_t)(__x) & (uint32_t)0x0000ff00UL) <<  8) | \
317
                (((uint32_t)(__x) & (uint32_t)0x00ff0000UL) >>  8) | \
318
                (((uint32_t)(__x) & (uint32_t)0xff000000UL) >> 24) ))
319

    
320
#ifdef HOST_WORDS_BIGENDIAN
321
#define PAT(x) x
322
#else
323
#define PAT(x) cbswap_32(x)
324
#endif
325

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

    
345
static const uint32_t dmask4[4] = {
346
    PAT(0x00000000),
347
    PAT(0x0000ffff),
348
    PAT(0xffff0000),
349
    PAT(0xffffffff),
350
};
351

    
352
static uint32_t color_table[2][8];
353

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

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

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

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

    
436
    printf(" fg: %d bg: %d ch:'%2X' '%c'\n", t_attrib->fgcol, t_attrib->bgcol, ch, ch);
437
}
438
#endif
439

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

    
449
#ifdef DEBUG_CONSOLE
450
    printf("x: %2i y: %2i", x, y);
451
    console_print_text_attributes(t_attrib, ch);
452
#endif
453

    
454
    if (t_attrib->invers) {
455
        bgcol = color_table[t_attrib->bold][t_attrib->fgcol];
456
        fgcol = color_table[t_attrib->bold][t_attrib->bgcol];
457
    } else {
458
        fgcol = color_table[t_attrib->bold][t_attrib->fgcol];
459
        bgcol = color_table[t_attrib->bold][t_attrib->bgcol];
460
    }
461

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

    
516
static void text_console_resize(TextConsole *s)
517
{
518
    TextCell *cells, *c, *c1;
519
    int w1, x, y, last_width;
520

    
521
    last_width = s->width;
522
    s->width = s->g_width / FONT_WIDTH;
523
    s->height = s->g_height / FONT_HEIGHT;
524

    
525
    w1 = last_width;
526
    if (s->width < w1)
527
        w1 = s->width;
528

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

    
548
static inline void text_update_xy(TextConsole *s, int x, int y)
549
{
550
    s->text_x[0] = MIN(s->text_x[0], x);
551
    s->text_x[1] = MAX(s->text_x[1], x);
552
    s->text_y[0] = MIN(s->text_y[0], y);
553
    s->text_y[1] = MAX(s->text_y[1], y);
554
}
555

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

    
568
static void update_xy(TextConsole *s, int x, int y)
569
{
570
    TextCell *c;
571
    int y1, y2;
572

    
573
    if (s == active_console) {
574
        if (!ds_get_bits_per_pixel(s->ds)) {
575
            text_update_xy(s, x, y);
576
            return;
577
        }
578

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

    
592
static void console_show_cursor(TextConsole *s, int show)
593
{
594
    TextCell *c;
595
    int y, y1;
596

    
597
    if (s == active_console) {
598
        int x = s->x;
599

    
600
        if (!ds_get_bits_per_pixel(s->ds)) {
601
            s->cursor_invalidate = 1;
602
            return;
603
        }
604

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

    
626
static void console_refresh(TextConsole *s)
627
{
628
    TextCell *c;
629
    int x, y, y1;
630

    
631
    if (s != active_console)
632
        return;
633
    if (!ds_get_bits_per_pixel(s->ds)) {
634
        s->text_x[0] = 0;
635
        s->text_y[0] = 0;
636
        s->text_x[1] = s->width - 1;
637
        s->text_y[1] = s->height - 1;
638
        s->cursor_invalidate = 1;
639
        return;
640
    }
641

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

    
659
static void console_scroll(int ydelta)
660
{
661
    TextConsole *s;
662
    int i, y1;
663

    
664
    s = active_console;
665
    if (!s || (s->console_type == GRAPHIC_CONSOLE))
666
        return;
667

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

    
693
static void console_put_lf(TextConsole *s)
694
{
695
    TextCell *c;
696
    int x, y1;
697

    
698
    s->y++;
699
    if (s->y >= s->height) {
700
        s->y = s->height - 1;
701

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

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

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

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

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

    
846
static void console_putchar(TextConsole *s, int ch)
847
{
848
    TextCell *c;
849
    int y1, i;
850
    int x, y;
851

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

    
1069
void console_select(unsigned int index)
1070
{
1071
    TextConsole *s;
1072

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

    
1094
static int console_puts(CharDriverState *chr, const uint8_t *buf, int len)
1095
{
1096
    TextConsole *s = chr->opaque;
1097
    int i;
1098

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

    
1116
static void kbd_send_chars(void *opaque)
1117
{
1118
    TextConsole *s = opaque;
1119
    int len;
1120
    uint8_t buf[16];
1121

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

    
1138
/* called when an ascii key is pressed */
1139
void kbd_put_keysym(int keysym)
1140
{
1141
    TextConsole *s;
1142
    uint8_t buf[16], *q;
1143
    int c;
1144

    
1145
    s = active_console;
1146
    if (!s || (s->console_type == GRAPHIC_CONSOLE))
1147
        return;
1148

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

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

    
1205
static void text_console_update(void *opaque, console_ch_t *chardata)
1206
{
1207
    TextConsole *s = (TextConsole *) opaque;
1208
    int i, j, src;
1209

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

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

    
1244
static TextConsole *new_console(DisplayState *ds, console_type_t console_type)
1245
{
1246
    TextConsole *s;
1247
    int i;
1248

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

    
1276
static DisplaySurface* defaultallocator_create_displaysurface(int width, int height)
1277
{
1278
    DisplaySurface *surface = (DisplaySurface*) g_malloc0(sizeof(DisplaySurface));
1279

    
1280
    int linesize = width * 4;
1281
    qemu_alloc_display(surface, width, height, linesize,
1282
                       qemu_default_pixelformat(32), 0);
1283
    return surface;
1284
}
1285

    
1286
static DisplaySurface* defaultallocator_resize_displaysurface(DisplaySurface *surface,
1287
                                          int width, int height)
1288
{
1289
    int linesize = width * 4;
1290
    qemu_alloc_display(surface, width, height, linesize,
1291
                       qemu_default_pixelformat(32), 0);
1292
    return surface;
1293
}
1294

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

    
1316
DisplaySurface* qemu_create_displaysurface_from(int width, int height, int bpp,
1317
                                              int linesize, uint8_t *data)
1318
{
1319
    DisplaySurface *surface = (DisplaySurface*) g_malloc0(sizeof(DisplaySurface));
1320

    
1321
    surface->width = width;
1322
    surface->height = height;
1323
    surface->linesize = linesize;
1324
    surface->pf = qemu_default_pixelformat(bpp);
1325
#ifdef HOST_WORDS_BIGENDIAN
1326
    surface->flags = QEMU_BIG_ENDIAN_FLAG;
1327
#endif
1328
    surface->data = data;
1329

    
1330
    return surface;
1331
}
1332

    
1333
static void defaultallocator_free_displaysurface(DisplaySurface *surface)
1334
{
1335
    if (surface == NULL)
1336
        return;
1337
    if (surface->flags & QEMU_ALLOCATED_FLAG)
1338
        g_free(surface->data);
1339
    g_free(surface);
1340
}
1341

    
1342
static struct DisplayAllocator default_allocator = {
1343
    defaultallocator_create_displaysurface,
1344
    defaultallocator_resize_displaysurface,
1345
    defaultallocator_free_displaysurface
1346
};
1347

    
1348
static void dumb_display_init(void)
1349
{
1350
    DisplayState *ds = g_malloc0(sizeof(DisplayState));
1351
    int width = 640;
1352
    int height = 480;
1353

    
1354
    ds->allocator = &default_allocator;
1355
    if (is_fixedsize_console()) {
1356
        width = active_console->g_width;
1357
        height = active_console->g_height;
1358
    }
1359
    ds->surface = qemu_create_displaysurface(ds, width, height);
1360
    register_displaystate(ds);
1361
}
1362

    
1363
/***********************************************************/
1364
/* register display */
1365

    
1366
void register_displaystate(DisplayState *ds)
1367
{
1368
    DisplayState **s;
1369
    s = &display_state;
1370
    while (*s != NULL)
1371
        s = &(*s)->next;
1372
    ds->next = NULL;
1373
    *s = ds;
1374
}
1375

    
1376
DisplayState *get_displaystate(void)
1377
{
1378
    if (!display_state) {
1379
        dumb_display_init ();
1380
    }
1381
    return display_state;
1382
}
1383

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

    
1396
DisplayState *graphic_console_init(vga_hw_update_ptr update,
1397
                                   vga_hw_invalidate_ptr invalidate,
1398
                                   vga_hw_screen_dump_ptr screen_dump,
1399
                                   vga_hw_text_update_ptr text_update,
1400
                                   void *opaque)
1401
{
1402
    TextConsole *s;
1403
    DisplayState *ds;
1404

    
1405
    ds = (DisplayState *) g_malloc0(sizeof(DisplayState));
1406
    ds->allocator = &default_allocator; 
1407
    ds->surface = qemu_create_displaysurface(ds, 640, 480);
1408

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

    
1421
    register_displaystate(ds);
1422
    return ds;
1423
}
1424

    
1425
int is_graphic_console(void)
1426
{
1427
    return active_console && active_console->console_type == GRAPHIC_CONSOLE;
1428
}
1429

    
1430
int is_fixedsize_console(void)
1431
{
1432
    return active_console && active_console->console_type != TEXT_CONSOLE;
1433
}
1434

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

    
1446
static void text_console_set_echo(CharDriverState *chr, bool echo)
1447
{
1448
    TextConsole *s = chr->opaque;
1449

    
1450
    s->echo = echo;
1451
}
1452

    
1453
static void text_console_do_init(CharDriverState *chr, DisplayState *ds)
1454
{
1455
    TextConsole *s;
1456
    static int color_inited;
1457

    
1458
    s = chr->opaque;
1459

    
1460
    chr->chr_write = console_puts;
1461

    
1462
    s->out_fifo.buf = s->out_fifo_buf;
1463
    s->out_fifo.buf_size = sizeof(s->out_fifo_buf);
1464
    s->kbd_timer = qemu_new_timer_ms(rt_clock, kbd_send_chars, s);
1465
    s->ds = ds;
1466

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

    
1481
    s->hw_invalidate = text_console_invalidate;
1482
    s->hw_text_update = text_console_update;
1483
    s->hw = s;
1484

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

    
1497
    if (chr->label) {
1498
        char msg[128];
1499
        int len;
1500

    
1501
        s->t_attrib.bgcol = COLOR_BLUE;
1502
        len = snprintf(msg, sizeof(msg), "%s console\r\n", chr->label);
1503
        console_puts(chr, (uint8_t*)msg, len);
1504
        s->t_attrib = s->t_attrib_default;
1505
    }
1506

    
1507
    qemu_chr_generic_open(chr);
1508
    if (chr->init)
1509
        chr->init(chr);
1510
}
1511

    
1512
CharDriverState *text_console_init(QemuOpts *opts)
1513
{
1514
    CharDriverState *chr;
1515
    TextConsole *s;
1516
    unsigned width;
1517
    unsigned height;
1518

    
1519
    chr = g_malloc0(sizeof(CharDriverState));
1520

    
1521
    width = qemu_opt_get_number(opts, "width", 0);
1522
    if (width == 0)
1523
        width = qemu_opt_get_number(opts, "cols", 0) * FONT_WIDTH;
1524

    
1525
    height = qemu_opt_get_number(opts, "height", 0);
1526
    if (height == 0)
1527
        height = qemu_opt_get_number(opts, "rows", 0) * FONT_HEIGHT;
1528

    
1529
    if (width == 0 || height == 0) {
1530
        s = new_console(NULL, TEXT_CONSOLE);
1531
    } else {
1532
        s = new_console(NULL, TEXT_CONSOLE_FIXED_SIZE);
1533
    }
1534

    
1535
    if (!s) {
1536
        g_free(chr);
1537
        return NULL;
1538
    }
1539

    
1540
    s->chr = chr;
1541
    s->g_width = width;
1542
    s->g_height = height;
1543
    chr->opaque = s;
1544
    chr->chr_set_echo = text_console_set_echo;
1545
    return chr;
1546
}
1547

    
1548
void text_consoles_set_display(DisplayState *ds)
1549
{
1550
    int i;
1551

    
1552
    for (i = 0; i < nb_consoles; i++) {
1553
        if (consoles[i]->console_type != GRAPHIC_CONSOLE) {
1554
            text_console_do_init(consoles[i]->chr, ds);
1555
        }
1556
    }
1557
}
1558

    
1559
void qemu_console_resize(DisplayState *ds, int width, int height)
1560
{
1561
    TextConsole *s = get_graphic_console(ds);
1562
    if (!s) return;
1563

    
1564
    s->g_width = width;
1565
    s->g_height = height;
1566
    if (is_graphic_console()) {
1567
        ds->surface = qemu_resize_displaysurface(ds, width, height);
1568
        dpy_resize(ds);
1569
    }
1570
}
1571

    
1572
void qemu_console_copy(DisplayState *ds, int src_x, int src_y,
1573
                       int dst_x, int dst_y, int w, int h)
1574
{
1575
    if (is_graphic_console()) {
1576
        dpy_copy(ds, src_x, src_y, dst_x, dst_y, w, h);
1577
    }
1578
}
1579

    
1580
PixelFormat qemu_different_endianness_pixelformat(int bpp)
1581
{
1582
    PixelFormat pf;
1583

    
1584
    memset(&pf, 0x00, sizeof(PixelFormat));
1585

    
1586
    pf.bits_per_pixel = bpp;
1587
    pf.bytes_per_pixel = bpp / 8;
1588
    pf.depth = bpp == 32 ? 24 : bpp;
1589

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

    
1629
PixelFormat qemu_default_pixelformat(int bpp)
1630
{
1631
    PixelFormat pf;
1632

    
1633
    memset(&pf, 0x00, sizeof(PixelFormat));
1634

    
1635
    pf.bits_per_pixel = bpp;
1636
    pf.bytes_per_pixel = bpp / 8;
1637
    pf.depth = bpp == 32 ? 24 : bpp;
1638

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