Statistics
| Branch: | Revision:

root / console.c @ 99a0949b

History | View | Annotate | Download (44.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
} e_console_type;
114

    
115
/* ??? This is mis-named.
116
   It is used for both text and graphical consoles.  */
117
struct TextConsole {
118
    e_console_type 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 TextConsole *active_console;
158
static TextConsole *consoles[MAX_CONSOLES];
159
static int nb_consoles = 0;
160

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

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

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

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

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

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

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

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

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

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

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

    
295
/***********************************************************/
296
/* basic char display */
297

    
298
#define FONT_HEIGHT 16
299
#define FONT_WIDTH 8
300

    
301
#include "vgafont.h"
302

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
1268
DisplayState *graphic_console_init(vga_hw_update_ptr update,
1269
                                   vga_hw_invalidate_ptr invalidate,
1270
                                   vga_hw_screen_dump_ptr screen_dump,
1271
                                   vga_hw_text_update_ptr text_update,
1272
                                   void *opaque)
1273
{
1274
    TextConsole *s;
1275
    DisplayState *ds;
1276

    
1277
    ds = (DisplayState *) qemu_mallocz(sizeof(DisplayState));
1278
    ds->allocator = &default_allocator; 
1279
    ds->surface = qemu_create_displaysurface(ds, 640, 480);
1280

    
1281
    s = new_console(ds, GRAPHIC_CONSOLE);
1282
    if (s == NULL) {
1283
        qemu_free_displaysurface(ds);
1284
        qemu_free(ds);
1285
        return NULL;
1286
    }
1287
    s->hw_update = update;
1288
    s->hw_invalidate = invalidate;
1289
    s->hw_screen_dump = screen_dump;
1290
    s->hw_text_update = text_update;
1291
    s->hw = opaque;
1292

    
1293
    register_displaystate(ds);
1294
    return ds;
1295
}
1296

    
1297
int is_graphic_console(void)
1298
{
1299
    return active_console && active_console->console_type == GRAPHIC_CONSOLE;
1300
}
1301

    
1302
int is_fixedsize_console(void)
1303
{
1304
    return active_console && active_console->console_type != TEXT_CONSOLE;
1305
}
1306

    
1307
void console_color_init(DisplayState *ds)
1308
{
1309
    int i, j;
1310
    for (j = 0; j < 2; j++) {
1311
        for (i = 0; i < 8; i++) {
1312
            color_table[j][i] = col_expand(ds,
1313
                   vga_get_color(ds, color_table_rgb[j][i]));
1314
        }
1315
    }
1316
}
1317

    
1318
static int n_text_consoles;
1319
static CharDriverState *text_consoles[128];
1320
static QemuOpts *text_console_opts[128];
1321

    
1322
static void text_console_do_init(CharDriverState *chr, DisplayState *ds, QemuOpts *opts)
1323
{
1324
    TextConsole *s;
1325
    unsigned width;
1326
    unsigned height;
1327
    static int color_inited;
1328

    
1329
    width = qemu_opt_get_number(opts, "width", 0);
1330
    if (width == 0)
1331
        width = qemu_opt_get_number(opts, "cols", 0) * FONT_WIDTH;
1332

    
1333
    height = qemu_opt_get_number(opts, "height", 0);
1334
    if (height == 0)
1335
        height = qemu_opt_get_number(opts, "rows", 0) * FONT_HEIGHT;
1336

    
1337
    if (width == 0 || height == 0) {
1338
        s = new_console(ds, TEXT_CONSOLE);
1339
        width = ds_get_width(s->ds);
1340
        height = ds_get_height(s->ds);
1341
    } else {
1342
        s = new_console(ds, TEXT_CONSOLE_FIXED_SIZE);
1343
    }
1344

    
1345
    if (!s) {
1346
        free(chr);
1347
        return;
1348
    }
1349
    chr->opaque = s;
1350
    chr->chr_write = console_puts;
1351
    chr->chr_send_event = console_send_event;
1352

    
1353
    s->chr = chr;
1354
    s->out_fifo.buf = s->out_fifo_buf;
1355
    s->out_fifo.buf_size = sizeof(s->out_fifo_buf);
1356
    s->kbd_timer = qemu_new_timer(rt_clock, kbd_send_chars, s);
1357
    s->ds = ds;
1358

    
1359
    if (!color_inited) {
1360
        color_inited = 1;
1361
        console_color_init(s->ds);
1362
    }
1363
    s->y_displayed = 0;
1364
    s->y_base = 0;
1365
    s->total_height = DEFAULT_BACKSCROLL;
1366
    s->x = 0;
1367
    s->y = 0;
1368
    s->g_width = width;
1369
    s->g_height = height;
1370

    
1371
    s->hw_invalidate = text_console_invalidate;
1372
    s->hw_text_update = text_console_update;
1373
    s->hw = s;
1374

    
1375
    /* Set text attribute defaults */
1376
    s->t_attrib_default.bold = 0;
1377
    s->t_attrib_default.uline = 0;
1378
    s->t_attrib_default.blink = 0;
1379
    s->t_attrib_default.invers = 0;
1380
    s->t_attrib_default.unvisible = 0;
1381
    s->t_attrib_default.fgcol = COLOR_WHITE;
1382
    s->t_attrib_default.bgcol = COLOR_BLACK;
1383
    /* set current text attributes to default */
1384
    s->t_attrib = s->t_attrib_default;
1385
    text_console_resize(s);
1386

    
1387
    qemu_chr_reset(chr);
1388
    if (chr->init)
1389
        chr->init(chr);
1390
}
1391

    
1392
CharDriverState *text_console_init(QemuOpts *opts)
1393
{
1394
    CharDriverState *chr;
1395

    
1396
    chr = qemu_mallocz(sizeof(CharDriverState));
1397

    
1398
    if (n_text_consoles == 128) {
1399
        fprintf(stderr, "Too many text consoles\n");
1400
        exit(1);
1401
    }
1402
    text_consoles[n_text_consoles] = chr;
1403
    text_console_opts[n_text_consoles] = opts;
1404
    n_text_consoles++;
1405

    
1406
    return chr;
1407
}
1408

    
1409
void text_consoles_set_display(DisplayState *ds)
1410
{
1411
    int i;
1412

    
1413
    for (i = 0; i < n_text_consoles; i++) {
1414
        text_console_do_init(text_consoles[i], ds, text_console_opts[i]);
1415
        qemu_opts_del(text_console_opts[i]);
1416
        text_console_opts[i] = NULL;
1417
    }
1418

    
1419
    n_text_consoles = 0;
1420
}
1421

    
1422
void qemu_console_resize(DisplayState *ds, int width, int height)
1423
{
1424
    TextConsole *s = get_graphic_console(ds);
1425
    if (!s) return;
1426

    
1427
    s->g_width = width;
1428
    s->g_height = height;
1429
    if (is_graphic_console()) {
1430
        ds->surface = qemu_resize_displaysurface(ds, width, height);
1431
        dpy_resize(ds);
1432
    }
1433
}
1434

    
1435
void qemu_console_copy(DisplayState *ds, int src_x, int src_y,
1436
                       int dst_x, int dst_y, int w, int h)
1437
{
1438
    if (is_graphic_console()) {
1439
        dpy_copy(ds, src_x, src_y, dst_x, dst_y, w, h);
1440
    }
1441
}
1442

    
1443
PixelFormat qemu_different_endianness_pixelformat(int bpp)
1444
{
1445
    PixelFormat pf;
1446

    
1447
    memset(&pf, 0x00, sizeof(PixelFormat));
1448

    
1449
    pf.bits_per_pixel = bpp;
1450
    pf.bytes_per_pixel = bpp / 8;
1451
    pf.depth = bpp == 32 ? 24 : bpp;
1452

    
1453
    switch (bpp) {
1454
        case 24:
1455
            pf.rmask = 0x000000FF;
1456
            pf.gmask = 0x0000FF00;
1457
            pf.bmask = 0x00FF0000;
1458
            pf.rmax = 255;
1459
            pf.gmax = 255;
1460
            pf.bmax = 255;
1461
            pf.rshift = 0;
1462
            pf.gshift = 8;
1463
            pf.bshift = 16;
1464
            pf.rbits = 8;
1465
            pf.gbits = 8;
1466
            pf.bbits = 8;
1467
            break;
1468
        case 32:
1469
            pf.rmask = 0x0000FF00;
1470
            pf.gmask = 0x00FF0000;
1471
            pf.bmask = 0xFF000000;
1472
            pf.amask = 0x00000000;
1473
            pf.amax = 255;
1474
            pf.rmax = 255;
1475
            pf.gmax = 255;
1476
            pf.bmax = 255;
1477
            pf.ashift = 0;
1478
            pf.rshift = 8;
1479
            pf.gshift = 16;
1480
            pf.bshift = 24;
1481
            pf.rbits = 8;
1482
            pf.gbits = 8;
1483
            pf.bbits = 8;
1484
            pf.abits = 8;
1485
            break;
1486
        default:
1487
            break;
1488
    }
1489
    return pf;
1490
}
1491

    
1492
PixelFormat qemu_default_pixelformat(int bpp)
1493
{
1494
    PixelFormat pf;
1495

    
1496
    memset(&pf, 0x00, sizeof(PixelFormat));
1497

    
1498
    pf.bits_per_pixel = bpp;
1499
    pf.bytes_per_pixel = bpp / 8;
1500
    pf.depth = bpp == 32 ? 24 : bpp;
1501

    
1502
    switch (bpp) {
1503
        case 16:
1504
            pf.rmask = 0x0000F800;
1505
            pf.gmask = 0x000007E0;
1506
            pf.bmask = 0x0000001F;
1507
            pf.rmax = 31;
1508
            pf.gmax = 63;
1509
            pf.bmax = 31;
1510
            pf.rshift = 11;
1511
            pf.gshift = 5;
1512
            pf.bshift = 0;
1513
            pf.rbits = 5;
1514
            pf.gbits = 6;
1515
            pf.bbits = 5;
1516
            break;
1517
        case 24:
1518
            pf.rmask = 0x00FF0000;
1519
            pf.gmask = 0x0000FF00;
1520
            pf.bmask = 0x000000FF;
1521
            pf.rmax = 255;
1522
            pf.gmax = 255;
1523
            pf.bmax = 255;
1524
            pf.rshift = 16;
1525
            pf.gshift = 8;
1526
            pf.bshift = 0;
1527
            pf.rbits = 8;
1528
            pf.gbits = 8;
1529
            pf.bbits = 8;
1530
        case 32:
1531
            pf.rmask = 0x00FF0000;
1532
            pf.gmask = 0x0000FF00;
1533
            pf.bmask = 0x000000FF;
1534
            pf.amax = 255;
1535
            pf.rmax = 255;
1536
            pf.gmax = 255;
1537
            pf.bmax = 255;
1538
            pf.ashift = 24;
1539
            pf.rshift = 16;
1540
            pf.gshift = 8;
1541
            pf.bshift = 0;
1542
            pf.rbits = 8;
1543
            pf.gbits = 8;
1544
            pf.bbits = 8;
1545
            pf.abits = 8;
1546
            break;
1547
        default:
1548
            break;
1549
    }
1550
    return pf;
1551
}
1552

    
1553
DisplaySurface* defaultallocator_create_displaysurface(int width, int height)
1554
{
1555
    DisplaySurface *surface = (DisplaySurface*) qemu_mallocz(sizeof(DisplaySurface));
1556

    
1557
    surface->width = width;
1558
    surface->height = height;
1559
    surface->linesize = width * 4;
1560
    surface->pf = qemu_default_pixelformat(32);
1561
#ifdef HOST_WORDS_BIGENDIAN
1562
    surface->flags = QEMU_ALLOCATED_FLAG | QEMU_BIG_ENDIAN_FLAG;
1563
#else
1564
    surface->flags = QEMU_ALLOCATED_FLAG;
1565
#endif
1566
    surface->data = (uint8_t*) qemu_mallocz(surface->linesize * surface->height);
1567

    
1568
    return surface;
1569
}
1570

    
1571
DisplaySurface* defaultallocator_resize_displaysurface(DisplaySurface *surface,
1572
                                          int width, int height)
1573
{
1574
    surface->width = width;
1575
    surface->height = height;
1576
    surface->linesize = width * 4;
1577
    surface->pf = qemu_default_pixelformat(32);
1578
    if (surface->flags & QEMU_ALLOCATED_FLAG)
1579
        surface->data = (uint8_t*) qemu_realloc(surface->data, surface->linesize * surface->height);
1580
    else
1581
        surface->data = (uint8_t*) qemu_malloc(surface->linesize * surface->height);
1582
#ifdef HOST_WORDS_BIGENDIAN
1583
    surface->flags = QEMU_ALLOCATED_FLAG | QEMU_BIG_ENDIAN_FLAG;
1584
#else
1585
    surface->flags = QEMU_ALLOCATED_FLAG;
1586
#endif
1587

    
1588
    return surface;
1589
}
1590

    
1591
DisplaySurface* qemu_create_displaysurface_from(int width, int height, int bpp,
1592
                                              int linesize, uint8_t *data)
1593
{
1594
    DisplaySurface *surface = (DisplaySurface*) qemu_mallocz(sizeof(DisplaySurface));
1595

    
1596
    surface->width = width;
1597
    surface->height = height;
1598
    surface->linesize = linesize;
1599
    surface->pf = qemu_default_pixelformat(bpp);
1600
#ifdef HOST_WORDS_BIGENDIAN
1601
    surface->flags = QEMU_BIG_ENDIAN_FLAG;
1602
#endif
1603
    surface->data = data;
1604

    
1605
    return surface;
1606
}
1607

    
1608
void defaultallocator_free_displaysurface(DisplaySurface *surface)
1609
{
1610
    if (surface == NULL)
1611
        return;
1612
    if (surface->flags & QEMU_ALLOCATED_FLAG)
1613
        qemu_free(surface->data);
1614
    qemu_free(surface);
1615
}