~ahs3/+junk/cq-qemu

« back to all changes in this revision

Viewing changes to console.c

  • Committer: Al Stone
  • Date: 2012-02-09 01:17:20 UTC
  • Revision ID: albert.stone@canonical.com-20120209011720-tztl7ik3qayz80p4
first commit to bzr for qemu

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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
    int index;
 
119
    console_type_t console_type;
 
120
    DisplayState *ds;
 
121
    /* Graphic console state.  */
 
122
    vga_hw_update_ptr hw_update;
 
123
    vga_hw_invalidate_ptr hw_invalidate;
 
124
    vga_hw_screen_dump_ptr hw_screen_dump;
 
125
    vga_hw_text_update_ptr hw_text_update;
 
126
    void *hw;
 
127
 
 
128
    int g_width, g_height;
 
129
    int width;
 
130
    int height;
 
131
    int total_height;
 
132
    int backscroll_height;
 
133
    int x, y;
 
134
    int x_saved, y_saved;
 
135
    int y_displayed;
 
136
    int y_base;
 
137
    TextAttributes t_attrib_default; /* default text attributes */
 
138
    TextAttributes t_attrib; /* currently active text attributes */
 
139
    TextCell *cells;
 
140
    int text_x[2], text_y[2], cursor_invalidate;
 
141
    int echo;
 
142
 
 
143
    int update_x0;
 
144
    int update_y0;
 
145
    int update_x1;
 
146
    int update_y1;
 
147
 
 
148
    enum TTYState state;
 
149
    int esc_params[MAX_ESC_PARAMS];
 
150
    int nb_esc_params;
 
151
 
 
152
    CharDriverState *chr;
 
153
    /* fifo for key pressed */
 
154
    QEMUFIFO out_fifo;
 
155
    uint8_t out_fifo_buf[16];
 
156
    QEMUTimer *kbd_timer;
 
157
};
 
158
 
 
159
static DisplayState *display_state;
 
160
static TextConsole *active_console;
 
161
static TextConsole *consoles[MAX_CONSOLES];
 
162
static int nb_consoles = 0;
 
163
 
 
164
void vga_hw_update(void)
 
165
{
 
166
    if (active_console && active_console->hw_update)
 
167
        active_console->hw_update(active_console->hw);
 
168
}
 
169
 
 
170
void vga_hw_invalidate(void)
 
171
{
 
172
    if (active_console && active_console->hw_invalidate)
 
173
        active_console->hw_invalidate(active_console->hw);
 
174
}
 
175
 
 
176
void vga_hw_screen_dump(const char *filename)
 
177
{
 
178
    TextConsole *previous_active_console;
 
179
 
 
180
    previous_active_console = active_console;
 
181
 
 
182
    /* There is currently no way of specifying which screen we want to dump,
 
183
       so always dump the first one.  */
 
184
    console_select(0);
 
185
    if (consoles[0] && consoles[0]->hw_screen_dump) {
 
186
        consoles[0]->hw_screen_dump(consoles[0]->hw, filename);
 
187
    }
 
188
 
 
189
    console_select(previous_active_console->index);
 
190
}
 
191
 
 
192
void vga_hw_text_update(console_ch_t *chardata)
 
193
{
 
194
    if (active_console && active_console->hw_text_update)
 
195
        active_console->hw_text_update(active_console->hw, chardata);
 
196
}
 
197
 
 
198
/* convert a RGBA color to a color index usable in graphic primitives */
 
199
static unsigned int vga_get_color(DisplayState *ds, unsigned int rgba)
 
200
{
 
201
    unsigned int r, g, b, color;
 
202
 
 
203
    switch(ds_get_bits_per_pixel(ds)) {
 
204
#if 0
 
205
    case 8:
 
206
        r = (rgba >> 16) & 0xff;
 
207
        g = (rgba >> 8) & 0xff;
 
208
        b = (rgba) & 0xff;
 
209
        color = (rgb_to_index[r] * 6 * 6) +
 
210
            (rgb_to_index[g] * 6) +
 
211
            (rgb_to_index[b]);
 
212
        break;
 
213
#endif
 
214
    case 15:
 
215
        r = (rgba >> 16) & 0xff;
 
216
        g = (rgba >> 8) & 0xff;
 
217
        b = (rgba) & 0xff;
 
218
        color = ((r >> 3) << 10) | ((g >> 3) << 5) | (b >> 3);
 
219
        break;
 
220
    case 16:
 
221
        r = (rgba >> 16) & 0xff;
 
222
        g = (rgba >> 8) & 0xff;
 
223
        b = (rgba) & 0xff;
 
224
        color = ((r >> 3) << 11) | ((g >> 2) << 5) | (b >> 3);
 
225
        break;
 
226
    case 32:
 
227
    default:
 
228
        color = rgba;
 
229
        break;
 
230
    }
 
231
    return color;
 
232
}
 
233
 
 
234
static void vga_fill_rect (DisplayState *ds,
 
235
                           int posx, int posy, int width, int height, uint32_t color)
 
236
{
 
237
    uint8_t *d, *d1;
 
238
    int x, y, bpp;
 
239
 
 
240
    bpp = (ds_get_bits_per_pixel(ds) + 7) >> 3;
 
241
    d1 = ds_get_data(ds) +
 
242
        ds_get_linesize(ds) * posy + bpp * posx;
 
243
    for (y = 0; y < height; y++) {
 
244
        d = d1;
 
245
        switch(bpp) {
 
246
        case 1:
 
247
            for (x = 0; x < width; x++) {
 
248
                *((uint8_t *)d) = color;
 
249
                d++;
 
250
            }
 
251
            break;
 
252
        case 2:
 
253
            for (x = 0; x < width; x++) {
 
254
                *((uint16_t *)d) = color;
 
255
                d += 2;
 
256
            }
 
257
            break;
 
258
        case 4:
 
259
            for (x = 0; x < width; x++) {
 
260
                *((uint32_t *)d) = color;
 
261
                d += 4;
 
262
            }
 
263
            break;
 
264
        }
 
265
        d1 += ds_get_linesize(ds);
 
266
    }
 
267
}
 
268
 
 
269
/* copy from (xs, ys) to (xd, yd) a rectangle of size (w, h) */
 
270
static void vga_bitblt(DisplayState *ds, int xs, int ys, int xd, int yd, int w, int h)
 
271
{
 
272
    const uint8_t *s;
 
273
    uint8_t *d;
 
274
    int wb, y, bpp;
 
275
 
 
276
    bpp = (ds_get_bits_per_pixel(ds) + 7) >> 3;
 
277
    wb = w * bpp;
 
278
    if (yd <= ys) {
 
279
        s = ds_get_data(ds) +
 
280
            ds_get_linesize(ds) * ys + bpp * xs;
 
281
        d = ds_get_data(ds) +
 
282
            ds_get_linesize(ds) * yd + bpp * xd;
 
283
        for (y = 0; y < h; y++) {
 
284
            memmove(d, s, wb);
 
285
            d += ds_get_linesize(ds);
 
286
            s += ds_get_linesize(ds);
 
287
        }
 
288
    } else {
 
289
        s = ds_get_data(ds) +
 
290
            ds_get_linesize(ds) * (ys + h - 1) + bpp * xs;
 
291
        d = ds_get_data(ds) +
 
292
            ds_get_linesize(ds) * (yd + h - 1) + bpp * xd;
 
293
       for (y = 0; y < h; y++) {
 
294
            memmove(d, s, wb);
 
295
            d -= ds_get_linesize(ds);
 
296
            s -= ds_get_linesize(ds);
 
297
        }
 
298
    }
 
299
}
 
300
 
 
301
/***********************************************************/
 
302
/* basic char display */
 
303
 
 
304
#define FONT_HEIGHT 16
 
305
#define FONT_WIDTH 8
 
306
 
 
307
#include "vgafont.h"
 
308
 
 
309
#define cbswap_32(__x) \
 
310
((uint32_t)( \
 
311
                (((uint32_t)(__x) & (uint32_t)0x000000ffUL) << 24) | \
 
312
                (((uint32_t)(__x) & (uint32_t)0x0000ff00UL) <<  8) | \
 
313
                (((uint32_t)(__x) & (uint32_t)0x00ff0000UL) >>  8) | \
 
314
                (((uint32_t)(__x) & (uint32_t)0xff000000UL) >> 24) ))
 
315
 
 
316
#ifdef HOST_WORDS_BIGENDIAN
 
317
#define PAT(x) x
 
318
#else
 
319
#define PAT(x) cbswap_32(x)
 
320
#endif
 
321
 
 
322
static const uint32_t dmask16[16] = {
 
323
    PAT(0x00000000),
 
324
    PAT(0x000000ff),
 
325
    PAT(0x0000ff00),
 
326
    PAT(0x0000ffff),
 
327
    PAT(0x00ff0000),
 
328
    PAT(0x00ff00ff),
 
329
    PAT(0x00ffff00),
 
330
    PAT(0x00ffffff),
 
331
    PAT(0xff000000),
 
332
    PAT(0xff0000ff),
 
333
    PAT(0xff00ff00),
 
334
    PAT(0xff00ffff),
 
335
    PAT(0xffff0000),
 
336
    PAT(0xffff00ff),
 
337
    PAT(0xffffff00),
 
338
    PAT(0xffffffff),
 
339
};
 
340
 
 
341
static const uint32_t dmask4[4] = {
 
342
    PAT(0x00000000),
 
343
    PAT(0x0000ffff),
 
344
    PAT(0xffff0000),
 
345
    PAT(0xffffffff),
 
346
};
 
347
 
 
348
static uint32_t color_table[2][8];
 
349
 
 
350
#ifndef CONFIG_CURSES
 
351
enum color_names {
 
352
    COLOR_BLACK   = 0,
 
353
    COLOR_RED     = 1,
 
354
    COLOR_GREEN   = 2,
 
355
    COLOR_YELLOW  = 3,
 
356
    COLOR_BLUE    = 4,
 
357
    COLOR_MAGENTA = 5,
 
358
    COLOR_CYAN    = 6,
 
359
    COLOR_WHITE   = 7
 
360
};
 
361
#endif
 
362
 
 
363
static const uint32_t color_table_rgb[2][8] = {
 
364
    {   /* dark */
 
365
        QEMU_RGB(0x00, 0x00, 0x00),  /* black */
 
366
        QEMU_RGB(0xaa, 0x00, 0x00),  /* red */
 
367
        QEMU_RGB(0x00, 0xaa, 0x00),  /* green */
 
368
        QEMU_RGB(0xaa, 0xaa, 0x00),  /* yellow */
 
369
        QEMU_RGB(0x00, 0x00, 0xaa),  /* blue */
 
370
        QEMU_RGB(0xaa, 0x00, 0xaa),  /* magenta */
 
371
        QEMU_RGB(0x00, 0xaa, 0xaa),  /* cyan */
 
372
        QEMU_RGB(0xaa, 0xaa, 0xaa),  /* white */
 
373
    },
 
374
    {   /* bright */
 
375
        QEMU_RGB(0x00, 0x00, 0x00),  /* black */
 
376
        QEMU_RGB(0xff, 0x00, 0x00),  /* red */
 
377
        QEMU_RGB(0x00, 0xff, 0x00),  /* green */
 
378
        QEMU_RGB(0xff, 0xff, 0x00),  /* yellow */
 
379
        QEMU_RGB(0x00, 0x00, 0xff),  /* blue */
 
380
        QEMU_RGB(0xff, 0x00, 0xff),  /* magenta */
 
381
        QEMU_RGB(0x00, 0xff, 0xff),  /* cyan */
 
382
        QEMU_RGB(0xff, 0xff, 0xff),  /* white */
 
383
    }
 
384
};
 
385
 
 
386
static inline unsigned int col_expand(DisplayState *ds, unsigned int col)
 
387
{
 
388
    switch(ds_get_bits_per_pixel(ds)) {
 
389
    case 8:
 
390
        col |= col << 8;
 
391
        col |= col << 16;
 
392
        break;
 
393
    case 15:
 
394
    case 16:
 
395
        col |= col << 16;
 
396
        break;
 
397
    default:
 
398
        break;
 
399
    }
 
400
 
 
401
    return col;
 
402
}
 
403
#ifdef DEBUG_CONSOLE
 
404
static void console_print_text_attributes(TextAttributes *t_attrib, char ch)
 
405
{
 
406
    if (t_attrib->bold) {
 
407
        printf("b");
 
408
    } else {
 
409
        printf(" ");
 
410
    }
 
411
    if (t_attrib->uline) {
 
412
        printf("u");
 
413
    } else {
 
414
        printf(" ");
 
415
    }
 
416
    if (t_attrib->blink) {
 
417
        printf("l");
 
418
    } else {
 
419
        printf(" ");
 
420
    }
 
421
    if (t_attrib->invers) {
 
422
        printf("i");
 
423
    } else {
 
424
        printf(" ");
 
425
    }
 
426
    if (t_attrib->unvisible) {
 
427
        printf("n");
 
428
    } else {
 
429
        printf(" ");
 
430
    }
 
431
 
 
432
    printf(" fg: %d bg: %d ch:'%2X' '%c'\n", t_attrib->fgcol, t_attrib->bgcol, ch, ch);
 
433
}
 
434
#endif
 
435
 
 
436
static void vga_putcharxy(DisplayState *ds, int x, int y, int ch,
 
437
                          TextAttributes *t_attrib)
 
438
{
 
439
    uint8_t *d;
 
440
    const uint8_t *font_ptr;
 
441
    unsigned int font_data, linesize, xorcol, bpp;
 
442
    int i;
 
443
    unsigned int fgcol, bgcol;
 
444
 
 
445
#ifdef DEBUG_CONSOLE
 
446
    printf("x: %2i y: %2i", x, y);
 
447
    console_print_text_attributes(t_attrib, ch);
 
448
#endif
 
449
 
 
450
    if (t_attrib->invers) {
 
451
        bgcol = color_table[t_attrib->bold][t_attrib->fgcol];
 
452
        fgcol = color_table[t_attrib->bold][t_attrib->bgcol];
 
453
    } else {
 
454
        fgcol = color_table[t_attrib->bold][t_attrib->fgcol];
 
455
        bgcol = color_table[t_attrib->bold][t_attrib->bgcol];
 
456
    }
 
457
 
 
458
    bpp = (ds_get_bits_per_pixel(ds) + 7) >> 3;
 
459
    d = ds_get_data(ds) +
 
460
        ds_get_linesize(ds) * y * FONT_HEIGHT + bpp * x * FONT_WIDTH;
 
461
    linesize = ds_get_linesize(ds);
 
462
    font_ptr = vgafont16 + FONT_HEIGHT * ch;
 
463
    xorcol = bgcol ^ fgcol;
 
464
    switch(ds_get_bits_per_pixel(ds)) {
 
465
    case 8:
 
466
        for(i = 0; i < FONT_HEIGHT; i++) {
 
467
            font_data = *font_ptr++;
 
468
            if (t_attrib->uline
 
469
                && ((i == FONT_HEIGHT - 2) || (i == FONT_HEIGHT - 3))) {
 
470
                font_data = 0xFF;
 
471
            }
 
472
            ((uint32_t *)d)[0] = (dmask16[(font_data >> 4)] & xorcol) ^ bgcol;
 
473
            ((uint32_t *)d)[1] = (dmask16[(font_data >> 0) & 0xf] & xorcol) ^ bgcol;
 
474
            d += linesize;
 
475
        }
 
476
        break;
 
477
    case 16:
 
478
    case 15:
 
479
        for(i = 0; i < FONT_HEIGHT; i++) {
 
480
            font_data = *font_ptr++;
 
481
            if (t_attrib->uline
 
482
                && ((i == FONT_HEIGHT - 2) || (i == FONT_HEIGHT - 3))) {
 
483
                font_data = 0xFF;
 
484
            }
 
485
            ((uint32_t *)d)[0] = (dmask4[(font_data >> 6)] & xorcol) ^ bgcol;
 
486
            ((uint32_t *)d)[1] = (dmask4[(font_data >> 4) & 3] & xorcol) ^ bgcol;
 
487
            ((uint32_t *)d)[2] = (dmask4[(font_data >> 2) & 3] & xorcol) ^ bgcol;
 
488
            ((uint32_t *)d)[3] = (dmask4[(font_data >> 0) & 3] & xorcol) ^ bgcol;
 
489
            d += linesize;
 
490
        }
 
491
        break;
 
492
    case 32:
 
493
        for(i = 0; i < FONT_HEIGHT; i++) {
 
494
            font_data = *font_ptr++;
 
495
            if (t_attrib->uline && ((i == FONT_HEIGHT - 2) || (i == FONT_HEIGHT - 3))) {
 
496
                font_data = 0xFF;
 
497
            }
 
498
            ((uint32_t *)d)[0] = (-((font_data >> 7)) & xorcol) ^ bgcol;
 
499
            ((uint32_t *)d)[1] = (-((font_data >> 6) & 1) & xorcol) ^ bgcol;
 
500
            ((uint32_t *)d)[2] = (-((font_data >> 5) & 1) & xorcol) ^ bgcol;
 
501
            ((uint32_t *)d)[3] = (-((font_data >> 4) & 1) & xorcol) ^ bgcol;
 
502
            ((uint32_t *)d)[4] = (-((font_data >> 3) & 1) & xorcol) ^ bgcol;
 
503
            ((uint32_t *)d)[5] = (-((font_data >> 2) & 1) & xorcol) ^ bgcol;
 
504
            ((uint32_t *)d)[6] = (-((font_data >> 1) & 1) & xorcol) ^ bgcol;
 
505
            ((uint32_t *)d)[7] = (-((font_data >> 0) & 1) & xorcol) ^ bgcol;
 
506
            d += linesize;
 
507
        }
 
508
        break;
 
509
    }
 
510
}
 
511
 
 
512
static void text_console_resize(TextConsole *s)
 
513
{
 
514
    TextCell *cells, *c, *c1;
 
515
    int w1, x, y, last_width;
 
516
 
 
517
    last_width = s->width;
 
518
    s->width = s->g_width / FONT_WIDTH;
 
519
    s->height = s->g_height / FONT_HEIGHT;
 
520
 
 
521
    w1 = last_width;
 
522
    if (s->width < w1)
 
523
        w1 = s->width;
 
524
 
 
525
    cells = g_malloc(s->width * s->total_height * sizeof(TextCell));
 
526
    for(y = 0; y < s->total_height; y++) {
 
527
        c = &cells[y * s->width];
 
528
        if (w1 > 0) {
 
529
            c1 = &s->cells[y * last_width];
 
530
            for(x = 0; x < w1; x++) {
 
531
                *c++ = *c1++;
 
532
            }
 
533
        }
 
534
        for(x = w1; x < s->width; x++) {
 
535
            c->ch = ' ';
 
536
            c->t_attrib = s->t_attrib_default;
 
537
            c++;
 
538
        }
 
539
    }
 
540
    g_free(s->cells);
 
541
    s->cells = cells;
 
542
}
 
543
 
 
544
static inline void text_update_xy(TextConsole *s, int x, int y)
 
545
{
 
546
    s->text_x[0] = MIN(s->text_x[0], x);
 
547
    s->text_x[1] = MAX(s->text_x[1], x);
 
548
    s->text_y[0] = MIN(s->text_y[0], y);
 
549
    s->text_y[1] = MAX(s->text_y[1], y);
 
550
}
 
551
 
 
552
static void invalidate_xy(TextConsole *s, int x, int y)
 
553
{
 
554
    if (s->update_x0 > x * FONT_WIDTH)
 
555
        s->update_x0 = x * FONT_WIDTH;
 
556
    if (s->update_y0 > y * FONT_HEIGHT)
 
557
        s->update_y0 = y * FONT_HEIGHT;
 
558
    if (s->update_x1 < (x + 1) * FONT_WIDTH)
 
559
        s->update_x1 = (x + 1) * FONT_WIDTH;
 
560
    if (s->update_y1 < (y + 1) * FONT_HEIGHT)
 
561
        s->update_y1 = (y + 1) * FONT_HEIGHT;
 
562
}
 
563
 
 
564
static void update_xy(TextConsole *s, int x, int y)
 
565
{
 
566
    TextCell *c;
 
567
    int y1, y2;
 
568
 
 
569
    if (s == active_console) {
 
570
        if (!ds_get_bits_per_pixel(s->ds)) {
 
571
            text_update_xy(s, x, y);
 
572
            return;
 
573
        }
 
574
 
 
575
        y1 = (s->y_base + y) % s->total_height;
 
576
        y2 = y1 - s->y_displayed;
 
577
        if (y2 < 0)
 
578
            y2 += s->total_height;
 
579
        if (y2 < s->height) {
 
580
            c = &s->cells[y1 * s->width + x];
 
581
            vga_putcharxy(s->ds, x, y2, c->ch,
 
582
                          &(c->t_attrib));
 
583
            invalidate_xy(s, x, y2);
 
584
        }
 
585
    }
 
586
}
 
587
 
 
588
static void console_show_cursor(TextConsole *s, int show)
 
589
{
 
590
    TextCell *c;
 
591
    int y, y1;
 
592
 
 
593
    if (s == active_console) {
 
594
        int x = s->x;
 
595
 
 
596
        if (!ds_get_bits_per_pixel(s->ds)) {
 
597
            s->cursor_invalidate = 1;
 
598
            return;
 
599
        }
 
600
 
 
601
        if (x >= s->width) {
 
602
            x = s->width - 1;
 
603
        }
 
604
        y1 = (s->y_base + s->y) % s->total_height;
 
605
        y = y1 - s->y_displayed;
 
606
        if (y < 0)
 
607
            y += s->total_height;
 
608
        if (y < s->height) {
 
609
            c = &s->cells[y1 * s->width + x];
 
610
            if (show) {
 
611
                TextAttributes t_attrib = s->t_attrib_default;
 
612
                t_attrib.invers = !(t_attrib.invers); /* invert fg and bg */
 
613
                vga_putcharxy(s->ds, x, y, c->ch, &t_attrib);
 
614
            } else {
 
615
                vga_putcharxy(s->ds, x, y, c->ch, &(c->t_attrib));
 
616
            }
 
617
            invalidate_xy(s, x, y);
 
618
        }
 
619
    }
 
620
}
 
621
 
 
622
static void console_refresh(TextConsole *s)
 
623
{
 
624
    TextCell *c;
 
625
    int x, y, y1;
 
626
 
 
627
    if (s != active_console)
 
628
        return;
 
629
    if (!ds_get_bits_per_pixel(s->ds)) {
 
630
        s->text_x[0] = 0;
 
631
        s->text_y[0] = 0;
 
632
        s->text_x[1] = s->width - 1;
 
633
        s->text_y[1] = s->height - 1;
 
634
        s->cursor_invalidate = 1;
 
635
        return;
 
636
    }
 
637
 
 
638
    vga_fill_rect(s->ds, 0, 0, ds_get_width(s->ds), ds_get_height(s->ds),
 
639
                  color_table[0][COLOR_BLACK]);
 
640
    y1 = s->y_displayed;
 
641
    for(y = 0; y < s->height; y++) {
 
642
        c = s->cells + y1 * s->width;
 
643
        for(x = 0; x < s->width; x++) {
 
644
            vga_putcharxy(s->ds, x, y, c->ch,
 
645
                          &(c->t_attrib));
 
646
            c++;
 
647
        }
 
648
        if (++y1 == s->total_height)
 
649
            y1 = 0;
 
650
    }
 
651
    console_show_cursor(s, 1);
 
652
    dpy_update(s->ds, 0, 0, ds_get_width(s->ds), ds_get_height(s->ds));
 
653
}
 
654
 
 
655
static void console_scroll(int ydelta)
 
656
{
 
657
    TextConsole *s;
 
658
    int i, y1;
 
659
 
 
660
    s = active_console;
 
661
    if (!s || (s->console_type == GRAPHIC_CONSOLE))
 
662
        return;
 
663
 
 
664
    if (ydelta > 0) {
 
665
        for(i = 0; i < ydelta; i++) {
 
666
            if (s->y_displayed == s->y_base)
 
667
                break;
 
668
            if (++s->y_displayed == s->total_height)
 
669
                s->y_displayed = 0;
 
670
        }
 
671
    } else {
 
672
        ydelta = -ydelta;
 
673
        i = s->backscroll_height;
 
674
        if (i > s->total_height - s->height)
 
675
            i = s->total_height - s->height;
 
676
        y1 = s->y_base - i;
 
677
        if (y1 < 0)
 
678
            y1 += s->total_height;
 
679
        for(i = 0; i < ydelta; i++) {
 
680
            if (s->y_displayed == y1)
 
681
                break;
 
682
            if (--s->y_displayed < 0)
 
683
                s->y_displayed = s->total_height - 1;
 
684
        }
 
685
    }
 
686
    console_refresh(s);
 
687
}
 
688
 
 
689
static void console_put_lf(TextConsole *s)
 
690
{
 
691
    TextCell *c;
 
692
    int x, y1;
 
693
 
 
694
    s->y++;
 
695
    if (s->y >= s->height) {
 
696
        s->y = s->height - 1;
 
697
 
 
698
        if (s->y_displayed == s->y_base) {
 
699
            if (++s->y_displayed == s->total_height)
 
700
                s->y_displayed = 0;
 
701
        }
 
702
        if (++s->y_base == s->total_height)
 
703
            s->y_base = 0;
 
704
        if (s->backscroll_height < s->total_height)
 
705
            s->backscroll_height++;
 
706
        y1 = (s->y_base + s->height - 1) % s->total_height;
 
707
        c = &s->cells[y1 * s->width];
 
708
        for(x = 0; x < s->width; x++) {
 
709
            c->ch = ' ';
 
710
            c->t_attrib = s->t_attrib_default;
 
711
            c++;
 
712
        }
 
713
        if (s == active_console && s->y_displayed == s->y_base) {
 
714
            if (!ds_get_bits_per_pixel(s->ds)) {
 
715
                s->text_x[0] = 0;
 
716
                s->text_y[0] = 0;
 
717
                s->text_x[1] = s->width - 1;
 
718
                s->text_y[1] = s->height - 1;
 
719
                return;
 
720
            }
 
721
 
 
722
            vga_bitblt(s->ds, 0, FONT_HEIGHT, 0, 0,
 
723
                       s->width * FONT_WIDTH,
 
724
                       (s->height - 1) * FONT_HEIGHT);
 
725
            vga_fill_rect(s->ds, 0, (s->height - 1) * FONT_HEIGHT,
 
726
                          s->width * FONT_WIDTH, FONT_HEIGHT,
 
727
                          color_table[0][s->t_attrib_default.bgcol]);
 
728
            s->update_x0 = 0;
 
729
            s->update_y0 = 0;
 
730
            s->update_x1 = s->width * FONT_WIDTH;
 
731
            s->update_y1 = s->height * FONT_HEIGHT;
 
732
        }
 
733
    }
 
734
}
 
735
 
 
736
/* Set console attributes depending on the current escape codes.
 
737
 * NOTE: I know this code is not very efficient (checking every color for it
 
738
 * self) but it is more readable and better maintainable.
 
739
 */
 
740
static void console_handle_escape(TextConsole *s)
 
741
{
 
742
    int i;
 
743
 
 
744
    for (i=0; i<s->nb_esc_params; i++) {
 
745
        switch (s->esc_params[i]) {
 
746
            case 0: /* reset all console attributes to default */
 
747
                s->t_attrib = s->t_attrib_default;
 
748
                break;
 
749
            case 1:
 
750
                s->t_attrib.bold = 1;
 
751
                break;
 
752
            case 4:
 
753
                s->t_attrib.uline = 1;
 
754
                break;
 
755
            case 5:
 
756
                s->t_attrib.blink = 1;
 
757
                break;
 
758
            case 7:
 
759
                s->t_attrib.invers = 1;
 
760
                break;
 
761
            case 8:
 
762
                s->t_attrib.unvisible = 1;
 
763
                break;
 
764
            case 22:
 
765
                s->t_attrib.bold = 0;
 
766
                break;
 
767
            case 24:
 
768
                s->t_attrib.uline = 0;
 
769
                break;
 
770
            case 25:
 
771
                s->t_attrib.blink = 0;
 
772
                break;
 
773
            case 27:
 
774
                s->t_attrib.invers = 0;
 
775
                break;
 
776
            case 28:
 
777
                s->t_attrib.unvisible = 0;
 
778
                break;
 
779
            /* set foreground color */
 
780
            case 30:
 
781
                s->t_attrib.fgcol=COLOR_BLACK;
 
782
                break;
 
783
            case 31:
 
784
                s->t_attrib.fgcol=COLOR_RED;
 
785
                break;
 
786
            case 32:
 
787
                s->t_attrib.fgcol=COLOR_GREEN;
 
788
                break;
 
789
            case 33:
 
790
                s->t_attrib.fgcol=COLOR_YELLOW;
 
791
                break;
 
792
            case 34:
 
793
                s->t_attrib.fgcol=COLOR_BLUE;
 
794
                break;
 
795
            case 35:
 
796
                s->t_attrib.fgcol=COLOR_MAGENTA;
 
797
                break;
 
798
            case 36:
 
799
                s->t_attrib.fgcol=COLOR_CYAN;
 
800
                break;
 
801
            case 37:
 
802
                s->t_attrib.fgcol=COLOR_WHITE;
 
803
                break;
 
804
            /* set background color */
 
805
            case 40:
 
806
                s->t_attrib.bgcol=COLOR_BLACK;
 
807
                break;
 
808
            case 41:
 
809
                s->t_attrib.bgcol=COLOR_RED;
 
810
                break;
 
811
            case 42:
 
812
                s->t_attrib.bgcol=COLOR_GREEN;
 
813
                break;
 
814
            case 43:
 
815
                s->t_attrib.bgcol=COLOR_YELLOW;
 
816
                break;
 
817
            case 44:
 
818
                s->t_attrib.bgcol=COLOR_BLUE;
 
819
                break;
 
820
            case 45:
 
821
                s->t_attrib.bgcol=COLOR_MAGENTA;
 
822
                break;
 
823
            case 46:
 
824
                s->t_attrib.bgcol=COLOR_CYAN;
 
825
                break;
 
826
            case 47:
 
827
                s->t_attrib.bgcol=COLOR_WHITE;
 
828
                break;
 
829
        }
 
830
    }
 
831
}
 
832
 
 
833
static void console_clear_xy(TextConsole *s, int x, int y)
 
834
{
 
835
    int y1 = (s->y_base + y) % s->total_height;
 
836
    TextCell *c = &s->cells[y1 * s->width + x];
 
837
    c->ch = ' ';
 
838
    c->t_attrib = s->t_attrib_default;
 
839
    update_xy(s, x, y);
 
840
}
 
841
 
 
842
static void console_putchar(TextConsole *s, int ch)
 
843
{
 
844
    TextCell *c;
 
845
    int y1, i;
 
846
    int x, y;
 
847
 
 
848
    switch(s->state) {
 
849
    case TTY_STATE_NORM:
 
850
        switch(ch) {
 
851
        case '\r':  /* carriage return */
 
852
            s->x = 0;
 
853
            break;
 
854
        case '\n':  /* newline */
 
855
            console_put_lf(s);
 
856
            break;
 
857
        case '\b':  /* backspace */
 
858
            if (s->x > 0)
 
859
                s->x--;
 
860
            break;
 
861
        case '\t':  /* tabspace */
 
862
            if (s->x + (8 - (s->x % 8)) > s->width) {
 
863
                s->x = 0;
 
864
                console_put_lf(s);
 
865
            } else {
 
866
                s->x = s->x + (8 - (s->x % 8));
 
867
            }
 
868
            break;
 
869
        case '\a':  /* alert aka. bell */
 
870
            /* TODO: has to be implemented */
 
871
            break;
 
872
        case 14:
 
873
            /* SI (shift in), character set 0 (ignored) */
 
874
            break;
 
875
        case 15:
 
876
            /* SO (shift out), character set 1 (ignored) */
 
877
            break;
 
878
        case 27:    /* esc (introducing an escape sequence) */
 
879
            s->state = TTY_STATE_ESC;
 
880
            break;
 
881
        default:
 
882
            if (s->x >= s->width) {
 
883
                /* line wrap */
 
884
                s->x = 0;
 
885
                console_put_lf(s);
 
886
            }
 
887
            y1 = (s->y_base + s->y) % s->total_height;
 
888
            c = &s->cells[y1 * s->width + s->x];
 
889
            c->ch = ch;
 
890
            c->t_attrib = s->t_attrib;
 
891
            update_xy(s, s->x, s->y);
 
892
            s->x++;
 
893
            break;
 
894
        }
 
895
        break;
 
896
    case TTY_STATE_ESC: /* check if it is a terminal escape sequence */
 
897
        if (ch == '[') {
 
898
            for(i=0;i<MAX_ESC_PARAMS;i++)
 
899
                s->esc_params[i] = 0;
 
900
            s->nb_esc_params = 0;
 
901
            s->state = TTY_STATE_CSI;
 
902
        } else {
 
903
            s->state = TTY_STATE_NORM;
 
904
        }
 
905
        break;
 
906
    case TTY_STATE_CSI: /* handle escape sequence parameters */
 
907
        if (ch >= '0' && ch <= '9') {
 
908
            if (s->nb_esc_params < MAX_ESC_PARAMS) {
 
909
                s->esc_params[s->nb_esc_params] =
 
910
                    s->esc_params[s->nb_esc_params] * 10 + ch - '0';
 
911
            }
 
912
        } else {
 
913
            s->nb_esc_params++;
 
914
            if (ch == ';')
 
915
                break;
 
916
#ifdef DEBUG_CONSOLE
 
917
            fprintf(stderr, "escape sequence CSI%d;%d%c, %d parameters\n",
 
918
                    s->esc_params[0], s->esc_params[1], ch, s->nb_esc_params);
 
919
#endif
 
920
            s->state = TTY_STATE_NORM;
 
921
            switch(ch) {
 
922
            case 'A':
 
923
                /* move cursor up */
 
924
                if (s->esc_params[0] == 0) {
 
925
                    s->esc_params[0] = 1;
 
926
                }
 
927
                s->y -= s->esc_params[0];
 
928
                if (s->y < 0) {
 
929
                    s->y = 0;
 
930
                }
 
931
                break;
 
932
            case 'B':
 
933
                /* move cursor down */
 
934
                if (s->esc_params[0] == 0) {
 
935
                    s->esc_params[0] = 1;
 
936
                }
 
937
                s->y += s->esc_params[0];
 
938
                if (s->y >= s->height) {
 
939
                    s->y = s->height - 1;
 
940
                }
 
941
                break;
 
942
            case 'C':
 
943
                /* move cursor right */
 
944
                if (s->esc_params[0] == 0) {
 
945
                    s->esc_params[0] = 1;
 
946
                }
 
947
                s->x += s->esc_params[0];
 
948
                if (s->x >= s->width) {
 
949
                    s->x = s->width - 1;
 
950
                }
 
951
                break;
 
952
            case 'D':
 
953
                /* move cursor left */
 
954
                if (s->esc_params[0] == 0) {
 
955
                    s->esc_params[0] = 1;
 
956
                }
 
957
                s->x -= s->esc_params[0];
 
958
                if (s->x < 0) {
 
959
                    s->x = 0;
 
960
                }
 
961
                break;
 
962
            case 'G':
 
963
                /* move cursor to column */
 
964
                s->x = s->esc_params[0] - 1;
 
965
                if (s->x < 0) {
 
966
                    s->x = 0;
 
967
                }
 
968
                break;
 
969
            case 'f':
 
970
            case 'H':
 
971
                /* move cursor to row, column */
 
972
                s->x = s->esc_params[1] - 1;
 
973
                if (s->x < 0) {
 
974
                    s->x = 0;
 
975
                }
 
976
                s->y = s->esc_params[0] - 1;
 
977
                if (s->y < 0) {
 
978
                    s->y = 0;
 
979
                }
 
980
                break;
 
981
            case 'J':
 
982
                switch (s->esc_params[0]) {
 
983
                case 0:
 
984
                    /* clear to end of screen */
 
985
                    for (y = s->y; y < s->height; y++) {
 
986
                        for (x = 0; x < s->width; x++) {
 
987
                            if (y == s->y && x < s->x) {
 
988
                                continue;
 
989
                            }
 
990
                            console_clear_xy(s, x, y);
 
991
                        }
 
992
                    }
 
993
                    break;
 
994
                case 1:
 
995
                    /* clear from beginning of screen */
 
996
                    for (y = 0; y <= s->y; y++) {
 
997
                        for (x = 0; x < s->width; x++) {
 
998
                            if (y == s->y && x > s->x) {
 
999
                                break;
 
1000
                            }
 
1001
                            console_clear_xy(s, x, y);
 
1002
                        }
 
1003
                    }
 
1004
                    break;
 
1005
                case 2:
 
1006
                    /* clear entire screen */
 
1007
                    for (y = 0; y <= s->height; y++) {
 
1008
                        for (x = 0; x < s->width; x++) {
 
1009
                            console_clear_xy(s, x, y);
 
1010
                        }
 
1011
                    }
 
1012
                break;
 
1013
                }
 
1014
            case 'K':
 
1015
                switch (s->esc_params[0]) {
 
1016
                case 0:
 
1017
                /* clear to eol */
 
1018
                for(x = s->x; x < s->width; x++) {
 
1019
                        console_clear_xy(s, x, s->y);
 
1020
                }
 
1021
                break;
 
1022
                case 1:
 
1023
                    /* clear from beginning of line */
 
1024
                    for (x = 0; x <= s->x; x++) {
 
1025
                        console_clear_xy(s, x, s->y);
 
1026
                    }
 
1027
                    break;
 
1028
                case 2:
 
1029
                    /* clear entire line */
 
1030
                    for(x = 0; x < s->width; x++) {
 
1031
                        console_clear_xy(s, x, s->y);
 
1032
                    }
 
1033
                break;
 
1034
            }
 
1035
                break;
 
1036
            case 'm':
 
1037
            console_handle_escape(s);
 
1038
            break;
 
1039
            case 'n':
 
1040
                /* report cursor position */
 
1041
                /* TODO: send ESC[row;colR */
 
1042
                break;
 
1043
            case 's':
 
1044
                /* save cursor position */
 
1045
                s->x_saved = s->x;
 
1046
                s->y_saved = s->y;
 
1047
                break;
 
1048
            case 'u':
 
1049
                /* restore cursor position */
 
1050
                s->x = s->x_saved;
 
1051
                s->y = s->y_saved;
 
1052
                break;
 
1053
            default:
 
1054
#ifdef DEBUG_CONSOLE
 
1055
                fprintf(stderr, "unhandled escape character '%c'\n", ch);
 
1056
#endif
 
1057
                break;
 
1058
            }
 
1059
            break;
 
1060
        }
 
1061
    }
 
1062
}
 
1063
 
 
1064
void console_select(unsigned int index)
 
1065
{
 
1066
    TextConsole *s;
 
1067
 
 
1068
    if (index >= MAX_CONSOLES)
 
1069
        return;
 
1070
    if (active_console) {
 
1071
        active_console->g_width = ds_get_width(active_console->ds);
 
1072
        active_console->g_height = ds_get_height(active_console->ds);
 
1073
    }
 
1074
    s = consoles[index];
 
1075
    if (s) {
 
1076
        DisplayState *ds = s->ds;
 
1077
        active_console = s;
 
1078
        if (ds_get_bits_per_pixel(s->ds)) {
 
1079
            ds->surface = qemu_resize_displaysurface(ds, s->g_width, s->g_height);
 
1080
        } else {
 
1081
            s->ds->surface->width = s->width;
 
1082
            s->ds->surface->height = s->height;
 
1083
        }
 
1084
        dpy_resize(s->ds);
 
1085
        vga_hw_invalidate();
 
1086
    }
 
1087
}
 
1088
 
 
1089
static int console_puts(CharDriverState *chr, const uint8_t *buf, int len)
 
1090
{
 
1091
    TextConsole *s = chr->opaque;
 
1092
    int i;
 
1093
 
 
1094
    s->update_x0 = s->width * FONT_WIDTH;
 
1095
    s->update_y0 = s->height * FONT_HEIGHT;
 
1096
    s->update_x1 = 0;
 
1097
    s->update_y1 = 0;
 
1098
    console_show_cursor(s, 0);
 
1099
    for(i = 0; i < len; i++) {
 
1100
        console_putchar(s, buf[i]);
 
1101
    }
 
1102
    console_show_cursor(s, 1);
 
1103
    if (ds_get_bits_per_pixel(s->ds) && s->update_x0 < s->update_x1) {
 
1104
        dpy_update(s->ds, s->update_x0, s->update_y0,
 
1105
                   s->update_x1 - s->update_x0,
 
1106
                   s->update_y1 - s->update_y0);
 
1107
    }
 
1108
    return len;
 
1109
}
 
1110
 
 
1111
static void kbd_send_chars(void *opaque)
 
1112
{
 
1113
    TextConsole *s = opaque;
 
1114
    int len;
 
1115
    uint8_t buf[16];
 
1116
 
 
1117
    len = qemu_chr_be_can_write(s->chr);
 
1118
    if (len > s->out_fifo.count)
 
1119
        len = s->out_fifo.count;
 
1120
    if (len > 0) {
 
1121
        if (len > sizeof(buf))
 
1122
            len = sizeof(buf);
 
1123
        qemu_fifo_read(&s->out_fifo, buf, len);
 
1124
        qemu_chr_be_write(s->chr, buf, len);
 
1125
    }
 
1126
    /* characters are pending: we send them a bit later (XXX:
 
1127
       horrible, should change char device API) */
 
1128
    if (s->out_fifo.count > 0) {
 
1129
        qemu_mod_timer(s->kbd_timer, qemu_get_clock_ms(rt_clock) + 1);
 
1130
    }
 
1131
}
 
1132
 
 
1133
/* called when an ascii key is pressed */
 
1134
void kbd_put_keysym(int keysym)
 
1135
{
 
1136
    TextConsole *s;
 
1137
    uint8_t buf[16], *q;
 
1138
    int c;
 
1139
 
 
1140
    s = active_console;
 
1141
    if (!s || (s->console_type == GRAPHIC_CONSOLE))
 
1142
        return;
 
1143
 
 
1144
    switch(keysym) {
 
1145
    case QEMU_KEY_CTRL_UP:
 
1146
        console_scroll(-1);
 
1147
        break;
 
1148
    case QEMU_KEY_CTRL_DOWN:
 
1149
        console_scroll(1);
 
1150
        break;
 
1151
    case QEMU_KEY_CTRL_PAGEUP:
 
1152
        console_scroll(-10);
 
1153
        break;
 
1154
    case QEMU_KEY_CTRL_PAGEDOWN:
 
1155
        console_scroll(10);
 
1156
        break;
 
1157
    default:
 
1158
        /* convert the QEMU keysym to VT100 key string */
 
1159
        q = buf;
 
1160
        if (keysym >= 0xe100 && keysym <= 0xe11f) {
 
1161
            *q++ = '\033';
 
1162
            *q++ = '[';
 
1163
            c = keysym - 0xe100;
 
1164
            if (c >= 10)
 
1165
                *q++ = '0' + (c / 10);
 
1166
            *q++ = '0' + (c % 10);
 
1167
            *q++ = '~';
 
1168
        } else if (keysym >= 0xe120 && keysym <= 0xe17f) {
 
1169
            *q++ = '\033';
 
1170
            *q++ = '[';
 
1171
            *q++ = keysym & 0xff;
 
1172
        } else if (s->echo && (keysym == '\r' || keysym == '\n')) {
 
1173
            console_puts(s->chr, (const uint8_t *) "\r", 1);
 
1174
            *q++ = '\n';
 
1175
        } else {
 
1176
            *q++ = keysym;
 
1177
        }
 
1178
        if (s->echo) {
 
1179
            console_puts(s->chr, buf, q - buf);
 
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, console_ch_t *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, console_type_t console_type)
 
1240
{
 
1241
    TextConsole *s;
 
1242
    int i;
 
1243
 
 
1244
    if (nb_consoles >= MAX_CONSOLES)
 
1245
        return NULL;
 
1246
    s = g_malloc0(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
        s->index = nb_consoles;
 
1255
        consoles[nb_consoles++] = s;
 
1256
    } else {
 
1257
        /* HACK: Put graphical consoles before text consoles.  */
 
1258
        for (i = nb_consoles; i > 0; i--) {
 
1259
            if (consoles[i - 1]->console_type == GRAPHIC_CONSOLE)
 
1260
                break;
 
1261
            consoles[i] = consoles[i - 1];
 
1262
            consoles[i]->index = i;
 
1263
        }
 
1264
        s->index = i;
 
1265
        consoles[i] = s;
 
1266
        nb_consoles++;
 
1267
    }
 
1268
    return s;
 
1269
}
 
1270
 
 
1271
static DisplaySurface* defaultallocator_create_displaysurface(int width, int height)
 
1272
{
 
1273
    DisplaySurface *surface = (DisplaySurface*) g_malloc0(sizeof(DisplaySurface));
 
1274
 
 
1275
    int linesize = width * 4;
 
1276
    qemu_alloc_display(surface, width, height, linesize,
 
1277
                       qemu_default_pixelformat(32), 0);
 
1278
    return surface;
 
1279
}
 
1280
 
 
1281
static DisplaySurface* defaultallocator_resize_displaysurface(DisplaySurface *surface,
 
1282
                                          int width, int height)
 
1283
{
 
1284
    int linesize = width * 4;
 
1285
    qemu_alloc_display(surface, width, height, linesize,
 
1286
                       qemu_default_pixelformat(32), 0);
 
1287
    return surface;
 
1288
}
 
1289
 
 
1290
void qemu_alloc_display(DisplaySurface *surface, int width, int height,
 
1291
                        int linesize, PixelFormat pf, int newflags)
 
1292
{
 
1293
    void *data;
 
1294
    surface->width = width;
 
1295
    surface->height = height;
 
1296
    surface->linesize = linesize;
 
1297
    surface->pf = pf;
 
1298
    if (surface->flags & QEMU_ALLOCATED_FLAG) {
 
1299
        data = g_realloc(surface->data,
 
1300
                            surface->linesize * surface->height);
 
1301
    } else {
 
1302
        data = g_malloc(surface->linesize * surface->height);
 
1303
    }
 
1304
    surface->data = (uint8_t *)data;
 
1305
    surface->flags = newflags | QEMU_ALLOCATED_FLAG;
 
1306
#ifdef HOST_WORDS_BIGENDIAN
 
1307
    surface->flags |= QEMU_BIG_ENDIAN_FLAG;
 
1308
#endif
 
1309
}
 
1310
 
 
1311
DisplaySurface* qemu_create_displaysurface_from(int width, int height, int bpp,
 
1312
                                              int linesize, uint8_t *data)
 
1313
{
 
1314
    DisplaySurface *surface = (DisplaySurface*) g_malloc0(sizeof(DisplaySurface));
 
1315
 
 
1316
    surface->width = width;
 
1317
    surface->height = height;
 
1318
    surface->linesize = linesize;
 
1319
    surface->pf = qemu_default_pixelformat(bpp);
 
1320
#ifdef HOST_WORDS_BIGENDIAN
 
1321
    surface->flags = QEMU_BIG_ENDIAN_FLAG;
 
1322
#endif
 
1323
    surface->data = data;
 
1324
 
 
1325
    return surface;
 
1326
}
 
1327
 
 
1328
static void defaultallocator_free_displaysurface(DisplaySurface *surface)
 
1329
{
 
1330
    if (surface == NULL)
 
1331
        return;
 
1332
    if (surface->flags & QEMU_ALLOCATED_FLAG)
 
1333
        g_free(surface->data);
 
1334
    g_free(surface);
 
1335
}
 
1336
 
 
1337
static struct DisplayAllocator default_allocator = {
 
1338
    defaultallocator_create_displaysurface,
 
1339
    defaultallocator_resize_displaysurface,
 
1340
    defaultallocator_free_displaysurface
 
1341
};
 
1342
 
 
1343
static void dumb_display_init(void)
 
1344
{
 
1345
    DisplayState *ds = g_malloc0(sizeof(DisplayState));
 
1346
    int width = 640;
 
1347
    int height = 480;
 
1348
 
 
1349
    ds->allocator = &default_allocator;
 
1350
    if (is_fixedsize_console()) {
 
1351
        width = active_console->g_width;
 
1352
        height = active_console->g_height;
 
1353
    }
 
1354
    ds->surface = qemu_create_displaysurface(ds, width, height);
 
1355
    register_displaystate(ds);
 
1356
}
 
1357
 
 
1358
/***********************************************************/
 
1359
/* register display */
 
1360
 
 
1361
void register_displaystate(DisplayState *ds)
 
1362
{
 
1363
    DisplayState **s;
 
1364
    s = &display_state;
 
1365
    while (*s != NULL)
 
1366
        s = &(*s)->next;
 
1367
    ds->next = NULL;
 
1368
    *s = ds;
 
1369
}
 
1370
 
 
1371
DisplayState *get_displaystate(void)
 
1372
{
 
1373
    if (!display_state) {
 
1374
        dumb_display_init ();
 
1375
    }
 
1376
    return display_state;
 
1377
}
 
1378
 
 
1379
DisplayAllocator *register_displayallocator(DisplayState *ds, DisplayAllocator *da)
 
1380
{
 
1381
    if(ds->allocator ==  &default_allocator) {
 
1382
        DisplaySurface *surf;
 
1383
        surf = da->create_displaysurface(ds_get_width(ds), ds_get_height(ds));
 
1384
        defaultallocator_free_displaysurface(ds->surface);
 
1385
        ds->surface = surf;
 
1386
        ds->allocator = da;
 
1387
    }
 
1388
    return ds->allocator;
 
1389
}
 
1390
 
 
1391
DisplayState *graphic_console_init(vga_hw_update_ptr update,
 
1392
                                   vga_hw_invalidate_ptr invalidate,
 
1393
                                   vga_hw_screen_dump_ptr screen_dump,
 
1394
                                   vga_hw_text_update_ptr text_update,
 
1395
                                   void *opaque)
 
1396
{
 
1397
    TextConsole *s;
 
1398
    DisplayState *ds;
 
1399
 
 
1400
    ds = (DisplayState *) g_malloc0(sizeof(DisplayState));
 
1401
    ds->allocator = &default_allocator; 
 
1402
    ds->surface = qemu_create_displaysurface(ds, 640, 480);
 
1403
 
 
1404
    s = new_console(ds, GRAPHIC_CONSOLE);
 
1405
    if (s == NULL) {
 
1406
        qemu_free_displaysurface(ds);
 
1407
        g_free(ds);
 
1408
        return NULL;
 
1409
    }
 
1410
    s->hw_update = update;
 
1411
    s->hw_invalidate = invalidate;
 
1412
    s->hw_screen_dump = screen_dump;
 
1413
    s->hw_text_update = text_update;
 
1414
    s->hw = opaque;
 
1415
 
 
1416
    register_displaystate(ds);
 
1417
    return ds;
 
1418
}
 
1419
 
 
1420
int is_graphic_console(void)
 
1421
{
 
1422
    return active_console && active_console->console_type == GRAPHIC_CONSOLE;
 
1423
}
 
1424
 
 
1425
int is_fixedsize_console(void)
 
1426
{
 
1427
    return active_console && active_console->console_type != TEXT_CONSOLE;
 
1428
}
 
1429
 
 
1430
void console_color_init(DisplayState *ds)
 
1431
{
 
1432
    int i, j;
 
1433
    for (j = 0; j < 2; j++) {
 
1434
        for (i = 0; i < 8; i++) {
 
1435
            color_table[j][i] = col_expand(ds,
 
1436
                   vga_get_color(ds, color_table_rgb[j][i]));
 
1437
        }
 
1438
    }
 
1439
}
 
1440
 
 
1441
static int n_text_consoles;
 
1442
static CharDriverState *text_consoles[128];
 
1443
 
 
1444
static void text_console_set_echo(CharDriverState *chr, bool echo)
 
1445
{
 
1446
    TextConsole *s = chr->opaque;
 
1447
 
 
1448
    s->echo = echo;
 
1449
}
 
1450
 
 
1451
static void text_console_do_init(CharDriverState *chr, DisplayState *ds)
 
1452
{
 
1453
    TextConsole *s;
 
1454
    static int color_inited;
 
1455
 
 
1456
    s = chr->opaque;
 
1457
 
 
1458
    chr->chr_write = console_puts;
 
1459
 
 
1460
    s->out_fifo.buf = s->out_fifo_buf;
 
1461
    s->out_fifo.buf_size = sizeof(s->out_fifo_buf);
 
1462
    s->kbd_timer = qemu_new_timer_ms(rt_clock, kbd_send_chars, s);
 
1463
    s->ds = ds;
 
1464
 
 
1465
    if (!color_inited) {
 
1466
        color_inited = 1;
 
1467
        console_color_init(s->ds);
 
1468
    }
 
1469
    s->y_displayed = 0;
 
1470
    s->y_base = 0;
 
1471
    s->total_height = DEFAULT_BACKSCROLL;
 
1472
    s->x = 0;
 
1473
    s->y = 0;
 
1474
    if (s->console_type == TEXT_CONSOLE) {
 
1475
        s->g_width = ds_get_width(s->ds);
 
1476
        s->g_height = ds_get_height(s->ds);
 
1477
    }
 
1478
 
 
1479
    s->hw_invalidate = text_console_invalidate;
 
1480
    s->hw_text_update = text_console_update;
 
1481
    s->hw = s;
 
1482
 
 
1483
    /* Set text attribute defaults */
 
1484
    s->t_attrib_default.bold = 0;
 
1485
    s->t_attrib_default.uline = 0;
 
1486
    s->t_attrib_default.blink = 0;
 
1487
    s->t_attrib_default.invers = 0;
 
1488
    s->t_attrib_default.unvisible = 0;
 
1489
    s->t_attrib_default.fgcol = COLOR_WHITE;
 
1490
    s->t_attrib_default.bgcol = COLOR_BLACK;
 
1491
    /* set current text attributes to default */
 
1492
    s->t_attrib = s->t_attrib_default;
 
1493
    text_console_resize(s);
 
1494
 
 
1495
    if (chr->label) {
 
1496
        char msg[128];
 
1497
        int len;
 
1498
 
 
1499
        s->t_attrib.bgcol = COLOR_BLUE;
 
1500
        len = snprintf(msg, sizeof(msg), "%s console\r\n", chr->label);
 
1501
        console_puts(chr, (uint8_t*)msg, len);
 
1502
        s->t_attrib = s->t_attrib_default;
 
1503
    }
 
1504
 
 
1505
    qemu_chr_generic_open(chr);
 
1506
    if (chr->init)
 
1507
        chr->init(chr);
 
1508
}
 
1509
 
 
1510
int text_console_init(QemuOpts *opts, CharDriverState **_chr)
 
1511
{
 
1512
    CharDriverState *chr;
 
1513
    TextConsole *s;
 
1514
    unsigned width;
 
1515
    unsigned height;
 
1516
 
 
1517
    chr = g_malloc0(sizeof(CharDriverState));
 
1518
 
 
1519
    if (n_text_consoles == 128) {
 
1520
        fprintf(stderr, "Too many text consoles\n");
 
1521
        exit(1);
 
1522
    }
 
1523
    text_consoles[n_text_consoles] = chr;
 
1524
    n_text_consoles++;
 
1525
 
 
1526
    width = qemu_opt_get_number(opts, "width", 0);
 
1527
    if (width == 0)
 
1528
        width = qemu_opt_get_number(opts, "cols", 0) * FONT_WIDTH;
 
1529
 
 
1530
    height = qemu_opt_get_number(opts, "height", 0);
 
1531
    if (height == 0)
 
1532
        height = qemu_opt_get_number(opts, "rows", 0) * FONT_HEIGHT;
 
1533
 
 
1534
    if (width == 0 || height == 0) {
 
1535
        s = new_console(NULL, TEXT_CONSOLE);
 
1536
    } else {
 
1537
        s = new_console(NULL, TEXT_CONSOLE_FIXED_SIZE);
 
1538
    }
 
1539
 
 
1540
    if (!s) {
 
1541
        g_free(chr);
 
1542
        return -EBUSY;
 
1543
    }
 
1544
 
 
1545
    s->chr = chr;
 
1546
    s->g_width = width;
 
1547
    s->g_height = height;
 
1548
    chr->opaque = s;
 
1549
    chr->chr_set_echo = text_console_set_echo;
 
1550
 
 
1551
    *_chr = chr;
 
1552
    return 0;
 
1553
}
 
1554
 
 
1555
void text_consoles_set_display(DisplayState *ds)
 
1556
{
 
1557
    int i;
 
1558
 
 
1559
    for (i = 0; i < n_text_consoles; i++) {
 
1560
        text_console_do_init(text_consoles[i], ds);
 
1561
    }
 
1562
 
 
1563
    n_text_consoles = 0;
 
1564
}
 
1565
 
 
1566
void qemu_console_resize(DisplayState *ds, int width, int height)
 
1567
{
 
1568
    TextConsole *s = get_graphic_console(ds);
 
1569
    if (!s) return;
 
1570
 
 
1571
    s->g_width = width;
 
1572
    s->g_height = height;
 
1573
    if (is_graphic_console()) {
 
1574
        ds->surface = qemu_resize_displaysurface(ds, width, height);
 
1575
        dpy_resize(ds);
 
1576
    }
 
1577
}
 
1578
 
 
1579
void qemu_console_copy(DisplayState *ds, int src_x, int src_y,
 
1580
                       int dst_x, int dst_y, int w, int h)
 
1581
{
 
1582
    if (is_graphic_console()) {
 
1583
        dpy_copy(ds, src_x, src_y, dst_x, dst_y, w, h);
 
1584
    }
 
1585
}
 
1586
 
 
1587
PixelFormat qemu_different_endianness_pixelformat(int bpp)
 
1588
{
 
1589
    PixelFormat pf;
 
1590
 
 
1591
    memset(&pf, 0x00, sizeof(PixelFormat));
 
1592
 
 
1593
    pf.bits_per_pixel = bpp;
 
1594
    pf.bytes_per_pixel = bpp / 8;
 
1595
    pf.depth = bpp == 32 ? 24 : bpp;
 
1596
 
 
1597
    switch (bpp) {
 
1598
        case 24:
 
1599
            pf.rmask = 0x000000FF;
 
1600
            pf.gmask = 0x0000FF00;
 
1601
            pf.bmask = 0x00FF0000;
 
1602
            pf.rmax = 255;
 
1603
            pf.gmax = 255;
 
1604
            pf.bmax = 255;
 
1605
            pf.rshift = 0;
 
1606
            pf.gshift = 8;
 
1607
            pf.bshift = 16;
 
1608
            pf.rbits = 8;
 
1609
            pf.gbits = 8;
 
1610
            pf.bbits = 8;
 
1611
            break;
 
1612
        case 32:
 
1613
            pf.rmask = 0x0000FF00;
 
1614
            pf.gmask = 0x00FF0000;
 
1615
            pf.bmask = 0xFF000000;
 
1616
            pf.amask = 0x00000000;
 
1617
            pf.amax = 255;
 
1618
            pf.rmax = 255;
 
1619
            pf.gmax = 255;
 
1620
            pf.bmax = 255;
 
1621
            pf.ashift = 0;
 
1622
            pf.rshift = 8;
 
1623
            pf.gshift = 16;
 
1624
            pf.bshift = 24;
 
1625
            pf.rbits = 8;
 
1626
            pf.gbits = 8;
 
1627
            pf.bbits = 8;
 
1628
            pf.abits = 8;
 
1629
            break;
 
1630
        default:
 
1631
            break;
 
1632
    }
 
1633
    return pf;
 
1634
}
 
1635
 
 
1636
PixelFormat qemu_default_pixelformat(int bpp)
 
1637
{
 
1638
    PixelFormat pf;
 
1639
 
 
1640
    memset(&pf, 0x00, sizeof(PixelFormat));
 
1641
 
 
1642
    pf.bits_per_pixel = bpp;
 
1643
    pf.bytes_per_pixel = bpp / 8;
 
1644
    pf.depth = bpp == 32 ? 24 : bpp;
 
1645
 
 
1646
    switch (bpp) {
 
1647
        case 15:
 
1648
            pf.bits_per_pixel = 16;
 
1649
            pf.bytes_per_pixel = 2;
 
1650
            pf.rmask = 0x00007c00;
 
1651
            pf.gmask = 0x000003E0;
 
1652
            pf.bmask = 0x0000001F;
 
1653
            pf.rmax = 31;
 
1654
            pf.gmax = 31;
 
1655
            pf.bmax = 31;
 
1656
            pf.rshift = 10;
 
1657
            pf.gshift = 5;
 
1658
            pf.bshift = 0;
 
1659
            pf.rbits = 5;
 
1660
            pf.gbits = 5;
 
1661
            pf.bbits = 5;
 
1662
            break;
 
1663
        case 16:
 
1664
            pf.rmask = 0x0000F800;
 
1665
            pf.gmask = 0x000007E0;
 
1666
            pf.bmask = 0x0000001F;
 
1667
            pf.rmax = 31;
 
1668
            pf.gmax = 63;
 
1669
            pf.bmax = 31;
 
1670
            pf.rshift = 11;
 
1671
            pf.gshift = 5;
 
1672
            pf.bshift = 0;
 
1673
            pf.rbits = 5;
 
1674
            pf.gbits = 6;
 
1675
            pf.bbits = 5;
 
1676
            break;
 
1677
        case 24:
 
1678
            pf.rmask = 0x00FF0000;
 
1679
            pf.gmask = 0x0000FF00;
 
1680
            pf.bmask = 0x000000FF;
 
1681
            pf.rmax = 255;
 
1682
            pf.gmax = 255;
 
1683
            pf.bmax = 255;
 
1684
            pf.rshift = 16;
 
1685
            pf.gshift = 8;
 
1686
            pf.bshift = 0;
 
1687
            pf.rbits = 8;
 
1688
            pf.gbits = 8;
 
1689
            pf.bbits = 8;
 
1690
        case 32:
 
1691
            pf.rmask = 0x00FF0000;
 
1692
            pf.gmask = 0x0000FF00;
 
1693
            pf.bmask = 0x000000FF;
 
1694
            pf.amax = 255;
 
1695
            pf.rmax = 255;
 
1696
            pf.gmax = 255;
 
1697
            pf.bmax = 255;
 
1698
            pf.ashift = 24;
 
1699
            pf.rshift = 16;
 
1700
            pf.gshift = 8;
 
1701
            pf.bshift = 0;
 
1702
            pf.rbits = 8;
 
1703
            pf.gbits = 8;
 
1704
            pf.bbits = 8;
 
1705
            pf.abits = 8;
 
1706
            break;
 
1707
        default:
 
1708
            break;
 
1709
    }
 
1710
    return pf;
 
1711
}