Statistics
| Branch: | Revision:

root / console.c @ 19bf7c87

History | View | Annotate | Download (46.9 kB)

1
/*
2
 * QEMU graphical console
3
 *
4
 * Copyright (c) 2004 Fabrice Bellard
5
 *
6
 * Permission is hereby granted, free of charge, to any person obtaining a copy
7
 * of this software and associated documentation files (the "Software"), to deal
8
 * in the Software without restriction, including without limitation the rights
9
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
10
 * copies of the Software, and to permit persons to whom the Software is
11
 * furnished to do so, subject to the following conditions:
12
 *
13
 * The above copyright notice and this permission notice shall be included in
14
 * all copies or substantial portions of the Software.
15
 *
16
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
17
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
18
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL
19
 * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
20
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
21
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
22
 * THE SOFTWARE.
23
 */
24
#include "qemu-common.h"
25
#include "console.h"
26
#include "qemu-timer.h"
27

    
28
//#define DEBUG_CONSOLE
29
#define DEFAULT_BACKSCROLL 512
30
#define MAX_CONSOLES 12
31

    
32
#define QEMU_RGBA(r, g, b, a) (((a) << 24) | ((r) << 16) | ((g) << 8) | (b))
33
#define QEMU_RGB(r, g, b) QEMU_RGBA(r, g, b, 0xff)
34

    
35
typedef struct TextAttributes {
36
    uint8_t fgcol:4;
37
    uint8_t bgcol:4;
38
    uint8_t bold:1;
39
    uint8_t uline:1;
40
    uint8_t blink:1;
41
    uint8_t invers:1;
42
    uint8_t unvisible:1;
43
} TextAttributes;
44

    
45
typedef struct TextCell {
46
    uint8_t ch;
47
    TextAttributes t_attrib;
48
} TextCell;
49

    
50
#define MAX_ESC_PARAMS 3
51

    
52
enum TTYState {
53
    TTY_STATE_NORM,
54
    TTY_STATE_ESC,
55
    TTY_STATE_CSI,
56
};
57

    
58
typedef struct QEMUFIFO {
59
    uint8_t *buf;
60
    int buf_size;
61
    int count, wptr, rptr;
62
} QEMUFIFO;
63

    
64
static int qemu_fifo_write(QEMUFIFO *f, const uint8_t *buf, int len1)
65
{
66
    int l, len;
67

    
68
    l = f->buf_size - f->count;
69
    if (len1 > l)
70
        len1 = l;
71
    len = len1;
72
    while (len > 0) {
73
        l = f->buf_size - f->wptr;
74
        if (l > len)
75
            l = len;
76
        memcpy(f->buf + f->wptr, buf, l);
77
        f->wptr += l;
78
        if (f->wptr >= f->buf_size)
79
            f->wptr = 0;
80
        buf += l;
81
        len -= l;
82
    }
83
    f->count += len1;
84
    return len1;
85
}
86

    
87
static int qemu_fifo_read(QEMUFIFO *f, uint8_t *buf, int len1)
88
{
89
    int l, len;
90

    
91
    if (len1 > f->count)
92
        len1 = f->count;
93
    len = len1;
94
    while (len > 0) {
95
        l = f->buf_size - f->rptr;
96
        if (l > len)
97
            l = len;
98
        memcpy(buf, f->buf + f->rptr, l);
99
        f->rptr += l;
100
        if (f->rptr >= f->buf_size)
101
            f->rptr = 0;
102
        buf += l;
103
        len -= l;
104
    }
105
    f->count -= len1;
106
    return len1;
107
}
108

    
109
typedef enum {
110
    GRAPHIC_CONSOLE,
111
    TEXT_CONSOLE,
112
    TEXT_CONSOLE_FIXED_SIZE
113
} console_type_t;
114

    
115
/* ??? This is mis-named.
116
   It is used for both text and graphical consoles.  */
117
struct TextConsole {
118
    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
    if (previous_active_console) {
190
        console_select(previous_active_console->index);
191
    }
192
}
193

    
194
void vga_hw_text_update(console_ch_t *chardata)
195
{
196
    if (active_console && active_console->hw_text_update)
197
        active_console->hw_text_update(active_console->hw, chardata);
198
}
199

    
200
/* convert a RGBA color to a color index usable in graphic primitives */
201
static unsigned int vga_get_color(DisplayState *ds, unsigned int rgba)
202
{
203
    unsigned int r, g, b, color;
204

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

    
236
static void vga_fill_rect (DisplayState *ds,
237
                           int posx, int posy, int width, int height, uint32_t color)
238
{
239
    uint8_t *d, *d1;
240
    int x, y, bpp;
241

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

    
271
/* copy from (xs, ys) to (xd, yd) a rectangle of size (w, h) */
272
static void vga_bitblt(DisplayState *ds, int xs, int ys, int xd, int yd, int w, int h)
273
{
274
    const uint8_t *s;
275
    uint8_t *d;
276
    int wb, y, bpp;
277

    
278
    bpp = (ds_get_bits_per_pixel(ds) + 7) >> 3;
279
    wb = w * bpp;
280
    if (yd <= ys) {
281
        s = ds_get_data(ds) +
282
            ds_get_linesize(ds) * ys + bpp * xs;
283
        d = ds_get_data(ds) +
284
            ds_get_linesize(ds) * yd + bpp * xd;
285
        for (y = 0; y < h; y++) {
286
            memmove(d, s, wb);
287
            d += ds_get_linesize(ds);
288
            s += ds_get_linesize(ds);
289
        }
290
    } else {
291
        s = ds_get_data(ds) +
292
            ds_get_linesize(ds) * (ys + h - 1) + bpp * xs;
293
        d = ds_get_data(ds) +
294
            ds_get_linesize(ds) * (yd + h - 1) + bpp * xd;
295
       for (y = 0; y < h; y++) {
296
            memmove(d, s, wb);
297
            d -= ds_get_linesize(ds);
298
            s -= ds_get_linesize(ds);
299
        }
300
    }
301
}
302

    
303
/***********************************************************/
304
/* basic char display */
305

    
306
#define FONT_HEIGHT 16
307
#define FONT_WIDTH 8
308

    
309
#include "vgafont.h"
310

    
311
#define cbswap_32(__x) \
312
((uint32_t)( \
313
                (((uint32_t)(__x) & (uint32_t)0x000000ffUL) << 24) | \
314
                (((uint32_t)(__x) & (uint32_t)0x0000ff00UL) <<  8) | \
315
                (((uint32_t)(__x) & (uint32_t)0x00ff0000UL) >>  8) | \
316
                (((uint32_t)(__x) & (uint32_t)0xff000000UL) >> 24) ))
317

    
318
#ifdef HOST_WORDS_BIGENDIAN
319
#define PAT(x) x
320
#else
321
#define PAT(x) cbswap_32(x)
322
#endif
323

    
324
static const uint32_t dmask16[16] = {
325
    PAT(0x00000000),
326
    PAT(0x000000ff),
327
    PAT(0x0000ff00),
328
    PAT(0x0000ffff),
329
    PAT(0x00ff0000),
330
    PAT(0x00ff00ff),
331
    PAT(0x00ffff00),
332
    PAT(0x00ffffff),
333
    PAT(0xff000000),
334
    PAT(0xff0000ff),
335
    PAT(0xff00ff00),
336
    PAT(0xff00ffff),
337
    PAT(0xffff0000),
338
    PAT(0xffff00ff),
339
    PAT(0xffffff00),
340
    PAT(0xffffffff),
341
};
342

    
343
static const uint32_t dmask4[4] = {
344
    PAT(0x00000000),
345
    PAT(0x0000ffff),
346
    PAT(0xffff0000),
347
    PAT(0xffffffff),
348
};
349

    
350
static uint32_t color_table[2][8];
351

    
352
#ifndef CONFIG_CURSES
353
enum color_names {
354
    COLOR_BLACK   = 0,
355
    COLOR_RED     = 1,
356
    COLOR_GREEN   = 2,
357
    COLOR_YELLOW  = 3,
358
    COLOR_BLUE    = 4,
359
    COLOR_MAGENTA = 5,
360
    COLOR_CYAN    = 6,
361
    COLOR_WHITE   = 7
362
};
363
#endif
364

    
365
static const uint32_t color_table_rgb[2][8] = {
366
    {   /* dark */
367
        QEMU_RGB(0x00, 0x00, 0x00),  /* black */
368
        QEMU_RGB(0xaa, 0x00, 0x00),  /* red */
369
        QEMU_RGB(0x00, 0xaa, 0x00),  /* green */
370
        QEMU_RGB(0xaa, 0xaa, 0x00),  /* yellow */
371
        QEMU_RGB(0x00, 0x00, 0xaa),  /* blue */
372
        QEMU_RGB(0xaa, 0x00, 0xaa),  /* magenta */
373
        QEMU_RGB(0x00, 0xaa, 0xaa),  /* cyan */
374
        QEMU_RGB(0xaa, 0xaa, 0xaa),  /* white */
375
    },
376
    {   /* bright */
377
        QEMU_RGB(0x00, 0x00, 0x00),  /* black */
378
        QEMU_RGB(0xff, 0x00, 0x00),  /* red */
379
        QEMU_RGB(0x00, 0xff, 0x00),  /* green */
380
        QEMU_RGB(0xff, 0xff, 0x00),  /* yellow */
381
        QEMU_RGB(0x00, 0x00, 0xff),  /* blue */
382
        QEMU_RGB(0xff, 0x00, 0xff),  /* magenta */
383
        QEMU_RGB(0x00, 0xff, 0xff),  /* cyan */
384
        QEMU_RGB(0xff, 0xff, 0xff),  /* white */
385
    }
386
};
387

    
388
static inline unsigned int col_expand(DisplayState *ds, unsigned int col)
389
{
390
    switch(ds_get_bits_per_pixel(ds)) {
391
    case 8:
392
        col |= col << 8;
393
        col |= col << 16;
394
        break;
395
    case 15:
396
    case 16:
397
        col |= col << 16;
398
        break;
399
    default:
400
        break;
401
    }
402

    
403
    return col;
404
}
405
#ifdef DEBUG_CONSOLE
406
static void console_print_text_attributes(TextAttributes *t_attrib, char ch)
407
{
408
    if (t_attrib->bold) {
409
        printf("b");
410
    } else {
411
        printf(" ");
412
    }
413
    if (t_attrib->uline) {
414
        printf("u");
415
    } else {
416
        printf(" ");
417
    }
418
    if (t_attrib->blink) {
419
        printf("l");
420
    } else {
421
        printf(" ");
422
    }
423
    if (t_attrib->invers) {
424
        printf("i");
425
    } else {
426
        printf(" ");
427
    }
428
    if (t_attrib->unvisible) {
429
        printf("n");
430
    } else {
431
        printf(" ");
432
    }
433

    
434
    printf(" fg: %d bg: %d ch:'%2X' '%c'\n", t_attrib->fgcol, t_attrib->bgcol, ch, ch);
435
}
436
#endif
437

    
438
static void vga_putcharxy(DisplayState *ds, int x, int y, int ch,
439
                          TextAttributes *t_attrib)
440
{
441
    uint8_t *d;
442
    const uint8_t *font_ptr;
443
    unsigned int font_data, linesize, xorcol, bpp;
444
    int i;
445
    unsigned int fgcol, bgcol;
446

    
447
#ifdef DEBUG_CONSOLE
448
    printf("x: %2i y: %2i", x, y);
449
    console_print_text_attributes(t_attrib, ch);
450
#endif
451

    
452
    if (t_attrib->invers) {
453
        bgcol = color_table[t_attrib->bold][t_attrib->fgcol];
454
        fgcol = color_table[t_attrib->bold][t_attrib->bgcol];
455
    } else {
456
        fgcol = color_table[t_attrib->bold][t_attrib->fgcol];
457
        bgcol = color_table[t_attrib->bold][t_attrib->bgcol];
458
    }
459

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

    
514
static void text_console_resize(TextConsole *s)
515
{
516
    TextCell *cells, *c, *c1;
517
    int w1, x, y, last_width;
518

    
519
    last_width = s->width;
520
    s->width = s->g_width / FONT_WIDTH;
521
    s->height = s->g_height / FONT_HEIGHT;
522

    
523
    w1 = last_width;
524
    if (s->width < w1)
525
        w1 = s->width;
526

    
527
    cells = g_malloc(s->width * s->total_height * sizeof(TextCell));
528
    for(y = 0; y < s->total_height; y++) {
529
        c = &cells[y * s->width];
530
        if (w1 > 0) {
531
            c1 = &s->cells[y * last_width];
532
            for(x = 0; x < w1; x++) {
533
                *c++ = *c1++;
534
            }
535
        }
536
        for(x = w1; x < s->width; x++) {
537
            c->ch = ' ';
538
            c->t_attrib = s->t_attrib_default;
539
            c++;
540
        }
541
    }
542
    g_free(s->cells);
543
    s->cells = cells;
544
}
545

    
546
static inline void text_update_xy(TextConsole *s, int x, int y)
547
{
548
    s->text_x[0] = MIN(s->text_x[0], x);
549
    s->text_x[1] = MAX(s->text_x[1], x);
550
    s->text_y[0] = MIN(s->text_y[0], y);
551
    s->text_y[1] = MAX(s->text_y[1], y);
552
}
553

    
554
static void invalidate_xy(TextConsole *s, int x, int y)
555
{
556
    if (s->update_x0 > x * FONT_WIDTH)
557
        s->update_x0 = x * FONT_WIDTH;
558
    if (s->update_y0 > y * FONT_HEIGHT)
559
        s->update_y0 = y * FONT_HEIGHT;
560
    if (s->update_x1 < (x + 1) * FONT_WIDTH)
561
        s->update_x1 = (x + 1) * FONT_WIDTH;
562
    if (s->update_y1 < (y + 1) * FONT_HEIGHT)
563
        s->update_y1 = (y + 1) * FONT_HEIGHT;
564
}
565

    
566
static void update_xy(TextConsole *s, int x, int y)
567
{
568
    TextCell *c;
569
    int y1, y2;
570

    
571
    if (s == active_console) {
572
        if (!ds_get_bits_per_pixel(s->ds)) {
573
            text_update_xy(s, x, y);
574
            return;
575
        }
576

    
577
        y1 = (s->y_base + y) % s->total_height;
578
        y2 = y1 - s->y_displayed;
579
        if (y2 < 0)
580
            y2 += s->total_height;
581
        if (y2 < s->height) {
582
            c = &s->cells[y1 * s->width + x];
583
            vga_putcharxy(s->ds, x, y2, c->ch,
584
                          &(c->t_attrib));
585
            invalidate_xy(s, x, y2);
586
        }
587
    }
588
}
589

    
590
static void console_show_cursor(TextConsole *s, int show)
591
{
592
    TextCell *c;
593
    int y, y1;
594

    
595
    if (s == active_console) {
596
        int x = s->x;
597

    
598
        if (!ds_get_bits_per_pixel(s->ds)) {
599
            s->cursor_invalidate = 1;
600
            return;
601
        }
602

    
603
        if (x >= s->width) {
604
            x = s->width - 1;
605
        }
606
        y1 = (s->y_base + s->y) % s->total_height;
607
        y = y1 - s->y_displayed;
608
        if (y < 0)
609
            y += s->total_height;
610
        if (y < s->height) {
611
            c = &s->cells[y1 * s->width + x];
612
            if (show) {
613
                TextAttributes t_attrib = s->t_attrib_default;
614
                t_attrib.invers = !(t_attrib.invers); /* invert fg and bg */
615
                vga_putcharxy(s->ds, x, y, c->ch, &t_attrib);
616
            } else {
617
                vga_putcharxy(s->ds, x, y, c->ch, &(c->t_attrib));
618
            }
619
            invalidate_xy(s, x, y);
620
        }
621
    }
622
}
623

    
624
static void console_refresh(TextConsole *s)
625
{
626
    TextCell *c;
627
    int x, y, y1;
628

    
629
    if (s != active_console)
630
        return;
631
    if (!ds_get_bits_per_pixel(s->ds)) {
632
        s->text_x[0] = 0;
633
        s->text_y[0] = 0;
634
        s->text_x[1] = s->width - 1;
635
        s->text_y[1] = s->height - 1;
636
        s->cursor_invalidate = 1;
637
        return;
638
    }
639

    
640
    vga_fill_rect(s->ds, 0, 0, ds_get_width(s->ds), ds_get_height(s->ds),
641
                  color_table[0][COLOR_BLACK]);
642
    y1 = s->y_displayed;
643
    for(y = 0; y < s->height; y++) {
644
        c = s->cells + y1 * s->width;
645
        for(x = 0; x < s->width; x++) {
646
            vga_putcharxy(s->ds, x, y, c->ch,
647
                          &(c->t_attrib));
648
            c++;
649
        }
650
        if (++y1 == s->total_height)
651
            y1 = 0;
652
    }
653
    console_show_cursor(s, 1);
654
    dpy_update(s->ds, 0, 0, ds_get_width(s->ds), ds_get_height(s->ds));
655
}
656

    
657
static void console_scroll(int ydelta)
658
{
659
    TextConsole *s;
660
    int i, y1;
661

    
662
    s = active_console;
663
    if (!s || (s->console_type == GRAPHIC_CONSOLE))
664
        return;
665

    
666
    if (ydelta > 0) {
667
        for(i = 0; i < ydelta; i++) {
668
            if (s->y_displayed == s->y_base)
669
                break;
670
            if (++s->y_displayed == s->total_height)
671
                s->y_displayed = 0;
672
        }
673
    } else {
674
        ydelta = -ydelta;
675
        i = s->backscroll_height;
676
        if (i > s->total_height - s->height)
677
            i = s->total_height - s->height;
678
        y1 = s->y_base - i;
679
        if (y1 < 0)
680
            y1 += s->total_height;
681
        for(i = 0; i < ydelta; i++) {
682
            if (s->y_displayed == y1)
683
                break;
684
            if (--s->y_displayed < 0)
685
                s->y_displayed = s->total_height - 1;
686
        }
687
    }
688
    console_refresh(s);
689
}
690

    
691
static void console_put_lf(TextConsole *s)
692
{
693
    TextCell *c;
694
    int x, y1;
695

    
696
    s->y++;
697
    if (s->y >= s->height) {
698
        s->y = s->height - 1;
699

    
700
        if (s->y_displayed == s->y_base) {
701
            if (++s->y_displayed == s->total_height)
702
                s->y_displayed = 0;
703
        }
704
        if (++s->y_base == s->total_height)
705
            s->y_base = 0;
706
        if (s->backscroll_height < s->total_height)
707
            s->backscroll_height++;
708
        y1 = (s->y_base + s->height - 1) % s->total_height;
709
        c = &s->cells[y1 * s->width];
710
        for(x = 0; x < s->width; x++) {
711
            c->ch = ' ';
712
            c->t_attrib = s->t_attrib_default;
713
            c++;
714
        }
715
        if (s == active_console && s->y_displayed == s->y_base) {
716
            if (!ds_get_bits_per_pixel(s->ds)) {
717
                s->text_x[0] = 0;
718
                s->text_y[0] = 0;
719
                s->text_x[1] = s->width - 1;
720
                s->text_y[1] = s->height - 1;
721
                return;
722
            }
723

    
724
            vga_bitblt(s->ds, 0, FONT_HEIGHT, 0, 0,
725
                       s->width * FONT_WIDTH,
726
                       (s->height - 1) * FONT_HEIGHT);
727
            vga_fill_rect(s->ds, 0, (s->height - 1) * FONT_HEIGHT,
728
                          s->width * FONT_WIDTH, FONT_HEIGHT,
729
                          color_table[0][s->t_attrib_default.bgcol]);
730
            s->update_x0 = 0;
731
            s->update_y0 = 0;
732
            s->update_x1 = s->width * FONT_WIDTH;
733
            s->update_y1 = s->height * FONT_HEIGHT;
734
        }
735
    }
736
}
737

    
738
/* Set console attributes depending on the current escape codes.
739
 * NOTE: I know this code is not very efficient (checking every color for it
740
 * self) but it is more readable and better maintainable.
741
 */
742
static void console_handle_escape(TextConsole *s)
743
{
744
    int i;
745

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

    
835
static void console_clear_xy(TextConsole *s, int x, int y)
836
{
837
    int y1 = (s->y_base + y) % s->total_height;
838
    TextCell *c = &s->cells[y1 * s->width + x];
839
    c->ch = ' ';
840
    c->t_attrib = s->t_attrib_default;
841
    update_xy(s, x, y);
842
}
843

    
844
static void console_putchar(TextConsole *s, int ch)
845
{
846
    TextCell *c;
847
    int y1, i;
848
    int x, y;
849

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

    
1067
void console_select(unsigned int index)
1068
{
1069
    TextConsole *s;
1070

    
1071
    if (index >= MAX_CONSOLES)
1072
        return;
1073
    if (active_console) {
1074
        active_console->g_width = ds_get_width(active_console->ds);
1075
        active_console->g_height = ds_get_height(active_console->ds);
1076
    }
1077
    s = consoles[index];
1078
    if (s) {
1079
        DisplayState *ds = s->ds;
1080
        active_console = s;
1081
        if (ds_get_bits_per_pixel(s->ds)) {
1082
            ds->surface = qemu_resize_displaysurface(ds, s->g_width, s->g_height);
1083
        } else {
1084
            s->ds->surface->width = s->width;
1085
            s->ds->surface->height = s->height;
1086
        }
1087
        dpy_resize(s->ds);
1088
        vga_hw_invalidate();
1089
    }
1090
}
1091

    
1092
static int console_puts(CharDriverState *chr, const uint8_t *buf, int len)
1093
{
1094
    TextConsole *s = chr->opaque;
1095
    int i;
1096

    
1097
    s->update_x0 = s->width * FONT_WIDTH;
1098
    s->update_y0 = s->height * FONT_HEIGHT;
1099
    s->update_x1 = 0;
1100
    s->update_y1 = 0;
1101
    console_show_cursor(s, 0);
1102
    for(i = 0; i < len; i++) {
1103
        console_putchar(s, buf[i]);
1104
    }
1105
    console_show_cursor(s, 1);
1106
    if (ds_get_bits_per_pixel(s->ds) && s->update_x0 < s->update_x1) {
1107
        dpy_update(s->ds, s->update_x0, s->update_y0,
1108
                   s->update_x1 - s->update_x0,
1109
                   s->update_y1 - s->update_y0);
1110
    }
1111
    return len;
1112
}
1113

    
1114
static void kbd_send_chars(void *opaque)
1115
{
1116
    TextConsole *s = opaque;
1117
    int len;
1118
    uint8_t buf[16];
1119

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

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

    
1143
    s = active_console;
1144
    if (!s || (s->console_type == GRAPHIC_CONSOLE))
1145
        return;
1146

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

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

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

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

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

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

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

    
1274
static DisplaySurface* defaultallocator_create_displaysurface(int width, int height)
1275
{
1276
    DisplaySurface *surface = (DisplaySurface*) g_malloc0(sizeof(DisplaySurface));
1277

    
1278
    int linesize = width * 4;
1279
    qemu_alloc_display(surface, width, height, linesize,
1280
                       qemu_default_pixelformat(32), 0);
1281
    return surface;
1282
}
1283

    
1284
static DisplaySurface* defaultallocator_resize_displaysurface(DisplaySurface *surface,
1285
                                          int width, int height)
1286
{
1287
    int linesize = width * 4;
1288
    qemu_alloc_display(surface, width, height, linesize,
1289
                       qemu_default_pixelformat(32), 0);
1290
    return surface;
1291
}
1292

    
1293
void qemu_alloc_display(DisplaySurface *surface, int width, int height,
1294
                        int linesize, PixelFormat pf, int newflags)
1295
{
1296
    void *data;
1297
    surface->width = width;
1298
    surface->height = height;
1299
    surface->linesize = linesize;
1300
    surface->pf = pf;
1301
    if (surface->flags & QEMU_ALLOCATED_FLAG) {
1302
        data = g_realloc(surface->data,
1303
                            surface->linesize * surface->height);
1304
    } else {
1305
        data = g_malloc(surface->linesize * surface->height);
1306
    }
1307
    surface->data = (uint8_t *)data;
1308
    surface->flags = newflags | QEMU_ALLOCATED_FLAG;
1309
#ifdef HOST_WORDS_BIGENDIAN
1310
    surface->flags |= QEMU_BIG_ENDIAN_FLAG;
1311
#endif
1312
}
1313

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

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

    
1328
    return surface;
1329
}
1330

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

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

    
1346
static void dumb_display_init(void)
1347
{
1348
    DisplayState *ds = g_malloc0(sizeof(DisplayState));
1349
    int width = 640;
1350
    int height = 480;
1351

    
1352
    ds->allocator = &default_allocator;
1353
    if (is_fixedsize_console()) {
1354
        width = active_console->g_width;
1355
        height = active_console->g_height;
1356
    }
1357
    ds->surface = qemu_create_displaysurface(ds, width, height);
1358
    register_displaystate(ds);
1359
}
1360

    
1361
/***********************************************************/
1362
/* register display */
1363

    
1364
void register_displaystate(DisplayState *ds)
1365
{
1366
    DisplayState **s;
1367
    s = &display_state;
1368
    while (*s != NULL)
1369
        s = &(*s)->next;
1370
    ds->next = NULL;
1371
    *s = ds;
1372
}
1373

    
1374
DisplayState *get_displaystate(void)
1375
{
1376
    if (!display_state) {
1377
        dumb_display_init ();
1378
    }
1379
    return display_state;
1380
}
1381

    
1382
DisplayAllocator *register_displayallocator(DisplayState *ds, DisplayAllocator *da)
1383
{
1384
    if(ds->allocator ==  &default_allocator) {
1385
        DisplaySurface *surf;
1386
        surf = da->create_displaysurface(ds_get_width(ds), ds_get_height(ds));
1387
        defaultallocator_free_displaysurface(ds->surface);
1388
        ds->surface = surf;
1389
        ds->allocator = da;
1390
    }
1391
    return ds->allocator;
1392
}
1393

    
1394
DisplayState *graphic_console_init(vga_hw_update_ptr update,
1395
                                   vga_hw_invalidate_ptr invalidate,
1396
                                   vga_hw_screen_dump_ptr screen_dump,
1397
                                   vga_hw_text_update_ptr text_update,
1398
                                   void *opaque)
1399
{
1400
    TextConsole *s;
1401
    DisplayState *ds;
1402

    
1403
    ds = (DisplayState *) g_malloc0(sizeof(DisplayState));
1404
    ds->allocator = &default_allocator; 
1405
    ds->surface = qemu_create_displaysurface(ds, 640, 480);
1406

    
1407
    s = new_console(ds, GRAPHIC_CONSOLE);
1408
    if (s == NULL) {
1409
        qemu_free_displaysurface(ds);
1410
        g_free(ds);
1411
        return NULL;
1412
    }
1413
    s->hw_update = update;
1414
    s->hw_invalidate = invalidate;
1415
    s->hw_screen_dump = screen_dump;
1416
    s->hw_text_update = text_update;
1417
    s->hw = opaque;
1418

    
1419
    register_displaystate(ds);
1420
    return ds;
1421
}
1422

    
1423
int is_graphic_console(void)
1424
{
1425
    return active_console && active_console->console_type == GRAPHIC_CONSOLE;
1426
}
1427

    
1428
int is_fixedsize_console(void)
1429
{
1430
    return active_console && active_console->console_type != TEXT_CONSOLE;
1431
}
1432

    
1433
void console_color_init(DisplayState *ds)
1434
{
1435
    int i, j;
1436
    for (j = 0; j < 2; j++) {
1437
        for (i = 0; i < 8; i++) {
1438
            color_table[j][i] = col_expand(ds,
1439
                   vga_get_color(ds, color_table_rgb[j][i]));
1440
        }
1441
    }
1442
}
1443

    
1444
static int n_text_consoles;
1445
static CharDriverState *text_consoles[128];
1446

    
1447
static void text_console_set_echo(CharDriverState *chr, bool echo)
1448
{
1449
    TextConsole *s = chr->opaque;
1450

    
1451
    s->echo = echo;
1452
}
1453

    
1454
static void text_console_do_init(CharDriverState *chr, DisplayState *ds)
1455
{
1456
    TextConsole *s;
1457
    static int color_inited;
1458

    
1459
    s = chr->opaque;
1460

    
1461
    chr->chr_write = console_puts;
1462

    
1463
    s->out_fifo.buf = s->out_fifo_buf;
1464
    s->out_fifo.buf_size = sizeof(s->out_fifo_buf);
1465
    s->kbd_timer = qemu_new_timer_ms(rt_clock, kbd_send_chars, s);
1466
    s->ds = ds;
1467

    
1468
    if (!color_inited) {
1469
        color_inited = 1;
1470
        console_color_init(s->ds);
1471
    }
1472
    s->y_displayed = 0;
1473
    s->y_base = 0;
1474
    s->total_height = DEFAULT_BACKSCROLL;
1475
    s->x = 0;
1476
    s->y = 0;
1477
    if (s->console_type == TEXT_CONSOLE) {
1478
        s->g_width = ds_get_width(s->ds);
1479
        s->g_height = ds_get_height(s->ds);
1480
    }
1481

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

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

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

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

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

    
1513
int text_console_init(QemuOpts *opts, CharDriverState **_chr)
1514
{
1515
    CharDriverState *chr;
1516
    TextConsole *s;
1517
    unsigned width;
1518
    unsigned height;
1519

    
1520
    chr = g_malloc0(sizeof(CharDriverState));
1521

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

    
1529
    width = qemu_opt_get_number(opts, "width", 0);
1530
    if (width == 0)
1531
        width = qemu_opt_get_number(opts, "cols", 0) * FONT_WIDTH;
1532

    
1533
    height = qemu_opt_get_number(opts, "height", 0);
1534
    if (height == 0)
1535
        height = qemu_opt_get_number(opts, "rows", 0) * FONT_HEIGHT;
1536

    
1537
    if (width == 0 || height == 0) {
1538
        s = new_console(NULL, TEXT_CONSOLE);
1539
    } else {
1540
        s = new_console(NULL, TEXT_CONSOLE_FIXED_SIZE);
1541
    }
1542

    
1543
    if (!s) {
1544
        g_free(chr);
1545
        return -EBUSY;
1546
    }
1547

    
1548
    s->chr = chr;
1549
    s->g_width = width;
1550
    s->g_height = height;
1551
    chr->opaque = s;
1552
    chr->chr_set_echo = text_console_set_echo;
1553

    
1554
    *_chr = chr;
1555
    return 0;
1556
}
1557

    
1558
void text_consoles_set_display(DisplayState *ds)
1559
{
1560
    int i;
1561

    
1562
    for (i = 0; i < n_text_consoles; i++) {
1563
        text_console_do_init(text_consoles[i], ds);
1564
    }
1565

    
1566
    n_text_consoles = 0;
1567
}
1568

    
1569
void qemu_console_resize(DisplayState *ds, int width, int height)
1570
{
1571
    TextConsole *s = get_graphic_console(ds);
1572
    if (!s) return;
1573

    
1574
    s->g_width = width;
1575
    s->g_height = height;
1576
    if (is_graphic_console()) {
1577
        ds->surface = qemu_resize_displaysurface(ds, width, height);
1578
        dpy_resize(ds);
1579
    }
1580
}
1581

    
1582
void qemu_console_copy(DisplayState *ds, int src_x, int src_y,
1583
                       int dst_x, int dst_y, int w, int h)
1584
{
1585
    if (is_graphic_console()) {
1586
        dpy_copy(ds, src_x, src_y, dst_x, dst_y, w, h);
1587
    }
1588
}
1589

    
1590
PixelFormat qemu_different_endianness_pixelformat(int bpp)
1591
{
1592
    PixelFormat pf;
1593

    
1594
    memset(&pf, 0x00, sizeof(PixelFormat));
1595

    
1596
    pf.bits_per_pixel = bpp;
1597
    pf.bytes_per_pixel = bpp / 8;
1598
    pf.depth = bpp == 32 ? 24 : bpp;
1599

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

    
1639
PixelFormat qemu_default_pixelformat(int bpp)
1640
{
1641
    PixelFormat pf;
1642

    
1643
    memset(&pf, 0x00, sizeof(PixelFormat));
1644

    
1645
    pf.bits_per_pixel = bpp;
1646
    pf.bytes_per_pixel = bpp / 8;
1647
    pf.depth = bpp == 32 ? 24 : bpp;
1648

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