blob: 3b5cabba3a6cf944fb16feaf2011816a1d06f4c6 [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"
bellarde7f0ad52004-07-14 17:28:59 +000027
pbrook6d6f7c22006-03-11 15:35:30 +000028//#define DEBUG_CONSOLE
bellarde7f0ad52004-07-14 17:28:59 +000029#define DEFAULT_BACKSCROLL 512
30#define MAX_CONSOLES 12
Jan Kiszkabf1bed82012-07-10 22:00:55 +020031#define CONSOLE_CURSOR_PERIOD 500
bellarde7f0ad52004-07-14 17:28:59 +000032
bellard26489842006-06-25 17:37:36 +000033#define QEMU_RGBA(r, g, b, a) (((a) << 24) | ((r) << 16) | ((g) << 8) | (b))
34#define QEMU_RGB(r, g, b) QEMU_RGBA(r, g, b, 0xff)
bellarde7f0ad52004-07-14 17:28:59 +000035
pbrook6d6f7c22006-03-11 15:35:30 +000036typedef struct TextAttributes {
37 uint8_t fgcol:4;
38 uint8_t bgcol:4;
39 uint8_t bold:1;
40 uint8_t uline:1;
41 uint8_t blink:1;
42 uint8_t invers:1;
43 uint8_t unvisible:1;
44} TextAttributes;
45
bellarde7f0ad52004-07-14 17:28:59 +000046typedef struct TextCell {
47 uint8_t ch;
pbrook6d6f7c22006-03-11 15:35:30 +000048 TextAttributes t_attrib;
bellarde7f0ad52004-07-14 17:28:59 +000049} TextCell;
50
51#define MAX_ESC_PARAMS 3
52
53enum TTYState {
54 TTY_STATE_NORM,
55 TTY_STATE_ESC,
56 TTY_STATE_CSI,
57};
58
bellarde15d7372006-06-25 16:26:29 +000059typedef struct QEMUFIFO {
60 uint8_t *buf;
61 int buf_size;
62 int count, wptr, rptr;
63} QEMUFIFO;
64
pbrook9596ebb2007-11-18 01:44:38 +000065static int qemu_fifo_write(QEMUFIFO *f, const uint8_t *buf, int len1)
bellarde15d7372006-06-25 16:26:29 +000066{
67 int l, len;
68
69 l = f->buf_size - f->count;
70 if (len1 > l)
71 len1 = l;
72 len = len1;
73 while (len > 0) {
74 l = f->buf_size - f->wptr;
75 if (l > len)
76 l = len;
77 memcpy(f->buf + f->wptr, buf, l);
78 f->wptr += l;
79 if (f->wptr >= f->buf_size)
80 f->wptr = 0;
81 buf += l;
82 len -= l;
83 }
84 f->count += len1;
85 return len1;
86}
87
pbrook9596ebb2007-11-18 01:44:38 +000088static int qemu_fifo_read(QEMUFIFO *f, uint8_t *buf, int len1)
bellarde15d7372006-06-25 16:26:29 +000089{
90 int l, len;
91
92 if (len1 > f->count)
93 len1 = f->count;
94 len = len1;
95 while (len > 0) {
96 l = f->buf_size - f->rptr;
97 if (l > len)
98 l = len;
99 memcpy(buf, f->buf + f->rptr, l);
100 f->rptr += l;
101 if (f->rptr >= f->buf_size)
102 f->rptr = 0;
103 buf += l;
104 len -= l;
105 }
106 f->count -= len1;
107 return len1;
108}
109
thsaf3a9032007-07-11 23:14:59 +0000110typedef enum {
111 GRAPHIC_CONSOLE,
balrogc21bbcf2008-09-24 03:32:33 +0000112 TEXT_CONSOLE,
113 TEXT_CONSOLE_FIXED_SIZE
Anthony Liguoric227f092009-10-01 16:12:16 -0500114} console_type_t;
thsaf3a9032007-07-11 23:14:59 +0000115
pbrook95219892006-04-09 01:06:34 +0000116/* ??? This is mis-named.
117 It is used for both text and graphical consoles. */
bellarde7f0ad52004-07-14 17:28:59 +0000118struct TextConsole {
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;
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;
128
bellarde7f0ad52004-07-14 17:28:59 +0000129 int g_width, g_height;
130 int width;
131 int height;
132 int total_height;
133 int backscroll_height;
bellarde7f0ad52004-07-14 17:28:59 +0000134 int x, y;
thsadb47962007-01-16 23:02:36 +0000135 int x_saved, y_saved;
bellarde7f0ad52004-07-14 17:28:59 +0000136 int y_displayed;
137 int y_base;
pbrook6d6f7c22006-03-11 15:35:30 +0000138 TextAttributes t_attrib_default; /* default text attributes */
139 TextAttributes t_attrib; /* currently active text attributes */
bellarde7f0ad52004-07-14 17:28:59 +0000140 TextCell *cells;
balrog4d3b6f62008-02-10 16:33:14 +0000141 int text_x[2], text_y[2], cursor_invalidate;
Paolo Bonzini41048332010-12-23 13:42:52 +0100142 int echo;
Jan Kiszkabf1bed82012-07-10 22:00:55 +0200143 bool cursor_visible_phase;
144 QEMUTimer *cursor_timer;
bellarde7f0ad52004-07-14 17:28:59 +0000145
pbrook14778c22009-01-21 03:02:52 +0000146 int update_x0;
147 int update_y0;
148 int update_x1;
149 int update_y1;
150
bellarde7f0ad52004-07-14 17:28:59 +0000151 enum TTYState state;
152 int esc_params[MAX_ESC_PARAMS];
153 int nb_esc_params;
154
pbrooke5b0bc42007-01-27 23:46:43 +0000155 CharDriverState *chr;
bellarde15d7372006-06-25 16:26:29 +0000156 /* fifo for key pressed */
157 QEMUFIFO out_fifo;
158 uint8_t out_fifo_buf[16];
159 QEMUTimer *kbd_timer;
bellarde7f0ad52004-07-14 17:28:59 +0000160};
161
Paolo Bonzini98b50082010-02-11 00:29:57 +0100162static DisplayState *display_state;
bellarde7f0ad52004-07-14 17:28:59 +0000163static TextConsole *active_console;
164static TextConsole *consoles[MAX_CONSOLES];
165static int nb_consoles = 0;
166
pbrook95219892006-04-09 01:06:34 +0000167void vga_hw_update(void)
168{
thsadb47962007-01-16 23:02:36 +0000169 if (active_console && active_console->hw_update)
pbrook95219892006-04-09 01:06:34 +0000170 active_console->hw_update(active_console->hw);
171}
172
173void vga_hw_invalidate(void)
174{
Gerd Hoffmann26572b82010-05-20 15:23:06 +0200175 if (active_console && active_console->hw_invalidate)
pbrook95219892006-04-09 01:06:34 +0000176 active_console->hw_invalidate(active_console->hw);
177}
178
179void vga_hw_screen_dump(const char *filename)
180{
balrog8571c052008-07-19 13:04:26 +0000181 TextConsole *previous_active_console;
Gerd Hoffmann45efb162012-02-24 12:43:45 +0100182 bool cswitch;
balrog8571c052008-07-19 13:04:26 +0000183
184 previous_active_console = active_console;
Gerd Hoffmann45efb162012-02-24 12:43:45 +0100185 cswitch = previous_active_console && previous_active_console->index != 0;
Jan Kiszkaf81bdef2011-09-16 00:48:07 +0200186
balrog8571c052008-07-19 13:04:26 +0000187 /* There is currently no way of specifying which screen we want to dump,
aurel327b455222008-09-02 00:09:16 +0000188 so always dump the first one. */
Gerd Hoffmann45efb162012-02-24 12:43:45 +0100189 if (cswitch) {
190 console_select(0);
191 }
Jan Kiszkaf81bdef2011-09-16 00:48:07 +0200192 if (consoles[0] && consoles[0]->hw_screen_dump) {
Gerd Hoffmann45efb162012-02-24 12:43:45 +0100193 consoles[0]->hw_screen_dump(consoles[0]->hw, filename, cswitch);
Gerd Hoffmann16735102012-02-24 12:43:44 +0100194 } else {
195 error_report("screen dump not implemented");
Jan Kiszkaf81bdef2011-09-16 00:48:07 +0200196 }
197
Gerd Hoffmann45efb162012-02-24 12:43:45 +0100198 if (cswitch) {
Alexander Graf33bcd982011-11-18 16:41:59 +0100199 console_select(previous_active_console->index);
200 }
pbrook95219892006-04-09 01:06:34 +0000201}
202
Anthony Liguoric227f092009-10-01 16:12:16 -0500203void vga_hw_text_update(console_ch_t *chardata)
balrog4d3b6f62008-02-10 16:33:14 +0000204{
205 if (active_console && active_console->hw_text_update)
206 active_console->hw_text_update(active_console->hw, chardata);
207}
208
bellarde7f0ad52004-07-14 17:28:59 +0000209/* convert a RGBA color to a color index usable in graphic primitives */
210static unsigned int vga_get_color(DisplayState *ds, unsigned int rgba)
211{
212 unsigned int r, g, b, color;
213
aliguori0e1f5a02008-11-24 19:29:13 +0000214 switch(ds_get_bits_per_pixel(ds)) {
bellarde7f0ad52004-07-14 17:28:59 +0000215#if 0
216 case 8:
217 r = (rgba >> 16) & 0xff;
218 g = (rgba >> 8) & 0xff;
219 b = (rgba) & 0xff;
ths5fafdf22007-09-16 21:08:06 +0000220 color = (rgb_to_index[r] * 6 * 6) +
221 (rgb_to_index[g] * 6) +
bellarde7f0ad52004-07-14 17:28:59 +0000222 (rgb_to_index[b]);
223 break;
224#endif
225 case 15:
226 r = (rgba >> 16) & 0xff;
227 g = (rgba >> 8) & 0xff;
228 b = (rgba) & 0xff;
229 color = ((r >> 3) << 10) | ((g >> 3) << 5) | (b >> 3);
230 break;
231 case 16:
232 r = (rgba >> 16) & 0xff;
233 g = (rgba >> 8) & 0xff;
234 b = (rgba) & 0xff;
235 color = ((r >> 3) << 11) | ((g >> 2) << 5) | (b >> 3);
236 break;
237 case 32:
238 default:
239 color = rgba;
240 break;
241 }
242 return color;
243}
244
ths5fafdf22007-09-16 21:08:06 +0000245static void vga_fill_rect (DisplayState *ds,
bellarde7f0ad52004-07-14 17:28:59 +0000246 int posx, int posy, int width, int height, uint32_t color)
247{
248 uint8_t *d, *d1;
249 int x, y, bpp;
ths3b46e622007-09-17 08:09:54 +0000250
aliguori0e1f5a02008-11-24 19:29:13 +0000251 bpp = (ds_get_bits_per_pixel(ds) + 7) >> 3;
252 d1 = ds_get_data(ds) +
253 ds_get_linesize(ds) * posy + bpp * posx;
bellarde7f0ad52004-07-14 17:28:59 +0000254 for (y = 0; y < height; y++) {
255 d = d1;
256 switch(bpp) {
257 case 1:
258 for (x = 0; x < width; x++) {
259 *((uint8_t *)d) = color;
260 d++;
261 }
262 break;
263 case 2:
264 for (x = 0; x < width; x++) {
265 *((uint16_t *)d) = color;
266 d += 2;
267 }
268 break;
269 case 4:
270 for (x = 0; x < width; x++) {
271 *((uint32_t *)d) = color;
272 d += 4;
273 }
274 break;
275 }
aliguori0e1f5a02008-11-24 19:29:13 +0000276 d1 += ds_get_linesize(ds);
bellarde7f0ad52004-07-14 17:28:59 +0000277 }
278}
279
280/* copy from (xs, ys) to (xd, yd) a rectangle of size (w, h) */
281static void vga_bitblt(DisplayState *ds, int xs, int ys, int xd, int yd, int w, int h)
282{
283 const uint8_t *s;
284 uint8_t *d;
285 int wb, y, bpp;
286
aliguori0e1f5a02008-11-24 19:29:13 +0000287 bpp = (ds_get_bits_per_pixel(ds) + 7) >> 3;
bellarde7f0ad52004-07-14 17:28:59 +0000288 wb = w * bpp;
289 if (yd <= ys) {
aliguori0e1f5a02008-11-24 19:29:13 +0000290 s = ds_get_data(ds) +
291 ds_get_linesize(ds) * ys + bpp * xs;
292 d = ds_get_data(ds) +
293 ds_get_linesize(ds) * yd + bpp * xd;
bellarde7f0ad52004-07-14 17:28:59 +0000294 for (y = 0; y < h; y++) {
295 memmove(d, s, wb);
aliguori0e1f5a02008-11-24 19:29:13 +0000296 d += ds_get_linesize(ds);
297 s += ds_get_linesize(ds);
bellarde7f0ad52004-07-14 17:28:59 +0000298 }
299 } else {
aliguori0e1f5a02008-11-24 19:29:13 +0000300 s = ds_get_data(ds) +
301 ds_get_linesize(ds) * (ys + h - 1) + bpp * xs;
302 d = ds_get_data(ds) +
303 ds_get_linesize(ds) * (yd + h - 1) + bpp * xd;
bellarde7f0ad52004-07-14 17:28:59 +0000304 for (y = 0; y < h; y++) {
305 memmove(d, s, wb);
aliguori0e1f5a02008-11-24 19:29:13 +0000306 d -= ds_get_linesize(ds);
307 s -= ds_get_linesize(ds);
bellarde7f0ad52004-07-14 17:28:59 +0000308 }
309 }
310}
311
312/***********************************************************/
313/* basic char display */
314
315#define FONT_HEIGHT 16
316#define FONT_WIDTH 8
317
318#include "vgafont.h"
319
320#define cbswap_32(__x) \
321((uint32_t)( \
322 (((uint32_t)(__x) & (uint32_t)0x000000ffUL) << 24) | \
323 (((uint32_t)(__x) & (uint32_t)0x0000ff00UL) << 8) | \
324 (((uint32_t)(__x) & (uint32_t)0x00ff0000UL) >> 8) | \
325 (((uint32_t)(__x) & (uint32_t)0xff000000UL) >> 24) ))
326
Juan Quintelae2542fe2009-07-27 16:13:06 +0200327#ifdef HOST_WORDS_BIGENDIAN
bellarde7f0ad52004-07-14 17:28:59 +0000328#define PAT(x) x
329#else
330#define PAT(x) cbswap_32(x)
331#endif
332
333static const uint32_t dmask16[16] = {
334 PAT(0x00000000),
335 PAT(0x000000ff),
336 PAT(0x0000ff00),
337 PAT(0x0000ffff),
338 PAT(0x00ff0000),
339 PAT(0x00ff00ff),
340 PAT(0x00ffff00),
341 PAT(0x00ffffff),
342 PAT(0xff000000),
343 PAT(0xff0000ff),
344 PAT(0xff00ff00),
345 PAT(0xff00ffff),
346 PAT(0xffff0000),
347 PAT(0xffff00ff),
348 PAT(0xffffff00),
349 PAT(0xffffffff),
350};
351
352static const uint32_t dmask4[4] = {
353 PAT(0x00000000),
354 PAT(0x0000ffff),
355 PAT(0xffff0000),
356 PAT(0xffffffff),
357};
358
pbrook6d6f7c22006-03-11 15:35:30 +0000359static uint32_t color_table[2][8];
bellarde7f0ad52004-07-14 17:28:59 +0000360
Devin J. Pohlydf00bed2011-09-07 15:44:36 -0400361#ifndef CONFIG_CURSES
pbrook6d6f7c22006-03-11 15:35:30 +0000362enum color_names {
363 COLOR_BLACK = 0,
364 COLOR_RED = 1,
365 COLOR_GREEN = 2,
366 COLOR_YELLOW = 3,
367 COLOR_BLUE = 4,
368 COLOR_MAGENTA = 5,
369 COLOR_CYAN = 6,
370 COLOR_WHITE = 7
371};
Devin J. Pohlydf00bed2011-09-07 15:44:36 -0400372#endif
pbrook6d6f7c22006-03-11 15:35:30 +0000373
374static const uint32_t color_table_rgb[2][8] = {
375 { /* dark */
bellard26489842006-06-25 17:37:36 +0000376 QEMU_RGB(0x00, 0x00, 0x00), /* black */
377 QEMU_RGB(0xaa, 0x00, 0x00), /* red */
378 QEMU_RGB(0x00, 0xaa, 0x00), /* green */
379 QEMU_RGB(0xaa, 0xaa, 0x00), /* yellow */
380 QEMU_RGB(0x00, 0x00, 0xaa), /* blue */
381 QEMU_RGB(0xaa, 0x00, 0xaa), /* magenta */
382 QEMU_RGB(0x00, 0xaa, 0xaa), /* cyan */
383 QEMU_RGB(0xaa, 0xaa, 0xaa), /* white */
pbrook6d6f7c22006-03-11 15:35:30 +0000384 },
385 { /* bright */
bellard26489842006-06-25 17:37:36 +0000386 QEMU_RGB(0x00, 0x00, 0x00), /* black */
387 QEMU_RGB(0xff, 0x00, 0x00), /* red */
388 QEMU_RGB(0x00, 0xff, 0x00), /* green */
389 QEMU_RGB(0xff, 0xff, 0x00), /* yellow */
390 QEMU_RGB(0x00, 0x00, 0xff), /* blue */
391 QEMU_RGB(0xff, 0x00, 0xff), /* magenta */
392 QEMU_RGB(0x00, 0xff, 0xff), /* cyan */
393 QEMU_RGB(0xff, 0xff, 0xff), /* white */
pbrook6d6f7c22006-03-11 15:35:30 +0000394 }
bellarde7f0ad52004-07-14 17:28:59 +0000395};
396
397static inline unsigned int col_expand(DisplayState *ds, unsigned int col)
398{
aliguori0e1f5a02008-11-24 19:29:13 +0000399 switch(ds_get_bits_per_pixel(ds)) {
bellarde7f0ad52004-07-14 17:28:59 +0000400 case 8:
401 col |= col << 8;
402 col |= col << 16;
403 break;
404 case 15:
405 case 16:
406 col |= col << 16;
407 break;
408 default:
409 break;
410 }
411
412 return col;
413}
pbrook6d6f7c22006-03-11 15:35:30 +0000414#ifdef DEBUG_CONSOLE
415static void console_print_text_attributes(TextAttributes *t_attrib, char ch)
416{
417 if (t_attrib->bold) {
418 printf("b");
419 } else {
420 printf(" ");
421 }
422 if (t_attrib->uline) {
423 printf("u");
424 } else {
425 printf(" ");
426 }
427 if (t_attrib->blink) {
428 printf("l");
429 } else {
430 printf(" ");
431 }
432 if (t_attrib->invers) {
433 printf("i");
434 } else {
435 printf(" ");
436 }
437 if (t_attrib->unvisible) {
438 printf("n");
439 } else {
440 printf(" ");
441 }
442
443 printf(" fg: %d bg: %d ch:'%2X' '%c'\n", t_attrib->fgcol, t_attrib->bgcol, ch, ch);
444}
445#endif
bellarde7f0ad52004-07-14 17:28:59 +0000446
ths5fafdf22007-09-16 21:08:06 +0000447static void vga_putcharxy(DisplayState *ds, int x, int y, int ch,
pbrook6d6f7c22006-03-11 15:35:30 +0000448 TextAttributes *t_attrib)
bellarde7f0ad52004-07-14 17:28:59 +0000449{
450 uint8_t *d;
451 const uint8_t *font_ptr;
452 unsigned int font_data, linesize, xorcol, bpp;
453 int i;
pbrook6d6f7c22006-03-11 15:35:30 +0000454 unsigned int fgcol, bgcol;
455
456#ifdef DEBUG_CONSOLE
457 printf("x: %2i y: %2i", x, y);
458 console_print_text_attributes(t_attrib, ch);
459#endif
460
461 if (t_attrib->invers) {
462 bgcol = color_table[t_attrib->bold][t_attrib->fgcol];
463 fgcol = color_table[t_attrib->bold][t_attrib->bgcol];
464 } else {
465 fgcol = color_table[t_attrib->bold][t_attrib->fgcol];
466 bgcol = color_table[t_attrib->bold][t_attrib->bgcol];
467 }
bellarde7f0ad52004-07-14 17:28:59 +0000468
aliguori0e1f5a02008-11-24 19:29:13 +0000469 bpp = (ds_get_bits_per_pixel(ds) + 7) >> 3;
470 d = ds_get_data(ds) +
471 ds_get_linesize(ds) * y * FONT_HEIGHT + bpp * x * FONT_WIDTH;
472 linesize = ds_get_linesize(ds);
bellarde7f0ad52004-07-14 17:28:59 +0000473 font_ptr = vgafont16 + FONT_HEIGHT * ch;
474 xorcol = bgcol ^ fgcol;
aliguori0e1f5a02008-11-24 19:29:13 +0000475 switch(ds_get_bits_per_pixel(ds)) {
bellarde7f0ad52004-07-14 17:28:59 +0000476 case 8:
477 for(i = 0; i < FONT_HEIGHT; i++) {
478 font_data = *font_ptr++;
pbrook6d6f7c22006-03-11 15:35:30 +0000479 if (t_attrib->uline
480 && ((i == FONT_HEIGHT - 2) || (i == FONT_HEIGHT - 3))) {
Markus Armbruster439229c2011-11-04 10:38:29 +0100481 font_data = 0xFF;
pbrook6d6f7c22006-03-11 15:35:30 +0000482 }
bellarde7f0ad52004-07-14 17:28:59 +0000483 ((uint32_t *)d)[0] = (dmask16[(font_data >> 4)] & xorcol) ^ bgcol;
484 ((uint32_t *)d)[1] = (dmask16[(font_data >> 0) & 0xf] & xorcol) ^ bgcol;
485 d += linesize;
486 }
487 break;
488 case 16:
489 case 15:
490 for(i = 0; i < FONT_HEIGHT; i++) {
491 font_data = *font_ptr++;
pbrook6d6f7c22006-03-11 15:35:30 +0000492 if (t_attrib->uline
493 && ((i == FONT_HEIGHT - 2) || (i == FONT_HEIGHT - 3))) {
Markus Armbruster439229c2011-11-04 10:38:29 +0100494 font_data = 0xFF;
pbrook6d6f7c22006-03-11 15:35:30 +0000495 }
bellarde7f0ad52004-07-14 17:28:59 +0000496 ((uint32_t *)d)[0] = (dmask4[(font_data >> 6)] & xorcol) ^ bgcol;
497 ((uint32_t *)d)[1] = (dmask4[(font_data >> 4) & 3] & xorcol) ^ bgcol;
498 ((uint32_t *)d)[2] = (dmask4[(font_data >> 2) & 3] & xorcol) ^ bgcol;
499 ((uint32_t *)d)[3] = (dmask4[(font_data >> 0) & 3] & xorcol) ^ bgcol;
500 d += linesize;
501 }
502 break;
503 case 32:
504 for(i = 0; i < FONT_HEIGHT; i++) {
505 font_data = *font_ptr++;
pbrook6d6f7c22006-03-11 15:35:30 +0000506 if (t_attrib->uline && ((i == FONT_HEIGHT - 2) || (i == FONT_HEIGHT - 3))) {
Markus Armbruster439229c2011-11-04 10:38:29 +0100507 font_data = 0xFF;
pbrook6d6f7c22006-03-11 15:35:30 +0000508 }
bellarde7f0ad52004-07-14 17:28:59 +0000509 ((uint32_t *)d)[0] = (-((font_data >> 7)) & xorcol) ^ bgcol;
510 ((uint32_t *)d)[1] = (-((font_data >> 6) & 1) & xorcol) ^ bgcol;
511 ((uint32_t *)d)[2] = (-((font_data >> 5) & 1) & xorcol) ^ bgcol;
512 ((uint32_t *)d)[3] = (-((font_data >> 4) & 1) & xorcol) ^ bgcol;
513 ((uint32_t *)d)[4] = (-((font_data >> 3) & 1) & xorcol) ^ bgcol;
514 ((uint32_t *)d)[5] = (-((font_data >> 2) & 1) & xorcol) ^ bgcol;
515 ((uint32_t *)d)[6] = (-((font_data >> 1) & 1) & xorcol) ^ bgcol;
516 ((uint32_t *)d)[7] = (-((font_data >> 0) & 1) & xorcol) ^ bgcol;
517 d += linesize;
518 }
519 break;
520 }
521}
522
523static void text_console_resize(TextConsole *s)
524{
525 TextCell *cells, *c, *c1;
526 int w1, x, y, last_width;
527
528 last_width = s->width;
529 s->width = s->g_width / FONT_WIDTH;
530 s->height = s->g_height / FONT_HEIGHT;
531
532 w1 = last_width;
533 if (s->width < w1)
534 w1 = s->width;
535
Anthony Liguori7267c092011-08-20 22:09:37 -0500536 cells = g_malloc(s->width * s->total_height * sizeof(TextCell));
bellarde7f0ad52004-07-14 17:28:59 +0000537 for(y = 0; y < s->total_height; y++) {
538 c = &cells[y * s->width];
539 if (w1 > 0) {
540 c1 = &s->cells[y * last_width];
541 for(x = 0; x < w1; x++) {
542 *c++ = *c1++;
543 }
544 }
545 for(x = w1; x < s->width; x++) {
546 c->ch = ' ';
pbrook6d6f7c22006-03-11 15:35:30 +0000547 c->t_attrib = s->t_attrib_default;
bellarde7f0ad52004-07-14 17:28:59 +0000548 c++;
549 }
550 }
Anthony Liguori7267c092011-08-20 22:09:37 -0500551 g_free(s->cells);
bellarde7f0ad52004-07-14 17:28:59 +0000552 s->cells = cells;
553}
554
balrog4d3b6f62008-02-10 16:33:14 +0000555static inline void text_update_xy(TextConsole *s, int x, int y)
556{
557 s->text_x[0] = MIN(s->text_x[0], x);
558 s->text_x[1] = MAX(s->text_x[1], x);
559 s->text_y[0] = MIN(s->text_y[0], y);
560 s->text_y[1] = MAX(s->text_y[1], y);
561}
562
pbrook14778c22009-01-21 03:02:52 +0000563static void invalidate_xy(TextConsole *s, int x, int y)
564{
565 if (s->update_x0 > x * FONT_WIDTH)
566 s->update_x0 = x * FONT_WIDTH;
567 if (s->update_y0 > y * FONT_HEIGHT)
568 s->update_y0 = y * FONT_HEIGHT;
569 if (s->update_x1 < (x + 1) * FONT_WIDTH)
570 s->update_x1 = (x + 1) * FONT_WIDTH;
571 if (s->update_y1 < (y + 1) * FONT_HEIGHT)
572 s->update_y1 = (y + 1) * FONT_HEIGHT;
573}
574
bellarde7f0ad52004-07-14 17:28:59 +0000575static void update_xy(TextConsole *s, int x, int y)
576{
577 TextCell *c;
578 int y1, y2;
579
580 if (s == active_console) {
aliguori0e1f5a02008-11-24 19:29:13 +0000581 if (!ds_get_bits_per_pixel(s->ds)) {
balrog4d3b6f62008-02-10 16:33:14 +0000582 text_update_xy(s, x, y);
583 return;
584 }
585
bellarde7f0ad52004-07-14 17:28:59 +0000586 y1 = (s->y_base + y) % s->total_height;
587 y2 = y1 - s->y_displayed;
588 if (y2 < 0)
589 y2 += s->total_height;
590 if (y2 < s->height) {
591 c = &s->cells[y1 * s->width + x];
ths5fafdf22007-09-16 21:08:06 +0000592 vga_putcharxy(s->ds, x, y2, c->ch,
pbrook6d6f7c22006-03-11 15:35:30 +0000593 &(c->t_attrib));
pbrook14778c22009-01-21 03:02:52 +0000594 invalidate_xy(s, x, y2);
bellarde7f0ad52004-07-14 17:28:59 +0000595 }
596 }
597}
598
599static void console_show_cursor(TextConsole *s, int show)
600{
601 TextCell *c;
602 int y, y1;
603
604 if (s == active_console) {
thsed8276a2007-02-10 22:37:56 +0000605 int x = s->x;
balrog4d3b6f62008-02-10 16:33:14 +0000606
aliguori0e1f5a02008-11-24 19:29:13 +0000607 if (!ds_get_bits_per_pixel(s->ds)) {
balrog4d3b6f62008-02-10 16:33:14 +0000608 s->cursor_invalidate = 1;
609 return;
610 }
611
thsed8276a2007-02-10 22:37:56 +0000612 if (x >= s->width) {
613 x = s->width - 1;
614 }
bellarde7f0ad52004-07-14 17:28:59 +0000615 y1 = (s->y_base + s->y) % s->total_height;
616 y = y1 - s->y_displayed;
617 if (y < 0)
618 y += s->total_height;
619 if (y < s->height) {
thsed8276a2007-02-10 22:37:56 +0000620 c = &s->cells[y1 * s->width + x];
Jan Kiszkabf1bed82012-07-10 22:00:55 +0200621 if (show && s->cursor_visible_phase) {
pbrook6d6f7c22006-03-11 15:35:30 +0000622 TextAttributes t_attrib = s->t_attrib_default;
623 t_attrib.invers = !(t_attrib.invers); /* invert fg and bg */
thsed8276a2007-02-10 22:37:56 +0000624 vga_putcharxy(s->ds, x, y, c->ch, &t_attrib);
bellarde7f0ad52004-07-14 17:28:59 +0000625 } else {
thsed8276a2007-02-10 22:37:56 +0000626 vga_putcharxy(s->ds, x, y, c->ch, &(c->t_attrib));
bellarde7f0ad52004-07-14 17:28:59 +0000627 }
pbrook14778c22009-01-21 03:02:52 +0000628 invalidate_xy(s, x, y);
bellarde7f0ad52004-07-14 17:28:59 +0000629 }
630 }
631}
632
633static void console_refresh(TextConsole *s)
634{
635 TextCell *c;
636 int x, y, y1;
637
ths5fafdf22007-09-16 21:08:06 +0000638 if (s != active_console)
bellarde7f0ad52004-07-14 17:28:59 +0000639 return;
aliguori0e1f5a02008-11-24 19:29:13 +0000640 if (!ds_get_bits_per_pixel(s->ds)) {
balrog4d3b6f62008-02-10 16:33:14 +0000641 s->text_x[0] = 0;
642 s->text_y[0] = 0;
643 s->text_x[1] = s->width - 1;
644 s->text_y[1] = s->height - 1;
645 s->cursor_invalidate = 1;
646 return;
647 }
bellarde7f0ad52004-07-14 17:28:59 +0000648
aliguori0e1f5a02008-11-24 19:29:13 +0000649 vga_fill_rect(s->ds, 0, 0, ds_get_width(s->ds), ds_get_height(s->ds),
pbrook6d6f7c22006-03-11 15:35:30 +0000650 color_table[0][COLOR_BLACK]);
bellarde7f0ad52004-07-14 17:28:59 +0000651 y1 = s->y_displayed;
652 for(y = 0; y < s->height; y++) {
653 c = s->cells + y1 * s->width;
654 for(x = 0; x < s->width; x++) {
ths5fafdf22007-09-16 21:08:06 +0000655 vga_putcharxy(s->ds, x, y, c->ch,
pbrook6d6f7c22006-03-11 15:35:30 +0000656 &(c->t_attrib));
bellarde7f0ad52004-07-14 17:28:59 +0000657 c++;
658 }
659 if (++y1 == s->total_height)
660 y1 = 0;
661 }
bellarde7f0ad52004-07-14 17:28:59 +0000662 console_show_cursor(s, 1);
pbrook14778c22009-01-21 03:02:52 +0000663 dpy_update(s->ds, 0, 0, ds_get_width(s->ds), ds_get_height(s->ds));
bellarde7f0ad52004-07-14 17:28:59 +0000664}
665
666static void console_scroll(int ydelta)
667{
668 TextConsole *s;
669 int i, y1;
ths3b46e622007-09-17 08:09:54 +0000670
bellarde7f0ad52004-07-14 17:28:59 +0000671 s = active_console;
thsaf3a9032007-07-11 23:14:59 +0000672 if (!s || (s->console_type == GRAPHIC_CONSOLE))
bellarde7f0ad52004-07-14 17:28:59 +0000673 return;
674
675 if (ydelta > 0) {
676 for(i = 0; i < ydelta; i++) {
677 if (s->y_displayed == s->y_base)
678 break;
679 if (++s->y_displayed == s->total_height)
680 s->y_displayed = 0;
681 }
682 } else {
683 ydelta = -ydelta;
684 i = s->backscroll_height;
685 if (i > s->total_height - s->height)
686 i = s->total_height - s->height;
687 y1 = s->y_base - i;
688 if (y1 < 0)
689 y1 += s->total_height;
690 for(i = 0; i < ydelta; i++) {
691 if (s->y_displayed == y1)
692 break;
693 if (--s->y_displayed < 0)
694 s->y_displayed = s->total_height - 1;
695 }
696 }
697 console_refresh(s);
698}
699
700static void console_put_lf(TextConsole *s)
701{
702 TextCell *c;
703 int x, y1;
704
bellarde7f0ad52004-07-14 17:28:59 +0000705 s->y++;
706 if (s->y >= s->height) {
707 s->y = s->height - 1;
pbrook6d6f7c22006-03-11 15:35:30 +0000708
bellarde7f0ad52004-07-14 17:28:59 +0000709 if (s->y_displayed == s->y_base) {
710 if (++s->y_displayed == s->total_height)
711 s->y_displayed = 0;
712 }
713 if (++s->y_base == s->total_height)
714 s->y_base = 0;
715 if (s->backscroll_height < s->total_height)
716 s->backscroll_height++;
717 y1 = (s->y_base + s->height - 1) % s->total_height;
718 c = &s->cells[y1 * s->width];
719 for(x = 0; x < s->width; x++) {
720 c->ch = ' ';
pbrook6d6f7c22006-03-11 15:35:30 +0000721 c->t_attrib = s->t_attrib_default;
bellarde7f0ad52004-07-14 17:28:59 +0000722 c++;
723 }
724 if (s == active_console && s->y_displayed == s->y_base) {
aliguori0e1f5a02008-11-24 19:29:13 +0000725 if (!ds_get_bits_per_pixel(s->ds)) {
balrog4d3b6f62008-02-10 16:33:14 +0000726 s->text_x[0] = 0;
727 s->text_y[0] = 0;
728 s->text_x[1] = s->width - 1;
729 s->text_y[1] = s->height - 1;
730 return;
731 }
732
ths5fafdf22007-09-16 21:08:06 +0000733 vga_bitblt(s->ds, 0, FONT_HEIGHT, 0, 0,
734 s->width * FONT_WIDTH,
bellarde7f0ad52004-07-14 17:28:59 +0000735 (s->height - 1) * FONT_HEIGHT);
736 vga_fill_rect(s->ds, 0, (s->height - 1) * FONT_HEIGHT,
ths5fafdf22007-09-16 21:08:06 +0000737 s->width * FONT_WIDTH, FONT_HEIGHT,
pbrook6d6f7c22006-03-11 15:35:30 +0000738 color_table[0][s->t_attrib_default.bgcol]);
pbrook14778c22009-01-21 03:02:52 +0000739 s->update_x0 = 0;
740 s->update_y0 = 0;
741 s->update_x1 = s->width * FONT_WIDTH;
742 s->update_y1 = s->height * FONT_HEIGHT;
bellarde7f0ad52004-07-14 17:28:59 +0000743 }
744 }
745}
746
pbrook6d6f7c22006-03-11 15:35:30 +0000747/* Set console attributes depending on the current escape codes.
748 * NOTE: I know this code is not very efficient (checking every color for it
749 * self) but it is more readable and better maintainable.
750 */
751static void console_handle_escape(TextConsole *s)
752{
753 int i;
754
pbrook6d6f7c22006-03-11 15:35:30 +0000755 for (i=0; i<s->nb_esc_params; i++) {
756 switch (s->esc_params[i]) {
757 case 0: /* reset all console attributes to default */
758 s->t_attrib = s->t_attrib_default;
759 break;
760 case 1:
761 s->t_attrib.bold = 1;
762 break;
763 case 4:
764 s->t_attrib.uline = 1;
765 break;
766 case 5:
767 s->t_attrib.blink = 1;
768 break;
769 case 7:
770 s->t_attrib.invers = 1;
771 break;
772 case 8:
773 s->t_attrib.unvisible = 1;
774 break;
775 case 22:
776 s->t_attrib.bold = 0;
777 break;
778 case 24:
779 s->t_attrib.uline = 0;
780 break;
781 case 25:
782 s->t_attrib.blink = 0;
783 break;
784 case 27:
785 s->t_attrib.invers = 0;
786 break;
787 case 28:
788 s->t_attrib.unvisible = 0;
789 break;
790 /* set foreground color */
791 case 30:
792 s->t_attrib.fgcol=COLOR_BLACK;
793 break;
794 case 31:
795 s->t_attrib.fgcol=COLOR_RED;
796 break;
797 case 32:
798 s->t_attrib.fgcol=COLOR_GREEN;
799 break;
800 case 33:
801 s->t_attrib.fgcol=COLOR_YELLOW;
802 break;
803 case 34:
804 s->t_attrib.fgcol=COLOR_BLUE;
805 break;
806 case 35:
807 s->t_attrib.fgcol=COLOR_MAGENTA;
808 break;
809 case 36:
810 s->t_attrib.fgcol=COLOR_CYAN;
811 break;
812 case 37:
813 s->t_attrib.fgcol=COLOR_WHITE;
814 break;
815 /* set background color */
816 case 40:
817 s->t_attrib.bgcol=COLOR_BLACK;
818 break;
819 case 41:
820 s->t_attrib.bgcol=COLOR_RED;
821 break;
822 case 42:
823 s->t_attrib.bgcol=COLOR_GREEN;
824 break;
825 case 43:
826 s->t_attrib.bgcol=COLOR_YELLOW;
827 break;
828 case 44:
829 s->t_attrib.bgcol=COLOR_BLUE;
830 break;
831 case 45:
832 s->t_attrib.bgcol=COLOR_MAGENTA;
833 break;
834 case 46:
835 s->t_attrib.bgcol=COLOR_CYAN;
836 break;
837 case 47:
838 s->t_attrib.bgcol=COLOR_WHITE;
839 break;
840 }
841 }
842}
843
thsadb47962007-01-16 23:02:36 +0000844static void console_clear_xy(TextConsole *s, int x, int y)
845{
846 int y1 = (s->y_base + y) % s->total_height;
847 TextCell *c = &s->cells[y1 * s->width + x];
848 c->ch = ' ';
849 c->t_attrib = s->t_attrib_default;
thsadb47962007-01-16 23:02:36 +0000850 update_xy(s, x, y);
851}
852
Ian Campbell3eea5492012-09-04 10:26:09 -0500853/* set cursor, checking bounds */
854static void set_cursor(TextConsole *s, int x, int y)
855{
856 if (x < 0) {
857 x = 0;
858 }
859 if (y < 0) {
860 y = 0;
861 }
862 if (y >= s->height) {
863 y = s->height - 1;
864 }
865 if (x >= s->width) {
866 x = s->width - 1;
867 }
868
869 s->x = x;
870 s->y = y;
871}
872
bellarde7f0ad52004-07-14 17:28:59 +0000873static void console_putchar(TextConsole *s, int ch)
874{
875 TextCell *c;
thsadb47962007-01-16 23:02:36 +0000876 int y1, i;
877 int x, y;
bellarde7f0ad52004-07-14 17:28:59 +0000878
879 switch(s->state) {
880 case TTY_STATE_NORM:
881 switch(ch) {
pbrook6d6f7c22006-03-11 15:35:30 +0000882 case '\r': /* carriage return */
bellarde7f0ad52004-07-14 17:28:59 +0000883 s->x = 0;
884 break;
pbrook6d6f7c22006-03-11 15:35:30 +0000885 case '\n': /* newline */
bellarde7f0ad52004-07-14 17:28:59 +0000886 console_put_lf(s);
887 break;
pbrook6d6f7c22006-03-11 15:35:30 +0000888 case '\b': /* backspace */
ths5fafdf22007-09-16 21:08:06 +0000889 if (s->x > 0)
bellarde15d7372006-06-25 16:26:29 +0000890 s->x--;
pbrook6d6f7c22006-03-11 15:35:30 +0000891 break;
892 case '\t': /* tabspace */
893 if (s->x + (8 - (s->x % 8)) > s->width) {
bellardbd468842006-07-14 20:24:31 +0000894 s->x = 0;
pbrook6d6f7c22006-03-11 15:35:30 +0000895 console_put_lf(s);
896 } else {
897 s->x = s->x + (8 - (s->x % 8));
898 }
899 break;
900 case '\a': /* alert aka. bell */
901 /* TODO: has to be implemented */
902 break;
thsadb47962007-01-16 23:02:36 +0000903 case 14:
904 /* SI (shift in), character set 0 (ignored) */
905 break;
906 case 15:
907 /* SO (shift out), character set 1 (ignored) */
908 break;
pbrook6d6f7c22006-03-11 15:35:30 +0000909 case 27: /* esc (introducing an escape sequence) */
bellarde7f0ad52004-07-14 17:28:59 +0000910 s->state = TTY_STATE_ESC;
911 break;
912 default:
thsed8276a2007-02-10 22:37:56 +0000913 if (s->x >= s->width) {
914 /* line wrap */
915 s->x = 0;
916 console_put_lf(s);
thsadb47962007-01-16 23:02:36 +0000917 }
bellarde7f0ad52004-07-14 17:28:59 +0000918 y1 = (s->y_base + s->y) % s->total_height;
919 c = &s->cells[y1 * s->width + s->x];
920 c->ch = ch;
pbrook6d6f7c22006-03-11 15:35:30 +0000921 c->t_attrib = s->t_attrib;
bellarde7f0ad52004-07-14 17:28:59 +0000922 update_xy(s, s->x, s->y);
923 s->x++;
bellarde7f0ad52004-07-14 17:28:59 +0000924 break;
925 }
926 break;
pbrook6d6f7c22006-03-11 15:35:30 +0000927 case TTY_STATE_ESC: /* check if it is a terminal escape sequence */
bellarde7f0ad52004-07-14 17:28:59 +0000928 if (ch == '[') {
929 for(i=0;i<MAX_ESC_PARAMS;i++)
930 s->esc_params[i] = 0;
931 s->nb_esc_params = 0;
932 s->state = TTY_STATE_CSI;
933 } else {
934 s->state = TTY_STATE_NORM;
935 }
936 break;
pbrook6d6f7c22006-03-11 15:35:30 +0000937 case TTY_STATE_CSI: /* handle escape sequence parameters */
bellarde7f0ad52004-07-14 17:28:59 +0000938 if (ch >= '0' && ch <= '9') {
939 if (s->nb_esc_params < MAX_ESC_PARAMS) {
ths5fafdf22007-09-16 21:08:06 +0000940 s->esc_params[s->nb_esc_params] =
bellarde7f0ad52004-07-14 17:28:59 +0000941 s->esc_params[s->nb_esc_params] * 10 + ch - '0';
942 }
943 } else {
Ian Campbell3eea5492012-09-04 10:26:09 -0500944 if (s->nb_esc_params < MAX_ESC_PARAMS)
945 s->nb_esc_params++;
bellarde7f0ad52004-07-14 17:28:59 +0000946 if (ch == ';')
947 break;
thsadb47962007-01-16 23:02:36 +0000948#ifdef DEBUG_CONSOLE
949 fprintf(stderr, "escape sequence CSI%d;%d%c, %d parameters\n",
950 s->esc_params[0], s->esc_params[1], ch, s->nb_esc_params);
951#endif
bellarde7f0ad52004-07-14 17:28:59 +0000952 s->state = TTY_STATE_NORM;
953 switch(ch) {
thsadb47962007-01-16 23:02:36 +0000954 case 'A':
955 /* move cursor up */
956 if (s->esc_params[0] == 0) {
957 s->esc_params[0] = 1;
958 }
Ian Campbell3eea5492012-09-04 10:26:09 -0500959 set_cursor(s, s->x, s->y - s->esc_params[0]);
bellarde7f0ad52004-07-14 17:28:59 +0000960 break;
thsadb47962007-01-16 23:02:36 +0000961 case 'B':
962 /* move cursor down */
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]);
thsadb47962007-01-16 23:02:36 +0000967 break;
968 case 'C':
969 /* move cursor right */
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->esc_params[0], s->y);
thsadb47962007-01-16 23:02:36 +0000974 break;
975 case 'D':
976 /* move cursor left */
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 'G':
983 /* move cursor to column */
Ian Campbell3eea5492012-09-04 10:26:09 -0500984 set_cursor(s, s->esc_params[0] - 1, s->y);
thsadb47962007-01-16 23:02:36 +0000985 break;
986 case 'f':
987 case 'H':
988 /* move cursor to row, column */
Ian Campbell3eea5492012-09-04 10:26:09 -0500989 set_cursor(s, s->esc_params[1] - 1, s->esc_params[0] - 1);
thsadb47962007-01-16 23:02:36 +0000990 break;
991 case 'J':
992 switch (s->esc_params[0]) {
993 case 0:
994 /* clear to end of screen */
995 for (y = s->y; y < s->height; y++) {
996 for (x = 0; x < s->width; x++) {
997 if (y == s->y && x < s->x) {
998 continue;
999 }
1000 console_clear_xy(s, x, y);
1001 }
1002 }
1003 break;
1004 case 1:
1005 /* clear from beginning of screen */
1006 for (y = 0; y <= s->y; y++) {
1007 for (x = 0; x < s->width; x++) {
1008 if (y == s->y && x > s->x) {
1009 break;
1010 }
1011 console_clear_xy(s, x, y);
1012 }
1013 }
1014 break;
1015 case 2:
1016 /* clear entire screen */
1017 for (y = 0; y <= s->height; y++) {
1018 for (x = 0; x < s->width; x++) {
1019 console_clear_xy(s, x, y);
1020 }
1021 }
Markus Armbrusterf94a9502011-11-22 11:59:06 +01001022 break;
thsadb47962007-01-16 23:02:36 +00001023 }
Markus Armbruster95d8f9f2011-11-22 11:59:07 +01001024 break;
thsadb47962007-01-16 23:02:36 +00001025 case 'K':
1026 switch (s->esc_params[0]) {
1027 case 0:
Markus Armbrusterf94a9502011-11-22 11:59:06 +01001028 /* clear to eol */
1029 for(x = s->x; x < s->width; x++) {
thsadb47962007-01-16 23:02:36 +00001030 console_clear_xy(s, x, s->y);
Markus Armbrusterf94a9502011-11-22 11:59:06 +01001031 }
1032 break;
thsadb47962007-01-16 23:02:36 +00001033 case 1:
1034 /* clear from beginning of line */
1035 for (x = 0; x <= s->x; x++) {
1036 console_clear_xy(s, x, s->y);
1037 }
1038 break;
1039 case 2:
1040 /* clear entire line */
1041 for(x = 0; x < s->width; x++) {
1042 console_clear_xy(s, x, s->y);
1043 }
Markus Armbrusterf94a9502011-11-22 11:59:06 +01001044 break;
1045 }
thsadb47962007-01-16 23:02:36 +00001046 break;
1047 case 'm':
Markus Armbrusterf94a9502011-11-22 11:59:06 +01001048 console_handle_escape(s);
1049 break;
thsadb47962007-01-16 23:02:36 +00001050 case 'n':
1051 /* report cursor position */
1052 /* TODO: send ESC[row;colR */
1053 break;
1054 case 's':
1055 /* save cursor position */
1056 s->x_saved = s->x;
1057 s->y_saved = s->y;
1058 break;
1059 case 'u':
1060 /* restore cursor position */
1061 s->x = s->x_saved;
1062 s->y = s->y_saved;
1063 break;
1064 default:
1065#ifdef DEBUG_CONSOLE
1066 fprintf(stderr, "unhandled escape character '%c'\n", ch);
1067#endif
1068 break;
1069 }
1070 break;
bellarde7f0ad52004-07-14 17:28:59 +00001071 }
1072 }
1073}
1074
1075void console_select(unsigned int index)
1076{
1077 TextConsole *s;
pbrook6d6f7c22006-03-11 15:35:30 +00001078
bellarde7f0ad52004-07-14 17:28:59 +00001079 if (index >= MAX_CONSOLES)
1080 return;
Stefan Hajnoczi358664c2010-09-20 14:11:19 +01001081 if (active_console) {
1082 active_console->g_width = ds_get_width(active_console->ds);
1083 active_console->g_height = ds_get_height(active_console->ds);
1084 }
bellarde7f0ad52004-07-14 17:28:59 +00001085 s = consoles[index];
1086 if (s) {
aliguori7d957bd2009-01-15 22:14:11 +00001087 DisplayState *ds = s->ds;
Jan Kiszkabf1bed82012-07-10 22:00:55 +02001088
Stefan Weil8bd6b062012-08-17 15:50:44 +02001089 if (active_console && active_console->cursor_timer) {
Jan Kiszkabf1bed82012-07-10 22:00:55 +02001090 qemu_del_timer(active_console->cursor_timer);
1091 }
bellarde7f0ad52004-07-14 17:28:59 +00001092 active_console = s;
aliguori68f00992009-01-21 18:59:12 +00001093 if (ds_get_bits_per_pixel(s->ds)) {
aliguori7b5d76d2009-03-13 15:02:13 +00001094 ds->surface = qemu_resize_displaysurface(ds, s->g_width, s->g_height);
aliguori68f00992009-01-21 18:59:12 +00001095 } else {
1096 s->ds->surface->width = s->width;
1097 s->ds->surface->height = s->height;
1098 }
Jan Kiszkabf1bed82012-07-10 22:00:55 +02001099 if (s->cursor_timer) {
1100 qemu_mod_timer(s->cursor_timer,
1101 qemu_get_clock_ms(rt_clock) + CONSOLE_CURSOR_PERIOD / 2);
1102 }
aliguori7d957bd2009-01-15 22:14:11 +00001103 dpy_resize(s->ds);
balrog4d3b6f62008-02-10 16:33:14 +00001104 vga_hw_invalidate();
bellarde7f0ad52004-07-14 17:28:59 +00001105 }
1106}
1107
1108static int console_puts(CharDriverState *chr, const uint8_t *buf, int len)
1109{
1110 TextConsole *s = chr->opaque;
1111 int i;
1112
pbrook14778c22009-01-21 03:02:52 +00001113 s->update_x0 = s->width * FONT_WIDTH;
1114 s->update_y0 = s->height * FONT_HEIGHT;
1115 s->update_x1 = 0;
1116 s->update_y1 = 0;
bellarde7f0ad52004-07-14 17:28:59 +00001117 console_show_cursor(s, 0);
1118 for(i = 0; i < len; i++) {
1119 console_putchar(s, buf[i]);
1120 }
1121 console_show_cursor(s, 1);
pbrook14778c22009-01-21 03:02:52 +00001122 if (ds_get_bits_per_pixel(s->ds) && s->update_x0 < s->update_x1) {
1123 dpy_update(s->ds, s->update_x0, s->update_y0,
1124 s->update_x1 - s->update_x0,
1125 s->update_y1 - s->update_y0);
1126 }
bellarde7f0ad52004-07-14 17:28:59 +00001127 return len;
1128}
1129
bellarde15d7372006-06-25 16:26:29 +00001130static void kbd_send_chars(void *opaque)
1131{
1132 TextConsole *s = opaque;
1133 int len;
1134 uint8_t buf[16];
ths3b46e622007-09-17 08:09:54 +00001135
Anthony Liguori909cda12011-08-15 11:17:31 -05001136 len = qemu_chr_be_can_write(s->chr);
bellarde15d7372006-06-25 16:26:29 +00001137 if (len > s->out_fifo.count)
1138 len = s->out_fifo.count;
1139 if (len > 0) {
1140 if (len > sizeof(buf))
1141 len = sizeof(buf);
1142 qemu_fifo_read(&s->out_fifo, buf, len);
Anthony Liguorifa5efcc2011-08-15 11:17:30 -05001143 qemu_chr_be_write(s->chr, buf, len);
bellarde15d7372006-06-25 16:26:29 +00001144 }
1145 /* characters are pending: we send them a bit later (XXX:
1146 horrible, should change char device API) */
1147 if (s->out_fifo.count > 0) {
Paolo Bonzini7bd427d2011-03-11 16:47:48 +01001148 qemu_mod_timer(s->kbd_timer, qemu_get_clock_ms(rt_clock) + 1);
bellarde15d7372006-06-25 16:26:29 +00001149 }
1150}
1151
bellarde7f0ad52004-07-14 17:28:59 +00001152/* called when an ascii key is pressed */
1153void kbd_put_keysym(int keysym)
1154{
1155 TextConsole *s;
1156 uint8_t buf[16], *q;
1157 int c;
1158
1159 s = active_console;
thsaf3a9032007-07-11 23:14:59 +00001160 if (!s || (s->console_type == GRAPHIC_CONSOLE))
bellarde7f0ad52004-07-14 17:28:59 +00001161 return;
1162
1163 switch(keysym) {
1164 case QEMU_KEY_CTRL_UP:
1165 console_scroll(-1);
1166 break;
1167 case QEMU_KEY_CTRL_DOWN:
1168 console_scroll(1);
1169 break;
1170 case QEMU_KEY_CTRL_PAGEUP:
1171 console_scroll(-10);
1172 break;
1173 case QEMU_KEY_CTRL_PAGEDOWN:
1174 console_scroll(10);
1175 break;
1176 default:
bellarde15d7372006-06-25 16:26:29 +00001177 /* convert the QEMU keysym to VT100 key string */
1178 q = buf;
1179 if (keysym >= 0xe100 && keysym <= 0xe11f) {
1180 *q++ = '\033';
1181 *q++ = '[';
1182 c = keysym - 0xe100;
1183 if (c >= 10)
1184 *q++ = '0' + (c / 10);
1185 *q++ = '0' + (c % 10);
1186 *q++ = '~';
1187 } else if (keysym >= 0xe120 && keysym <= 0xe17f) {
1188 *q++ = '\033';
1189 *q++ = '[';
1190 *q++ = keysym & 0xff;
Paolo Bonzini41048332010-12-23 13:42:52 +01001191 } else if (s->echo && (keysym == '\r' || keysym == '\n')) {
1192 console_puts(s->chr, (const uint8_t *) "\r", 1);
1193 *q++ = '\n';
bellarde15d7372006-06-25 16:26:29 +00001194 } else {
Paolo Bonzini41048332010-12-23 13:42:52 +01001195 *q++ = keysym;
1196 }
1197 if (s->echo) {
1198 console_puts(s->chr, buf, q - buf);
bellarde15d7372006-06-25 16:26:29 +00001199 }
pbrooke5b0bc42007-01-27 23:46:43 +00001200 if (s->chr->chr_read) {
bellarde15d7372006-06-25 16:26:29 +00001201 qemu_fifo_write(&s->out_fifo, buf, q - buf);
1202 kbd_send_chars(s);
bellarde7f0ad52004-07-14 17:28:59 +00001203 }
1204 break;
1205 }
1206}
1207
balrog4d3b6f62008-02-10 16:33:14 +00001208static void text_console_invalidate(void *opaque)
1209{
1210 TextConsole *s = (TextConsole *) opaque;
aliguori68f00992009-01-21 18:59:12 +00001211 if (!ds_get_bits_per_pixel(s->ds) && s->console_type == TEXT_CONSOLE) {
1212 s->g_width = ds_get_width(s->ds);
1213 s->g_height = ds_get_height(s->ds);
1214 text_console_resize(s);
1215 }
balrog4d3b6f62008-02-10 16:33:14 +00001216 console_refresh(s);
1217}
1218
Anthony Liguoric227f092009-10-01 16:12:16 -05001219static void text_console_update(void *opaque, console_ch_t *chardata)
balrog4d3b6f62008-02-10 16:33:14 +00001220{
1221 TextConsole *s = (TextConsole *) opaque;
1222 int i, j, src;
1223
1224 if (s->text_x[0] <= s->text_x[1]) {
1225 src = (s->y_base + s->text_y[0]) * s->width;
1226 chardata += s->text_y[0] * s->width;
1227 for (i = s->text_y[0]; i <= s->text_y[1]; i ++)
1228 for (j = 0; j < s->width; j ++, src ++)
1229 console_write_ch(chardata ++, s->cells[src].ch |
1230 (s->cells[src].t_attrib.fgcol << 12) |
1231 (s->cells[src].t_attrib.bgcol << 8) |
1232 (s->cells[src].t_attrib.bold << 21));
1233 dpy_update(s->ds, s->text_x[0], s->text_y[0],
1234 s->text_x[1] - s->text_x[0], i - s->text_y[0]);
1235 s->text_x[0] = s->width;
1236 s->text_y[0] = s->height;
1237 s->text_x[1] = 0;
1238 s->text_y[1] = 0;
1239 }
1240 if (s->cursor_invalidate) {
1241 dpy_cursor(s->ds, s->x, s->y);
1242 s->cursor_invalidate = 0;
1243 }
1244}
1245
aliguori42aa98e2009-01-16 21:01:48 +00001246static TextConsole *get_graphic_console(DisplayState *ds)
blueswir1a147d622009-01-16 19:41:04 +00001247{
aliguori3023f332009-01-16 19:04:14 +00001248 int i;
1249 TextConsole *s;
1250 for (i = 0; i < nb_consoles; i++) {
1251 s = consoles[i];
aliguori42aa98e2009-01-16 21:01:48 +00001252 if (s->console_type == GRAPHIC_CONSOLE && s->ds == ds)
aliguori3023f332009-01-16 19:04:14 +00001253 return s;
1254 }
1255 return NULL;
1256}
1257
Anthony Liguoric227f092009-10-01 16:12:16 -05001258static TextConsole *new_console(DisplayState *ds, console_type_t console_type)
bellarde7f0ad52004-07-14 17:28:59 +00001259{
1260 TextConsole *s;
pbrook95219892006-04-09 01:06:34 +00001261 int i;
bellarde7f0ad52004-07-14 17:28:59 +00001262
1263 if (nb_consoles >= MAX_CONSOLES)
1264 return NULL;
Anthony Liguori7267c092011-08-20 22:09:37 -05001265 s = g_malloc0(sizeof(TextConsole));
thsaf3a9032007-07-11 23:14:59 +00001266 if (!active_console || ((active_console->console_type != GRAPHIC_CONSOLE) &&
1267 (console_type == GRAPHIC_CONSOLE))) {
bellarde7f0ad52004-07-14 17:28:59 +00001268 active_console = s;
thsaf3a9032007-07-11 23:14:59 +00001269 }
bellarde7f0ad52004-07-14 17:28:59 +00001270 s->ds = ds;
thsaf3a9032007-07-11 23:14:59 +00001271 s->console_type = console_type;
1272 if (console_type != GRAPHIC_CONSOLE) {
Jan Kiszkaf81bdef2011-09-16 00:48:07 +02001273 s->index = nb_consoles;
pbrook95219892006-04-09 01:06:34 +00001274 consoles[nb_consoles++] = s;
1275 } else {
1276 /* HACK: Put graphical consoles before text consoles. */
1277 for (i = nb_consoles; i > 0; i--) {
thsaf3a9032007-07-11 23:14:59 +00001278 if (consoles[i - 1]->console_type == GRAPHIC_CONSOLE)
pbrook95219892006-04-09 01:06:34 +00001279 break;
1280 consoles[i] = consoles[i - 1];
Jan Kiszkaf81bdef2011-09-16 00:48:07 +02001281 consoles[i]->index = i;
pbrook95219892006-04-09 01:06:34 +00001282 }
Jan Kiszkaf81bdef2011-09-16 00:48:07 +02001283 s->index = i;
pbrook95219892006-04-09 01:06:34 +00001284 consoles[i] = s;
aliguori3023f332009-01-16 19:04:14 +00001285 nb_consoles++;
pbrook95219892006-04-09 01:06:34 +00001286 }
bellarde7f0ad52004-07-14 17:28:59 +00001287 return s;
1288}
1289
Paolo Bonzini98b50082010-02-11 00:29:57 +01001290static DisplaySurface* defaultallocator_create_displaysurface(int width, int height)
1291{
Anthony Liguori7267c092011-08-20 22:09:37 -05001292 DisplaySurface *surface = (DisplaySurface*) g_malloc0(sizeof(DisplaySurface));
Paolo Bonzini98b50082010-02-11 00:29:57 +01001293
Jes Sorensenffe8b822011-03-16 13:33:30 +01001294 int linesize = width * 4;
1295 qemu_alloc_display(surface, width, height, linesize,
1296 qemu_default_pixelformat(32), 0);
Paolo Bonzini98b50082010-02-11 00:29:57 +01001297 return surface;
1298}
1299
1300static DisplaySurface* defaultallocator_resize_displaysurface(DisplaySurface *surface,
1301 int width, int height)
1302{
Jes Sorensenffe8b822011-03-16 13:33:30 +01001303 int linesize = width * 4;
1304 qemu_alloc_display(surface, width, height, linesize,
1305 qemu_default_pixelformat(32), 0);
1306 return surface;
1307}
1308
1309void qemu_alloc_display(DisplaySurface *surface, int width, int height,
1310 int linesize, PixelFormat pf, int newflags)
1311{
1312 void *data;
Paolo Bonzini98b50082010-02-11 00:29:57 +01001313 surface->width = width;
1314 surface->height = height;
Jes Sorensenffe8b822011-03-16 13:33:30 +01001315 surface->linesize = linesize;
1316 surface->pf = pf;
1317 if (surface->flags & QEMU_ALLOCATED_FLAG) {
Anthony Liguori7267c092011-08-20 22:09:37 -05001318 data = g_realloc(surface->data,
Jes Sorensenffe8b822011-03-16 13:33:30 +01001319 surface->linesize * surface->height);
1320 } else {
Anthony Liguori7267c092011-08-20 22:09:37 -05001321 data = g_malloc(surface->linesize * surface->height);
Jes Sorensenffe8b822011-03-16 13:33:30 +01001322 }
1323 surface->data = (uint8_t *)data;
1324 surface->flags = newflags | QEMU_ALLOCATED_FLAG;
Paolo Bonzini98b50082010-02-11 00:29:57 +01001325#ifdef HOST_WORDS_BIGENDIAN
Jes Sorensenffe8b822011-03-16 13:33:30 +01001326 surface->flags |= QEMU_BIG_ENDIAN_FLAG;
Paolo Bonzini98b50082010-02-11 00:29:57 +01001327#endif
Paolo Bonzini98b50082010-02-11 00:29:57 +01001328}
1329
1330DisplaySurface* qemu_create_displaysurface_from(int width, int height, int bpp,
1331 int linesize, uint8_t *data)
1332{
Anthony Liguori7267c092011-08-20 22:09:37 -05001333 DisplaySurface *surface = (DisplaySurface*) g_malloc0(sizeof(DisplaySurface));
Paolo Bonzini98b50082010-02-11 00:29:57 +01001334
1335 surface->width = width;
1336 surface->height = height;
1337 surface->linesize = linesize;
1338 surface->pf = qemu_default_pixelformat(bpp);
1339#ifdef HOST_WORDS_BIGENDIAN
1340 surface->flags = QEMU_BIG_ENDIAN_FLAG;
1341#endif
1342 surface->data = data;
1343
1344 return surface;
1345}
1346
1347static void defaultallocator_free_displaysurface(DisplaySurface *surface)
1348{
1349 if (surface == NULL)
1350 return;
1351 if (surface->flags & QEMU_ALLOCATED_FLAG)
Anthony Liguori7267c092011-08-20 22:09:37 -05001352 g_free(surface->data);
1353 g_free(surface);
Paolo Bonzini98b50082010-02-11 00:29:57 +01001354}
1355
1356static struct DisplayAllocator default_allocator = {
1357 defaultallocator_create_displaysurface,
1358 defaultallocator_resize_displaysurface,
1359 defaultallocator_free_displaysurface
1360};
1361
1362static void dumb_display_init(void)
1363{
Anthony Liguori7267c092011-08-20 22:09:37 -05001364 DisplayState *ds = g_malloc0(sizeof(DisplayState));
Jan Kiszka18026512011-06-19 11:53:02 +02001365 int width = 640;
1366 int height = 480;
1367
Paolo Bonzini98b50082010-02-11 00:29:57 +01001368 ds->allocator = &default_allocator;
Jan Kiszka18026512011-06-19 11:53:02 +02001369 if (is_fixedsize_console()) {
1370 width = active_console->g_width;
1371 height = active_console->g_height;
1372 }
1373 ds->surface = qemu_create_displaysurface(ds, width, height);
Paolo Bonzini98b50082010-02-11 00:29:57 +01001374 register_displaystate(ds);
1375}
1376
1377/***********************************************************/
1378/* register display */
1379
1380void register_displaystate(DisplayState *ds)
1381{
1382 DisplayState **s;
1383 s = &display_state;
1384 while (*s != NULL)
1385 s = &(*s)->next;
1386 ds->next = NULL;
1387 *s = ds;
1388}
1389
1390DisplayState *get_displaystate(void)
1391{
1392 if (!display_state) {
1393 dumb_display_init ();
1394 }
1395 return display_state;
1396}
1397
1398DisplayAllocator *register_displayallocator(DisplayState *ds, DisplayAllocator *da)
1399{
1400 if(ds->allocator == &default_allocator) {
1401 DisplaySurface *surf;
1402 surf = da->create_displaysurface(ds_get_width(ds), ds_get_height(ds));
1403 defaultallocator_free_displaysurface(ds->surface);
1404 ds->surface = surf;
1405 ds->allocator = da;
1406 }
1407 return ds->allocator;
1408}
1409
aliguori3023f332009-01-16 19:04:14 +00001410DisplayState *graphic_console_init(vga_hw_update_ptr update,
1411 vga_hw_invalidate_ptr invalidate,
1412 vga_hw_screen_dump_ptr screen_dump,
1413 vga_hw_text_update_ptr text_update,
1414 void *opaque)
bellarde7f0ad52004-07-14 17:28:59 +00001415{
pbrook95219892006-04-09 01:06:34 +00001416 TextConsole *s;
aliguori3023f332009-01-16 19:04:14 +00001417 DisplayState *ds;
aurel32f0f2f972009-01-16 21:13:49 +00001418
Anthony Liguori7267c092011-08-20 22:09:37 -05001419 ds = (DisplayState *) g_malloc0(sizeof(DisplayState));
aliguori7b5d76d2009-03-13 15:02:13 +00001420 ds->allocator = &default_allocator;
1421 ds->surface = qemu_create_displaysurface(ds, 640, 480);
pbrook95219892006-04-09 01:06:34 +00001422
thsaf3a9032007-07-11 23:14:59 +00001423 s = new_console(ds, GRAPHIC_CONSOLE);
aliguori3023f332009-01-16 19:04:14 +00001424 if (s == NULL) {
aliguori7b5d76d2009-03-13 15:02:13 +00001425 qemu_free_displaysurface(ds);
Anthony Liguori7267c092011-08-20 22:09:37 -05001426 g_free(ds);
aliguori3023f332009-01-16 19:04:14 +00001427 return NULL;
1428 }
pbrook95219892006-04-09 01:06:34 +00001429 s->hw_update = update;
1430 s->hw_invalidate = invalidate;
1431 s->hw_screen_dump = screen_dump;
balrog4d3b6f62008-02-10 16:33:14 +00001432 s->hw_text_update = text_update;
pbrook95219892006-04-09 01:06:34 +00001433 s->hw = opaque;
aliguori3023f332009-01-16 19:04:14 +00001434
aurel32f0f2f972009-01-16 21:13:49 +00001435 register_displaystate(ds);
aliguori3023f332009-01-16 19:04:14 +00001436 return ds;
pbrook95219892006-04-09 01:06:34 +00001437}
1438
1439int is_graphic_console(void)
1440{
balrog4d3b6f62008-02-10 16:33:14 +00001441 return active_console && active_console->console_type == GRAPHIC_CONSOLE;
bellarde7f0ad52004-07-14 17:28:59 +00001442}
1443
balrogc21bbcf2008-09-24 03:32:33 +00001444int is_fixedsize_console(void)
1445{
1446 return active_console && active_console->console_type != TEXT_CONSOLE;
1447}
1448
balroga528b802007-10-30 22:38:53 +00001449void console_color_init(DisplayState *ds)
1450{
1451 int i, j;
1452 for (j = 0; j < 2; j++) {
1453 for (i = 0; i < 8; i++) {
aurel32f0f2f972009-01-16 21:13:49 +00001454 color_table[j][i] = col_expand(ds,
balroga528b802007-10-30 22:38:53 +00001455 vga_get_color(ds, color_table_rgb[j][i]));
1456 }
1457 }
1458}
1459
Paolo Bonzini41048332010-12-23 13:42:52 +01001460static void text_console_set_echo(CharDriverState *chr, bool echo)
1461{
1462 TextConsole *s = chr->opaque;
1463
1464 s->echo = echo;
1465}
1466
Jan Kiszkabf1bed82012-07-10 22:00:55 +02001467static void text_console_update_cursor(void *opaque)
1468{
1469 TextConsole *s = opaque;
1470
1471 s->cursor_visible_phase = !s->cursor_visible_phase;
1472 vga_hw_invalidate();
1473 qemu_mod_timer(s->cursor_timer,
1474 qemu_get_clock_ms(rt_clock) + CONSOLE_CURSOR_PERIOD / 2);
1475}
1476
Paolo Bonzini44b37b92010-12-23 13:42:53 +01001477static void text_console_do_init(CharDriverState *chr, DisplayState *ds)
bellarde7f0ad52004-07-14 17:28:59 +00001478{
bellarde7f0ad52004-07-14 17:28:59 +00001479 TextConsole *s;
bellarde7f0ad52004-07-14 17:28:59 +00001480 static int color_inited;
pbrook6d6f7c22006-03-11 15:35:30 +00001481
Paolo Bonzini491e1142010-12-23 13:42:51 +01001482 s = chr->opaque;
Gerd Hoffmann6ea314d2009-09-10 10:58:49 +02001483
bellarde7f0ad52004-07-14 17:28:59 +00001484 chr->chr_write = console_puts;
bellard6fcfafb2004-08-01 21:48:30 +00001485
bellarde15d7372006-06-25 16:26:29 +00001486 s->out_fifo.buf = s->out_fifo_buf;
1487 s->out_fifo.buf_size = sizeof(s->out_fifo_buf);
Paolo Bonzini7bd427d2011-03-11 16:47:48 +01001488 s->kbd_timer = qemu_new_timer_ms(rt_clock, kbd_send_chars, s);
aliguori3023f332009-01-16 19:04:14 +00001489 s->ds = ds;
ths3b46e622007-09-17 08:09:54 +00001490
bellarde7f0ad52004-07-14 17:28:59 +00001491 if (!color_inited) {
1492 color_inited = 1;
balroga528b802007-10-30 22:38:53 +00001493 console_color_init(s->ds);
bellarde7f0ad52004-07-14 17:28:59 +00001494 }
1495 s->y_displayed = 0;
1496 s->y_base = 0;
1497 s->total_height = DEFAULT_BACKSCROLL;
1498 s->x = 0;
1499 s->y = 0;
Paolo Bonzini491e1142010-12-23 13:42:51 +01001500 if (s->console_type == TEXT_CONSOLE) {
1501 s->g_width = ds_get_width(s->ds);
1502 s->g_height = ds_get_height(s->ds);
1503 }
pbrook6d6f7c22006-03-11 15:35:30 +00001504
Jan Kiszkabf1bed82012-07-10 22:00:55 +02001505 s->cursor_timer =
1506 qemu_new_timer_ms(rt_clock, text_console_update_cursor, s);
1507
balrog4d3b6f62008-02-10 16:33:14 +00001508 s->hw_invalidate = text_console_invalidate;
1509 s->hw_text_update = text_console_update;
1510 s->hw = s;
1511
pbrook6d6f7c22006-03-11 15:35:30 +00001512 /* Set text attribute defaults */
1513 s->t_attrib_default.bold = 0;
1514 s->t_attrib_default.uline = 0;
1515 s->t_attrib_default.blink = 0;
1516 s->t_attrib_default.invers = 0;
1517 s->t_attrib_default.unvisible = 0;
1518 s->t_attrib_default.fgcol = COLOR_WHITE;
1519 s->t_attrib_default.bgcol = COLOR_BLACK;
pbrook6d6f7c22006-03-11 15:35:30 +00001520 /* set current text attributes to default */
1521 s->t_attrib = s->t_attrib_default;
bellarde7f0ad52004-07-14 17:28:59 +00001522 text_console_resize(s);
1523
Gerd Hoffmann51bfa4d2009-12-08 13:11:39 +01001524 if (chr->label) {
1525 char msg[128];
1526 int len;
1527
Gerd Hoffmann735ba582009-12-08 13:11:40 +01001528 s->t_attrib.bgcol = COLOR_BLUE;
Gerd Hoffmann51bfa4d2009-12-08 13:11:39 +01001529 len = snprintf(msg, sizeof(msg), "%s console\r\n", chr->label);
1530 console_puts(chr, (uint8_t*)msg, len);
Gerd Hoffmann735ba582009-12-08 13:11:40 +01001531 s->t_attrib = s->t_attrib_default;
Gerd Hoffmann51bfa4d2009-12-08 13:11:39 +01001532 }
1533
Amit Shah127338e2009-11-03 19:59:56 +05301534 qemu_chr_generic_open(chr);
aurel32ceecf1d2009-01-18 14:08:04 +00001535 if (chr->init)
1536 chr->init(chr);
bellarde7f0ad52004-07-14 17:28:59 +00001537}
pbrookc60e08d2008-07-01 16:24:38 +00001538
Markus Armbruster1f514702012-02-07 15:09:08 +01001539CharDriverState *text_console_init(QemuOpts *opts)
aliguori2796dae2009-01-16 20:23:27 +00001540{
1541 CharDriverState *chr;
Paolo Bonzini491e1142010-12-23 13:42:51 +01001542 TextConsole *s;
1543 unsigned width;
1544 unsigned height;
aliguori2796dae2009-01-16 20:23:27 +00001545
Anthony Liguori7267c092011-08-20 22:09:37 -05001546 chr = g_malloc0(sizeof(CharDriverState));
aliguori2796dae2009-01-16 20:23:27 +00001547
Paolo Bonzini491e1142010-12-23 13:42:51 +01001548 width = qemu_opt_get_number(opts, "width", 0);
1549 if (width == 0)
1550 width = qemu_opt_get_number(opts, "cols", 0) * FONT_WIDTH;
1551
1552 height = qemu_opt_get_number(opts, "height", 0);
1553 if (height == 0)
1554 height = qemu_opt_get_number(opts, "rows", 0) * FONT_HEIGHT;
1555
1556 if (width == 0 || height == 0) {
1557 s = new_console(NULL, TEXT_CONSOLE);
1558 } else {
1559 s = new_console(NULL, TEXT_CONSOLE_FIXED_SIZE);
1560 }
1561
1562 if (!s) {
Stefan Weil5354d082011-10-02 18:53:09 +02001563 g_free(chr);
Markus Armbruster1f514702012-02-07 15:09:08 +01001564 return NULL;
Paolo Bonzini491e1142010-12-23 13:42:51 +01001565 }
1566
1567 s->chr = chr;
1568 s->g_width = width;
1569 s->g_height = height;
1570 chr->opaque = s;
Paolo Bonzini41048332010-12-23 13:42:52 +01001571 chr->chr_set_echo = text_console_set_echo;
Markus Armbruster1f514702012-02-07 15:09:08 +01001572 return chr;
aliguori2796dae2009-01-16 20:23:27 +00001573}
1574
1575void text_consoles_set_display(DisplayState *ds)
1576{
1577 int i;
1578
Markus Armbruster8811e1e2012-02-07 15:09:21 +01001579 for (i = 0; i < nb_consoles; i++) {
1580 if (consoles[i]->console_type != GRAPHIC_CONSOLE) {
1581 text_console_do_init(consoles[i]->chr, ds);
1582 }
aliguori2796dae2009-01-16 20:23:27 +00001583 }
aliguori2796dae2009-01-16 20:23:27 +00001584}
1585
aliguori3023f332009-01-16 19:04:14 +00001586void qemu_console_resize(DisplayState *ds, int width, int height)
pbrookc60e08d2008-07-01 16:24:38 +00001587{
aliguori42aa98e2009-01-16 21:01:48 +00001588 TextConsole *s = get_graphic_console(ds);
aliguorif497f142009-01-21 19:18:00 +00001589 if (!s) return;
1590
aliguori3023f332009-01-16 19:04:14 +00001591 s->g_width = width;
1592 s->g_height = height;
1593 if (is_graphic_console()) {
aliguori7b5d76d2009-03-13 15:02:13 +00001594 ds->surface = qemu_resize_displaysurface(ds, width, height);
aliguori3023f332009-01-16 19:04:14 +00001595 dpy_resize(ds);
pbrookc60e08d2008-07-01 16:24:38 +00001596 }
1597}
balrog38334f72008-09-24 02:21:24 +00001598
aliguori3023f332009-01-16 19:04:14 +00001599void qemu_console_copy(DisplayState *ds, int src_x, int src_y,
1600 int dst_x, int dst_y, int w, int h)
balrogc21bbcf2008-09-24 03:32:33 +00001601{
aliguori3023f332009-01-16 19:04:14 +00001602 if (is_graphic_console()) {
1603 dpy_copy(ds, src_x, src_y, dst_x, dst_y, w, h);
balrog38334f72008-09-24 02:21:24 +00001604 }
1605}
aliguori7d957bd2009-01-15 22:14:11 +00001606
malc0da2ea12009-01-23 19:56:19 +00001607PixelFormat qemu_different_endianness_pixelformat(int bpp)
aliguori7d957bd2009-01-15 22:14:11 +00001608{
1609 PixelFormat pf;
1610
1611 memset(&pf, 0x00, sizeof(PixelFormat));
1612
1613 pf.bits_per_pixel = bpp;
1614 pf.bytes_per_pixel = bpp / 8;
1615 pf.depth = bpp == 32 ? 24 : bpp;
1616
1617 switch (bpp) {
malc0da2ea12009-01-23 19:56:19 +00001618 case 24:
1619 pf.rmask = 0x000000FF;
1620 pf.gmask = 0x0000FF00;
1621 pf.bmask = 0x00FF0000;
1622 pf.rmax = 255;
1623 pf.gmax = 255;
1624 pf.bmax = 255;
1625 pf.rshift = 0;
1626 pf.gshift = 8;
1627 pf.bshift = 16;
aliguori90a1e3c2009-01-26 15:37:30 +00001628 pf.rbits = 8;
1629 pf.gbits = 8;
1630 pf.bbits = 8;
aliguori7d957bd2009-01-15 22:14:11 +00001631 break;
malc0da2ea12009-01-23 19:56:19 +00001632 case 32:
1633 pf.rmask = 0x0000FF00;
1634 pf.gmask = 0x00FF0000;
1635 pf.bmask = 0xFF000000;
1636 pf.amask = 0x00000000;
1637 pf.amax = 255;
1638 pf.rmax = 255;
1639 pf.gmax = 255;
1640 pf.bmax = 255;
1641 pf.ashift = 0;
1642 pf.rshift = 8;
1643 pf.gshift = 16;
1644 pf.bshift = 24;
aliguori90a1e3c2009-01-26 15:37:30 +00001645 pf.rbits = 8;
1646 pf.gbits = 8;
1647 pf.bbits = 8;
1648 pf.abits = 8;
malc0da2ea12009-01-23 19:56:19 +00001649 break;
1650 default:
1651 break;
1652 }
1653 return pf;
1654}
1655
1656PixelFormat qemu_default_pixelformat(int bpp)
1657{
1658 PixelFormat pf;
1659
1660 memset(&pf, 0x00, sizeof(PixelFormat));
1661
1662 pf.bits_per_pixel = bpp;
1663 pf.bytes_per_pixel = bpp / 8;
1664 pf.depth = bpp == 32 ? 24 : bpp;
1665
1666 switch (bpp) {
Gerd Hoffmannb6278082010-05-21 11:59:14 +02001667 case 15:
1668 pf.bits_per_pixel = 16;
1669 pf.bytes_per_pixel = 2;
1670 pf.rmask = 0x00007c00;
1671 pf.gmask = 0x000003E0;
1672 pf.bmask = 0x0000001F;
1673 pf.rmax = 31;
1674 pf.gmax = 31;
1675 pf.bmax = 31;
1676 pf.rshift = 10;
1677 pf.gshift = 5;
1678 pf.bshift = 0;
1679 pf.rbits = 5;
1680 pf.gbits = 5;
1681 pf.bbits = 5;
1682 break;
aliguori7d957bd2009-01-15 22:14:11 +00001683 case 16:
1684 pf.rmask = 0x0000F800;
1685 pf.gmask = 0x000007E0;
1686 pf.bmask = 0x0000001F;
1687 pf.rmax = 31;
1688 pf.gmax = 63;
1689 pf.bmax = 31;
1690 pf.rshift = 11;
1691 pf.gshift = 5;
1692 pf.bshift = 0;
aliguori90a1e3c2009-01-26 15:37:30 +00001693 pf.rbits = 5;
1694 pf.gbits = 6;
1695 pf.bbits = 5;
aliguori7d957bd2009-01-15 22:14:11 +00001696 break;
1697 case 24:
aliguori7d957bd2009-01-15 22:14:11 +00001698 pf.rmask = 0x00FF0000;
1699 pf.gmask = 0x0000FF00;
1700 pf.bmask = 0x000000FF;
1701 pf.rmax = 255;
1702 pf.gmax = 255;
1703 pf.bmax = 255;
1704 pf.rshift = 16;
1705 pf.gshift = 8;
1706 pf.bshift = 0;
aliguori90a1e3c2009-01-26 15:37:30 +00001707 pf.rbits = 8;
1708 pf.gbits = 8;
1709 pf.bbits = 8;
Markus Armbruster0eba62e2011-11-22 12:56:10 +01001710 break;
malc0da2ea12009-01-23 19:56:19 +00001711 case 32:
1712 pf.rmask = 0x00FF0000;
1713 pf.gmask = 0x0000FF00;
1714 pf.bmask = 0x000000FF;
1715 pf.amax = 255;
1716 pf.rmax = 255;
1717 pf.gmax = 255;
1718 pf.bmax = 255;
1719 pf.ashift = 24;
1720 pf.rshift = 16;
1721 pf.gshift = 8;
1722 pf.bshift = 0;
aliguori90a1e3c2009-01-26 15:37:30 +00001723 pf.rbits = 8;
1724 pf.gbits = 8;
1725 pf.bbits = 8;
1726 pf.abits = 8;
aliguori7d957bd2009-01-15 22:14:11 +00001727 break;
1728 default:
1729 break;
1730 }
1731 return pf;
1732}