blob: 27b165975bea470295380b4e5eab00ee56a53974 [file] [log] [blame]
bellarde7f0ad52004-07-14 17:28:59 +00001/*
2 * QEMU graphical console
ths5fafdf22007-09-16 21:08:06 +00003 *
bellarde7f0ad52004-07-14 17:28:59 +00004 * Copyright (c) 2004 Fabrice Bellard
ths5fafdf22007-09-16 21:08:06 +00005 *
bellarde7f0ad52004-07-14 17:28:59 +00006 * 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 */
pbrook87ecb682007-11-17 17:14:51 +000024#include "qemu-common.h"
Paolo Bonzini28ecbae2012-11-28 12:06:30 +010025#include "ui/console.h"
Paolo Bonzini1de7afc2012-12-17 18:20:00 +010026#include "qemu/timer.h"
Luiz Capitulinoad39cf62012-05-24 13:48:23 -030027#include "qmp-commands.h"
Paolo Bonzini927d4872012-12-17 18:20:05 +010028#include "char/char.h"
bellarde7f0ad52004-07-14 17:28:59 +000029
pbrook6d6f7c22006-03-11 15:35:30 +000030//#define DEBUG_CONSOLE
bellarde7f0ad52004-07-14 17:28:59 +000031#define DEFAULT_BACKSCROLL 512
32#define MAX_CONSOLES 12
Jan Kiszkabf1bed82012-07-10 22:00:55 +020033#define CONSOLE_CURSOR_PERIOD 500
bellarde7f0ad52004-07-14 17:28:59 +000034
bellard26489842006-06-25 17:37:36 +000035#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)
bellarde7f0ad52004-07-14 17:28:59 +000037
pbrook6d6f7c22006-03-11 15:35:30 +000038typedef 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
bellarde7f0ad52004-07-14 17:28:59 +000048typedef struct TextCell {
49 uint8_t ch;
pbrook6d6f7c22006-03-11 15:35:30 +000050 TextAttributes t_attrib;
bellarde7f0ad52004-07-14 17:28:59 +000051} 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
bellarde15d7372006-06-25 16:26:29 +000061typedef struct QEMUFIFO {
62 uint8_t *buf;
63 int buf_size;
64 int count, wptr, rptr;
65} QEMUFIFO;
66
pbrook9596ebb2007-11-18 01:44:38 +000067static int qemu_fifo_write(QEMUFIFO *f, const uint8_t *buf, int len1)
bellarde15d7372006-06-25 16:26:29 +000068{
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
pbrook9596ebb2007-11-18 01:44:38 +000090static int qemu_fifo_read(QEMUFIFO *f, uint8_t *buf, int len1)
bellarde15d7372006-06-25 16:26:29 +000091{
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
thsaf3a9032007-07-11 23:14:59 +0000112typedef enum {
113 GRAPHIC_CONSOLE,
balrogc21bbcf2008-09-24 03:32:33 +0000114 TEXT_CONSOLE,
115 TEXT_CONSOLE_FIXED_SIZE
Anthony Liguoric227f092009-10-01 16:12:16 -0500116} console_type_t;
thsaf3a9032007-07-11 23:14:59 +0000117
Gerd Hoffmann76ffb0b2012-09-28 13:24:17 +0200118struct QemuConsole {
Jan Kiszkaf81bdef2011-09-16 00:48:07 +0200119 int index;
Anthony Liguoric227f092009-10-01 16:12:16 -0500120 console_type_t console_type;
bellarde7f0ad52004-07-14 17:28:59 +0000121 DisplayState *ds;
Gerd Hoffmann76ffb0b2012-09-28 13:24:17 +0200122
pbrook95219892006-04-09 01:06:34 +0000123 /* 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;
balrog4d3b6f62008-02-10 16:33:14 +0000127 vga_hw_text_update_ptr hw_text_update;
pbrook95219892006-04-09 01:06:34 +0000128 void *hw;
bellarde7f0ad52004-07-14 17:28:59 +0000129 int g_width, g_height;
Gerd Hoffmann76ffb0b2012-09-28 13:24:17 +0200130
131 /* Text console state */
bellarde7f0ad52004-07-14 17:28:59 +0000132 int width;
133 int height;
134 int total_height;
135 int backscroll_height;
bellarde7f0ad52004-07-14 17:28:59 +0000136 int x, y;
thsadb47962007-01-16 23:02:36 +0000137 int x_saved, y_saved;
bellarde7f0ad52004-07-14 17:28:59 +0000138 int y_displayed;
139 int y_base;
pbrook6d6f7c22006-03-11 15:35:30 +0000140 TextAttributes t_attrib_default; /* default text attributes */
141 TextAttributes t_attrib; /* currently active text attributes */
bellarde7f0ad52004-07-14 17:28:59 +0000142 TextCell *cells;
balrog4d3b6f62008-02-10 16:33:14 +0000143 int text_x[2], text_y[2], cursor_invalidate;
Paolo Bonzini41048332010-12-23 13:42:52 +0100144 int echo;
Jan Kiszkabf1bed82012-07-10 22:00:55 +0200145 bool cursor_visible_phase;
146 QEMUTimer *cursor_timer;
bellarde7f0ad52004-07-14 17:28:59 +0000147
pbrook14778c22009-01-21 03:02:52 +0000148 int update_x0;
149 int update_y0;
150 int update_x1;
151 int update_y1;
152
bellarde7f0ad52004-07-14 17:28:59 +0000153 enum TTYState state;
154 int esc_params[MAX_ESC_PARAMS];
155 int nb_esc_params;
156
pbrooke5b0bc42007-01-27 23:46:43 +0000157 CharDriverState *chr;
bellarde15d7372006-06-25 16:26:29 +0000158 /* fifo for key pressed */
159 QEMUFIFO out_fifo;
160 uint8_t out_fifo_buf[16];
161 QEMUTimer *kbd_timer;
bellarde7f0ad52004-07-14 17:28:59 +0000162};
163
Paolo Bonzini98b50082010-02-11 00:29:57 +0100164static DisplayState *display_state;
Gerd Hoffmann76ffb0b2012-09-28 13:24:17 +0200165static QemuConsole *active_console;
166static QemuConsole *consoles[MAX_CONSOLES];
bellarde7f0ad52004-07-14 17:28:59 +0000167static int nb_consoles = 0;
168
pbrook95219892006-04-09 01:06:34 +0000169void vga_hw_update(void)
170{
thsadb47962007-01-16 23:02:36 +0000171 if (active_console && active_console->hw_update)
pbrook95219892006-04-09 01:06:34 +0000172 active_console->hw_update(active_console->hw);
173}
174
175void vga_hw_invalidate(void)
176{
Gerd Hoffmann26572b82010-05-20 15:23:06 +0200177 if (active_console && active_console->hw_invalidate)
pbrook95219892006-04-09 01:06:34 +0000178 active_console->hw_invalidate(active_console->hw);
179}
180
Luiz Capitulinoad39cf62012-05-24 13:48:23 -0300181void qmp_screendump(const char *filename, Error **errp)
pbrook95219892006-04-09 01:06:34 +0000182{
Gerd Hoffmann76ffb0b2012-09-28 13:24:17 +0200183 QemuConsole *previous_active_console;
Gerd Hoffmann45efb162012-02-24 12:43:45 +0100184 bool cswitch;
balrog8571c052008-07-19 13:04:26 +0000185
186 previous_active_console = active_console;
Gerd Hoffmann45efb162012-02-24 12:43:45 +0100187 cswitch = previous_active_console && previous_active_console->index != 0;
Jan Kiszkaf81bdef2011-09-16 00:48:07 +0200188
balrog8571c052008-07-19 13:04:26 +0000189 /* There is currently no way of specifying which screen we want to dump,
aurel327b455222008-09-02 00:09:16 +0000190 so always dump the first one. */
Gerd Hoffmann45efb162012-02-24 12:43:45 +0100191 if (cswitch) {
192 console_select(0);
193 }
Jan Kiszkaf81bdef2011-09-16 00:48:07 +0200194 if (consoles[0] && consoles[0]->hw_screen_dump) {
Luiz Capitulinoad39cf62012-05-24 13:48:23 -0300195 consoles[0]->hw_screen_dump(consoles[0]->hw, filename, cswitch, errp);
Gerd Hoffmann16735102012-02-24 12:43:44 +0100196 } else {
Markus Armbruster312fd5f2013-02-08 21:22:16 +0100197 error_setg(errp, "device doesn't support screendump");
Jan Kiszkaf81bdef2011-09-16 00:48:07 +0200198 }
199
Gerd Hoffmann45efb162012-02-24 12:43:45 +0100200 if (cswitch) {
Alexander Graf33bcd982011-11-18 16:41:59 +0100201 console_select(previous_active_console->index);
202 }
pbrook95219892006-04-09 01:06:34 +0000203}
204
Anthony Liguoric227f092009-10-01 16:12:16 -0500205void vga_hw_text_update(console_ch_t *chardata)
balrog4d3b6f62008-02-10 16:33:14 +0000206{
207 if (active_console && active_console->hw_text_update)
208 active_console->hw_text_update(active_console->hw, chardata);
209}
210
ths5fafdf22007-09-16 21:08:06 +0000211static void vga_fill_rect (DisplayState *ds,
bellarde7f0ad52004-07-14 17:28:59 +0000212 int posx, int posy, int width, int height, uint32_t color)
213{
214 uint8_t *d, *d1;
215 int x, y, bpp;
ths3b46e622007-09-17 08:09:54 +0000216
aliguori0e1f5a02008-11-24 19:29:13 +0000217 bpp = (ds_get_bits_per_pixel(ds) + 7) >> 3;
218 d1 = ds_get_data(ds) +
219 ds_get_linesize(ds) * posy + bpp * posx;
bellarde7f0ad52004-07-14 17:28:59 +0000220 for (y = 0; y < height; y++) {
221 d = d1;
222 switch(bpp) {
223 case 1:
224 for (x = 0; x < width; x++) {
225 *((uint8_t *)d) = color;
226 d++;
227 }
228 break;
229 case 2:
230 for (x = 0; x < width; x++) {
231 *((uint16_t *)d) = color;
232 d += 2;
233 }
234 break;
235 case 4:
236 for (x = 0; x < width; x++) {
237 *((uint32_t *)d) = color;
238 d += 4;
239 }
240 break;
241 }
aliguori0e1f5a02008-11-24 19:29:13 +0000242 d1 += ds_get_linesize(ds);
bellarde7f0ad52004-07-14 17:28:59 +0000243 }
244}
245
246/* copy from (xs, ys) to (xd, yd) a rectangle of size (w, h) */
247static void vga_bitblt(DisplayState *ds, int xs, int ys, int xd, int yd, int w, int h)
248{
249 const uint8_t *s;
250 uint8_t *d;
251 int wb, y, bpp;
252
aliguori0e1f5a02008-11-24 19:29:13 +0000253 bpp = (ds_get_bits_per_pixel(ds) + 7) >> 3;
bellarde7f0ad52004-07-14 17:28:59 +0000254 wb = w * bpp;
255 if (yd <= ys) {
aliguori0e1f5a02008-11-24 19:29:13 +0000256 s = ds_get_data(ds) +
257 ds_get_linesize(ds) * ys + bpp * xs;
258 d = ds_get_data(ds) +
259 ds_get_linesize(ds) * yd + bpp * xd;
bellarde7f0ad52004-07-14 17:28:59 +0000260 for (y = 0; y < h; y++) {
261 memmove(d, s, wb);
aliguori0e1f5a02008-11-24 19:29:13 +0000262 d += ds_get_linesize(ds);
263 s += ds_get_linesize(ds);
bellarde7f0ad52004-07-14 17:28:59 +0000264 }
265 } else {
aliguori0e1f5a02008-11-24 19:29:13 +0000266 s = ds_get_data(ds) +
267 ds_get_linesize(ds) * (ys + h - 1) + bpp * xs;
268 d = ds_get_data(ds) +
269 ds_get_linesize(ds) * (yd + h - 1) + bpp * xd;
bellarde7f0ad52004-07-14 17:28:59 +0000270 for (y = 0; y < h; y++) {
271 memmove(d, s, wb);
aliguori0e1f5a02008-11-24 19:29:13 +0000272 d -= ds_get_linesize(ds);
273 s -= ds_get_linesize(ds);
bellarde7f0ad52004-07-14 17:28:59 +0000274 }
275 }
276}
277
278/***********************************************************/
279/* basic char display */
280
281#define FONT_HEIGHT 16
282#define FONT_WIDTH 8
283
284#include "vgafont.h"
285
286#define cbswap_32(__x) \
287((uint32_t)( \
288 (((uint32_t)(__x) & (uint32_t)0x000000ffUL) << 24) | \
289 (((uint32_t)(__x) & (uint32_t)0x0000ff00UL) << 8) | \
290 (((uint32_t)(__x) & (uint32_t)0x00ff0000UL) >> 8) | \
291 (((uint32_t)(__x) & (uint32_t)0xff000000UL) >> 24) ))
292
Juan Quintelae2542fe2009-07-27 16:13:06 +0200293#ifdef HOST_WORDS_BIGENDIAN
bellarde7f0ad52004-07-14 17:28:59 +0000294#define PAT(x) x
295#else
296#define PAT(x) cbswap_32(x)
297#endif
298
299static const uint32_t dmask16[16] = {
300 PAT(0x00000000),
301 PAT(0x000000ff),
302 PAT(0x0000ff00),
303 PAT(0x0000ffff),
304 PAT(0x00ff0000),
305 PAT(0x00ff00ff),
306 PAT(0x00ffff00),
307 PAT(0x00ffffff),
308 PAT(0xff000000),
309 PAT(0xff0000ff),
310 PAT(0xff00ff00),
311 PAT(0xff00ffff),
312 PAT(0xffff0000),
313 PAT(0xffff00ff),
314 PAT(0xffffff00),
315 PAT(0xffffffff),
316};
317
318static const uint32_t dmask4[4] = {
319 PAT(0x00000000),
320 PAT(0x0000ffff),
321 PAT(0xffff0000),
322 PAT(0xffffffff),
323};
324
Devin J. Pohlydf00bed2011-09-07 15:44:36 -0400325#ifndef CONFIG_CURSES
pbrook6d6f7c22006-03-11 15:35:30 +0000326enum color_names {
327 COLOR_BLACK = 0,
328 COLOR_RED = 1,
329 COLOR_GREEN = 2,
330 COLOR_YELLOW = 3,
331 COLOR_BLUE = 4,
332 COLOR_MAGENTA = 5,
333 COLOR_CYAN = 6,
334 COLOR_WHITE = 7
335};
Devin J. Pohlydf00bed2011-09-07 15:44:36 -0400336#endif
pbrook6d6f7c22006-03-11 15:35:30 +0000337
338static const uint32_t color_table_rgb[2][8] = {
339 { /* dark */
bellard26489842006-06-25 17:37:36 +0000340 QEMU_RGB(0x00, 0x00, 0x00), /* black */
341 QEMU_RGB(0xaa, 0x00, 0x00), /* red */
342 QEMU_RGB(0x00, 0xaa, 0x00), /* green */
343 QEMU_RGB(0xaa, 0xaa, 0x00), /* yellow */
344 QEMU_RGB(0x00, 0x00, 0xaa), /* blue */
345 QEMU_RGB(0xaa, 0x00, 0xaa), /* magenta */
346 QEMU_RGB(0x00, 0xaa, 0xaa), /* cyan */
347 QEMU_RGB(0xaa, 0xaa, 0xaa), /* white */
pbrook6d6f7c22006-03-11 15:35:30 +0000348 },
349 { /* bright */
bellard26489842006-06-25 17:37:36 +0000350 QEMU_RGB(0x00, 0x00, 0x00), /* black */
351 QEMU_RGB(0xff, 0x00, 0x00), /* red */
352 QEMU_RGB(0x00, 0xff, 0x00), /* green */
353 QEMU_RGB(0xff, 0xff, 0x00), /* yellow */
354 QEMU_RGB(0x00, 0x00, 0xff), /* blue */
355 QEMU_RGB(0xff, 0x00, 0xff), /* magenta */
356 QEMU_RGB(0x00, 0xff, 0xff), /* cyan */
357 QEMU_RGB(0xff, 0xff, 0xff), /* white */
pbrook6d6f7c22006-03-11 15:35:30 +0000358 }
bellarde7f0ad52004-07-14 17:28:59 +0000359};
360
pbrook6d6f7c22006-03-11 15:35:30 +0000361#ifdef DEBUG_CONSOLE
362static void console_print_text_attributes(TextAttributes *t_attrib, char ch)
363{
364 if (t_attrib->bold) {
365 printf("b");
366 } else {
367 printf(" ");
368 }
369 if (t_attrib->uline) {
370 printf("u");
371 } else {
372 printf(" ");
373 }
374 if (t_attrib->blink) {
375 printf("l");
376 } else {
377 printf(" ");
378 }
379 if (t_attrib->invers) {
380 printf("i");
381 } else {
382 printf(" ");
383 }
384 if (t_attrib->unvisible) {
385 printf("n");
386 } else {
387 printf(" ");
388 }
389
390 printf(" fg: %d bg: %d ch:'%2X' '%c'\n", t_attrib->fgcol, t_attrib->bgcol, ch, ch);
391}
392#endif
bellarde7f0ad52004-07-14 17:28:59 +0000393
ths5fafdf22007-09-16 21:08:06 +0000394static void vga_putcharxy(DisplayState *ds, int x, int y, int ch,
pbrook6d6f7c22006-03-11 15:35:30 +0000395 TextAttributes *t_attrib)
bellarde7f0ad52004-07-14 17:28:59 +0000396{
397 uint8_t *d;
398 const uint8_t *font_ptr;
399 unsigned int font_data, linesize, xorcol, bpp;
400 int i;
pbrook6d6f7c22006-03-11 15:35:30 +0000401 unsigned int fgcol, bgcol;
402
403#ifdef DEBUG_CONSOLE
404 printf("x: %2i y: %2i", x, y);
405 console_print_text_attributes(t_attrib, ch);
406#endif
407
408 if (t_attrib->invers) {
Gerd Hoffmanncf6f0542013-03-06 09:50:51 +0100409 bgcol = color_table_rgb[t_attrib->bold][t_attrib->fgcol];
410 fgcol = color_table_rgb[t_attrib->bold][t_attrib->bgcol];
pbrook6d6f7c22006-03-11 15:35:30 +0000411 } else {
Gerd Hoffmanncf6f0542013-03-06 09:50:51 +0100412 fgcol = color_table_rgb[t_attrib->bold][t_attrib->fgcol];
413 bgcol = color_table_rgb[t_attrib->bold][t_attrib->bgcol];
pbrook6d6f7c22006-03-11 15:35:30 +0000414 }
bellarde7f0ad52004-07-14 17:28:59 +0000415
aliguori0e1f5a02008-11-24 19:29:13 +0000416 bpp = (ds_get_bits_per_pixel(ds) + 7) >> 3;
417 d = ds_get_data(ds) +
418 ds_get_linesize(ds) * y * FONT_HEIGHT + bpp * x * FONT_WIDTH;
419 linesize = ds_get_linesize(ds);
bellarde7f0ad52004-07-14 17:28:59 +0000420 font_ptr = vgafont16 + FONT_HEIGHT * ch;
421 xorcol = bgcol ^ fgcol;
aliguori0e1f5a02008-11-24 19:29:13 +0000422 switch(ds_get_bits_per_pixel(ds)) {
bellarde7f0ad52004-07-14 17:28:59 +0000423 case 8:
424 for(i = 0; i < FONT_HEIGHT; i++) {
425 font_data = *font_ptr++;
pbrook6d6f7c22006-03-11 15:35:30 +0000426 if (t_attrib->uline
427 && ((i == FONT_HEIGHT - 2) || (i == FONT_HEIGHT - 3))) {
Markus Armbruster439229c2011-11-04 10:38:29 +0100428 font_data = 0xFF;
pbrook6d6f7c22006-03-11 15:35:30 +0000429 }
bellarde7f0ad52004-07-14 17:28:59 +0000430 ((uint32_t *)d)[0] = (dmask16[(font_data >> 4)] & xorcol) ^ bgcol;
431 ((uint32_t *)d)[1] = (dmask16[(font_data >> 0) & 0xf] & xorcol) ^ bgcol;
432 d += linesize;
433 }
434 break;
435 case 16:
436 case 15:
437 for(i = 0; i < FONT_HEIGHT; i++) {
438 font_data = *font_ptr++;
pbrook6d6f7c22006-03-11 15:35:30 +0000439 if (t_attrib->uline
440 && ((i == FONT_HEIGHT - 2) || (i == FONT_HEIGHT - 3))) {
Markus Armbruster439229c2011-11-04 10:38:29 +0100441 font_data = 0xFF;
pbrook6d6f7c22006-03-11 15:35:30 +0000442 }
bellarde7f0ad52004-07-14 17:28:59 +0000443 ((uint32_t *)d)[0] = (dmask4[(font_data >> 6)] & xorcol) ^ bgcol;
444 ((uint32_t *)d)[1] = (dmask4[(font_data >> 4) & 3] & xorcol) ^ bgcol;
445 ((uint32_t *)d)[2] = (dmask4[(font_data >> 2) & 3] & xorcol) ^ bgcol;
446 ((uint32_t *)d)[3] = (dmask4[(font_data >> 0) & 3] & xorcol) ^ bgcol;
447 d += linesize;
448 }
449 break;
450 case 32:
451 for(i = 0; i < FONT_HEIGHT; i++) {
452 font_data = *font_ptr++;
pbrook6d6f7c22006-03-11 15:35:30 +0000453 if (t_attrib->uline && ((i == FONT_HEIGHT - 2) || (i == FONT_HEIGHT - 3))) {
Markus Armbruster439229c2011-11-04 10:38:29 +0100454 font_data = 0xFF;
pbrook6d6f7c22006-03-11 15:35:30 +0000455 }
bellarde7f0ad52004-07-14 17:28:59 +0000456 ((uint32_t *)d)[0] = (-((font_data >> 7)) & xorcol) ^ bgcol;
457 ((uint32_t *)d)[1] = (-((font_data >> 6) & 1) & xorcol) ^ bgcol;
458 ((uint32_t *)d)[2] = (-((font_data >> 5) & 1) & xorcol) ^ bgcol;
459 ((uint32_t *)d)[3] = (-((font_data >> 4) & 1) & xorcol) ^ bgcol;
460 ((uint32_t *)d)[4] = (-((font_data >> 3) & 1) & xorcol) ^ bgcol;
461 ((uint32_t *)d)[5] = (-((font_data >> 2) & 1) & xorcol) ^ bgcol;
462 ((uint32_t *)d)[6] = (-((font_data >> 1) & 1) & xorcol) ^ bgcol;
463 ((uint32_t *)d)[7] = (-((font_data >> 0) & 1) & xorcol) ^ bgcol;
464 d += linesize;
465 }
466 break;
467 }
468}
469
Gerd Hoffmann76ffb0b2012-09-28 13:24:17 +0200470static void text_console_resize(QemuConsole *s)
bellarde7f0ad52004-07-14 17:28:59 +0000471{
472 TextCell *cells, *c, *c1;
473 int w1, x, y, last_width;
474
475 last_width = s->width;
476 s->width = s->g_width / FONT_WIDTH;
477 s->height = s->g_height / FONT_HEIGHT;
478
479 w1 = last_width;
480 if (s->width < w1)
481 w1 = s->width;
482
Anthony Liguori7267c092011-08-20 22:09:37 -0500483 cells = g_malloc(s->width * s->total_height * sizeof(TextCell));
bellarde7f0ad52004-07-14 17:28:59 +0000484 for(y = 0; y < s->total_height; y++) {
485 c = &cells[y * s->width];
486 if (w1 > 0) {
487 c1 = &s->cells[y * last_width];
488 for(x = 0; x < w1; x++) {
489 *c++ = *c1++;
490 }
491 }
492 for(x = w1; x < s->width; x++) {
493 c->ch = ' ';
pbrook6d6f7c22006-03-11 15:35:30 +0000494 c->t_attrib = s->t_attrib_default;
bellarde7f0ad52004-07-14 17:28:59 +0000495 c++;
496 }
497 }
Anthony Liguori7267c092011-08-20 22:09:37 -0500498 g_free(s->cells);
bellarde7f0ad52004-07-14 17:28:59 +0000499 s->cells = cells;
500}
501
Gerd Hoffmann76ffb0b2012-09-28 13:24:17 +0200502static inline void text_update_xy(QemuConsole *s, int x, int y)
balrog4d3b6f62008-02-10 16:33:14 +0000503{
504 s->text_x[0] = MIN(s->text_x[0], x);
505 s->text_x[1] = MAX(s->text_x[1], x);
506 s->text_y[0] = MIN(s->text_y[0], y);
507 s->text_y[1] = MAX(s->text_y[1], y);
508}
509
Gerd Hoffmann76ffb0b2012-09-28 13:24:17 +0200510static void invalidate_xy(QemuConsole *s, int x, int y)
pbrook14778c22009-01-21 03:02:52 +0000511{
512 if (s->update_x0 > x * FONT_WIDTH)
513 s->update_x0 = x * FONT_WIDTH;
514 if (s->update_y0 > y * FONT_HEIGHT)
515 s->update_y0 = y * FONT_HEIGHT;
516 if (s->update_x1 < (x + 1) * FONT_WIDTH)
517 s->update_x1 = (x + 1) * FONT_WIDTH;
518 if (s->update_y1 < (y + 1) * FONT_HEIGHT)
519 s->update_y1 = (y + 1) * FONT_HEIGHT;
520}
521
Gerd Hoffmann76ffb0b2012-09-28 13:24:17 +0200522static void update_xy(QemuConsole *s, int x, int y)
bellarde7f0ad52004-07-14 17:28:59 +0000523{
524 TextCell *c;
525 int y1, y2;
526
527 if (s == active_console) {
aliguori0e1f5a02008-11-24 19:29:13 +0000528 if (!ds_get_bits_per_pixel(s->ds)) {
balrog4d3b6f62008-02-10 16:33:14 +0000529 text_update_xy(s, x, y);
530 return;
531 }
532
bellarde7f0ad52004-07-14 17:28:59 +0000533 y1 = (s->y_base + y) % s->total_height;
534 y2 = y1 - s->y_displayed;
535 if (y2 < 0)
536 y2 += s->total_height;
537 if (y2 < s->height) {
538 c = &s->cells[y1 * s->width + x];
ths5fafdf22007-09-16 21:08:06 +0000539 vga_putcharxy(s->ds, x, y2, c->ch,
pbrook6d6f7c22006-03-11 15:35:30 +0000540 &(c->t_attrib));
pbrook14778c22009-01-21 03:02:52 +0000541 invalidate_xy(s, x, y2);
bellarde7f0ad52004-07-14 17:28:59 +0000542 }
543 }
544}
545
Gerd Hoffmann76ffb0b2012-09-28 13:24:17 +0200546static void console_show_cursor(QemuConsole *s, int show)
bellarde7f0ad52004-07-14 17:28:59 +0000547{
548 TextCell *c;
549 int y, y1;
550
551 if (s == active_console) {
thsed8276a2007-02-10 22:37:56 +0000552 int x = s->x;
balrog4d3b6f62008-02-10 16:33:14 +0000553
aliguori0e1f5a02008-11-24 19:29:13 +0000554 if (!ds_get_bits_per_pixel(s->ds)) {
balrog4d3b6f62008-02-10 16:33:14 +0000555 s->cursor_invalidate = 1;
556 return;
557 }
558
thsed8276a2007-02-10 22:37:56 +0000559 if (x >= s->width) {
560 x = s->width - 1;
561 }
bellarde7f0ad52004-07-14 17:28:59 +0000562 y1 = (s->y_base + s->y) % s->total_height;
563 y = y1 - s->y_displayed;
564 if (y < 0)
565 y += s->total_height;
566 if (y < s->height) {
thsed8276a2007-02-10 22:37:56 +0000567 c = &s->cells[y1 * s->width + x];
Jan Kiszkabf1bed82012-07-10 22:00:55 +0200568 if (show && s->cursor_visible_phase) {
pbrook6d6f7c22006-03-11 15:35:30 +0000569 TextAttributes t_attrib = s->t_attrib_default;
570 t_attrib.invers = !(t_attrib.invers); /* invert fg and bg */
thsed8276a2007-02-10 22:37:56 +0000571 vga_putcharxy(s->ds, x, y, c->ch, &t_attrib);
bellarde7f0ad52004-07-14 17:28:59 +0000572 } else {
thsed8276a2007-02-10 22:37:56 +0000573 vga_putcharxy(s->ds, x, y, c->ch, &(c->t_attrib));
bellarde7f0ad52004-07-14 17:28:59 +0000574 }
pbrook14778c22009-01-21 03:02:52 +0000575 invalidate_xy(s, x, y);
bellarde7f0ad52004-07-14 17:28:59 +0000576 }
577 }
578}
579
Gerd Hoffmann76ffb0b2012-09-28 13:24:17 +0200580static void console_refresh(QemuConsole *s)
bellarde7f0ad52004-07-14 17:28:59 +0000581{
582 TextCell *c;
583 int x, y, y1;
584
ths5fafdf22007-09-16 21:08:06 +0000585 if (s != active_console)
bellarde7f0ad52004-07-14 17:28:59 +0000586 return;
Gerd Hoffmanna93a4a22012-09-28 15:02:08 +0200587
588 if (s->ds->have_text) {
balrog4d3b6f62008-02-10 16:33:14 +0000589 s->text_x[0] = 0;
590 s->text_y[0] = 0;
591 s->text_x[1] = s->width - 1;
592 s->text_y[1] = s->height - 1;
593 s->cursor_invalidate = 1;
balrog4d3b6f62008-02-10 16:33:14 +0000594 }
bellarde7f0ad52004-07-14 17:28:59 +0000595
Gerd Hoffmanna93a4a22012-09-28 15:02:08 +0200596 if (s->ds->have_gfx) {
597 vga_fill_rect(s->ds, 0, 0, ds_get_width(s->ds), ds_get_height(s->ds),
Gerd Hoffmanncf6f0542013-03-06 09:50:51 +0100598 color_table_rgb[0][COLOR_BLACK]);
Gerd Hoffmanna93a4a22012-09-28 15:02:08 +0200599 y1 = s->y_displayed;
600 for (y = 0; y < s->height; y++) {
601 c = s->cells + y1 * s->width;
602 for (x = 0; x < s->width; x++) {
603 vga_putcharxy(s->ds, x, y, c->ch,
604 &(c->t_attrib));
605 c++;
606 }
607 if (++y1 == s->total_height) {
608 y1 = 0;
609 }
bellarde7f0ad52004-07-14 17:28:59 +0000610 }
Gerd Hoffmanna93a4a22012-09-28 15:02:08 +0200611 console_show_cursor(s, 1);
Gerd Hoffmannc78f7132013-03-05 15:24:14 +0100612 dpy_gfx_update(s, 0, 0, ds_get_width(s->ds), ds_get_height(s->ds));
bellarde7f0ad52004-07-14 17:28:59 +0000613 }
bellarde7f0ad52004-07-14 17:28:59 +0000614}
615
616static void console_scroll(int ydelta)
617{
Gerd Hoffmann76ffb0b2012-09-28 13:24:17 +0200618 QemuConsole *s;
bellarde7f0ad52004-07-14 17:28:59 +0000619 int i, y1;
ths3b46e622007-09-17 08:09:54 +0000620
bellarde7f0ad52004-07-14 17:28:59 +0000621 s = active_console;
thsaf3a9032007-07-11 23:14:59 +0000622 if (!s || (s->console_type == GRAPHIC_CONSOLE))
bellarde7f0ad52004-07-14 17:28:59 +0000623 return;
624
625 if (ydelta > 0) {
626 for(i = 0; i < ydelta; i++) {
627 if (s->y_displayed == s->y_base)
628 break;
629 if (++s->y_displayed == s->total_height)
630 s->y_displayed = 0;
631 }
632 } else {
633 ydelta = -ydelta;
634 i = s->backscroll_height;
635 if (i > s->total_height - s->height)
636 i = s->total_height - s->height;
637 y1 = s->y_base - i;
638 if (y1 < 0)
639 y1 += s->total_height;
640 for(i = 0; i < ydelta; i++) {
641 if (s->y_displayed == y1)
642 break;
643 if (--s->y_displayed < 0)
644 s->y_displayed = s->total_height - 1;
645 }
646 }
647 console_refresh(s);
648}
649
Gerd Hoffmann76ffb0b2012-09-28 13:24:17 +0200650static void console_put_lf(QemuConsole *s)
bellarde7f0ad52004-07-14 17:28:59 +0000651{
652 TextCell *c;
653 int x, y1;
654
bellarde7f0ad52004-07-14 17:28:59 +0000655 s->y++;
656 if (s->y >= s->height) {
657 s->y = s->height - 1;
pbrook6d6f7c22006-03-11 15:35:30 +0000658
bellarde7f0ad52004-07-14 17:28:59 +0000659 if (s->y_displayed == s->y_base) {
660 if (++s->y_displayed == s->total_height)
661 s->y_displayed = 0;
662 }
663 if (++s->y_base == s->total_height)
664 s->y_base = 0;
665 if (s->backscroll_height < s->total_height)
666 s->backscroll_height++;
667 y1 = (s->y_base + s->height - 1) % s->total_height;
668 c = &s->cells[y1 * s->width];
669 for(x = 0; x < s->width; x++) {
670 c->ch = ' ';
pbrook6d6f7c22006-03-11 15:35:30 +0000671 c->t_attrib = s->t_attrib_default;
bellarde7f0ad52004-07-14 17:28:59 +0000672 c++;
673 }
674 if (s == active_console && s->y_displayed == s->y_base) {
aliguori0e1f5a02008-11-24 19:29:13 +0000675 if (!ds_get_bits_per_pixel(s->ds)) {
balrog4d3b6f62008-02-10 16:33:14 +0000676 s->text_x[0] = 0;
677 s->text_y[0] = 0;
678 s->text_x[1] = s->width - 1;
679 s->text_y[1] = s->height - 1;
680 return;
681 }
682
ths5fafdf22007-09-16 21:08:06 +0000683 vga_bitblt(s->ds, 0, FONT_HEIGHT, 0, 0,
684 s->width * FONT_WIDTH,
bellarde7f0ad52004-07-14 17:28:59 +0000685 (s->height - 1) * FONT_HEIGHT);
686 vga_fill_rect(s->ds, 0, (s->height - 1) * FONT_HEIGHT,
ths5fafdf22007-09-16 21:08:06 +0000687 s->width * FONT_WIDTH, FONT_HEIGHT,
Gerd Hoffmanncf6f0542013-03-06 09:50:51 +0100688 color_table_rgb[0][s->t_attrib_default.bgcol]);
pbrook14778c22009-01-21 03:02:52 +0000689 s->update_x0 = 0;
690 s->update_y0 = 0;
691 s->update_x1 = s->width * FONT_WIDTH;
692 s->update_y1 = s->height * FONT_HEIGHT;
bellarde7f0ad52004-07-14 17:28:59 +0000693 }
694 }
695}
696
pbrook6d6f7c22006-03-11 15:35:30 +0000697/* Set console attributes depending on the current escape codes.
698 * NOTE: I know this code is not very efficient (checking every color for it
699 * self) but it is more readable and better maintainable.
700 */
Gerd Hoffmann76ffb0b2012-09-28 13:24:17 +0200701static void console_handle_escape(QemuConsole *s)
pbrook6d6f7c22006-03-11 15:35:30 +0000702{
703 int i;
704
pbrook6d6f7c22006-03-11 15:35:30 +0000705 for (i=0; i<s->nb_esc_params; i++) {
706 switch (s->esc_params[i]) {
707 case 0: /* reset all console attributes to default */
708 s->t_attrib = s->t_attrib_default;
709 break;
710 case 1:
711 s->t_attrib.bold = 1;
712 break;
713 case 4:
714 s->t_attrib.uline = 1;
715 break;
716 case 5:
717 s->t_attrib.blink = 1;
718 break;
719 case 7:
720 s->t_attrib.invers = 1;
721 break;
722 case 8:
723 s->t_attrib.unvisible = 1;
724 break;
725 case 22:
726 s->t_attrib.bold = 0;
727 break;
728 case 24:
729 s->t_attrib.uline = 0;
730 break;
731 case 25:
732 s->t_attrib.blink = 0;
733 break;
734 case 27:
735 s->t_attrib.invers = 0;
736 break;
737 case 28:
738 s->t_attrib.unvisible = 0;
739 break;
740 /* set foreground color */
741 case 30:
742 s->t_attrib.fgcol=COLOR_BLACK;
743 break;
744 case 31:
745 s->t_attrib.fgcol=COLOR_RED;
746 break;
747 case 32:
748 s->t_attrib.fgcol=COLOR_GREEN;
749 break;
750 case 33:
751 s->t_attrib.fgcol=COLOR_YELLOW;
752 break;
753 case 34:
754 s->t_attrib.fgcol=COLOR_BLUE;
755 break;
756 case 35:
757 s->t_attrib.fgcol=COLOR_MAGENTA;
758 break;
759 case 36:
760 s->t_attrib.fgcol=COLOR_CYAN;
761 break;
762 case 37:
763 s->t_attrib.fgcol=COLOR_WHITE;
764 break;
765 /* set background color */
766 case 40:
767 s->t_attrib.bgcol=COLOR_BLACK;
768 break;
769 case 41:
770 s->t_attrib.bgcol=COLOR_RED;
771 break;
772 case 42:
773 s->t_attrib.bgcol=COLOR_GREEN;
774 break;
775 case 43:
776 s->t_attrib.bgcol=COLOR_YELLOW;
777 break;
778 case 44:
779 s->t_attrib.bgcol=COLOR_BLUE;
780 break;
781 case 45:
782 s->t_attrib.bgcol=COLOR_MAGENTA;
783 break;
784 case 46:
785 s->t_attrib.bgcol=COLOR_CYAN;
786 break;
787 case 47:
788 s->t_attrib.bgcol=COLOR_WHITE;
789 break;
790 }
791 }
792}
793
Gerd Hoffmann76ffb0b2012-09-28 13:24:17 +0200794static void console_clear_xy(QemuConsole *s, int x, int y)
thsadb47962007-01-16 23:02:36 +0000795{
796 int y1 = (s->y_base + y) % s->total_height;
797 TextCell *c = &s->cells[y1 * s->width + x];
798 c->ch = ' ';
799 c->t_attrib = s->t_attrib_default;
thsadb47962007-01-16 23:02:36 +0000800 update_xy(s, x, y);
801}
802
Ian Campbell3eea5492012-09-04 10:26:09 -0500803/* set cursor, checking bounds */
Gerd Hoffmann76ffb0b2012-09-28 13:24:17 +0200804static void set_cursor(QemuConsole *s, int x, int y)
Ian Campbell3eea5492012-09-04 10:26:09 -0500805{
806 if (x < 0) {
807 x = 0;
808 }
809 if (y < 0) {
810 y = 0;
811 }
812 if (y >= s->height) {
813 y = s->height - 1;
814 }
815 if (x >= s->width) {
816 x = s->width - 1;
817 }
818
819 s->x = x;
820 s->y = y;
821}
822
Gerd Hoffmann76ffb0b2012-09-28 13:24:17 +0200823static void console_putchar(QemuConsole *s, int ch)
bellarde7f0ad52004-07-14 17:28:59 +0000824{
825 TextCell *c;
thsadb47962007-01-16 23:02:36 +0000826 int y1, i;
827 int x, y;
bellarde7f0ad52004-07-14 17:28:59 +0000828
829 switch(s->state) {
830 case TTY_STATE_NORM:
831 switch(ch) {
pbrook6d6f7c22006-03-11 15:35:30 +0000832 case '\r': /* carriage return */
bellarde7f0ad52004-07-14 17:28:59 +0000833 s->x = 0;
834 break;
pbrook6d6f7c22006-03-11 15:35:30 +0000835 case '\n': /* newline */
bellarde7f0ad52004-07-14 17:28:59 +0000836 console_put_lf(s);
837 break;
pbrook6d6f7c22006-03-11 15:35:30 +0000838 case '\b': /* backspace */
ths5fafdf22007-09-16 21:08:06 +0000839 if (s->x > 0)
bellarde15d7372006-06-25 16:26:29 +0000840 s->x--;
pbrook6d6f7c22006-03-11 15:35:30 +0000841 break;
842 case '\t': /* tabspace */
843 if (s->x + (8 - (s->x % 8)) > s->width) {
bellardbd468842006-07-14 20:24:31 +0000844 s->x = 0;
pbrook6d6f7c22006-03-11 15:35:30 +0000845 console_put_lf(s);
846 } else {
847 s->x = s->x + (8 - (s->x % 8));
848 }
849 break;
850 case '\a': /* alert aka. bell */
851 /* TODO: has to be implemented */
852 break;
thsadb47962007-01-16 23:02:36 +0000853 case 14:
854 /* SI (shift in), character set 0 (ignored) */
855 break;
856 case 15:
857 /* SO (shift out), character set 1 (ignored) */
858 break;
pbrook6d6f7c22006-03-11 15:35:30 +0000859 case 27: /* esc (introducing an escape sequence) */
bellarde7f0ad52004-07-14 17:28:59 +0000860 s->state = TTY_STATE_ESC;
861 break;
862 default:
thsed8276a2007-02-10 22:37:56 +0000863 if (s->x >= s->width) {
864 /* line wrap */
865 s->x = 0;
866 console_put_lf(s);
thsadb47962007-01-16 23:02:36 +0000867 }
bellarde7f0ad52004-07-14 17:28:59 +0000868 y1 = (s->y_base + s->y) % s->total_height;
869 c = &s->cells[y1 * s->width + s->x];
870 c->ch = ch;
pbrook6d6f7c22006-03-11 15:35:30 +0000871 c->t_attrib = s->t_attrib;
bellarde7f0ad52004-07-14 17:28:59 +0000872 update_xy(s, s->x, s->y);
873 s->x++;
bellarde7f0ad52004-07-14 17:28:59 +0000874 break;
875 }
876 break;
pbrook6d6f7c22006-03-11 15:35:30 +0000877 case TTY_STATE_ESC: /* check if it is a terminal escape sequence */
bellarde7f0ad52004-07-14 17:28:59 +0000878 if (ch == '[') {
879 for(i=0;i<MAX_ESC_PARAMS;i++)
880 s->esc_params[i] = 0;
881 s->nb_esc_params = 0;
882 s->state = TTY_STATE_CSI;
883 } else {
884 s->state = TTY_STATE_NORM;
885 }
886 break;
pbrook6d6f7c22006-03-11 15:35:30 +0000887 case TTY_STATE_CSI: /* handle escape sequence parameters */
bellarde7f0ad52004-07-14 17:28:59 +0000888 if (ch >= '0' && ch <= '9') {
889 if (s->nb_esc_params < MAX_ESC_PARAMS) {
Laszlo Ersekc10600a2012-09-17 11:10:03 +0200890 int *param = &s->esc_params[s->nb_esc_params];
891 int digit = (ch - '0');
892
893 *param = (*param <= (INT_MAX - digit) / 10) ?
894 *param * 10 + digit : INT_MAX;
bellarde7f0ad52004-07-14 17:28:59 +0000895 }
896 } else {
Ian Campbell3eea5492012-09-04 10:26:09 -0500897 if (s->nb_esc_params < MAX_ESC_PARAMS)
898 s->nb_esc_params++;
bellarde7f0ad52004-07-14 17:28:59 +0000899 if (ch == ';')
900 break;
thsadb47962007-01-16 23:02:36 +0000901#ifdef DEBUG_CONSOLE
902 fprintf(stderr, "escape sequence CSI%d;%d%c, %d parameters\n",
903 s->esc_params[0], s->esc_params[1], ch, s->nb_esc_params);
904#endif
bellarde7f0ad52004-07-14 17:28:59 +0000905 s->state = TTY_STATE_NORM;
906 switch(ch) {
thsadb47962007-01-16 23:02:36 +0000907 case 'A':
908 /* move cursor up */
909 if (s->esc_params[0] == 0) {
910 s->esc_params[0] = 1;
911 }
Ian Campbell3eea5492012-09-04 10:26:09 -0500912 set_cursor(s, s->x, s->y - s->esc_params[0]);
bellarde7f0ad52004-07-14 17:28:59 +0000913 break;
thsadb47962007-01-16 23:02:36 +0000914 case 'B':
915 /* move cursor down */
916 if (s->esc_params[0] == 0) {
917 s->esc_params[0] = 1;
918 }
Ian Campbell3eea5492012-09-04 10:26:09 -0500919 set_cursor(s, s->x, s->y + s->esc_params[0]);
thsadb47962007-01-16 23:02:36 +0000920 break;
921 case 'C':
922 /* move cursor right */
923 if (s->esc_params[0] == 0) {
924 s->esc_params[0] = 1;
925 }
Ian Campbell3eea5492012-09-04 10:26:09 -0500926 set_cursor(s, s->x + s->esc_params[0], s->y);
thsadb47962007-01-16 23:02:36 +0000927 break;
928 case 'D':
929 /* move cursor left */
930 if (s->esc_params[0] == 0) {
931 s->esc_params[0] = 1;
932 }
Ian Campbell3eea5492012-09-04 10:26:09 -0500933 set_cursor(s, s->x - s->esc_params[0], s->y);
thsadb47962007-01-16 23:02:36 +0000934 break;
935 case 'G':
936 /* move cursor to column */
Ian Campbell3eea5492012-09-04 10:26:09 -0500937 set_cursor(s, s->esc_params[0] - 1, s->y);
thsadb47962007-01-16 23:02:36 +0000938 break;
939 case 'f':
940 case 'H':
941 /* move cursor to row, column */
Ian Campbell3eea5492012-09-04 10:26:09 -0500942 set_cursor(s, s->esc_params[1] - 1, s->esc_params[0] - 1);
thsadb47962007-01-16 23:02:36 +0000943 break;
944 case 'J':
945 switch (s->esc_params[0]) {
946 case 0:
947 /* clear to end of screen */
948 for (y = s->y; y < s->height; y++) {
949 for (x = 0; x < s->width; x++) {
950 if (y == s->y && x < s->x) {
951 continue;
952 }
953 console_clear_xy(s, x, y);
954 }
955 }
956 break;
957 case 1:
958 /* clear from beginning of screen */
959 for (y = 0; y <= s->y; y++) {
960 for (x = 0; x < s->width; x++) {
961 if (y == s->y && x > s->x) {
962 break;
963 }
964 console_clear_xy(s, x, y);
965 }
966 }
967 break;
968 case 2:
969 /* clear entire screen */
970 for (y = 0; y <= s->height; y++) {
971 for (x = 0; x < s->width; x++) {
972 console_clear_xy(s, x, y);
973 }
974 }
Markus Armbrusterf94a9502011-11-22 11:59:06 +0100975 break;
thsadb47962007-01-16 23:02:36 +0000976 }
Markus Armbruster95d8f9f2011-11-22 11:59:07 +0100977 break;
thsadb47962007-01-16 23:02:36 +0000978 case 'K':
979 switch (s->esc_params[0]) {
980 case 0:
Markus Armbrusterf94a9502011-11-22 11:59:06 +0100981 /* clear to eol */
982 for(x = s->x; x < s->width; x++) {
thsadb47962007-01-16 23:02:36 +0000983 console_clear_xy(s, x, s->y);
Markus Armbrusterf94a9502011-11-22 11:59:06 +0100984 }
985 break;
thsadb47962007-01-16 23:02:36 +0000986 case 1:
987 /* clear from beginning of line */
988 for (x = 0; x <= s->x; x++) {
989 console_clear_xy(s, x, s->y);
990 }
991 break;
992 case 2:
993 /* clear entire line */
994 for(x = 0; x < s->width; x++) {
995 console_clear_xy(s, x, s->y);
996 }
Markus Armbrusterf94a9502011-11-22 11:59:06 +0100997 break;
998 }
thsadb47962007-01-16 23:02:36 +0000999 break;
1000 case 'm':
Markus Armbrusterf94a9502011-11-22 11:59:06 +01001001 console_handle_escape(s);
1002 break;
thsadb47962007-01-16 23:02:36 +00001003 case 'n':
1004 /* report cursor position */
1005 /* TODO: send ESC[row;colR */
1006 break;
1007 case 's':
1008 /* save cursor position */
1009 s->x_saved = s->x;
1010 s->y_saved = s->y;
1011 break;
1012 case 'u':
1013 /* restore cursor position */
1014 s->x = s->x_saved;
1015 s->y = s->y_saved;
1016 break;
1017 default:
1018#ifdef DEBUG_CONSOLE
1019 fprintf(stderr, "unhandled escape character '%c'\n", ch);
1020#endif
1021 break;
1022 }
1023 break;
bellarde7f0ad52004-07-14 17:28:59 +00001024 }
1025 }
1026}
1027
1028void console_select(unsigned int index)
1029{
Gerd Hoffmann76ffb0b2012-09-28 13:24:17 +02001030 QemuConsole *s;
pbrook6d6f7c22006-03-11 15:35:30 +00001031
bellarde7f0ad52004-07-14 17:28:59 +00001032 if (index >= MAX_CONSOLES)
1033 return;
Stefan Hajnoczi358664c2010-09-20 14:11:19 +01001034 if (active_console) {
1035 active_console->g_width = ds_get_width(active_console->ds);
1036 active_console->g_height = ds_get_height(active_console->ds);
1037 }
bellarde7f0ad52004-07-14 17:28:59 +00001038 s = consoles[index];
1039 if (s) {
aliguori7d957bd2009-01-15 22:14:11 +00001040 DisplayState *ds = s->ds;
Jan Kiszkabf1bed82012-07-10 22:00:55 +02001041
Stefan Weil8bd6b062012-08-17 15:50:44 +02001042 if (active_console && active_console->cursor_timer) {
Jan Kiszkabf1bed82012-07-10 22:00:55 +02001043 qemu_del_timer(active_console->cursor_timer);
1044 }
bellarde7f0ad52004-07-14 17:28:59 +00001045 active_console = s;
Gerd Hoffmanna93a4a22012-09-28 15:02:08 +02001046 if (ds->have_gfx) {
Gerd Hoffmannda229ef2013-02-28 10:48:02 +01001047 DisplaySurface *surface;
1048 surface = qemu_create_displaysurface(s->g_width, s->g_height);
Gerd Hoffmannc78f7132013-03-05 15:24:14 +01001049 dpy_gfx_replace_surface(s, surface);
Gerd Hoffmanna93a4a22012-09-28 15:02:08 +02001050 }
1051 if (ds->have_text) {
Gerd Hoffmannc78f7132013-03-05 15:24:14 +01001052 dpy_text_resize(s, s->width, s->height);
aliguori68f00992009-01-21 18:59:12 +00001053 }
Jan Kiszkabf1bed82012-07-10 22:00:55 +02001054 if (s->cursor_timer) {
1055 qemu_mod_timer(s->cursor_timer,
1056 qemu_get_clock_ms(rt_clock) + CONSOLE_CURSOR_PERIOD / 2);
1057 }
balrog4d3b6f62008-02-10 16:33:14 +00001058 vga_hw_invalidate();
bellarde7f0ad52004-07-14 17:28:59 +00001059 }
1060}
1061
1062static int console_puts(CharDriverState *chr, const uint8_t *buf, int len)
1063{
Gerd Hoffmann76ffb0b2012-09-28 13:24:17 +02001064 QemuConsole *s = chr->opaque;
bellarde7f0ad52004-07-14 17:28:59 +00001065 int i;
1066
pbrook14778c22009-01-21 03:02:52 +00001067 s->update_x0 = s->width * FONT_WIDTH;
1068 s->update_y0 = s->height * FONT_HEIGHT;
1069 s->update_x1 = 0;
1070 s->update_y1 = 0;
bellarde7f0ad52004-07-14 17:28:59 +00001071 console_show_cursor(s, 0);
1072 for(i = 0; i < len; i++) {
1073 console_putchar(s, buf[i]);
1074 }
1075 console_show_cursor(s, 1);
Gerd Hoffmanna93a4a22012-09-28 15:02:08 +02001076 if (s->ds->have_gfx && s->update_x0 < s->update_x1) {
Gerd Hoffmannc78f7132013-03-05 15:24:14 +01001077 dpy_gfx_update(s, s->update_x0, s->update_y0,
Gerd Hoffmanna93a4a22012-09-28 15:02:08 +02001078 s->update_x1 - s->update_x0,
1079 s->update_y1 - s->update_y0);
pbrook14778c22009-01-21 03:02:52 +00001080 }
bellarde7f0ad52004-07-14 17:28:59 +00001081 return len;
1082}
1083
bellarde15d7372006-06-25 16:26:29 +00001084static void kbd_send_chars(void *opaque)
1085{
Gerd Hoffmann76ffb0b2012-09-28 13:24:17 +02001086 QemuConsole *s = opaque;
bellarde15d7372006-06-25 16:26:29 +00001087 int len;
1088 uint8_t buf[16];
ths3b46e622007-09-17 08:09:54 +00001089
Anthony Liguori909cda12011-08-15 11:17:31 -05001090 len = qemu_chr_be_can_write(s->chr);
bellarde15d7372006-06-25 16:26:29 +00001091 if (len > s->out_fifo.count)
1092 len = s->out_fifo.count;
1093 if (len > 0) {
1094 if (len > sizeof(buf))
1095 len = sizeof(buf);
1096 qemu_fifo_read(&s->out_fifo, buf, len);
Anthony Liguorifa5efcc2011-08-15 11:17:30 -05001097 qemu_chr_be_write(s->chr, buf, len);
bellarde15d7372006-06-25 16:26:29 +00001098 }
1099 /* characters are pending: we send them a bit later (XXX:
1100 horrible, should change char device API) */
1101 if (s->out_fifo.count > 0) {
Paolo Bonzini7bd427d2011-03-11 16:47:48 +01001102 qemu_mod_timer(s->kbd_timer, qemu_get_clock_ms(rt_clock) + 1);
bellarde15d7372006-06-25 16:26:29 +00001103 }
1104}
1105
bellarde7f0ad52004-07-14 17:28:59 +00001106/* called when an ascii key is pressed */
1107void kbd_put_keysym(int keysym)
1108{
Gerd Hoffmann76ffb0b2012-09-28 13:24:17 +02001109 QemuConsole *s;
bellarde7f0ad52004-07-14 17:28:59 +00001110 uint8_t buf[16], *q;
1111 int c;
1112
1113 s = active_console;
thsaf3a9032007-07-11 23:14:59 +00001114 if (!s || (s->console_type == GRAPHIC_CONSOLE))
bellarde7f0ad52004-07-14 17:28:59 +00001115 return;
1116
1117 switch(keysym) {
1118 case QEMU_KEY_CTRL_UP:
1119 console_scroll(-1);
1120 break;
1121 case QEMU_KEY_CTRL_DOWN:
1122 console_scroll(1);
1123 break;
1124 case QEMU_KEY_CTRL_PAGEUP:
1125 console_scroll(-10);
1126 break;
1127 case QEMU_KEY_CTRL_PAGEDOWN:
1128 console_scroll(10);
1129 break;
1130 default:
bellarde15d7372006-06-25 16:26:29 +00001131 /* convert the QEMU keysym to VT100 key string */
1132 q = buf;
1133 if (keysym >= 0xe100 && keysym <= 0xe11f) {
1134 *q++ = '\033';
1135 *q++ = '[';
1136 c = keysym - 0xe100;
1137 if (c >= 10)
1138 *q++ = '0' + (c / 10);
1139 *q++ = '0' + (c % 10);
1140 *q++ = '~';
1141 } else if (keysym >= 0xe120 && keysym <= 0xe17f) {
1142 *q++ = '\033';
1143 *q++ = '[';
1144 *q++ = keysym & 0xff;
Paolo Bonzini41048332010-12-23 13:42:52 +01001145 } else if (s->echo && (keysym == '\r' || keysym == '\n')) {
1146 console_puts(s->chr, (const uint8_t *) "\r", 1);
1147 *q++ = '\n';
bellarde15d7372006-06-25 16:26:29 +00001148 } else {
Paolo Bonzini41048332010-12-23 13:42:52 +01001149 *q++ = keysym;
1150 }
1151 if (s->echo) {
1152 console_puts(s->chr, buf, q - buf);
bellarde15d7372006-06-25 16:26:29 +00001153 }
pbrooke5b0bc42007-01-27 23:46:43 +00001154 if (s->chr->chr_read) {
bellarde15d7372006-06-25 16:26:29 +00001155 qemu_fifo_write(&s->out_fifo, buf, q - buf);
1156 kbd_send_chars(s);
bellarde7f0ad52004-07-14 17:28:59 +00001157 }
1158 break;
1159 }
1160}
1161
balrog4d3b6f62008-02-10 16:33:14 +00001162static void text_console_invalidate(void *opaque)
1163{
Gerd Hoffmann76ffb0b2012-09-28 13:24:17 +02001164 QemuConsole *s = (QemuConsole *) opaque;
aliguori68f00992009-01-21 18:59:12 +00001165 if (!ds_get_bits_per_pixel(s->ds) && s->console_type == TEXT_CONSOLE) {
1166 s->g_width = ds_get_width(s->ds);
1167 s->g_height = ds_get_height(s->ds);
1168 text_console_resize(s);
1169 }
balrog4d3b6f62008-02-10 16:33:14 +00001170 console_refresh(s);
1171}
1172
Anthony Liguoric227f092009-10-01 16:12:16 -05001173static void text_console_update(void *opaque, console_ch_t *chardata)
balrog4d3b6f62008-02-10 16:33:14 +00001174{
Gerd Hoffmann76ffb0b2012-09-28 13:24:17 +02001175 QemuConsole *s = (QemuConsole *) opaque;
balrog4d3b6f62008-02-10 16:33:14 +00001176 int i, j, src;
1177
1178 if (s->text_x[0] <= s->text_x[1]) {
1179 src = (s->y_base + s->text_y[0]) * s->width;
1180 chardata += s->text_y[0] * s->width;
1181 for (i = s->text_y[0]; i <= s->text_y[1]; i ++)
1182 for (j = 0; j < s->width; j ++, src ++)
1183 console_write_ch(chardata ++, s->cells[src].ch |
1184 (s->cells[src].t_attrib.fgcol << 12) |
1185 (s->cells[src].t_attrib.bgcol << 8) |
1186 (s->cells[src].t_attrib.bold << 21));
Gerd Hoffmannc78f7132013-03-05 15:24:14 +01001187 dpy_text_update(s, s->text_x[0], s->text_y[0],
Gerd Hoffmanna93a4a22012-09-28 15:02:08 +02001188 s->text_x[1] - s->text_x[0], i - s->text_y[0]);
balrog4d3b6f62008-02-10 16:33:14 +00001189 s->text_x[0] = s->width;
1190 s->text_y[0] = s->height;
1191 s->text_x[1] = 0;
1192 s->text_y[1] = 0;
1193 }
1194 if (s->cursor_invalidate) {
Gerd Hoffmannc78f7132013-03-05 15:24:14 +01001195 dpy_text_cursor(s, s->x, s->y);
balrog4d3b6f62008-02-10 16:33:14 +00001196 s->cursor_invalidate = 0;
1197 }
1198}
1199
Gerd Hoffmann76ffb0b2012-09-28 13:24:17 +02001200static QemuConsole *new_console(DisplayState *ds, console_type_t console_type)
bellarde7f0ad52004-07-14 17:28:59 +00001201{
Gerd Hoffmann76ffb0b2012-09-28 13:24:17 +02001202 QemuConsole *s;
pbrook95219892006-04-09 01:06:34 +00001203 int i;
bellarde7f0ad52004-07-14 17:28:59 +00001204
1205 if (nb_consoles >= MAX_CONSOLES)
1206 return NULL;
Gerd Hoffmann76ffb0b2012-09-28 13:24:17 +02001207 s = g_malloc0(sizeof(QemuConsole));
thsaf3a9032007-07-11 23:14:59 +00001208 if (!active_console || ((active_console->console_type != GRAPHIC_CONSOLE) &&
1209 (console_type == GRAPHIC_CONSOLE))) {
bellarde7f0ad52004-07-14 17:28:59 +00001210 active_console = s;
thsaf3a9032007-07-11 23:14:59 +00001211 }
bellarde7f0ad52004-07-14 17:28:59 +00001212 s->ds = ds;
thsaf3a9032007-07-11 23:14:59 +00001213 s->console_type = console_type;
1214 if (console_type != GRAPHIC_CONSOLE) {
Jan Kiszkaf81bdef2011-09-16 00:48:07 +02001215 s->index = nb_consoles;
pbrook95219892006-04-09 01:06:34 +00001216 consoles[nb_consoles++] = s;
1217 } else {
1218 /* HACK: Put graphical consoles before text consoles. */
1219 for (i = nb_consoles; i > 0; i--) {
thsaf3a9032007-07-11 23:14:59 +00001220 if (consoles[i - 1]->console_type == GRAPHIC_CONSOLE)
pbrook95219892006-04-09 01:06:34 +00001221 break;
1222 consoles[i] = consoles[i - 1];
Jan Kiszkaf81bdef2011-09-16 00:48:07 +02001223 consoles[i]->index = i;
pbrook95219892006-04-09 01:06:34 +00001224 }
Jan Kiszkaf81bdef2011-09-16 00:48:07 +02001225 s->index = i;
pbrook95219892006-04-09 01:06:34 +00001226 consoles[i] = s;
aliguori3023f332009-01-16 19:04:14 +00001227 nb_consoles++;
pbrook95219892006-04-09 01:06:34 +00001228 }
bellarde7f0ad52004-07-14 17:28:59 +00001229 return s;
1230}
1231
Gerd Hoffmann537a4392012-09-27 11:06:36 +02001232static void qemu_alloc_display(DisplaySurface *surface, int width, int height,
1233 int linesize, PixelFormat pf, int newflags)
Jes Sorensenffe8b822011-03-16 13:33:30 +01001234{
Jes Sorensenffe8b822011-03-16 13:33:30 +01001235 surface->pf = pf;
Gerd Hoffmann69c77772012-09-26 15:20:05 +02001236
1237 qemu_pixman_image_unref(surface->image);
1238 surface->image = NULL;
Gerd Hoffmann69c77772012-09-26 15:20:05 +02001239
1240 surface->format = qemu_pixman_get_format(&pf);
1241 assert(surface->format != 0);
1242 surface->image = pixman_image_create_bits(surface->format,
1243 width, height,
1244 NULL, linesize);
1245 assert(surface->image != NULL);
1246
Jes Sorensenffe8b822011-03-16 13:33:30 +01001247 surface->flags = newflags | QEMU_ALLOCATED_FLAG;
Paolo Bonzini98b50082010-02-11 00:29:57 +01001248#ifdef HOST_WORDS_BIGENDIAN
Jes Sorensenffe8b822011-03-16 13:33:30 +01001249 surface->flags |= QEMU_BIG_ENDIAN_FLAG;
Paolo Bonzini98b50082010-02-11 00:29:57 +01001250#endif
Paolo Bonzini98b50082010-02-11 00:29:57 +01001251}
1252
Gerd Hoffmannda229ef2013-02-28 10:48:02 +01001253DisplaySurface *qemu_create_displaysurface(int width, int height)
Gerd Hoffmann537a4392012-09-27 11:06:36 +02001254{
1255 DisplaySurface *surface = g_new0(DisplaySurface, 1);
Gerd Hoffmann537a4392012-09-27 11:06:36 +02001256 int linesize = width * 4;
Gerd Hoffmannda229ef2013-02-28 10:48:02 +01001257
1258 trace_displaysurface_create(surface, width, height);
Gerd Hoffmann537a4392012-09-27 11:06:36 +02001259 qemu_alloc_display(surface, width, height, linesize,
1260 qemu_default_pixelformat(32), 0);
1261 return surface;
1262}
1263
Gerd Hoffmann187cd1d2012-09-26 07:46:20 +02001264DisplaySurface *qemu_create_displaysurface_from(int width, int height, int bpp,
Gerd Hoffmannb1424e02013-02-20 09:37:12 +01001265 int linesize, uint8_t *data,
1266 bool byteswap)
Paolo Bonzini98b50082010-02-11 00:29:57 +01001267{
Gerd Hoffmann69c77772012-09-26 15:20:05 +02001268 DisplaySurface *surface = g_new0(DisplaySurface, 1);
Paolo Bonzini98b50082010-02-11 00:29:57 +01001269
Gerd Hoffmannda229ef2013-02-28 10:48:02 +01001270 trace_displaysurface_create_from(surface, width, height, bpp, byteswap);
Gerd Hoffmannb1424e02013-02-20 09:37:12 +01001271 if (byteswap) {
1272 surface->pf = qemu_different_endianness_pixelformat(bpp);
1273 } else {
1274 surface->pf = qemu_default_pixelformat(bpp);
1275 }
Gerd Hoffmann69c77772012-09-26 15:20:05 +02001276
1277 surface->format = qemu_pixman_get_format(&surface->pf);
1278 assert(surface->format != 0);
1279 surface->image = pixman_image_create_bits(surface->format,
1280 width, height,
1281 (void *)data, linesize);
1282 assert(surface->image != NULL);
1283
Paolo Bonzini98b50082010-02-11 00:29:57 +01001284#ifdef HOST_WORDS_BIGENDIAN
1285 surface->flags = QEMU_BIG_ENDIAN_FLAG;
1286#endif
Paolo Bonzini98b50082010-02-11 00:29:57 +01001287
1288 return surface;
1289}
1290
Gerd Hoffmannda229ef2013-02-28 10:48:02 +01001291void qemu_free_displaysurface(DisplaySurface *surface)
Paolo Bonzini98b50082010-02-11 00:29:57 +01001292{
Gerd Hoffmannda229ef2013-02-28 10:48:02 +01001293 if (surface == NULL) {
Paolo Bonzini98b50082010-02-11 00:29:57 +01001294 return;
Gerd Hoffmann187cd1d2012-09-26 07:46:20 +02001295 }
Gerd Hoffmannda229ef2013-02-28 10:48:02 +01001296 trace_displaysurface_free(surface);
1297 qemu_pixman_image_unref(surface->image);
1298 g_free(surface);
Paolo Bonzini98b50082010-02-11 00:29:57 +01001299}
1300
Gerd Hoffmann7c20b4a2012-11-13 14:51:41 +01001301void register_displaychangelistener(DisplayState *ds,
1302 DisplayChangeListener *dcl)
1303{
1304 trace_displaychangelistener_register(dcl, dcl->ops->dpy_name);
1305 dcl->ds = ds;
1306 QLIST_INSERT_HEAD(&ds->listeners, dcl, next);
1307 gui_setup_refresh(ds);
Gerd Hoffmannc12aeb82013-02-28 15:03:04 +01001308 if (dcl->ops->dpy_gfx_switch) {
Gerd Hoffmannbc2ed972013-03-01 13:03:04 +01001309 dcl->ops->dpy_gfx_switch(dcl, ds->surface);
Gerd Hoffmann7c20b4a2012-11-13 14:51:41 +01001310 }
1311}
1312
1313void unregister_displaychangelistener(DisplayChangeListener *dcl)
1314{
1315 DisplayState *ds = dcl->ds;
1316 trace_displaychangelistener_unregister(dcl, dcl->ops->dpy_name);
1317 QLIST_REMOVE(dcl, next);
1318 gui_setup_refresh(ds);
1319}
1320
Gerd Hoffmannc78f7132013-03-05 15:24:14 +01001321void dpy_gfx_update(QemuConsole *con, int x, int y, int w, int h)
Gerd Hoffmann7c20b4a2012-11-13 14:51:41 +01001322{
Gerd Hoffmannc78f7132013-03-05 15:24:14 +01001323 DisplayState *s = con->ds;
Gerd Hoffmann7c20b4a2012-11-13 14:51:41 +01001324 struct DisplayChangeListener *dcl;
1325 int width = pixman_image_get_width(s->surface->image);
1326 int height = pixman_image_get_height(s->surface->image);
1327
1328 x = MAX(x, 0);
1329 y = MAX(y, 0);
1330 x = MIN(x, width);
1331 y = MIN(y, height);
1332 w = MIN(w, width - x);
1333 h = MIN(h, height - y);
1334
1335 QLIST_FOREACH(dcl, &s->listeners, next) {
1336 if (dcl->ops->dpy_gfx_update) {
Gerd Hoffmannbc2ed972013-03-01 13:03:04 +01001337 dcl->ops->dpy_gfx_update(dcl, x, y, w, h);
Gerd Hoffmann7c20b4a2012-11-13 14:51:41 +01001338 }
1339 }
1340}
1341
Gerd Hoffmannc78f7132013-03-05 15:24:14 +01001342void dpy_gfx_replace_surface(QemuConsole *con,
Gerd Hoffmannda229ef2013-02-28 10:48:02 +01001343 DisplaySurface *surface)
Gerd Hoffmann7c20b4a2012-11-13 14:51:41 +01001344{
Gerd Hoffmannc78f7132013-03-05 15:24:14 +01001345 DisplayState *s = con->ds;
Gerd Hoffmannda229ef2013-02-28 10:48:02 +01001346 DisplaySurface *old_surface = s->surface;
Gerd Hoffmann7c20b4a2012-11-13 14:51:41 +01001347 struct DisplayChangeListener *dcl;
Gerd Hoffmannda229ef2013-02-28 10:48:02 +01001348
1349 s->surface = surface;
Gerd Hoffmann7c20b4a2012-11-13 14:51:41 +01001350 QLIST_FOREACH(dcl, &s->listeners, next) {
Gerd Hoffmannc12aeb82013-02-28 15:03:04 +01001351 if (dcl->ops->dpy_gfx_switch) {
Gerd Hoffmannbc2ed972013-03-01 13:03:04 +01001352 dcl->ops->dpy_gfx_switch(dcl, surface);
Gerd Hoffmann7c20b4a2012-11-13 14:51:41 +01001353 }
1354 }
Gerd Hoffmannda229ef2013-02-28 10:48:02 +01001355 qemu_free_displaysurface(old_surface);
Gerd Hoffmann7c20b4a2012-11-13 14:51:41 +01001356}
1357
1358void dpy_refresh(DisplayState *s)
1359{
1360 struct DisplayChangeListener *dcl;
1361 QLIST_FOREACH(dcl, &s->listeners, next) {
1362 if (dcl->ops->dpy_refresh) {
Gerd Hoffmannbc2ed972013-03-01 13:03:04 +01001363 dcl->ops->dpy_refresh(dcl);
Gerd Hoffmann7c20b4a2012-11-13 14:51:41 +01001364 }
1365 }
1366}
1367
Gerd Hoffmannc78f7132013-03-05 15:24:14 +01001368void dpy_gfx_copy(QemuConsole *con, int src_x, int src_y,
1369 int dst_x, int dst_y, int w, int h)
Gerd Hoffmann7c20b4a2012-11-13 14:51:41 +01001370{
Gerd Hoffmannc78f7132013-03-05 15:24:14 +01001371 DisplayState *s = con->ds;
Gerd Hoffmann7c20b4a2012-11-13 14:51:41 +01001372 struct DisplayChangeListener *dcl;
1373 QLIST_FOREACH(dcl, &s->listeners, next) {
1374 if (dcl->ops->dpy_gfx_copy) {
Gerd Hoffmannbc2ed972013-03-01 13:03:04 +01001375 dcl->ops->dpy_gfx_copy(dcl, src_x, src_y, dst_x, dst_y, w, h);
Gerd Hoffmann7c20b4a2012-11-13 14:51:41 +01001376 } else { /* TODO */
Gerd Hoffmannbc2ed972013-03-01 13:03:04 +01001377 dcl->ops->dpy_gfx_update(dcl, dst_x, dst_y, w, h);
Gerd Hoffmann7c20b4a2012-11-13 14:51:41 +01001378 }
1379 }
1380}
1381
Gerd Hoffmannc78f7132013-03-05 15:24:14 +01001382void dpy_text_cursor(QemuConsole *con, int x, int y)
Gerd Hoffmann7c20b4a2012-11-13 14:51:41 +01001383{
Gerd Hoffmannc78f7132013-03-05 15:24:14 +01001384 DisplayState *s = con->ds;
Gerd Hoffmann7c20b4a2012-11-13 14:51:41 +01001385 struct DisplayChangeListener *dcl;
1386 QLIST_FOREACH(dcl, &s->listeners, next) {
1387 if (dcl->ops->dpy_text_cursor) {
Gerd Hoffmannbc2ed972013-03-01 13:03:04 +01001388 dcl->ops->dpy_text_cursor(dcl, x, y);
Gerd Hoffmann7c20b4a2012-11-13 14:51:41 +01001389 }
1390 }
1391}
1392
Gerd Hoffmannc78f7132013-03-05 15:24:14 +01001393void dpy_text_update(QemuConsole *con, int x, int y, int w, int h)
Gerd Hoffmann7c20b4a2012-11-13 14:51:41 +01001394{
Gerd Hoffmannc78f7132013-03-05 15:24:14 +01001395 DisplayState *s = con->ds;
Gerd Hoffmann7c20b4a2012-11-13 14:51:41 +01001396 struct DisplayChangeListener *dcl;
1397 QLIST_FOREACH(dcl, &s->listeners, next) {
1398 if (dcl->ops->dpy_text_update) {
Gerd Hoffmannbc2ed972013-03-01 13:03:04 +01001399 dcl->ops->dpy_text_update(dcl, x, y, w, h);
Gerd Hoffmann7c20b4a2012-11-13 14:51:41 +01001400 }
1401 }
1402}
1403
Gerd Hoffmannc78f7132013-03-05 15:24:14 +01001404void dpy_text_resize(QemuConsole *con, int w, int h)
Gerd Hoffmann7c20b4a2012-11-13 14:51:41 +01001405{
Gerd Hoffmannc78f7132013-03-05 15:24:14 +01001406 DisplayState *s = con->ds;
Gerd Hoffmann7c20b4a2012-11-13 14:51:41 +01001407 struct DisplayChangeListener *dcl;
1408 QLIST_FOREACH(dcl, &s->listeners, next) {
1409 if (dcl->ops->dpy_text_resize) {
Gerd Hoffmannbc2ed972013-03-01 13:03:04 +01001410 dcl->ops->dpy_text_resize(dcl, w, h);
Gerd Hoffmann7c20b4a2012-11-13 14:51:41 +01001411 }
1412 }
1413}
1414
Gerd Hoffmannc78f7132013-03-05 15:24:14 +01001415void dpy_mouse_set(QemuConsole *con, int x, int y, int on)
Gerd Hoffmann7c20b4a2012-11-13 14:51:41 +01001416{
Gerd Hoffmannc78f7132013-03-05 15:24:14 +01001417 DisplayState *s = con->ds;
Gerd Hoffmann7c20b4a2012-11-13 14:51:41 +01001418 struct DisplayChangeListener *dcl;
1419 QLIST_FOREACH(dcl, &s->listeners, next) {
1420 if (dcl->ops->dpy_mouse_set) {
Gerd Hoffmannbc2ed972013-03-01 13:03:04 +01001421 dcl->ops->dpy_mouse_set(dcl, x, y, on);
Gerd Hoffmann7c20b4a2012-11-13 14:51:41 +01001422 }
1423 }
1424}
1425
Gerd Hoffmannc78f7132013-03-05 15:24:14 +01001426void dpy_cursor_define(QemuConsole *con, QEMUCursor *cursor)
Gerd Hoffmann7c20b4a2012-11-13 14:51:41 +01001427{
Gerd Hoffmannc78f7132013-03-05 15:24:14 +01001428 DisplayState *s = con->ds;
Gerd Hoffmann7c20b4a2012-11-13 14:51:41 +01001429 struct DisplayChangeListener *dcl;
1430 QLIST_FOREACH(dcl, &s->listeners, next) {
1431 if (dcl->ops->dpy_cursor_define) {
Gerd Hoffmannbc2ed972013-03-01 13:03:04 +01001432 dcl->ops->dpy_cursor_define(dcl, cursor);
Gerd Hoffmann7c20b4a2012-11-13 14:51:41 +01001433 }
1434 }
1435}
1436
Gerd Hoffmannc78f7132013-03-05 15:24:14 +01001437bool dpy_cursor_define_supported(QemuConsole *con)
Gerd Hoffmann7c20b4a2012-11-13 14:51:41 +01001438{
Gerd Hoffmannc78f7132013-03-05 15:24:14 +01001439 DisplayState *s = con->ds;
Gerd Hoffmann7c20b4a2012-11-13 14:51:41 +01001440 struct DisplayChangeListener *dcl;
1441 QLIST_FOREACH(dcl, &s->listeners, next) {
1442 if (dcl->ops->dpy_cursor_define) {
1443 return true;
1444 }
1445 }
1446 return false;
1447}
1448
Paolo Bonzini98b50082010-02-11 00:29:57 +01001449static void dumb_display_init(void)
1450{
Anthony Liguori7267c092011-08-20 22:09:37 -05001451 DisplayState *ds = g_malloc0(sizeof(DisplayState));
Jan Kiszka18026512011-06-19 11:53:02 +02001452 int width = 640;
1453 int height = 480;
1454
Jan Kiszka18026512011-06-19 11:53:02 +02001455 if (is_fixedsize_console()) {
1456 width = active_console->g_width;
1457 height = active_console->g_height;
1458 }
Gerd Hoffmannc78f7132013-03-05 15:24:14 +01001459 ds->surface = qemu_create_displaysurface(width, height);
Gerd Hoffmannda229ef2013-02-28 10:48:02 +01001460
Paolo Bonzini98b50082010-02-11 00:29:57 +01001461 register_displaystate(ds);
1462}
1463
1464/***********************************************************/
1465/* register display */
1466
1467void register_displaystate(DisplayState *ds)
1468{
1469 DisplayState **s;
1470 s = &display_state;
1471 while (*s != NULL)
1472 s = &(*s)->next;
1473 ds->next = NULL;
1474 *s = ds;
1475}
1476
1477DisplayState *get_displaystate(void)
1478{
1479 if (!display_state) {
1480 dumb_display_init ();
1481 }
1482 return display_state;
1483}
1484
Gerd Hoffmannc78f7132013-03-05 15:24:14 +01001485QemuConsole *graphic_console_init(vga_hw_update_ptr update,
1486 vga_hw_invalidate_ptr invalidate,
1487 vga_hw_screen_dump_ptr screen_dump,
1488 vga_hw_text_update_ptr text_update,
1489 void *opaque)
bellarde7f0ad52004-07-14 17:28:59 +00001490{
Gerd Hoffmann76ffb0b2012-09-28 13:24:17 +02001491 QemuConsole *s;
aliguori3023f332009-01-16 19:04:14 +00001492 DisplayState *ds;
aurel32f0f2f972009-01-16 21:13:49 +00001493
Anthony Liguori7267c092011-08-20 22:09:37 -05001494 ds = (DisplayState *) g_malloc0(sizeof(DisplayState));
thsaf3a9032007-07-11 23:14:59 +00001495 s = new_console(ds, GRAPHIC_CONSOLE);
pbrook95219892006-04-09 01:06:34 +00001496 s->hw_update = update;
1497 s->hw_invalidate = invalidate;
1498 s->hw_screen_dump = screen_dump;
balrog4d3b6f62008-02-10 16:33:14 +00001499 s->hw_text_update = text_update;
pbrook95219892006-04-09 01:06:34 +00001500 s->hw = opaque;
aliguori3023f332009-01-16 19:04:14 +00001501
Gerd Hoffmannc78f7132013-03-05 15:24:14 +01001502 ds->surface = qemu_create_displaysurface(640, 480);
Gerd Hoffmannda229ef2013-02-28 10:48:02 +01001503
aurel32f0f2f972009-01-16 21:13:49 +00001504 register_displaystate(ds);
Gerd Hoffmannc78f7132013-03-05 15:24:14 +01001505 return s;
pbrook95219892006-04-09 01:06:34 +00001506}
1507
1508int is_graphic_console(void)
1509{
balrog4d3b6f62008-02-10 16:33:14 +00001510 return active_console && active_console->console_type == GRAPHIC_CONSOLE;
bellarde7f0ad52004-07-14 17:28:59 +00001511}
1512
balrogc21bbcf2008-09-24 03:32:33 +00001513int is_fixedsize_console(void)
1514{
1515 return active_console && active_console->console_type != TEXT_CONSOLE;
1516}
1517
Paolo Bonzini41048332010-12-23 13:42:52 +01001518static void text_console_set_echo(CharDriverState *chr, bool echo)
1519{
Gerd Hoffmann76ffb0b2012-09-28 13:24:17 +02001520 QemuConsole *s = chr->opaque;
Paolo Bonzini41048332010-12-23 13:42:52 +01001521
1522 s->echo = echo;
1523}
1524
Jan Kiszkabf1bed82012-07-10 22:00:55 +02001525static void text_console_update_cursor(void *opaque)
1526{
Gerd Hoffmann76ffb0b2012-09-28 13:24:17 +02001527 QemuConsole *s = opaque;
Jan Kiszkabf1bed82012-07-10 22:00:55 +02001528
1529 s->cursor_visible_phase = !s->cursor_visible_phase;
1530 vga_hw_invalidate();
1531 qemu_mod_timer(s->cursor_timer,
1532 qemu_get_clock_ms(rt_clock) + CONSOLE_CURSOR_PERIOD / 2);
1533}
1534
Paolo Bonzini44b37b92010-12-23 13:42:53 +01001535static void text_console_do_init(CharDriverState *chr, DisplayState *ds)
bellarde7f0ad52004-07-14 17:28:59 +00001536{
Gerd Hoffmann76ffb0b2012-09-28 13:24:17 +02001537 QemuConsole *s;
pbrook6d6f7c22006-03-11 15:35:30 +00001538
Paolo Bonzini491e1142010-12-23 13:42:51 +01001539 s = chr->opaque;
Gerd Hoffmann6ea314d2009-09-10 10:58:49 +02001540
bellarde7f0ad52004-07-14 17:28:59 +00001541 chr->chr_write = console_puts;
bellard6fcfafb2004-08-01 21:48:30 +00001542
bellarde15d7372006-06-25 16:26:29 +00001543 s->out_fifo.buf = s->out_fifo_buf;
1544 s->out_fifo.buf_size = sizeof(s->out_fifo_buf);
Paolo Bonzini7bd427d2011-03-11 16:47:48 +01001545 s->kbd_timer = qemu_new_timer_ms(rt_clock, kbd_send_chars, s);
aliguori3023f332009-01-16 19:04:14 +00001546 s->ds = ds;
ths3b46e622007-09-17 08:09:54 +00001547
bellarde7f0ad52004-07-14 17:28:59 +00001548 s->y_displayed = 0;
1549 s->y_base = 0;
1550 s->total_height = DEFAULT_BACKSCROLL;
1551 s->x = 0;
1552 s->y = 0;
Paolo Bonzini491e1142010-12-23 13:42:51 +01001553 if (s->console_type == TEXT_CONSOLE) {
1554 s->g_width = ds_get_width(s->ds);
1555 s->g_height = ds_get_height(s->ds);
1556 }
pbrook6d6f7c22006-03-11 15:35:30 +00001557
Jan Kiszkabf1bed82012-07-10 22:00:55 +02001558 s->cursor_timer =
1559 qemu_new_timer_ms(rt_clock, text_console_update_cursor, s);
1560
balrog4d3b6f62008-02-10 16:33:14 +00001561 s->hw_invalidate = text_console_invalidate;
1562 s->hw_text_update = text_console_update;
1563 s->hw = s;
1564
pbrook6d6f7c22006-03-11 15:35:30 +00001565 /* Set text attribute defaults */
1566 s->t_attrib_default.bold = 0;
1567 s->t_attrib_default.uline = 0;
1568 s->t_attrib_default.blink = 0;
1569 s->t_attrib_default.invers = 0;
1570 s->t_attrib_default.unvisible = 0;
1571 s->t_attrib_default.fgcol = COLOR_WHITE;
1572 s->t_attrib_default.bgcol = COLOR_BLACK;
pbrook6d6f7c22006-03-11 15:35:30 +00001573 /* set current text attributes to default */
1574 s->t_attrib = s->t_attrib_default;
bellarde7f0ad52004-07-14 17:28:59 +00001575 text_console_resize(s);
1576
Gerd Hoffmann51bfa4d2009-12-08 13:11:39 +01001577 if (chr->label) {
1578 char msg[128];
1579 int len;
1580
Gerd Hoffmann735ba582009-12-08 13:11:40 +01001581 s->t_attrib.bgcol = COLOR_BLUE;
Gerd Hoffmann51bfa4d2009-12-08 13:11:39 +01001582 len = snprintf(msg, sizeof(msg), "%s console\r\n", chr->label);
1583 console_puts(chr, (uint8_t*)msg, len);
Gerd Hoffmann735ba582009-12-08 13:11:40 +01001584 s->t_attrib = s->t_attrib_default;
Gerd Hoffmann51bfa4d2009-12-08 13:11:39 +01001585 }
1586
Amit Shah127338e2009-11-03 19:59:56 +05301587 qemu_chr_generic_open(chr);
aurel32ceecf1d2009-01-18 14:08:04 +00001588 if (chr->init)
1589 chr->init(chr);
bellarde7f0ad52004-07-14 17:28:59 +00001590}
pbrookc60e08d2008-07-01 16:24:38 +00001591
Gerd Hoffmann702ec692013-02-25 15:52:32 +01001592static CharDriverState *text_console_init(ChardevVC *vc)
aliguori2796dae2009-01-16 20:23:27 +00001593{
1594 CharDriverState *chr;
Gerd Hoffmann76ffb0b2012-09-28 13:24:17 +02001595 QemuConsole *s;
Gerd Hoffmann702ec692013-02-25 15:52:32 +01001596 unsigned width = 0;
1597 unsigned height = 0;
aliguori2796dae2009-01-16 20:23:27 +00001598
Anthony Liguori7267c092011-08-20 22:09:37 -05001599 chr = g_malloc0(sizeof(CharDriverState));
aliguori2796dae2009-01-16 20:23:27 +00001600
Gerd Hoffmann702ec692013-02-25 15:52:32 +01001601 if (vc->has_width) {
1602 width = vc->width;
1603 } else if (vc->has_cols) {
1604 width = vc->cols * FONT_WIDTH;
1605 }
Paolo Bonzini491e1142010-12-23 13:42:51 +01001606
Gerd Hoffmann702ec692013-02-25 15:52:32 +01001607 if (vc->has_height) {
1608 height = vc->height;
1609 } else if (vc->has_rows) {
1610 height = vc->rows * FONT_HEIGHT;
1611 }
Paolo Bonzini491e1142010-12-23 13:42:51 +01001612
1613 if (width == 0 || height == 0) {
1614 s = new_console(NULL, TEXT_CONSOLE);
1615 } else {
1616 s = new_console(NULL, TEXT_CONSOLE_FIXED_SIZE);
1617 }
1618
1619 if (!s) {
Stefan Weil5354d082011-10-02 18:53:09 +02001620 g_free(chr);
Markus Armbruster1f514702012-02-07 15:09:08 +01001621 return NULL;
Paolo Bonzini491e1142010-12-23 13:42:51 +01001622 }
1623
1624 s->chr = chr;
1625 s->g_width = width;
1626 s->g_height = height;
1627 chr->opaque = s;
Paolo Bonzini41048332010-12-23 13:42:52 +01001628 chr->chr_set_echo = text_console_set_echo;
Markus Armbruster1f514702012-02-07 15:09:08 +01001629 return chr;
aliguori2796dae2009-01-16 20:23:27 +00001630}
1631
Anthony Liguorid82831d2013-02-20 07:43:19 -06001632static VcHandler *vc_handler = text_console_init;
1633
Gerd Hoffmann702ec692013-02-25 15:52:32 +01001634CharDriverState *vc_init(ChardevVC *vc)
Anthony Liguorid82831d2013-02-20 07:43:19 -06001635{
Gerd Hoffmann702ec692013-02-25 15:52:32 +01001636 return vc_handler(vc);
Anthony Liguorid82831d2013-02-20 07:43:19 -06001637}
1638
1639void register_vc_handler(VcHandler *handler)
1640{
1641 vc_handler = handler;
1642}
1643
aliguori2796dae2009-01-16 20:23:27 +00001644void text_consoles_set_display(DisplayState *ds)
1645{
1646 int i;
1647
Markus Armbruster8811e1e2012-02-07 15:09:21 +01001648 for (i = 0; i < nb_consoles; i++) {
1649 if (consoles[i]->console_type != GRAPHIC_CONSOLE) {
1650 text_console_do_init(consoles[i]->chr, ds);
1651 }
aliguori2796dae2009-01-16 20:23:27 +00001652 }
aliguori2796dae2009-01-16 20:23:27 +00001653}
1654
Gerd Hoffmannc78f7132013-03-05 15:24:14 +01001655void qemu_console_resize(QemuConsole *s, int width, int height)
pbrookc60e08d2008-07-01 16:24:38 +00001656{
aliguori3023f332009-01-16 19:04:14 +00001657 s->g_width = width;
1658 s->g_height = height;
1659 if (is_graphic_console()) {
Gerd Hoffmannda229ef2013-02-28 10:48:02 +01001660 DisplaySurface *surface;
1661 surface = qemu_create_displaysurface(width, height);
Gerd Hoffmannc78f7132013-03-05 15:24:14 +01001662 dpy_gfx_replace_surface(s, surface);
pbrookc60e08d2008-07-01 16:24:38 +00001663 }
1664}
balrog38334f72008-09-24 02:21:24 +00001665
Gerd Hoffmannc78f7132013-03-05 15:24:14 +01001666void qemu_console_copy(QemuConsole *con, int src_x, int src_y,
aliguori3023f332009-01-16 19:04:14 +00001667 int dst_x, int dst_y, int w, int h)
balrogc21bbcf2008-09-24 03:32:33 +00001668{
aliguori3023f332009-01-16 19:04:14 +00001669 if (is_graphic_console()) {
Gerd Hoffmannc78f7132013-03-05 15:24:14 +01001670 dpy_gfx_copy(con, src_x, src_y, dst_x, dst_y, w, h);
balrog38334f72008-09-24 02:21:24 +00001671 }
1672}
aliguori7d957bd2009-01-15 22:14:11 +00001673
Gerd Hoffmannc78f7132013-03-05 15:24:14 +01001674DisplaySurface *qemu_console_surface(QemuConsole *console)
1675{
1676 return console->ds->surface;
1677}
1678
1679DisplayState *qemu_console_displaystate(QemuConsole *console)
1680{
1681 return console->ds;
1682}
1683
malc0da2ea12009-01-23 19:56:19 +00001684PixelFormat qemu_different_endianness_pixelformat(int bpp)
aliguori7d957bd2009-01-15 22:14:11 +00001685{
1686 PixelFormat pf;
1687
1688 memset(&pf, 0x00, sizeof(PixelFormat));
1689
1690 pf.bits_per_pixel = bpp;
BALATON Zoltanfeadf1a2012-08-22 17:19:42 +02001691 pf.bytes_per_pixel = DIV_ROUND_UP(bpp, 8);
aliguori7d957bd2009-01-15 22:14:11 +00001692 pf.depth = bpp == 32 ? 24 : bpp;
1693
1694 switch (bpp) {
malc0da2ea12009-01-23 19:56:19 +00001695 case 24:
1696 pf.rmask = 0x000000FF;
1697 pf.gmask = 0x0000FF00;
1698 pf.bmask = 0x00FF0000;
1699 pf.rmax = 255;
1700 pf.gmax = 255;
1701 pf.bmax = 255;
1702 pf.rshift = 0;
1703 pf.gshift = 8;
1704 pf.bshift = 16;
aliguori90a1e3c2009-01-26 15:37:30 +00001705 pf.rbits = 8;
1706 pf.gbits = 8;
1707 pf.bbits = 8;
aliguori7d957bd2009-01-15 22:14:11 +00001708 break;
malc0da2ea12009-01-23 19:56:19 +00001709 case 32:
1710 pf.rmask = 0x0000FF00;
1711 pf.gmask = 0x00FF0000;
1712 pf.bmask = 0xFF000000;
1713 pf.amask = 0x00000000;
1714 pf.amax = 255;
1715 pf.rmax = 255;
1716 pf.gmax = 255;
1717 pf.bmax = 255;
1718 pf.ashift = 0;
1719 pf.rshift = 8;
1720 pf.gshift = 16;
1721 pf.bshift = 24;
aliguori90a1e3c2009-01-26 15:37:30 +00001722 pf.rbits = 8;
1723 pf.gbits = 8;
1724 pf.bbits = 8;
1725 pf.abits = 8;
malc0da2ea12009-01-23 19:56:19 +00001726 break;
1727 default:
1728 break;
1729 }
1730 return pf;
1731}
1732
1733PixelFormat qemu_default_pixelformat(int bpp)
1734{
1735 PixelFormat pf;
1736
1737 memset(&pf, 0x00, sizeof(PixelFormat));
1738
1739 pf.bits_per_pixel = bpp;
BALATON Zoltanfeadf1a2012-08-22 17:19:42 +02001740 pf.bytes_per_pixel = DIV_ROUND_UP(bpp, 8);
malc0da2ea12009-01-23 19:56:19 +00001741 pf.depth = bpp == 32 ? 24 : bpp;
1742
1743 switch (bpp) {
Gerd Hoffmannb6278082010-05-21 11:59:14 +02001744 case 15:
1745 pf.bits_per_pixel = 16;
Gerd Hoffmannb6278082010-05-21 11:59:14 +02001746 pf.rmask = 0x00007c00;
1747 pf.gmask = 0x000003E0;
1748 pf.bmask = 0x0000001F;
1749 pf.rmax = 31;
1750 pf.gmax = 31;
1751 pf.bmax = 31;
1752 pf.rshift = 10;
1753 pf.gshift = 5;
1754 pf.bshift = 0;
1755 pf.rbits = 5;
1756 pf.gbits = 5;
1757 pf.bbits = 5;
1758 break;
aliguori7d957bd2009-01-15 22:14:11 +00001759 case 16:
1760 pf.rmask = 0x0000F800;
1761 pf.gmask = 0x000007E0;
1762 pf.bmask = 0x0000001F;
1763 pf.rmax = 31;
1764 pf.gmax = 63;
1765 pf.bmax = 31;
1766 pf.rshift = 11;
1767 pf.gshift = 5;
1768 pf.bshift = 0;
aliguori90a1e3c2009-01-26 15:37:30 +00001769 pf.rbits = 5;
1770 pf.gbits = 6;
1771 pf.bbits = 5;
aliguori7d957bd2009-01-15 22:14:11 +00001772 break;
1773 case 24:
aliguori7d957bd2009-01-15 22:14:11 +00001774 pf.rmask = 0x00FF0000;
1775 pf.gmask = 0x0000FF00;
1776 pf.bmask = 0x000000FF;
1777 pf.rmax = 255;
1778 pf.gmax = 255;
1779 pf.bmax = 255;
1780 pf.rshift = 16;
1781 pf.gshift = 8;
1782 pf.bshift = 0;
aliguori90a1e3c2009-01-26 15:37:30 +00001783 pf.rbits = 8;
1784 pf.gbits = 8;
1785 pf.bbits = 8;
Markus Armbruster0eba62e2011-11-22 12:56:10 +01001786 break;
malc0da2ea12009-01-23 19:56:19 +00001787 case 32:
1788 pf.rmask = 0x00FF0000;
1789 pf.gmask = 0x0000FF00;
1790 pf.bmask = 0x000000FF;
malc0da2ea12009-01-23 19:56:19 +00001791 pf.rmax = 255;
1792 pf.gmax = 255;
1793 pf.bmax = 255;
malc0da2ea12009-01-23 19:56:19 +00001794 pf.rshift = 16;
1795 pf.gshift = 8;
1796 pf.bshift = 0;
aliguori90a1e3c2009-01-26 15:37:30 +00001797 pf.rbits = 8;
1798 pf.gbits = 8;
1799 pf.bbits = 8;
aliguori7d957bd2009-01-15 22:14:11 +00001800 break;
1801 default:
1802 break;
1803 }
1804 return pf;
1805}
Anthony Liguori01f45d92013-03-05 23:21:32 +05301806
Gerd Hoffmann702ec692013-02-25 15:52:32 +01001807static void qemu_chr_parse_vc(QemuOpts *opts, ChardevBackend *backend,
1808 Error **errp)
1809{
1810 int val;
1811
1812 backend->vc = g_new0(ChardevVC, 1);
1813
1814 val = qemu_opt_get_number(opts, "width", 0);
1815 if (val != 0) {
1816 backend->vc->has_width = true;
1817 backend->vc->width = val;
1818 }
1819
1820 val = qemu_opt_get_number(opts, "height", 0);
1821 if (val != 0) {
1822 backend->vc->has_height = true;
1823 backend->vc->height = val;
1824 }
1825
1826 val = qemu_opt_get_number(opts, "cols", 0);
1827 if (val != 0) {
1828 backend->vc->has_cols = true;
1829 backend->vc->cols = val;
1830 }
1831
1832 val = qemu_opt_get_number(opts, "rows", 0);
1833 if (val != 0) {
1834 backend->vc->has_rows = true;
1835 backend->vc->rows = val;
1836 }
1837}
1838
Anthony Liguori01f45d92013-03-05 23:21:32 +05301839static void register_types(void)
1840{
Gerd Hoffmann702ec692013-02-25 15:52:32 +01001841 register_char_driver_qapi("vc", CHARDEV_BACKEND_KIND_VC,
1842 qemu_chr_parse_vc);
Anthony Liguori01f45d92013-03-05 23:21:32 +05301843}
1844
1845type_init(register_types);