Statistics
| Branch: | Revision:

root / console.c @ e34b12ae

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
    console_type_t console_type;
119
    DisplayState *ds;
120
    /* Graphic console state.  */
121
    vga_hw_update_ptr hw_update;
122
    vga_hw_invalidate_ptr hw_invalidate;
123
    vga_hw_screen_dump_ptr hw_screen_dump;
124
    vga_hw_text_update_ptr hw_text_update;
125
    void *hw;
126

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

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

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

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

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

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

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

    
175
void vga_hw_screen_dump(const char *filename)
176
{
177
    TextConsole *previous_active_console;
178

    
179
    previous_active_console = active_console;
180
    active_console = consoles[0];
181
    /* There is currently no way of specifying which screen we want to dump,
182
       so always dump the first one.  */
183
    if (consoles[0] && consoles[0]->hw_screen_dump)
184
        consoles[0]->hw_screen_dump(consoles[0]->hw, filename);
185
    active_console = previous_active_console;
186
}
187

    
188
void vga_hw_text_update(console_ch_t *chardata)
189
{
190
    if (active_console && active_console->hw_text_update)
191
        active_console->hw_text_update(active_console->hw, chardata);
192
}
193

    
194
/* convert a RGBA color to a color index usable in graphic primitives */
195
static unsigned int vga_get_color(DisplayState *ds, unsigned int rgba)
196
{
197
    unsigned int r, g, b, color;
198

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

    
230
static void vga_fill_rect (DisplayState *ds,
231
                           int posx, int posy, int width, int height, uint32_t color)
232
{
233
    uint8_t *d, *d1;
234
    int x, y, bpp;
235

    
236
    bpp = (ds_get_bits_per_pixel(ds) + 7) >> 3;
237
    d1 = ds_get_data(ds) +
238
        ds_get_linesize(ds) * posy + bpp * posx;
239
    for (y = 0; y < height; y++) {
240
        d = d1;
241
        switch(bpp) {
242
        case 1:
243
            for (x = 0; x < width; x++) {
244
                *((uint8_t *)d) = color;
245
                d++;
246
            }
247
            break;
248
        case 2:
249
            for (x = 0; x < width; x++) {
250
                *((uint16_t *)d) = color;
251
                d += 2;
252
            }
253
            break;
254
        case 4:
255
            for (x = 0; x < width; x++) {
256
                *((uint32_t *)d) = color;
257
                d += 4;
258
            }
259
            break;
260
        }
261
        d1 += ds_get_linesize(ds);
262
    }
263
}
264

    
265
/* copy from (xs, ys) to (xd, yd) a rectangle of size (w, h) */
266
static void vga_bitblt(DisplayState *ds, int xs, int ys, int xd, int yd, int w, int h)
267
{
268
    const uint8_t *s;
269
    uint8_t *d;
270
    int wb, y, bpp;
271

    
272
    bpp = (ds_get_bits_per_pixel(ds) + 7) >> 3;
273
    wb = w * bpp;
274
    if (yd <= ys) {
275
        s = ds_get_data(ds) +
276
            ds_get_linesize(ds) * ys + bpp * xs;
277
        d = ds_get_data(ds) +
278
            ds_get_linesize(ds) * yd + bpp * xd;
279
        for (y = 0; y < h; y++) {
280
            memmove(d, s, wb);
281
            d += ds_get_linesize(ds);
282
            s += ds_get_linesize(ds);
283
        }
284
    } else {
285
        s = ds_get_data(ds) +
286
            ds_get_linesize(ds) * (ys + h - 1) + bpp * xs;
287
        d = ds_get_data(ds) +
288
            ds_get_linesize(ds) * (yd + h - 1) + bpp * xd;
289
       for (y = 0; y < h; y++) {
290
            memmove(d, s, wb);
291
            d -= ds_get_linesize(ds);
292
            s -= ds_get_linesize(ds);
293
        }
294
    }
295
}
296

    
297
/***********************************************************/
298
/* basic char display */
299

    
300
#define FONT_HEIGHT 16
301
#define FONT_WIDTH 8
302

    
303
#include "vgafont.h"
304

    
305
#define cbswap_32(__x) \
306
((uint32_t)( \
307
                (((uint32_t)(__x) & (uint32_t)0x000000ffUL) << 24) | \
308
                (((uint32_t)(__x) & (uint32_t)0x0000ff00UL) <<  8) | \
309
                (((uint32_t)(__x) & (uint32_t)0x00ff0000UL) >>  8) | \
310
                (((uint32_t)(__x) & (uint32_t)0xff000000UL) >> 24) ))
311

    
312
#ifdef HOST_WORDS_BIGENDIAN
313
#define PAT(x) x
314
#else
315
#define PAT(x) cbswap_32(x)
316
#endif
317

    
318
static const uint32_t dmask16[16] = {
319
    PAT(0x00000000),
320
    PAT(0x000000ff),
321
    PAT(0x0000ff00),
322
    PAT(0x0000ffff),
323
    PAT(0x00ff0000),
324
    PAT(0x00ff00ff),
325
    PAT(0x00ffff00),
326
    PAT(0x00ffffff),
327
    PAT(0xff000000),
328
    PAT(0xff0000ff),
329
    PAT(0xff00ff00),
330
    PAT(0xff00ffff),
331
    PAT(0xffff0000),
332
    PAT(0xffff00ff),
333
    PAT(0xffffff00),
334
    PAT(0xffffffff),
335
};
336

    
337
static const uint32_t dmask4[4] = {
338
    PAT(0x00000000),
339
    PAT(0x0000ffff),
340
    PAT(0xffff0000),
341
    PAT(0xffffffff),
342
};
343

    
344
static uint32_t color_table[2][8];
345

    
346
enum color_names {
347
    COLOR_BLACK   = 0,
348
    COLOR_RED     = 1,
349
    COLOR_GREEN   = 2,
350
    COLOR_YELLOW  = 3,
351
    COLOR_BLUE    = 4,
352
    COLOR_MAGENTA = 5,
353
    COLOR_CYAN    = 6,
354
    COLOR_WHITE   = 7
355
};
356

    
357
static const uint32_t color_table_rgb[2][8] = {
358
    {   /* dark */
359
        QEMU_RGB(0x00, 0x00, 0x00),  /* black */
360
        QEMU_RGB(0xaa, 0x00, 0x00),  /* red */
361
        QEMU_RGB(0x00, 0xaa, 0x00),  /* green */
362
        QEMU_RGB(0xaa, 0xaa, 0x00),  /* yellow */
363
        QEMU_RGB(0x00, 0x00, 0xaa),  /* blue */
364
        QEMU_RGB(0xaa, 0x00, 0xaa),  /* magenta */
365
        QEMU_RGB(0x00, 0xaa, 0xaa),  /* cyan */
366
        QEMU_RGB(0xaa, 0xaa, 0xaa),  /* white */
367
    },
368
    {   /* bright */
369
        QEMU_RGB(0x00, 0x00, 0x00),  /* black */
370
        QEMU_RGB(0xff, 0x00, 0x00),  /* red */
371
        QEMU_RGB(0x00, 0xff, 0x00),  /* green */
372
        QEMU_RGB(0xff, 0xff, 0x00),  /* yellow */
373
        QEMU_RGB(0x00, 0x00, 0xff),  /* blue */
374
        QEMU_RGB(0xff, 0x00, 0xff),  /* magenta */
375
        QEMU_RGB(0x00, 0xff, 0xff),  /* cyan */
376
        QEMU_RGB(0xff, 0xff, 0xff),  /* white */
377
    }
378
};
379

    
380
static inline unsigned int col_expand(DisplayState *ds, unsigned int col)
381
{
382
    switch(ds_get_bits_per_pixel(ds)) {
383
    case 8:
384
        col |= col << 8;
385
        col |= col << 16;
386
        break;
387
    case 15:
388
    case 16:
389
        col |= col << 16;
390
        break;
391
    default:
392
        break;
393
    }
394

    
395
    return col;
396
}
397
#ifdef DEBUG_CONSOLE
398
static void console_print_text_attributes(TextAttributes *t_attrib, char ch)
399
{
400
    if (t_attrib->bold) {
401
        printf("b");
402
    } else {
403
        printf(" ");
404
    }
405
    if (t_attrib->uline) {
406
        printf("u");
407
    } else {
408
        printf(" ");
409
    }
410
    if (t_attrib->blink) {
411
        printf("l");
412
    } else {
413
        printf(" ");
414
    }
415
    if (t_attrib->invers) {
416
        printf("i");
417
    } else {
418
        printf(" ");
419
    }
420
    if (t_attrib->unvisible) {
421
        printf("n");
422
    } else {
423
        printf(" ");
424
    }
425

    
426
    printf(" fg: %d bg: %d ch:'%2X' '%c'\n", t_attrib->fgcol, t_attrib->bgcol, ch, ch);
427
}
428
#endif
429

    
430
static void vga_putcharxy(DisplayState *ds, int x, int y, int ch,
431
                          TextAttributes *t_attrib)
432
{
433
    uint8_t *d;
434
    const uint8_t *font_ptr;
435
    unsigned int font_data, linesize, xorcol, bpp;
436
    int i;
437
    unsigned int fgcol, bgcol;
438

    
439
#ifdef DEBUG_CONSOLE
440
    printf("x: %2i y: %2i", x, y);
441
    console_print_text_attributes(t_attrib, ch);
442
#endif
443

    
444
    if (t_attrib->invers) {
445
        bgcol = color_table[t_attrib->bold][t_attrib->fgcol];
446
        fgcol = color_table[t_attrib->bold][t_attrib->bgcol];
447
    } else {
448
        fgcol = color_table[t_attrib->bold][t_attrib->fgcol];
449
        bgcol = color_table[t_attrib->bold][t_attrib->bgcol];
450
    }
451

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

    
506
static void text_console_resize(TextConsole *s)
507
{
508
    TextCell *cells, *c, *c1;
509
    int w1, x, y, last_width;
510

    
511
    last_width = s->width;
512
    s->width = s->g_width / FONT_WIDTH;
513
    s->height = s->g_height / FONT_HEIGHT;
514

    
515
    w1 = last_width;
516
    if (s->width < w1)
517
        w1 = s->width;
518

    
519
    cells = qemu_malloc(s->width * s->total_height * sizeof(TextCell));
520
    for(y = 0; y < s->total_height; y++) {
521
        c = &cells[y * s->width];
522
        if (w1 > 0) {
523
            c1 = &s->cells[y * last_width];
524
            for(x = 0; x < w1; x++) {
525
                *c++ = *c1++;
526
            }
527
        }
528
        for(x = w1; x < s->width; x++) {
529
            c->ch = ' ';
530
            c->t_attrib = s->t_attrib_default;
531
            c++;
532
        }
533
    }
534
    qemu_free(s->cells);
535
    s->cells = cells;
536
}
537

    
538
static inline void text_update_xy(TextConsole *s, int x, int y)
539
{
540
    s->text_x[0] = MIN(s->text_x[0], x);
541
    s->text_x[1] = MAX(s->text_x[1], x);
542
    s->text_y[0] = MIN(s->text_y[0], y);
543
    s->text_y[1] = MAX(s->text_y[1], y);
544
}
545

    
546
static void invalidate_xy(TextConsole *s, int x, int y)
547
{
548
    if (s->update_x0 > x * FONT_WIDTH)
549
        s->update_x0 = x * FONT_WIDTH;
550
    if (s->update_y0 > y * FONT_HEIGHT)
551
        s->update_y0 = y * FONT_HEIGHT;
552
    if (s->update_x1 < (x + 1) * FONT_WIDTH)
553
        s->update_x1 = (x + 1) * FONT_WIDTH;
554
    if (s->update_y1 < (y + 1) * FONT_HEIGHT)
555
        s->update_y1 = (y + 1) * FONT_HEIGHT;
556
}
557

    
558
static void update_xy(TextConsole *s, int x, int y)
559
{
560
    TextCell *c;
561
    int y1, y2;
562

    
563
    if (s == active_console) {
564
        if (!ds_get_bits_per_pixel(s->ds)) {
565
            text_update_xy(s, x, y);
566
            return;
567
        }
568

    
569
        y1 = (s->y_base + y) % s->total_height;
570
        y2 = y1 - s->y_displayed;
571
        if (y2 < 0)
572
            y2 += s->total_height;
573
        if (y2 < s->height) {
574
            c = &s->cells[y1 * s->width + x];
575
            vga_putcharxy(s->ds, x, y2, c->ch,
576
                          &(c->t_attrib));
577
            invalidate_xy(s, x, y2);
578
        }
579
    }
580
}
581

    
582
static void console_show_cursor(TextConsole *s, int show)
583
{
584
    TextCell *c;
585
    int y, y1;
586

    
587
    if (s == active_console) {
588
        int x = s->x;
589

    
590
        if (!ds_get_bits_per_pixel(s->ds)) {
591
            s->cursor_invalidate = 1;
592
            return;
593
        }
594

    
595
        if (x >= s->width) {
596
            x = s->width - 1;
597
        }
598
        y1 = (s->y_base + s->y) % s->total_height;
599
        y = y1 - s->y_displayed;
600
        if (y < 0)
601
            y += s->total_height;
602
        if (y < s->height) {
603
            c = &s->cells[y1 * s->width + x];
604
            if (show) {
605
                TextAttributes t_attrib = s->t_attrib_default;
606
                t_attrib.invers = !(t_attrib.invers); /* invert fg and bg */
607
                vga_putcharxy(s->ds, x, y, c->ch, &t_attrib);
608
            } else {
609
                vga_putcharxy(s->ds, x, y, c->ch, &(c->t_attrib));
610
            }
611
            invalidate_xy(s, x, y);
612
        }
613
    }
614
}
615

    
616
static void console_refresh(TextConsole *s)
617
{
618
    TextCell *c;
619
    int x, y, y1;
620

    
621
    if (s != active_console)
622
        return;
623
    if (!ds_get_bits_per_pixel(s->ds)) {
624
        s->text_x[0] = 0;
625
        s->text_y[0] = 0;
626
        s->text_x[1] = s->width - 1;
627
        s->text_y[1] = s->height - 1;
628
        s->cursor_invalidate = 1;
629
        return;
630
    }
631

    
632
    vga_fill_rect(s->ds, 0, 0, ds_get_width(s->ds), ds_get_height(s->ds),
633
                  color_table[0][COLOR_BLACK]);
634
    y1 = s->y_displayed;
635
    for(y = 0; y < s->height; y++) {
636
        c = s->cells + y1 * s->width;
637
        for(x = 0; x < s->width; x++) {
638
            vga_putcharxy(s->ds, x, y, c->ch,
639
                          &(c->t_attrib));
640
            c++;
641
        }
642
        if (++y1 == s->total_height)
643
            y1 = 0;
644
    }
645
    console_show_cursor(s, 1);
646
    dpy_update(s->ds, 0, 0, ds_get_width(s->ds), ds_get_height(s->ds));
647
}
648

    
649
static void console_scroll(int ydelta)
650
{
651
    TextConsole *s;
652
    int i, y1;
653

    
654
    s = active_console;
655
    if (!s || (s->console_type == GRAPHIC_CONSOLE))
656
        return;
657

    
658
    if (ydelta > 0) {
659
        for(i = 0; i < ydelta; i++) {
660
            if (s->y_displayed == s->y_base)
661
                break;
662
            if (++s->y_displayed == s->total_height)
663
                s->y_displayed = 0;
664
        }
665
    } else {
666
        ydelta = -ydelta;
667
        i = s->backscroll_height;
668
        if (i > s->total_height - s->height)
669
            i = s->total_height - s->height;
670
        y1 = s->y_base - i;
671
        if (y1 < 0)
672
            y1 += s->total_height;
673
        for(i = 0; i < ydelta; i++) {
674
            if (s->y_displayed == y1)
675
                break;
676
            if (--s->y_displayed < 0)
677
                s->y_displayed = s->total_height - 1;
678
        }
679
    }
680
    console_refresh(s);
681
}
682

    
683
static void console_put_lf(TextConsole *s)
684
{
685
    TextCell *c;
686
    int x, y1;
687

    
688
    s->y++;
689
    if (s->y >= s->height) {
690
        s->y = s->height - 1;
691

    
692
        if (s->y_displayed == s->y_base) {
693
            if (++s->y_displayed == s->total_height)
694
                s->y_displayed = 0;
695
        }
696
        if (++s->y_base == s->total_height)
697
            s->y_base = 0;
698
        if (s->backscroll_height < s->total_height)
699
            s->backscroll_height++;
700
        y1 = (s->y_base + s->height - 1) % s->total_height;
701
        c = &s->cells[y1 * s->width];
702
        for(x = 0; x < s->width; x++) {
703
            c->ch = ' ';
704
            c->t_attrib = s->t_attrib_default;
705
            c++;
706
        }
707
        if (s == active_console && s->y_displayed == s->y_base) {
708
            if (!ds_get_bits_per_pixel(s->ds)) {
709
                s->text_x[0] = 0;
710
                s->text_y[0] = 0;
711
                s->text_x[1] = s->width - 1;
712
                s->text_y[1] = s->height - 1;
713
                return;
714
            }
715

    
716
            vga_bitblt(s->ds, 0, FONT_HEIGHT, 0, 0,
717
                       s->width * FONT_WIDTH,
718
                       (s->height - 1) * FONT_HEIGHT);
719
            vga_fill_rect(s->ds, 0, (s->height - 1) * FONT_HEIGHT,
720
                          s->width * FONT_WIDTH, FONT_HEIGHT,
721
                          color_table[0][s->t_attrib_default.bgcol]);
722
            s->update_x0 = 0;
723
            s->update_y0 = 0;
724
            s->update_x1 = s->width * FONT_WIDTH;
725
            s->update_y1 = s->height * FONT_HEIGHT;
726
        }
727
    }
728
}
729

    
730
/* Set console attributes depending on the current escape codes.
731
 * NOTE: I know this code is not very efficient (checking every color for it
732
 * self) but it is more readable and better maintainable.
733
 */
734
static void console_handle_escape(TextConsole *s)
735
{
736
    int i;
737

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

    
827
static void console_clear_xy(TextConsole *s, int x, int y)
828
{
829
    int y1 = (s->y_base + y) % s->total_height;
830
    TextCell *c = &s->cells[y1 * s->width + x];
831
    c->ch = ' ';
832
    c->t_attrib = s->t_attrib_default;
833
    update_xy(s, x, y);
834
}
835

    
836
static void console_putchar(TextConsole *s, int ch)
837
{
838
    TextCell *c;
839
    int y1, i;
840
    int x, y;
841

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

    
1058
void console_select(unsigned int index)
1059
{
1060
    TextConsole *s;
1061

    
1062
    if (index >= MAX_CONSOLES)
1063
        return;
1064
    if (active_console) {
1065
        active_console->g_width = ds_get_width(active_console->ds);
1066
        active_console->g_height = ds_get_height(active_console->ds);
1067
    }
1068
    s = consoles[index];
1069
    if (s) {
1070
        DisplayState *ds = s->ds;
1071
        active_console = s;
1072
        if (ds_get_bits_per_pixel(s->ds)) {
1073
            ds->surface = qemu_resize_displaysurface(ds, s->g_width, s->g_height);
1074
        } else {
1075
            s->ds->surface->width = s->width;
1076
            s->ds->surface->height = s->height;
1077
        }
1078
        dpy_resize(s->ds);
1079
        vga_hw_invalidate();
1080
    }
1081
}
1082

    
1083
static int console_puts(CharDriverState *chr, const uint8_t *buf, int len)
1084
{
1085
    TextConsole *s = chr->opaque;
1086
    int i;
1087

    
1088
    s->update_x0 = s->width * FONT_WIDTH;
1089
    s->update_y0 = s->height * FONT_HEIGHT;
1090
    s->update_x1 = 0;
1091
    s->update_y1 = 0;
1092
    console_show_cursor(s, 0);
1093
    for(i = 0; i < len; i++) {
1094
        console_putchar(s, buf[i]);
1095
    }
1096
    console_show_cursor(s, 1);
1097
    if (ds_get_bits_per_pixel(s->ds) && s->update_x0 < s->update_x1) {
1098
        dpy_update(s->ds, s->update_x0, s->update_y0,
1099
                   s->update_x1 - s->update_x0,
1100
                   s->update_y1 - s->update_y0);
1101
    }
1102
    return len;
1103
}
1104

    
1105
static void console_send_event(CharDriverState *chr, int event)
1106
{
1107
    TextConsole *s = chr->opaque;
1108
    int i;
1109

    
1110
    if (event == CHR_EVENT_FOCUS) {
1111
        for(i = 0; i < nb_consoles; i++) {
1112
            if (consoles[i] == s) {
1113
                console_select(i);
1114
                break;
1115
            }
1116
        }
1117
    }
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_can_read(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_read(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 = qemu_mallocz(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
        consoles[nb_consoles++] = s;
1264
    } else {
1265
        /* HACK: Put graphical consoles before text consoles.  */
1266
        for (i = nb_consoles; i > 0; i--) {
1267
            if (consoles[i - 1]->console_type == GRAPHIC_CONSOLE)
1268
                break;
1269
            consoles[i] = consoles[i - 1];
1270
        }
1271
        consoles[i] = s;
1272
        nb_consoles++;
1273
    }
1274
    return s;
1275
}
1276

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

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

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

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

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

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

    
1331
    return surface;
1332
}
1333

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

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

    
1349
static void dumb_display_init(void)
1350
{
1351
    DisplayState *ds = qemu_mallocz(sizeof(DisplayState));
1352
    ds->allocator = &default_allocator;
1353
    ds->surface = qemu_create_displaysurface(ds, 640, 480);
1354
    register_displaystate(ds);
1355
}
1356

    
1357
/***********************************************************/
1358
/* register display */
1359

    
1360
void register_displaystate(DisplayState *ds)
1361
{
1362
    DisplayState **s;
1363
    s = &display_state;
1364
    while (*s != NULL)
1365
        s = &(*s)->next;
1366
    ds->next = NULL;
1367
    *s = ds;
1368
}
1369

    
1370
DisplayState *get_displaystate(void)
1371
{
1372
    if (!display_state) {
1373
        dumb_display_init ();
1374
    }
1375
    return display_state;
1376
}
1377

    
1378
DisplayAllocator *register_displayallocator(DisplayState *ds, DisplayAllocator *da)
1379
{
1380
    if(ds->allocator ==  &default_allocator) {
1381
        DisplaySurface *surf;
1382
        surf = da->create_displaysurface(ds_get_width(ds), ds_get_height(ds));
1383
        defaultallocator_free_displaysurface(ds->surface);
1384
        ds->surface = surf;
1385
        ds->allocator = da;
1386
    }
1387
    return ds->allocator;
1388
}
1389

    
1390
DisplayState *graphic_console_init(vga_hw_update_ptr update,
1391
                                   vga_hw_invalidate_ptr invalidate,
1392
                                   vga_hw_screen_dump_ptr screen_dump,
1393
                                   vga_hw_text_update_ptr text_update,
1394
                                   void *opaque)
1395
{
1396
    TextConsole *s;
1397
    DisplayState *ds;
1398

    
1399
    ds = (DisplayState *) qemu_mallocz(sizeof(DisplayState));
1400
    ds->allocator = &default_allocator; 
1401
    ds->surface = qemu_create_displaysurface(ds, 640, 480);
1402

    
1403
    s = new_console(ds, GRAPHIC_CONSOLE);
1404
    if (s == NULL) {
1405
        qemu_free_displaysurface(ds);
1406
        qemu_free(ds);
1407
        return NULL;
1408
    }
1409
    s->hw_update = update;
1410
    s->hw_invalidate = invalidate;
1411
    s->hw_screen_dump = screen_dump;
1412
    s->hw_text_update = text_update;
1413
    s->hw = opaque;
1414

    
1415
    register_displaystate(ds);
1416
    return ds;
1417
}
1418

    
1419
int is_graphic_console(void)
1420
{
1421
    return active_console && active_console->console_type == GRAPHIC_CONSOLE;
1422
}
1423

    
1424
int is_fixedsize_console(void)
1425
{
1426
    return active_console && active_console->console_type != TEXT_CONSOLE;
1427
}
1428

    
1429
void console_color_init(DisplayState *ds)
1430
{
1431
    int i, j;
1432
    for (j = 0; j < 2; j++) {
1433
        for (i = 0; i < 8; i++) {
1434
            color_table[j][i] = col_expand(ds,
1435
                   vga_get_color(ds, color_table_rgb[j][i]));
1436
        }
1437
    }
1438
}
1439

    
1440
static int n_text_consoles;
1441
static CharDriverState *text_consoles[128];
1442

    
1443
static void text_console_set_echo(CharDriverState *chr, bool echo)
1444
{
1445
    TextConsole *s = chr->opaque;
1446

    
1447
    s->echo = echo;
1448
}
1449

    
1450
static void text_console_do_init(CharDriverState *chr, DisplayState *ds)
1451
{
1452
    TextConsole *s;
1453
    static int color_inited;
1454

    
1455
    s = chr->opaque;
1456

    
1457
    chr->chr_write = console_puts;
1458
    chr->chr_send_event = console_send_event;
1459

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

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

    
1479
    s->hw_invalidate = text_console_invalidate;
1480
    s->hw_text_update = text_console_update;
1481
    s->hw = s;
1482

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

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

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

    
1505
    qemu_chr_generic_open(chr);
1506
    if (chr->init)
1507
        chr->init(chr);
1508
}
1509

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

    
1517
    chr = qemu_mallocz(sizeof(CharDriverState));
1518

    
1519
    if (n_text_consoles == 128) {
1520
        fprintf(stderr, "Too many text consoles\n");
1521
        exit(1);
1522
    }
1523
    text_consoles[n_text_consoles] = chr;
1524
    n_text_consoles++;
1525

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

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

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

    
1540
    if (!s) {
1541
        free(chr);
1542
        return NULL;
1543
    }
1544

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

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

    
1557
    for (i = 0; i < n_text_consoles; i++) {
1558
        text_console_do_init(text_consoles[i], ds);
1559
    }
1560

    
1561
    n_text_consoles = 0;
1562
}
1563

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

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

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

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

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

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

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

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

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

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

    
1644
    switch (bpp) {
1645
        case 15:
1646
            pf.bits_per_pixel = 16;
1647
            pf.bytes_per_pixel = 2;
1648
            pf.rmask = 0x00007c00;
1649
            pf.gmask = 0x000003E0;
1650
            pf.bmask = 0x0000001F;
1651
            pf.rmax = 31;
1652
            pf.gmax = 31;
1653
            pf.bmax = 31;
1654
            pf.rshift = 10;
1655
            pf.gshift = 5;
1656
            pf.bshift = 0;
1657
            pf.rbits = 5;
1658
            pf.gbits = 5;
1659
            pf.bbits = 5;
1660
            break;
1661
        case 16:
1662
            pf.rmask = 0x0000F800;
1663
            pf.gmask = 0x000007E0;
1664
            pf.bmask = 0x0000001F;
1665
            pf.rmax = 31;
1666
            pf.gmax = 63;
1667
            pf.bmax = 31;
1668
            pf.rshift = 11;
1669
            pf.gshift = 5;
1670
            pf.bshift = 0;
1671
            pf.rbits = 5;
1672
            pf.gbits = 6;
1673
            pf.bbits = 5;
1674
            break;
1675
        case 24:
1676
            pf.rmask = 0x00FF0000;
1677
            pf.gmask = 0x0000FF00;
1678
            pf.bmask = 0x000000FF;
1679
            pf.rmax = 255;
1680
            pf.gmax = 255;
1681
            pf.bmax = 255;
1682
            pf.rshift = 16;
1683
            pf.gshift = 8;
1684
            pf.bshift = 0;
1685
            pf.rbits = 8;
1686
            pf.gbits = 8;
1687
            pf.bbits = 8;
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
}