Statistics
| Branch: | Revision:

root / console.c @ ccfcaba6

History | View | Annotate | Download (46.7 kB)

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

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

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

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

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

    
50
#define MAX_ESC_PARAMS 3
51

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

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

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

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

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

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

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

    
115
/* ??? This is mis-named.
116
   It is used for both text and graphical consoles.  */
117
struct TextConsole {
118
    console_type_t console_type;
119
    DisplayState *ds;
120
    /* Graphic console state.  */
121
    vga_hw_update_ptr hw_update;
122
    vga_hw_invalidate_ptr hw_invalidate;
123
    vga_hw_screen_dump_ptr hw_screen_dump;
124
    vga_hw_text_update_ptr hw_text_update;
125
    void *hw;
126

    
127
    int g_width, g_height;
128
    int width;
129
    int height;
130
    int total_height;
131
    int backscroll_height;
132
    int x, y;
133
    int x_saved, y_saved;
134
    int y_displayed;
135
    int y_base;
136
    TextAttributes t_attrib_default; /* default text attributes */
137
    TextAttributes t_attrib; /* currently active text attributes */
138
    TextCell *cells;
139
    int text_x[2], text_y[2], cursor_invalidate;
140
    int echo;
141

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

    
297
/***********************************************************/
298
/* basic char display */
299

    
300
#define FONT_HEIGHT 16
301
#define FONT_WIDTH 8
302

    
303
#include "vgafont.h"
304

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

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

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

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

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

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

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

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

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

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

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

    
441
#ifdef DEBUG_CONSOLE
442
    printf("x: %2i y: %2i", x, y);
443
    console_print_text_attributes(t_attrib, ch);
444
#endif
445

    
446
    if (t_attrib->invers) {
447
        bgcol = color_table[t_attrib->bold][t_attrib->fgcol];
448
        fgcol = color_table[t_attrib->bold][t_attrib->bgcol];
449
    } else {
450
        fgcol = color_table[t_attrib->bold][t_attrib->fgcol];
451
        bgcol = color_table[t_attrib->bold][t_attrib->bgcol];
452
    }
453

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

    
508
static void text_console_resize(TextConsole *s)
509
{
510
    TextCell *cells, *c, *c1;
511
    int w1, x, y, last_width;
512

    
513
    last_width = s->width;
514
    s->width = s->g_width / FONT_WIDTH;
515
    s->height = s->g_height / FONT_HEIGHT;
516

    
517
    w1 = last_width;
518
    if (s->width < w1)
519
        w1 = s->width;
520

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

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

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

    
560
static void update_xy(TextConsole *s, int x, int y)
561
{
562
    TextCell *c;
563
    int y1, y2;
564

    
565
    if (s == active_console) {
566
        if (!ds_get_bits_per_pixel(s->ds)) {
567
            text_update_xy(s, x, y);
568
            return;
569
        }
570

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

    
584
static void console_show_cursor(TextConsole *s, int show)
585
{
586
    TextCell *c;
587
    int y, y1;
588

    
589
    if (s == active_console) {
590
        int x = s->x;
591

    
592
        if (!ds_get_bits_per_pixel(s->ds)) {
593
            s->cursor_invalidate = 1;
594
            return;
595
        }
596

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

    
618
static void console_refresh(TextConsole *s)
619
{
620
    TextCell *c;
621
    int x, y, y1;
622

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

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

    
651
static void console_scroll(int ydelta)
652
{
653
    TextConsole *s;
654
    int i, y1;
655

    
656
    s = active_console;
657
    if (!s || (s->console_type == GRAPHIC_CONSOLE))
658
        return;
659

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

    
685
static void console_put_lf(TextConsole *s)
686
{
687
    TextCell *c;
688
    int x, y1;
689

    
690
    s->y++;
691
    if (s->y >= s->height) {
692
        s->y = s->height - 1;
693

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

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

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

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

    
829
static void console_clear_xy(TextConsole *s, int x, int y)
830
{
831
    int y1 = (s->y_base + y) % s->total_height;
832
    TextCell *c = &s->cells[y1 * s->width + x];
833
    c->ch = ' ';
834
    c->t_attrib = s->t_attrib_default;
835
    update_xy(s, x, y);
836
}
837

    
838
static void console_putchar(TextConsole *s, int ch)
839
{
840
    TextCell *c;
841
    int y1, i;
842
    int x, y;
843

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

    
1060
void console_select(unsigned int index)
1061
{
1062
    TextConsole *s;
1063

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

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

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

    
1107
static void kbd_send_chars(void *opaque)
1108
{
1109
    TextConsole *s = opaque;
1110
    int len;
1111
    uint8_t buf[16];
1112

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

    
1129
/* called when an ascii key is pressed */
1130
void kbd_put_keysym(int keysym)
1131
{
1132
    TextConsole *s;
1133
    uint8_t buf[16], *q;
1134
    int c;
1135

    
1136
    s = active_console;
1137
    if (!s || (s->console_type == GRAPHIC_CONSOLE))
1138
        return;
1139

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

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

    
1196
static void text_console_update(void *opaque, console_ch_t *chardata)
1197
{
1198
    TextConsole *s = (TextConsole *) opaque;
1199
    int i, j, src;
1200

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

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

    
1235
static TextConsole *new_console(DisplayState *ds, console_type_t console_type)
1236
{
1237
    TextConsole *s;
1238
    int i;
1239

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

    
1264
static DisplaySurface* defaultallocator_create_displaysurface(int width, int height)
1265
{
1266
    DisplaySurface *surface = (DisplaySurface*) g_malloc0(sizeof(DisplaySurface));
1267

    
1268
    int linesize = width * 4;
1269
    qemu_alloc_display(surface, width, height, linesize,
1270
                       qemu_default_pixelformat(32), 0);
1271
    return surface;
1272
}
1273

    
1274
static DisplaySurface* defaultallocator_resize_displaysurface(DisplaySurface *surface,
1275
                                          int width, int height)
1276
{
1277
    int linesize = width * 4;
1278
    qemu_alloc_display(surface, width, height, linesize,
1279
                       qemu_default_pixelformat(32), 0);
1280
    return surface;
1281
}
1282

    
1283
void qemu_alloc_display(DisplaySurface *surface, int width, int height,
1284
                        int linesize, PixelFormat pf, int newflags)
1285
{
1286
    void *data;
1287
    surface->width = width;
1288
    surface->height = height;
1289
    surface->linesize = linesize;
1290
    surface->pf = pf;
1291
    if (surface->flags & QEMU_ALLOCATED_FLAG) {
1292
        data = g_realloc(surface->data,
1293
                            surface->linesize * surface->height);
1294
    } else {
1295
        data = g_malloc(surface->linesize * surface->height);
1296
    }
1297
    surface->data = (uint8_t *)data;
1298
    surface->flags = newflags | QEMU_ALLOCATED_FLAG;
1299
#ifdef HOST_WORDS_BIGENDIAN
1300
    surface->flags |= QEMU_BIG_ENDIAN_FLAG;
1301
#endif
1302
}
1303

    
1304
DisplaySurface* qemu_create_displaysurface_from(int width, int height, int bpp,
1305
                                              int linesize, uint8_t *data)
1306
{
1307
    DisplaySurface *surface = (DisplaySurface*) g_malloc0(sizeof(DisplaySurface));
1308

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

    
1318
    return surface;
1319
}
1320

    
1321
static void defaultallocator_free_displaysurface(DisplaySurface *surface)
1322
{
1323
    if (surface == NULL)
1324
        return;
1325
    if (surface->flags & QEMU_ALLOCATED_FLAG)
1326
        g_free(surface->data);
1327
    g_free(surface);
1328
}
1329

    
1330
static struct DisplayAllocator default_allocator = {
1331
    defaultallocator_create_displaysurface,
1332
    defaultallocator_resize_displaysurface,
1333
    defaultallocator_free_displaysurface
1334
};
1335

    
1336
static void dumb_display_init(void)
1337
{
1338
    DisplayState *ds = g_malloc0(sizeof(DisplayState));
1339
    int width = 640;
1340
    int height = 480;
1341

    
1342
    ds->allocator = &default_allocator;
1343
    if (is_fixedsize_console()) {
1344
        width = active_console->g_width;
1345
        height = active_console->g_height;
1346
    }
1347
    ds->surface = qemu_create_displaysurface(ds, width, height);
1348
    register_displaystate(ds);
1349
}
1350

    
1351
/***********************************************************/
1352
/* register display */
1353

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

    
1364
DisplayState *get_displaystate(void)
1365
{
1366
    if (!display_state) {
1367
        dumb_display_init ();
1368
    }
1369
    return display_state;
1370
}
1371

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

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

    
1393
    ds = (DisplayState *) g_malloc0(sizeof(DisplayState));
1394
    ds->allocator = &default_allocator; 
1395
    ds->surface = qemu_create_displaysurface(ds, 640, 480);
1396

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

    
1409
    register_displaystate(ds);
1410
    return ds;
1411
}
1412

    
1413
int is_graphic_console(void)
1414
{
1415
    return active_console && active_console->console_type == GRAPHIC_CONSOLE;
1416
}
1417

    
1418
int is_fixedsize_console(void)
1419
{
1420
    return active_console && active_console->console_type != TEXT_CONSOLE;
1421
}
1422

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

    
1434
static int n_text_consoles;
1435
static CharDriverState *text_consoles[128];
1436

    
1437
static void text_console_set_echo(CharDriverState *chr, bool echo)
1438
{
1439
    TextConsole *s = chr->opaque;
1440

    
1441
    s->echo = echo;
1442
}
1443

    
1444
static void text_console_do_init(CharDriverState *chr, DisplayState *ds)
1445
{
1446
    TextConsole *s;
1447
    static int color_inited;
1448

    
1449
    s = chr->opaque;
1450

    
1451
    chr->chr_write = console_puts;
1452

    
1453
    s->out_fifo.buf = s->out_fifo_buf;
1454
    s->out_fifo.buf_size = sizeof(s->out_fifo_buf);
1455
    s->kbd_timer = qemu_new_timer_ms(rt_clock, kbd_send_chars, s);
1456
    s->ds = ds;
1457

    
1458
    if (!color_inited) {
1459
        color_inited = 1;
1460
        console_color_init(s->ds);
1461
    }
1462
    s->y_displayed = 0;
1463
    s->y_base = 0;
1464
    s->total_height = DEFAULT_BACKSCROLL;
1465
    s->x = 0;
1466
    s->y = 0;
1467
    if (s->console_type == TEXT_CONSOLE) {
1468
        s->g_width = ds_get_width(s->ds);
1469
        s->g_height = ds_get_height(s->ds);
1470
    }
1471

    
1472
    s->hw_invalidate = text_console_invalidate;
1473
    s->hw_text_update = text_console_update;
1474
    s->hw = s;
1475

    
1476
    /* Set text attribute defaults */
1477
    s->t_attrib_default.bold = 0;
1478
    s->t_attrib_default.uline = 0;
1479
    s->t_attrib_default.blink = 0;
1480
    s->t_attrib_default.invers = 0;
1481
    s->t_attrib_default.unvisible = 0;
1482
    s->t_attrib_default.fgcol = COLOR_WHITE;
1483
    s->t_attrib_default.bgcol = COLOR_BLACK;
1484
    /* set current text attributes to default */
1485
    s->t_attrib = s->t_attrib_default;
1486
    text_console_resize(s);
1487

    
1488
    if (chr->label) {
1489
        char msg[128];
1490
        int len;
1491

    
1492
        s->t_attrib.bgcol = COLOR_BLUE;
1493
        len = snprintf(msg, sizeof(msg), "%s console\r\n", chr->label);
1494
        console_puts(chr, (uint8_t*)msg, len);
1495
        s->t_attrib = s->t_attrib_default;
1496
    }
1497

    
1498
    qemu_chr_generic_open(chr);
1499
    if (chr->init)
1500
        chr->init(chr);
1501
}
1502

    
1503
int text_console_init(QemuOpts *opts, CharDriverState **_chr)
1504
{
1505
    CharDriverState *chr;
1506
    TextConsole *s;
1507
    unsigned width;
1508
    unsigned height;
1509

    
1510
    chr = g_malloc0(sizeof(CharDriverState));
1511

    
1512
    if (n_text_consoles == 128) {
1513
        fprintf(stderr, "Too many text consoles\n");
1514
        exit(1);
1515
    }
1516
    text_consoles[n_text_consoles] = chr;
1517
    n_text_consoles++;
1518

    
1519
    width = qemu_opt_get_number(opts, "width", 0);
1520
    if (width == 0)
1521
        width = qemu_opt_get_number(opts, "cols", 0) * FONT_WIDTH;
1522

    
1523
    height = qemu_opt_get_number(opts, "height", 0);
1524
    if (height == 0)
1525
        height = qemu_opt_get_number(opts, "rows", 0) * FONT_HEIGHT;
1526

    
1527
    if (width == 0 || height == 0) {
1528
        s = new_console(NULL, TEXT_CONSOLE);
1529
    } else {
1530
        s = new_console(NULL, TEXT_CONSOLE_FIXED_SIZE);
1531
    }
1532

    
1533
    if (!s) {
1534
        free(chr);
1535
        return -EBUSY;
1536
    }
1537

    
1538
    s->chr = chr;
1539
    s->g_width = width;
1540
    s->g_height = height;
1541
    chr->opaque = s;
1542
    chr->chr_set_echo = text_console_set_echo;
1543

    
1544
    *_chr = chr;
1545
    return 0;
1546
}
1547

    
1548
void text_consoles_set_display(DisplayState *ds)
1549
{
1550
    int i;
1551

    
1552
    for (i = 0; i < n_text_consoles; i++) {
1553
        text_console_do_init(text_consoles[i], ds);
1554
    }
1555

    
1556
    n_text_consoles = 0;
1557
}
1558

    
1559
void qemu_console_resize(DisplayState *ds, int width, int height)
1560
{
1561
    TextConsole *s = get_graphic_console(ds);
1562
    if (!s) return;
1563

    
1564
    s->g_width = width;
1565
    s->g_height = height;
1566
    if (is_graphic_console()) {
1567
        ds->surface = qemu_resize_displaysurface(ds, width, height);
1568
        dpy_resize(ds);
1569
    }
1570
}
1571

    
1572
void qemu_console_copy(DisplayState *ds, int src_x, int src_y,
1573
                       int dst_x, int dst_y, int w, int h)
1574
{
1575
    if (is_graphic_console()) {
1576
        dpy_copy(ds, src_x, src_y, dst_x, dst_y, w, h);
1577
    }
1578
}
1579

    
1580
PixelFormat qemu_different_endianness_pixelformat(int bpp)
1581
{
1582
    PixelFormat pf;
1583

    
1584
    memset(&pf, 0x00, sizeof(PixelFormat));
1585

    
1586
    pf.bits_per_pixel = bpp;
1587
    pf.bytes_per_pixel = bpp / 8;
1588
    pf.depth = bpp == 32 ? 24 : bpp;
1589

    
1590
    switch (bpp) {
1591
        case 24:
1592
            pf.rmask = 0x000000FF;
1593
            pf.gmask = 0x0000FF00;
1594
            pf.bmask = 0x00FF0000;
1595
            pf.rmax = 255;
1596
            pf.gmax = 255;
1597
            pf.bmax = 255;
1598
            pf.rshift = 0;
1599
            pf.gshift = 8;
1600
            pf.bshift = 16;
1601
            pf.rbits = 8;
1602
            pf.gbits = 8;
1603
            pf.bbits = 8;
1604
            break;
1605
        case 32:
1606
            pf.rmask = 0x0000FF00;
1607
            pf.gmask = 0x00FF0000;
1608
            pf.bmask = 0xFF000000;
1609
            pf.amask = 0x00000000;
1610
            pf.amax = 255;
1611
            pf.rmax = 255;
1612
            pf.gmax = 255;
1613
            pf.bmax = 255;
1614
            pf.ashift = 0;
1615
            pf.rshift = 8;
1616
            pf.gshift = 16;
1617
            pf.bshift = 24;
1618
            pf.rbits = 8;
1619
            pf.gbits = 8;
1620
            pf.bbits = 8;
1621
            pf.abits = 8;
1622
            break;
1623
        default:
1624
            break;
1625
    }
1626
    return pf;
1627
}
1628

    
1629
PixelFormat qemu_default_pixelformat(int bpp)
1630
{
1631
    PixelFormat pf;
1632

    
1633
    memset(&pf, 0x00, sizeof(PixelFormat));
1634

    
1635
    pf.bits_per_pixel = bpp;
1636
    pf.bytes_per_pixel = bpp / 8;
1637
    pf.depth = bpp == 32 ? 24 : bpp;
1638

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