Statistics
| Branch: | Revision:

root / console.c @ 358664cc

History | View | Annotate | Download (46.5 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 && 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
    update_xy(s, x, y);
833
}
834

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
1285
    return surface;
1286
}
1287

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

    
1305
    return surface;
1306
}
1307

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

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

    
1322
    return surface;
1323
}
1324

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

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

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

    
1348
/***********************************************************/
1349
/* register display */
1350

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
1529
    return chr;
1530
}
1531

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

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

    
1542
    n_text_consoles = 0;
1543
}
1544

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

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

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

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

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

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

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

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

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

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

    
1625
    switch (bpp) {
1626
        case 15:
1627
            pf.bits_per_pixel = 16;
1628
            pf.bytes_per_pixel = 2;
1629
            pf.rmask = 0x00007c00;
1630
            pf.gmask = 0x000003E0;
1631
            pf.bmask = 0x0000001F;
1632
            pf.rmax = 31;
1633
            pf.gmax = 31;
1634
            pf.bmax = 31;
1635
            pf.rshift = 10;
1636
            pf.gshift = 5;
1637
            pf.bshift = 0;
1638
            pf.rbits = 5;
1639
            pf.gbits = 5;
1640
            pf.bbits = 5;
1641
            break;
1642
        case 16:
1643
            pf.rmask = 0x0000F800;
1644
            pf.gmask = 0x000007E0;
1645
            pf.bmask = 0x0000001F;
1646
            pf.rmax = 31;
1647
            pf.gmax = 63;
1648
            pf.bmax = 31;
1649
            pf.rshift = 11;
1650
            pf.gshift = 5;
1651
            pf.bshift = 0;
1652
            pf.rbits = 5;
1653
            pf.gbits = 6;
1654
            pf.bbits = 5;
1655
            break;
1656
        case 24:
1657
            pf.rmask = 0x00FF0000;
1658
            pf.gmask = 0x0000FF00;
1659
            pf.bmask = 0x000000FF;
1660
            pf.rmax = 255;
1661
            pf.gmax = 255;
1662
            pf.bmax = 255;
1663
            pf.rshift = 16;
1664
            pf.gshift = 8;
1665
            pf.bshift = 0;
1666
            pf.rbits = 8;
1667
            pf.gbits = 8;
1668
            pf.bbits = 8;
1669
        case 32:
1670
            pf.rmask = 0x00FF0000;
1671
            pf.gmask = 0x0000FF00;
1672
            pf.bmask = 0x000000FF;
1673
            pf.amax = 255;
1674
            pf.rmax = 255;
1675
            pf.gmax = 255;
1676
            pf.bmax = 255;
1677
            pf.ashift = 24;
1678
            pf.rshift = 16;
1679
            pf.gshift = 8;
1680
            pf.bshift = 0;
1681
            pf.rbits = 8;
1682
            pf.gbits = 8;
1683
            pf.bbits = 8;
1684
            pf.abits = 8;
1685
            break;
1686
        default:
1687
            break;
1688
    }
1689
    return pf;
1690
}