Statistics
| Branch: | Revision:

root / console.c @ 98b50080

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
296
/***********************************************************/
297
/* basic char display */
298

    
299
#define FONT_HEIGHT 16
300
#define FONT_WIDTH 8
301

    
302
#include "vgafont.h"
303

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
826
static void console_clear_xy(TextConsole *s, int x, int y)
827
{
828
    int y1 = (s->y_base + y) % s->total_height;
829
    TextCell *c = &s->cells[y1 * s->width + x];
830
    c->ch = ' ';
831
    c->t_attrib = s->t_attrib_default;
832
    c++;
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
    active_console->g_width = ds_get_width(active_console->ds);
1065
    active_console->g_height = ds_get_height(active_console->ds);
1066
    s = consoles[index];
1067
    if (s) {
1068
        DisplayState *ds = s->ds;
1069
        active_console = s;
1070
        if (ds_get_bits_per_pixel(s->ds)) {
1071
            ds->surface = qemu_resize_displaysurface(ds, s->g_width, s->g_height);
1072
        } else {
1073
            s->ds->surface->width = s->width;
1074
            s->ds->surface->height = s->height;
1075
        }
1076
        dpy_resize(s->ds);
1077
        vga_hw_invalidate();
1078
    }
1079
}
1080

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

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

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

    
1108
    if (event == CHR_EVENT_FOCUS) {
1109
        for(i = 0; i < nb_consoles; i++) {
1110
            if (consoles[i] == s) {
1111
                console_select(i);
1112
                break;
1113
            }
1114
        }
1115
    }
1116
}
1117

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

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

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

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

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

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

    
1201
static void text_console_update(void *opaque, console_ch_t *chardata)
1202
{
1203
    TextConsole *s = (TextConsole *) opaque;
1204
    int i, j, src;
1205

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

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

    
1240
static TextConsole *new_console(DisplayState *ds, console_type_t console_type)
1241
{
1242
    TextConsole *s;
1243
    int i;
1244

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

    
1269
static DisplaySurface* defaultallocator_create_displaysurface(int width, int height)
1270
{
1271
    DisplaySurface *surface = (DisplaySurface*) qemu_mallocz(sizeof(DisplaySurface));
1272

    
1273
    surface->width = width;
1274
    surface->height = height;
1275
    surface->linesize = width * 4;
1276
    surface->pf = qemu_default_pixelformat(32);
1277
#ifdef HOST_WORDS_BIGENDIAN
1278
    surface->flags = QEMU_ALLOCATED_FLAG | QEMU_BIG_ENDIAN_FLAG;
1279
#else
1280
    surface->flags = QEMU_ALLOCATED_FLAG;
1281
#endif
1282
    surface->data = (uint8_t*) qemu_mallocz(surface->linesize * surface->height);
1283

    
1284
    return surface;
1285
}
1286

    
1287
static DisplaySurface* defaultallocator_resize_displaysurface(DisplaySurface *surface,
1288
                                          int width, int height)
1289
{
1290
    surface->width = width;
1291
    surface->height = height;
1292
    surface->linesize = width * 4;
1293
    surface->pf = qemu_default_pixelformat(32);
1294
    if (surface->flags & QEMU_ALLOCATED_FLAG)
1295
        surface->data = (uint8_t*) qemu_realloc(surface->data, surface->linesize * surface->height);
1296
    else
1297
        surface->data = (uint8_t*) qemu_malloc(surface->linesize * surface->height);
1298
#ifdef HOST_WORDS_BIGENDIAN
1299
    surface->flags = QEMU_ALLOCATED_FLAG | QEMU_BIG_ENDIAN_FLAG;
1300
#else
1301
    surface->flags = QEMU_ALLOCATED_FLAG;
1302
#endif
1303

    
1304
    return surface;
1305
}
1306

    
1307
DisplaySurface* qemu_create_displaysurface_from(int width, int height, int bpp,
1308
                                              int linesize, uint8_t *data)
1309
{
1310
    DisplaySurface *surface = (DisplaySurface*) qemu_mallocz(sizeof(DisplaySurface));
1311

    
1312
    surface->width = width;
1313
    surface->height = height;
1314
    surface->linesize = linesize;
1315
    surface->pf = qemu_default_pixelformat(bpp);
1316
#ifdef HOST_WORDS_BIGENDIAN
1317
    surface->flags = QEMU_BIG_ENDIAN_FLAG;
1318
#endif
1319
    surface->data = data;
1320

    
1321
    return surface;
1322
}
1323

    
1324
static void defaultallocator_free_displaysurface(DisplaySurface *surface)
1325
{
1326
    if (surface == NULL)
1327
        return;
1328
    if (surface->flags & QEMU_ALLOCATED_FLAG)
1329
        qemu_free(surface->data);
1330
    qemu_free(surface);
1331
}
1332

    
1333
static struct DisplayAllocator default_allocator = {
1334
    defaultallocator_create_displaysurface,
1335
    defaultallocator_resize_displaysurface,
1336
    defaultallocator_free_displaysurface
1337
};
1338

    
1339
static void dumb_display_init(void)
1340
{
1341
    DisplayState *ds = qemu_mallocz(sizeof(DisplayState));
1342
    ds->allocator = &default_allocator;
1343
    ds->surface = qemu_create_displaysurface(ds, 640, 480);
1344
    register_displaystate(ds);
1345
}
1346

    
1347
/***********************************************************/
1348
/* register display */
1349

    
1350
void register_displaystate(DisplayState *ds)
1351
{
1352
    DisplayState **s;
1353
    s = &display_state;
1354
    while (*s != NULL)
1355
        s = &(*s)->next;
1356
    ds->next = NULL;
1357
    *s = ds;
1358
}
1359

    
1360
DisplayState *get_displaystate(void)
1361
{
1362
    if (!display_state) {
1363
        dumb_display_init ();
1364
    }
1365
    return display_state;
1366
}
1367

    
1368
DisplayAllocator *register_displayallocator(DisplayState *ds, DisplayAllocator *da)
1369
{
1370
    if(ds->allocator ==  &default_allocator) {
1371
        DisplaySurface *surf;
1372
        surf = da->create_displaysurface(ds_get_width(ds), ds_get_height(ds));
1373
        defaultallocator_free_displaysurface(ds->surface);
1374
        ds->surface = surf;
1375
        ds->allocator = da;
1376
    }
1377
    return ds->allocator;
1378
}
1379

    
1380
DisplayState *graphic_console_init(vga_hw_update_ptr update,
1381
                                   vga_hw_invalidate_ptr invalidate,
1382
                                   vga_hw_screen_dump_ptr screen_dump,
1383
                                   vga_hw_text_update_ptr text_update,
1384
                                   void *opaque)
1385
{
1386
    TextConsole *s;
1387
    DisplayState *ds;
1388

    
1389
    ds = (DisplayState *) qemu_mallocz(sizeof(DisplayState));
1390
    ds->allocator = &default_allocator; 
1391
    ds->surface = qemu_create_displaysurface(ds, 640, 480);
1392

    
1393
    s = new_console(ds, GRAPHIC_CONSOLE);
1394
    if (s == NULL) {
1395
        qemu_free_displaysurface(ds);
1396
        qemu_free(ds);
1397
        return NULL;
1398
    }
1399
    s->hw_update = update;
1400
    s->hw_invalidate = invalidate;
1401
    s->hw_screen_dump = screen_dump;
1402
    s->hw_text_update = text_update;
1403
    s->hw = opaque;
1404

    
1405
    register_displaystate(ds);
1406
    return ds;
1407
}
1408

    
1409
int is_graphic_console(void)
1410
{
1411
    return active_console && active_console->console_type == GRAPHIC_CONSOLE;
1412
}
1413

    
1414
int is_fixedsize_console(void)
1415
{
1416
    return active_console && active_console->console_type != TEXT_CONSOLE;
1417
}
1418

    
1419
void console_color_init(DisplayState *ds)
1420
{
1421
    int i, j;
1422
    for (j = 0; j < 2; j++) {
1423
        for (i = 0; i < 8; i++) {
1424
            color_table[j][i] = col_expand(ds,
1425
                   vga_get_color(ds, color_table_rgb[j][i]));
1426
        }
1427
    }
1428
}
1429

    
1430
static int n_text_consoles;
1431
static CharDriverState *text_consoles[128];
1432
static QemuOpts *text_console_opts[128];
1433

    
1434
static void text_console_do_init(CharDriverState *chr, DisplayState *ds, QemuOpts *opts)
1435
{
1436
    TextConsole *s;
1437
    unsigned width;
1438
    unsigned height;
1439
    static int color_inited;
1440

    
1441
    width = qemu_opt_get_number(opts, "width", 0);
1442
    if (width == 0)
1443
        width = qemu_opt_get_number(opts, "cols", 0) * FONT_WIDTH;
1444

    
1445
    height = qemu_opt_get_number(opts, "height", 0);
1446
    if (height == 0)
1447
        height = qemu_opt_get_number(opts, "rows", 0) * FONT_HEIGHT;
1448

    
1449
    if (width == 0 || height == 0) {
1450
        s = new_console(ds, TEXT_CONSOLE);
1451
        width = ds_get_width(s->ds);
1452
        height = ds_get_height(s->ds);
1453
    } else {
1454
        s = new_console(ds, TEXT_CONSOLE_FIXED_SIZE);
1455
    }
1456

    
1457
    if (!s) {
1458
        free(chr);
1459
        return;
1460
    }
1461
    chr->opaque = s;
1462
    chr->chr_write = console_puts;
1463
    chr->chr_send_event = console_send_event;
1464

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

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

    
1483
    s->hw_invalidate = text_console_invalidate;
1484
    s->hw_text_update = text_console_update;
1485
    s->hw = s;
1486

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

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

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

    
1509
    qemu_chr_generic_open(chr);
1510
    if (chr->init)
1511
        chr->init(chr);
1512
}
1513

    
1514
CharDriverState *text_console_init(QemuOpts *opts)
1515
{
1516
    CharDriverState *chr;
1517

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

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

    
1528
    return chr;
1529
}
1530

    
1531
void text_consoles_set_display(DisplayState *ds)
1532
{
1533
    int i;
1534

    
1535
    for (i = 0; i < n_text_consoles; i++) {
1536
        text_console_do_init(text_consoles[i], ds, text_console_opts[i]);
1537
        qemu_opts_del(text_console_opts[i]);
1538
        text_console_opts[i] = NULL;
1539
    }
1540

    
1541
    n_text_consoles = 0;
1542
}
1543

    
1544
void qemu_console_resize(DisplayState *ds, int width, int height)
1545
{
1546
    TextConsole *s = get_graphic_console(ds);
1547
    if (!s) return;
1548

    
1549
    s->g_width = width;
1550
    s->g_height = height;
1551
    if (is_graphic_console()) {
1552
        ds->surface = qemu_resize_displaysurface(ds, width, height);
1553
        dpy_resize(ds);
1554
    }
1555
}
1556

    
1557
void qemu_console_copy(DisplayState *ds, int src_x, int src_y,
1558
                       int dst_x, int dst_y, int w, int h)
1559
{
1560
    if (is_graphic_console()) {
1561
        dpy_copy(ds, src_x, src_y, dst_x, dst_y, w, h);
1562
    }
1563
}
1564

    
1565
PixelFormat qemu_different_endianness_pixelformat(int bpp)
1566
{
1567
    PixelFormat pf;
1568

    
1569
    memset(&pf, 0x00, sizeof(PixelFormat));
1570

    
1571
    pf.bits_per_pixel = bpp;
1572
    pf.bytes_per_pixel = bpp / 8;
1573
    pf.depth = bpp == 32 ? 24 : bpp;
1574

    
1575
    switch (bpp) {
1576
        case 24:
1577
            pf.rmask = 0x000000FF;
1578
            pf.gmask = 0x0000FF00;
1579
            pf.bmask = 0x00FF0000;
1580
            pf.rmax = 255;
1581
            pf.gmax = 255;
1582
            pf.bmax = 255;
1583
            pf.rshift = 0;
1584
            pf.gshift = 8;
1585
            pf.bshift = 16;
1586
            pf.rbits = 8;
1587
            pf.gbits = 8;
1588
            pf.bbits = 8;
1589
            break;
1590
        case 32:
1591
            pf.rmask = 0x0000FF00;
1592
            pf.gmask = 0x00FF0000;
1593
            pf.bmask = 0xFF000000;
1594
            pf.amask = 0x00000000;
1595
            pf.amax = 255;
1596
            pf.rmax = 255;
1597
            pf.gmax = 255;
1598
            pf.bmax = 255;
1599
            pf.ashift = 0;
1600
            pf.rshift = 8;
1601
            pf.gshift = 16;
1602
            pf.bshift = 24;
1603
            pf.rbits = 8;
1604
            pf.gbits = 8;
1605
            pf.bbits = 8;
1606
            pf.abits = 8;
1607
            break;
1608
        default:
1609
            break;
1610
    }
1611
    return pf;
1612
}
1613

    
1614
PixelFormat qemu_default_pixelformat(int bpp)
1615
{
1616
    PixelFormat pf;
1617

    
1618
    memset(&pf, 0x00, sizeof(PixelFormat));
1619

    
1620
    pf.bits_per_pixel = bpp;
1621
    pf.bytes_per_pixel = bpp / 8;
1622
    pf.depth = bpp == 32 ? 24 : bpp;
1623

    
1624
    switch (bpp) {
1625
        case 16:
1626
            pf.rmask = 0x0000F800;
1627
            pf.gmask = 0x000007E0;
1628
            pf.bmask = 0x0000001F;
1629
            pf.rmax = 31;
1630
            pf.gmax = 63;
1631
            pf.bmax = 31;
1632
            pf.rshift = 11;
1633
            pf.gshift = 5;
1634
            pf.bshift = 0;
1635
            pf.rbits = 5;
1636
            pf.gbits = 6;
1637
            pf.bbits = 5;
1638
            break;
1639
        case 24:
1640
            pf.rmask = 0x00FF0000;
1641
            pf.gmask = 0x0000FF00;
1642
            pf.bmask = 0x000000FF;
1643
            pf.rmax = 255;
1644
            pf.gmax = 255;
1645
            pf.bmax = 255;
1646
            pf.rshift = 16;
1647
            pf.gshift = 8;
1648
            pf.bshift = 0;
1649
            pf.rbits = 8;
1650
            pf.gbits = 8;
1651
            pf.bbits = 8;
1652
        case 32:
1653
            pf.rmask = 0x00FF0000;
1654
            pf.gmask = 0x0000FF00;
1655
            pf.bmask = 0x000000FF;
1656
            pf.amax = 255;
1657
            pf.rmax = 255;
1658
            pf.gmax = 255;
1659
            pf.bmax = 255;
1660
            pf.ashift = 24;
1661
            pf.rshift = 16;
1662
            pf.gshift = 8;
1663
            pf.bshift = 0;
1664
            pf.rbits = 8;
1665
            pf.gbits = 8;
1666
            pf.bbits = 8;
1667
            pf.abits = 8;
1668
            break;
1669
        default:
1670
            break;
1671
    }
1672
    return pf;
1673
}