]> git.proxmox.com Git - qemu.git/blame - ui/console.c
cocoa: stop using DisplayState
[qemu.git] / ui / console.c
CommitLineData
e7f0ad58
FB
1/*
2 * QEMU graphical console
5fafdf24 3 *
e7f0ad58 4 * Copyright (c) 2004 Fabrice Bellard
5fafdf24 5 *
e7f0ad58
FB
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 */
87ecb68b 24#include "qemu-common.h"
28ecbaee 25#include "ui/console.h"
1de7afc9 26#include "qemu/timer.h"
ad39cf6d 27#include "qmp-commands.h"
927d4878 28#include "char/char.h"
e7f0ad58 29
6d6f7c28 30//#define DEBUG_CONSOLE
e7f0ad58
FB
31#define DEFAULT_BACKSCROLL 512
32#define MAX_CONSOLES 12
bf1bed81 33#define CONSOLE_CURSOR_PERIOD 500
e7f0ad58 34
26489844
FB
35#define QEMU_RGBA(r, g, b, a) (((a) << 24) | ((r) << 16) | ((g) << 8) | (b))
36#define QEMU_RGB(r, g, b) QEMU_RGBA(r, g, b, 0xff)
e7f0ad58 37
6d6f7c28
PB
38typedef struct TextAttributes {
39 uint8_t fgcol:4;
40 uint8_t bgcol:4;
41 uint8_t bold:1;
42 uint8_t uline:1;
43 uint8_t blink:1;
44 uint8_t invers:1;
45 uint8_t unvisible:1;
46} TextAttributes;
47
e7f0ad58
FB
48typedef struct TextCell {
49 uint8_t ch;
6d6f7c28 50 TextAttributes t_attrib;
e7f0ad58
FB
51} TextCell;
52
53#define MAX_ESC_PARAMS 3
54
55enum TTYState {
56 TTY_STATE_NORM,
57 TTY_STATE_ESC,
58 TTY_STATE_CSI,
59};
60
e15d7371
FB
61typedef struct QEMUFIFO {
62 uint8_t *buf;
63 int buf_size;
64 int count, wptr, rptr;
65} QEMUFIFO;
66
9596ebb7 67static int qemu_fifo_write(QEMUFIFO *f, const uint8_t *buf, int len1)
e15d7371
FB
68{
69 int l, len;
70
71 l = f->buf_size - f->count;
72 if (len1 > l)
73 len1 = l;
74 len = len1;
75 while (len > 0) {
76 l = f->buf_size - f->wptr;
77 if (l > len)
78 l = len;
79 memcpy(f->buf + f->wptr, buf, l);
80 f->wptr += l;
81 if (f->wptr >= f->buf_size)
82 f->wptr = 0;
83 buf += l;
84 len -= l;
85 }
86 f->count += len1;
87 return len1;
88}
89
9596ebb7 90static int qemu_fifo_read(QEMUFIFO *f, uint8_t *buf, int len1)
e15d7371
FB
91{
92 int l, len;
93
94 if (len1 > f->count)
95 len1 = f->count;
96 len = len1;
97 while (len > 0) {
98 l = f->buf_size - f->rptr;
99 if (l > len)
100 l = len;
101 memcpy(buf, f->buf + f->rptr, l);
102 f->rptr += l;
103 if (f->rptr >= f->buf_size)
104 f->rptr = 0;
105 buf += l;
106 len -= l;
107 }
108 f->count -= len1;
109 return len1;
110}
111
af3a9031
TS
112typedef enum {
113 GRAPHIC_CONSOLE,
c21bbcfa
AZ
114 TEXT_CONSOLE,
115 TEXT_CONSOLE_FIXED_SIZE
c227f099 116} console_type_t;
af3a9031 117
76ffb0b4 118struct QemuConsole {
f81bdefb 119 int index;
c227f099 120 console_type_t console_type;
e7f0ad58 121 DisplayState *ds;
76ffb0b4 122
95219897
PB
123 /* Graphic console state. */
124 vga_hw_update_ptr hw_update;
125 vga_hw_invalidate_ptr hw_invalidate;
126 vga_hw_screen_dump_ptr hw_screen_dump;
4d3b6f6e 127 vga_hw_text_update_ptr hw_text_update;
95219897 128 void *hw;
e7f0ad58 129 int g_width, g_height;
76ffb0b4
GH
130
131 /* Text console state */
e7f0ad58
FB
132 int width;
133 int height;
134 int total_height;
135 int backscroll_height;
e7f0ad58 136 int x, y;
adb47967 137 int x_saved, y_saved;
e7f0ad58
FB
138 int y_displayed;
139 int y_base;
6d6f7c28
PB
140 TextAttributes t_attrib_default; /* default text attributes */
141 TextAttributes t_attrib; /* currently active text attributes */
e7f0ad58 142 TextCell *cells;
4d3b6f6e 143 int text_x[2], text_y[2], cursor_invalidate;
4104833f 144 int echo;
bf1bed81
JK
145 bool cursor_visible_phase;
146 QEMUTimer *cursor_timer;
e7f0ad58 147
14778c20
PB
148 int update_x0;
149 int update_y0;
150 int update_x1;
151 int update_y1;
152
e7f0ad58
FB
153 enum TTYState state;
154 int esc_params[MAX_ESC_PARAMS];
155 int nb_esc_params;
156
e5b0bc44 157 CharDriverState *chr;
e15d7371
FB
158 /* fifo for key pressed */
159 QEMUFIFO out_fifo;
160 uint8_t out_fifo_buf[16];
161 QEMUTimer *kbd_timer;
e7f0ad58
FB
162};
163
98b50080 164static DisplayState *display_state;
76ffb0b4
GH
165static QemuConsole *active_console;
166static QemuConsole *consoles[MAX_CONSOLES];
e7f0ad58
FB
167static int nb_consoles = 0;
168
95219897
PB
169void vga_hw_update(void)
170{
adb47967 171 if (active_console && active_console->hw_update)
95219897
PB
172 active_console->hw_update(active_console->hw);
173}
174
175void vga_hw_invalidate(void)
176{
26572b8a 177 if (active_console && active_console->hw_invalidate)
95219897
PB
178 active_console->hw_invalidate(active_console->hw);
179}
180
ad39cf6d 181void qmp_screendump(const char *filename, Error **errp)
95219897 182{
76ffb0b4 183 QemuConsole *previous_active_console;
45efb161 184 bool cswitch;
8571c055
AZ
185
186 previous_active_console = active_console;
45efb161 187 cswitch = previous_active_console && previous_active_console->index != 0;
f81bdefb 188
8571c055 189 /* There is currently no way of specifying which screen we want to dump,
7b455225 190 so always dump the first one. */
45efb161
GH
191 if (cswitch) {
192 console_select(0);
193 }
f81bdefb 194 if (consoles[0] && consoles[0]->hw_screen_dump) {
ad39cf6d 195 consoles[0]->hw_screen_dump(consoles[0]->hw, filename, cswitch, errp);
16735102 196 } else {
312fd5f2 197 error_setg(errp, "device doesn't support screendump");
f81bdefb
JK
198 }
199
45efb161 200 if (cswitch) {
33bcd98c
AG
201 console_select(previous_active_console->index);
202 }
95219897
PB
203}
204
c227f099 205void vga_hw_text_update(console_ch_t *chardata)
4d3b6f6e
AZ
206{
207 if (active_console && active_console->hw_text_update)
208 active_console->hw_text_update(active_console->hw, chardata);
209}
210
e7f0ad58
FB
211/* convert a RGBA color to a color index usable in graphic primitives */
212static unsigned int vga_get_color(DisplayState *ds, unsigned int rgba)
213{
214 unsigned int r, g, b, color;
215
0e1f5a0c 216 switch(ds_get_bits_per_pixel(ds)) {
e7f0ad58
FB
217#if 0
218 case 8:
219 r = (rgba >> 16) & 0xff;
220 g = (rgba >> 8) & 0xff;
221 b = (rgba) & 0xff;
5fafdf24
TS
222 color = (rgb_to_index[r] * 6 * 6) +
223 (rgb_to_index[g] * 6) +
e7f0ad58
FB
224 (rgb_to_index[b]);
225 break;
226#endif
227 case 15:
228 r = (rgba >> 16) & 0xff;
229 g = (rgba >> 8) & 0xff;
230 b = (rgba) & 0xff;
231 color = ((r >> 3) << 10) | ((g >> 3) << 5) | (b >> 3);
232 break;
233 case 16:
234 r = (rgba >> 16) & 0xff;
235 g = (rgba >> 8) & 0xff;
236 b = (rgba) & 0xff;
237 color = ((r >> 3) << 11) | ((g >> 2) << 5) | (b >> 3);
238 break;
239 case 32:
240 default:
241 color = rgba;
242 break;
243 }
244 return color;
245}
246
5fafdf24 247static void vga_fill_rect (DisplayState *ds,
e7f0ad58
FB
248 int posx, int posy, int width, int height, uint32_t color)
249{
250 uint8_t *d, *d1;
251 int x, y, bpp;
3b46e624 252
0e1f5a0c
AL
253 bpp = (ds_get_bits_per_pixel(ds) + 7) >> 3;
254 d1 = ds_get_data(ds) +
255 ds_get_linesize(ds) * posy + bpp * posx;
e7f0ad58
FB
256 for (y = 0; y < height; y++) {
257 d = d1;
258 switch(bpp) {
259 case 1:
260 for (x = 0; x < width; x++) {
261 *((uint8_t *)d) = color;
262 d++;
263 }
264 break;
265 case 2:
266 for (x = 0; x < width; x++) {
267 *((uint16_t *)d) = color;
268 d += 2;
269 }
270 break;
271 case 4:
272 for (x = 0; x < width; x++) {
273 *((uint32_t *)d) = color;
274 d += 4;
275 }
276 break;
277 }
0e1f5a0c 278 d1 += ds_get_linesize(ds);
e7f0ad58
FB
279 }
280}
281
282/* copy from (xs, ys) to (xd, yd) a rectangle of size (w, h) */
283static void vga_bitblt(DisplayState *ds, int xs, int ys, int xd, int yd, int w, int h)
284{
285 const uint8_t *s;
286 uint8_t *d;
287 int wb, y, bpp;
288
0e1f5a0c 289 bpp = (ds_get_bits_per_pixel(ds) + 7) >> 3;
e7f0ad58
FB
290 wb = w * bpp;
291 if (yd <= ys) {
0e1f5a0c
AL
292 s = ds_get_data(ds) +
293 ds_get_linesize(ds) * ys + bpp * xs;
294 d = ds_get_data(ds) +
295 ds_get_linesize(ds) * yd + bpp * xd;
e7f0ad58
FB
296 for (y = 0; y < h; y++) {
297 memmove(d, s, wb);
0e1f5a0c
AL
298 d += ds_get_linesize(ds);
299 s += ds_get_linesize(ds);
e7f0ad58
FB
300 }
301 } else {
0e1f5a0c
AL
302 s = ds_get_data(ds) +
303 ds_get_linesize(ds) * (ys + h - 1) + bpp * xs;
304 d = ds_get_data(ds) +
305 ds_get_linesize(ds) * (yd + h - 1) + bpp * xd;
e7f0ad58
FB
306 for (y = 0; y < h; y++) {
307 memmove(d, s, wb);
0e1f5a0c
AL
308 d -= ds_get_linesize(ds);
309 s -= ds_get_linesize(ds);
e7f0ad58
FB
310 }
311 }
312}
313
314/***********************************************************/
315/* basic char display */
316
317#define FONT_HEIGHT 16
318#define FONT_WIDTH 8
319
320#include "vgafont.h"
321
322#define cbswap_32(__x) \
323((uint32_t)( \
324 (((uint32_t)(__x) & (uint32_t)0x000000ffUL) << 24) | \
325 (((uint32_t)(__x) & (uint32_t)0x0000ff00UL) << 8) | \
326 (((uint32_t)(__x) & (uint32_t)0x00ff0000UL) >> 8) | \
327 (((uint32_t)(__x) & (uint32_t)0xff000000UL) >> 24) ))
328
e2542fe2 329#ifdef HOST_WORDS_BIGENDIAN
e7f0ad58
FB
330#define PAT(x) x
331#else
332#define PAT(x) cbswap_32(x)
333#endif
334
335static const uint32_t dmask16[16] = {
336 PAT(0x00000000),
337 PAT(0x000000ff),
338 PAT(0x0000ff00),
339 PAT(0x0000ffff),
340 PAT(0x00ff0000),
341 PAT(0x00ff00ff),
342 PAT(0x00ffff00),
343 PAT(0x00ffffff),
344 PAT(0xff000000),
345 PAT(0xff0000ff),
346 PAT(0xff00ff00),
347 PAT(0xff00ffff),
348 PAT(0xffff0000),
349 PAT(0xffff00ff),
350 PAT(0xffffff00),
351 PAT(0xffffffff),
352};
353
354static const uint32_t dmask4[4] = {
355 PAT(0x00000000),
356 PAT(0x0000ffff),
357 PAT(0xffff0000),
358 PAT(0xffffffff),
359};
360
6d6f7c28
PB
361static uint32_t color_table[2][8];
362
df00bed0 363#ifndef CONFIG_CURSES
6d6f7c28
PB
364enum color_names {
365 COLOR_BLACK = 0,
366 COLOR_RED = 1,
367 COLOR_GREEN = 2,
368 COLOR_YELLOW = 3,
369 COLOR_BLUE = 4,
370 COLOR_MAGENTA = 5,
371 COLOR_CYAN = 6,
372 COLOR_WHITE = 7
373};
df00bed0 374#endif
6d6f7c28
PB
375
376static const uint32_t color_table_rgb[2][8] = {
377 { /* dark */
26489844
FB
378 QEMU_RGB(0x00, 0x00, 0x00), /* black */
379 QEMU_RGB(0xaa, 0x00, 0x00), /* red */
380 QEMU_RGB(0x00, 0xaa, 0x00), /* green */
381 QEMU_RGB(0xaa, 0xaa, 0x00), /* yellow */
382 QEMU_RGB(0x00, 0x00, 0xaa), /* blue */
383 QEMU_RGB(0xaa, 0x00, 0xaa), /* magenta */
384 QEMU_RGB(0x00, 0xaa, 0xaa), /* cyan */
385 QEMU_RGB(0xaa, 0xaa, 0xaa), /* white */
6d6f7c28
PB
386 },
387 { /* bright */
26489844
FB
388 QEMU_RGB(0x00, 0x00, 0x00), /* black */
389 QEMU_RGB(0xff, 0x00, 0x00), /* red */
390 QEMU_RGB(0x00, 0xff, 0x00), /* green */
391 QEMU_RGB(0xff, 0xff, 0x00), /* yellow */
392 QEMU_RGB(0x00, 0x00, 0xff), /* blue */
393 QEMU_RGB(0xff, 0x00, 0xff), /* magenta */
394 QEMU_RGB(0x00, 0xff, 0xff), /* cyan */
395 QEMU_RGB(0xff, 0xff, 0xff), /* white */
6d6f7c28 396 }
e7f0ad58
FB
397};
398
399static inline unsigned int col_expand(DisplayState *ds, unsigned int col)
400{
0e1f5a0c 401 switch(ds_get_bits_per_pixel(ds)) {
e7f0ad58
FB
402 case 8:
403 col |= col << 8;
404 col |= col << 16;
405 break;
406 case 15:
407 case 16:
408 col |= col << 16;
409 break;
410 default:
411 break;
412 }
413
414 return col;
415}
6d6f7c28
PB
416#ifdef DEBUG_CONSOLE
417static void console_print_text_attributes(TextAttributes *t_attrib, char ch)
418{
419 if (t_attrib->bold) {
420 printf("b");
421 } else {
422 printf(" ");
423 }
424 if (t_attrib->uline) {
425 printf("u");
426 } else {
427 printf(" ");
428 }
429 if (t_attrib->blink) {
430 printf("l");
431 } else {
432 printf(" ");
433 }
434 if (t_attrib->invers) {
435 printf("i");
436 } else {
437 printf(" ");
438 }
439 if (t_attrib->unvisible) {
440 printf("n");
441 } else {
442 printf(" ");
443 }
444
445 printf(" fg: %d bg: %d ch:'%2X' '%c'\n", t_attrib->fgcol, t_attrib->bgcol, ch, ch);
446}
447#endif
e7f0ad58 448
5fafdf24 449static void vga_putcharxy(DisplayState *ds, int x, int y, int ch,
6d6f7c28 450 TextAttributes *t_attrib)
e7f0ad58
FB
451{
452 uint8_t *d;
453 const uint8_t *font_ptr;
454 unsigned int font_data, linesize, xorcol, bpp;
455 int i;
6d6f7c28
PB
456 unsigned int fgcol, bgcol;
457
458#ifdef DEBUG_CONSOLE
459 printf("x: %2i y: %2i", x, y);
460 console_print_text_attributes(t_attrib, ch);
461#endif
462
463 if (t_attrib->invers) {
464 bgcol = color_table[t_attrib->bold][t_attrib->fgcol];
465 fgcol = color_table[t_attrib->bold][t_attrib->bgcol];
466 } else {
467 fgcol = color_table[t_attrib->bold][t_attrib->fgcol];
468 bgcol = color_table[t_attrib->bold][t_attrib->bgcol];
469 }
e7f0ad58 470
0e1f5a0c
AL
471 bpp = (ds_get_bits_per_pixel(ds) + 7) >> 3;
472 d = ds_get_data(ds) +
473 ds_get_linesize(ds) * y * FONT_HEIGHT + bpp * x * FONT_WIDTH;
474 linesize = ds_get_linesize(ds);
e7f0ad58
FB
475 font_ptr = vgafont16 + FONT_HEIGHT * ch;
476 xorcol = bgcol ^ fgcol;
0e1f5a0c 477 switch(ds_get_bits_per_pixel(ds)) {
e7f0ad58
FB
478 case 8:
479 for(i = 0; i < FONT_HEIGHT; i++) {
480 font_data = *font_ptr++;
6d6f7c28
PB
481 if (t_attrib->uline
482 && ((i == FONT_HEIGHT - 2) || (i == FONT_HEIGHT - 3))) {
439229c7 483 font_data = 0xFF;
6d6f7c28 484 }
e7f0ad58
FB
485 ((uint32_t *)d)[0] = (dmask16[(font_data >> 4)] & xorcol) ^ bgcol;
486 ((uint32_t *)d)[1] = (dmask16[(font_data >> 0) & 0xf] & xorcol) ^ bgcol;
487 d += linesize;
488 }
489 break;
490 case 16:
491 case 15:
492 for(i = 0; i < FONT_HEIGHT; i++) {
493 font_data = *font_ptr++;
6d6f7c28
PB
494 if (t_attrib->uline
495 && ((i == FONT_HEIGHT - 2) || (i == FONT_HEIGHT - 3))) {
439229c7 496 font_data = 0xFF;
6d6f7c28 497 }
e7f0ad58
FB
498 ((uint32_t *)d)[0] = (dmask4[(font_data >> 6)] & xorcol) ^ bgcol;
499 ((uint32_t *)d)[1] = (dmask4[(font_data >> 4) & 3] & xorcol) ^ bgcol;
500 ((uint32_t *)d)[2] = (dmask4[(font_data >> 2) & 3] & xorcol) ^ bgcol;
501 ((uint32_t *)d)[3] = (dmask4[(font_data >> 0) & 3] & xorcol) ^ bgcol;
502 d += linesize;
503 }
504 break;
505 case 32:
506 for(i = 0; i < FONT_HEIGHT; i++) {
507 font_data = *font_ptr++;
6d6f7c28 508 if (t_attrib->uline && ((i == FONT_HEIGHT - 2) || (i == FONT_HEIGHT - 3))) {
439229c7 509 font_data = 0xFF;
6d6f7c28 510 }
e7f0ad58
FB
511 ((uint32_t *)d)[0] = (-((font_data >> 7)) & xorcol) ^ bgcol;
512 ((uint32_t *)d)[1] = (-((font_data >> 6) & 1) & xorcol) ^ bgcol;
513 ((uint32_t *)d)[2] = (-((font_data >> 5) & 1) & xorcol) ^ bgcol;
514 ((uint32_t *)d)[3] = (-((font_data >> 4) & 1) & xorcol) ^ bgcol;
515 ((uint32_t *)d)[4] = (-((font_data >> 3) & 1) & xorcol) ^ bgcol;
516 ((uint32_t *)d)[5] = (-((font_data >> 2) & 1) & xorcol) ^ bgcol;
517 ((uint32_t *)d)[6] = (-((font_data >> 1) & 1) & xorcol) ^ bgcol;
518 ((uint32_t *)d)[7] = (-((font_data >> 0) & 1) & xorcol) ^ bgcol;
519 d += linesize;
520 }
521 break;
522 }
523}
524
76ffb0b4 525static void text_console_resize(QemuConsole *s)
e7f0ad58
FB
526{
527 TextCell *cells, *c, *c1;
528 int w1, x, y, last_width;
529
530 last_width = s->width;
531 s->width = s->g_width / FONT_WIDTH;
532 s->height = s->g_height / FONT_HEIGHT;
533
534 w1 = last_width;
535 if (s->width < w1)
536 w1 = s->width;
537
7267c094 538 cells = g_malloc(s->width * s->total_height * sizeof(TextCell));
e7f0ad58
FB
539 for(y = 0; y < s->total_height; y++) {
540 c = &cells[y * s->width];
541 if (w1 > 0) {
542 c1 = &s->cells[y * last_width];
543 for(x = 0; x < w1; x++) {
544 *c++ = *c1++;
545 }
546 }
547 for(x = w1; x < s->width; x++) {
548 c->ch = ' ';
6d6f7c28 549 c->t_attrib = s->t_attrib_default;
e7f0ad58
FB
550 c++;
551 }
552 }
7267c094 553 g_free(s->cells);
e7f0ad58
FB
554 s->cells = cells;
555}
556
76ffb0b4 557static inline void text_update_xy(QemuConsole *s, int x, int y)
4d3b6f6e
AZ
558{
559 s->text_x[0] = MIN(s->text_x[0], x);
560 s->text_x[1] = MAX(s->text_x[1], x);
561 s->text_y[0] = MIN(s->text_y[0], y);
562 s->text_y[1] = MAX(s->text_y[1], y);
563}
564
76ffb0b4 565static void invalidate_xy(QemuConsole *s, int x, int y)
14778c20
PB
566{
567 if (s->update_x0 > x * FONT_WIDTH)
568 s->update_x0 = x * FONT_WIDTH;
569 if (s->update_y0 > y * FONT_HEIGHT)
570 s->update_y0 = y * FONT_HEIGHT;
571 if (s->update_x1 < (x + 1) * FONT_WIDTH)
572 s->update_x1 = (x + 1) * FONT_WIDTH;
573 if (s->update_y1 < (y + 1) * FONT_HEIGHT)
574 s->update_y1 = (y + 1) * FONT_HEIGHT;
575}
576
76ffb0b4 577static void update_xy(QemuConsole *s, int x, int y)
e7f0ad58
FB
578{
579 TextCell *c;
580 int y1, y2;
581
582 if (s == active_console) {
0e1f5a0c 583 if (!ds_get_bits_per_pixel(s->ds)) {
4d3b6f6e
AZ
584 text_update_xy(s, x, y);
585 return;
586 }
587
e7f0ad58
FB
588 y1 = (s->y_base + y) % s->total_height;
589 y2 = y1 - s->y_displayed;
590 if (y2 < 0)
591 y2 += s->total_height;
592 if (y2 < s->height) {
593 c = &s->cells[y1 * s->width + x];
5fafdf24 594 vga_putcharxy(s->ds, x, y2, c->ch,
6d6f7c28 595 &(c->t_attrib));
14778c20 596 invalidate_xy(s, x, y2);
e7f0ad58
FB
597 }
598 }
599}
600
76ffb0b4 601static void console_show_cursor(QemuConsole *s, int show)
e7f0ad58
FB
602{
603 TextCell *c;
604 int y, y1;
605
606 if (s == active_console) {
ed8276ac 607 int x = s->x;
4d3b6f6e 608
0e1f5a0c 609 if (!ds_get_bits_per_pixel(s->ds)) {
4d3b6f6e
AZ
610 s->cursor_invalidate = 1;
611 return;
612 }
613
ed8276ac
TS
614 if (x >= s->width) {
615 x = s->width - 1;
616 }
e7f0ad58
FB
617 y1 = (s->y_base + s->y) % s->total_height;
618 y = y1 - s->y_displayed;
619 if (y < 0)
620 y += s->total_height;
621 if (y < s->height) {
ed8276ac 622 c = &s->cells[y1 * s->width + x];
bf1bed81 623 if (show && s->cursor_visible_phase) {
6d6f7c28
PB
624 TextAttributes t_attrib = s->t_attrib_default;
625 t_attrib.invers = !(t_attrib.invers); /* invert fg and bg */
ed8276ac 626 vga_putcharxy(s->ds, x, y, c->ch, &t_attrib);
e7f0ad58 627 } else {
ed8276ac 628 vga_putcharxy(s->ds, x, y, c->ch, &(c->t_attrib));
e7f0ad58 629 }
14778c20 630 invalidate_xy(s, x, y);
e7f0ad58
FB
631 }
632 }
633}
634
76ffb0b4 635static void console_refresh(QemuConsole *s)
e7f0ad58
FB
636{
637 TextCell *c;
638 int x, y, y1;
639
5fafdf24 640 if (s != active_console)
e7f0ad58 641 return;
a93a4a22
GH
642
643 if (s->ds->have_text) {
4d3b6f6e
AZ
644 s->text_x[0] = 0;
645 s->text_y[0] = 0;
646 s->text_x[1] = s->width - 1;
647 s->text_y[1] = s->height - 1;
648 s->cursor_invalidate = 1;
4d3b6f6e 649 }
e7f0ad58 650
a93a4a22
GH
651 if (s->ds->have_gfx) {
652 vga_fill_rect(s->ds, 0, 0, ds_get_width(s->ds), ds_get_height(s->ds),
653 color_table[0][COLOR_BLACK]);
654 y1 = s->y_displayed;
655 for (y = 0; y < s->height; y++) {
656 c = s->cells + y1 * s->width;
657 for (x = 0; x < s->width; x++) {
658 vga_putcharxy(s->ds, x, y, c->ch,
659 &(c->t_attrib));
660 c++;
661 }
662 if (++y1 == s->total_height) {
663 y1 = 0;
664 }
e7f0ad58 665 }
a93a4a22
GH
666 console_show_cursor(s, 1);
667 dpy_gfx_update(s->ds, 0, 0, ds_get_width(s->ds), ds_get_height(s->ds));
e7f0ad58 668 }
e7f0ad58
FB
669}
670
671static void console_scroll(int ydelta)
672{
76ffb0b4 673 QemuConsole *s;
e7f0ad58 674 int i, y1;
3b46e624 675
e7f0ad58 676 s = active_console;
af3a9031 677 if (!s || (s->console_type == GRAPHIC_CONSOLE))
e7f0ad58
FB
678 return;
679
680 if (ydelta > 0) {
681 for(i = 0; i < ydelta; i++) {
682 if (s->y_displayed == s->y_base)
683 break;
684 if (++s->y_displayed == s->total_height)
685 s->y_displayed = 0;
686 }
687 } else {
688 ydelta = -ydelta;
689 i = s->backscroll_height;
690 if (i > s->total_height - s->height)
691 i = s->total_height - s->height;
692 y1 = s->y_base - i;
693 if (y1 < 0)
694 y1 += s->total_height;
695 for(i = 0; i < ydelta; i++) {
696 if (s->y_displayed == y1)
697 break;
698 if (--s->y_displayed < 0)
699 s->y_displayed = s->total_height - 1;
700 }
701 }
702 console_refresh(s);
703}
704
76ffb0b4 705static void console_put_lf(QemuConsole *s)
e7f0ad58
FB
706{
707 TextCell *c;
708 int x, y1;
709
e7f0ad58
FB
710 s->y++;
711 if (s->y >= s->height) {
712 s->y = s->height - 1;
6d6f7c28 713
e7f0ad58
FB
714 if (s->y_displayed == s->y_base) {
715 if (++s->y_displayed == s->total_height)
716 s->y_displayed = 0;
717 }
718 if (++s->y_base == s->total_height)
719 s->y_base = 0;
720 if (s->backscroll_height < s->total_height)
721 s->backscroll_height++;
722 y1 = (s->y_base + s->height - 1) % s->total_height;
723 c = &s->cells[y1 * s->width];
724 for(x = 0; x < s->width; x++) {
725 c->ch = ' ';
6d6f7c28 726 c->t_attrib = s->t_attrib_default;
e7f0ad58
FB
727 c++;
728 }
729 if (s == active_console && s->y_displayed == s->y_base) {
0e1f5a0c 730 if (!ds_get_bits_per_pixel(s->ds)) {
4d3b6f6e
AZ
731 s->text_x[0] = 0;
732 s->text_y[0] = 0;
733 s->text_x[1] = s->width - 1;
734 s->text_y[1] = s->height - 1;
735 return;
736 }
737
5fafdf24
TS
738 vga_bitblt(s->ds, 0, FONT_HEIGHT, 0, 0,
739 s->width * FONT_WIDTH,
e7f0ad58
FB
740 (s->height - 1) * FONT_HEIGHT);
741 vga_fill_rect(s->ds, 0, (s->height - 1) * FONT_HEIGHT,
5fafdf24 742 s->width * FONT_WIDTH, FONT_HEIGHT,
6d6f7c28 743 color_table[0][s->t_attrib_default.bgcol]);
14778c20
PB
744 s->update_x0 = 0;
745 s->update_y0 = 0;
746 s->update_x1 = s->width * FONT_WIDTH;
747 s->update_y1 = s->height * FONT_HEIGHT;
e7f0ad58
FB
748 }
749 }
750}
751
6d6f7c28
PB
752/* Set console attributes depending on the current escape codes.
753 * NOTE: I know this code is not very efficient (checking every color for it
754 * self) but it is more readable and better maintainable.
755 */
76ffb0b4 756static void console_handle_escape(QemuConsole *s)
6d6f7c28
PB
757{
758 int i;
759
6d6f7c28
PB
760 for (i=0; i<s->nb_esc_params; i++) {
761 switch (s->esc_params[i]) {
762 case 0: /* reset all console attributes to default */
763 s->t_attrib = s->t_attrib_default;
764 break;
765 case 1:
766 s->t_attrib.bold = 1;
767 break;
768 case 4:
769 s->t_attrib.uline = 1;
770 break;
771 case 5:
772 s->t_attrib.blink = 1;
773 break;
774 case 7:
775 s->t_attrib.invers = 1;
776 break;
777 case 8:
778 s->t_attrib.unvisible = 1;
779 break;
780 case 22:
781 s->t_attrib.bold = 0;
782 break;
783 case 24:
784 s->t_attrib.uline = 0;
785 break;
786 case 25:
787 s->t_attrib.blink = 0;
788 break;
789 case 27:
790 s->t_attrib.invers = 0;
791 break;
792 case 28:
793 s->t_attrib.unvisible = 0;
794 break;
795 /* set foreground color */
796 case 30:
797 s->t_attrib.fgcol=COLOR_BLACK;
798 break;
799 case 31:
800 s->t_attrib.fgcol=COLOR_RED;
801 break;
802 case 32:
803 s->t_attrib.fgcol=COLOR_GREEN;
804 break;
805 case 33:
806 s->t_attrib.fgcol=COLOR_YELLOW;
807 break;
808 case 34:
809 s->t_attrib.fgcol=COLOR_BLUE;
810 break;
811 case 35:
812 s->t_attrib.fgcol=COLOR_MAGENTA;
813 break;
814 case 36:
815 s->t_attrib.fgcol=COLOR_CYAN;
816 break;
817 case 37:
818 s->t_attrib.fgcol=COLOR_WHITE;
819 break;
820 /* set background color */
821 case 40:
822 s->t_attrib.bgcol=COLOR_BLACK;
823 break;
824 case 41:
825 s->t_attrib.bgcol=COLOR_RED;
826 break;
827 case 42:
828 s->t_attrib.bgcol=COLOR_GREEN;
829 break;
830 case 43:
831 s->t_attrib.bgcol=COLOR_YELLOW;
832 break;
833 case 44:
834 s->t_attrib.bgcol=COLOR_BLUE;
835 break;
836 case 45:
837 s->t_attrib.bgcol=COLOR_MAGENTA;
838 break;
839 case 46:
840 s->t_attrib.bgcol=COLOR_CYAN;
841 break;
842 case 47:
843 s->t_attrib.bgcol=COLOR_WHITE;
844 break;
845 }
846 }
847}
848
76ffb0b4 849static void console_clear_xy(QemuConsole *s, int x, int y)
adb47967
TS
850{
851 int y1 = (s->y_base + y) % s->total_height;
852 TextCell *c = &s->cells[y1 * s->width + x];
853 c->ch = ' ';
854 c->t_attrib = s->t_attrib_default;
adb47967
TS
855 update_xy(s, x, y);
856}
857
3eea5498 858/* set cursor, checking bounds */
76ffb0b4 859static void set_cursor(QemuConsole *s, int x, int y)
3eea5498
IC
860{
861 if (x < 0) {
862 x = 0;
863 }
864 if (y < 0) {
865 y = 0;
866 }
867 if (y >= s->height) {
868 y = s->height - 1;
869 }
870 if (x >= s->width) {
871 x = s->width - 1;
872 }
873
874 s->x = x;
875 s->y = y;
876}
877
76ffb0b4 878static void console_putchar(QemuConsole *s, int ch)
e7f0ad58
FB
879{
880 TextCell *c;
adb47967
TS
881 int y1, i;
882 int x, y;
e7f0ad58
FB
883
884 switch(s->state) {
885 case TTY_STATE_NORM:
886 switch(ch) {
6d6f7c28 887 case '\r': /* carriage return */
e7f0ad58
FB
888 s->x = 0;
889 break;
6d6f7c28 890 case '\n': /* newline */
e7f0ad58
FB
891 console_put_lf(s);
892 break;
6d6f7c28 893 case '\b': /* backspace */
5fafdf24 894 if (s->x > 0)
e15d7371 895 s->x--;
6d6f7c28
PB
896 break;
897 case '\t': /* tabspace */
898 if (s->x + (8 - (s->x % 8)) > s->width) {
bd468840 899 s->x = 0;
6d6f7c28
PB
900 console_put_lf(s);
901 } else {
902 s->x = s->x + (8 - (s->x % 8));
903 }
904 break;
905 case '\a': /* alert aka. bell */
906 /* TODO: has to be implemented */
907 break;
adb47967
TS
908 case 14:
909 /* SI (shift in), character set 0 (ignored) */
910 break;
911 case 15:
912 /* SO (shift out), character set 1 (ignored) */
913 break;
6d6f7c28 914 case 27: /* esc (introducing an escape sequence) */
e7f0ad58
FB
915 s->state = TTY_STATE_ESC;
916 break;
917 default:
ed8276ac
TS
918 if (s->x >= s->width) {
919 /* line wrap */
920 s->x = 0;
921 console_put_lf(s);
adb47967 922 }
e7f0ad58
FB
923 y1 = (s->y_base + s->y) % s->total_height;
924 c = &s->cells[y1 * s->width + s->x];
925 c->ch = ch;
6d6f7c28 926 c->t_attrib = s->t_attrib;
e7f0ad58
FB
927 update_xy(s, s->x, s->y);
928 s->x++;
e7f0ad58
FB
929 break;
930 }
931 break;
6d6f7c28 932 case TTY_STATE_ESC: /* check if it is a terminal escape sequence */
e7f0ad58
FB
933 if (ch == '[') {
934 for(i=0;i<MAX_ESC_PARAMS;i++)
935 s->esc_params[i] = 0;
936 s->nb_esc_params = 0;
937 s->state = TTY_STATE_CSI;
938 } else {
939 s->state = TTY_STATE_NORM;
940 }
941 break;
6d6f7c28 942 case TTY_STATE_CSI: /* handle escape sequence parameters */
e7f0ad58
FB
943 if (ch >= '0' && ch <= '9') {
944 if (s->nb_esc_params < MAX_ESC_PARAMS) {
c10600af
LE
945 int *param = &s->esc_params[s->nb_esc_params];
946 int digit = (ch - '0');
947
948 *param = (*param <= (INT_MAX - digit) / 10) ?
949 *param * 10 + digit : INT_MAX;
e7f0ad58
FB
950 }
951 } else {
3eea5498
IC
952 if (s->nb_esc_params < MAX_ESC_PARAMS)
953 s->nb_esc_params++;
e7f0ad58
FB
954 if (ch == ';')
955 break;
adb47967
TS
956#ifdef DEBUG_CONSOLE
957 fprintf(stderr, "escape sequence CSI%d;%d%c, %d parameters\n",
958 s->esc_params[0], s->esc_params[1], ch, s->nb_esc_params);
959#endif
e7f0ad58
FB
960 s->state = TTY_STATE_NORM;
961 switch(ch) {
adb47967
TS
962 case 'A':
963 /* move cursor up */
964 if (s->esc_params[0] == 0) {
965 s->esc_params[0] = 1;
966 }
3eea5498 967 set_cursor(s, s->x, s->y - s->esc_params[0]);
adb47967
TS
968 break;
969 case 'B':
970 /* move cursor down */
971 if (s->esc_params[0] == 0) {
972 s->esc_params[0] = 1;
973 }
3eea5498 974 set_cursor(s, s->x, s->y + s->esc_params[0]);
e7f0ad58
FB
975 break;
976 case 'C':
adb47967
TS
977 /* move cursor right */
978 if (s->esc_params[0] == 0) {
979 s->esc_params[0] = 1;
980 }
3eea5498 981 set_cursor(s, s->x + s->esc_params[0], s->y);
e7f0ad58 982 break;
adb47967
TS
983 case 'D':
984 /* move cursor left */
985 if (s->esc_params[0] == 0) {
986 s->esc_params[0] = 1;
987 }
3eea5498 988 set_cursor(s, s->x - s->esc_params[0], s->y);
adb47967
TS
989 break;
990 case 'G':
991 /* move cursor to column */
3eea5498 992 set_cursor(s, s->esc_params[0] - 1, s->y);
adb47967
TS
993 break;
994 case 'f':
995 case 'H':
996 /* move cursor to row, column */
3eea5498 997 set_cursor(s, s->esc_params[1] - 1, s->esc_params[0] - 1);
adb47967
TS
998 break;
999 case 'J':
1000 switch (s->esc_params[0]) {
1001 case 0:
1002 /* clear to end of screen */
1003 for (y = s->y; y < s->height; y++) {
1004 for (x = 0; x < s->width; x++) {
1005 if (y == s->y && x < s->x) {
1006 continue;
1007 }
1008 console_clear_xy(s, x, y);
1009 }
1010 }
1011 break;
1012 case 1:
1013 /* clear from beginning of screen */
1014 for (y = 0; y <= s->y; y++) {
1015 for (x = 0; x < s->width; x++) {
1016 if (y == s->y && x > s->x) {
1017 break;
1018 }
1019 console_clear_xy(s, x, y);
1020 }
1021 }
1022 break;
1023 case 2:
1024 /* clear entire screen */
1025 for (y = 0; y <= s->height; y++) {
1026 for (x = 0; x < s->width; x++) {
1027 console_clear_xy(s, x, y);
1028 }
1029 }
f94a950f 1030 break;
adb47967 1031 }
95d8f9f4 1032 break;
e7f0ad58 1033 case 'K':
adb47967
TS
1034 switch (s->esc_params[0]) {
1035 case 0:
f94a950f
MA
1036 /* clear to eol */
1037 for(x = s->x; x < s->width; x++) {
adb47967 1038 console_clear_xy(s, x, s->y);
f94a950f
MA
1039 }
1040 break;
adb47967
TS
1041 case 1:
1042 /* clear from beginning of line */
1043 for (x = 0; x <= s->x; x++) {
1044 console_clear_xy(s, x, s->y);
1045 }
1046 break;
1047 case 2:
1048 /* clear entire line */
1049 for(x = 0; x < s->width; x++) {
1050 console_clear_xy(s, x, s->y);
1051 }
f94a950f
MA
1052 break;
1053 }
adb47967
TS
1054 break;
1055 case 'm':
f94a950f
MA
1056 console_handle_escape(s);
1057 break;
adb47967
TS
1058 case 'n':
1059 /* report cursor position */
1060 /* TODO: send ESC[row;colR */
1061 break;
1062 case 's':
1063 /* save cursor position */
1064 s->x_saved = s->x;
1065 s->y_saved = s->y;
1066 break;
1067 case 'u':
1068 /* restore cursor position */
1069 s->x = s->x_saved;
1070 s->y = s->y_saved;
1071 break;
1072 default:
1073#ifdef DEBUG_CONSOLE
1074 fprintf(stderr, "unhandled escape character '%c'\n", ch);
1075#endif
1076 break;
1077 }
1078 break;
e7f0ad58
FB
1079 }
1080 }
1081}
1082
1083void console_select(unsigned int index)
1084{
76ffb0b4 1085 QemuConsole *s;
6d6f7c28 1086
e7f0ad58
FB
1087 if (index >= MAX_CONSOLES)
1088 return;
358664cc
SH
1089 if (active_console) {
1090 active_console->g_width = ds_get_width(active_console->ds);
1091 active_console->g_height = ds_get_height(active_console->ds);
1092 }
e7f0ad58
FB
1093 s = consoles[index];
1094 if (s) {
7d957bd8 1095 DisplayState *ds = s->ds;
bf1bed81 1096
8bd6b06d 1097 if (active_console && active_console->cursor_timer) {
bf1bed81
JK
1098 qemu_del_timer(active_console->cursor_timer);
1099 }
e7f0ad58 1100 active_console = s;
a93a4a22 1101 if (ds->have_gfx) {
da229ef3
GH
1102 DisplaySurface *surface;
1103 surface = qemu_create_displaysurface(s->g_width, s->g_height);
1104 dpy_gfx_replace_surface(ds, surface);
a93a4a22
GH
1105 }
1106 if (ds->have_text) {
1107 dpy_text_resize(ds, s->width, s->height);
68f00996 1108 }
bf1bed81
JK
1109 if (s->cursor_timer) {
1110 qemu_mod_timer(s->cursor_timer,
1111 qemu_get_clock_ms(rt_clock) + CONSOLE_CURSOR_PERIOD / 2);
1112 }
4d3b6f6e 1113 vga_hw_invalidate();
e7f0ad58
FB
1114 }
1115}
1116
1117static int console_puts(CharDriverState *chr, const uint8_t *buf, int len)
1118{
76ffb0b4 1119 QemuConsole *s = chr->opaque;
e7f0ad58
FB
1120 int i;
1121
14778c20
PB
1122 s->update_x0 = s->width * FONT_WIDTH;
1123 s->update_y0 = s->height * FONT_HEIGHT;
1124 s->update_x1 = 0;
1125 s->update_y1 = 0;
e7f0ad58
FB
1126 console_show_cursor(s, 0);
1127 for(i = 0; i < len; i++) {
1128 console_putchar(s, buf[i]);
1129 }
1130 console_show_cursor(s, 1);
a93a4a22
GH
1131 if (s->ds->have_gfx && s->update_x0 < s->update_x1) {
1132 dpy_gfx_update(s->ds, s->update_x0, s->update_y0,
1133 s->update_x1 - s->update_x0,
1134 s->update_y1 - s->update_y0);
14778c20 1135 }
e7f0ad58
FB
1136 return len;
1137}
1138
e15d7371
FB
1139static void kbd_send_chars(void *opaque)
1140{
76ffb0b4 1141 QemuConsole *s = opaque;
e15d7371
FB
1142 int len;
1143 uint8_t buf[16];
3b46e624 1144
909cda12 1145 len = qemu_chr_be_can_write(s->chr);
e15d7371
FB
1146 if (len > s->out_fifo.count)
1147 len = s->out_fifo.count;
1148 if (len > 0) {
1149 if (len > sizeof(buf))
1150 len = sizeof(buf);
1151 qemu_fifo_read(&s->out_fifo, buf, len);
fa5efccb 1152 qemu_chr_be_write(s->chr, buf, len);
e15d7371
FB
1153 }
1154 /* characters are pending: we send them a bit later (XXX:
1155 horrible, should change char device API) */
1156 if (s->out_fifo.count > 0) {
7bd427d8 1157 qemu_mod_timer(s->kbd_timer, qemu_get_clock_ms(rt_clock) + 1);
e15d7371
FB
1158 }
1159}
1160
e7f0ad58
FB
1161/* called when an ascii key is pressed */
1162void kbd_put_keysym(int keysym)
1163{
76ffb0b4 1164 QemuConsole *s;
e7f0ad58
FB
1165 uint8_t buf[16], *q;
1166 int c;
1167
1168 s = active_console;
af3a9031 1169 if (!s || (s->console_type == GRAPHIC_CONSOLE))
e7f0ad58
FB
1170 return;
1171
1172 switch(keysym) {
1173 case QEMU_KEY_CTRL_UP:
1174 console_scroll(-1);
1175 break;
1176 case QEMU_KEY_CTRL_DOWN:
1177 console_scroll(1);
1178 break;
1179 case QEMU_KEY_CTRL_PAGEUP:
1180 console_scroll(-10);
1181 break;
1182 case QEMU_KEY_CTRL_PAGEDOWN:
1183 console_scroll(10);
1184 break;
1185 default:
e15d7371
FB
1186 /* convert the QEMU keysym to VT100 key string */
1187 q = buf;
1188 if (keysym >= 0xe100 && keysym <= 0xe11f) {
1189 *q++ = '\033';
1190 *q++ = '[';
1191 c = keysym - 0xe100;
1192 if (c >= 10)
1193 *q++ = '0' + (c / 10);
1194 *q++ = '0' + (c % 10);
1195 *q++ = '~';
1196 } else if (keysym >= 0xe120 && keysym <= 0xe17f) {
1197 *q++ = '\033';
1198 *q++ = '[';
1199 *q++ = keysym & 0xff;
4104833f
PB
1200 } else if (s->echo && (keysym == '\r' || keysym == '\n')) {
1201 console_puts(s->chr, (const uint8_t *) "\r", 1);
1202 *q++ = '\n';
e15d7371 1203 } else {
4104833f
PB
1204 *q++ = keysym;
1205 }
1206 if (s->echo) {
1207 console_puts(s->chr, buf, q - buf);
e15d7371 1208 }
e5b0bc44 1209 if (s->chr->chr_read) {
e15d7371
FB
1210 qemu_fifo_write(&s->out_fifo, buf, q - buf);
1211 kbd_send_chars(s);
e7f0ad58
FB
1212 }
1213 break;
1214 }
1215}
1216
4d3b6f6e
AZ
1217static void text_console_invalidate(void *opaque)
1218{
76ffb0b4 1219 QemuConsole *s = (QemuConsole *) opaque;
68f00996
AL
1220 if (!ds_get_bits_per_pixel(s->ds) && s->console_type == TEXT_CONSOLE) {
1221 s->g_width = ds_get_width(s->ds);
1222 s->g_height = ds_get_height(s->ds);
1223 text_console_resize(s);
1224 }
4d3b6f6e
AZ
1225 console_refresh(s);
1226}
1227
c227f099 1228static void text_console_update(void *opaque, console_ch_t *chardata)
4d3b6f6e 1229{
76ffb0b4 1230 QemuConsole *s = (QemuConsole *) opaque;
4d3b6f6e
AZ
1231 int i, j, src;
1232
1233 if (s->text_x[0] <= s->text_x[1]) {
1234 src = (s->y_base + s->text_y[0]) * s->width;
1235 chardata += s->text_y[0] * s->width;
1236 for (i = s->text_y[0]; i <= s->text_y[1]; i ++)
1237 for (j = 0; j < s->width; j ++, src ++)
1238 console_write_ch(chardata ++, s->cells[src].ch |
1239 (s->cells[src].t_attrib.fgcol << 12) |
1240 (s->cells[src].t_attrib.bgcol << 8) |
1241 (s->cells[src].t_attrib.bold << 21));
a93a4a22
GH
1242 dpy_text_update(s->ds, s->text_x[0], s->text_y[0],
1243 s->text_x[1] - s->text_x[0], i - s->text_y[0]);
4d3b6f6e
AZ
1244 s->text_x[0] = s->width;
1245 s->text_y[0] = s->height;
1246 s->text_x[1] = 0;
1247 s->text_y[1] = 0;
1248 }
1249 if (s->cursor_invalidate) {
bf2fde70 1250 dpy_text_cursor(s->ds, s->x, s->y);
4d3b6f6e
AZ
1251 s->cursor_invalidate = 0;
1252 }
1253}
1254
76ffb0b4 1255static QemuConsole *get_graphic_console(DisplayState *ds)
a147d62b 1256{
3023f332 1257 int i;
76ffb0b4 1258 QemuConsole *s;
3023f332
AL
1259 for (i = 0; i < nb_consoles; i++) {
1260 s = consoles[i];
42aa98e8 1261 if (s->console_type == GRAPHIC_CONSOLE && s->ds == ds)
3023f332
AL
1262 return s;
1263 }
1264 return NULL;
1265}
1266
76ffb0b4 1267static QemuConsole *new_console(DisplayState *ds, console_type_t console_type)
e7f0ad58 1268{
76ffb0b4 1269 QemuConsole *s;
95219897 1270 int i;
e7f0ad58
FB
1271
1272 if (nb_consoles >= MAX_CONSOLES)
1273 return NULL;
76ffb0b4 1274 s = g_malloc0(sizeof(QemuConsole));
af3a9031
TS
1275 if (!active_console || ((active_console->console_type != GRAPHIC_CONSOLE) &&
1276 (console_type == GRAPHIC_CONSOLE))) {
e7f0ad58 1277 active_console = s;
af3a9031 1278 }
e7f0ad58 1279 s->ds = ds;
af3a9031
TS
1280 s->console_type = console_type;
1281 if (console_type != GRAPHIC_CONSOLE) {
f81bdefb 1282 s->index = nb_consoles;
95219897
PB
1283 consoles[nb_consoles++] = s;
1284 } else {
1285 /* HACK: Put graphical consoles before text consoles. */
1286 for (i = nb_consoles; i > 0; i--) {
af3a9031 1287 if (consoles[i - 1]->console_type == GRAPHIC_CONSOLE)
95219897
PB
1288 break;
1289 consoles[i] = consoles[i - 1];
f81bdefb 1290 consoles[i]->index = i;
95219897 1291 }
f81bdefb 1292 s->index = i;
95219897 1293 consoles[i] = s;
3023f332 1294 nb_consoles++;
95219897
PB
1295 }
1296 return s;
1297}
1298
537a4391
GH
1299static void qemu_alloc_display(DisplaySurface *surface, int width, int height,
1300 int linesize, PixelFormat pf, int newflags)
ffe8b821 1301{
ffe8b821 1302 surface->pf = pf;
69c77777
GH
1303
1304 qemu_pixman_image_unref(surface->image);
1305 surface->image = NULL;
69c77777
GH
1306
1307 surface->format = qemu_pixman_get_format(&pf);
1308 assert(surface->format != 0);
1309 surface->image = pixman_image_create_bits(surface->format,
1310 width, height,
1311 NULL, linesize);
1312 assert(surface->image != NULL);
1313
ffe8b821 1314 surface->flags = newflags | QEMU_ALLOCATED_FLAG;
98b50080 1315#ifdef HOST_WORDS_BIGENDIAN
ffe8b821 1316 surface->flags |= QEMU_BIG_ENDIAN_FLAG;
98b50080 1317#endif
98b50080
PB
1318}
1319
da229ef3 1320DisplaySurface *qemu_create_displaysurface(int width, int height)
537a4391
GH
1321{
1322 DisplaySurface *surface = g_new0(DisplaySurface, 1);
537a4391 1323 int linesize = width * 4;
da229ef3
GH
1324
1325 trace_displaysurface_create(surface, width, height);
537a4391
GH
1326 qemu_alloc_display(surface, width, height, linesize,
1327 qemu_default_pixelformat(32), 0);
1328 return surface;
1329}
1330
187cd1d9 1331DisplaySurface *qemu_create_displaysurface_from(int width, int height, int bpp,
b1424e03
GH
1332 int linesize, uint8_t *data,
1333 bool byteswap)
98b50080 1334{
69c77777 1335 DisplaySurface *surface = g_new0(DisplaySurface, 1);
98b50080 1336
da229ef3 1337 trace_displaysurface_create_from(surface, width, height, bpp, byteswap);
b1424e03
GH
1338 if (byteswap) {
1339 surface->pf = qemu_different_endianness_pixelformat(bpp);
1340 } else {
1341 surface->pf = qemu_default_pixelformat(bpp);
1342 }
69c77777
GH
1343
1344 surface->format = qemu_pixman_get_format(&surface->pf);
1345 assert(surface->format != 0);
1346 surface->image = pixman_image_create_bits(surface->format,
1347 width, height,
1348 (void *)data, linesize);
1349 assert(surface->image != NULL);
1350
98b50080
PB
1351#ifdef HOST_WORDS_BIGENDIAN
1352 surface->flags = QEMU_BIG_ENDIAN_FLAG;
1353#endif
98b50080
PB
1354
1355 return surface;
1356}
1357
da229ef3 1358void qemu_free_displaysurface(DisplaySurface *surface)
98b50080 1359{
da229ef3 1360 if (surface == NULL) {
98b50080 1361 return;
187cd1d9 1362 }
da229ef3
GH
1363 trace_displaysurface_free(surface);
1364 qemu_pixman_image_unref(surface->image);
1365 g_free(surface);
98b50080
PB
1366}
1367
7c20b4a3
GH
1368void register_displaychangelistener(DisplayState *ds,
1369 DisplayChangeListener *dcl)
1370{
1371 trace_displaychangelistener_register(dcl, dcl->ops->dpy_name);
1372 dcl->ds = ds;
1373 QLIST_INSERT_HEAD(&ds->listeners, dcl, next);
1374 gui_setup_refresh(ds);
c12aeb86
GH
1375 if (dcl->ops->dpy_gfx_switch) {
1376 dcl->ops->dpy_gfx_switch(dcl, ds, ds->surface);
7c20b4a3
GH
1377 }
1378}
1379
1380void unregister_displaychangelistener(DisplayChangeListener *dcl)
1381{
1382 DisplayState *ds = dcl->ds;
1383 trace_displaychangelistener_unregister(dcl, dcl->ops->dpy_name);
1384 QLIST_REMOVE(dcl, next);
1385 gui_setup_refresh(ds);
1386}
1387
1388void dpy_gfx_update(DisplayState *s, int x, int y, int w, int h)
1389{
1390 struct DisplayChangeListener *dcl;
1391 int width = pixman_image_get_width(s->surface->image);
1392 int height = pixman_image_get_height(s->surface->image);
1393
1394 x = MAX(x, 0);
1395 y = MAX(y, 0);
1396 x = MIN(x, width);
1397 y = MIN(y, height);
1398 w = MIN(w, width - x);
1399 h = MIN(h, height - y);
1400
1401 QLIST_FOREACH(dcl, &s->listeners, next) {
1402 if (dcl->ops->dpy_gfx_update) {
1403 dcl->ops->dpy_gfx_update(dcl, s, x, y, w, h);
1404 }
1405 }
1406}
1407
da229ef3
GH
1408void dpy_gfx_replace_surface(DisplayState *s,
1409 DisplaySurface *surface)
7c20b4a3 1410{
da229ef3 1411 DisplaySurface *old_surface = s->surface;
7c20b4a3 1412 struct DisplayChangeListener *dcl;
da229ef3
GH
1413
1414 s->surface = surface;
7c20b4a3 1415 QLIST_FOREACH(dcl, &s->listeners, next) {
c12aeb86
GH
1416 if (dcl->ops->dpy_gfx_switch) {
1417 dcl->ops->dpy_gfx_switch(dcl, s, surface);
7c20b4a3
GH
1418 }
1419 }
da229ef3 1420 qemu_free_displaysurface(old_surface);
7c20b4a3
GH
1421}
1422
1423void dpy_refresh(DisplayState *s)
1424{
1425 struct DisplayChangeListener *dcl;
1426 QLIST_FOREACH(dcl, &s->listeners, next) {
1427 if (dcl->ops->dpy_refresh) {
1428 dcl->ops->dpy_refresh(dcl, s);
1429 }
1430 }
1431}
1432
1433void dpy_gfx_copy(struct DisplayState *s, int src_x, int src_y,
1434 int dst_x, int dst_y, int w, int h)
1435{
1436 struct DisplayChangeListener *dcl;
1437 QLIST_FOREACH(dcl, &s->listeners, next) {
1438 if (dcl->ops->dpy_gfx_copy) {
1439 dcl->ops->dpy_gfx_copy(dcl, s, src_x, src_y, dst_x, dst_y, w, h);
1440 } else { /* TODO */
1441 dcl->ops->dpy_gfx_update(dcl, s, dst_x, dst_y, w, h);
1442 }
1443 }
1444}
1445
1446void dpy_text_cursor(struct DisplayState *s, int x, int y)
1447{
1448 struct DisplayChangeListener *dcl;
1449 QLIST_FOREACH(dcl, &s->listeners, next) {
1450 if (dcl->ops->dpy_text_cursor) {
1451 dcl->ops->dpy_text_cursor(dcl, s, x, y);
1452 }
1453 }
1454}
1455
1456void dpy_text_update(DisplayState *s, int x, int y, int w, int h)
1457{
1458 struct DisplayChangeListener *dcl;
1459 QLIST_FOREACH(dcl, &s->listeners, next) {
1460 if (dcl->ops->dpy_text_update) {
1461 dcl->ops->dpy_text_update(dcl, s, x, y, w, h);
1462 }
1463 }
1464}
1465
1466void dpy_text_resize(DisplayState *s, int w, int h)
1467{
1468 struct DisplayChangeListener *dcl;
1469 QLIST_FOREACH(dcl, &s->listeners, next) {
1470 if (dcl->ops->dpy_text_resize) {
1471 dcl->ops->dpy_text_resize(dcl, s, w, h);
1472 }
1473 }
1474}
1475
1476void dpy_mouse_set(struct DisplayState *s, int x, int y, int on)
1477{
1478 struct DisplayChangeListener *dcl;
1479 QLIST_FOREACH(dcl, &s->listeners, next) {
1480 if (dcl->ops->dpy_mouse_set) {
1481 dcl->ops->dpy_mouse_set(dcl, s, x, y, on);
1482 }
1483 }
1484}
1485
1486void dpy_cursor_define(struct DisplayState *s, QEMUCursor *cursor)
1487{
1488 struct DisplayChangeListener *dcl;
1489 QLIST_FOREACH(dcl, &s->listeners, next) {
1490 if (dcl->ops->dpy_cursor_define) {
1491 dcl->ops->dpy_cursor_define(dcl, s, cursor);
1492 }
1493 }
1494}
1495
1496bool dpy_cursor_define_supported(struct DisplayState *s)
1497{
1498 struct DisplayChangeListener *dcl;
1499 QLIST_FOREACH(dcl, &s->listeners, next) {
1500 if (dcl->ops->dpy_cursor_define) {
1501 return true;
1502 }
1503 }
1504 return false;
1505}
1506
98b50080
PB
1507static void dumb_display_init(void)
1508{
7267c094 1509 DisplayState *ds = g_malloc0(sizeof(DisplayState));
da229ef3 1510 DisplaySurface *surface;
1802651c
JK
1511 int width = 640;
1512 int height = 480;
1513
1802651c
JK
1514 if (is_fixedsize_console()) {
1515 width = active_console->g_width;
1516 height = active_console->g_height;
1517 }
da229ef3
GH
1518 surface = qemu_create_displaysurface(width, height);
1519 dpy_gfx_replace_surface(ds, surface);
1520
98b50080
PB
1521 register_displaystate(ds);
1522}
1523
1524/***********************************************************/
1525/* register display */
1526
1527void register_displaystate(DisplayState *ds)
1528{
1529 DisplayState **s;
1530 s = &display_state;
1531 while (*s != NULL)
1532 s = &(*s)->next;
1533 ds->next = NULL;
1534 *s = ds;
1535}
1536
1537DisplayState *get_displaystate(void)
1538{
1539 if (!display_state) {
1540 dumb_display_init ();
1541 }
1542 return display_state;
1543}
1544
3023f332
AL
1545DisplayState *graphic_console_init(vga_hw_update_ptr update,
1546 vga_hw_invalidate_ptr invalidate,
1547 vga_hw_screen_dump_ptr screen_dump,
1548 vga_hw_text_update_ptr text_update,
1549 void *opaque)
95219897 1550{
76ffb0b4 1551 QemuConsole *s;
3023f332 1552 DisplayState *ds;
da229ef3 1553 DisplaySurface *surface;
f0f2f976 1554
7267c094 1555 ds = (DisplayState *) g_malloc0(sizeof(DisplayState));
af3a9031 1556 s = new_console(ds, GRAPHIC_CONSOLE);
95219897
PB
1557 s->hw_update = update;
1558 s->hw_invalidate = invalidate;
1559 s->hw_screen_dump = screen_dump;
4d3b6f6e 1560 s->hw_text_update = text_update;
95219897 1561 s->hw = opaque;
3023f332 1562
da229ef3
GH
1563 surface = qemu_create_displaysurface(640, 480);
1564 dpy_gfx_replace_surface(ds, surface);
1565
f0f2f976 1566 register_displaystate(ds);
3023f332 1567 return ds;
e7f0ad58
FB
1568}
1569
95219897 1570int is_graphic_console(void)
e7f0ad58 1571{
4d3b6f6e 1572 return active_console && active_console->console_type == GRAPHIC_CONSOLE;
e7f0ad58
FB
1573}
1574
c21bbcfa
AZ
1575int is_fixedsize_console(void)
1576{
1577 return active_console && active_console->console_type != TEXT_CONSOLE;
1578}
1579
a528b80c
AZ
1580void console_color_init(DisplayState *ds)
1581{
1582 int i, j;
1583 for (j = 0; j < 2; j++) {
1584 for (i = 0; i < 8; i++) {
f0f2f976 1585 color_table[j][i] = col_expand(ds,
a528b80c
AZ
1586 vga_get_color(ds, color_table_rgb[j][i]));
1587 }
1588 }
1589}
1590
4104833f
PB
1591static void text_console_set_echo(CharDriverState *chr, bool echo)
1592{
76ffb0b4 1593 QemuConsole *s = chr->opaque;
4104833f
PB
1594
1595 s->echo = echo;
1596}
1597
bf1bed81
JK
1598static void text_console_update_cursor(void *opaque)
1599{
76ffb0b4 1600 QemuConsole *s = opaque;
bf1bed81
JK
1601
1602 s->cursor_visible_phase = !s->cursor_visible_phase;
1603 vga_hw_invalidate();
1604 qemu_mod_timer(s->cursor_timer,
1605 qemu_get_clock_ms(rt_clock) + CONSOLE_CURSOR_PERIOD / 2);
1606}
1607
44b37b93 1608static void text_console_do_init(CharDriverState *chr, DisplayState *ds)
e7f0ad58 1609{
76ffb0b4 1610 QemuConsole *s;
e7f0ad58 1611 static int color_inited;
6d6f7c28 1612
491e114a 1613 s = chr->opaque;
6ea314d9 1614
e7f0ad58 1615 chr->chr_write = console_puts;
6fcfafb7 1616
e15d7371
FB
1617 s->out_fifo.buf = s->out_fifo_buf;
1618 s->out_fifo.buf_size = sizeof(s->out_fifo_buf);
7bd427d8 1619 s->kbd_timer = qemu_new_timer_ms(rt_clock, kbd_send_chars, s);
3023f332 1620 s->ds = ds;
3b46e624 1621
e7f0ad58
FB
1622 if (!color_inited) {
1623 color_inited = 1;
a528b80c 1624 console_color_init(s->ds);
e7f0ad58
FB
1625 }
1626 s->y_displayed = 0;
1627 s->y_base = 0;
1628 s->total_height = DEFAULT_BACKSCROLL;
1629 s->x = 0;
1630 s->y = 0;
491e114a
PB
1631 if (s->console_type == TEXT_CONSOLE) {
1632 s->g_width = ds_get_width(s->ds);
1633 s->g_height = ds_get_height(s->ds);
1634 }
6d6f7c28 1635
bf1bed81
JK
1636 s->cursor_timer =
1637 qemu_new_timer_ms(rt_clock, text_console_update_cursor, s);
1638
4d3b6f6e
AZ
1639 s->hw_invalidate = text_console_invalidate;
1640 s->hw_text_update = text_console_update;
1641 s->hw = s;
1642
6d6f7c28
PB
1643 /* Set text attribute defaults */
1644 s->t_attrib_default.bold = 0;
1645 s->t_attrib_default.uline = 0;
1646 s->t_attrib_default.blink = 0;
1647 s->t_attrib_default.invers = 0;
1648 s->t_attrib_default.unvisible = 0;
1649 s->t_attrib_default.fgcol = COLOR_WHITE;
1650 s->t_attrib_default.bgcol = COLOR_BLACK;
6d6f7c28
PB
1651 /* set current text attributes to default */
1652 s->t_attrib = s->t_attrib_default;
e7f0ad58
FB
1653 text_console_resize(s);
1654
51bfa4d3
GH
1655 if (chr->label) {
1656 char msg[128];
1657 int len;
1658
735ba588 1659 s->t_attrib.bgcol = COLOR_BLUE;
51bfa4d3
GH
1660 len = snprintf(msg, sizeof(msg), "%s console\r\n", chr->label);
1661 console_puts(chr, (uint8_t*)msg, len);
735ba588 1662 s->t_attrib = s->t_attrib_default;
51bfa4d3
GH
1663 }
1664
127338e6 1665 qemu_chr_generic_open(chr);
ceecf1d1
AJ
1666 if (chr->init)
1667 chr->init(chr);
e7f0ad58 1668}
c60e08d9 1669
702ec69c 1670static CharDriverState *text_console_init(ChardevVC *vc)
2796dae0
AL
1671{
1672 CharDriverState *chr;
76ffb0b4 1673 QemuConsole *s;
702ec69c
GH
1674 unsigned width = 0;
1675 unsigned height = 0;
2796dae0 1676
7267c094 1677 chr = g_malloc0(sizeof(CharDriverState));
2796dae0 1678
702ec69c
GH
1679 if (vc->has_width) {
1680 width = vc->width;
1681 } else if (vc->has_cols) {
1682 width = vc->cols * FONT_WIDTH;
1683 }
491e114a 1684
702ec69c
GH
1685 if (vc->has_height) {
1686 height = vc->height;
1687 } else if (vc->has_rows) {
1688 height = vc->rows * FONT_HEIGHT;
1689 }
491e114a
PB
1690
1691 if (width == 0 || height == 0) {
1692 s = new_console(NULL, TEXT_CONSOLE);
1693 } else {
1694 s = new_console(NULL, TEXT_CONSOLE_FIXED_SIZE);
1695 }
1696
1697 if (!s) {
5354d083 1698 g_free(chr);
1f51470d 1699 return NULL;
491e114a
PB
1700 }
1701
1702 s->chr = chr;
1703 s->g_width = width;
1704 s->g_height = height;
1705 chr->opaque = s;
4104833f 1706 chr->chr_set_echo = text_console_set_echo;
1f51470d 1707 return chr;
2796dae0
AL
1708}
1709
d82831db
AL
1710static VcHandler *vc_handler = text_console_init;
1711
702ec69c 1712CharDriverState *vc_init(ChardevVC *vc)
d82831db 1713{
702ec69c 1714 return vc_handler(vc);
d82831db
AL
1715}
1716
1717void register_vc_handler(VcHandler *handler)
1718{
1719 vc_handler = handler;
1720}
1721
2796dae0
AL
1722void text_consoles_set_display(DisplayState *ds)
1723{
1724 int i;
1725
8811e1e1
MA
1726 for (i = 0; i < nb_consoles; i++) {
1727 if (consoles[i]->console_type != GRAPHIC_CONSOLE) {
1728 text_console_do_init(consoles[i]->chr, ds);
1729 }
2796dae0 1730 }
2796dae0
AL
1731}
1732
3023f332 1733void qemu_console_resize(DisplayState *ds, int width, int height)
c60e08d9 1734{
76ffb0b4 1735 QemuConsole *s = get_graphic_console(ds);
f497f140
AL
1736 if (!s) return;
1737
3023f332
AL
1738 s->g_width = width;
1739 s->g_height = height;
1740 if (is_graphic_console()) {
da229ef3
GH
1741 DisplaySurface *surface;
1742 surface = qemu_create_displaysurface(width, height);
1743 dpy_gfx_replace_surface(ds, surface);
c60e08d9
PB
1744 }
1745}
38334f76 1746
3023f332
AL
1747void qemu_console_copy(DisplayState *ds, int src_x, int src_y,
1748 int dst_x, int dst_y, int w, int h)
c21bbcfa 1749{
3023f332 1750 if (is_graphic_console()) {
a93a4a22 1751 dpy_gfx_copy(ds, src_x, src_y, dst_x, dst_y, w, h);
38334f76
AZ
1752 }
1753}
7d957bd8 1754
0da2ea1b 1755PixelFormat qemu_different_endianness_pixelformat(int bpp)
7d957bd8
AL
1756{
1757 PixelFormat pf;
1758
1759 memset(&pf, 0x00, sizeof(PixelFormat));
1760
1761 pf.bits_per_pixel = bpp;
feadf1a4 1762 pf.bytes_per_pixel = DIV_ROUND_UP(bpp, 8);
7d957bd8
AL
1763 pf.depth = bpp == 32 ? 24 : bpp;
1764
1765 switch (bpp) {
0da2ea1b 1766 case 24:
1767 pf.rmask = 0x000000FF;
1768 pf.gmask = 0x0000FF00;
1769 pf.bmask = 0x00FF0000;
1770 pf.rmax = 255;
1771 pf.gmax = 255;
1772 pf.bmax = 255;
1773 pf.rshift = 0;
1774 pf.gshift = 8;
1775 pf.bshift = 16;
90a1e3c0
AL
1776 pf.rbits = 8;
1777 pf.gbits = 8;
1778 pf.bbits = 8;
7d957bd8 1779 break;
0da2ea1b 1780 case 32:
1781 pf.rmask = 0x0000FF00;
1782 pf.gmask = 0x00FF0000;
1783 pf.bmask = 0xFF000000;
1784 pf.amask = 0x00000000;
1785 pf.amax = 255;
1786 pf.rmax = 255;
1787 pf.gmax = 255;
1788 pf.bmax = 255;
1789 pf.ashift = 0;
1790 pf.rshift = 8;
1791 pf.gshift = 16;
1792 pf.bshift = 24;
90a1e3c0
AL
1793 pf.rbits = 8;
1794 pf.gbits = 8;
1795 pf.bbits = 8;
1796 pf.abits = 8;
0da2ea1b 1797 break;
1798 default:
1799 break;
1800 }
1801 return pf;
1802}
1803
1804PixelFormat qemu_default_pixelformat(int bpp)
1805{
1806 PixelFormat pf;
1807
1808 memset(&pf, 0x00, sizeof(PixelFormat));
1809
1810 pf.bits_per_pixel = bpp;
feadf1a4 1811 pf.bytes_per_pixel = DIV_ROUND_UP(bpp, 8);
0da2ea1b 1812 pf.depth = bpp == 32 ? 24 : bpp;
1813
1814 switch (bpp) {
b6278084
GH
1815 case 15:
1816 pf.bits_per_pixel = 16;
b6278084
GH
1817 pf.rmask = 0x00007c00;
1818 pf.gmask = 0x000003E0;
1819 pf.bmask = 0x0000001F;
1820 pf.rmax = 31;
1821 pf.gmax = 31;
1822 pf.bmax = 31;
1823 pf.rshift = 10;
1824 pf.gshift = 5;
1825 pf.bshift = 0;
1826 pf.rbits = 5;
1827 pf.gbits = 5;
1828 pf.bbits = 5;
1829 break;
7d957bd8
AL
1830 case 16:
1831 pf.rmask = 0x0000F800;
1832 pf.gmask = 0x000007E0;
1833 pf.bmask = 0x0000001F;
1834 pf.rmax = 31;
1835 pf.gmax = 63;
1836 pf.bmax = 31;
1837 pf.rshift = 11;
1838 pf.gshift = 5;
1839 pf.bshift = 0;
90a1e3c0
AL
1840 pf.rbits = 5;
1841 pf.gbits = 6;
1842 pf.bbits = 5;
7d957bd8
AL
1843 break;
1844 case 24:
0da2ea1b 1845 pf.rmask = 0x00FF0000;
1846 pf.gmask = 0x0000FF00;
1847 pf.bmask = 0x000000FF;
1848 pf.rmax = 255;
1849 pf.gmax = 255;
1850 pf.bmax = 255;
1851 pf.rshift = 16;
1852 pf.gshift = 8;
1853 pf.bshift = 0;
90a1e3c0
AL
1854 pf.rbits = 8;
1855 pf.gbits = 8;
1856 pf.bbits = 8;
0eba62e0 1857 break;
7d957bd8
AL
1858 case 32:
1859 pf.rmask = 0x00FF0000;
1860 pf.gmask = 0x0000FF00;
1861 pf.bmask = 0x000000FF;
1862 pf.rmax = 255;
1863 pf.gmax = 255;
1864 pf.bmax = 255;
1865 pf.rshift = 16;
1866 pf.gshift = 8;
1867 pf.bshift = 0;
90a1e3c0
AL
1868 pf.rbits = 8;
1869 pf.gbits = 8;
1870 pf.bbits = 8;
7d957bd8
AL
1871 break;
1872 default:
1873 break;
1874 }
1875 return pf;
1876}
01f45d98 1877
702ec69c
GH
1878static void qemu_chr_parse_vc(QemuOpts *opts, ChardevBackend *backend,
1879 Error **errp)
1880{
1881 int val;
1882
1883 backend->vc = g_new0(ChardevVC, 1);
1884
1885 val = qemu_opt_get_number(opts, "width", 0);
1886 if (val != 0) {
1887 backend->vc->has_width = true;
1888 backend->vc->width = val;
1889 }
1890
1891 val = qemu_opt_get_number(opts, "height", 0);
1892 if (val != 0) {
1893 backend->vc->has_height = true;
1894 backend->vc->height = val;
1895 }
1896
1897 val = qemu_opt_get_number(opts, "cols", 0);
1898 if (val != 0) {
1899 backend->vc->has_cols = true;
1900 backend->vc->cols = val;
1901 }
1902
1903 val = qemu_opt_get_number(opts, "rows", 0);
1904 if (val != 0) {
1905 backend->vc->has_rows = true;
1906 backend->vc->rows = val;
1907 }
1908}
1909
01f45d98
AL
1910static void register_types(void)
1911{
702ec69c
GH
1912 register_char_driver_qapi("vc", CHARDEV_BACKEND_KIND_VC,
1913 qemu_chr_parse_vc);
01f45d98
AL
1914}
1915
1916type_init(register_types);