blob: be7f4f1a258a89ccba00279867091a9e12bfce60 [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 Bonzinidccfcd02013-04-08 16:55:25 +020028#include "sysemu/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
Gerd Hoffmann1562e532013-03-06 13:40:47 +0100211static void vga_fill_rect(QemuConsole *con,
212 int posx, int posy, int width, int height,
213 uint32_t color)
bellarde7f0ad52004-07-14 17:28:59 +0000214{
Gerd Hoffmann1562e532013-03-06 13:40:47 +0100215 DisplaySurface *surface = qemu_console_surface(con);
Gerd Hoffmann68db6dc2013-03-06 15:43:23 +0100216 pixman_rectangle16_t rect = {
217 .x = posx, .y = posy, .width = width, .height = height
218 };
219 pixman_color_t pcolor;
ths3b46e622007-09-17 08:09:54 +0000220
Gerd Hoffmann68db6dc2013-03-06 15:43:23 +0100221 pcolor = qemu_pixman_color(&surface->pf, color);
222 pixman_image_fill_rectangles(PIXMAN_OP_SRC, surface->image,
223 &pcolor, 1, &rect);
bellarde7f0ad52004-07-14 17:28:59 +0000224}
225
226/* copy from (xs, ys) to (xd, yd) a rectangle of size (w, h) */
Gerd Hoffmann1562e532013-03-06 13:40:47 +0100227static void vga_bitblt(QemuConsole *con,
228 int xs, int ys, int xd, int yd, int w, int h)
bellarde7f0ad52004-07-14 17:28:59 +0000229{
Gerd Hoffmann1562e532013-03-06 13:40:47 +0100230 DisplaySurface *surface = qemu_console_surface(con);
bellarde7f0ad52004-07-14 17:28:59 +0000231
Gerd Hoffmann68db6dc2013-03-06 15:43:23 +0100232 pixman_image_composite(PIXMAN_OP_SRC,
233 surface->image, NULL, surface->image,
234 xs, ys, 0, 0, xd, yd, w, h);
bellarde7f0ad52004-07-14 17:28:59 +0000235}
236
237/***********************************************************/
238/* basic char display */
239
240#define FONT_HEIGHT 16
241#define FONT_WIDTH 8
242
243#include "vgafont.h"
244
245#define cbswap_32(__x) \
246((uint32_t)( \
247 (((uint32_t)(__x) & (uint32_t)0x000000ffUL) << 24) | \
248 (((uint32_t)(__x) & (uint32_t)0x0000ff00UL) << 8) | \
249 (((uint32_t)(__x) & (uint32_t)0x00ff0000UL) >> 8) | \
250 (((uint32_t)(__x) & (uint32_t)0xff000000UL) >> 24) ))
251
Juan Quintelae2542fe2009-07-27 16:13:06 +0200252#ifdef HOST_WORDS_BIGENDIAN
bellarde7f0ad52004-07-14 17:28:59 +0000253#define PAT(x) x
254#else
255#define PAT(x) cbswap_32(x)
256#endif
257
258static const uint32_t dmask16[16] = {
259 PAT(0x00000000),
260 PAT(0x000000ff),
261 PAT(0x0000ff00),
262 PAT(0x0000ffff),
263 PAT(0x00ff0000),
264 PAT(0x00ff00ff),
265 PAT(0x00ffff00),
266 PAT(0x00ffffff),
267 PAT(0xff000000),
268 PAT(0xff0000ff),
269 PAT(0xff00ff00),
270 PAT(0xff00ffff),
271 PAT(0xffff0000),
272 PAT(0xffff00ff),
273 PAT(0xffffff00),
274 PAT(0xffffffff),
275};
276
277static const uint32_t dmask4[4] = {
278 PAT(0x00000000),
279 PAT(0x0000ffff),
280 PAT(0xffff0000),
281 PAT(0xffffffff),
282};
283
Devin J. Pohlydf00bed2011-09-07 15:44:36 -0400284#ifndef CONFIG_CURSES
pbrook6d6f7c22006-03-11 15:35:30 +0000285enum color_names {
286 COLOR_BLACK = 0,
287 COLOR_RED = 1,
288 COLOR_GREEN = 2,
289 COLOR_YELLOW = 3,
290 COLOR_BLUE = 4,
291 COLOR_MAGENTA = 5,
292 COLOR_CYAN = 6,
293 COLOR_WHITE = 7
294};
Devin J. Pohlydf00bed2011-09-07 15:44:36 -0400295#endif
pbrook6d6f7c22006-03-11 15:35:30 +0000296
297static const uint32_t color_table_rgb[2][8] = {
298 { /* dark */
bellard26489842006-06-25 17:37:36 +0000299 QEMU_RGB(0x00, 0x00, 0x00), /* black */
300 QEMU_RGB(0xaa, 0x00, 0x00), /* red */
301 QEMU_RGB(0x00, 0xaa, 0x00), /* green */
302 QEMU_RGB(0xaa, 0xaa, 0x00), /* yellow */
303 QEMU_RGB(0x00, 0x00, 0xaa), /* blue */
304 QEMU_RGB(0xaa, 0x00, 0xaa), /* magenta */
305 QEMU_RGB(0x00, 0xaa, 0xaa), /* cyan */
306 QEMU_RGB(0xaa, 0xaa, 0xaa), /* white */
pbrook6d6f7c22006-03-11 15:35:30 +0000307 },
308 { /* bright */
bellard26489842006-06-25 17:37:36 +0000309 QEMU_RGB(0x00, 0x00, 0x00), /* black */
310 QEMU_RGB(0xff, 0x00, 0x00), /* red */
311 QEMU_RGB(0x00, 0xff, 0x00), /* green */
312 QEMU_RGB(0xff, 0xff, 0x00), /* yellow */
313 QEMU_RGB(0x00, 0x00, 0xff), /* blue */
314 QEMU_RGB(0xff, 0x00, 0xff), /* magenta */
315 QEMU_RGB(0x00, 0xff, 0xff), /* cyan */
316 QEMU_RGB(0xff, 0xff, 0xff), /* white */
pbrook6d6f7c22006-03-11 15:35:30 +0000317 }
bellarde7f0ad52004-07-14 17:28:59 +0000318};
319
pbrook6d6f7c22006-03-11 15:35:30 +0000320#ifdef DEBUG_CONSOLE
321static void console_print_text_attributes(TextAttributes *t_attrib, char ch)
322{
323 if (t_attrib->bold) {
324 printf("b");
325 } else {
326 printf(" ");
327 }
328 if (t_attrib->uline) {
329 printf("u");
330 } else {
331 printf(" ");
332 }
333 if (t_attrib->blink) {
334 printf("l");
335 } else {
336 printf(" ");
337 }
338 if (t_attrib->invers) {
339 printf("i");
340 } else {
341 printf(" ");
342 }
343 if (t_attrib->unvisible) {
344 printf("n");
345 } else {
346 printf(" ");
347 }
348
349 printf(" fg: %d bg: %d ch:'%2X' '%c'\n", t_attrib->fgcol, t_attrib->bgcol, ch, ch);
350}
351#endif
bellarde7f0ad52004-07-14 17:28:59 +0000352
Gerd Hoffmann1562e532013-03-06 13:40:47 +0100353static void vga_putcharxy(QemuConsole *s, int x, int y, int ch,
pbrook6d6f7c22006-03-11 15:35:30 +0000354 TextAttributes *t_attrib)
bellarde7f0ad52004-07-14 17:28:59 +0000355{
Gerd Hoffmann1562e532013-03-06 13:40:47 +0100356 DisplaySurface *surface = qemu_console_surface(s);
bellarde7f0ad52004-07-14 17:28:59 +0000357 uint8_t *d;
358 const uint8_t *font_ptr;
359 unsigned int font_data, linesize, xorcol, bpp;
360 int i;
pbrook6d6f7c22006-03-11 15:35:30 +0000361 unsigned int fgcol, bgcol;
362
363#ifdef DEBUG_CONSOLE
364 printf("x: %2i y: %2i", x, y);
365 console_print_text_attributes(t_attrib, ch);
366#endif
367
368 if (t_attrib->invers) {
Gerd Hoffmanncf6f0542013-03-06 09:50:51 +0100369 bgcol = color_table_rgb[t_attrib->bold][t_attrib->fgcol];
370 fgcol = color_table_rgb[t_attrib->bold][t_attrib->bgcol];
pbrook6d6f7c22006-03-11 15:35:30 +0000371 } else {
Gerd Hoffmanncf6f0542013-03-06 09:50:51 +0100372 fgcol = color_table_rgb[t_attrib->bold][t_attrib->fgcol];
373 bgcol = color_table_rgb[t_attrib->bold][t_attrib->bgcol];
pbrook6d6f7c22006-03-11 15:35:30 +0000374 }
bellarde7f0ad52004-07-14 17:28:59 +0000375
Gerd Hoffmann1562e532013-03-06 13:40:47 +0100376 bpp = surface_bytes_per_pixel(surface);
377 d = surface_data(surface) +
378 surface_stride(surface) * y * FONT_HEIGHT + bpp * x * FONT_WIDTH;
379 linesize = surface_stride(surface);
bellarde7f0ad52004-07-14 17:28:59 +0000380 font_ptr = vgafont16 + FONT_HEIGHT * ch;
381 xorcol = bgcol ^ fgcol;
Gerd Hoffmann1562e532013-03-06 13:40:47 +0100382 switch (surface_bits_per_pixel(surface)) {
bellarde7f0ad52004-07-14 17:28:59 +0000383 case 8:
384 for(i = 0; i < FONT_HEIGHT; i++) {
385 font_data = *font_ptr++;
pbrook6d6f7c22006-03-11 15:35:30 +0000386 if (t_attrib->uline
387 && ((i == FONT_HEIGHT - 2) || (i == FONT_HEIGHT - 3))) {
Markus Armbruster439229c2011-11-04 10:38:29 +0100388 font_data = 0xFF;
pbrook6d6f7c22006-03-11 15:35:30 +0000389 }
bellarde7f0ad52004-07-14 17:28:59 +0000390 ((uint32_t *)d)[0] = (dmask16[(font_data >> 4)] & xorcol) ^ bgcol;
391 ((uint32_t *)d)[1] = (dmask16[(font_data >> 0) & 0xf] & xorcol) ^ bgcol;
392 d += linesize;
393 }
394 break;
395 case 16:
396 case 15:
397 for(i = 0; i < FONT_HEIGHT; i++) {
398 font_data = *font_ptr++;
pbrook6d6f7c22006-03-11 15:35:30 +0000399 if (t_attrib->uline
400 && ((i == FONT_HEIGHT - 2) || (i == FONT_HEIGHT - 3))) {
Markus Armbruster439229c2011-11-04 10:38:29 +0100401 font_data = 0xFF;
pbrook6d6f7c22006-03-11 15:35:30 +0000402 }
bellarde7f0ad52004-07-14 17:28:59 +0000403 ((uint32_t *)d)[0] = (dmask4[(font_data >> 6)] & xorcol) ^ bgcol;
404 ((uint32_t *)d)[1] = (dmask4[(font_data >> 4) & 3] & xorcol) ^ bgcol;
405 ((uint32_t *)d)[2] = (dmask4[(font_data >> 2) & 3] & xorcol) ^ bgcol;
406 ((uint32_t *)d)[3] = (dmask4[(font_data >> 0) & 3] & xorcol) ^ bgcol;
407 d += linesize;
408 }
409 break;
410 case 32:
411 for(i = 0; i < FONT_HEIGHT; i++) {
412 font_data = *font_ptr++;
pbrook6d6f7c22006-03-11 15:35:30 +0000413 if (t_attrib->uline && ((i == FONT_HEIGHT - 2) || (i == FONT_HEIGHT - 3))) {
Markus Armbruster439229c2011-11-04 10:38:29 +0100414 font_data = 0xFF;
pbrook6d6f7c22006-03-11 15:35:30 +0000415 }
bellarde7f0ad52004-07-14 17:28:59 +0000416 ((uint32_t *)d)[0] = (-((font_data >> 7)) & xorcol) ^ bgcol;
417 ((uint32_t *)d)[1] = (-((font_data >> 6) & 1) & xorcol) ^ bgcol;
418 ((uint32_t *)d)[2] = (-((font_data >> 5) & 1) & xorcol) ^ bgcol;
419 ((uint32_t *)d)[3] = (-((font_data >> 4) & 1) & xorcol) ^ bgcol;
420 ((uint32_t *)d)[4] = (-((font_data >> 3) & 1) & xorcol) ^ bgcol;
421 ((uint32_t *)d)[5] = (-((font_data >> 2) & 1) & xorcol) ^ bgcol;
422 ((uint32_t *)d)[6] = (-((font_data >> 1) & 1) & xorcol) ^ bgcol;
423 ((uint32_t *)d)[7] = (-((font_data >> 0) & 1) & xorcol) ^ bgcol;
424 d += linesize;
425 }
426 break;
427 }
428}
429
Gerd Hoffmann76ffb0b2012-09-28 13:24:17 +0200430static void text_console_resize(QemuConsole *s)
bellarde7f0ad52004-07-14 17:28:59 +0000431{
432 TextCell *cells, *c, *c1;
433 int w1, x, y, last_width;
434
435 last_width = s->width;
436 s->width = s->g_width / FONT_WIDTH;
437 s->height = s->g_height / FONT_HEIGHT;
438
439 w1 = last_width;
440 if (s->width < w1)
441 w1 = s->width;
442
Anthony Liguori7267c092011-08-20 22:09:37 -0500443 cells = g_malloc(s->width * s->total_height * sizeof(TextCell));
bellarde7f0ad52004-07-14 17:28:59 +0000444 for(y = 0; y < s->total_height; y++) {
445 c = &cells[y * s->width];
446 if (w1 > 0) {
447 c1 = &s->cells[y * last_width];
448 for(x = 0; x < w1; x++) {
449 *c++ = *c1++;
450 }
451 }
452 for(x = w1; x < s->width; x++) {
453 c->ch = ' ';
pbrook6d6f7c22006-03-11 15:35:30 +0000454 c->t_attrib = s->t_attrib_default;
bellarde7f0ad52004-07-14 17:28:59 +0000455 c++;
456 }
457 }
Anthony Liguori7267c092011-08-20 22:09:37 -0500458 g_free(s->cells);
bellarde7f0ad52004-07-14 17:28:59 +0000459 s->cells = cells;
460}
461
Gerd Hoffmann76ffb0b2012-09-28 13:24:17 +0200462static inline void text_update_xy(QemuConsole *s, int x, int y)
balrog4d3b6f62008-02-10 16:33:14 +0000463{
464 s->text_x[0] = MIN(s->text_x[0], x);
465 s->text_x[1] = MAX(s->text_x[1], x);
466 s->text_y[0] = MIN(s->text_y[0], y);
467 s->text_y[1] = MAX(s->text_y[1], y);
468}
469
Gerd Hoffmann76ffb0b2012-09-28 13:24:17 +0200470static void invalidate_xy(QemuConsole *s, int x, int y)
pbrook14778c22009-01-21 03:02:52 +0000471{
472 if (s->update_x0 > x * FONT_WIDTH)
473 s->update_x0 = x * FONT_WIDTH;
474 if (s->update_y0 > y * FONT_HEIGHT)
475 s->update_y0 = y * FONT_HEIGHT;
476 if (s->update_x1 < (x + 1) * FONT_WIDTH)
477 s->update_x1 = (x + 1) * FONT_WIDTH;
478 if (s->update_y1 < (y + 1) * FONT_HEIGHT)
479 s->update_y1 = (y + 1) * FONT_HEIGHT;
480}
481
Gerd Hoffmann76ffb0b2012-09-28 13:24:17 +0200482static void update_xy(QemuConsole *s, int x, int y)
bellarde7f0ad52004-07-14 17:28:59 +0000483{
484 TextCell *c;
485 int y1, y2;
486
Gerd Hoffmann1562e532013-03-06 13:40:47 +0100487 if (s != active_console) {
488 return;
489 }
balrog4d3b6f62008-02-10 16:33:14 +0000490
Gerd Hoffmann1562e532013-03-06 13:40:47 +0100491 if (s->ds->have_text) {
492 text_update_xy(s, x, y);
493 }
494
495 if (s->ds->have_gfx) {
bellarde7f0ad52004-07-14 17:28:59 +0000496 y1 = (s->y_base + y) % s->total_height;
497 y2 = y1 - s->y_displayed;
498 if (y2 < 0)
499 y2 += s->total_height;
500 if (y2 < s->height) {
501 c = &s->cells[y1 * s->width + x];
Gerd Hoffmann1562e532013-03-06 13:40:47 +0100502 vga_putcharxy(s, x, y2, c->ch,
pbrook6d6f7c22006-03-11 15:35:30 +0000503 &(c->t_attrib));
pbrook14778c22009-01-21 03:02:52 +0000504 invalidate_xy(s, x, y2);
bellarde7f0ad52004-07-14 17:28:59 +0000505 }
506 }
507}
508
Gerd Hoffmann76ffb0b2012-09-28 13:24:17 +0200509static void console_show_cursor(QemuConsole *s, int show)
bellarde7f0ad52004-07-14 17:28:59 +0000510{
511 TextCell *c;
512 int y, y1;
Gerd Hoffmann1562e532013-03-06 13:40:47 +0100513 int x = s->x;
bellarde7f0ad52004-07-14 17:28:59 +0000514
Gerd Hoffmann1562e532013-03-06 13:40:47 +0100515 if (s != active_console) {
516 return;
517 }
balrog4d3b6f62008-02-10 16:33:14 +0000518
Gerd Hoffmann1562e532013-03-06 13:40:47 +0100519 if (s->ds->have_text) {
520 s->cursor_invalidate = 1;
521 }
balrog4d3b6f62008-02-10 16:33:14 +0000522
Gerd Hoffmann1562e532013-03-06 13:40:47 +0100523 if (s->ds->have_gfx) {
thsed8276a2007-02-10 22:37:56 +0000524 if (x >= s->width) {
525 x = s->width - 1;
526 }
bellarde7f0ad52004-07-14 17:28:59 +0000527 y1 = (s->y_base + s->y) % s->total_height;
528 y = y1 - s->y_displayed;
529 if (y < 0)
530 y += s->total_height;
531 if (y < s->height) {
thsed8276a2007-02-10 22:37:56 +0000532 c = &s->cells[y1 * s->width + x];
Jan Kiszkabf1bed82012-07-10 22:00:55 +0200533 if (show && s->cursor_visible_phase) {
pbrook6d6f7c22006-03-11 15:35:30 +0000534 TextAttributes t_attrib = s->t_attrib_default;
535 t_attrib.invers = !(t_attrib.invers); /* invert fg and bg */
Gerd Hoffmann1562e532013-03-06 13:40:47 +0100536 vga_putcharxy(s, x, y, c->ch, &t_attrib);
bellarde7f0ad52004-07-14 17:28:59 +0000537 } else {
Gerd Hoffmann1562e532013-03-06 13:40:47 +0100538 vga_putcharxy(s, x, y, c->ch, &(c->t_attrib));
bellarde7f0ad52004-07-14 17:28:59 +0000539 }
pbrook14778c22009-01-21 03:02:52 +0000540 invalidate_xy(s, x, y);
bellarde7f0ad52004-07-14 17:28:59 +0000541 }
542 }
543}
544
Gerd Hoffmann76ffb0b2012-09-28 13:24:17 +0200545static void console_refresh(QemuConsole *s)
bellarde7f0ad52004-07-14 17:28:59 +0000546{
Gerd Hoffmann1562e532013-03-06 13:40:47 +0100547 DisplaySurface *surface = qemu_console_surface(s);
bellarde7f0ad52004-07-14 17:28:59 +0000548 TextCell *c;
549 int x, y, y1;
550
ths5fafdf22007-09-16 21:08:06 +0000551 if (s != active_console)
bellarde7f0ad52004-07-14 17:28:59 +0000552 return;
Gerd Hoffmanna93a4a22012-09-28 15:02:08 +0200553
554 if (s->ds->have_text) {
balrog4d3b6f62008-02-10 16:33:14 +0000555 s->text_x[0] = 0;
556 s->text_y[0] = 0;
557 s->text_x[1] = s->width - 1;
558 s->text_y[1] = s->height - 1;
559 s->cursor_invalidate = 1;
balrog4d3b6f62008-02-10 16:33:14 +0000560 }
bellarde7f0ad52004-07-14 17:28:59 +0000561
Gerd Hoffmanna93a4a22012-09-28 15:02:08 +0200562 if (s->ds->have_gfx) {
Gerd Hoffmann1562e532013-03-06 13:40:47 +0100563 vga_fill_rect(s, 0, 0, surface_width(surface), surface_height(surface),
Gerd Hoffmanncf6f0542013-03-06 09:50:51 +0100564 color_table_rgb[0][COLOR_BLACK]);
Gerd Hoffmanna93a4a22012-09-28 15:02:08 +0200565 y1 = s->y_displayed;
566 for (y = 0; y < s->height; y++) {
567 c = s->cells + y1 * s->width;
568 for (x = 0; x < s->width; x++) {
Gerd Hoffmann1562e532013-03-06 13:40:47 +0100569 vga_putcharxy(s, x, y, c->ch,
Gerd Hoffmanna93a4a22012-09-28 15:02:08 +0200570 &(c->t_attrib));
571 c++;
572 }
573 if (++y1 == s->total_height) {
574 y1 = 0;
575 }
bellarde7f0ad52004-07-14 17:28:59 +0000576 }
Gerd Hoffmanna93a4a22012-09-28 15:02:08 +0200577 console_show_cursor(s, 1);
Gerd Hoffmann1562e532013-03-06 13:40:47 +0100578 dpy_gfx_update(s, 0, 0,
579 surface_width(surface), surface_height(surface));
bellarde7f0ad52004-07-14 17:28:59 +0000580 }
bellarde7f0ad52004-07-14 17:28:59 +0000581}
582
583static void console_scroll(int ydelta)
584{
Gerd Hoffmann76ffb0b2012-09-28 13:24:17 +0200585 QemuConsole *s;
bellarde7f0ad52004-07-14 17:28:59 +0000586 int i, y1;
ths3b46e622007-09-17 08:09:54 +0000587
bellarde7f0ad52004-07-14 17:28:59 +0000588 s = active_console;
thsaf3a9032007-07-11 23:14:59 +0000589 if (!s || (s->console_type == GRAPHIC_CONSOLE))
bellarde7f0ad52004-07-14 17:28:59 +0000590 return;
591
592 if (ydelta > 0) {
593 for(i = 0; i < ydelta; i++) {
594 if (s->y_displayed == s->y_base)
595 break;
596 if (++s->y_displayed == s->total_height)
597 s->y_displayed = 0;
598 }
599 } else {
600 ydelta = -ydelta;
601 i = s->backscroll_height;
602 if (i > s->total_height - s->height)
603 i = s->total_height - s->height;
604 y1 = s->y_base - i;
605 if (y1 < 0)
606 y1 += s->total_height;
607 for(i = 0; i < ydelta; i++) {
608 if (s->y_displayed == y1)
609 break;
610 if (--s->y_displayed < 0)
611 s->y_displayed = s->total_height - 1;
612 }
613 }
614 console_refresh(s);
615}
616
Gerd Hoffmann76ffb0b2012-09-28 13:24:17 +0200617static void console_put_lf(QemuConsole *s)
bellarde7f0ad52004-07-14 17:28:59 +0000618{
619 TextCell *c;
620 int x, y1;
621
bellarde7f0ad52004-07-14 17:28:59 +0000622 s->y++;
623 if (s->y >= s->height) {
624 s->y = s->height - 1;
pbrook6d6f7c22006-03-11 15:35:30 +0000625
bellarde7f0ad52004-07-14 17:28:59 +0000626 if (s->y_displayed == s->y_base) {
627 if (++s->y_displayed == s->total_height)
628 s->y_displayed = 0;
629 }
630 if (++s->y_base == s->total_height)
631 s->y_base = 0;
632 if (s->backscroll_height < s->total_height)
633 s->backscroll_height++;
634 y1 = (s->y_base + s->height - 1) % s->total_height;
635 c = &s->cells[y1 * s->width];
636 for(x = 0; x < s->width; x++) {
637 c->ch = ' ';
pbrook6d6f7c22006-03-11 15:35:30 +0000638 c->t_attrib = s->t_attrib_default;
bellarde7f0ad52004-07-14 17:28:59 +0000639 c++;
640 }
641 if (s == active_console && s->y_displayed == s->y_base) {
Gerd Hoffmann1562e532013-03-06 13:40:47 +0100642 if (s->ds->have_text) {
balrog4d3b6f62008-02-10 16:33:14 +0000643 s->text_x[0] = 0;
644 s->text_y[0] = 0;
645 s->text_x[1] = s->width - 1;
646 s->text_y[1] = s->height - 1;
balrog4d3b6f62008-02-10 16:33:14 +0000647 }
648
Gerd Hoffmann1562e532013-03-06 13:40:47 +0100649 if (s->ds->have_gfx) {
650 vga_bitblt(s, 0, FONT_HEIGHT, 0, 0,
651 s->width * FONT_WIDTH,
652 (s->height - 1) * FONT_HEIGHT);
653 vga_fill_rect(s, 0, (s->height - 1) * FONT_HEIGHT,
654 s->width * FONT_WIDTH, FONT_HEIGHT,
655 color_table_rgb[0][s->t_attrib_default.bgcol]);
656 s->update_x0 = 0;
657 s->update_y0 = 0;
658 s->update_x1 = s->width * FONT_WIDTH;
659 s->update_y1 = s->height * FONT_HEIGHT;
660 }
bellarde7f0ad52004-07-14 17:28:59 +0000661 }
662 }
663}
664
pbrook6d6f7c22006-03-11 15:35:30 +0000665/* Set console attributes depending on the current escape codes.
666 * NOTE: I know this code is not very efficient (checking every color for it
667 * self) but it is more readable and better maintainable.
668 */
Gerd Hoffmann76ffb0b2012-09-28 13:24:17 +0200669static void console_handle_escape(QemuConsole *s)
pbrook6d6f7c22006-03-11 15:35:30 +0000670{
671 int i;
672
pbrook6d6f7c22006-03-11 15:35:30 +0000673 for (i=0; i<s->nb_esc_params; i++) {
674 switch (s->esc_params[i]) {
675 case 0: /* reset all console attributes to default */
676 s->t_attrib = s->t_attrib_default;
677 break;
678 case 1:
679 s->t_attrib.bold = 1;
680 break;
681 case 4:
682 s->t_attrib.uline = 1;
683 break;
684 case 5:
685 s->t_attrib.blink = 1;
686 break;
687 case 7:
688 s->t_attrib.invers = 1;
689 break;
690 case 8:
691 s->t_attrib.unvisible = 1;
692 break;
693 case 22:
694 s->t_attrib.bold = 0;
695 break;
696 case 24:
697 s->t_attrib.uline = 0;
698 break;
699 case 25:
700 s->t_attrib.blink = 0;
701 break;
702 case 27:
703 s->t_attrib.invers = 0;
704 break;
705 case 28:
706 s->t_attrib.unvisible = 0;
707 break;
708 /* set foreground color */
709 case 30:
710 s->t_attrib.fgcol=COLOR_BLACK;
711 break;
712 case 31:
713 s->t_attrib.fgcol=COLOR_RED;
714 break;
715 case 32:
716 s->t_attrib.fgcol=COLOR_GREEN;
717 break;
718 case 33:
719 s->t_attrib.fgcol=COLOR_YELLOW;
720 break;
721 case 34:
722 s->t_attrib.fgcol=COLOR_BLUE;
723 break;
724 case 35:
725 s->t_attrib.fgcol=COLOR_MAGENTA;
726 break;
727 case 36:
728 s->t_attrib.fgcol=COLOR_CYAN;
729 break;
730 case 37:
731 s->t_attrib.fgcol=COLOR_WHITE;
732 break;
733 /* set background color */
734 case 40:
735 s->t_attrib.bgcol=COLOR_BLACK;
736 break;
737 case 41:
738 s->t_attrib.bgcol=COLOR_RED;
739 break;
740 case 42:
741 s->t_attrib.bgcol=COLOR_GREEN;
742 break;
743 case 43:
744 s->t_attrib.bgcol=COLOR_YELLOW;
745 break;
746 case 44:
747 s->t_attrib.bgcol=COLOR_BLUE;
748 break;
749 case 45:
750 s->t_attrib.bgcol=COLOR_MAGENTA;
751 break;
752 case 46:
753 s->t_attrib.bgcol=COLOR_CYAN;
754 break;
755 case 47:
756 s->t_attrib.bgcol=COLOR_WHITE;
757 break;
758 }
759 }
760}
761
Gerd Hoffmann76ffb0b2012-09-28 13:24:17 +0200762static void console_clear_xy(QemuConsole *s, int x, int y)
thsadb47962007-01-16 23:02:36 +0000763{
764 int y1 = (s->y_base + y) % s->total_height;
765 TextCell *c = &s->cells[y1 * s->width + x];
766 c->ch = ' ';
767 c->t_attrib = s->t_attrib_default;
thsadb47962007-01-16 23:02:36 +0000768 update_xy(s, x, y);
769}
770
Ian Campbell3eea5492012-09-04 10:26:09 -0500771/* set cursor, checking bounds */
Gerd Hoffmann76ffb0b2012-09-28 13:24:17 +0200772static void set_cursor(QemuConsole *s, int x, int y)
Ian Campbell3eea5492012-09-04 10:26:09 -0500773{
774 if (x < 0) {
775 x = 0;
776 }
777 if (y < 0) {
778 y = 0;
779 }
780 if (y >= s->height) {
781 y = s->height - 1;
782 }
783 if (x >= s->width) {
784 x = s->width - 1;
785 }
786
787 s->x = x;
788 s->y = y;
789}
790
Gerd Hoffmann76ffb0b2012-09-28 13:24:17 +0200791static void console_putchar(QemuConsole *s, int ch)
bellarde7f0ad52004-07-14 17:28:59 +0000792{
793 TextCell *c;
thsadb47962007-01-16 23:02:36 +0000794 int y1, i;
795 int x, y;
bellarde7f0ad52004-07-14 17:28:59 +0000796
797 switch(s->state) {
798 case TTY_STATE_NORM:
799 switch(ch) {
pbrook6d6f7c22006-03-11 15:35:30 +0000800 case '\r': /* carriage return */
bellarde7f0ad52004-07-14 17:28:59 +0000801 s->x = 0;
802 break;
pbrook6d6f7c22006-03-11 15:35:30 +0000803 case '\n': /* newline */
bellarde7f0ad52004-07-14 17:28:59 +0000804 console_put_lf(s);
805 break;
pbrook6d6f7c22006-03-11 15:35:30 +0000806 case '\b': /* backspace */
ths5fafdf22007-09-16 21:08:06 +0000807 if (s->x > 0)
bellarde15d7372006-06-25 16:26:29 +0000808 s->x--;
pbrook6d6f7c22006-03-11 15:35:30 +0000809 break;
810 case '\t': /* tabspace */
811 if (s->x + (8 - (s->x % 8)) > s->width) {
bellardbd468842006-07-14 20:24:31 +0000812 s->x = 0;
pbrook6d6f7c22006-03-11 15:35:30 +0000813 console_put_lf(s);
814 } else {
815 s->x = s->x + (8 - (s->x % 8));
816 }
817 break;
818 case '\a': /* alert aka. bell */
819 /* TODO: has to be implemented */
820 break;
thsadb47962007-01-16 23:02:36 +0000821 case 14:
822 /* SI (shift in), character set 0 (ignored) */
823 break;
824 case 15:
825 /* SO (shift out), character set 1 (ignored) */
826 break;
pbrook6d6f7c22006-03-11 15:35:30 +0000827 case 27: /* esc (introducing an escape sequence) */
bellarde7f0ad52004-07-14 17:28:59 +0000828 s->state = TTY_STATE_ESC;
829 break;
830 default:
thsed8276a2007-02-10 22:37:56 +0000831 if (s->x >= s->width) {
832 /* line wrap */
833 s->x = 0;
834 console_put_lf(s);
thsadb47962007-01-16 23:02:36 +0000835 }
bellarde7f0ad52004-07-14 17:28:59 +0000836 y1 = (s->y_base + s->y) % s->total_height;
837 c = &s->cells[y1 * s->width + s->x];
838 c->ch = ch;
pbrook6d6f7c22006-03-11 15:35:30 +0000839 c->t_attrib = s->t_attrib;
bellarde7f0ad52004-07-14 17:28:59 +0000840 update_xy(s, s->x, s->y);
841 s->x++;
bellarde7f0ad52004-07-14 17:28:59 +0000842 break;
843 }
844 break;
pbrook6d6f7c22006-03-11 15:35:30 +0000845 case TTY_STATE_ESC: /* check if it is a terminal escape sequence */
bellarde7f0ad52004-07-14 17:28:59 +0000846 if (ch == '[') {
847 for(i=0;i<MAX_ESC_PARAMS;i++)
848 s->esc_params[i] = 0;
849 s->nb_esc_params = 0;
850 s->state = TTY_STATE_CSI;
851 } else {
852 s->state = TTY_STATE_NORM;
853 }
854 break;
pbrook6d6f7c22006-03-11 15:35:30 +0000855 case TTY_STATE_CSI: /* handle escape sequence parameters */
bellarde7f0ad52004-07-14 17:28:59 +0000856 if (ch >= '0' && ch <= '9') {
857 if (s->nb_esc_params < MAX_ESC_PARAMS) {
Laszlo Ersekc10600a2012-09-17 11:10:03 +0200858 int *param = &s->esc_params[s->nb_esc_params];
859 int digit = (ch - '0');
860
861 *param = (*param <= (INT_MAX - digit) / 10) ?
862 *param * 10 + digit : INT_MAX;
bellarde7f0ad52004-07-14 17:28:59 +0000863 }
864 } else {
Ian Campbell3eea5492012-09-04 10:26:09 -0500865 if (s->nb_esc_params < MAX_ESC_PARAMS)
866 s->nb_esc_params++;
bellarde7f0ad52004-07-14 17:28:59 +0000867 if (ch == ';')
868 break;
thsadb47962007-01-16 23:02:36 +0000869#ifdef DEBUG_CONSOLE
870 fprintf(stderr, "escape sequence CSI%d;%d%c, %d parameters\n",
871 s->esc_params[0], s->esc_params[1], ch, s->nb_esc_params);
872#endif
bellarde7f0ad52004-07-14 17:28:59 +0000873 s->state = TTY_STATE_NORM;
874 switch(ch) {
thsadb47962007-01-16 23:02:36 +0000875 case 'A':
876 /* move cursor up */
877 if (s->esc_params[0] == 0) {
878 s->esc_params[0] = 1;
879 }
Ian Campbell3eea5492012-09-04 10:26:09 -0500880 set_cursor(s, s->x, s->y - s->esc_params[0]);
bellarde7f0ad52004-07-14 17:28:59 +0000881 break;
thsadb47962007-01-16 23:02:36 +0000882 case 'B':
883 /* move cursor down */
884 if (s->esc_params[0] == 0) {
885 s->esc_params[0] = 1;
886 }
Ian Campbell3eea5492012-09-04 10:26:09 -0500887 set_cursor(s, s->x, s->y + s->esc_params[0]);
thsadb47962007-01-16 23:02:36 +0000888 break;
889 case 'C':
890 /* move cursor right */
891 if (s->esc_params[0] == 0) {
892 s->esc_params[0] = 1;
893 }
Ian Campbell3eea5492012-09-04 10:26:09 -0500894 set_cursor(s, s->x + s->esc_params[0], s->y);
thsadb47962007-01-16 23:02:36 +0000895 break;
896 case 'D':
897 /* move cursor left */
898 if (s->esc_params[0] == 0) {
899 s->esc_params[0] = 1;
900 }
Ian Campbell3eea5492012-09-04 10:26:09 -0500901 set_cursor(s, s->x - s->esc_params[0], s->y);
thsadb47962007-01-16 23:02:36 +0000902 break;
903 case 'G':
904 /* move cursor to column */
Ian Campbell3eea5492012-09-04 10:26:09 -0500905 set_cursor(s, s->esc_params[0] - 1, s->y);
thsadb47962007-01-16 23:02:36 +0000906 break;
907 case 'f':
908 case 'H':
909 /* move cursor to row, column */
Ian Campbell3eea5492012-09-04 10:26:09 -0500910 set_cursor(s, s->esc_params[1] - 1, s->esc_params[0] - 1);
thsadb47962007-01-16 23:02:36 +0000911 break;
912 case 'J':
913 switch (s->esc_params[0]) {
914 case 0:
915 /* clear to end of screen */
916 for (y = s->y; y < s->height; y++) {
917 for (x = 0; x < s->width; x++) {
918 if (y == s->y && x < s->x) {
919 continue;
920 }
921 console_clear_xy(s, x, y);
922 }
923 }
924 break;
925 case 1:
926 /* clear from beginning of screen */
927 for (y = 0; y <= s->y; y++) {
928 for (x = 0; x < s->width; x++) {
929 if (y == s->y && x > s->x) {
930 break;
931 }
932 console_clear_xy(s, x, y);
933 }
934 }
935 break;
936 case 2:
937 /* clear entire screen */
938 for (y = 0; y <= s->height; y++) {
939 for (x = 0; x < s->width; x++) {
940 console_clear_xy(s, x, y);
941 }
942 }
Markus Armbrusterf94a9502011-11-22 11:59:06 +0100943 break;
thsadb47962007-01-16 23:02:36 +0000944 }
Markus Armbruster95d8f9f2011-11-22 11:59:07 +0100945 break;
thsadb47962007-01-16 23:02:36 +0000946 case 'K':
947 switch (s->esc_params[0]) {
948 case 0:
Markus Armbrusterf94a9502011-11-22 11:59:06 +0100949 /* clear to eol */
950 for(x = s->x; x < s->width; x++) {
thsadb47962007-01-16 23:02:36 +0000951 console_clear_xy(s, x, s->y);
Markus Armbrusterf94a9502011-11-22 11:59:06 +0100952 }
953 break;
thsadb47962007-01-16 23:02:36 +0000954 case 1:
955 /* clear from beginning of line */
956 for (x = 0; x <= s->x; x++) {
957 console_clear_xy(s, x, s->y);
958 }
959 break;
960 case 2:
961 /* clear entire line */
962 for(x = 0; x < s->width; x++) {
963 console_clear_xy(s, x, s->y);
964 }
Markus Armbrusterf94a9502011-11-22 11:59:06 +0100965 break;
966 }
thsadb47962007-01-16 23:02:36 +0000967 break;
968 case 'm':
Markus Armbrusterf94a9502011-11-22 11:59:06 +0100969 console_handle_escape(s);
970 break;
thsadb47962007-01-16 23:02:36 +0000971 case 'n':
972 /* report cursor position */
973 /* TODO: send ESC[row;colR */
974 break;
975 case 's':
976 /* save cursor position */
977 s->x_saved = s->x;
978 s->y_saved = s->y;
979 break;
980 case 'u':
981 /* restore cursor position */
982 s->x = s->x_saved;
983 s->y = s->y_saved;
984 break;
985 default:
986#ifdef DEBUG_CONSOLE
987 fprintf(stderr, "unhandled escape character '%c'\n", ch);
988#endif
989 break;
990 }
991 break;
bellarde7f0ad52004-07-14 17:28:59 +0000992 }
993 }
994}
995
996void console_select(unsigned int index)
997{
Gerd Hoffmann1562e532013-03-06 13:40:47 +0100998 DisplaySurface *surface;
Gerd Hoffmann76ffb0b2012-09-28 13:24:17 +0200999 QemuConsole *s;
pbrook6d6f7c22006-03-11 15:35:30 +00001000
bellarde7f0ad52004-07-14 17:28:59 +00001001 if (index >= MAX_CONSOLES)
1002 return;
Stefan Hajnoczi358664c2010-09-20 14:11:19 +01001003 if (active_console) {
Gerd Hoffmann1562e532013-03-06 13:40:47 +01001004 surface = qemu_console_surface(active_console);
1005 active_console->g_width = surface_width(surface);
1006 active_console->g_height = surface_height(surface);
Stefan Hajnoczi358664c2010-09-20 14:11:19 +01001007 }
bellarde7f0ad52004-07-14 17:28:59 +00001008 s = consoles[index];
1009 if (s) {
aliguori7d957bd2009-01-15 22:14:11 +00001010 DisplayState *ds = s->ds;
Jan Kiszkabf1bed82012-07-10 22:00:55 +02001011
Stefan Weil8bd6b062012-08-17 15:50:44 +02001012 if (active_console && active_console->cursor_timer) {
Jan Kiszkabf1bed82012-07-10 22:00:55 +02001013 qemu_del_timer(active_console->cursor_timer);
1014 }
bellarde7f0ad52004-07-14 17:28:59 +00001015 active_console = s;
Gerd Hoffmanna93a4a22012-09-28 15:02:08 +02001016 if (ds->have_gfx) {
Gerd Hoffmannda229ef2013-02-28 10:48:02 +01001017 surface = qemu_create_displaysurface(s->g_width, s->g_height);
Gerd Hoffmannc78f7132013-03-05 15:24:14 +01001018 dpy_gfx_replace_surface(s, surface);
Gerd Hoffmanna93a4a22012-09-28 15:02:08 +02001019 }
1020 if (ds->have_text) {
Gerd Hoffmannc78f7132013-03-05 15:24:14 +01001021 dpy_text_resize(s, s->width, s->height);
aliguori68f00992009-01-21 18:59:12 +00001022 }
Jan Kiszkabf1bed82012-07-10 22:00:55 +02001023 if (s->cursor_timer) {
1024 qemu_mod_timer(s->cursor_timer,
1025 qemu_get_clock_ms(rt_clock) + CONSOLE_CURSOR_PERIOD / 2);
1026 }
balrog4d3b6f62008-02-10 16:33:14 +00001027 vga_hw_invalidate();
bellarde7f0ad52004-07-14 17:28:59 +00001028 }
1029}
1030
1031static int console_puts(CharDriverState *chr, const uint8_t *buf, int len)
1032{
Gerd Hoffmann76ffb0b2012-09-28 13:24:17 +02001033 QemuConsole *s = chr->opaque;
bellarde7f0ad52004-07-14 17:28:59 +00001034 int i;
1035
pbrook14778c22009-01-21 03:02:52 +00001036 s->update_x0 = s->width * FONT_WIDTH;
1037 s->update_y0 = s->height * FONT_HEIGHT;
1038 s->update_x1 = 0;
1039 s->update_y1 = 0;
bellarde7f0ad52004-07-14 17:28:59 +00001040 console_show_cursor(s, 0);
1041 for(i = 0; i < len; i++) {
1042 console_putchar(s, buf[i]);
1043 }
1044 console_show_cursor(s, 1);
Gerd Hoffmanna93a4a22012-09-28 15:02:08 +02001045 if (s->ds->have_gfx && s->update_x0 < s->update_x1) {
Gerd Hoffmannc78f7132013-03-05 15:24:14 +01001046 dpy_gfx_update(s, s->update_x0, s->update_y0,
Gerd Hoffmanna93a4a22012-09-28 15:02:08 +02001047 s->update_x1 - s->update_x0,
1048 s->update_y1 - s->update_y0);
pbrook14778c22009-01-21 03:02:52 +00001049 }
bellarde7f0ad52004-07-14 17:28:59 +00001050 return len;
1051}
1052
bellarde15d7372006-06-25 16:26:29 +00001053static void kbd_send_chars(void *opaque)
1054{
Gerd Hoffmann76ffb0b2012-09-28 13:24:17 +02001055 QemuConsole *s = opaque;
bellarde15d7372006-06-25 16:26:29 +00001056 int len;
1057 uint8_t buf[16];
ths3b46e622007-09-17 08:09:54 +00001058
Anthony Liguori909cda12011-08-15 11:17:31 -05001059 len = qemu_chr_be_can_write(s->chr);
bellarde15d7372006-06-25 16:26:29 +00001060 if (len > s->out_fifo.count)
1061 len = s->out_fifo.count;
1062 if (len > 0) {
1063 if (len > sizeof(buf))
1064 len = sizeof(buf);
1065 qemu_fifo_read(&s->out_fifo, buf, len);
Anthony Liguorifa5efcc2011-08-15 11:17:30 -05001066 qemu_chr_be_write(s->chr, buf, len);
bellarde15d7372006-06-25 16:26:29 +00001067 }
1068 /* characters are pending: we send them a bit later (XXX:
1069 horrible, should change char device API) */
1070 if (s->out_fifo.count > 0) {
Paolo Bonzini7bd427d2011-03-11 16:47:48 +01001071 qemu_mod_timer(s->kbd_timer, qemu_get_clock_ms(rt_clock) + 1);
bellarde15d7372006-06-25 16:26:29 +00001072 }
1073}
1074
bellarde7f0ad52004-07-14 17:28:59 +00001075/* called when an ascii key is pressed */
1076void kbd_put_keysym(int keysym)
1077{
Gerd Hoffmann76ffb0b2012-09-28 13:24:17 +02001078 QemuConsole *s;
bellarde7f0ad52004-07-14 17:28:59 +00001079 uint8_t buf[16], *q;
1080 int c;
1081
1082 s = active_console;
thsaf3a9032007-07-11 23:14:59 +00001083 if (!s || (s->console_type == GRAPHIC_CONSOLE))
bellarde7f0ad52004-07-14 17:28:59 +00001084 return;
1085
1086 switch(keysym) {
1087 case QEMU_KEY_CTRL_UP:
1088 console_scroll(-1);
1089 break;
1090 case QEMU_KEY_CTRL_DOWN:
1091 console_scroll(1);
1092 break;
1093 case QEMU_KEY_CTRL_PAGEUP:
1094 console_scroll(-10);
1095 break;
1096 case QEMU_KEY_CTRL_PAGEDOWN:
1097 console_scroll(10);
1098 break;
1099 default:
bellarde15d7372006-06-25 16:26:29 +00001100 /* convert the QEMU keysym to VT100 key string */
1101 q = buf;
1102 if (keysym >= 0xe100 && keysym <= 0xe11f) {
1103 *q++ = '\033';
1104 *q++ = '[';
1105 c = keysym - 0xe100;
1106 if (c >= 10)
1107 *q++ = '0' + (c / 10);
1108 *q++ = '0' + (c % 10);
1109 *q++ = '~';
1110 } else if (keysym >= 0xe120 && keysym <= 0xe17f) {
1111 *q++ = '\033';
1112 *q++ = '[';
1113 *q++ = keysym & 0xff;
Paolo Bonzini41048332010-12-23 13:42:52 +01001114 } else if (s->echo && (keysym == '\r' || keysym == '\n')) {
1115 console_puts(s->chr, (const uint8_t *) "\r", 1);
1116 *q++ = '\n';
bellarde15d7372006-06-25 16:26:29 +00001117 } else {
Paolo Bonzini41048332010-12-23 13:42:52 +01001118 *q++ = keysym;
1119 }
1120 if (s->echo) {
1121 console_puts(s->chr, buf, q - buf);
bellarde15d7372006-06-25 16:26:29 +00001122 }
pbrooke5b0bc42007-01-27 23:46:43 +00001123 if (s->chr->chr_read) {
bellarde15d7372006-06-25 16:26:29 +00001124 qemu_fifo_write(&s->out_fifo, buf, q - buf);
1125 kbd_send_chars(s);
bellarde7f0ad52004-07-14 17:28:59 +00001126 }
1127 break;
1128 }
1129}
1130
balrog4d3b6f62008-02-10 16:33:14 +00001131static void text_console_invalidate(void *opaque)
1132{
Gerd Hoffmann76ffb0b2012-09-28 13:24:17 +02001133 QemuConsole *s = (QemuConsole *) opaque;
Gerd Hoffmann1562e532013-03-06 13:40:47 +01001134 DisplaySurface *surface = qemu_console_surface(s);
1135
1136 if (s->ds->have_text && s->console_type == TEXT_CONSOLE) {
1137 s->g_width = surface_width(surface);
1138 s->g_height = surface_height(surface);
aliguori68f00992009-01-21 18:59:12 +00001139 text_console_resize(s);
1140 }
balrog4d3b6f62008-02-10 16:33:14 +00001141 console_refresh(s);
1142}
1143
Anthony Liguoric227f092009-10-01 16:12:16 -05001144static void text_console_update(void *opaque, console_ch_t *chardata)
balrog4d3b6f62008-02-10 16:33:14 +00001145{
Gerd Hoffmann76ffb0b2012-09-28 13:24:17 +02001146 QemuConsole *s = (QemuConsole *) opaque;
balrog4d3b6f62008-02-10 16:33:14 +00001147 int i, j, src;
1148
1149 if (s->text_x[0] <= s->text_x[1]) {
1150 src = (s->y_base + s->text_y[0]) * s->width;
1151 chardata += s->text_y[0] * s->width;
1152 for (i = s->text_y[0]; i <= s->text_y[1]; i ++)
1153 for (j = 0; j < s->width; j ++, src ++)
1154 console_write_ch(chardata ++, s->cells[src].ch |
1155 (s->cells[src].t_attrib.fgcol << 12) |
1156 (s->cells[src].t_attrib.bgcol << 8) |
1157 (s->cells[src].t_attrib.bold << 21));
Gerd Hoffmannc78f7132013-03-05 15:24:14 +01001158 dpy_text_update(s, s->text_x[0], s->text_y[0],
Gerd Hoffmanna93a4a22012-09-28 15:02:08 +02001159 s->text_x[1] - s->text_x[0], i - s->text_y[0]);
balrog4d3b6f62008-02-10 16:33:14 +00001160 s->text_x[0] = s->width;
1161 s->text_y[0] = s->height;
1162 s->text_x[1] = 0;
1163 s->text_y[1] = 0;
1164 }
1165 if (s->cursor_invalidate) {
Gerd Hoffmannc78f7132013-03-05 15:24:14 +01001166 dpy_text_cursor(s, s->x, s->y);
balrog4d3b6f62008-02-10 16:33:14 +00001167 s->cursor_invalidate = 0;
1168 }
1169}
1170
Gerd Hoffmann76ffb0b2012-09-28 13:24:17 +02001171static QemuConsole *new_console(DisplayState *ds, console_type_t console_type)
bellarde7f0ad52004-07-14 17:28:59 +00001172{
Gerd Hoffmann76ffb0b2012-09-28 13:24:17 +02001173 QemuConsole *s;
pbrook95219892006-04-09 01:06:34 +00001174 int i;
bellarde7f0ad52004-07-14 17:28:59 +00001175
1176 if (nb_consoles >= MAX_CONSOLES)
1177 return NULL;
Gerd Hoffmann76ffb0b2012-09-28 13:24:17 +02001178 s = g_malloc0(sizeof(QemuConsole));
thsaf3a9032007-07-11 23:14:59 +00001179 if (!active_console || ((active_console->console_type != GRAPHIC_CONSOLE) &&
1180 (console_type == GRAPHIC_CONSOLE))) {
bellarde7f0ad52004-07-14 17:28:59 +00001181 active_console = s;
thsaf3a9032007-07-11 23:14:59 +00001182 }
bellarde7f0ad52004-07-14 17:28:59 +00001183 s->ds = ds;
thsaf3a9032007-07-11 23:14:59 +00001184 s->console_type = console_type;
1185 if (console_type != GRAPHIC_CONSOLE) {
Jan Kiszkaf81bdef2011-09-16 00:48:07 +02001186 s->index = nb_consoles;
pbrook95219892006-04-09 01:06:34 +00001187 consoles[nb_consoles++] = s;
1188 } else {
1189 /* HACK: Put graphical consoles before text consoles. */
1190 for (i = nb_consoles; i > 0; i--) {
thsaf3a9032007-07-11 23:14:59 +00001191 if (consoles[i - 1]->console_type == GRAPHIC_CONSOLE)
pbrook95219892006-04-09 01:06:34 +00001192 break;
1193 consoles[i] = consoles[i - 1];
Jan Kiszkaf81bdef2011-09-16 00:48:07 +02001194 consoles[i]->index = i;
pbrook95219892006-04-09 01:06:34 +00001195 }
Jan Kiszkaf81bdef2011-09-16 00:48:07 +02001196 s->index = i;
pbrook95219892006-04-09 01:06:34 +00001197 consoles[i] = s;
aliguori3023f332009-01-16 19:04:14 +00001198 nb_consoles++;
pbrook95219892006-04-09 01:06:34 +00001199 }
bellarde7f0ad52004-07-14 17:28:59 +00001200 return s;
1201}
1202
Gerd Hoffmann537a4392012-09-27 11:06:36 +02001203static void qemu_alloc_display(DisplaySurface *surface, int width, int height,
1204 int linesize, PixelFormat pf, int newflags)
Jes Sorensenffe8b822011-03-16 13:33:30 +01001205{
Jes Sorensenffe8b822011-03-16 13:33:30 +01001206 surface->pf = pf;
Gerd Hoffmann69c77772012-09-26 15:20:05 +02001207
1208 qemu_pixman_image_unref(surface->image);
1209 surface->image = NULL;
Gerd Hoffmann69c77772012-09-26 15:20:05 +02001210
1211 surface->format = qemu_pixman_get_format(&pf);
1212 assert(surface->format != 0);
1213 surface->image = pixman_image_create_bits(surface->format,
1214 width, height,
1215 NULL, linesize);
1216 assert(surface->image != NULL);
1217
Jes Sorensenffe8b822011-03-16 13:33:30 +01001218 surface->flags = newflags | QEMU_ALLOCATED_FLAG;
Paolo Bonzini98b50082010-02-11 00:29:57 +01001219#ifdef HOST_WORDS_BIGENDIAN
Jes Sorensenffe8b822011-03-16 13:33:30 +01001220 surface->flags |= QEMU_BIG_ENDIAN_FLAG;
Paolo Bonzini98b50082010-02-11 00:29:57 +01001221#endif
Paolo Bonzini98b50082010-02-11 00:29:57 +01001222}
1223
Gerd Hoffmannda229ef2013-02-28 10:48:02 +01001224DisplaySurface *qemu_create_displaysurface(int width, int height)
Gerd Hoffmann537a4392012-09-27 11:06:36 +02001225{
1226 DisplaySurface *surface = g_new0(DisplaySurface, 1);
Gerd Hoffmann537a4392012-09-27 11:06:36 +02001227 int linesize = width * 4;
Gerd Hoffmannda229ef2013-02-28 10:48:02 +01001228
1229 trace_displaysurface_create(surface, width, height);
Gerd Hoffmann537a4392012-09-27 11:06:36 +02001230 qemu_alloc_display(surface, width, height, linesize,
1231 qemu_default_pixelformat(32), 0);
1232 return surface;
1233}
1234
Gerd Hoffmann187cd1d2012-09-26 07:46:20 +02001235DisplaySurface *qemu_create_displaysurface_from(int width, int height, int bpp,
Gerd Hoffmannb1424e02013-02-20 09:37:12 +01001236 int linesize, uint8_t *data,
1237 bool byteswap)
Paolo Bonzini98b50082010-02-11 00:29:57 +01001238{
Gerd Hoffmann69c77772012-09-26 15:20:05 +02001239 DisplaySurface *surface = g_new0(DisplaySurface, 1);
Paolo Bonzini98b50082010-02-11 00:29:57 +01001240
Gerd Hoffmannda229ef2013-02-28 10:48:02 +01001241 trace_displaysurface_create_from(surface, width, height, bpp, byteswap);
Gerd Hoffmannb1424e02013-02-20 09:37:12 +01001242 if (byteswap) {
1243 surface->pf = qemu_different_endianness_pixelformat(bpp);
1244 } else {
1245 surface->pf = qemu_default_pixelformat(bpp);
1246 }
Gerd Hoffmann69c77772012-09-26 15:20:05 +02001247
1248 surface->format = qemu_pixman_get_format(&surface->pf);
1249 assert(surface->format != 0);
1250 surface->image = pixman_image_create_bits(surface->format,
1251 width, height,
1252 (void *)data, linesize);
1253 assert(surface->image != NULL);
1254
Paolo Bonzini98b50082010-02-11 00:29:57 +01001255#ifdef HOST_WORDS_BIGENDIAN
1256 surface->flags = QEMU_BIG_ENDIAN_FLAG;
1257#endif
Paolo Bonzini98b50082010-02-11 00:29:57 +01001258
1259 return surface;
1260}
1261
Gerd Hoffmannda229ef2013-02-28 10:48:02 +01001262void qemu_free_displaysurface(DisplaySurface *surface)
Paolo Bonzini98b50082010-02-11 00:29:57 +01001263{
Gerd Hoffmannda229ef2013-02-28 10:48:02 +01001264 if (surface == NULL) {
Paolo Bonzini98b50082010-02-11 00:29:57 +01001265 return;
Gerd Hoffmann187cd1d2012-09-26 07:46:20 +02001266 }
Gerd Hoffmannda229ef2013-02-28 10:48:02 +01001267 trace_displaysurface_free(surface);
1268 qemu_pixman_image_unref(surface->image);
1269 g_free(surface);
Paolo Bonzini98b50082010-02-11 00:29:57 +01001270}
1271
Gerd Hoffmann7c20b4a2012-11-13 14:51:41 +01001272void register_displaychangelistener(DisplayState *ds,
1273 DisplayChangeListener *dcl)
1274{
1275 trace_displaychangelistener_register(dcl, dcl->ops->dpy_name);
1276 dcl->ds = ds;
1277 QLIST_INSERT_HEAD(&ds->listeners, dcl, next);
1278 gui_setup_refresh(ds);
Gerd Hoffmannc12aeb82013-02-28 15:03:04 +01001279 if (dcl->ops->dpy_gfx_switch) {
Gerd Hoffmannbc2ed972013-03-01 13:03:04 +01001280 dcl->ops->dpy_gfx_switch(dcl, ds->surface);
Gerd Hoffmann7c20b4a2012-11-13 14:51:41 +01001281 }
1282}
1283
1284void unregister_displaychangelistener(DisplayChangeListener *dcl)
1285{
1286 DisplayState *ds = dcl->ds;
1287 trace_displaychangelistener_unregister(dcl, dcl->ops->dpy_name);
1288 QLIST_REMOVE(dcl, next);
1289 gui_setup_refresh(ds);
1290}
1291
Gerd Hoffmannc78f7132013-03-05 15:24:14 +01001292void dpy_gfx_update(QemuConsole *con, int x, int y, int w, int h)
Gerd Hoffmann7c20b4a2012-11-13 14:51:41 +01001293{
Gerd Hoffmannc78f7132013-03-05 15:24:14 +01001294 DisplayState *s = con->ds;
Gerd Hoffmann7c20b4a2012-11-13 14:51:41 +01001295 struct DisplayChangeListener *dcl;
1296 int width = pixman_image_get_width(s->surface->image);
1297 int height = pixman_image_get_height(s->surface->image);
1298
1299 x = MAX(x, 0);
1300 y = MAX(y, 0);
1301 x = MIN(x, width);
1302 y = MIN(y, height);
1303 w = MIN(w, width - x);
1304 h = MIN(h, height - y);
1305
1306 QLIST_FOREACH(dcl, &s->listeners, next) {
1307 if (dcl->ops->dpy_gfx_update) {
Gerd Hoffmannbc2ed972013-03-01 13:03:04 +01001308 dcl->ops->dpy_gfx_update(dcl, x, y, w, h);
Gerd Hoffmann7c20b4a2012-11-13 14:51:41 +01001309 }
1310 }
1311}
1312
Gerd Hoffmannc78f7132013-03-05 15:24:14 +01001313void dpy_gfx_replace_surface(QemuConsole *con,
Gerd Hoffmannda229ef2013-02-28 10:48:02 +01001314 DisplaySurface *surface)
Gerd Hoffmann7c20b4a2012-11-13 14:51:41 +01001315{
Gerd Hoffmannc78f7132013-03-05 15:24:14 +01001316 DisplayState *s = con->ds;
Gerd Hoffmannda229ef2013-02-28 10:48:02 +01001317 DisplaySurface *old_surface = s->surface;
Gerd Hoffmann7c20b4a2012-11-13 14:51:41 +01001318 struct DisplayChangeListener *dcl;
Gerd Hoffmannda229ef2013-02-28 10:48:02 +01001319
1320 s->surface = surface;
Gerd Hoffmann7c20b4a2012-11-13 14:51:41 +01001321 QLIST_FOREACH(dcl, &s->listeners, next) {
Gerd Hoffmannc12aeb82013-02-28 15:03:04 +01001322 if (dcl->ops->dpy_gfx_switch) {
Gerd Hoffmannbc2ed972013-03-01 13:03:04 +01001323 dcl->ops->dpy_gfx_switch(dcl, surface);
Gerd Hoffmann7c20b4a2012-11-13 14:51:41 +01001324 }
1325 }
Gerd Hoffmannda229ef2013-02-28 10:48:02 +01001326 qemu_free_displaysurface(old_surface);
Gerd Hoffmann7c20b4a2012-11-13 14:51:41 +01001327}
1328
1329void dpy_refresh(DisplayState *s)
1330{
1331 struct DisplayChangeListener *dcl;
1332 QLIST_FOREACH(dcl, &s->listeners, next) {
1333 if (dcl->ops->dpy_refresh) {
Gerd Hoffmannbc2ed972013-03-01 13:03:04 +01001334 dcl->ops->dpy_refresh(dcl);
Gerd Hoffmann7c20b4a2012-11-13 14:51:41 +01001335 }
1336 }
1337}
1338
Gerd Hoffmannc78f7132013-03-05 15:24:14 +01001339void dpy_gfx_copy(QemuConsole *con, int src_x, int src_y,
1340 int dst_x, int dst_y, int w, int h)
Gerd Hoffmann7c20b4a2012-11-13 14:51:41 +01001341{
Gerd Hoffmannc78f7132013-03-05 15:24:14 +01001342 DisplayState *s = con->ds;
Gerd Hoffmann7c20b4a2012-11-13 14:51:41 +01001343 struct DisplayChangeListener *dcl;
1344 QLIST_FOREACH(dcl, &s->listeners, next) {
1345 if (dcl->ops->dpy_gfx_copy) {
Gerd Hoffmannbc2ed972013-03-01 13:03:04 +01001346 dcl->ops->dpy_gfx_copy(dcl, src_x, src_y, dst_x, dst_y, w, h);
Gerd Hoffmann7c20b4a2012-11-13 14:51:41 +01001347 } else { /* TODO */
Gerd Hoffmannbc2ed972013-03-01 13:03:04 +01001348 dcl->ops->dpy_gfx_update(dcl, dst_x, dst_y, w, h);
Gerd Hoffmann7c20b4a2012-11-13 14:51:41 +01001349 }
1350 }
1351}
1352
Gerd Hoffmannc78f7132013-03-05 15:24:14 +01001353void dpy_text_cursor(QemuConsole *con, int x, int y)
Gerd Hoffmann7c20b4a2012-11-13 14:51:41 +01001354{
Gerd Hoffmannc78f7132013-03-05 15:24:14 +01001355 DisplayState *s = con->ds;
Gerd Hoffmann7c20b4a2012-11-13 14:51:41 +01001356 struct DisplayChangeListener *dcl;
1357 QLIST_FOREACH(dcl, &s->listeners, next) {
1358 if (dcl->ops->dpy_text_cursor) {
Gerd Hoffmannbc2ed972013-03-01 13:03:04 +01001359 dcl->ops->dpy_text_cursor(dcl, x, y);
Gerd Hoffmann7c20b4a2012-11-13 14:51:41 +01001360 }
1361 }
1362}
1363
Gerd Hoffmannc78f7132013-03-05 15:24:14 +01001364void dpy_text_update(QemuConsole *con, int x, int y, int w, int h)
Gerd Hoffmann7c20b4a2012-11-13 14:51:41 +01001365{
Gerd Hoffmannc78f7132013-03-05 15:24:14 +01001366 DisplayState *s = con->ds;
Gerd Hoffmann7c20b4a2012-11-13 14:51:41 +01001367 struct DisplayChangeListener *dcl;
1368 QLIST_FOREACH(dcl, &s->listeners, next) {
1369 if (dcl->ops->dpy_text_update) {
Gerd Hoffmannbc2ed972013-03-01 13:03:04 +01001370 dcl->ops->dpy_text_update(dcl, x, y, w, h);
Gerd Hoffmann7c20b4a2012-11-13 14:51:41 +01001371 }
1372 }
1373}
1374
Gerd Hoffmannc78f7132013-03-05 15:24:14 +01001375void dpy_text_resize(QemuConsole *con, int w, int h)
Gerd Hoffmann7c20b4a2012-11-13 14:51:41 +01001376{
Gerd Hoffmannc78f7132013-03-05 15:24:14 +01001377 DisplayState *s = con->ds;
Gerd Hoffmann7c20b4a2012-11-13 14:51:41 +01001378 struct DisplayChangeListener *dcl;
1379 QLIST_FOREACH(dcl, &s->listeners, next) {
1380 if (dcl->ops->dpy_text_resize) {
Gerd Hoffmannbc2ed972013-03-01 13:03:04 +01001381 dcl->ops->dpy_text_resize(dcl, w, h);
Gerd Hoffmann7c20b4a2012-11-13 14:51:41 +01001382 }
1383 }
1384}
1385
Gerd Hoffmannc78f7132013-03-05 15:24:14 +01001386void dpy_mouse_set(QemuConsole *con, int x, int y, int on)
Gerd Hoffmann7c20b4a2012-11-13 14:51:41 +01001387{
Gerd Hoffmannc78f7132013-03-05 15:24:14 +01001388 DisplayState *s = con->ds;
Gerd Hoffmann7c20b4a2012-11-13 14:51:41 +01001389 struct DisplayChangeListener *dcl;
1390 QLIST_FOREACH(dcl, &s->listeners, next) {
1391 if (dcl->ops->dpy_mouse_set) {
Gerd Hoffmannbc2ed972013-03-01 13:03:04 +01001392 dcl->ops->dpy_mouse_set(dcl, x, y, on);
Gerd Hoffmann7c20b4a2012-11-13 14:51:41 +01001393 }
1394 }
1395}
1396
Gerd Hoffmannc78f7132013-03-05 15:24:14 +01001397void dpy_cursor_define(QemuConsole *con, QEMUCursor *cursor)
Gerd Hoffmann7c20b4a2012-11-13 14:51:41 +01001398{
Gerd Hoffmannc78f7132013-03-05 15:24:14 +01001399 DisplayState *s = con->ds;
Gerd Hoffmann7c20b4a2012-11-13 14:51:41 +01001400 struct DisplayChangeListener *dcl;
1401 QLIST_FOREACH(dcl, &s->listeners, next) {
1402 if (dcl->ops->dpy_cursor_define) {
Gerd Hoffmannbc2ed972013-03-01 13:03:04 +01001403 dcl->ops->dpy_cursor_define(dcl, cursor);
Gerd Hoffmann7c20b4a2012-11-13 14:51:41 +01001404 }
1405 }
1406}
1407
Gerd Hoffmannc78f7132013-03-05 15:24:14 +01001408bool dpy_cursor_define_supported(QemuConsole *con)
Gerd Hoffmann7c20b4a2012-11-13 14:51:41 +01001409{
Gerd Hoffmannc78f7132013-03-05 15:24:14 +01001410 DisplayState *s = con->ds;
Gerd Hoffmann7c20b4a2012-11-13 14:51:41 +01001411 struct DisplayChangeListener *dcl;
1412 QLIST_FOREACH(dcl, &s->listeners, next) {
1413 if (dcl->ops->dpy_cursor_define) {
1414 return true;
1415 }
1416 }
1417 return false;
1418}
1419
Paolo Bonzini98b50082010-02-11 00:29:57 +01001420static void dumb_display_init(void)
1421{
Anthony Liguori7267c092011-08-20 22:09:37 -05001422 DisplayState *ds = g_malloc0(sizeof(DisplayState));
Jan Kiszka18026512011-06-19 11:53:02 +02001423 int width = 640;
1424 int height = 480;
1425
Jan Kiszka18026512011-06-19 11:53:02 +02001426 if (is_fixedsize_console()) {
1427 width = active_console->g_width;
1428 height = active_console->g_height;
1429 }
Gerd Hoffmannc78f7132013-03-05 15:24:14 +01001430 ds->surface = qemu_create_displaysurface(width, height);
Gerd Hoffmannda229ef2013-02-28 10:48:02 +01001431
Paolo Bonzini98b50082010-02-11 00:29:57 +01001432 register_displaystate(ds);
1433}
1434
1435/***********************************************************/
1436/* register display */
1437
1438void register_displaystate(DisplayState *ds)
1439{
1440 DisplayState **s;
1441 s = &display_state;
1442 while (*s != NULL)
1443 s = &(*s)->next;
1444 ds->next = NULL;
1445 *s = ds;
1446}
1447
1448DisplayState *get_displaystate(void)
1449{
1450 if (!display_state) {
1451 dumb_display_init ();
1452 }
1453 return display_state;
1454}
1455
Gerd Hoffmannc78f7132013-03-05 15:24:14 +01001456QemuConsole *graphic_console_init(vga_hw_update_ptr update,
1457 vga_hw_invalidate_ptr invalidate,
1458 vga_hw_screen_dump_ptr screen_dump,
1459 vga_hw_text_update_ptr text_update,
1460 void *opaque)
bellarde7f0ad52004-07-14 17:28:59 +00001461{
Gerd Hoffmann76ffb0b2012-09-28 13:24:17 +02001462 QemuConsole *s;
aliguori3023f332009-01-16 19:04:14 +00001463 DisplayState *ds;
aurel32f0f2f972009-01-16 21:13:49 +00001464
Anthony Liguori7267c092011-08-20 22:09:37 -05001465 ds = (DisplayState *) g_malloc0(sizeof(DisplayState));
thsaf3a9032007-07-11 23:14:59 +00001466 s = new_console(ds, GRAPHIC_CONSOLE);
pbrook95219892006-04-09 01:06:34 +00001467 s->hw_update = update;
1468 s->hw_invalidate = invalidate;
1469 s->hw_screen_dump = screen_dump;
balrog4d3b6f62008-02-10 16:33:14 +00001470 s->hw_text_update = text_update;
pbrook95219892006-04-09 01:06:34 +00001471 s->hw = opaque;
aliguori3023f332009-01-16 19:04:14 +00001472
Gerd Hoffmannc78f7132013-03-05 15:24:14 +01001473 ds->surface = qemu_create_displaysurface(640, 480);
Gerd Hoffmannda229ef2013-02-28 10:48:02 +01001474
aurel32f0f2f972009-01-16 21:13:49 +00001475 register_displaystate(ds);
Gerd Hoffmannc78f7132013-03-05 15:24:14 +01001476 return s;
pbrook95219892006-04-09 01:06:34 +00001477}
1478
1479int is_graphic_console(void)
1480{
balrog4d3b6f62008-02-10 16:33:14 +00001481 return active_console && active_console->console_type == GRAPHIC_CONSOLE;
bellarde7f0ad52004-07-14 17:28:59 +00001482}
1483
balrogc21bbcf2008-09-24 03:32:33 +00001484int is_fixedsize_console(void)
1485{
1486 return active_console && active_console->console_type != TEXT_CONSOLE;
1487}
1488
Paolo Bonzini41048332010-12-23 13:42:52 +01001489static void text_console_set_echo(CharDriverState *chr, bool echo)
1490{
Gerd Hoffmann76ffb0b2012-09-28 13:24:17 +02001491 QemuConsole *s = chr->opaque;
Paolo Bonzini41048332010-12-23 13:42:52 +01001492
1493 s->echo = echo;
1494}
1495
Jan Kiszkabf1bed82012-07-10 22:00:55 +02001496static void text_console_update_cursor(void *opaque)
1497{
Gerd Hoffmann76ffb0b2012-09-28 13:24:17 +02001498 QemuConsole *s = opaque;
Jan Kiszkabf1bed82012-07-10 22:00:55 +02001499
1500 s->cursor_visible_phase = !s->cursor_visible_phase;
1501 vga_hw_invalidate();
1502 qemu_mod_timer(s->cursor_timer,
1503 qemu_get_clock_ms(rt_clock) + CONSOLE_CURSOR_PERIOD / 2);
1504}
1505
Paolo Bonzini44b37b92010-12-23 13:42:53 +01001506static void text_console_do_init(CharDriverState *chr, DisplayState *ds)
bellarde7f0ad52004-07-14 17:28:59 +00001507{
Gerd Hoffmann76ffb0b2012-09-28 13:24:17 +02001508 QemuConsole *s;
pbrook6d6f7c22006-03-11 15:35:30 +00001509
Paolo Bonzini491e1142010-12-23 13:42:51 +01001510 s = chr->opaque;
Gerd Hoffmann6ea314d2009-09-10 10:58:49 +02001511
bellarde7f0ad52004-07-14 17:28:59 +00001512 chr->chr_write = console_puts;
bellard6fcfafb2004-08-01 21:48:30 +00001513
bellarde15d7372006-06-25 16:26:29 +00001514 s->out_fifo.buf = s->out_fifo_buf;
1515 s->out_fifo.buf_size = sizeof(s->out_fifo_buf);
Paolo Bonzini7bd427d2011-03-11 16:47:48 +01001516 s->kbd_timer = qemu_new_timer_ms(rt_clock, kbd_send_chars, s);
aliguori3023f332009-01-16 19:04:14 +00001517 s->ds = ds;
ths3b46e622007-09-17 08:09:54 +00001518
bellarde7f0ad52004-07-14 17:28:59 +00001519 s->y_displayed = 0;
1520 s->y_base = 0;
1521 s->total_height = DEFAULT_BACKSCROLL;
1522 s->x = 0;
1523 s->y = 0;
Paolo Bonzini491e1142010-12-23 13:42:51 +01001524 if (s->console_type == TEXT_CONSOLE) {
Gerd Hoffmann1562e532013-03-06 13:40:47 +01001525 s->g_width = surface_width(s->ds->surface);
1526 s->g_height = surface_height(s->ds->surface);
Paolo Bonzini491e1142010-12-23 13:42:51 +01001527 }
pbrook6d6f7c22006-03-11 15:35:30 +00001528
Jan Kiszkabf1bed82012-07-10 22:00:55 +02001529 s->cursor_timer =
1530 qemu_new_timer_ms(rt_clock, text_console_update_cursor, s);
1531
balrog4d3b6f62008-02-10 16:33:14 +00001532 s->hw_invalidate = text_console_invalidate;
1533 s->hw_text_update = text_console_update;
1534 s->hw = s;
1535
pbrook6d6f7c22006-03-11 15:35:30 +00001536 /* Set text attribute defaults */
1537 s->t_attrib_default.bold = 0;
1538 s->t_attrib_default.uline = 0;
1539 s->t_attrib_default.blink = 0;
1540 s->t_attrib_default.invers = 0;
1541 s->t_attrib_default.unvisible = 0;
1542 s->t_attrib_default.fgcol = COLOR_WHITE;
1543 s->t_attrib_default.bgcol = COLOR_BLACK;
pbrook6d6f7c22006-03-11 15:35:30 +00001544 /* set current text attributes to default */
1545 s->t_attrib = s->t_attrib_default;
bellarde7f0ad52004-07-14 17:28:59 +00001546 text_console_resize(s);
1547
Gerd Hoffmann51bfa4d2009-12-08 13:11:39 +01001548 if (chr->label) {
1549 char msg[128];
1550 int len;
1551
Gerd Hoffmann735ba582009-12-08 13:11:40 +01001552 s->t_attrib.bgcol = COLOR_BLUE;
Gerd Hoffmann51bfa4d2009-12-08 13:11:39 +01001553 len = snprintf(msg, sizeof(msg), "%s console\r\n", chr->label);
1554 console_puts(chr, (uint8_t*)msg, len);
Gerd Hoffmann735ba582009-12-08 13:11:40 +01001555 s->t_attrib = s->t_attrib_default;
Gerd Hoffmann51bfa4d2009-12-08 13:11:39 +01001556 }
1557
Hans de Goedefee204f2013-03-26 11:07:54 +01001558 qemu_chr_be_generic_open(chr);
aurel32ceecf1d2009-01-18 14:08:04 +00001559 if (chr->init)
1560 chr->init(chr);
bellarde7f0ad52004-07-14 17:28:59 +00001561}
pbrookc60e08d2008-07-01 16:24:38 +00001562
Gerd Hoffmann702ec692013-02-25 15:52:32 +01001563static CharDriverState *text_console_init(ChardevVC *vc)
aliguori2796dae2009-01-16 20:23:27 +00001564{
1565 CharDriverState *chr;
Gerd Hoffmann76ffb0b2012-09-28 13:24:17 +02001566 QemuConsole *s;
Gerd Hoffmann702ec692013-02-25 15:52:32 +01001567 unsigned width = 0;
1568 unsigned height = 0;
aliguori2796dae2009-01-16 20:23:27 +00001569
Anthony Liguori7267c092011-08-20 22:09:37 -05001570 chr = g_malloc0(sizeof(CharDriverState));
aliguori2796dae2009-01-16 20:23:27 +00001571
Gerd Hoffmann702ec692013-02-25 15:52:32 +01001572 if (vc->has_width) {
1573 width = vc->width;
1574 } else if (vc->has_cols) {
1575 width = vc->cols * FONT_WIDTH;
1576 }
Paolo Bonzini491e1142010-12-23 13:42:51 +01001577
Gerd Hoffmann702ec692013-02-25 15:52:32 +01001578 if (vc->has_height) {
1579 height = vc->height;
1580 } else if (vc->has_rows) {
1581 height = vc->rows * FONT_HEIGHT;
1582 }
Paolo Bonzini491e1142010-12-23 13:42:51 +01001583
1584 if (width == 0 || height == 0) {
1585 s = new_console(NULL, TEXT_CONSOLE);
1586 } else {
1587 s = new_console(NULL, TEXT_CONSOLE_FIXED_SIZE);
1588 }
1589
1590 if (!s) {
Stefan Weil5354d082011-10-02 18:53:09 +02001591 g_free(chr);
Markus Armbruster1f514702012-02-07 15:09:08 +01001592 return NULL;
Paolo Bonzini491e1142010-12-23 13:42:51 +01001593 }
1594
1595 s->chr = chr;
1596 s->g_width = width;
1597 s->g_height = height;
1598 chr->opaque = s;
Paolo Bonzini41048332010-12-23 13:42:52 +01001599 chr->chr_set_echo = text_console_set_echo;
Markus Armbruster1f514702012-02-07 15:09:08 +01001600 return chr;
aliguori2796dae2009-01-16 20:23:27 +00001601}
1602
Anthony Liguorid82831d2013-02-20 07:43:19 -06001603static VcHandler *vc_handler = text_console_init;
1604
Gerd Hoffmann702ec692013-02-25 15:52:32 +01001605CharDriverState *vc_init(ChardevVC *vc)
Anthony Liguorid82831d2013-02-20 07:43:19 -06001606{
Gerd Hoffmann702ec692013-02-25 15:52:32 +01001607 return vc_handler(vc);
Anthony Liguorid82831d2013-02-20 07:43:19 -06001608}
1609
1610void register_vc_handler(VcHandler *handler)
1611{
1612 vc_handler = handler;
1613}
1614
aliguori2796dae2009-01-16 20:23:27 +00001615void text_consoles_set_display(DisplayState *ds)
1616{
1617 int i;
1618
Markus Armbruster8811e1e2012-02-07 15:09:21 +01001619 for (i = 0; i < nb_consoles; i++) {
1620 if (consoles[i]->console_type != GRAPHIC_CONSOLE) {
1621 text_console_do_init(consoles[i]->chr, ds);
1622 }
aliguori2796dae2009-01-16 20:23:27 +00001623 }
aliguori2796dae2009-01-16 20:23:27 +00001624}
1625
Gerd Hoffmannc78f7132013-03-05 15:24:14 +01001626void qemu_console_resize(QemuConsole *s, int width, int height)
pbrookc60e08d2008-07-01 16:24:38 +00001627{
aliguori3023f332009-01-16 19:04:14 +00001628 s->g_width = width;
1629 s->g_height = height;
1630 if (is_graphic_console()) {
Gerd Hoffmannda229ef2013-02-28 10:48:02 +01001631 DisplaySurface *surface;
1632 surface = qemu_create_displaysurface(width, height);
Gerd Hoffmannc78f7132013-03-05 15:24:14 +01001633 dpy_gfx_replace_surface(s, surface);
pbrookc60e08d2008-07-01 16:24:38 +00001634 }
1635}
balrog38334f72008-09-24 02:21:24 +00001636
Gerd Hoffmannc78f7132013-03-05 15:24:14 +01001637void qemu_console_copy(QemuConsole *con, int src_x, int src_y,
aliguori3023f332009-01-16 19:04:14 +00001638 int dst_x, int dst_y, int w, int h)
balrogc21bbcf2008-09-24 03:32:33 +00001639{
aliguori3023f332009-01-16 19:04:14 +00001640 if (is_graphic_console()) {
Gerd Hoffmannc78f7132013-03-05 15:24:14 +01001641 dpy_gfx_copy(con, src_x, src_y, dst_x, dst_y, w, h);
balrog38334f72008-09-24 02:21:24 +00001642 }
1643}
aliguori7d957bd2009-01-15 22:14:11 +00001644
Gerd Hoffmannc78f7132013-03-05 15:24:14 +01001645DisplaySurface *qemu_console_surface(QemuConsole *console)
1646{
1647 return console->ds->surface;
1648}
1649
1650DisplayState *qemu_console_displaystate(QemuConsole *console)
1651{
1652 return console->ds;
1653}
1654
malc0da2ea12009-01-23 19:56:19 +00001655PixelFormat qemu_different_endianness_pixelformat(int bpp)
aliguori7d957bd2009-01-15 22:14:11 +00001656{
1657 PixelFormat pf;
1658
1659 memset(&pf, 0x00, sizeof(PixelFormat));
1660
1661 pf.bits_per_pixel = bpp;
BALATON Zoltanfeadf1a2012-08-22 17:19:42 +02001662 pf.bytes_per_pixel = DIV_ROUND_UP(bpp, 8);
aliguori7d957bd2009-01-15 22:14:11 +00001663 pf.depth = bpp == 32 ? 24 : bpp;
1664
1665 switch (bpp) {
malc0da2ea12009-01-23 19:56:19 +00001666 case 24:
1667 pf.rmask = 0x000000FF;
1668 pf.gmask = 0x0000FF00;
1669 pf.bmask = 0x00FF0000;
1670 pf.rmax = 255;
1671 pf.gmax = 255;
1672 pf.bmax = 255;
1673 pf.rshift = 0;
1674 pf.gshift = 8;
1675 pf.bshift = 16;
aliguori90a1e3c2009-01-26 15:37:30 +00001676 pf.rbits = 8;
1677 pf.gbits = 8;
1678 pf.bbits = 8;
aliguori7d957bd2009-01-15 22:14:11 +00001679 break;
malc0da2ea12009-01-23 19:56:19 +00001680 case 32:
1681 pf.rmask = 0x0000FF00;
1682 pf.gmask = 0x00FF0000;
1683 pf.bmask = 0xFF000000;
1684 pf.amask = 0x00000000;
1685 pf.amax = 255;
1686 pf.rmax = 255;
1687 pf.gmax = 255;
1688 pf.bmax = 255;
1689 pf.ashift = 0;
1690 pf.rshift = 8;
1691 pf.gshift = 16;
1692 pf.bshift = 24;
aliguori90a1e3c2009-01-26 15:37:30 +00001693 pf.rbits = 8;
1694 pf.gbits = 8;
1695 pf.bbits = 8;
1696 pf.abits = 8;
malc0da2ea12009-01-23 19:56:19 +00001697 break;
1698 default:
1699 break;
1700 }
1701 return pf;
1702}
1703
1704PixelFormat qemu_default_pixelformat(int bpp)
1705{
1706 PixelFormat pf;
1707
1708 memset(&pf, 0x00, sizeof(PixelFormat));
1709
1710 pf.bits_per_pixel = bpp;
BALATON Zoltanfeadf1a2012-08-22 17:19:42 +02001711 pf.bytes_per_pixel = DIV_ROUND_UP(bpp, 8);
malc0da2ea12009-01-23 19:56:19 +00001712 pf.depth = bpp == 32 ? 24 : bpp;
1713
1714 switch (bpp) {
Gerd Hoffmannb6278082010-05-21 11:59:14 +02001715 case 15:
1716 pf.bits_per_pixel = 16;
Gerd Hoffmannb6278082010-05-21 11:59:14 +02001717 pf.rmask = 0x00007c00;
1718 pf.gmask = 0x000003E0;
1719 pf.bmask = 0x0000001F;
1720 pf.rmax = 31;
1721 pf.gmax = 31;
1722 pf.bmax = 31;
1723 pf.rshift = 10;
1724 pf.gshift = 5;
1725 pf.bshift = 0;
1726 pf.rbits = 5;
1727 pf.gbits = 5;
1728 pf.bbits = 5;
1729 break;
aliguori7d957bd2009-01-15 22:14:11 +00001730 case 16:
1731 pf.rmask = 0x0000F800;
1732 pf.gmask = 0x000007E0;
1733 pf.bmask = 0x0000001F;
1734 pf.rmax = 31;
1735 pf.gmax = 63;
1736 pf.bmax = 31;
1737 pf.rshift = 11;
1738 pf.gshift = 5;
1739 pf.bshift = 0;
aliguori90a1e3c2009-01-26 15:37:30 +00001740 pf.rbits = 5;
1741 pf.gbits = 6;
1742 pf.bbits = 5;
aliguori7d957bd2009-01-15 22:14:11 +00001743 break;
1744 case 24:
aliguori7d957bd2009-01-15 22:14:11 +00001745 pf.rmask = 0x00FF0000;
1746 pf.gmask = 0x0000FF00;
1747 pf.bmask = 0x000000FF;
1748 pf.rmax = 255;
1749 pf.gmax = 255;
1750 pf.bmax = 255;
1751 pf.rshift = 16;
1752 pf.gshift = 8;
1753 pf.bshift = 0;
aliguori90a1e3c2009-01-26 15:37:30 +00001754 pf.rbits = 8;
1755 pf.gbits = 8;
1756 pf.bbits = 8;
Markus Armbruster0eba62e2011-11-22 12:56:10 +01001757 break;
malc0da2ea12009-01-23 19:56:19 +00001758 case 32:
1759 pf.rmask = 0x00FF0000;
1760 pf.gmask = 0x0000FF00;
1761 pf.bmask = 0x000000FF;
malc0da2ea12009-01-23 19:56:19 +00001762 pf.rmax = 255;
1763 pf.gmax = 255;
1764 pf.bmax = 255;
malc0da2ea12009-01-23 19:56:19 +00001765 pf.rshift = 16;
1766 pf.gshift = 8;
1767 pf.bshift = 0;
aliguori90a1e3c2009-01-26 15:37:30 +00001768 pf.rbits = 8;
1769 pf.gbits = 8;
1770 pf.bbits = 8;
aliguori7d957bd2009-01-15 22:14:11 +00001771 break;
1772 default:
1773 break;
1774 }
1775 return pf;
1776}
Anthony Liguori01f45d92013-03-05 23:21:32 +05301777
Gerd Hoffmann702ec692013-02-25 15:52:32 +01001778static void qemu_chr_parse_vc(QemuOpts *opts, ChardevBackend *backend,
1779 Error **errp)
1780{
1781 int val;
1782
1783 backend->vc = g_new0(ChardevVC, 1);
1784
1785 val = qemu_opt_get_number(opts, "width", 0);
1786 if (val != 0) {
1787 backend->vc->has_width = true;
1788 backend->vc->width = val;
1789 }
1790
1791 val = qemu_opt_get_number(opts, "height", 0);
1792 if (val != 0) {
1793 backend->vc->has_height = true;
1794 backend->vc->height = val;
1795 }
1796
1797 val = qemu_opt_get_number(opts, "cols", 0);
1798 if (val != 0) {
1799 backend->vc->has_cols = true;
1800 backend->vc->cols = val;
1801 }
1802
1803 val = qemu_opt_get_number(opts, "rows", 0);
1804 if (val != 0) {
1805 backend->vc->has_rows = true;
1806 backend->vc->rows = val;
1807 }
1808}
1809
Anthony Liguori01f45d92013-03-05 23:21:32 +05301810static void register_types(void)
1811{
Gerd Hoffmann702ec692013-02-25 15:52:32 +01001812 register_char_driver_qapi("vc", CHARDEV_BACKEND_KIND_VC,
1813 qemu_chr_parse_vc);
Anthony Liguori01f45d92013-03-05 23:21:32 +05301814}
1815
1816type_init(register_types);