blob: 871c1d47b2d29a442436f595c3ed2b6fb04f316c [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
31
bellard26489842006-06-25 17:37:36 +000032#define QEMU_RGBA(r, g, b, a) (((a) << 24) | ((r) << 16) | ((g) << 8) | (b))
33#define QEMU_RGB(r, g, b) QEMU_RGBA(r, g, b, 0xff)
bellarde7f0ad52004-07-14 17:28:59 +000034
pbrook6d6f7c22006-03-11 15:35:30 +000035typedef struct TextAttributes {
36 uint8_t fgcol:4;
37 uint8_t bgcol:4;
38 uint8_t bold:1;
39 uint8_t uline:1;
40 uint8_t blink:1;
41 uint8_t invers:1;
42 uint8_t unvisible:1;
43} TextAttributes;
44
bellarde7f0ad52004-07-14 17:28:59 +000045typedef struct TextCell {
46 uint8_t ch;
pbrook6d6f7c22006-03-11 15:35:30 +000047 TextAttributes t_attrib;
bellarde7f0ad52004-07-14 17:28:59 +000048} TextCell;
49
50#define MAX_ESC_PARAMS 3
51
52enum TTYState {
53 TTY_STATE_NORM,
54 TTY_STATE_ESC,
55 TTY_STATE_CSI,
56};
57
bellarde15d7372006-06-25 16:26:29 +000058typedef struct QEMUFIFO {
59 uint8_t *buf;
60 int buf_size;
61 int count, wptr, rptr;
62} QEMUFIFO;
63
pbrook9596ebb2007-11-18 01:44:38 +000064static int qemu_fifo_write(QEMUFIFO *f, const uint8_t *buf, int len1)
bellarde15d7372006-06-25 16:26:29 +000065{
66 int l, len;
67
68 l = f->buf_size - f->count;
69 if (len1 > l)
70 len1 = l;
71 len = len1;
72 while (len > 0) {
73 l = f->buf_size - f->wptr;
74 if (l > len)
75 l = len;
76 memcpy(f->buf + f->wptr, buf, l);
77 f->wptr += l;
78 if (f->wptr >= f->buf_size)
79 f->wptr = 0;
80 buf += l;
81 len -= l;
82 }
83 f->count += len1;
84 return len1;
85}
86
pbrook9596ebb2007-11-18 01:44:38 +000087static int qemu_fifo_read(QEMUFIFO *f, uint8_t *buf, int len1)
bellarde15d7372006-06-25 16:26:29 +000088{
89 int l, len;
90
91 if (len1 > f->count)
92 len1 = f->count;
93 len = len1;
94 while (len > 0) {
95 l = f->buf_size - f->rptr;
96 if (l > len)
97 l = len;
98 memcpy(buf, f->buf + f->rptr, l);
99 f->rptr += l;
100 if (f->rptr >= f->buf_size)
101 f->rptr = 0;
102 buf += l;
103 len -= l;
104 }
105 f->count -= len1;
106 return len1;
107}
108
thsaf3a9032007-07-11 23:14:59 +0000109typedef enum {
110 GRAPHIC_CONSOLE,
balrogc21bbcf2008-09-24 03:32:33 +0000111 TEXT_CONSOLE,
112 TEXT_CONSOLE_FIXED_SIZE
Anthony Liguoric227f092009-10-01 16:12:16 -0500113} console_type_t;
thsaf3a9032007-07-11 23:14:59 +0000114
pbrook95219892006-04-09 01:06:34 +0000115/* ??? This is mis-named.
116 It is used for both text and graphical consoles. */
bellarde7f0ad52004-07-14 17:28:59 +0000117struct TextConsole {
Anthony Liguoric227f092009-10-01 16:12:16 -0500118 console_type_t console_type;
bellarde7f0ad52004-07-14 17:28:59 +0000119 DisplayState *ds;
pbrook95219892006-04-09 01:06:34 +0000120 /* Graphic console state. */
121 vga_hw_update_ptr hw_update;
122 vga_hw_invalidate_ptr hw_invalidate;
123 vga_hw_screen_dump_ptr hw_screen_dump;
balrog4d3b6f62008-02-10 16:33:14 +0000124 vga_hw_text_update_ptr hw_text_update;
pbrook95219892006-04-09 01:06:34 +0000125 void *hw;
126
bellarde7f0ad52004-07-14 17:28:59 +0000127 int g_width, g_height;
128 int width;
129 int height;
130 int total_height;
131 int backscroll_height;
bellarde7f0ad52004-07-14 17:28:59 +0000132 int x, y;
thsadb47962007-01-16 23:02:36 +0000133 int x_saved, y_saved;
bellarde7f0ad52004-07-14 17:28:59 +0000134 int y_displayed;
135 int y_base;
pbrook6d6f7c22006-03-11 15:35:30 +0000136 TextAttributes t_attrib_default; /* default text attributes */
137 TextAttributes t_attrib; /* currently active text attributes */
bellarde7f0ad52004-07-14 17:28:59 +0000138 TextCell *cells;
balrog4d3b6f62008-02-10 16:33:14 +0000139 int text_x[2], text_y[2], cursor_invalidate;
Paolo Bonzini41048332010-12-23 13:42:52 +0100140 int echo;
bellarde7f0ad52004-07-14 17:28:59 +0000141
pbrook14778c22009-01-21 03:02:52 +0000142 int update_x0;
143 int update_y0;
144 int update_x1;
145 int update_y1;
146
bellarde7f0ad52004-07-14 17:28:59 +0000147 enum TTYState state;
148 int esc_params[MAX_ESC_PARAMS];
149 int nb_esc_params;
150
pbrooke5b0bc42007-01-27 23:46:43 +0000151 CharDriverState *chr;
bellarde15d7372006-06-25 16:26:29 +0000152 /* fifo for key pressed */
153 QEMUFIFO out_fifo;
154 uint8_t out_fifo_buf[16];
155 QEMUTimer *kbd_timer;
bellarde7f0ad52004-07-14 17:28:59 +0000156};
157
Paolo Bonzini98b50082010-02-11 00:29:57 +0100158static DisplayState *display_state;
bellarde7f0ad52004-07-14 17:28:59 +0000159static TextConsole *active_console;
160static TextConsole *consoles[MAX_CONSOLES];
161static int nb_consoles = 0;
162
pbrook95219892006-04-09 01:06:34 +0000163void vga_hw_update(void)
164{
thsadb47962007-01-16 23:02:36 +0000165 if (active_console && active_console->hw_update)
pbrook95219892006-04-09 01:06:34 +0000166 active_console->hw_update(active_console->hw);
167}
168
169void vga_hw_invalidate(void)
170{
Gerd Hoffmann26572b82010-05-20 15:23:06 +0200171 if (active_console && active_console->hw_invalidate)
pbrook95219892006-04-09 01:06:34 +0000172 active_console->hw_invalidate(active_console->hw);
173}
174
175void vga_hw_screen_dump(const char *filename)
176{
balrog8571c052008-07-19 13:04:26 +0000177 TextConsole *previous_active_console;
178
179 previous_active_console = active_console;
180 active_console = consoles[0];
181 /* There is currently no way of specifying which screen we want to dump,
aurel327b455222008-09-02 00:09:16 +0000182 so always dump the first one. */
pbrook95219892006-04-09 01:06:34 +0000183 if (consoles[0]->hw_screen_dump)
184 consoles[0]->hw_screen_dump(consoles[0]->hw, filename);
balrog8571c052008-07-19 13:04:26 +0000185 active_console = previous_active_console;
pbrook95219892006-04-09 01:06:34 +0000186}
187
Anthony Liguoric227f092009-10-01 16:12:16 -0500188void vga_hw_text_update(console_ch_t *chardata)
balrog4d3b6f62008-02-10 16:33:14 +0000189{
190 if (active_console && active_console->hw_text_update)
191 active_console->hw_text_update(active_console->hw, chardata);
192}
193
bellarde7f0ad52004-07-14 17:28:59 +0000194/* convert a RGBA color to a color index usable in graphic primitives */
195static unsigned int vga_get_color(DisplayState *ds, unsigned int rgba)
196{
197 unsigned int r, g, b, color;
198
aliguori0e1f5a02008-11-24 19:29:13 +0000199 switch(ds_get_bits_per_pixel(ds)) {
bellarde7f0ad52004-07-14 17:28:59 +0000200#if 0
201 case 8:
202 r = (rgba >> 16) & 0xff;
203 g = (rgba >> 8) & 0xff;
204 b = (rgba) & 0xff;
ths5fafdf22007-09-16 21:08:06 +0000205 color = (rgb_to_index[r] * 6 * 6) +
206 (rgb_to_index[g] * 6) +
bellarde7f0ad52004-07-14 17:28:59 +0000207 (rgb_to_index[b]);
208 break;
209#endif
210 case 15:
211 r = (rgba >> 16) & 0xff;
212 g = (rgba >> 8) & 0xff;
213 b = (rgba) & 0xff;
214 color = ((r >> 3) << 10) | ((g >> 3) << 5) | (b >> 3);
215 break;
216 case 16:
217 r = (rgba >> 16) & 0xff;
218 g = (rgba >> 8) & 0xff;
219 b = (rgba) & 0xff;
220 color = ((r >> 3) << 11) | ((g >> 2) << 5) | (b >> 3);
221 break;
222 case 32:
223 default:
224 color = rgba;
225 break;
226 }
227 return color;
228}
229
ths5fafdf22007-09-16 21:08:06 +0000230static void vga_fill_rect (DisplayState *ds,
bellarde7f0ad52004-07-14 17:28:59 +0000231 int posx, int posy, int width, int height, uint32_t color)
232{
233 uint8_t *d, *d1;
234 int x, y, bpp;
ths3b46e622007-09-17 08:09:54 +0000235
aliguori0e1f5a02008-11-24 19:29:13 +0000236 bpp = (ds_get_bits_per_pixel(ds) + 7) >> 3;
237 d1 = ds_get_data(ds) +
238 ds_get_linesize(ds) * posy + bpp * posx;
bellarde7f0ad52004-07-14 17:28:59 +0000239 for (y = 0; y < height; y++) {
240 d = d1;
241 switch(bpp) {
242 case 1:
243 for (x = 0; x < width; x++) {
244 *((uint8_t *)d) = color;
245 d++;
246 }
247 break;
248 case 2:
249 for (x = 0; x < width; x++) {
250 *((uint16_t *)d) = color;
251 d += 2;
252 }
253 break;
254 case 4:
255 for (x = 0; x < width; x++) {
256 *((uint32_t *)d) = color;
257 d += 4;
258 }
259 break;
260 }
aliguori0e1f5a02008-11-24 19:29:13 +0000261 d1 += ds_get_linesize(ds);
bellarde7f0ad52004-07-14 17:28:59 +0000262 }
263}
264
265/* copy from (xs, ys) to (xd, yd) a rectangle of size (w, h) */
266static void vga_bitblt(DisplayState *ds, int xs, int ys, int xd, int yd, int w, int h)
267{
268 const uint8_t *s;
269 uint8_t *d;
270 int wb, y, bpp;
271
aliguori0e1f5a02008-11-24 19:29:13 +0000272 bpp = (ds_get_bits_per_pixel(ds) + 7) >> 3;
bellarde7f0ad52004-07-14 17:28:59 +0000273 wb = w * bpp;
274 if (yd <= ys) {
aliguori0e1f5a02008-11-24 19:29:13 +0000275 s = ds_get_data(ds) +
276 ds_get_linesize(ds) * ys + bpp * xs;
277 d = ds_get_data(ds) +
278 ds_get_linesize(ds) * yd + bpp * xd;
bellarde7f0ad52004-07-14 17:28:59 +0000279 for (y = 0; y < h; y++) {
280 memmove(d, s, wb);
aliguori0e1f5a02008-11-24 19:29:13 +0000281 d += ds_get_linesize(ds);
282 s += ds_get_linesize(ds);
bellarde7f0ad52004-07-14 17:28:59 +0000283 }
284 } else {
aliguori0e1f5a02008-11-24 19:29:13 +0000285 s = ds_get_data(ds) +
286 ds_get_linesize(ds) * (ys + h - 1) + bpp * xs;
287 d = ds_get_data(ds) +
288 ds_get_linesize(ds) * (yd + h - 1) + bpp * xd;
bellarde7f0ad52004-07-14 17:28:59 +0000289 for (y = 0; y < h; y++) {
290 memmove(d, s, wb);
aliguori0e1f5a02008-11-24 19:29:13 +0000291 d -= ds_get_linesize(ds);
292 s -= ds_get_linesize(ds);
bellarde7f0ad52004-07-14 17:28:59 +0000293 }
294 }
295}
296
297/***********************************************************/
298/* basic char display */
299
300#define FONT_HEIGHT 16
301#define FONT_WIDTH 8
302
303#include "vgafont.h"
304
305#define cbswap_32(__x) \
306((uint32_t)( \
307 (((uint32_t)(__x) & (uint32_t)0x000000ffUL) << 24) | \
308 (((uint32_t)(__x) & (uint32_t)0x0000ff00UL) << 8) | \
309 (((uint32_t)(__x) & (uint32_t)0x00ff0000UL) >> 8) | \
310 (((uint32_t)(__x) & (uint32_t)0xff000000UL) >> 24) ))
311
Juan Quintelae2542fe2009-07-27 16:13:06 +0200312#ifdef HOST_WORDS_BIGENDIAN
bellarde7f0ad52004-07-14 17:28:59 +0000313#define PAT(x) x
314#else
315#define PAT(x) cbswap_32(x)
316#endif
317
318static const uint32_t dmask16[16] = {
319 PAT(0x00000000),
320 PAT(0x000000ff),
321 PAT(0x0000ff00),
322 PAT(0x0000ffff),
323 PAT(0x00ff0000),
324 PAT(0x00ff00ff),
325 PAT(0x00ffff00),
326 PAT(0x00ffffff),
327 PAT(0xff000000),
328 PAT(0xff0000ff),
329 PAT(0xff00ff00),
330 PAT(0xff00ffff),
331 PAT(0xffff0000),
332 PAT(0xffff00ff),
333 PAT(0xffffff00),
334 PAT(0xffffffff),
335};
336
337static const uint32_t dmask4[4] = {
338 PAT(0x00000000),
339 PAT(0x0000ffff),
340 PAT(0xffff0000),
341 PAT(0xffffffff),
342};
343
pbrook6d6f7c22006-03-11 15:35:30 +0000344static uint32_t color_table[2][8];
bellarde7f0ad52004-07-14 17:28:59 +0000345
pbrook6d6f7c22006-03-11 15:35:30 +0000346enum color_names {
347 COLOR_BLACK = 0,
348 COLOR_RED = 1,
349 COLOR_GREEN = 2,
350 COLOR_YELLOW = 3,
351 COLOR_BLUE = 4,
352 COLOR_MAGENTA = 5,
353 COLOR_CYAN = 6,
354 COLOR_WHITE = 7
355};
356
357static const uint32_t color_table_rgb[2][8] = {
358 { /* dark */
bellard26489842006-06-25 17:37:36 +0000359 QEMU_RGB(0x00, 0x00, 0x00), /* black */
360 QEMU_RGB(0xaa, 0x00, 0x00), /* red */
361 QEMU_RGB(0x00, 0xaa, 0x00), /* green */
362 QEMU_RGB(0xaa, 0xaa, 0x00), /* yellow */
363 QEMU_RGB(0x00, 0x00, 0xaa), /* blue */
364 QEMU_RGB(0xaa, 0x00, 0xaa), /* magenta */
365 QEMU_RGB(0x00, 0xaa, 0xaa), /* cyan */
366 QEMU_RGB(0xaa, 0xaa, 0xaa), /* white */
pbrook6d6f7c22006-03-11 15:35:30 +0000367 },
368 { /* bright */
bellard26489842006-06-25 17:37:36 +0000369 QEMU_RGB(0x00, 0x00, 0x00), /* black */
370 QEMU_RGB(0xff, 0x00, 0x00), /* red */
371 QEMU_RGB(0x00, 0xff, 0x00), /* green */
372 QEMU_RGB(0xff, 0xff, 0x00), /* yellow */
373 QEMU_RGB(0x00, 0x00, 0xff), /* blue */
374 QEMU_RGB(0xff, 0x00, 0xff), /* magenta */
375 QEMU_RGB(0x00, 0xff, 0xff), /* cyan */
376 QEMU_RGB(0xff, 0xff, 0xff), /* white */
pbrook6d6f7c22006-03-11 15:35:30 +0000377 }
bellarde7f0ad52004-07-14 17:28:59 +0000378};
379
380static inline unsigned int col_expand(DisplayState *ds, unsigned int col)
381{
aliguori0e1f5a02008-11-24 19:29:13 +0000382 switch(ds_get_bits_per_pixel(ds)) {
bellarde7f0ad52004-07-14 17:28:59 +0000383 case 8:
384 col |= col << 8;
385 col |= col << 16;
386 break;
387 case 15:
388 case 16:
389 col |= col << 16;
390 break;
391 default:
392 break;
393 }
394
395 return col;
396}
pbrook6d6f7c22006-03-11 15:35:30 +0000397#ifdef DEBUG_CONSOLE
398static void console_print_text_attributes(TextAttributes *t_attrib, char ch)
399{
400 if (t_attrib->bold) {
401 printf("b");
402 } else {
403 printf(" ");
404 }
405 if (t_attrib->uline) {
406 printf("u");
407 } else {
408 printf(" ");
409 }
410 if (t_attrib->blink) {
411 printf("l");
412 } else {
413 printf(" ");
414 }
415 if (t_attrib->invers) {
416 printf("i");
417 } else {
418 printf(" ");
419 }
420 if (t_attrib->unvisible) {
421 printf("n");
422 } else {
423 printf(" ");
424 }
425
426 printf(" fg: %d bg: %d ch:'%2X' '%c'\n", t_attrib->fgcol, t_attrib->bgcol, ch, ch);
427}
428#endif
bellarde7f0ad52004-07-14 17:28:59 +0000429
ths5fafdf22007-09-16 21:08:06 +0000430static void vga_putcharxy(DisplayState *ds, int x, int y, int ch,
pbrook6d6f7c22006-03-11 15:35:30 +0000431 TextAttributes *t_attrib)
bellarde7f0ad52004-07-14 17:28:59 +0000432{
433 uint8_t *d;
434 const uint8_t *font_ptr;
435 unsigned int font_data, linesize, xorcol, bpp;
436 int i;
pbrook6d6f7c22006-03-11 15:35:30 +0000437 unsigned int fgcol, bgcol;
438
439#ifdef DEBUG_CONSOLE
440 printf("x: %2i y: %2i", x, y);
441 console_print_text_attributes(t_attrib, ch);
442#endif
443
444 if (t_attrib->invers) {
445 bgcol = color_table[t_attrib->bold][t_attrib->fgcol];
446 fgcol = color_table[t_attrib->bold][t_attrib->bgcol];
447 } else {
448 fgcol = color_table[t_attrib->bold][t_attrib->fgcol];
449 bgcol = color_table[t_attrib->bold][t_attrib->bgcol];
450 }
bellarde7f0ad52004-07-14 17:28:59 +0000451
aliguori0e1f5a02008-11-24 19:29:13 +0000452 bpp = (ds_get_bits_per_pixel(ds) + 7) >> 3;
453 d = ds_get_data(ds) +
454 ds_get_linesize(ds) * y * FONT_HEIGHT + bpp * x * FONT_WIDTH;
455 linesize = ds_get_linesize(ds);
bellarde7f0ad52004-07-14 17:28:59 +0000456 font_ptr = vgafont16 + FONT_HEIGHT * ch;
457 xorcol = bgcol ^ fgcol;
aliguori0e1f5a02008-11-24 19:29:13 +0000458 switch(ds_get_bits_per_pixel(ds)) {
bellarde7f0ad52004-07-14 17:28:59 +0000459 case 8:
460 for(i = 0; i < FONT_HEIGHT; i++) {
461 font_data = *font_ptr++;
pbrook6d6f7c22006-03-11 15:35:30 +0000462 if (t_attrib->uline
463 && ((i == FONT_HEIGHT - 2) || (i == FONT_HEIGHT - 3))) {
464 font_data = 0xFFFF;
465 }
bellarde7f0ad52004-07-14 17:28:59 +0000466 ((uint32_t *)d)[0] = (dmask16[(font_data >> 4)] & xorcol) ^ bgcol;
467 ((uint32_t *)d)[1] = (dmask16[(font_data >> 0) & 0xf] & xorcol) ^ bgcol;
468 d += linesize;
469 }
470 break;
471 case 16:
472 case 15:
473 for(i = 0; i < FONT_HEIGHT; i++) {
474 font_data = *font_ptr++;
pbrook6d6f7c22006-03-11 15:35:30 +0000475 if (t_attrib->uline
476 && ((i == FONT_HEIGHT - 2) || (i == FONT_HEIGHT - 3))) {
477 font_data = 0xFFFF;
478 }
bellarde7f0ad52004-07-14 17:28:59 +0000479 ((uint32_t *)d)[0] = (dmask4[(font_data >> 6)] & xorcol) ^ bgcol;
480 ((uint32_t *)d)[1] = (dmask4[(font_data >> 4) & 3] & xorcol) ^ bgcol;
481 ((uint32_t *)d)[2] = (dmask4[(font_data >> 2) & 3] & xorcol) ^ bgcol;
482 ((uint32_t *)d)[3] = (dmask4[(font_data >> 0) & 3] & xorcol) ^ bgcol;
483 d += linesize;
484 }
485 break;
486 case 32:
487 for(i = 0; i < FONT_HEIGHT; i++) {
488 font_data = *font_ptr++;
pbrook6d6f7c22006-03-11 15:35:30 +0000489 if (t_attrib->uline && ((i == FONT_HEIGHT - 2) || (i == FONT_HEIGHT - 3))) {
490 font_data = 0xFFFF;
491 }
bellarde7f0ad52004-07-14 17:28:59 +0000492 ((uint32_t *)d)[0] = (-((font_data >> 7)) & xorcol) ^ bgcol;
493 ((uint32_t *)d)[1] = (-((font_data >> 6) & 1) & xorcol) ^ bgcol;
494 ((uint32_t *)d)[2] = (-((font_data >> 5) & 1) & xorcol) ^ bgcol;
495 ((uint32_t *)d)[3] = (-((font_data >> 4) & 1) & xorcol) ^ bgcol;
496 ((uint32_t *)d)[4] = (-((font_data >> 3) & 1) & xorcol) ^ bgcol;
497 ((uint32_t *)d)[5] = (-((font_data >> 2) & 1) & xorcol) ^ bgcol;
498 ((uint32_t *)d)[6] = (-((font_data >> 1) & 1) & xorcol) ^ bgcol;
499 ((uint32_t *)d)[7] = (-((font_data >> 0) & 1) & xorcol) ^ bgcol;
500 d += linesize;
501 }
502 break;
503 }
504}
505
506static void text_console_resize(TextConsole *s)
507{
508 TextCell *cells, *c, *c1;
509 int w1, x, y, last_width;
510
511 last_width = s->width;
512 s->width = s->g_width / FONT_WIDTH;
513 s->height = s->g_height / FONT_HEIGHT;
514
515 w1 = last_width;
516 if (s->width < w1)
517 w1 = s->width;
518
519 cells = qemu_malloc(s->width * s->total_height * sizeof(TextCell));
520 for(y = 0; y < s->total_height; y++) {
521 c = &cells[y * s->width];
522 if (w1 > 0) {
523 c1 = &s->cells[y * last_width];
524 for(x = 0; x < w1; x++) {
525 *c++ = *c1++;
526 }
527 }
528 for(x = w1; x < s->width; x++) {
529 c->ch = ' ';
pbrook6d6f7c22006-03-11 15:35:30 +0000530 c->t_attrib = s->t_attrib_default;
bellarde7f0ad52004-07-14 17:28:59 +0000531 c++;
532 }
533 }
balroga528b802007-10-30 22:38:53 +0000534 qemu_free(s->cells);
bellarde7f0ad52004-07-14 17:28:59 +0000535 s->cells = cells;
536}
537
balrog4d3b6f62008-02-10 16:33:14 +0000538static inline void text_update_xy(TextConsole *s, int x, int y)
539{
540 s->text_x[0] = MIN(s->text_x[0], x);
541 s->text_x[1] = MAX(s->text_x[1], x);
542 s->text_y[0] = MIN(s->text_y[0], y);
543 s->text_y[1] = MAX(s->text_y[1], y);
544}
545
pbrook14778c22009-01-21 03:02:52 +0000546static void invalidate_xy(TextConsole *s, int x, int y)
547{
548 if (s->update_x0 > x * FONT_WIDTH)
549 s->update_x0 = x * FONT_WIDTH;
550 if (s->update_y0 > y * FONT_HEIGHT)
551 s->update_y0 = y * FONT_HEIGHT;
552 if (s->update_x1 < (x + 1) * FONT_WIDTH)
553 s->update_x1 = (x + 1) * FONT_WIDTH;
554 if (s->update_y1 < (y + 1) * FONT_HEIGHT)
555 s->update_y1 = (y + 1) * FONT_HEIGHT;
556}
557
bellarde7f0ad52004-07-14 17:28:59 +0000558static void update_xy(TextConsole *s, int x, int y)
559{
560 TextCell *c;
561 int y1, y2;
562
563 if (s == active_console) {
aliguori0e1f5a02008-11-24 19:29:13 +0000564 if (!ds_get_bits_per_pixel(s->ds)) {
balrog4d3b6f62008-02-10 16:33:14 +0000565 text_update_xy(s, x, y);
566 return;
567 }
568
bellarde7f0ad52004-07-14 17:28:59 +0000569 y1 = (s->y_base + y) % s->total_height;
570 y2 = y1 - s->y_displayed;
571 if (y2 < 0)
572 y2 += s->total_height;
573 if (y2 < s->height) {
574 c = &s->cells[y1 * s->width + x];
ths5fafdf22007-09-16 21:08:06 +0000575 vga_putcharxy(s->ds, x, y2, c->ch,
pbrook6d6f7c22006-03-11 15:35:30 +0000576 &(c->t_attrib));
pbrook14778c22009-01-21 03:02:52 +0000577 invalidate_xy(s, x, y2);
bellarde7f0ad52004-07-14 17:28:59 +0000578 }
579 }
580}
581
582static void console_show_cursor(TextConsole *s, int show)
583{
584 TextCell *c;
585 int y, y1;
586
587 if (s == active_console) {
thsed8276a2007-02-10 22:37:56 +0000588 int x = s->x;
balrog4d3b6f62008-02-10 16:33:14 +0000589
aliguori0e1f5a02008-11-24 19:29:13 +0000590 if (!ds_get_bits_per_pixel(s->ds)) {
balrog4d3b6f62008-02-10 16:33:14 +0000591 s->cursor_invalidate = 1;
592 return;
593 }
594
thsed8276a2007-02-10 22:37:56 +0000595 if (x >= s->width) {
596 x = s->width - 1;
597 }
bellarde7f0ad52004-07-14 17:28:59 +0000598 y1 = (s->y_base + s->y) % s->total_height;
599 y = y1 - s->y_displayed;
600 if (y < 0)
601 y += s->total_height;
602 if (y < s->height) {
thsed8276a2007-02-10 22:37:56 +0000603 c = &s->cells[y1 * s->width + x];
bellarde7f0ad52004-07-14 17:28:59 +0000604 if (show) {
pbrook6d6f7c22006-03-11 15:35:30 +0000605 TextAttributes t_attrib = s->t_attrib_default;
606 t_attrib.invers = !(t_attrib.invers); /* invert fg and bg */
thsed8276a2007-02-10 22:37:56 +0000607 vga_putcharxy(s->ds, x, y, c->ch, &t_attrib);
bellarde7f0ad52004-07-14 17:28:59 +0000608 } else {
thsed8276a2007-02-10 22:37:56 +0000609 vga_putcharxy(s->ds, x, y, c->ch, &(c->t_attrib));
bellarde7f0ad52004-07-14 17:28:59 +0000610 }
pbrook14778c22009-01-21 03:02:52 +0000611 invalidate_xy(s, x, y);
bellarde7f0ad52004-07-14 17:28:59 +0000612 }
613 }
614}
615
616static void console_refresh(TextConsole *s)
617{
618 TextCell *c;
619 int x, y, y1;
620
ths5fafdf22007-09-16 21:08:06 +0000621 if (s != active_console)
bellarde7f0ad52004-07-14 17:28:59 +0000622 return;
aliguori0e1f5a02008-11-24 19:29:13 +0000623 if (!ds_get_bits_per_pixel(s->ds)) {
balrog4d3b6f62008-02-10 16:33:14 +0000624 s->text_x[0] = 0;
625 s->text_y[0] = 0;
626 s->text_x[1] = s->width - 1;
627 s->text_y[1] = s->height - 1;
628 s->cursor_invalidate = 1;
629 return;
630 }
bellarde7f0ad52004-07-14 17:28:59 +0000631
aliguori0e1f5a02008-11-24 19:29:13 +0000632 vga_fill_rect(s->ds, 0, 0, ds_get_width(s->ds), ds_get_height(s->ds),
pbrook6d6f7c22006-03-11 15:35:30 +0000633 color_table[0][COLOR_BLACK]);
bellarde7f0ad52004-07-14 17:28:59 +0000634 y1 = s->y_displayed;
635 for(y = 0; y < s->height; y++) {
636 c = s->cells + y1 * s->width;
637 for(x = 0; x < s->width; x++) {
ths5fafdf22007-09-16 21:08:06 +0000638 vga_putcharxy(s->ds, x, y, c->ch,
pbrook6d6f7c22006-03-11 15:35:30 +0000639 &(c->t_attrib));
bellarde7f0ad52004-07-14 17:28:59 +0000640 c++;
641 }
642 if (++y1 == s->total_height)
643 y1 = 0;
644 }
bellarde7f0ad52004-07-14 17:28:59 +0000645 console_show_cursor(s, 1);
pbrook14778c22009-01-21 03:02:52 +0000646 dpy_update(s->ds, 0, 0, ds_get_width(s->ds), ds_get_height(s->ds));
bellarde7f0ad52004-07-14 17:28:59 +0000647}
648
649static void console_scroll(int ydelta)
650{
651 TextConsole *s;
652 int i, y1;
ths3b46e622007-09-17 08:09:54 +0000653
bellarde7f0ad52004-07-14 17:28:59 +0000654 s = active_console;
thsaf3a9032007-07-11 23:14:59 +0000655 if (!s || (s->console_type == GRAPHIC_CONSOLE))
bellarde7f0ad52004-07-14 17:28:59 +0000656 return;
657
658 if (ydelta > 0) {
659 for(i = 0; i < ydelta; i++) {
660 if (s->y_displayed == s->y_base)
661 break;
662 if (++s->y_displayed == s->total_height)
663 s->y_displayed = 0;
664 }
665 } else {
666 ydelta = -ydelta;
667 i = s->backscroll_height;
668 if (i > s->total_height - s->height)
669 i = s->total_height - s->height;
670 y1 = s->y_base - i;
671 if (y1 < 0)
672 y1 += s->total_height;
673 for(i = 0; i < ydelta; i++) {
674 if (s->y_displayed == y1)
675 break;
676 if (--s->y_displayed < 0)
677 s->y_displayed = s->total_height - 1;
678 }
679 }
680 console_refresh(s);
681}
682
683static void console_put_lf(TextConsole *s)
684{
685 TextCell *c;
686 int x, y1;
687
bellarde7f0ad52004-07-14 17:28:59 +0000688 s->y++;
689 if (s->y >= s->height) {
690 s->y = s->height - 1;
pbrook6d6f7c22006-03-11 15:35:30 +0000691
bellarde7f0ad52004-07-14 17:28:59 +0000692 if (s->y_displayed == s->y_base) {
693 if (++s->y_displayed == s->total_height)
694 s->y_displayed = 0;
695 }
696 if (++s->y_base == s->total_height)
697 s->y_base = 0;
698 if (s->backscroll_height < s->total_height)
699 s->backscroll_height++;
700 y1 = (s->y_base + s->height - 1) % s->total_height;
701 c = &s->cells[y1 * s->width];
702 for(x = 0; x < s->width; x++) {
703 c->ch = ' ';
pbrook6d6f7c22006-03-11 15:35:30 +0000704 c->t_attrib = s->t_attrib_default;
bellarde7f0ad52004-07-14 17:28:59 +0000705 c++;
706 }
707 if (s == active_console && s->y_displayed == s->y_base) {
aliguori0e1f5a02008-11-24 19:29:13 +0000708 if (!ds_get_bits_per_pixel(s->ds)) {
balrog4d3b6f62008-02-10 16:33:14 +0000709 s->text_x[0] = 0;
710 s->text_y[0] = 0;
711 s->text_x[1] = s->width - 1;
712 s->text_y[1] = s->height - 1;
713 return;
714 }
715
ths5fafdf22007-09-16 21:08:06 +0000716 vga_bitblt(s->ds, 0, FONT_HEIGHT, 0, 0,
717 s->width * FONT_WIDTH,
bellarde7f0ad52004-07-14 17:28:59 +0000718 (s->height - 1) * FONT_HEIGHT);
719 vga_fill_rect(s->ds, 0, (s->height - 1) * FONT_HEIGHT,
ths5fafdf22007-09-16 21:08:06 +0000720 s->width * FONT_WIDTH, FONT_HEIGHT,
pbrook6d6f7c22006-03-11 15:35:30 +0000721 color_table[0][s->t_attrib_default.bgcol]);
pbrook14778c22009-01-21 03:02:52 +0000722 s->update_x0 = 0;
723 s->update_y0 = 0;
724 s->update_x1 = s->width * FONT_WIDTH;
725 s->update_y1 = s->height * FONT_HEIGHT;
bellarde7f0ad52004-07-14 17:28:59 +0000726 }
727 }
728}
729
pbrook6d6f7c22006-03-11 15:35:30 +0000730/* Set console attributes depending on the current escape codes.
731 * NOTE: I know this code is not very efficient (checking every color for it
732 * self) but it is more readable and better maintainable.
733 */
734static void console_handle_escape(TextConsole *s)
735{
736 int i;
737
pbrook6d6f7c22006-03-11 15:35:30 +0000738 for (i=0; i<s->nb_esc_params; i++) {
739 switch (s->esc_params[i]) {
740 case 0: /* reset all console attributes to default */
741 s->t_attrib = s->t_attrib_default;
742 break;
743 case 1:
744 s->t_attrib.bold = 1;
745 break;
746 case 4:
747 s->t_attrib.uline = 1;
748 break;
749 case 5:
750 s->t_attrib.blink = 1;
751 break;
752 case 7:
753 s->t_attrib.invers = 1;
754 break;
755 case 8:
756 s->t_attrib.unvisible = 1;
757 break;
758 case 22:
759 s->t_attrib.bold = 0;
760 break;
761 case 24:
762 s->t_attrib.uline = 0;
763 break;
764 case 25:
765 s->t_attrib.blink = 0;
766 break;
767 case 27:
768 s->t_attrib.invers = 0;
769 break;
770 case 28:
771 s->t_attrib.unvisible = 0;
772 break;
773 /* set foreground color */
774 case 30:
775 s->t_attrib.fgcol=COLOR_BLACK;
776 break;
777 case 31:
778 s->t_attrib.fgcol=COLOR_RED;
779 break;
780 case 32:
781 s->t_attrib.fgcol=COLOR_GREEN;
782 break;
783 case 33:
784 s->t_attrib.fgcol=COLOR_YELLOW;
785 break;
786 case 34:
787 s->t_attrib.fgcol=COLOR_BLUE;
788 break;
789 case 35:
790 s->t_attrib.fgcol=COLOR_MAGENTA;
791 break;
792 case 36:
793 s->t_attrib.fgcol=COLOR_CYAN;
794 break;
795 case 37:
796 s->t_attrib.fgcol=COLOR_WHITE;
797 break;
798 /* set background color */
799 case 40:
800 s->t_attrib.bgcol=COLOR_BLACK;
801 break;
802 case 41:
803 s->t_attrib.bgcol=COLOR_RED;
804 break;
805 case 42:
806 s->t_attrib.bgcol=COLOR_GREEN;
807 break;
808 case 43:
809 s->t_attrib.bgcol=COLOR_YELLOW;
810 break;
811 case 44:
812 s->t_attrib.bgcol=COLOR_BLUE;
813 break;
814 case 45:
815 s->t_attrib.bgcol=COLOR_MAGENTA;
816 break;
817 case 46:
818 s->t_attrib.bgcol=COLOR_CYAN;
819 break;
820 case 47:
821 s->t_attrib.bgcol=COLOR_WHITE;
822 break;
823 }
824 }
825}
826
thsadb47962007-01-16 23:02:36 +0000827static void console_clear_xy(TextConsole *s, int x, int y)
828{
829 int y1 = (s->y_base + y) % s->total_height;
830 TextCell *c = &s->cells[y1 * s->width + x];
831 c->ch = ' ';
832 c->t_attrib = s->t_attrib_default;
thsadb47962007-01-16 23:02:36 +0000833 update_xy(s, x, y);
834}
835
bellarde7f0ad52004-07-14 17:28:59 +0000836static void console_putchar(TextConsole *s, int ch)
837{
838 TextCell *c;
thsadb47962007-01-16 23:02:36 +0000839 int y1, i;
840 int x, y;
bellarde7f0ad52004-07-14 17:28:59 +0000841
842 switch(s->state) {
843 case TTY_STATE_NORM:
844 switch(ch) {
pbrook6d6f7c22006-03-11 15:35:30 +0000845 case '\r': /* carriage return */
bellarde7f0ad52004-07-14 17:28:59 +0000846 s->x = 0;
847 break;
pbrook6d6f7c22006-03-11 15:35:30 +0000848 case '\n': /* newline */
bellarde7f0ad52004-07-14 17:28:59 +0000849 console_put_lf(s);
850 break;
pbrook6d6f7c22006-03-11 15:35:30 +0000851 case '\b': /* backspace */
ths5fafdf22007-09-16 21:08:06 +0000852 if (s->x > 0)
bellarde15d7372006-06-25 16:26:29 +0000853 s->x--;
pbrook6d6f7c22006-03-11 15:35:30 +0000854 break;
855 case '\t': /* tabspace */
856 if (s->x + (8 - (s->x % 8)) > s->width) {
bellardbd468842006-07-14 20:24:31 +0000857 s->x = 0;
pbrook6d6f7c22006-03-11 15:35:30 +0000858 console_put_lf(s);
859 } else {
860 s->x = s->x + (8 - (s->x % 8));
861 }
862 break;
863 case '\a': /* alert aka. bell */
864 /* TODO: has to be implemented */
865 break;
thsadb47962007-01-16 23:02:36 +0000866 case 14:
867 /* SI (shift in), character set 0 (ignored) */
868 break;
869 case 15:
870 /* SO (shift out), character set 1 (ignored) */
871 break;
pbrook6d6f7c22006-03-11 15:35:30 +0000872 case 27: /* esc (introducing an escape sequence) */
bellarde7f0ad52004-07-14 17:28:59 +0000873 s->state = TTY_STATE_ESC;
874 break;
875 default:
thsed8276a2007-02-10 22:37:56 +0000876 if (s->x >= s->width) {
877 /* line wrap */
878 s->x = 0;
879 console_put_lf(s);
thsadb47962007-01-16 23:02:36 +0000880 }
bellarde7f0ad52004-07-14 17:28:59 +0000881 y1 = (s->y_base + s->y) % s->total_height;
882 c = &s->cells[y1 * s->width + s->x];
883 c->ch = ch;
pbrook6d6f7c22006-03-11 15:35:30 +0000884 c->t_attrib = s->t_attrib;
bellarde7f0ad52004-07-14 17:28:59 +0000885 update_xy(s, s->x, s->y);
886 s->x++;
bellarde7f0ad52004-07-14 17:28:59 +0000887 break;
888 }
889 break;
pbrook6d6f7c22006-03-11 15:35:30 +0000890 case TTY_STATE_ESC: /* check if it is a terminal escape sequence */
bellarde7f0ad52004-07-14 17:28:59 +0000891 if (ch == '[') {
892 for(i=0;i<MAX_ESC_PARAMS;i++)
893 s->esc_params[i] = 0;
894 s->nb_esc_params = 0;
895 s->state = TTY_STATE_CSI;
896 } else {
897 s->state = TTY_STATE_NORM;
898 }
899 break;
pbrook6d6f7c22006-03-11 15:35:30 +0000900 case TTY_STATE_CSI: /* handle escape sequence parameters */
bellarde7f0ad52004-07-14 17:28:59 +0000901 if (ch >= '0' && ch <= '9') {
902 if (s->nb_esc_params < MAX_ESC_PARAMS) {
ths5fafdf22007-09-16 21:08:06 +0000903 s->esc_params[s->nb_esc_params] =
bellarde7f0ad52004-07-14 17:28:59 +0000904 s->esc_params[s->nb_esc_params] * 10 + ch - '0';
905 }
906 } else {
907 s->nb_esc_params++;
908 if (ch == ';')
909 break;
thsadb47962007-01-16 23:02:36 +0000910#ifdef DEBUG_CONSOLE
911 fprintf(stderr, "escape sequence CSI%d;%d%c, %d parameters\n",
912 s->esc_params[0], s->esc_params[1], ch, s->nb_esc_params);
913#endif
bellarde7f0ad52004-07-14 17:28:59 +0000914 s->state = TTY_STATE_NORM;
915 switch(ch) {
thsadb47962007-01-16 23:02:36 +0000916 case 'A':
917 /* move cursor up */
918 if (s->esc_params[0] == 0) {
919 s->esc_params[0] = 1;
920 }
921 s->y -= s->esc_params[0];
922 if (s->y < 0) {
923 s->y = 0;
bellarde7f0ad52004-07-14 17:28:59 +0000924 }
925 break;
thsadb47962007-01-16 23:02:36 +0000926 case 'B':
927 /* move cursor down */
928 if (s->esc_params[0] == 0) {
929 s->esc_params[0] = 1;
930 }
931 s->y += s->esc_params[0];
932 if (s->y >= s->height) {
933 s->y = s->height - 1;
934 }
935 break;
936 case 'C':
937 /* move cursor right */
938 if (s->esc_params[0] == 0) {
939 s->esc_params[0] = 1;
940 }
941 s->x += s->esc_params[0];
942 if (s->x >= s->width) {
943 s->x = s->width - 1;
944 }
945 break;
946 case 'D':
947 /* move cursor left */
948 if (s->esc_params[0] == 0) {
949 s->esc_params[0] = 1;
950 }
951 s->x -= s->esc_params[0];
952 if (s->x < 0) {
953 s->x = 0;
954 }
955 break;
956 case 'G':
957 /* move cursor to column */
958 s->x = s->esc_params[0] - 1;
959 if (s->x < 0) {
960 s->x = 0;
961 }
962 break;
963 case 'f':
964 case 'H':
965 /* move cursor to row, column */
966 s->x = s->esc_params[1] - 1;
967 if (s->x < 0) {
968 s->x = 0;
969 }
970 s->y = s->esc_params[0] - 1;
971 if (s->y < 0) {
972 s->y = 0;
973 }
974 break;
975 case 'J':
976 switch (s->esc_params[0]) {
977 case 0:
978 /* clear to end of screen */
979 for (y = s->y; y < s->height; y++) {
980 for (x = 0; x < s->width; x++) {
981 if (y == s->y && x < s->x) {
982 continue;
983 }
984 console_clear_xy(s, x, y);
985 }
986 }
987 break;
988 case 1:
989 /* clear from beginning of screen */
990 for (y = 0; y <= s->y; y++) {
991 for (x = 0; x < s->width; x++) {
992 if (y == s->y && x > s->x) {
993 break;
994 }
995 console_clear_xy(s, x, y);
996 }
997 }
998 break;
999 case 2:
1000 /* clear entire screen */
1001 for (y = 0; y <= s->height; y++) {
1002 for (x = 0; x < s->width; x++) {
1003 console_clear_xy(s, x, y);
1004 }
1005 }
1006 break;
1007 }
1008 case 'K':
1009 switch (s->esc_params[0]) {
1010 case 0:
1011 /* clear to eol */
1012 for(x = s->x; x < s->width; x++) {
1013 console_clear_xy(s, x, s->y);
1014 }
1015 break;
1016 case 1:
1017 /* clear from beginning of line */
1018 for (x = 0; x <= s->x; x++) {
1019 console_clear_xy(s, x, s->y);
1020 }
1021 break;
1022 case 2:
1023 /* clear entire line */
1024 for(x = 0; x < s->width; x++) {
1025 console_clear_xy(s, x, s->y);
1026 }
bellarde7f0ad52004-07-14 17:28:59 +00001027 break;
1028 }
thsadb47962007-01-16 23:02:36 +00001029 break;
1030 case 'm':
pbrook6d6f7c22006-03-11 15:35:30 +00001031 console_handle_escape(s);
bellarde7f0ad52004-07-14 17:28:59 +00001032 break;
thsadb47962007-01-16 23:02:36 +00001033 case 'n':
1034 /* report cursor position */
1035 /* TODO: send ESC[row;colR */
1036 break;
1037 case 's':
1038 /* save cursor position */
1039 s->x_saved = s->x;
1040 s->y_saved = s->y;
1041 break;
1042 case 'u':
1043 /* restore cursor position */
1044 s->x = s->x_saved;
1045 s->y = s->y_saved;
1046 break;
1047 default:
1048#ifdef DEBUG_CONSOLE
1049 fprintf(stderr, "unhandled escape character '%c'\n", ch);
1050#endif
1051 break;
1052 }
1053 break;
bellarde7f0ad52004-07-14 17:28:59 +00001054 }
1055 }
1056}
1057
1058void console_select(unsigned int index)
1059{
1060 TextConsole *s;
pbrook6d6f7c22006-03-11 15:35:30 +00001061
bellarde7f0ad52004-07-14 17:28:59 +00001062 if (index >= MAX_CONSOLES)
1063 return;
Stefan Hajnoczi358664c2010-09-20 14:11:19 +01001064 if (active_console) {
1065 active_console->g_width = ds_get_width(active_console->ds);
1066 active_console->g_height = ds_get_height(active_console->ds);
1067 }
bellarde7f0ad52004-07-14 17:28:59 +00001068 s = consoles[index];
1069 if (s) {
aliguori7d957bd2009-01-15 22:14:11 +00001070 DisplayState *ds = s->ds;
bellarde7f0ad52004-07-14 17:28:59 +00001071 active_console = s;
aliguori68f00992009-01-21 18:59:12 +00001072 if (ds_get_bits_per_pixel(s->ds)) {
aliguori7b5d76d2009-03-13 15:02:13 +00001073 ds->surface = qemu_resize_displaysurface(ds, s->g_width, s->g_height);
aliguori68f00992009-01-21 18:59:12 +00001074 } else {
1075 s->ds->surface->width = s->width;
1076 s->ds->surface->height = s->height;
1077 }
aliguori7d957bd2009-01-15 22:14:11 +00001078 dpy_resize(s->ds);
balrog4d3b6f62008-02-10 16:33:14 +00001079 vga_hw_invalidate();
bellarde7f0ad52004-07-14 17:28:59 +00001080 }
1081}
1082
1083static int console_puts(CharDriverState *chr, const uint8_t *buf, int len)
1084{
1085 TextConsole *s = chr->opaque;
1086 int i;
1087
pbrook14778c22009-01-21 03:02:52 +00001088 s->update_x0 = s->width * FONT_WIDTH;
1089 s->update_y0 = s->height * FONT_HEIGHT;
1090 s->update_x1 = 0;
1091 s->update_y1 = 0;
bellarde7f0ad52004-07-14 17:28:59 +00001092 console_show_cursor(s, 0);
1093 for(i = 0; i < len; i++) {
1094 console_putchar(s, buf[i]);
1095 }
1096 console_show_cursor(s, 1);
pbrook14778c22009-01-21 03:02:52 +00001097 if (ds_get_bits_per_pixel(s->ds) && s->update_x0 < s->update_x1) {
1098 dpy_update(s->ds, s->update_x0, s->update_y0,
1099 s->update_x1 - s->update_x0,
1100 s->update_y1 - s->update_y0);
1101 }
bellarde7f0ad52004-07-14 17:28:59 +00001102 return len;
1103}
1104
bellard6fcfafb2004-08-01 21:48:30 +00001105static void console_send_event(CharDriverState *chr, int event)
1106{
1107 TextConsole *s = chr->opaque;
1108 int i;
1109
1110 if (event == CHR_EVENT_FOCUS) {
1111 for(i = 0; i < nb_consoles; i++) {
1112 if (consoles[i] == s) {
1113 console_select(i);
1114 break;
1115 }
1116 }
1117 }
1118}
1119
bellarde15d7372006-06-25 16:26:29 +00001120static void kbd_send_chars(void *opaque)
1121{
1122 TextConsole *s = opaque;
1123 int len;
1124 uint8_t buf[16];
ths3b46e622007-09-17 08:09:54 +00001125
pbrooke5b0bc42007-01-27 23:46:43 +00001126 len = qemu_chr_can_read(s->chr);
bellarde15d7372006-06-25 16:26:29 +00001127 if (len > s->out_fifo.count)
1128 len = s->out_fifo.count;
1129 if (len > 0) {
1130 if (len > sizeof(buf))
1131 len = sizeof(buf);
1132 qemu_fifo_read(&s->out_fifo, buf, len);
pbrooke5b0bc42007-01-27 23:46:43 +00001133 qemu_chr_read(s->chr, buf, len);
bellarde15d7372006-06-25 16:26:29 +00001134 }
1135 /* characters are pending: we send them a bit later (XXX:
1136 horrible, should change char device API) */
1137 if (s->out_fifo.count > 0) {
Paolo Bonzini7bd427d2011-03-11 16:47:48 +01001138 qemu_mod_timer(s->kbd_timer, qemu_get_clock_ms(rt_clock) + 1);
bellarde15d7372006-06-25 16:26:29 +00001139 }
1140}
1141
bellarde7f0ad52004-07-14 17:28:59 +00001142/* called when an ascii key is pressed */
1143void kbd_put_keysym(int keysym)
1144{
1145 TextConsole *s;
1146 uint8_t buf[16], *q;
1147 int c;
1148
1149 s = active_console;
thsaf3a9032007-07-11 23:14:59 +00001150 if (!s || (s->console_type == GRAPHIC_CONSOLE))
bellarde7f0ad52004-07-14 17:28:59 +00001151 return;
1152
1153 switch(keysym) {
1154 case QEMU_KEY_CTRL_UP:
1155 console_scroll(-1);
1156 break;
1157 case QEMU_KEY_CTRL_DOWN:
1158 console_scroll(1);
1159 break;
1160 case QEMU_KEY_CTRL_PAGEUP:
1161 console_scroll(-10);
1162 break;
1163 case QEMU_KEY_CTRL_PAGEDOWN:
1164 console_scroll(10);
1165 break;
1166 default:
bellarde15d7372006-06-25 16:26:29 +00001167 /* convert the QEMU keysym to VT100 key string */
1168 q = buf;
1169 if (keysym >= 0xe100 && keysym <= 0xe11f) {
1170 *q++ = '\033';
1171 *q++ = '[';
1172 c = keysym - 0xe100;
1173 if (c >= 10)
1174 *q++ = '0' + (c / 10);
1175 *q++ = '0' + (c % 10);
1176 *q++ = '~';
1177 } else if (keysym >= 0xe120 && keysym <= 0xe17f) {
1178 *q++ = '\033';
1179 *q++ = '[';
1180 *q++ = keysym & 0xff;
Paolo Bonzini41048332010-12-23 13:42:52 +01001181 } else if (s->echo && (keysym == '\r' || keysym == '\n')) {
1182 console_puts(s->chr, (const uint8_t *) "\r", 1);
1183 *q++ = '\n';
bellarde15d7372006-06-25 16:26:29 +00001184 } else {
Paolo Bonzini41048332010-12-23 13:42:52 +01001185 *q++ = keysym;
1186 }
1187 if (s->echo) {
1188 console_puts(s->chr, buf, q - buf);
bellarde15d7372006-06-25 16:26:29 +00001189 }
pbrooke5b0bc42007-01-27 23:46:43 +00001190 if (s->chr->chr_read) {
bellarde15d7372006-06-25 16:26:29 +00001191 qemu_fifo_write(&s->out_fifo, buf, q - buf);
1192 kbd_send_chars(s);
bellarde7f0ad52004-07-14 17:28:59 +00001193 }
1194 break;
1195 }
1196}
1197
balrog4d3b6f62008-02-10 16:33:14 +00001198static void text_console_invalidate(void *opaque)
1199{
1200 TextConsole *s = (TextConsole *) opaque;
aliguori68f00992009-01-21 18:59:12 +00001201 if (!ds_get_bits_per_pixel(s->ds) && s->console_type == TEXT_CONSOLE) {
1202 s->g_width = ds_get_width(s->ds);
1203 s->g_height = ds_get_height(s->ds);
1204 text_console_resize(s);
1205 }
balrog4d3b6f62008-02-10 16:33:14 +00001206 console_refresh(s);
1207}
1208
Anthony Liguoric227f092009-10-01 16:12:16 -05001209static void text_console_update(void *opaque, console_ch_t *chardata)
balrog4d3b6f62008-02-10 16:33:14 +00001210{
1211 TextConsole *s = (TextConsole *) opaque;
1212 int i, j, src;
1213
1214 if (s->text_x[0] <= s->text_x[1]) {
1215 src = (s->y_base + s->text_y[0]) * s->width;
1216 chardata += s->text_y[0] * s->width;
1217 for (i = s->text_y[0]; i <= s->text_y[1]; i ++)
1218 for (j = 0; j < s->width; j ++, src ++)
1219 console_write_ch(chardata ++, s->cells[src].ch |
1220 (s->cells[src].t_attrib.fgcol << 12) |
1221 (s->cells[src].t_attrib.bgcol << 8) |
1222 (s->cells[src].t_attrib.bold << 21));
1223 dpy_update(s->ds, s->text_x[0], s->text_y[0],
1224 s->text_x[1] - s->text_x[0], i - s->text_y[0]);
1225 s->text_x[0] = s->width;
1226 s->text_y[0] = s->height;
1227 s->text_x[1] = 0;
1228 s->text_y[1] = 0;
1229 }
1230 if (s->cursor_invalidate) {
1231 dpy_cursor(s->ds, s->x, s->y);
1232 s->cursor_invalidate = 0;
1233 }
1234}
1235
aliguori42aa98e2009-01-16 21:01:48 +00001236static TextConsole *get_graphic_console(DisplayState *ds)
blueswir1a147d622009-01-16 19:41:04 +00001237{
aliguori3023f332009-01-16 19:04:14 +00001238 int i;
1239 TextConsole *s;
1240 for (i = 0; i < nb_consoles; i++) {
1241 s = consoles[i];
aliguori42aa98e2009-01-16 21:01:48 +00001242 if (s->console_type == GRAPHIC_CONSOLE && s->ds == ds)
aliguori3023f332009-01-16 19:04:14 +00001243 return s;
1244 }
1245 return NULL;
1246}
1247
Anthony Liguoric227f092009-10-01 16:12:16 -05001248static TextConsole *new_console(DisplayState *ds, console_type_t console_type)
bellarde7f0ad52004-07-14 17:28:59 +00001249{
1250 TextConsole *s;
pbrook95219892006-04-09 01:06:34 +00001251 int i;
bellarde7f0ad52004-07-14 17:28:59 +00001252
1253 if (nb_consoles >= MAX_CONSOLES)
1254 return NULL;
1255 s = qemu_mallocz(sizeof(TextConsole));
thsaf3a9032007-07-11 23:14:59 +00001256 if (!active_console || ((active_console->console_type != GRAPHIC_CONSOLE) &&
1257 (console_type == GRAPHIC_CONSOLE))) {
bellarde7f0ad52004-07-14 17:28:59 +00001258 active_console = s;
thsaf3a9032007-07-11 23:14:59 +00001259 }
bellarde7f0ad52004-07-14 17:28:59 +00001260 s->ds = ds;
thsaf3a9032007-07-11 23:14:59 +00001261 s->console_type = console_type;
1262 if (console_type != GRAPHIC_CONSOLE) {
pbrook95219892006-04-09 01:06:34 +00001263 consoles[nb_consoles++] = s;
1264 } else {
1265 /* HACK: Put graphical consoles before text consoles. */
1266 for (i = nb_consoles; i > 0; i--) {
thsaf3a9032007-07-11 23:14:59 +00001267 if (consoles[i - 1]->console_type == GRAPHIC_CONSOLE)
pbrook95219892006-04-09 01:06:34 +00001268 break;
1269 consoles[i] = consoles[i - 1];
1270 }
1271 consoles[i] = s;
aliguori3023f332009-01-16 19:04:14 +00001272 nb_consoles++;
pbrook95219892006-04-09 01:06:34 +00001273 }
bellarde7f0ad52004-07-14 17:28:59 +00001274 return s;
1275}
1276
Paolo Bonzini98b50082010-02-11 00:29:57 +01001277static DisplaySurface* defaultallocator_create_displaysurface(int width, int height)
1278{
1279 DisplaySurface *surface = (DisplaySurface*) qemu_mallocz(sizeof(DisplaySurface));
1280
Jes Sorensenffe8b822011-03-16 13:33:30 +01001281 int linesize = width * 4;
1282 qemu_alloc_display(surface, width, height, linesize,
1283 qemu_default_pixelformat(32), 0);
Paolo Bonzini98b50082010-02-11 00:29:57 +01001284 return surface;
1285}
1286
1287static DisplaySurface* defaultallocator_resize_displaysurface(DisplaySurface *surface,
1288 int width, int height)
1289{
Jes Sorensenffe8b822011-03-16 13:33:30 +01001290 int linesize = width * 4;
1291 qemu_alloc_display(surface, width, height, linesize,
1292 qemu_default_pixelformat(32), 0);
1293 return surface;
1294}
1295
1296void qemu_alloc_display(DisplaySurface *surface, int width, int height,
1297 int linesize, PixelFormat pf, int newflags)
1298{
1299 void *data;
Paolo Bonzini98b50082010-02-11 00:29:57 +01001300 surface->width = width;
1301 surface->height = height;
Jes Sorensenffe8b822011-03-16 13:33:30 +01001302 surface->linesize = linesize;
1303 surface->pf = pf;
1304 if (surface->flags & QEMU_ALLOCATED_FLAG) {
1305 data = qemu_realloc(surface->data,
1306 surface->linesize * surface->height);
1307 } else {
1308 data = qemu_malloc(surface->linesize * surface->height);
1309 }
1310 surface->data = (uint8_t *)data;
1311 surface->flags = newflags | QEMU_ALLOCATED_FLAG;
Paolo Bonzini98b50082010-02-11 00:29:57 +01001312#ifdef HOST_WORDS_BIGENDIAN
Jes Sorensenffe8b822011-03-16 13:33:30 +01001313 surface->flags |= QEMU_BIG_ENDIAN_FLAG;
Paolo Bonzini98b50082010-02-11 00:29:57 +01001314#endif
Paolo Bonzini98b50082010-02-11 00:29:57 +01001315}
1316
1317DisplaySurface* qemu_create_displaysurface_from(int width, int height, int bpp,
1318 int linesize, uint8_t *data)
1319{
1320 DisplaySurface *surface = (DisplaySurface*) qemu_mallocz(sizeof(DisplaySurface));
1321
1322 surface->width = width;
1323 surface->height = height;
1324 surface->linesize = linesize;
1325 surface->pf = qemu_default_pixelformat(bpp);
1326#ifdef HOST_WORDS_BIGENDIAN
1327 surface->flags = QEMU_BIG_ENDIAN_FLAG;
1328#endif
1329 surface->data = data;
1330
1331 return surface;
1332}
1333
1334static void defaultallocator_free_displaysurface(DisplaySurface *surface)
1335{
1336 if (surface == NULL)
1337 return;
1338 if (surface->flags & QEMU_ALLOCATED_FLAG)
1339 qemu_free(surface->data);
1340 qemu_free(surface);
1341}
1342
1343static struct DisplayAllocator default_allocator = {
1344 defaultallocator_create_displaysurface,
1345 defaultallocator_resize_displaysurface,
1346 defaultallocator_free_displaysurface
1347};
1348
1349static void dumb_display_init(void)
1350{
1351 DisplayState *ds = qemu_mallocz(sizeof(DisplayState));
1352 ds->allocator = &default_allocator;
1353 ds->surface = qemu_create_displaysurface(ds, 640, 480);
1354 register_displaystate(ds);
1355}
1356
1357/***********************************************************/
1358/* register display */
1359
1360void register_displaystate(DisplayState *ds)
1361{
1362 DisplayState **s;
1363 s = &display_state;
1364 while (*s != NULL)
1365 s = &(*s)->next;
1366 ds->next = NULL;
1367 *s = ds;
1368}
1369
1370DisplayState *get_displaystate(void)
1371{
1372 if (!display_state) {
1373 dumb_display_init ();
1374 }
1375 return display_state;
1376}
1377
1378DisplayAllocator *register_displayallocator(DisplayState *ds, DisplayAllocator *da)
1379{
1380 if(ds->allocator == &default_allocator) {
1381 DisplaySurface *surf;
1382 surf = da->create_displaysurface(ds_get_width(ds), ds_get_height(ds));
1383 defaultallocator_free_displaysurface(ds->surface);
1384 ds->surface = surf;
1385 ds->allocator = da;
1386 }
1387 return ds->allocator;
1388}
1389
aliguori3023f332009-01-16 19:04:14 +00001390DisplayState *graphic_console_init(vga_hw_update_ptr update,
1391 vga_hw_invalidate_ptr invalidate,
1392 vga_hw_screen_dump_ptr screen_dump,
1393 vga_hw_text_update_ptr text_update,
1394 void *opaque)
bellarde7f0ad52004-07-14 17:28:59 +00001395{
pbrook95219892006-04-09 01:06:34 +00001396 TextConsole *s;
aliguori3023f332009-01-16 19:04:14 +00001397 DisplayState *ds;
aurel32f0f2f972009-01-16 21:13:49 +00001398
aliguori3023f332009-01-16 19:04:14 +00001399 ds = (DisplayState *) qemu_mallocz(sizeof(DisplayState));
aliguori7b5d76d2009-03-13 15:02:13 +00001400 ds->allocator = &default_allocator;
1401 ds->surface = qemu_create_displaysurface(ds, 640, 480);
pbrook95219892006-04-09 01:06:34 +00001402
thsaf3a9032007-07-11 23:14:59 +00001403 s = new_console(ds, GRAPHIC_CONSOLE);
aliguori3023f332009-01-16 19:04:14 +00001404 if (s == NULL) {
aliguori7b5d76d2009-03-13 15:02:13 +00001405 qemu_free_displaysurface(ds);
aliguori3023f332009-01-16 19:04:14 +00001406 qemu_free(ds);
1407 return NULL;
1408 }
pbrook95219892006-04-09 01:06:34 +00001409 s->hw_update = update;
1410 s->hw_invalidate = invalidate;
1411 s->hw_screen_dump = screen_dump;
balrog4d3b6f62008-02-10 16:33:14 +00001412 s->hw_text_update = text_update;
pbrook95219892006-04-09 01:06:34 +00001413 s->hw = opaque;
aliguori3023f332009-01-16 19:04:14 +00001414
aurel32f0f2f972009-01-16 21:13:49 +00001415 register_displaystate(ds);
aliguori3023f332009-01-16 19:04:14 +00001416 return ds;
pbrook95219892006-04-09 01:06:34 +00001417}
1418
1419int is_graphic_console(void)
1420{
balrog4d3b6f62008-02-10 16:33:14 +00001421 return active_console && active_console->console_type == GRAPHIC_CONSOLE;
bellarde7f0ad52004-07-14 17:28:59 +00001422}
1423
balrogc21bbcf2008-09-24 03:32:33 +00001424int is_fixedsize_console(void)
1425{
1426 return active_console && active_console->console_type != TEXT_CONSOLE;
1427}
1428
balroga528b802007-10-30 22:38:53 +00001429void console_color_init(DisplayState *ds)
1430{
1431 int i, j;
1432 for (j = 0; j < 2; j++) {
1433 for (i = 0; i < 8; i++) {
aurel32f0f2f972009-01-16 21:13:49 +00001434 color_table[j][i] = col_expand(ds,
balroga528b802007-10-30 22:38:53 +00001435 vga_get_color(ds, color_table_rgb[j][i]));
1436 }
1437 }
1438}
1439
aliguori2796dae2009-01-16 20:23:27 +00001440static int n_text_consoles;
1441static CharDriverState *text_consoles[128];
aliguori2796dae2009-01-16 20:23:27 +00001442
Paolo Bonzini41048332010-12-23 13:42:52 +01001443static void text_console_set_echo(CharDriverState *chr, bool echo)
1444{
1445 TextConsole *s = chr->opaque;
1446
1447 s->echo = echo;
1448}
1449
Paolo Bonzini44b37b92010-12-23 13:42:53 +01001450static void text_console_do_init(CharDriverState *chr, DisplayState *ds)
bellarde7f0ad52004-07-14 17:28:59 +00001451{
bellarde7f0ad52004-07-14 17:28:59 +00001452 TextConsole *s;
bellarde7f0ad52004-07-14 17:28:59 +00001453 static int color_inited;
pbrook6d6f7c22006-03-11 15:35:30 +00001454
Paolo Bonzini491e1142010-12-23 13:42:51 +01001455 s = chr->opaque;
Gerd Hoffmann6ea314d2009-09-10 10:58:49 +02001456
bellarde7f0ad52004-07-14 17:28:59 +00001457 chr->chr_write = console_puts;
bellard6fcfafb2004-08-01 21:48:30 +00001458 chr->chr_send_event = console_send_event;
1459
bellarde15d7372006-06-25 16:26:29 +00001460 s->out_fifo.buf = s->out_fifo_buf;
1461 s->out_fifo.buf_size = sizeof(s->out_fifo_buf);
Paolo Bonzini7bd427d2011-03-11 16:47:48 +01001462 s->kbd_timer = qemu_new_timer_ms(rt_clock, kbd_send_chars, s);
aliguori3023f332009-01-16 19:04:14 +00001463 s->ds = ds;
ths3b46e622007-09-17 08:09:54 +00001464
bellarde7f0ad52004-07-14 17:28:59 +00001465 if (!color_inited) {
1466 color_inited = 1;
balroga528b802007-10-30 22:38:53 +00001467 console_color_init(s->ds);
bellarde7f0ad52004-07-14 17:28:59 +00001468 }
1469 s->y_displayed = 0;
1470 s->y_base = 0;
1471 s->total_height = DEFAULT_BACKSCROLL;
1472 s->x = 0;
1473 s->y = 0;
Paolo Bonzini491e1142010-12-23 13:42:51 +01001474 if (s->console_type == TEXT_CONSOLE) {
1475 s->g_width = ds_get_width(s->ds);
1476 s->g_height = ds_get_height(s->ds);
1477 }
pbrook6d6f7c22006-03-11 15:35:30 +00001478
balrog4d3b6f62008-02-10 16:33:14 +00001479 s->hw_invalidate = text_console_invalidate;
1480 s->hw_text_update = text_console_update;
1481 s->hw = s;
1482
pbrook6d6f7c22006-03-11 15:35:30 +00001483 /* Set text attribute defaults */
1484 s->t_attrib_default.bold = 0;
1485 s->t_attrib_default.uline = 0;
1486 s->t_attrib_default.blink = 0;
1487 s->t_attrib_default.invers = 0;
1488 s->t_attrib_default.unvisible = 0;
1489 s->t_attrib_default.fgcol = COLOR_WHITE;
1490 s->t_attrib_default.bgcol = COLOR_BLACK;
pbrook6d6f7c22006-03-11 15:35:30 +00001491 /* set current text attributes to default */
1492 s->t_attrib = s->t_attrib_default;
bellarde7f0ad52004-07-14 17:28:59 +00001493 text_console_resize(s);
1494
Gerd Hoffmann51bfa4d2009-12-08 13:11:39 +01001495 if (chr->label) {
1496 char msg[128];
1497 int len;
1498
Gerd Hoffmann735ba582009-12-08 13:11:40 +01001499 s->t_attrib.bgcol = COLOR_BLUE;
Gerd Hoffmann51bfa4d2009-12-08 13:11:39 +01001500 len = snprintf(msg, sizeof(msg), "%s console\r\n", chr->label);
1501 console_puts(chr, (uint8_t*)msg, len);
Gerd Hoffmann735ba582009-12-08 13:11:40 +01001502 s->t_attrib = s->t_attrib_default;
Gerd Hoffmann51bfa4d2009-12-08 13:11:39 +01001503 }
1504
Amit Shah127338e2009-11-03 19:59:56 +05301505 qemu_chr_generic_open(chr);
aurel32ceecf1d2009-01-18 14:08:04 +00001506 if (chr->init)
1507 chr->init(chr);
bellarde7f0ad52004-07-14 17:28:59 +00001508}
pbrookc60e08d2008-07-01 16:24:38 +00001509
Gerd Hoffmann6ea314d2009-09-10 10:58:49 +02001510CharDriverState *text_console_init(QemuOpts *opts)
aliguori2796dae2009-01-16 20:23:27 +00001511{
1512 CharDriverState *chr;
Paolo Bonzini491e1142010-12-23 13:42:51 +01001513 TextConsole *s;
1514 unsigned width;
1515 unsigned height;
aliguori2796dae2009-01-16 20:23:27 +00001516
1517 chr = qemu_mallocz(sizeof(CharDriverState));
aliguori2796dae2009-01-16 20:23:27 +00001518
1519 if (n_text_consoles == 128) {
1520 fprintf(stderr, "Too many text consoles\n");
1521 exit(1);
1522 }
1523 text_consoles[n_text_consoles] = chr;
aliguori2796dae2009-01-16 20:23:27 +00001524 n_text_consoles++;
1525
Paolo Bonzini491e1142010-12-23 13:42:51 +01001526 width = qemu_opt_get_number(opts, "width", 0);
1527 if (width == 0)
1528 width = qemu_opt_get_number(opts, "cols", 0) * FONT_WIDTH;
1529
1530 height = qemu_opt_get_number(opts, "height", 0);
1531 if (height == 0)
1532 height = qemu_opt_get_number(opts, "rows", 0) * FONT_HEIGHT;
1533
1534 if (width == 0 || height == 0) {
1535 s = new_console(NULL, TEXT_CONSOLE);
1536 } else {
1537 s = new_console(NULL, TEXT_CONSOLE_FIXED_SIZE);
1538 }
1539
1540 if (!s) {
1541 free(chr);
1542 return NULL;
1543 }
1544
1545 s->chr = chr;
1546 s->g_width = width;
1547 s->g_height = height;
1548 chr->opaque = s;
Paolo Bonzini41048332010-12-23 13:42:52 +01001549 chr->chr_set_echo = text_console_set_echo;
aliguori2796dae2009-01-16 20:23:27 +00001550 return chr;
1551}
1552
1553void text_consoles_set_display(DisplayState *ds)
1554{
1555 int i;
1556
1557 for (i = 0; i < n_text_consoles; i++) {
Paolo Bonzini44b37b92010-12-23 13:42:53 +01001558 text_console_do_init(text_consoles[i], ds);
aliguori2796dae2009-01-16 20:23:27 +00001559 }
1560
1561 n_text_consoles = 0;
1562}
1563
aliguori3023f332009-01-16 19:04:14 +00001564void qemu_console_resize(DisplayState *ds, int width, int height)
pbrookc60e08d2008-07-01 16:24:38 +00001565{
aliguori42aa98e2009-01-16 21:01:48 +00001566 TextConsole *s = get_graphic_console(ds);
aliguorif497f142009-01-21 19:18:00 +00001567 if (!s) return;
1568
aliguori3023f332009-01-16 19:04:14 +00001569 s->g_width = width;
1570 s->g_height = height;
1571 if (is_graphic_console()) {
aliguori7b5d76d2009-03-13 15:02:13 +00001572 ds->surface = qemu_resize_displaysurface(ds, width, height);
aliguori3023f332009-01-16 19:04:14 +00001573 dpy_resize(ds);
pbrookc60e08d2008-07-01 16:24:38 +00001574 }
1575}
balrog38334f72008-09-24 02:21:24 +00001576
aliguori3023f332009-01-16 19:04:14 +00001577void qemu_console_copy(DisplayState *ds, int src_x, int src_y,
1578 int dst_x, int dst_y, int w, int h)
balrogc21bbcf2008-09-24 03:32:33 +00001579{
aliguori3023f332009-01-16 19:04:14 +00001580 if (is_graphic_console()) {
1581 dpy_copy(ds, src_x, src_y, dst_x, dst_y, w, h);
balrog38334f72008-09-24 02:21:24 +00001582 }
1583}
aliguori7d957bd2009-01-15 22:14:11 +00001584
malc0da2ea12009-01-23 19:56:19 +00001585PixelFormat qemu_different_endianness_pixelformat(int bpp)
aliguori7d957bd2009-01-15 22:14:11 +00001586{
1587 PixelFormat pf;
1588
1589 memset(&pf, 0x00, sizeof(PixelFormat));
1590
1591 pf.bits_per_pixel = bpp;
1592 pf.bytes_per_pixel = bpp / 8;
1593 pf.depth = bpp == 32 ? 24 : bpp;
1594
1595 switch (bpp) {
malc0da2ea12009-01-23 19:56:19 +00001596 case 24:
1597 pf.rmask = 0x000000FF;
1598 pf.gmask = 0x0000FF00;
1599 pf.bmask = 0x00FF0000;
1600 pf.rmax = 255;
1601 pf.gmax = 255;
1602 pf.bmax = 255;
1603 pf.rshift = 0;
1604 pf.gshift = 8;
1605 pf.bshift = 16;
aliguori90a1e3c2009-01-26 15:37:30 +00001606 pf.rbits = 8;
1607 pf.gbits = 8;
1608 pf.bbits = 8;
aliguori7d957bd2009-01-15 22:14:11 +00001609 break;
malc0da2ea12009-01-23 19:56:19 +00001610 case 32:
1611 pf.rmask = 0x0000FF00;
1612 pf.gmask = 0x00FF0000;
1613 pf.bmask = 0xFF000000;
1614 pf.amask = 0x00000000;
1615 pf.amax = 255;
1616 pf.rmax = 255;
1617 pf.gmax = 255;
1618 pf.bmax = 255;
1619 pf.ashift = 0;
1620 pf.rshift = 8;
1621 pf.gshift = 16;
1622 pf.bshift = 24;
aliguori90a1e3c2009-01-26 15:37:30 +00001623 pf.rbits = 8;
1624 pf.gbits = 8;
1625 pf.bbits = 8;
1626 pf.abits = 8;
malc0da2ea12009-01-23 19:56:19 +00001627 break;
1628 default:
1629 break;
1630 }
1631 return pf;
1632}
1633
1634PixelFormat qemu_default_pixelformat(int bpp)
1635{
1636 PixelFormat pf;
1637
1638 memset(&pf, 0x00, sizeof(PixelFormat));
1639
1640 pf.bits_per_pixel = bpp;
1641 pf.bytes_per_pixel = bpp / 8;
1642 pf.depth = bpp == 32 ? 24 : bpp;
1643
1644 switch (bpp) {
Gerd Hoffmannb6278082010-05-21 11:59:14 +02001645 case 15:
1646 pf.bits_per_pixel = 16;
1647 pf.bytes_per_pixel = 2;
1648 pf.rmask = 0x00007c00;
1649 pf.gmask = 0x000003E0;
1650 pf.bmask = 0x0000001F;
1651 pf.rmax = 31;
1652 pf.gmax = 31;
1653 pf.bmax = 31;
1654 pf.rshift = 10;
1655 pf.gshift = 5;
1656 pf.bshift = 0;
1657 pf.rbits = 5;
1658 pf.gbits = 5;
1659 pf.bbits = 5;
1660 break;
aliguori7d957bd2009-01-15 22:14:11 +00001661 case 16:
1662 pf.rmask = 0x0000F800;
1663 pf.gmask = 0x000007E0;
1664 pf.bmask = 0x0000001F;
1665 pf.rmax = 31;
1666 pf.gmax = 63;
1667 pf.bmax = 31;
1668 pf.rshift = 11;
1669 pf.gshift = 5;
1670 pf.bshift = 0;
aliguori90a1e3c2009-01-26 15:37:30 +00001671 pf.rbits = 5;
1672 pf.gbits = 6;
1673 pf.bbits = 5;
aliguori7d957bd2009-01-15 22:14:11 +00001674 break;
1675 case 24:
aliguori7d957bd2009-01-15 22:14:11 +00001676 pf.rmask = 0x00FF0000;
1677 pf.gmask = 0x0000FF00;
1678 pf.bmask = 0x000000FF;
1679 pf.rmax = 255;
1680 pf.gmax = 255;
1681 pf.bmax = 255;
1682 pf.rshift = 16;
1683 pf.gshift = 8;
1684 pf.bshift = 0;
aliguori90a1e3c2009-01-26 15:37:30 +00001685 pf.rbits = 8;
1686 pf.gbits = 8;
1687 pf.bbits = 8;
malc0da2ea12009-01-23 19:56:19 +00001688 case 32:
1689 pf.rmask = 0x00FF0000;
1690 pf.gmask = 0x0000FF00;
1691 pf.bmask = 0x000000FF;
1692 pf.amax = 255;
1693 pf.rmax = 255;
1694 pf.gmax = 255;
1695 pf.bmax = 255;
1696 pf.ashift = 24;
1697 pf.rshift = 16;
1698 pf.gshift = 8;
1699 pf.bshift = 0;
aliguori90a1e3c2009-01-26 15:37:30 +00001700 pf.rbits = 8;
1701 pf.gbits = 8;
1702 pf.bbits = 8;
1703 pf.abits = 8;
aliguori7d957bd2009-01-15 22:14:11 +00001704 break;
1705 default:
1706 break;
1707 }
1708 return pf;
1709}