blob: 048b48e721a7297e1d15a2b54088ebb5b7067597 [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"
25#include "console.h"
26#include "qemu-timer.h"
Luiz Capitulinoad39cf62012-05-24 13:48:23 -030027#include "qmp-commands.h"
bellarde7f0ad52004-07-14 17:28:59 +000028
pbrook6d6f7c22006-03-11 15:35:30 +000029//#define DEBUG_CONSOLE
bellarde7f0ad52004-07-14 17:28:59 +000030#define DEFAULT_BACKSCROLL 512
31#define MAX_CONSOLES 12
Jan Kiszkabf1bed82012-07-10 22:00:55 +020032#define CONSOLE_CURSOR_PERIOD 500
bellarde7f0ad52004-07-14 17:28:59 +000033
bellard26489842006-06-25 17:37:36 +000034#define QEMU_RGBA(r, g, b, a) (((a) << 24) | ((r) << 16) | ((g) << 8) | (b))
35#define QEMU_RGB(r, g, b) QEMU_RGBA(r, g, b, 0xff)
bellarde7f0ad52004-07-14 17:28:59 +000036
pbrook6d6f7c22006-03-11 15:35:30 +000037typedef struct TextAttributes {
38 uint8_t fgcol:4;
39 uint8_t bgcol:4;
40 uint8_t bold:1;
41 uint8_t uline:1;
42 uint8_t blink:1;
43 uint8_t invers:1;
44 uint8_t unvisible:1;
45} TextAttributes;
46
bellarde7f0ad52004-07-14 17:28:59 +000047typedef struct TextCell {
48 uint8_t ch;
pbrook6d6f7c22006-03-11 15:35:30 +000049 TextAttributes t_attrib;
bellarde7f0ad52004-07-14 17:28:59 +000050} TextCell;
51
52#define MAX_ESC_PARAMS 3
53
54enum TTYState {
55 TTY_STATE_NORM,
56 TTY_STATE_ESC,
57 TTY_STATE_CSI,
58};
59
bellarde15d7372006-06-25 16:26:29 +000060typedef struct QEMUFIFO {
61 uint8_t *buf;
62 int buf_size;
63 int count, wptr, rptr;
64} QEMUFIFO;
65
pbrook9596ebb2007-11-18 01:44:38 +000066static int qemu_fifo_write(QEMUFIFO *f, const uint8_t *buf, int len1)
bellarde15d7372006-06-25 16:26:29 +000067{
68 int l, len;
69
70 l = f->buf_size - f->count;
71 if (len1 > l)
72 len1 = l;
73 len = len1;
74 while (len > 0) {
75 l = f->buf_size - f->wptr;
76 if (l > len)
77 l = len;
78 memcpy(f->buf + f->wptr, buf, l);
79 f->wptr += l;
80 if (f->wptr >= f->buf_size)
81 f->wptr = 0;
82 buf += l;
83 len -= l;
84 }
85 f->count += len1;
86 return len1;
87}
88
pbrook9596ebb2007-11-18 01:44:38 +000089static int qemu_fifo_read(QEMUFIFO *f, uint8_t *buf, int len1)
bellarde15d7372006-06-25 16:26:29 +000090{
91 int l, len;
92
93 if (len1 > f->count)
94 len1 = f->count;
95 len = len1;
96 while (len > 0) {
97 l = f->buf_size - f->rptr;
98 if (l > len)
99 l = len;
100 memcpy(buf, f->buf + f->rptr, l);
101 f->rptr += l;
102 if (f->rptr >= f->buf_size)
103 f->rptr = 0;
104 buf += l;
105 len -= l;
106 }
107 f->count -= len1;
108 return len1;
109}
110
thsaf3a9032007-07-11 23:14:59 +0000111typedef enum {
112 GRAPHIC_CONSOLE,
balrogc21bbcf2008-09-24 03:32:33 +0000113 TEXT_CONSOLE,
114 TEXT_CONSOLE_FIXED_SIZE
Anthony Liguoric227f092009-10-01 16:12:16 -0500115} console_type_t;
thsaf3a9032007-07-11 23:14:59 +0000116
Gerd Hoffmann76ffb0b2012-09-28 13:24:17 +0200117struct QemuConsole {
Jan Kiszkaf81bdef2011-09-16 00:48:07 +0200118 int index;
Anthony Liguoric227f092009-10-01 16:12:16 -0500119 console_type_t console_type;
bellarde7f0ad52004-07-14 17:28:59 +0000120 DisplayState *ds;
Gerd Hoffmann76ffb0b2012-09-28 13:24:17 +0200121
pbrook95219892006-04-09 01:06:34 +0000122 /* Graphic console state. */
123 vga_hw_update_ptr hw_update;
124 vga_hw_invalidate_ptr hw_invalidate;
125 vga_hw_screen_dump_ptr hw_screen_dump;
balrog4d3b6f62008-02-10 16:33:14 +0000126 vga_hw_text_update_ptr hw_text_update;
pbrook95219892006-04-09 01:06:34 +0000127 void *hw;
bellarde7f0ad52004-07-14 17:28:59 +0000128 int g_width, g_height;
Gerd Hoffmann76ffb0b2012-09-28 13:24:17 +0200129
130 /* Text console state */
bellarde7f0ad52004-07-14 17:28:59 +0000131 int width;
132 int height;
133 int total_height;
134 int backscroll_height;
bellarde7f0ad52004-07-14 17:28:59 +0000135 int x, y;
thsadb47962007-01-16 23:02:36 +0000136 int x_saved, y_saved;
bellarde7f0ad52004-07-14 17:28:59 +0000137 int y_displayed;
138 int y_base;
pbrook6d6f7c22006-03-11 15:35:30 +0000139 TextAttributes t_attrib_default; /* default text attributes */
140 TextAttributes t_attrib; /* currently active text attributes */
bellarde7f0ad52004-07-14 17:28:59 +0000141 TextCell *cells;
balrog4d3b6f62008-02-10 16:33:14 +0000142 int text_x[2], text_y[2], cursor_invalidate;
Paolo Bonzini41048332010-12-23 13:42:52 +0100143 int echo;
Jan Kiszkabf1bed82012-07-10 22:00:55 +0200144 bool cursor_visible_phase;
145 QEMUTimer *cursor_timer;
bellarde7f0ad52004-07-14 17:28:59 +0000146
pbrook14778c22009-01-21 03:02:52 +0000147 int update_x0;
148 int update_y0;
149 int update_x1;
150 int update_y1;
151
bellarde7f0ad52004-07-14 17:28:59 +0000152 enum TTYState state;
153 int esc_params[MAX_ESC_PARAMS];
154 int nb_esc_params;
155
pbrooke5b0bc42007-01-27 23:46:43 +0000156 CharDriverState *chr;
bellarde15d7372006-06-25 16:26:29 +0000157 /* fifo for key pressed */
158 QEMUFIFO out_fifo;
159 uint8_t out_fifo_buf[16];
160 QEMUTimer *kbd_timer;
bellarde7f0ad52004-07-14 17:28:59 +0000161};
162
Paolo Bonzini98b50082010-02-11 00:29:57 +0100163static DisplayState *display_state;
Gerd Hoffmann76ffb0b2012-09-28 13:24:17 +0200164static QemuConsole *active_console;
165static QemuConsole *consoles[MAX_CONSOLES];
bellarde7f0ad52004-07-14 17:28:59 +0000166static int nb_consoles = 0;
167
pbrook95219892006-04-09 01:06:34 +0000168void vga_hw_update(void)
169{
thsadb47962007-01-16 23:02:36 +0000170 if (active_console && active_console->hw_update)
pbrook95219892006-04-09 01:06:34 +0000171 active_console->hw_update(active_console->hw);
172}
173
174void vga_hw_invalidate(void)
175{
Gerd Hoffmann26572b82010-05-20 15:23:06 +0200176 if (active_console && active_console->hw_invalidate)
pbrook95219892006-04-09 01:06:34 +0000177 active_console->hw_invalidate(active_console->hw);
178}
179
Luiz Capitulinoad39cf62012-05-24 13:48:23 -0300180void qmp_screendump(const char *filename, Error **errp)
pbrook95219892006-04-09 01:06:34 +0000181{
Gerd Hoffmann76ffb0b2012-09-28 13:24:17 +0200182 QemuConsole *previous_active_console;
Gerd Hoffmann45efb162012-02-24 12:43:45 +0100183 bool cswitch;
balrog8571c052008-07-19 13:04:26 +0000184
185 previous_active_console = active_console;
Gerd Hoffmann45efb162012-02-24 12:43:45 +0100186 cswitch = previous_active_console && previous_active_console->index != 0;
Jan Kiszkaf81bdef2011-09-16 00:48:07 +0200187
balrog8571c052008-07-19 13:04:26 +0000188 /* There is currently no way of specifying which screen we want to dump,
aurel327b455222008-09-02 00:09:16 +0000189 so always dump the first one. */
Gerd Hoffmann45efb162012-02-24 12:43:45 +0100190 if (cswitch) {
191 console_select(0);
192 }
Jan Kiszkaf81bdef2011-09-16 00:48:07 +0200193 if (consoles[0] && consoles[0]->hw_screen_dump) {
Luiz Capitulinoad39cf62012-05-24 13:48:23 -0300194 consoles[0]->hw_screen_dump(consoles[0]->hw, filename, cswitch, errp);
Gerd Hoffmann16735102012-02-24 12:43:44 +0100195 } else {
Luiz Capitulinoad39cf62012-05-24 13:48:23 -0300196 error_setg(errp, "device doesn't support screendump\n");
Jan Kiszkaf81bdef2011-09-16 00:48:07 +0200197 }
198
Gerd Hoffmann45efb162012-02-24 12:43:45 +0100199 if (cswitch) {
Alexander Graf33bcd982011-11-18 16:41:59 +0100200 console_select(previous_active_console->index);
201 }
pbrook95219892006-04-09 01:06:34 +0000202}
203
Anthony Liguoric227f092009-10-01 16:12:16 -0500204void vga_hw_text_update(console_ch_t *chardata)
balrog4d3b6f62008-02-10 16:33:14 +0000205{
206 if (active_console && active_console->hw_text_update)
207 active_console->hw_text_update(active_console->hw, chardata);
208}
209
bellarde7f0ad52004-07-14 17:28:59 +0000210/* convert a RGBA color to a color index usable in graphic primitives */
211static unsigned int vga_get_color(DisplayState *ds, unsigned int rgba)
212{
213 unsigned int r, g, b, color;
214
aliguori0e1f5a02008-11-24 19:29:13 +0000215 switch(ds_get_bits_per_pixel(ds)) {
bellarde7f0ad52004-07-14 17:28:59 +0000216#if 0
217 case 8:
218 r = (rgba >> 16) & 0xff;
219 g = (rgba >> 8) & 0xff;
220 b = (rgba) & 0xff;
ths5fafdf22007-09-16 21:08:06 +0000221 color = (rgb_to_index[r] * 6 * 6) +
222 (rgb_to_index[g] * 6) +
bellarde7f0ad52004-07-14 17:28:59 +0000223 (rgb_to_index[b]);
224 break;
225#endif
226 case 15:
227 r = (rgba >> 16) & 0xff;
228 g = (rgba >> 8) & 0xff;
229 b = (rgba) & 0xff;
230 color = ((r >> 3) << 10) | ((g >> 3) << 5) | (b >> 3);
231 break;
232 case 16:
233 r = (rgba >> 16) & 0xff;
234 g = (rgba >> 8) & 0xff;
235 b = (rgba) & 0xff;
236 color = ((r >> 3) << 11) | ((g >> 2) << 5) | (b >> 3);
237 break;
238 case 32:
239 default:
240 color = rgba;
241 break;
242 }
243 return color;
244}
245
ths5fafdf22007-09-16 21:08:06 +0000246static void vga_fill_rect (DisplayState *ds,
bellarde7f0ad52004-07-14 17:28:59 +0000247 int posx, int posy, int width, int height, uint32_t color)
248{
249 uint8_t *d, *d1;
250 int x, y, bpp;
ths3b46e622007-09-17 08:09:54 +0000251
aliguori0e1f5a02008-11-24 19:29:13 +0000252 bpp = (ds_get_bits_per_pixel(ds) + 7) >> 3;
253 d1 = ds_get_data(ds) +
254 ds_get_linesize(ds) * posy + bpp * posx;
bellarde7f0ad52004-07-14 17:28:59 +0000255 for (y = 0; y < height; y++) {
256 d = d1;
257 switch(bpp) {
258 case 1:
259 for (x = 0; x < width; x++) {
260 *((uint8_t *)d) = color;
261 d++;
262 }
263 break;
264 case 2:
265 for (x = 0; x < width; x++) {
266 *((uint16_t *)d) = color;
267 d += 2;
268 }
269 break;
270 case 4:
271 for (x = 0; x < width; x++) {
272 *((uint32_t *)d) = color;
273 d += 4;
274 }
275 break;
276 }
aliguori0e1f5a02008-11-24 19:29:13 +0000277 d1 += ds_get_linesize(ds);
bellarde7f0ad52004-07-14 17:28:59 +0000278 }
279}
280
281/* copy from (xs, ys) to (xd, yd) a rectangle of size (w, h) */
282static void vga_bitblt(DisplayState *ds, int xs, int ys, int xd, int yd, int w, int h)
283{
284 const uint8_t *s;
285 uint8_t *d;
286 int wb, y, bpp;
287
aliguori0e1f5a02008-11-24 19:29:13 +0000288 bpp = (ds_get_bits_per_pixel(ds) + 7) >> 3;
bellarde7f0ad52004-07-14 17:28:59 +0000289 wb = w * bpp;
290 if (yd <= ys) {
aliguori0e1f5a02008-11-24 19:29:13 +0000291 s = ds_get_data(ds) +
292 ds_get_linesize(ds) * ys + bpp * xs;
293 d = ds_get_data(ds) +
294 ds_get_linesize(ds) * yd + bpp * xd;
bellarde7f0ad52004-07-14 17:28:59 +0000295 for (y = 0; y < h; y++) {
296 memmove(d, s, wb);
aliguori0e1f5a02008-11-24 19:29:13 +0000297 d += ds_get_linesize(ds);
298 s += ds_get_linesize(ds);
bellarde7f0ad52004-07-14 17:28:59 +0000299 }
300 } else {
aliguori0e1f5a02008-11-24 19:29:13 +0000301 s = ds_get_data(ds) +
302 ds_get_linesize(ds) * (ys + h - 1) + bpp * xs;
303 d = ds_get_data(ds) +
304 ds_get_linesize(ds) * (yd + h - 1) + bpp * xd;
bellarde7f0ad52004-07-14 17:28:59 +0000305 for (y = 0; y < h; y++) {
306 memmove(d, s, wb);
aliguori0e1f5a02008-11-24 19:29:13 +0000307 d -= ds_get_linesize(ds);
308 s -= ds_get_linesize(ds);
bellarde7f0ad52004-07-14 17:28:59 +0000309 }
310 }
311}
312
313/***********************************************************/
314/* basic char display */
315
316#define FONT_HEIGHT 16
317#define FONT_WIDTH 8
318
319#include "vgafont.h"
320
321#define cbswap_32(__x) \
322((uint32_t)( \
323 (((uint32_t)(__x) & (uint32_t)0x000000ffUL) << 24) | \
324 (((uint32_t)(__x) & (uint32_t)0x0000ff00UL) << 8) | \
325 (((uint32_t)(__x) & (uint32_t)0x00ff0000UL) >> 8) | \
326 (((uint32_t)(__x) & (uint32_t)0xff000000UL) >> 24) ))
327
Juan Quintelae2542fe2009-07-27 16:13:06 +0200328#ifdef HOST_WORDS_BIGENDIAN
bellarde7f0ad52004-07-14 17:28:59 +0000329#define PAT(x) x
330#else
331#define PAT(x) cbswap_32(x)
332#endif
333
334static const uint32_t dmask16[16] = {
335 PAT(0x00000000),
336 PAT(0x000000ff),
337 PAT(0x0000ff00),
338 PAT(0x0000ffff),
339 PAT(0x00ff0000),
340 PAT(0x00ff00ff),
341 PAT(0x00ffff00),
342 PAT(0x00ffffff),
343 PAT(0xff000000),
344 PAT(0xff0000ff),
345 PAT(0xff00ff00),
346 PAT(0xff00ffff),
347 PAT(0xffff0000),
348 PAT(0xffff00ff),
349 PAT(0xffffff00),
350 PAT(0xffffffff),
351};
352
353static const uint32_t dmask4[4] = {
354 PAT(0x00000000),
355 PAT(0x0000ffff),
356 PAT(0xffff0000),
357 PAT(0xffffffff),
358};
359
pbrook6d6f7c22006-03-11 15:35:30 +0000360static uint32_t color_table[2][8];
bellarde7f0ad52004-07-14 17:28:59 +0000361
Devin J. Pohlydf00bed2011-09-07 15:44:36 -0400362#ifndef CONFIG_CURSES
pbrook6d6f7c22006-03-11 15:35:30 +0000363enum color_names {
364 COLOR_BLACK = 0,
365 COLOR_RED = 1,
366 COLOR_GREEN = 2,
367 COLOR_YELLOW = 3,
368 COLOR_BLUE = 4,
369 COLOR_MAGENTA = 5,
370 COLOR_CYAN = 6,
371 COLOR_WHITE = 7
372};
Devin J. Pohlydf00bed2011-09-07 15:44:36 -0400373#endif
pbrook6d6f7c22006-03-11 15:35:30 +0000374
375static const uint32_t color_table_rgb[2][8] = {
376 { /* dark */
bellard26489842006-06-25 17:37:36 +0000377 QEMU_RGB(0x00, 0x00, 0x00), /* black */
378 QEMU_RGB(0xaa, 0x00, 0x00), /* red */
379 QEMU_RGB(0x00, 0xaa, 0x00), /* green */
380 QEMU_RGB(0xaa, 0xaa, 0x00), /* yellow */
381 QEMU_RGB(0x00, 0x00, 0xaa), /* blue */
382 QEMU_RGB(0xaa, 0x00, 0xaa), /* magenta */
383 QEMU_RGB(0x00, 0xaa, 0xaa), /* cyan */
384 QEMU_RGB(0xaa, 0xaa, 0xaa), /* white */
pbrook6d6f7c22006-03-11 15:35:30 +0000385 },
386 { /* bright */
bellard26489842006-06-25 17:37:36 +0000387 QEMU_RGB(0x00, 0x00, 0x00), /* black */
388 QEMU_RGB(0xff, 0x00, 0x00), /* red */
389 QEMU_RGB(0x00, 0xff, 0x00), /* green */
390 QEMU_RGB(0xff, 0xff, 0x00), /* yellow */
391 QEMU_RGB(0x00, 0x00, 0xff), /* blue */
392 QEMU_RGB(0xff, 0x00, 0xff), /* magenta */
393 QEMU_RGB(0x00, 0xff, 0xff), /* cyan */
394 QEMU_RGB(0xff, 0xff, 0xff), /* white */
pbrook6d6f7c22006-03-11 15:35:30 +0000395 }
bellarde7f0ad52004-07-14 17:28:59 +0000396};
397
398static inline unsigned int col_expand(DisplayState *ds, unsigned int col)
399{
aliguori0e1f5a02008-11-24 19:29:13 +0000400 switch(ds_get_bits_per_pixel(ds)) {
bellarde7f0ad52004-07-14 17:28:59 +0000401 case 8:
402 col |= col << 8;
403 col |= col << 16;
404 break;
405 case 15:
406 case 16:
407 col |= col << 16;
408 break;
409 default:
410 break;
411 }
412
413 return col;
414}
pbrook6d6f7c22006-03-11 15:35:30 +0000415#ifdef DEBUG_CONSOLE
416static void console_print_text_attributes(TextAttributes *t_attrib, char ch)
417{
418 if (t_attrib->bold) {
419 printf("b");
420 } else {
421 printf(" ");
422 }
423 if (t_attrib->uline) {
424 printf("u");
425 } else {
426 printf(" ");
427 }
428 if (t_attrib->blink) {
429 printf("l");
430 } else {
431 printf(" ");
432 }
433 if (t_attrib->invers) {
434 printf("i");
435 } else {
436 printf(" ");
437 }
438 if (t_attrib->unvisible) {
439 printf("n");
440 } else {
441 printf(" ");
442 }
443
444 printf(" fg: %d bg: %d ch:'%2X' '%c'\n", t_attrib->fgcol, t_attrib->bgcol, ch, ch);
445}
446#endif
bellarde7f0ad52004-07-14 17:28:59 +0000447
ths5fafdf22007-09-16 21:08:06 +0000448static void vga_putcharxy(DisplayState *ds, int x, int y, int ch,
pbrook6d6f7c22006-03-11 15:35:30 +0000449 TextAttributes *t_attrib)
bellarde7f0ad52004-07-14 17:28:59 +0000450{
451 uint8_t *d;
452 const uint8_t *font_ptr;
453 unsigned int font_data, linesize, xorcol, bpp;
454 int i;
pbrook6d6f7c22006-03-11 15:35:30 +0000455 unsigned int fgcol, bgcol;
456
457#ifdef DEBUG_CONSOLE
458 printf("x: %2i y: %2i", x, y);
459 console_print_text_attributes(t_attrib, ch);
460#endif
461
462 if (t_attrib->invers) {
463 bgcol = color_table[t_attrib->bold][t_attrib->fgcol];
464 fgcol = color_table[t_attrib->bold][t_attrib->bgcol];
465 } else {
466 fgcol = color_table[t_attrib->bold][t_attrib->fgcol];
467 bgcol = color_table[t_attrib->bold][t_attrib->bgcol];
468 }
bellarde7f0ad52004-07-14 17:28:59 +0000469
aliguori0e1f5a02008-11-24 19:29:13 +0000470 bpp = (ds_get_bits_per_pixel(ds) + 7) >> 3;
471 d = ds_get_data(ds) +
472 ds_get_linesize(ds) * y * FONT_HEIGHT + bpp * x * FONT_WIDTH;
473 linesize = ds_get_linesize(ds);
bellarde7f0ad52004-07-14 17:28:59 +0000474 font_ptr = vgafont16 + FONT_HEIGHT * ch;
475 xorcol = bgcol ^ fgcol;
aliguori0e1f5a02008-11-24 19:29:13 +0000476 switch(ds_get_bits_per_pixel(ds)) {
bellarde7f0ad52004-07-14 17:28:59 +0000477 case 8:
478 for(i = 0; i < FONT_HEIGHT; i++) {
479 font_data = *font_ptr++;
pbrook6d6f7c22006-03-11 15:35:30 +0000480 if (t_attrib->uline
481 && ((i == FONT_HEIGHT - 2) || (i == FONT_HEIGHT - 3))) {
Markus Armbruster439229c2011-11-04 10:38:29 +0100482 font_data = 0xFF;
pbrook6d6f7c22006-03-11 15:35:30 +0000483 }
bellarde7f0ad52004-07-14 17:28:59 +0000484 ((uint32_t *)d)[0] = (dmask16[(font_data >> 4)] & xorcol) ^ bgcol;
485 ((uint32_t *)d)[1] = (dmask16[(font_data >> 0) & 0xf] & xorcol) ^ bgcol;
486 d += linesize;
487 }
488 break;
489 case 16:
490 case 15:
491 for(i = 0; i < FONT_HEIGHT; i++) {
492 font_data = *font_ptr++;
pbrook6d6f7c22006-03-11 15:35:30 +0000493 if (t_attrib->uline
494 && ((i == FONT_HEIGHT - 2) || (i == FONT_HEIGHT - 3))) {
Markus Armbruster439229c2011-11-04 10:38:29 +0100495 font_data = 0xFF;
pbrook6d6f7c22006-03-11 15:35:30 +0000496 }
bellarde7f0ad52004-07-14 17:28:59 +0000497 ((uint32_t *)d)[0] = (dmask4[(font_data >> 6)] & xorcol) ^ bgcol;
498 ((uint32_t *)d)[1] = (dmask4[(font_data >> 4) & 3] & xorcol) ^ bgcol;
499 ((uint32_t *)d)[2] = (dmask4[(font_data >> 2) & 3] & xorcol) ^ bgcol;
500 ((uint32_t *)d)[3] = (dmask4[(font_data >> 0) & 3] & xorcol) ^ bgcol;
501 d += linesize;
502 }
503 break;
504 case 32:
505 for(i = 0; i < FONT_HEIGHT; i++) {
506 font_data = *font_ptr++;
pbrook6d6f7c22006-03-11 15:35:30 +0000507 if (t_attrib->uline && ((i == FONT_HEIGHT - 2) || (i == FONT_HEIGHT - 3))) {
Markus Armbruster439229c2011-11-04 10:38:29 +0100508 font_data = 0xFF;
pbrook6d6f7c22006-03-11 15:35:30 +0000509 }
bellarde7f0ad52004-07-14 17:28:59 +0000510 ((uint32_t *)d)[0] = (-((font_data >> 7)) & xorcol) ^ bgcol;
511 ((uint32_t *)d)[1] = (-((font_data >> 6) & 1) & xorcol) ^ bgcol;
512 ((uint32_t *)d)[2] = (-((font_data >> 5) & 1) & xorcol) ^ bgcol;
513 ((uint32_t *)d)[3] = (-((font_data >> 4) & 1) & xorcol) ^ bgcol;
514 ((uint32_t *)d)[4] = (-((font_data >> 3) & 1) & xorcol) ^ bgcol;
515 ((uint32_t *)d)[5] = (-((font_data >> 2) & 1) & xorcol) ^ bgcol;
516 ((uint32_t *)d)[6] = (-((font_data >> 1) & 1) & xorcol) ^ bgcol;
517 ((uint32_t *)d)[7] = (-((font_data >> 0) & 1) & xorcol) ^ bgcol;
518 d += linesize;
519 }
520 break;
521 }
522}
523
Gerd Hoffmann76ffb0b2012-09-28 13:24:17 +0200524static void text_console_resize(QemuConsole *s)
bellarde7f0ad52004-07-14 17:28:59 +0000525{
526 TextCell *cells, *c, *c1;
527 int w1, x, y, last_width;
528
529 last_width = s->width;
530 s->width = s->g_width / FONT_WIDTH;
531 s->height = s->g_height / FONT_HEIGHT;
532
533 w1 = last_width;
534 if (s->width < w1)
535 w1 = s->width;
536
Anthony Liguori7267c092011-08-20 22:09:37 -0500537 cells = g_malloc(s->width * s->total_height * sizeof(TextCell));
bellarde7f0ad52004-07-14 17:28:59 +0000538 for(y = 0; y < s->total_height; y++) {
539 c = &cells[y * s->width];
540 if (w1 > 0) {
541 c1 = &s->cells[y * last_width];
542 for(x = 0; x < w1; x++) {
543 *c++ = *c1++;
544 }
545 }
546 for(x = w1; x < s->width; x++) {
547 c->ch = ' ';
pbrook6d6f7c22006-03-11 15:35:30 +0000548 c->t_attrib = s->t_attrib_default;
bellarde7f0ad52004-07-14 17:28:59 +0000549 c++;
550 }
551 }
Anthony Liguori7267c092011-08-20 22:09:37 -0500552 g_free(s->cells);
bellarde7f0ad52004-07-14 17:28:59 +0000553 s->cells = cells;
554}
555
Gerd Hoffmann76ffb0b2012-09-28 13:24:17 +0200556static inline void text_update_xy(QemuConsole *s, int x, int y)
balrog4d3b6f62008-02-10 16:33:14 +0000557{
558 s->text_x[0] = MIN(s->text_x[0], x);
559 s->text_x[1] = MAX(s->text_x[1], x);
560 s->text_y[0] = MIN(s->text_y[0], y);
561 s->text_y[1] = MAX(s->text_y[1], y);
562}
563
Gerd Hoffmann76ffb0b2012-09-28 13:24:17 +0200564static void invalidate_xy(QemuConsole *s, int x, int y)
pbrook14778c22009-01-21 03:02:52 +0000565{
566 if (s->update_x0 > x * FONT_WIDTH)
567 s->update_x0 = x * FONT_WIDTH;
568 if (s->update_y0 > y * FONT_HEIGHT)
569 s->update_y0 = y * FONT_HEIGHT;
570 if (s->update_x1 < (x + 1) * FONT_WIDTH)
571 s->update_x1 = (x + 1) * FONT_WIDTH;
572 if (s->update_y1 < (y + 1) * FONT_HEIGHT)
573 s->update_y1 = (y + 1) * FONT_HEIGHT;
574}
575
Gerd Hoffmann76ffb0b2012-09-28 13:24:17 +0200576static void update_xy(QemuConsole *s, int x, int y)
bellarde7f0ad52004-07-14 17:28:59 +0000577{
578 TextCell *c;
579 int y1, y2;
580
581 if (s == active_console) {
aliguori0e1f5a02008-11-24 19:29:13 +0000582 if (!ds_get_bits_per_pixel(s->ds)) {
balrog4d3b6f62008-02-10 16:33:14 +0000583 text_update_xy(s, x, y);
584 return;
585 }
586
bellarde7f0ad52004-07-14 17:28:59 +0000587 y1 = (s->y_base + y) % s->total_height;
588 y2 = y1 - s->y_displayed;
589 if (y2 < 0)
590 y2 += s->total_height;
591 if (y2 < s->height) {
592 c = &s->cells[y1 * s->width + x];
ths5fafdf22007-09-16 21:08:06 +0000593 vga_putcharxy(s->ds, x, y2, c->ch,
pbrook6d6f7c22006-03-11 15:35:30 +0000594 &(c->t_attrib));
pbrook14778c22009-01-21 03:02:52 +0000595 invalidate_xy(s, x, y2);
bellarde7f0ad52004-07-14 17:28:59 +0000596 }
597 }
598}
599
Gerd Hoffmann76ffb0b2012-09-28 13:24:17 +0200600static void console_show_cursor(QemuConsole *s, int show)
bellarde7f0ad52004-07-14 17:28:59 +0000601{
602 TextCell *c;
603 int y, y1;
604
605 if (s == active_console) {
thsed8276a2007-02-10 22:37:56 +0000606 int x = s->x;
balrog4d3b6f62008-02-10 16:33:14 +0000607
aliguori0e1f5a02008-11-24 19:29:13 +0000608 if (!ds_get_bits_per_pixel(s->ds)) {
balrog4d3b6f62008-02-10 16:33:14 +0000609 s->cursor_invalidate = 1;
610 return;
611 }
612
thsed8276a2007-02-10 22:37:56 +0000613 if (x >= s->width) {
614 x = s->width - 1;
615 }
bellarde7f0ad52004-07-14 17:28:59 +0000616 y1 = (s->y_base + s->y) % s->total_height;
617 y = y1 - s->y_displayed;
618 if (y < 0)
619 y += s->total_height;
620 if (y < s->height) {
thsed8276a2007-02-10 22:37:56 +0000621 c = &s->cells[y1 * s->width + x];
Jan Kiszkabf1bed82012-07-10 22:00:55 +0200622 if (show && s->cursor_visible_phase) {
pbrook6d6f7c22006-03-11 15:35:30 +0000623 TextAttributes t_attrib = s->t_attrib_default;
624 t_attrib.invers = !(t_attrib.invers); /* invert fg and bg */
thsed8276a2007-02-10 22:37:56 +0000625 vga_putcharxy(s->ds, x, y, c->ch, &t_attrib);
bellarde7f0ad52004-07-14 17:28:59 +0000626 } else {
thsed8276a2007-02-10 22:37:56 +0000627 vga_putcharxy(s->ds, x, y, c->ch, &(c->t_attrib));
bellarde7f0ad52004-07-14 17:28:59 +0000628 }
pbrook14778c22009-01-21 03:02:52 +0000629 invalidate_xy(s, x, y);
bellarde7f0ad52004-07-14 17:28:59 +0000630 }
631 }
632}
633
Gerd Hoffmann76ffb0b2012-09-28 13:24:17 +0200634static void console_refresh(QemuConsole *s)
bellarde7f0ad52004-07-14 17:28:59 +0000635{
636 TextCell *c;
637 int x, y, y1;
638
ths5fafdf22007-09-16 21:08:06 +0000639 if (s != active_console)
bellarde7f0ad52004-07-14 17:28:59 +0000640 return;
Gerd Hoffmanna93a4a22012-09-28 15:02:08 +0200641
642 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;
647 s->cursor_invalidate = 1;
balrog4d3b6f62008-02-10 16:33:14 +0000648 }
bellarde7f0ad52004-07-14 17:28:59 +0000649
Gerd Hoffmanna93a4a22012-09-28 15:02:08 +0200650 if (s->ds->have_gfx) {
651 vga_fill_rect(s->ds, 0, 0, ds_get_width(s->ds), ds_get_height(s->ds),
652 color_table[0][COLOR_BLACK]);
653 y1 = s->y_displayed;
654 for (y = 0; y < s->height; y++) {
655 c = s->cells + y1 * s->width;
656 for (x = 0; x < s->width; x++) {
657 vga_putcharxy(s->ds, x, y, c->ch,
658 &(c->t_attrib));
659 c++;
660 }
661 if (++y1 == s->total_height) {
662 y1 = 0;
663 }
bellarde7f0ad52004-07-14 17:28:59 +0000664 }
Gerd Hoffmanna93a4a22012-09-28 15:02:08 +0200665 console_show_cursor(s, 1);
666 dpy_gfx_update(s->ds, 0, 0, ds_get_width(s->ds), ds_get_height(s->ds));
bellarde7f0ad52004-07-14 17:28:59 +0000667 }
bellarde7f0ad52004-07-14 17:28:59 +0000668}
669
670static void console_scroll(int ydelta)
671{
Gerd Hoffmann76ffb0b2012-09-28 13:24:17 +0200672 QemuConsole *s;
bellarde7f0ad52004-07-14 17:28:59 +0000673 int i, y1;
ths3b46e622007-09-17 08:09:54 +0000674
bellarde7f0ad52004-07-14 17:28:59 +0000675 s = active_console;
thsaf3a9032007-07-11 23:14:59 +0000676 if (!s || (s->console_type == GRAPHIC_CONSOLE))
bellarde7f0ad52004-07-14 17:28:59 +0000677 return;
678
679 if (ydelta > 0) {
680 for(i = 0; i < ydelta; i++) {
681 if (s->y_displayed == s->y_base)
682 break;
683 if (++s->y_displayed == s->total_height)
684 s->y_displayed = 0;
685 }
686 } else {
687 ydelta = -ydelta;
688 i = s->backscroll_height;
689 if (i > s->total_height - s->height)
690 i = s->total_height - s->height;
691 y1 = s->y_base - i;
692 if (y1 < 0)
693 y1 += s->total_height;
694 for(i = 0; i < ydelta; i++) {
695 if (s->y_displayed == y1)
696 break;
697 if (--s->y_displayed < 0)
698 s->y_displayed = s->total_height - 1;
699 }
700 }
701 console_refresh(s);
702}
703
Gerd Hoffmann76ffb0b2012-09-28 13:24:17 +0200704static void console_put_lf(QemuConsole *s)
bellarde7f0ad52004-07-14 17:28:59 +0000705{
706 TextCell *c;
707 int x, y1;
708
bellarde7f0ad52004-07-14 17:28:59 +0000709 s->y++;
710 if (s->y >= s->height) {
711 s->y = s->height - 1;
pbrook6d6f7c22006-03-11 15:35:30 +0000712
bellarde7f0ad52004-07-14 17:28:59 +0000713 if (s->y_displayed == s->y_base) {
714 if (++s->y_displayed == s->total_height)
715 s->y_displayed = 0;
716 }
717 if (++s->y_base == s->total_height)
718 s->y_base = 0;
719 if (s->backscroll_height < s->total_height)
720 s->backscroll_height++;
721 y1 = (s->y_base + s->height - 1) % s->total_height;
722 c = &s->cells[y1 * s->width];
723 for(x = 0; x < s->width; x++) {
724 c->ch = ' ';
pbrook6d6f7c22006-03-11 15:35:30 +0000725 c->t_attrib = s->t_attrib_default;
bellarde7f0ad52004-07-14 17:28:59 +0000726 c++;
727 }
728 if (s == active_console && s->y_displayed == s->y_base) {
aliguori0e1f5a02008-11-24 19:29:13 +0000729 if (!ds_get_bits_per_pixel(s->ds)) {
balrog4d3b6f62008-02-10 16:33:14 +0000730 s->text_x[0] = 0;
731 s->text_y[0] = 0;
732 s->text_x[1] = s->width - 1;
733 s->text_y[1] = s->height - 1;
734 return;
735 }
736
ths5fafdf22007-09-16 21:08:06 +0000737 vga_bitblt(s->ds, 0, FONT_HEIGHT, 0, 0,
738 s->width * FONT_WIDTH,
bellarde7f0ad52004-07-14 17:28:59 +0000739 (s->height - 1) * FONT_HEIGHT);
740 vga_fill_rect(s->ds, 0, (s->height - 1) * FONT_HEIGHT,
ths5fafdf22007-09-16 21:08:06 +0000741 s->width * FONT_WIDTH, FONT_HEIGHT,
pbrook6d6f7c22006-03-11 15:35:30 +0000742 color_table[0][s->t_attrib_default.bgcol]);
pbrook14778c22009-01-21 03:02:52 +0000743 s->update_x0 = 0;
744 s->update_y0 = 0;
745 s->update_x1 = s->width * FONT_WIDTH;
746 s->update_y1 = s->height * FONT_HEIGHT;
bellarde7f0ad52004-07-14 17:28:59 +0000747 }
748 }
749}
750
pbrook6d6f7c22006-03-11 15:35:30 +0000751/* Set console attributes depending on the current escape codes.
752 * NOTE: I know this code is not very efficient (checking every color for it
753 * self) but it is more readable and better maintainable.
754 */
Gerd Hoffmann76ffb0b2012-09-28 13:24:17 +0200755static void console_handle_escape(QemuConsole *s)
pbrook6d6f7c22006-03-11 15:35:30 +0000756{
757 int i;
758
pbrook6d6f7c22006-03-11 15:35:30 +0000759 for (i=0; i<s->nb_esc_params; i++) {
760 switch (s->esc_params[i]) {
761 case 0: /* reset all console attributes to default */
762 s->t_attrib = s->t_attrib_default;
763 break;
764 case 1:
765 s->t_attrib.bold = 1;
766 break;
767 case 4:
768 s->t_attrib.uline = 1;
769 break;
770 case 5:
771 s->t_attrib.blink = 1;
772 break;
773 case 7:
774 s->t_attrib.invers = 1;
775 break;
776 case 8:
777 s->t_attrib.unvisible = 1;
778 break;
779 case 22:
780 s->t_attrib.bold = 0;
781 break;
782 case 24:
783 s->t_attrib.uline = 0;
784 break;
785 case 25:
786 s->t_attrib.blink = 0;
787 break;
788 case 27:
789 s->t_attrib.invers = 0;
790 break;
791 case 28:
792 s->t_attrib.unvisible = 0;
793 break;
794 /* set foreground color */
795 case 30:
796 s->t_attrib.fgcol=COLOR_BLACK;
797 break;
798 case 31:
799 s->t_attrib.fgcol=COLOR_RED;
800 break;
801 case 32:
802 s->t_attrib.fgcol=COLOR_GREEN;
803 break;
804 case 33:
805 s->t_attrib.fgcol=COLOR_YELLOW;
806 break;
807 case 34:
808 s->t_attrib.fgcol=COLOR_BLUE;
809 break;
810 case 35:
811 s->t_attrib.fgcol=COLOR_MAGENTA;
812 break;
813 case 36:
814 s->t_attrib.fgcol=COLOR_CYAN;
815 break;
816 case 37:
817 s->t_attrib.fgcol=COLOR_WHITE;
818 break;
819 /* set background color */
820 case 40:
821 s->t_attrib.bgcol=COLOR_BLACK;
822 break;
823 case 41:
824 s->t_attrib.bgcol=COLOR_RED;
825 break;
826 case 42:
827 s->t_attrib.bgcol=COLOR_GREEN;
828 break;
829 case 43:
830 s->t_attrib.bgcol=COLOR_YELLOW;
831 break;
832 case 44:
833 s->t_attrib.bgcol=COLOR_BLUE;
834 break;
835 case 45:
836 s->t_attrib.bgcol=COLOR_MAGENTA;
837 break;
838 case 46:
839 s->t_attrib.bgcol=COLOR_CYAN;
840 break;
841 case 47:
842 s->t_attrib.bgcol=COLOR_WHITE;
843 break;
844 }
845 }
846}
847
Gerd Hoffmann76ffb0b2012-09-28 13:24:17 +0200848static void console_clear_xy(QemuConsole *s, int x, int y)
thsadb47962007-01-16 23:02:36 +0000849{
850 int y1 = (s->y_base + y) % s->total_height;
851 TextCell *c = &s->cells[y1 * s->width + x];
852 c->ch = ' ';
853 c->t_attrib = s->t_attrib_default;
thsadb47962007-01-16 23:02:36 +0000854 update_xy(s, x, y);
855}
856
Ian Campbell3eea5492012-09-04 10:26:09 -0500857/* set cursor, checking bounds */
Gerd Hoffmann76ffb0b2012-09-28 13:24:17 +0200858static void set_cursor(QemuConsole *s, int x, int y)
Ian Campbell3eea5492012-09-04 10:26:09 -0500859{
860 if (x < 0) {
861 x = 0;
862 }
863 if (y < 0) {
864 y = 0;
865 }
866 if (y >= s->height) {
867 y = s->height - 1;
868 }
869 if (x >= s->width) {
870 x = s->width - 1;
871 }
872
873 s->x = x;
874 s->y = y;
875}
876
Gerd Hoffmann76ffb0b2012-09-28 13:24:17 +0200877static void console_putchar(QemuConsole *s, int ch)
bellarde7f0ad52004-07-14 17:28:59 +0000878{
879 TextCell *c;
thsadb47962007-01-16 23:02:36 +0000880 int y1, i;
881 int x, y;
bellarde7f0ad52004-07-14 17:28:59 +0000882
883 switch(s->state) {
884 case TTY_STATE_NORM:
885 switch(ch) {
pbrook6d6f7c22006-03-11 15:35:30 +0000886 case '\r': /* carriage return */
bellarde7f0ad52004-07-14 17:28:59 +0000887 s->x = 0;
888 break;
pbrook6d6f7c22006-03-11 15:35:30 +0000889 case '\n': /* newline */
bellarde7f0ad52004-07-14 17:28:59 +0000890 console_put_lf(s);
891 break;
pbrook6d6f7c22006-03-11 15:35:30 +0000892 case '\b': /* backspace */
ths5fafdf22007-09-16 21:08:06 +0000893 if (s->x > 0)
bellarde15d7372006-06-25 16:26:29 +0000894 s->x--;
pbrook6d6f7c22006-03-11 15:35:30 +0000895 break;
896 case '\t': /* tabspace */
897 if (s->x + (8 - (s->x % 8)) > s->width) {
bellardbd468842006-07-14 20:24:31 +0000898 s->x = 0;
pbrook6d6f7c22006-03-11 15:35:30 +0000899 console_put_lf(s);
900 } else {
901 s->x = s->x + (8 - (s->x % 8));
902 }
903 break;
904 case '\a': /* alert aka. bell */
905 /* TODO: has to be implemented */
906 break;
thsadb47962007-01-16 23:02:36 +0000907 case 14:
908 /* SI (shift in), character set 0 (ignored) */
909 break;
910 case 15:
911 /* SO (shift out), character set 1 (ignored) */
912 break;
pbrook6d6f7c22006-03-11 15:35:30 +0000913 case 27: /* esc (introducing an escape sequence) */
bellarde7f0ad52004-07-14 17:28:59 +0000914 s->state = TTY_STATE_ESC;
915 break;
916 default:
thsed8276a2007-02-10 22:37:56 +0000917 if (s->x >= s->width) {
918 /* line wrap */
919 s->x = 0;
920 console_put_lf(s);
thsadb47962007-01-16 23:02:36 +0000921 }
bellarde7f0ad52004-07-14 17:28:59 +0000922 y1 = (s->y_base + s->y) % s->total_height;
923 c = &s->cells[y1 * s->width + s->x];
924 c->ch = ch;
pbrook6d6f7c22006-03-11 15:35:30 +0000925 c->t_attrib = s->t_attrib;
bellarde7f0ad52004-07-14 17:28:59 +0000926 update_xy(s, s->x, s->y);
927 s->x++;
bellarde7f0ad52004-07-14 17:28:59 +0000928 break;
929 }
930 break;
pbrook6d6f7c22006-03-11 15:35:30 +0000931 case TTY_STATE_ESC: /* check if it is a terminal escape sequence */
bellarde7f0ad52004-07-14 17:28:59 +0000932 if (ch == '[') {
933 for(i=0;i<MAX_ESC_PARAMS;i++)
934 s->esc_params[i] = 0;
935 s->nb_esc_params = 0;
936 s->state = TTY_STATE_CSI;
937 } else {
938 s->state = TTY_STATE_NORM;
939 }
940 break;
pbrook6d6f7c22006-03-11 15:35:30 +0000941 case TTY_STATE_CSI: /* handle escape sequence parameters */
bellarde7f0ad52004-07-14 17:28:59 +0000942 if (ch >= '0' && ch <= '9') {
943 if (s->nb_esc_params < MAX_ESC_PARAMS) {
Laszlo Ersekc10600a2012-09-17 11:10:03 +0200944 int *param = &s->esc_params[s->nb_esc_params];
945 int digit = (ch - '0');
946
947 *param = (*param <= (INT_MAX - digit) / 10) ?
948 *param * 10 + digit : INT_MAX;
bellarde7f0ad52004-07-14 17:28:59 +0000949 }
950 } else {
Ian Campbell3eea5492012-09-04 10:26:09 -0500951 if (s->nb_esc_params < MAX_ESC_PARAMS)
952 s->nb_esc_params++;
bellarde7f0ad52004-07-14 17:28:59 +0000953 if (ch == ';')
954 break;
thsadb47962007-01-16 23:02:36 +0000955#ifdef DEBUG_CONSOLE
956 fprintf(stderr, "escape sequence CSI%d;%d%c, %d parameters\n",
957 s->esc_params[0], s->esc_params[1], ch, s->nb_esc_params);
958#endif
bellarde7f0ad52004-07-14 17:28:59 +0000959 s->state = TTY_STATE_NORM;
960 switch(ch) {
thsadb47962007-01-16 23:02:36 +0000961 case 'A':
962 /* move cursor up */
963 if (s->esc_params[0] == 0) {
964 s->esc_params[0] = 1;
965 }
Ian Campbell3eea5492012-09-04 10:26:09 -0500966 set_cursor(s, s->x, s->y - s->esc_params[0]);
bellarde7f0ad52004-07-14 17:28:59 +0000967 break;
thsadb47962007-01-16 23:02:36 +0000968 case 'B':
969 /* move cursor down */
970 if (s->esc_params[0] == 0) {
971 s->esc_params[0] = 1;
972 }
Ian Campbell3eea5492012-09-04 10:26:09 -0500973 set_cursor(s, s->x, s->y + s->esc_params[0]);
thsadb47962007-01-16 23:02:36 +0000974 break;
975 case 'C':
976 /* move cursor right */
977 if (s->esc_params[0] == 0) {
978 s->esc_params[0] = 1;
979 }
Ian Campbell3eea5492012-09-04 10:26:09 -0500980 set_cursor(s, s->x + s->esc_params[0], s->y);
thsadb47962007-01-16 23:02:36 +0000981 break;
982 case 'D':
983 /* move cursor left */
984 if (s->esc_params[0] == 0) {
985 s->esc_params[0] = 1;
986 }
Ian Campbell3eea5492012-09-04 10:26:09 -0500987 set_cursor(s, s->x - s->esc_params[0], s->y);
thsadb47962007-01-16 23:02:36 +0000988 break;
989 case 'G':
990 /* move cursor to column */
Ian Campbell3eea5492012-09-04 10:26:09 -0500991 set_cursor(s, s->esc_params[0] - 1, s->y);
thsadb47962007-01-16 23:02:36 +0000992 break;
993 case 'f':
994 case 'H':
995 /* move cursor to row, column */
Ian Campbell3eea5492012-09-04 10:26:09 -0500996 set_cursor(s, s->esc_params[1] - 1, s->esc_params[0] - 1);
thsadb47962007-01-16 23:02:36 +0000997 break;
998 case 'J':
999 switch (s->esc_params[0]) {
1000 case 0:
1001 /* clear to end of screen */
1002 for (y = s->y; y < s->height; y++) {
1003 for (x = 0; x < s->width; x++) {
1004 if (y == s->y && x < s->x) {
1005 continue;
1006 }
1007 console_clear_xy(s, x, y);
1008 }
1009 }
1010 break;
1011 case 1:
1012 /* clear from beginning of screen */
1013 for (y = 0; y <= s->y; y++) {
1014 for (x = 0; x < s->width; x++) {
1015 if (y == s->y && x > s->x) {
1016 break;
1017 }
1018 console_clear_xy(s, x, y);
1019 }
1020 }
1021 break;
1022 case 2:
1023 /* clear entire screen */
1024 for (y = 0; y <= s->height; y++) {
1025 for (x = 0; x < s->width; x++) {
1026 console_clear_xy(s, x, y);
1027 }
1028 }
Markus Armbrusterf94a9502011-11-22 11:59:06 +01001029 break;
thsadb47962007-01-16 23:02:36 +00001030 }
Markus Armbruster95d8f9f2011-11-22 11:59:07 +01001031 break;
thsadb47962007-01-16 23:02:36 +00001032 case 'K':
1033 switch (s->esc_params[0]) {
1034 case 0:
Markus Armbrusterf94a9502011-11-22 11:59:06 +01001035 /* clear to eol */
1036 for(x = s->x; x < s->width; x++) {
thsadb47962007-01-16 23:02:36 +00001037 console_clear_xy(s, x, s->y);
Markus Armbrusterf94a9502011-11-22 11:59:06 +01001038 }
1039 break;
thsadb47962007-01-16 23:02:36 +00001040 case 1:
1041 /* clear from beginning of line */
1042 for (x = 0; x <= s->x; x++) {
1043 console_clear_xy(s, x, s->y);
1044 }
1045 break;
1046 case 2:
1047 /* clear entire line */
1048 for(x = 0; x < s->width; x++) {
1049 console_clear_xy(s, x, s->y);
1050 }
Markus Armbrusterf94a9502011-11-22 11:59:06 +01001051 break;
1052 }
thsadb47962007-01-16 23:02:36 +00001053 break;
1054 case 'm':
Markus Armbrusterf94a9502011-11-22 11:59:06 +01001055 console_handle_escape(s);
1056 break;
thsadb47962007-01-16 23:02:36 +00001057 case 'n':
1058 /* report cursor position */
1059 /* TODO: send ESC[row;colR */
1060 break;
1061 case 's':
1062 /* save cursor position */
1063 s->x_saved = s->x;
1064 s->y_saved = s->y;
1065 break;
1066 case 'u':
1067 /* restore cursor position */
1068 s->x = s->x_saved;
1069 s->y = s->y_saved;
1070 break;
1071 default:
1072#ifdef DEBUG_CONSOLE
1073 fprintf(stderr, "unhandled escape character '%c'\n", ch);
1074#endif
1075 break;
1076 }
1077 break;
bellarde7f0ad52004-07-14 17:28:59 +00001078 }
1079 }
1080}
1081
1082void console_select(unsigned int index)
1083{
Gerd Hoffmann76ffb0b2012-09-28 13:24:17 +02001084 QemuConsole *s;
pbrook6d6f7c22006-03-11 15:35:30 +00001085
bellarde7f0ad52004-07-14 17:28:59 +00001086 if (index >= MAX_CONSOLES)
1087 return;
Stefan Hajnoczi358664c2010-09-20 14:11:19 +01001088 if (active_console) {
1089 active_console->g_width = ds_get_width(active_console->ds);
1090 active_console->g_height = ds_get_height(active_console->ds);
1091 }
bellarde7f0ad52004-07-14 17:28:59 +00001092 s = consoles[index];
1093 if (s) {
aliguori7d957bd2009-01-15 22:14:11 +00001094 DisplayState *ds = s->ds;
Jan Kiszkabf1bed82012-07-10 22:00:55 +02001095
Stefan Weil8bd6b062012-08-17 15:50:44 +02001096 if (active_console && active_console->cursor_timer) {
Jan Kiszkabf1bed82012-07-10 22:00:55 +02001097 qemu_del_timer(active_console->cursor_timer);
1098 }
bellarde7f0ad52004-07-14 17:28:59 +00001099 active_console = s;
Gerd Hoffmanna93a4a22012-09-28 15:02:08 +02001100 if (ds->have_gfx) {
aliguori7b5d76d2009-03-13 15:02:13 +00001101 ds->surface = qemu_resize_displaysurface(ds, s->g_width, s->g_height);
Gerd Hoffmanna93a4a22012-09-28 15:02:08 +02001102 dpy_gfx_resize(ds);
1103 }
1104 if (ds->have_text) {
1105 dpy_text_resize(ds, s->width, s->height);
aliguori68f00992009-01-21 18:59:12 +00001106 }
Jan Kiszkabf1bed82012-07-10 22:00:55 +02001107 if (s->cursor_timer) {
1108 qemu_mod_timer(s->cursor_timer,
1109 qemu_get_clock_ms(rt_clock) + CONSOLE_CURSOR_PERIOD / 2);
1110 }
balrog4d3b6f62008-02-10 16:33:14 +00001111 vga_hw_invalidate();
bellarde7f0ad52004-07-14 17:28:59 +00001112 }
1113}
1114
1115static int console_puts(CharDriverState *chr, const uint8_t *buf, int len)
1116{
Gerd Hoffmann76ffb0b2012-09-28 13:24:17 +02001117 QemuConsole *s = chr->opaque;
bellarde7f0ad52004-07-14 17:28:59 +00001118 int i;
1119
pbrook14778c22009-01-21 03:02:52 +00001120 s->update_x0 = s->width * FONT_WIDTH;
1121 s->update_y0 = s->height * FONT_HEIGHT;
1122 s->update_x1 = 0;
1123 s->update_y1 = 0;
bellarde7f0ad52004-07-14 17:28:59 +00001124 console_show_cursor(s, 0);
1125 for(i = 0; i < len; i++) {
1126 console_putchar(s, buf[i]);
1127 }
1128 console_show_cursor(s, 1);
Gerd Hoffmanna93a4a22012-09-28 15:02:08 +02001129 if (s->ds->have_gfx && s->update_x0 < s->update_x1) {
1130 dpy_gfx_update(s->ds, s->update_x0, s->update_y0,
1131 s->update_x1 - s->update_x0,
1132 s->update_y1 - s->update_y0);
pbrook14778c22009-01-21 03:02:52 +00001133 }
bellarde7f0ad52004-07-14 17:28:59 +00001134 return len;
1135}
1136
bellarde15d7372006-06-25 16:26:29 +00001137static void kbd_send_chars(void *opaque)
1138{
Gerd Hoffmann76ffb0b2012-09-28 13:24:17 +02001139 QemuConsole *s = opaque;
bellarde15d7372006-06-25 16:26:29 +00001140 int len;
1141 uint8_t buf[16];
ths3b46e622007-09-17 08:09:54 +00001142
Anthony Liguori909cda12011-08-15 11:17:31 -05001143 len = qemu_chr_be_can_write(s->chr);
bellarde15d7372006-06-25 16:26:29 +00001144 if (len > s->out_fifo.count)
1145 len = s->out_fifo.count;
1146 if (len > 0) {
1147 if (len > sizeof(buf))
1148 len = sizeof(buf);
1149 qemu_fifo_read(&s->out_fifo, buf, len);
Anthony Liguorifa5efcc2011-08-15 11:17:30 -05001150 qemu_chr_be_write(s->chr, buf, len);
bellarde15d7372006-06-25 16:26:29 +00001151 }
1152 /* characters are pending: we send them a bit later (XXX:
1153 horrible, should change char device API) */
1154 if (s->out_fifo.count > 0) {
Paolo Bonzini7bd427d2011-03-11 16:47:48 +01001155 qemu_mod_timer(s->kbd_timer, qemu_get_clock_ms(rt_clock) + 1);
bellarde15d7372006-06-25 16:26:29 +00001156 }
1157}
1158
bellarde7f0ad52004-07-14 17:28:59 +00001159/* called when an ascii key is pressed */
1160void kbd_put_keysym(int keysym)
1161{
Gerd Hoffmann76ffb0b2012-09-28 13:24:17 +02001162 QemuConsole *s;
bellarde7f0ad52004-07-14 17:28:59 +00001163 uint8_t buf[16], *q;
1164 int c;
1165
1166 s = active_console;
thsaf3a9032007-07-11 23:14:59 +00001167 if (!s || (s->console_type == GRAPHIC_CONSOLE))
bellarde7f0ad52004-07-14 17:28:59 +00001168 return;
1169
1170 switch(keysym) {
1171 case QEMU_KEY_CTRL_UP:
1172 console_scroll(-1);
1173 break;
1174 case QEMU_KEY_CTRL_DOWN:
1175 console_scroll(1);
1176 break;
1177 case QEMU_KEY_CTRL_PAGEUP:
1178 console_scroll(-10);
1179 break;
1180 case QEMU_KEY_CTRL_PAGEDOWN:
1181 console_scroll(10);
1182 break;
1183 default:
bellarde15d7372006-06-25 16:26:29 +00001184 /* convert the QEMU keysym to VT100 key string */
1185 q = buf;
1186 if (keysym >= 0xe100 && keysym <= 0xe11f) {
1187 *q++ = '\033';
1188 *q++ = '[';
1189 c = keysym - 0xe100;
1190 if (c >= 10)
1191 *q++ = '0' + (c / 10);
1192 *q++ = '0' + (c % 10);
1193 *q++ = '~';
1194 } else if (keysym >= 0xe120 && keysym <= 0xe17f) {
1195 *q++ = '\033';
1196 *q++ = '[';
1197 *q++ = keysym & 0xff;
Paolo Bonzini41048332010-12-23 13:42:52 +01001198 } else if (s->echo && (keysym == '\r' || keysym == '\n')) {
1199 console_puts(s->chr, (const uint8_t *) "\r", 1);
1200 *q++ = '\n';
bellarde15d7372006-06-25 16:26:29 +00001201 } else {
Paolo Bonzini41048332010-12-23 13:42:52 +01001202 *q++ = keysym;
1203 }
1204 if (s->echo) {
1205 console_puts(s->chr, buf, q - buf);
bellarde15d7372006-06-25 16:26:29 +00001206 }
pbrooke5b0bc42007-01-27 23:46:43 +00001207 if (s->chr->chr_read) {
bellarde15d7372006-06-25 16:26:29 +00001208 qemu_fifo_write(&s->out_fifo, buf, q - buf);
1209 kbd_send_chars(s);
bellarde7f0ad52004-07-14 17:28:59 +00001210 }
1211 break;
1212 }
1213}
1214
balrog4d3b6f62008-02-10 16:33:14 +00001215static void text_console_invalidate(void *opaque)
1216{
Gerd Hoffmann76ffb0b2012-09-28 13:24:17 +02001217 QemuConsole *s = (QemuConsole *) opaque;
aliguori68f00992009-01-21 18:59:12 +00001218 if (!ds_get_bits_per_pixel(s->ds) && s->console_type == TEXT_CONSOLE) {
1219 s->g_width = ds_get_width(s->ds);
1220 s->g_height = ds_get_height(s->ds);
1221 text_console_resize(s);
1222 }
balrog4d3b6f62008-02-10 16:33:14 +00001223 console_refresh(s);
1224}
1225
Anthony Liguoric227f092009-10-01 16:12:16 -05001226static void text_console_update(void *opaque, console_ch_t *chardata)
balrog4d3b6f62008-02-10 16:33:14 +00001227{
Gerd Hoffmann76ffb0b2012-09-28 13:24:17 +02001228 QemuConsole *s = (QemuConsole *) opaque;
balrog4d3b6f62008-02-10 16:33:14 +00001229 int i, j, src;
1230
1231 if (s->text_x[0] <= s->text_x[1]) {
1232 src = (s->y_base + s->text_y[0]) * s->width;
1233 chardata += s->text_y[0] * s->width;
1234 for (i = s->text_y[0]; i <= s->text_y[1]; i ++)
1235 for (j = 0; j < s->width; j ++, src ++)
1236 console_write_ch(chardata ++, s->cells[src].ch |
1237 (s->cells[src].t_attrib.fgcol << 12) |
1238 (s->cells[src].t_attrib.bgcol << 8) |
1239 (s->cells[src].t_attrib.bold << 21));
Gerd Hoffmanna93a4a22012-09-28 15:02:08 +02001240 dpy_text_update(s->ds, s->text_x[0], s->text_y[0],
1241 s->text_x[1] - s->text_x[0], i - s->text_y[0]);
balrog4d3b6f62008-02-10 16:33:14 +00001242 s->text_x[0] = s->width;
1243 s->text_y[0] = s->height;
1244 s->text_x[1] = 0;
1245 s->text_y[1] = 0;
1246 }
1247 if (s->cursor_invalidate) {
Gerd Hoffmannbf2fde72012-09-12 07:56:45 +02001248 dpy_text_cursor(s->ds, s->x, s->y);
balrog4d3b6f62008-02-10 16:33:14 +00001249 s->cursor_invalidate = 0;
1250 }
1251}
1252
Gerd Hoffmann76ffb0b2012-09-28 13:24:17 +02001253static QemuConsole *get_graphic_console(DisplayState *ds)
blueswir1a147d622009-01-16 19:41:04 +00001254{
aliguori3023f332009-01-16 19:04:14 +00001255 int i;
Gerd Hoffmann76ffb0b2012-09-28 13:24:17 +02001256 QemuConsole *s;
aliguori3023f332009-01-16 19:04:14 +00001257 for (i = 0; i < nb_consoles; i++) {
1258 s = consoles[i];
aliguori42aa98e2009-01-16 21:01:48 +00001259 if (s->console_type == GRAPHIC_CONSOLE && s->ds == ds)
aliguori3023f332009-01-16 19:04:14 +00001260 return s;
1261 }
1262 return NULL;
1263}
1264
Gerd Hoffmann76ffb0b2012-09-28 13:24:17 +02001265static QemuConsole *new_console(DisplayState *ds, console_type_t console_type)
bellarde7f0ad52004-07-14 17:28:59 +00001266{
Gerd Hoffmann76ffb0b2012-09-28 13:24:17 +02001267 QemuConsole *s;
pbrook95219892006-04-09 01:06:34 +00001268 int i;
bellarde7f0ad52004-07-14 17:28:59 +00001269
1270 if (nb_consoles >= MAX_CONSOLES)
1271 return NULL;
Gerd Hoffmann76ffb0b2012-09-28 13:24:17 +02001272 s = g_malloc0(sizeof(QemuConsole));
thsaf3a9032007-07-11 23:14:59 +00001273 if (!active_console || ((active_console->console_type != GRAPHIC_CONSOLE) &&
1274 (console_type == GRAPHIC_CONSOLE))) {
bellarde7f0ad52004-07-14 17:28:59 +00001275 active_console = s;
thsaf3a9032007-07-11 23:14:59 +00001276 }
bellarde7f0ad52004-07-14 17:28:59 +00001277 s->ds = ds;
thsaf3a9032007-07-11 23:14:59 +00001278 s->console_type = console_type;
1279 if (console_type != GRAPHIC_CONSOLE) {
Jan Kiszkaf81bdef2011-09-16 00:48:07 +02001280 s->index = nb_consoles;
pbrook95219892006-04-09 01:06:34 +00001281 consoles[nb_consoles++] = s;
1282 } else {
1283 /* HACK: Put graphical consoles before text consoles. */
1284 for (i = nb_consoles; i > 0; i--) {
thsaf3a9032007-07-11 23:14:59 +00001285 if (consoles[i - 1]->console_type == GRAPHIC_CONSOLE)
pbrook95219892006-04-09 01:06:34 +00001286 break;
1287 consoles[i] = consoles[i - 1];
Jan Kiszkaf81bdef2011-09-16 00:48:07 +02001288 consoles[i]->index = i;
pbrook95219892006-04-09 01:06:34 +00001289 }
Jan Kiszkaf81bdef2011-09-16 00:48:07 +02001290 s->index = i;
pbrook95219892006-04-09 01:06:34 +00001291 consoles[i] = s;
aliguori3023f332009-01-16 19:04:14 +00001292 nb_consoles++;
pbrook95219892006-04-09 01:06:34 +00001293 }
bellarde7f0ad52004-07-14 17:28:59 +00001294 return s;
1295}
1296
Gerd Hoffmann537a4392012-09-27 11:06:36 +02001297static void qemu_alloc_display(DisplaySurface *surface, int width, int height,
1298 int linesize, PixelFormat pf, int newflags)
Jes Sorensenffe8b822011-03-16 13:33:30 +01001299{
Jes Sorensenffe8b822011-03-16 13:33:30 +01001300 surface->pf = pf;
Gerd Hoffmann69c77772012-09-26 15:20:05 +02001301
1302 qemu_pixman_image_unref(surface->image);
1303 surface->image = NULL;
Gerd Hoffmann69c77772012-09-26 15:20:05 +02001304
1305 surface->format = qemu_pixman_get_format(&pf);
1306 assert(surface->format != 0);
1307 surface->image = pixman_image_create_bits(surface->format,
1308 width, height,
1309 NULL, linesize);
1310 assert(surface->image != NULL);
1311
Jes Sorensenffe8b822011-03-16 13:33:30 +01001312 surface->flags = newflags | QEMU_ALLOCATED_FLAG;
Paolo Bonzini98b50082010-02-11 00:29:57 +01001313#ifdef HOST_WORDS_BIGENDIAN
Jes Sorensenffe8b822011-03-16 13:33:30 +01001314 surface->flags |= QEMU_BIG_ENDIAN_FLAG;
Paolo Bonzini98b50082010-02-11 00:29:57 +01001315#endif
Paolo Bonzini98b50082010-02-11 00:29:57 +01001316}
1317
Gerd Hoffmann537a4392012-09-27 11:06:36 +02001318DisplaySurface *qemu_create_displaysurface(DisplayState *ds,
1319 int width, int height)
1320{
1321 DisplaySurface *surface = g_new0(DisplaySurface, 1);
1322
1323 int linesize = width * 4;
1324 qemu_alloc_display(surface, width, height, linesize,
1325 qemu_default_pixelformat(32), 0);
1326 return surface;
1327}
1328
1329DisplaySurface *qemu_resize_displaysurface(DisplayState *ds,
1330 int width, int height)
1331{
1332 int linesize = width * 4;
1333
1334 trace_displaysurface_resize(ds, ds->surface, width, height);
1335 qemu_alloc_display(ds->surface, width, height, linesize,
1336 qemu_default_pixelformat(32), 0);
1337 return ds->surface;
1338}
1339
Gerd Hoffmann187cd1d2012-09-26 07:46:20 +02001340DisplaySurface *qemu_create_displaysurface_from(int width, int height, int bpp,
Gerd Hoffmann69c77772012-09-26 15:20:05 +02001341 int linesize, uint8_t *data)
Paolo Bonzini98b50082010-02-11 00:29:57 +01001342{
Gerd Hoffmann69c77772012-09-26 15:20:05 +02001343 DisplaySurface *surface = g_new0(DisplaySurface, 1);
Paolo Bonzini98b50082010-02-11 00:29:57 +01001344
Paolo Bonzini98b50082010-02-11 00:29:57 +01001345 surface->pf = qemu_default_pixelformat(bpp);
Gerd Hoffmann69c77772012-09-26 15:20:05 +02001346
1347 surface->format = qemu_pixman_get_format(&surface->pf);
1348 assert(surface->format != 0);
1349 surface->image = pixman_image_create_bits(surface->format,
1350 width, height,
1351 (void *)data, linesize);
1352 assert(surface->image != NULL);
1353
Paolo Bonzini98b50082010-02-11 00:29:57 +01001354#ifdef HOST_WORDS_BIGENDIAN
1355 surface->flags = QEMU_BIG_ENDIAN_FLAG;
1356#endif
Paolo Bonzini98b50082010-02-11 00:29:57 +01001357
1358 return surface;
1359}
1360
Gerd Hoffmann187cd1d2012-09-26 07:46:20 +02001361void qemu_free_displaysurface(DisplayState *ds)
Paolo Bonzini98b50082010-02-11 00:29:57 +01001362{
Gerd Hoffmann187cd1d2012-09-26 07:46:20 +02001363 trace_displaysurface_free(ds, ds->surface);
1364 if (ds->surface == NULL) {
Paolo Bonzini98b50082010-02-11 00:29:57 +01001365 return;
Gerd Hoffmann187cd1d2012-09-26 07:46:20 +02001366 }
Gerd Hoffmann69c77772012-09-26 15:20:05 +02001367 qemu_pixman_image_unref(ds->surface->image);
Gerd Hoffmann187cd1d2012-09-26 07:46:20 +02001368 g_free(ds->surface);
Paolo Bonzini98b50082010-02-11 00:29:57 +01001369}
1370
Paolo Bonzini98b50082010-02-11 00:29:57 +01001371static void dumb_display_init(void)
1372{
Anthony Liguori7267c092011-08-20 22:09:37 -05001373 DisplayState *ds = g_malloc0(sizeof(DisplayState));
Jan Kiszka18026512011-06-19 11:53:02 +02001374 int width = 640;
1375 int height = 480;
1376
Jan Kiszka18026512011-06-19 11:53:02 +02001377 if (is_fixedsize_console()) {
1378 width = active_console->g_width;
1379 height = active_console->g_height;
1380 }
1381 ds->surface = qemu_create_displaysurface(ds, width, height);
Paolo Bonzini98b50082010-02-11 00:29:57 +01001382 register_displaystate(ds);
1383}
1384
1385/***********************************************************/
1386/* register display */
1387
1388void register_displaystate(DisplayState *ds)
1389{
1390 DisplayState **s;
1391 s = &display_state;
1392 while (*s != NULL)
1393 s = &(*s)->next;
1394 ds->next = NULL;
1395 *s = ds;
1396}
1397
1398DisplayState *get_displaystate(void)
1399{
1400 if (!display_state) {
1401 dumb_display_init ();
1402 }
1403 return display_state;
1404}
1405
aliguori3023f332009-01-16 19:04:14 +00001406DisplayState *graphic_console_init(vga_hw_update_ptr update,
1407 vga_hw_invalidate_ptr invalidate,
1408 vga_hw_screen_dump_ptr screen_dump,
1409 vga_hw_text_update_ptr text_update,
1410 void *opaque)
bellarde7f0ad52004-07-14 17:28:59 +00001411{
Gerd Hoffmann76ffb0b2012-09-28 13:24:17 +02001412 QemuConsole *s;
aliguori3023f332009-01-16 19:04:14 +00001413 DisplayState *ds;
aurel32f0f2f972009-01-16 21:13:49 +00001414
Anthony Liguori7267c092011-08-20 22:09:37 -05001415 ds = (DisplayState *) g_malloc0(sizeof(DisplayState));
aliguori7b5d76d2009-03-13 15:02:13 +00001416 ds->surface = qemu_create_displaysurface(ds, 640, 480);
pbrook95219892006-04-09 01:06:34 +00001417
thsaf3a9032007-07-11 23:14:59 +00001418 s = new_console(ds, GRAPHIC_CONSOLE);
aliguori3023f332009-01-16 19:04:14 +00001419 if (s == NULL) {
aliguori7b5d76d2009-03-13 15:02:13 +00001420 qemu_free_displaysurface(ds);
Anthony Liguori7267c092011-08-20 22:09:37 -05001421 g_free(ds);
aliguori3023f332009-01-16 19:04:14 +00001422 return NULL;
1423 }
pbrook95219892006-04-09 01:06:34 +00001424 s->hw_update = update;
1425 s->hw_invalidate = invalidate;
1426 s->hw_screen_dump = screen_dump;
balrog4d3b6f62008-02-10 16:33:14 +00001427 s->hw_text_update = text_update;
pbrook95219892006-04-09 01:06:34 +00001428 s->hw = opaque;
aliguori3023f332009-01-16 19:04:14 +00001429
aurel32f0f2f972009-01-16 21:13:49 +00001430 register_displaystate(ds);
aliguori3023f332009-01-16 19:04:14 +00001431 return ds;
pbrook95219892006-04-09 01:06:34 +00001432}
1433
1434int is_graphic_console(void)
1435{
balrog4d3b6f62008-02-10 16:33:14 +00001436 return active_console && active_console->console_type == GRAPHIC_CONSOLE;
bellarde7f0ad52004-07-14 17:28:59 +00001437}
1438
balrogc21bbcf2008-09-24 03:32:33 +00001439int is_fixedsize_console(void)
1440{
1441 return active_console && active_console->console_type != TEXT_CONSOLE;
1442}
1443
balroga528b802007-10-30 22:38:53 +00001444void console_color_init(DisplayState *ds)
1445{
1446 int i, j;
1447 for (j = 0; j < 2; j++) {
1448 for (i = 0; i < 8; i++) {
aurel32f0f2f972009-01-16 21:13:49 +00001449 color_table[j][i] = col_expand(ds,
balroga528b802007-10-30 22:38:53 +00001450 vga_get_color(ds, color_table_rgb[j][i]));
1451 }
1452 }
1453}
1454
Paolo Bonzini41048332010-12-23 13:42:52 +01001455static void text_console_set_echo(CharDriverState *chr, bool echo)
1456{
Gerd Hoffmann76ffb0b2012-09-28 13:24:17 +02001457 QemuConsole *s = chr->opaque;
Paolo Bonzini41048332010-12-23 13:42:52 +01001458
1459 s->echo = echo;
1460}
1461
Jan Kiszkabf1bed82012-07-10 22:00:55 +02001462static void text_console_update_cursor(void *opaque)
1463{
Gerd Hoffmann76ffb0b2012-09-28 13:24:17 +02001464 QemuConsole *s = opaque;
Jan Kiszkabf1bed82012-07-10 22:00:55 +02001465
1466 s->cursor_visible_phase = !s->cursor_visible_phase;
1467 vga_hw_invalidate();
1468 qemu_mod_timer(s->cursor_timer,
1469 qemu_get_clock_ms(rt_clock) + CONSOLE_CURSOR_PERIOD / 2);
1470}
1471
Paolo Bonzini44b37b92010-12-23 13:42:53 +01001472static void text_console_do_init(CharDriverState *chr, DisplayState *ds)
bellarde7f0ad52004-07-14 17:28:59 +00001473{
Gerd Hoffmann76ffb0b2012-09-28 13:24:17 +02001474 QemuConsole *s;
bellarde7f0ad52004-07-14 17:28:59 +00001475 static int color_inited;
pbrook6d6f7c22006-03-11 15:35:30 +00001476
Paolo Bonzini491e1142010-12-23 13:42:51 +01001477 s = chr->opaque;
Gerd Hoffmann6ea314d2009-09-10 10:58:49 +02001478
bellarde7f0ad52004-07-14 17:28:59 +00001479 chr->chr_write = console_puts;
bellard6fcfafb2004-08-01 21:48:30 +00001480
bellarde15d7372006-06-25 16:26:29 +00001481 s->out_fifo.buf = s->out_fifo_buf;
1482 s->out_fifo.buf_size = sizeof(s->out_fifo_buf);
Paolo Bonzini7bd427d2011-03-11 16:47:48 +01001483 s->kbd_timer = qemu_new_timer_ms(rt_clock, kbd_send_chars, s);
aliguori3023f332009-01-16 19:04:14 +00001484 s->ds = ds;
ths3b46e622007-09-17 08:09:54 +00001485
bellarde7f0ad52004-07-14 17:28:59 +00001486 if (!color_inited) {
1487 color_inited = 1;
balroga528b802007-10-30 22:38:53 +00001488 console_color_init(s->ds);
bellarde7f0ad52004-07-14 17:28:59 +00001489 }
1490 s->y_displayed = 0;
1491 s->y_base = 0;
1492 s->total_height = DEFAULT_BACKSCROLL;
1493 s->x = 0;
1494 s->y = 0;
Paolo Bonzini491e1142010-12-23 13:42:51 +01001495 if (s->console_type == TEXT_CONSOLE) {
1496 s->g_width = ds_get_width(s->ds);
1497 s->g_height = ds_get_height(s->ds);
1498 }
pbrook6d6f7c22006-03-11 15:35:30 +00001499
Jan Kiszkabf1bed82012-07-10 22:00:55 +02001500 s->cursor_timer =
1501 qemu_new_timer_ms(rt_clock, text_console_update_cursor, s);
1502
balrog4d3b6f62008-02-10 16:33:14 +00001503 s->hw_invalidate = text_console_invalidate;
1504 s->hw_text_update = text_console_update;
1505 s->hw = s;
1506
pbrook6d6f7c22006-03-11 15:35:30 +00001507 /* Set text attribute defaults */
1508 s->t_attrib_default.bold = 0;
1509 s->t_attrib_default.uline = 0;
1510 s->t_attrib_default.blink = 0;
1511 s->t_attrib_default.invers = 0;
1512 s->t_attrib_default.unvisible = 0;
1513 s->t_attrib_default.fgcol = COLOR_WHITE;
1514 s->t_attrib_default.bgcol = COLOR_BLACK;
pbrook6d6f7c22006-03-11 15:35:30 +00001515 /* set current text attributes to default */
1516 s->t_attrib = s->t_attrib_default;
bellarde7f0ad52004-07-14 17:28:59 +00001517 text_console_resize(s);
1518
Gerd Hoffmann51bfa4d2009-12-08 13:11:39 +01001519 if (chr->label) {
1520 char msg[128];
1521 int len;
1522
Gerd Hoffmann735ba582009-12-08 13:11:40 +01001523 s->t_attrib.bgcol = COLOR_BLUE;
Gerd Hoffmann51bfa4d2009-12-08 13:11:39 +01001524 len = snprintf(msg, sizeof(msg), "%s console\r\n", chr->label);
1525 console_puts(chr, (uint8_t*)msg, len);
Gerd Hoffmann735ba582009-12-08 13:11:40 +01001526 s->t_attrib = s->t_attrib_default;
Gerd Hoffmann51bfa4d2009-12-08 13:11:39 +01001527 }
1528
Amit Shah127338e2009-11-03 19:59:56 +05301529 qemu_chr_generic_open(chr);
aurel32ceecf1d2009-01-18 14:08:04 +00001530 if (chr->init)
1531 chr->init(chr);
bellarde7f0ad52004-07-14 17:28:59 +00001532}
pbrookc60e08d2008-07-01 16:24:38 +00001533
Markus Armbruster1f514702012-02-07 15:09:08 +01001534CharDriverState *text_console_init(QemuOpts *opts)
aliguori2796dae2009-01-16 20:23:27 +00001535{
1536 CharDriverState *chr;
Gerd Hoffmann76ffb0b2012-09-28 13:24:17 +02001537 QemuConsole *s;
Paolo Bonzini491e1142010-12-23 13:42:51 +01001538 unsigned width;
1539 unsigned height;
aliguori2796dae2009-01-16 20:23:27 +00001540
Anthony Liguori7267c092011-08-20 22:09:37 -05001541 chr = g_malloc0(sizeof(CharDriverState));
aliguori2796dae2009-01-16 20:23:27 +00001542
Paolo Bonzini491e1142010-12-23 13:42:51 +01001543 width = qemu_opt_get_number(opts, "width", 0);
1544 if (width == 0)
1545 width = qemu_opt_get_number(opts, "cols", 0) * FONT_WIDTH;
1546
1547 height = qemu_opt_get_number(opts, "height", 0);
1548 if (height == 0)
1549 height = qemu_opt_get_number(opts, "rows", 0) * FONT_HEIGHT;
1550
1551 if (width == 0 || height == 0) {
1552 s = new_console(NULL, TEXT_CONSOLE);
1553 } else {
1554 s = new_console(NULL, TEXT_CONSOLE_FIXED_SIZE);
1555 }
1556
1557 if (!s) {
Stefan Weil5354d082011-10-02 18:53:09 +02001558 g_free(chr);
Markus Armbruster1f514702012-02-07 15:09:08 +01001559 return NULL;
Paolo Bonzini491e1142010-12-23 13:42:51 +01001560 }
1561
1562 s->chr = chr;
1563 s->g_width = width;
1564 s->g_height = height;
1565 chr->opaque = s;
Paolo Bonzini41048332010-12-23 13:42:52 +01001566 chr->chr_set_echo = text_console_set_echo;
Markus Armbruster1f514702012-02-07 15:09:08 +01001567 return chr;
aliguori2796dae2009-01-16 20:23:27 +00001568}
1569
1570void text_consoles_set_display(DisplayState *ds)
1571{
1572 int i;
1573
Markus Armbruster8811e1e2012-02-07 15:09:21 +01001574 for (i = 0; i < nb_consoles; i++) {
1575 if (consoles[i]->console_type != GRAPHIC_CONSOLE) {
1576 text_console_do_init(consoles[i]->chr, ds);
1577 }
aliguori2796dae2009-01-16 20:23:27 +00001578 }
aliguori2796dae2009-01-16 20:23:27 +00001579}
1580
aliguori3023f332009-01-16 19:04:14 +00001581void qemu_console_resize(DisplayState *ds, int width, int height)
pbrookc60e08d2008-07-01 16:24:38 +00001582{
Gerd Hoffmann76ffb0b2012-09-28 13:24:17 +02001583 QemuConsole *s = get_graphic_console(ds);
aliguorif497f142009-01-21 19:18:00 +00001584 if (!s) return;
1585
aliguori3023f332009-01-16 19:04:14 +00001586 s->g_width = width;
1587 s->g_height = height;
1588 if (is_graphic_console()) {
aliguori7b5d76d2009-03-13 15:02:13 +00001589 ds->surface = qemu_resize_displaysurface(ds, width, height);
Gerd Hoffmanna93a4a22012-09-28 15:02:08 +02001590 dpy_gfx_resize(ds);
pbrookc60e08d2008-07-01 16:24:38 +00001591 }
1592}
balrog38334f72008-09-24 02:21:24 +00001593
aliguori3023f332009-01-16 19:04:14 +00001594void qemu_console_copy(DisplayState *ds, int src_x, int src_y,
1595 int dst_x, int dst_y, int w, int h)
balrogc21bbcf2008-09-24 03:32:33 +00001596{
aliguori3023f332009-01-16 19:04:14 +00001597 if (is_graphic_console()) {
Gerd Hoffmanna93a4a22012-09-28 15:02:08 +02001598 dpy_gfx_copy(ds, src_x, src_y, dst_x, dst_y, w, h);
balrog38334f72008-09-24 02:21:24 +00001599 }
1600}
aliguori7d957bd2009-01-15 22:14:11 +00001601
malc0da2ea12009-01-23 19:56:19 +00001602PixelFormat qemu_different_endianness_pixelformat(int bpp)
aliguori7d957bd2009-01-15 22:14:11 +00001603{
1604 PixelFormat pf;
1605
1606 memset(&pf, 0x00, sizeof(PixelFormat));
1607
1608 pf.bits_per_pixel = bpp;
BALATON Zoltanfeadf1a2012-08-22 17:19:42 +02001609 pf.bytes_per_pixel = DIV_ROUND_UP(bpp, 8);
aliguori7d957bd2009-01-15 22:14:11 +00001610 pf.depth = bpp == 32 ? 24 : bpp;
1611
1612 switch (bpp) {
malc0da2ea12009-01-23 19:56:19 +00001613 case 24:
1614 pf.rmask = 0x000000FF;
1615 pf.gmask = 0x0000FF00;
1616 pf.bmask = 0x00FF0000;
1617 pf.rmax = 255;
1618 pf.gmax = 255;
1619 pf.bmax = 255;
1620 pf.rshift = 0;
1621 pf.gshift = 8;
1622 pf.bshift = 16;
aliguori90a1e3c2009-01-26 15:37:30 +00001623 pf.rbits = 8;
1624 pf.gbits = 8;
1625 pf.bbits = 8;
aliguori7d957bd2009-01-15 22:14:11 +00001626 break;
malc0da2ea12009-01-23 19:56:19 +00001627 case 32:
1628 pf.rmask = 0x0000FF00;
1629 pf.gmask = 0x00FF0000;
1630 pf.bmask = 0xFF000000;
1631 pf.amask = 0x00000000;
1632 pf.amax = 255;
1633 pf.rmax = 255;
1634 pf.gmax = 255;
1635 pf.bmax = 255;
1636 pf.ashift = 0;
1637 pf.rshift = 8;
1638 pf.gshift = 16;
1639 pf.bshift = 24;
aliguori90a1e3c2009-01-26 15:37:30 +00001640 pf.rbits = 8;
1641 pf.gbits = 8;
1642 pf.bbits = 8;
1643 pf.abits = 8;
malc0da2ea12009-01-23 19:56:19 +00001644 break;
1645 default:
1646 break;
1647 }
1648 return pf;
1649}
1650
1651PixelFormat qemu_default_pixelformat(int bpp)
1652{
1653 PixelFormat pf;
1654
1655 memset(&pf, 0x00, sizeof(PixelFormat));
1656
1657 pf.bits_per_pixel = bpp;
BALATON Zoltanfeadf1a2012-08-22 17:19:42 +02001658 pf.bytes_per_pixel = DIV_ROUND_UP(bpp, 8);
malc0da2ea12009-01-23 19:56:19 +00001659 pf.depth = bpp == 32 ? 24 : bpp;
1660
1661 switch (bpp) {
Gerd Hoffmannb6278082010-05-21 11:59:14 +02001662 case 15:
1663 pf.bits_per_pixel = 16;
Gerd Hoffmannb6278082010-05-21 11:59:14 +02001664 pf.rmask = 0x00007c00;
1665 pf.gmask = 0x000003E0;
1666 pf.bmask = 0x0000001F;
1667 pf.rmax = 31;
1668 pf.gmax = 31;
1669 pf.bmax = 31;
1670 pf.rshift = 10;
1671 pf.gshift = 5;
1672 pf.bshift = 0;
1673 pf.rbits = 5;
1674 pf.gbits = 5;
1675 pf.bbits = 5;
1676 break;
aliguori7d957bd2009-01-15 22:14:11 +00001677 case 16:
1678 pf.rmask = 0x0000F800;
1679 pf.gmask = 0x000007E0;
1680 pf.bmask = 0x0000001F;
1681 pf.rmax = 31;
1682 pf.gmax = 63;
1683 pf.bmax = 31;
1684 pf.rshift = 11;
1685 pf.gshift = 5;
1686 pf.bshift = 0;
aliguori90a1e3c2009-01-26 15:37:30 +00001687 pf.rbits = 5;
1688 pf.gbits = 6;
1689 pf.bbits = 5;
aliguori7d957bd2009-01-15 22:14:11 +00001690 break;
1691 case 24:
aliguori7d957bd2009-01-15 22:14:11 +00001692 pf.rmask = 0x00FF0000;
1693 pf.gmask = 0x0000FF00;
1694 pf.bmask = 0x000000FF;
1695 pf.rmax = 255;
1696 pf.gmax = 255;
1697 pf.bmax = 255;
1698 pf.rshift = 16;
1699 pf.gshift = 8;
1700 pf.bshift = 0;
aliguori90a1e3c2009-01-26 15:37:30 +00001701 pf.rbits = 8;
1702 pf.gbits = 8;
1703 pf.bbits = 8;
Markus Armbruster0eba62e2011-11-22 12:56:10 +01001704 break;
malc0da2ea12009-01-23 19:56:19 +00001705 case 32:
1706 pf.rmask = 0x00FF0000;
1707 pf.gmask = 0x0000FF00;
1708 pf.bmask = 0x000000FF;
malc0da2ea12009-01-23 19:56:19 +00001709 pf.rmax = 255;
1710 pf.gmax = 255;
1711 pf.bmax = 255;
malc0da2ea12009-01-23 19:56:19 +00001712 pf.rshift = 16;
1713 pf.gshift = 8;
1714 pf.bshift = 0;
aliguori90a1e3c2009-01-26 15:37:30 +00001715 pf.rbits = 8;
1716 pf.gbits = 8;
1717 pf.bbits = 8;
aliguori7d957bd2009-01-15 22:14:11 +00001718 break;
1719 default:
1720 break;
1721 }
1722 return pf;
1723}