Statistics
| Branch: | Revision:

root / console.c @ 7bd427d8

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
    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]->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
    surface->width = width;
1282
    surface->height = height;
1283
    surface->linesize = width * 4;
1284
    surface->pf = qemu_default_pixelformat(32);
1285
#ifdef HOST_WORDS_BIGENDIAN
1286
    surface->flags = QEMU_ALLOCATED_FLAG | QEMU_BIG_ENDIAN_FLAG;
1287
#else
1288
    surface->flags = QEMU_ALLOCATED_FLAG;
1289
#endif
1290
    surface->data = (uint8_t*) qemu_mallocz(surface->linesize * surface->height);
1291

    
1292
    return surface;
1293
}
1294

    
1295
static DisplaySurface* defaultallocator_resize_displaysurface(DisplaySurface *surface,
1296
                                          int width, int height)
1297
{
1298
    surface->width = width;
1299
    surface->height = height;
1300
    surface->linesize = width * 4;
1301
    surface->pf = qemu_default_pixelformat(32);
1302
    if (surface->flags & QEMU_ALLOCATED_FLAG)
1303
        surface->data = (uint8_t*) qemu_realloc(surface->data, surface->linesize * surface->height);
1304
    else
1305
        surface->data = (uint8_t*) qemu_malloc(surface->linesize * surface->height);
1306
#ifdef HOST_WORDS_BIGENDIAN
1307
    surface->flags = QEMU_ALLOCATED_FLAG | QEMU_BIG_ENDIAN_FLAG;
1308
#else
1309
    surface->flags = QEMU_ALLOCATED_FLAG;
1310
#endif
1311

    
1312
    return surface;
1313
}
1314

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

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

    
1329
    return surface;
1330
}
1331

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

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

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

    
1355
/***********************************************************/
1356
/* register display */
1357

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

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

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

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

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

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

    
1413
    register_displaystate(ds);
1414
    return ds;
1415
}
1416

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

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

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

    
1438
static int n_text_consoles;
1439
static CharDriverState *text_consoles[128];
1440

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

    
1445
    s->echo = echo;
1446
}
1447

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

    
1453
    s = chr->opaque;
1454

    
1455
    chr->chr_write = console_puts;
1456
    chr->chr_send_event = console_send_event;
1457

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

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

    
1477
    s->hw_invalidate = text_console_invalidate;
1478
    s->hw_text_update = text_console_update;
1479
    s->hw = s;
1480

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

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

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

    
1503
    qemu_chr_generic_open(chr);
1504
    if (chr->init)
1505
        chr->init(chr);
1506
}
1507

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

    
1515
    chr = qemu_mallocz(sizeof(CharDriverState));
1516

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

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

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

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

    
1538
    if (!s) {
1539
        free(chr);
1540
        return NULL;
1541
    }
1542

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

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

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

    
1559
    n_text_consoles = 0;
1560
}
1561

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

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

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

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

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

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

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

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

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

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

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