blob: 698bc10a60c124846f09e9e30a2de4bf7b8bee54 [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;
bellarde7f0ad52004-07-14 17:28:59 +0000140
pbrook14778c22009-01-21 03:02:52 +0000141 int update_x0;
142 int update_y0;
143 int update_x1;
144 int update_y1;
145
bellarde7f0ad52004-07-14 17:28:59 +0000146 enum TTYState state;
147 int esc_params[MAX_ESC_PARAMS];
148 int nb_esc_params;
149
pbrooke5b0bc42007-01-27 23:46:43 +0000150 CharDriverState *chr;
bellarde15d7372006-06-25 16:26:29 +0000151 /* fifo for key pressed */
152 QEMUFIFO out_fifo;
153 uint8_t out_fifo_buf[16];
154 QEMUTimer *kbd_timer;
bellarde7f0ad52004-07-14 17:28:59 +0000155};
156
Paolo Bonzini98b50082010-02-11 00:29:57 +0100157static DisplayState *display_state;
bellarde7f0ad52004-07-14 17:28:59 +0000158static TextConsole *active_console;
159static TextConsole *consoles[MAX_CONSOLES];
160static int nb_consoles = 0;
161
pbrook95219892006-04-09 01:06:34 +0000162void vga_hw_update(void)
163{
thsadb47962007-01-16 23:02:36 +0000164 if (active_console && active_console->hw_update)
pbrook95219892006-04-09 01:06:34 +0000165 active_console->hw_update(active_console->hw);
166}
167
168void vga_hw_invalidate(void)
169{
Gerd Hoffmann26572b82010-05-20 15:23:06 +0200170 if (active_console && active_console->hw_invalidate)
pbrook95219892006-04-09 01:06:34 +0000171 active_console->hw_invalidate(active_console->hw);
172}
173
174void vga_hw_screen_dump(const char *filename)
175{
balrog8571c052008-07-19 13:04:26 +0000176 TextConsole *previous_active_console;
177
178 previous_active_console = active_console;
179 active_console = consoles[0];
180 /* There is currently no way of specifying which screen we want to dump,
aurel327b455222008-09-02 00:09:16 +0000181 so always dump the first one. */
pbrook95219892006-04-09 01:06:34 +0000182 if (consoles[0]->hw_screen_dump)
183 consoles[0]->hw_screen_dump(consoles[0]->hw, filename);
balrog8571c052008-07-19 13:04:26 +0000184 active_console = previous_active_console;
pbrook95219892006-04-09 01:06:34 +0000185}
186
Anthony Liguoric227f092009-10-01 16:12:16 -0500187void vga_hw_text_update(console_ch_t *chardata)
balrog4d3b6f62008-02-10 16:33:14 +0000188{
189 if (active_console && active_console->hw_text_update)
190 active_console->hw_text_update(active_console->hw, chardata);
191}
192
bellarde7f0ad52004-07-14 17:28:59 +0000193/* convert a RGBA color to a color index usable in graphic primitives */
194static unsigned int vga_get_color(DisplayState *ds, unsigned int rgba)
195{
196 unsigned int r, g, b, color;
197
aliguori0e1f5a02008-11-24 19:29:13 +0000198 switch(ds_get_bits_per_pixel(ds)) {
bellarde7f0ad52004-07-14 17:28:59 +0000199#if 0
200 case 8:
201 r = (rgba >> 16) & 0xff;
202 g = (rgba >> 8) & 0xff;
203 b = (rgba) & 0xff;
ths5fafdf22007-09-16 21:08:06 +0000204 color = (rgb_to_index[r] * 6 * 6) +
205 (rgb_to_index[g] * 6) +
bellarde7f0ad52004-07-14 17:28:59 +0000206 (rgb_to_index[b]);
207 break;
208#endif
209 case 15:
210 r = (rgba >> 16) & 0xff;
211 g = (rgba >> 8) & 0xff;
212 b = (rgba) & 0xff;
213 color = ((r >> 3) << 10) | ((g >> 3) << 5) | (b >> 3);
214 break;
215 case 16:
216 r = (rgba >> 16) & 0xff;
217 g = (rgba >> 8) & 0xff;
218 b = (rgba) & 0xff;
219 color = ((r >> 3) << 11) | ((g >> 2) << 5) | (b >> 3);
220 break;
221 case 32:
222 default:
223 color = rgba;
224 break;
225 }
226 return color;
227}
228
ths5fafdf22007-09-16 21:08:06 +0000229static void vga_fill_rect (DisplayState *ds,
bellarde7f0ad52004-07-14 17:28:59 +0000230 int posx, int posy, int width, int height, uint32_t color)
231{
232 uint8_t *d, *d1;
233 int x, y, bpp;
ths3b46e622007-09-17 08:09:54 +0000234
aliguori0e1f5a02008-11-24 19:29:13 +0000235 bpp = (ds_get_bits_per_pixel(ds) + 7) >> 3;
236 d1 = ds_get_data(ds) +
237 ds_get_linesize(ds) * posy + bpp * posx;
bellarde7f0ad52004-07-14 17:28:59 +0000238 for (y = 0; y < height; y++) {
239 d = d1;
240 switch(bpp) {
241 case 1:
242 for (x = 0; x < width; x++) {
243 *((uint8_t *)d) = color;
244 d++;
245 }
246 break;
247 case 2:
248 for (x = 0; x < width; x++) {
249 *((uint16_t *)d) = color;
250 d += 2;
251 }
252 break;
253 case 4:
254 for (x = 0; x < width; x++) {
255 *((uint32_t *)d) = color;
256 d += 4;
257 }
258 break;
259 }
aliguori0e1f5a02008-11-24 19:29:13 +0000260 d1 += ds_get_linesize(ds);
bellarde7f0ad52004-07-14 17:28:59 +0000261 }
262}
263
264/* copy from (xs, ys) to (xd, yd) a rectangle of size (w, h) */
265static void vga_bitblt(DisplayState *ds, int xs, int ys, int xd, int yd, int w, int h)
266{
267 const uint8_t *s;
268 uint8_t *d;
269 int wb, y, bpp;
270
aliguori0e1f5a02008-11-24 19:29:13 +0000271 bpp = (ds_get_bits_per_pixel(ds) + 7) >> 3;
bellarde7f0ad52004-07-14 17:28:59 +0000272 wb = w * bpp;
273 if (yd <= ys) {
aliguori0e1f5a02008-11-24 19:29:13 +0000274 s = ds_get_data(ds) +
275 ds_get_linesize(ds) * ys + bpp * xs;
276 d = ds_get_data(ds) +
277 ds_get_linesize(ds) * yd + bpp * xd;
bellarde7f0ad52004-07-14 17:28:59 +0000278 for (y = 0; y < h; y++) {
279 memmove(d, s, wb);
aliguori0e1f5a02008-11-24 19:29:13 +0000280 d += ds_get_linesize(ds);
281 s += ds_get_linesize(ds);
bellarde7f0ad52004-07-14 17:28:59 +0000282 }
283 } else {
aliguori0e1f5a02008-11-24 19:29:13 +0000284 s = ds_get_data(ds) +
285 ds_get_linesize(ds) * (ys + h - 1) + bpp * xs;
286 d = ds_get_data(ds) +
287 ds_get_linesize(ds) * (yd + h - 1) + bpp * xd;
bellarde7f0ad52004-07-14 17:28:59 +0000288 for (y = 0; y < h; y++) {
289 memmove(d, s, wb);
aliguori0e1f5a02008-11-24 19:29:13 +0000290 d -= ds_get_linesize(ds);
291 s -= ds_get_linesize(ds);
bellarde7f0ad52004-07-14 17:28:59 +0000292 }
293 }
294}
295
296/***********************************************************/
297/* basic char display */
298
299#define FONT_HEIGHT 16
300#define FONT_WIDTH 8
301
302#include "vgafont.h"
303
304#define cbswap_32(__x) \
305((uint32_t)( \
306 (((uint32_t)(__x) & (uint32_t)0x000000ffUL) << 24) | \
307 (((uint32_t)(__x) & (uint32_t)0x0000ff00UL) << 8) | \
308 (((uint32_t)(__x) & (uint32_t)0x00ff0000UL) >> 8) | \
309 (((uint32_t)(__x) & (uint32_t)0xff000000UL) >> 24) ))
310
Juan Quintelae2542fe2009-07-27 16:13:06 +0200311#ifdef HOST_WORDS_BIGENDIAN
bellarde7f0ad52004-07-14 17:28:59 +0000312#define PAT(x) x
313#else
314#define PAT(x) cbswap_32(x)
315#endif
316
317static const uint32_t dmask16[16] = {
318 PAT(0x00000000),
319 PAT(0x000000ff),
320 PAT(0x0000ff00),
321 PAT(0x0000ffff),
322 PAT(0x00ff0000),
323 PAT(0x00ff00ff),
324 PAT(0x00ffff00),
325 PAT(0x00ffffff),
326 PAT(0xff000000),
327 PAT(0xff0000ff),
328 PAT(0xff00ff00),
329 PAT(0xff00ffff),
330 PAT(0xffff0000),
331 PAT(0xffff00ff),
332 PAT(0xffffff00),
333 PAT(0xffffffff),
334};
335
336static const uint32_t dmask4[4] = {
337 PAT(0x00000000),
338 PAT(0x0000ffff),
339 PAT(0xffff0000),
340 PAT(0xffffffff),
341};
342
pbrook6d6f7c22006-03-11 15:35:30 +0000343static uint32_t color_table[2][8];
bellarde7f0ad52004-07-14 17:28:59 +0000344
pbrook6d6f7c22006-03-11 15:35:30 +0000345enum color_names {
346 COLOR_BLACK = 0,
347 COLOR_RED = 1,
348 COLOR_GREEN = 2,
349 COLOR_YELLOW = 3,
350 COLOR_BLUE = 4,
351 COLOR_MAGENTA = 5,
352 COLOR_CYAN = 6,
353 COLOR_WHITE = 7
354};
355
356static const uint32_t color_table_rgb[2][8] = {
357 { /* dark */
bellard26489842006-06-25 17:37:36 +0000358 QEMU_RGB(0x00, 0x00, 0x00), /* black */
359 QEMU_RGB(0xaa, 0x00, 0x00), /* red */
360 QEMU_RGB(0x00, 0xaa, 0x00), /* green */
361 QEMU_RGB(0xaa, 0xaa, 0x00), /* yellow */
362 QEMU_RGB(0x00, 0x00, 0xaa), /* blue */
363 QEMU_RGB(0xaa, 0x00, 0xaa), /* magenta */
364 QEMU_RGB(0x00, 0xaa, 0xaa), /* cyan */
365 QEMU_RGB(0xaa, 0xaa, 0xaa), /* white */
pbrook6d6f7c22006-03-11 15:35:30 +0000366 },
367 { /* bright */
bellard26489842006-06-25 17:37:36 +0000368 QEMU_RGB(0x00, 0x00, 0x00), /* black */
369 QEMU_RGB(0xff, 0x00, 0x00), /* red */
370 QEMU_RGB(0x00, 0xff, 0x00), /* green */
371 QEMU_RGB(0xff, 0xff, 0x00), /* yellow */
372 QEMU_RGB(0x00, 0x00, 0xff), /* blue */
373 QEMU_RGB(0xff, 0x00, 0xff), /* magenta */
374 QEMU_RGB(0x00, 0xff, 0xff), /* cyan */
375 QEMU_RGB(0xff, 0xff, 0xff), /* white */
pbrook6d6f7c22006-03-11 15:35:30 +0000376 }
bellarde7f0ad52004-07-14 17:28:59 +0000377};
378
379static inline unsigned int col_expand(DisplayState *ds, unsigned int col)
380{
aliguori0e1f5a02008-11-24 19:29:13 +0000381 switch(ds_get_bits_per_pixel(ds)) {
bellarde7f0ad52004-07-14 17:28:59 +0000382 case 8:
383 col |= col << 8;
384 col |= col << 16;
385 break;
386 case 15:
387 case 16:
388 col |= col << 16;
389 break;
390 default:
391 break;
392 }
393
394 return col;
395}
pbrook6d6f7c22006-03-11 15:35:30 +0000396#ifdef DEBUG_CONSOLE
397static void console_print_text_attributes(TextAttributes *t_attrib, char ch)
398{
399 if (t_attrib->bold) {
400 printf("b");
401 } else {
402 printf(" ");
403 }
404 if (t_attrib->uline) {
405 printf("u");
406 } else {
407 printf(" ");
408 }
409 if (t_attrib->blink) {
410 printf("l");
411 } else {
412 printf(" ");
413 }
414 if (t_attrib->invers) {
415 printf("i");
416 } else {
417 printf(" ");
418 }
419 if (t_attrib->unvisible) {
420 printf("n");
421 } else {
422 printf(" ");
423 }
424
425 printf(" fg: %d bg: %d ch:'%2X' '%c'\n", t_attrib->fgcol, t_attrib->bgcol, ch, ch);
426}
427#endif
bellarde7f0ad52004-07-14 17:28:59 +0000428
ths5fafdf22007-09-16 21:08:06 +0000429static void vga_putcharxy(DisplayState *ds, int x, int y, int ch,
pbrook6d6f7c22006-03-11 15:35:30 +0000430 TextAttributes *t_attrib)
bellarde7f0ad52004-07-14 17:28:59 +0000431{
432 uint8_t *d;
433 const uint8_t *font_ptr;
434 unsigned int font_data, linesize, xorcol, bpp;
435 int i;
pbrook6d6f7c22006-03-11 15:35:30 +0000436 unsigned int fgcol, bgcol;
437
438#ifdef DEBUG_CONSOLE
439 printf("x: %2i y: %2i", x, y);
440 console_print_text_attributes(t_attrib, ch);
441#endif
442
443 if (t_attrib->invers) {
444 bgcol = color_table[t_attrib->bold][t_attrib->fgcol];
445 fgcol = color_table[t_attrib->bold][t_attrib->bgcol];
446 } else {
447 fgcol = color_table[t_attrib->bold][t_attrib->fgcol];
448 bgcol = color_table[t_attrib->bold][t_attrib->bgcol];
449 }
bellarde7f0ad52004-07-14 17:28:59 +0000450
aliguori0e1f5a02008-11-24 19:29:13 +0000451 bpp = (ds_get_bits_per_pixel(ds) + 7) >> 3;
452 d = ds_get_data(ds) +
453 ds_get_linesize(ds) * y * FONT_HEIGHT + bpp * x * FONT_WIDTH;
454 linesize = ds_get_linesize(ds);
bellarde7f0ad52004-07-14 17:28:59 +0000455 font_ptr = vgafont16 + FONT_HEIGHT * ch;
456 xorcol = bgcol ^ fgcol;
aliguori0e1f5a02008-11-24 19:29:13 +0000457 switch(ds_get_bits_per_pixel(ds)) {
bellarde7f0ad52004-07-14 17:28:59 +0000458 case 8:
459 for(i = 0; i < FONT_HEIGHT; i++) {
460 font_data = *font_ptr++;
pbrook6d6f7c22006-03-11 15:35:30 +0000461 if (t_attrib->uline
462 && ((i == FONT_HEIGHT - 2) || (i == FONT_HEIGHT - 3))) {
463 font_data = 0xFFFF;
464 }
bellarde7f0ad52004-07-14 17:28:59 +0000465 ((uint32_t *)d)[0] = (dmask16[(font_data >> 4)] & xorcol) ^ bgcol;
466 ((uint32_t *)d)[1] = (dmask16[(font_data >> 0) & 0xf] & xorcol) ^ bgcol;
467 d += linesize;
468 }
469 break;
470 case 16:
471 case 15:
472 for(i = 0; i < FONT_HEIGHT; i++) {
473 font_data = *font_ptr++;
pbrook6d6f7c22006-03-11 15:35:30 +0000474 if (t_attrib->uline
475 && ((i == FONT_HEIGHT - 2) || (i == FONT_HEIGHT - 3))) {
476 font_data = 0xFFFF;
477 }
bellarde7f0ad52004-07-14 17:28:59 +0000478 ((uint32_t *)d)[0] = (dmask4[(font_data >> 6)] & xorcol) ^ bgcol;
479 ((uint32_t *)d)[1] = (dmask4[(font_data >> 4) & 3] & xorcol) ^ bgcol;
480 ((uint32_t *)d)[2] = (dmask4[(font_data >> 2) & 3] & xorcol) ^ bgcol;
481 ((uint32_t *)d)[3] = (dmask4[(font_data >> 0) & 3] & xorcol) ^ bgcol;
482 d += linesize;
483 }
484 break;
485 case 32:
486 for(i = 0; i < FONT_HEIGHT; i++) {
487 font_data = *font_ptr++;
pbrook6d6f7c22006-03-11 15:35:30 +0000488 if (t_attrib->uline && ((i == FONT_HEIGHT - 2) || (i == FONT_HEIGHT - 3))) {
489 font_data = 0xFFFF;
490 }
bellarde7f0ad52004-07-14 17:28:59 +0000491 ((uint32_t *)d)[0] = (-((font_data >> 7)) & xorcol) ^ bgcol;
492 ((uint32_t *)d)[1] = (-((font_data >> 6) & 1) & xorcol) ^ bgcol;
493 ((uint32_t *)d)[2] = (-((font_data >> 5) & 1) & xorcol) ^ bgcol;
494 ((uint32_t *)d)[3] = (-((font_data >> 4) & 1) & xorcol) ^ bgcol;
495 ((uint32_t *)d)[4] = (-((font_data >> 3) & 1) & xorcol) ^ bgcol;
496 ((uint32_t *)d)[5] = (-((font_data >> 2) & 1) & xorcol) ^ bgcol;
497 ((uint32_t *)d)[6] = (-((font_data >> 1) & 1) & xorcol) ^ bgcol;
498 ((uint32_t *)d)[7] = (-((font_data >> 0) & 1) & xorcol) ^ bgcol;
499 d += linesize;
500 }
501 break;
502 }
503}
504
505static void text_console_resize(TextConsole *s)
506{
507 TextCell *cells, *c, *c1;
508 int w1, x, y, last_width;
509
510 last_width = s->width;
511 s->width = s->g_width / FONT_WIDTH;
512 s->height = s->g_height / FONT_HEIGHT;
513
514 w1 = last_width;
515 if (s->width < w1)
516 w1 = s->width;
517
518 cells = qemu_malloc(s->width * s->total_height * sizeof(TextCell));
519 for(y = 0; y < s->total_height; y++) {
520 c = &cells[y * s->width];
521 if (w1 > 0) {
522 c1 = &s->cells[y * last_width];
523 for(x = 0; x < w1; x++) {
524 *c++ = *c1++;
525 }
526 }
527 for(x = w1; x < s->width; x++) {
528 c->ch = ' ';
pbrook6d6f7c22006-03-11 15:35:30 +0000529 c->t_attrib = s->t_attrib_default;
bellarde7f0ad52004-07-14 17:28:59 +0000530 c++;
531 }
532 }
balroga528b802007-10-30 22:38:53 +0000533 qemu_free(s->cells);
bellarde7f0ad52004-07-14 17:28:59 +0000534 s->cells = cells;
535}
536
balrog4d3b6f62008-02-10 16:33:14 +0000537static inline void text_update_xy(TextConsole *s, int x, int y)
538{
539 s->text_x[0] = MIN(s->text_x[0], x);
540 s->text_x[1] = MAX(s->text_x[1], x);
541 s->text_y[0] = MIN(s->text_y[0], y);
542 s->text_y[1] = MAX(s->text_y[1], y);
543}
544
pbrook14778c22009-01-21 03:02:52 +0000545static void invalidate_xy(TextConsole *s, int x, int y)
546{
547 if (s->update_x0 > x * FONT_WIDTH)
548 s->update_x0 = x * FONT_WIDTH;
549 if (s->update_y0 > y * FONT_HEIGHT)
550 s->update_y0 = y * FONT_HEIGHT;
551 if (s->update_x1 < (x + 1) * FONT_WIDTH)
552 s->update_x1 = (x + 1) * FONT_WIDTH;
553 if (s->update_y1 < (y + 1) * FONT_HEIGHT)
554 s->update_y1 = (y + 1) * FONT_HEIGHT;
555}
556
bellarde7f0ad52004-07-14 17:28:59 +0000557static void update_xy(TextConsole *s, int x, int y)
558{
559 TextCell *c;
560 int y1, y2;
561
562 if (s == active_console) {
aliguori0e1f5a02008-11-24 19:29:13 +0000563 if (!ds_get_bits_per_pixel(s->ds)) {
balrog4d3b6f62008-02-10 16:33:14 +0000564 text_update_xy(s, x, y);
565 return;
566 }
567
bellarde7f0ad52004-07-14 17:28:59 +0000568 y1 = (s->y_base + y) % s->total_height;
569 y2 = y1 - s->y_displayed;
570 if (y2 < 0)
571 y2 += s->total_height;
572 if (y2 < s->height) {
573 c = &s->cells[y1 * s->width + x];
ths5fafdf22007-09-16 21:08:06 +0000574 vga_putcharxy(s->ds, x, y2, c->ch,
pbrook6d6f7c22006-03-11 15:35:30 +0000575 &(c->t_attrib));
pbrook14778c22009-01-21 03:02:52 +0000576 invalidate_xy(s, x, y2);
bellarde7f0ad52004-07-14 17:28:59 +0000577 }
578 }
579}
580
581static void console_show_cursor(TextConsole *s, int show)
582{
583 TextCell *c;
584 int y, y1;
585
586 if (s == active_console) {
thsed8276a2007-02-10 22:37:56 +0000587 int x = s->x;
balrog4d3b6f62008-02-10 16:33:14 +0000588
aliguori0e1f5a02008-11-24 19:29:13 +0000589 if (!ds_get_bits_per_pixel(s->ds)) {
balrog4d3b6f62008-02-10 16:33:14 +0000590 s->cursor_invalidate = 1;
591 return;
592 }
593
thsed8276a2007-02-10 22:37:56 +0000594 if (x >= s->width) {
595 x = s->width - 1;
596 }
bellarde7f0ad52004-07-14 17:28:59 +0000597 y1 = (s->y_base + s->y) % s->total_height;
598 y = y1 - s->y_displayed;
599 if (y < 0)
600 y += s->total_height;
601 if (y < s->height) {
thsed8276a2007-02-10 22:37:56 +0000602 c = &s->cells[y1 * s->width + x];
bellarde7f0ad52004-07-14 17:28:59 +0000603 if (show) {
pbrook6d6f7c22006-03-11 15:35:30 +0000604 TextAttributes t_attrib = s->t_attrib_default;
605 t_attrib.invers = !(t_attrib.invers); /* invert fg and bg */
thsed8276a2007-02-10 22:37:56 +0000606 vga_putcharxy(s->ds, x, y, c->ch, &t_attrib);
bellarde7f0ad52004-07-14 17:28:59 +0000607 } else {
thsed8276a2007-02-10 22:37:56 +0000608 vga_putcharxy(s->ds, x, y, c->ch, &(c->t_attrib));
bellarde7f0ad52004-07-14 17:28:59 +0000609 }
pbrook14778c22009-01-21 03:02:52 +0000610 invalidate_xy(s, x, y);
bellarde7f0ad52004-07-14 17:28:59 +0000611 }
612 }
613}
614
615static void console_refresh(TextConsole *s)
616{
617 TextCell *c;
618 int x, y, y1;
619
ths5fafdf22007-09-16 21:08:06 +0000620 if (s != active_console)
bellarde7f0ad52004-07-14 17:28:59 +0000621 return;
aliguori0e1f5a02008-11-24 19:29:13 +0000622 if (!ds_get_bits_per_pixel(s->ds)) {
balrog4d3b6f62008-02-10 16:33:14 +0000623 s->text_x[0] = 0;
624 s->text_y[0] = 0;
625 s->text_x[1] = s->width - 1;
626 s->text_y[1] = s->height - 1;
627 s->cursor_invalidate = 1;
628 return;
629 }
bellarde7f0ad52004-07-14 17:28:59 +0000630
aliguori0e1f5a02008-11-24 19:29:13 +0000631 vga_fill_rect(s->ds, 0, 0, ds_get_width(s->ds), ds_get_height(s->ds),
pbrook6d6f7c22006-03-11 15:35:30 +0000632 color_table[0][COLOR_BLACK]);
bellarde7f0ad52004-07-14 17:28:59 +0000633 y1 = s->y_displayed;
634 for(y = 0; y < s->height; y++) {
635 c = s->cells + y1 * s->width;
636 for(x = 0; x < s->width; x++) {
ths5fafdf22007-09-16 21:08:06 +0000637 vga_putcharxy(s->ds, x, y, c->ch,
pbrook6d6f7c22006-03-11 15:35:30 +0000638 &(c->t_attrib));
bellarde7f0ad52004-07-14 17:28:59 +0000639 c++;
640 }
641 if (++y1 == s->total_height)
642 y1 = 0;
643 }
bellarde7f0ad52004-07-14 17:28:59 +0000644 console_show_cursor(s, 1);
pbrook14778c22009-01-21 03:02:52 +0000645 dpy_update(s->ds, 0, 0, ds_get_width(s->ds), ds_get_height(s->ds));
bellarde7f0ad52004-07-14 17:28:59 +0000646}
647
648static void console_scroll(int ydelta)
649{
650 TextConsole *s;
651 int i, y1;
ths3b46e622007-09-17 08:09:54 +0000652
bellarde7f0ad52004-07-14 17:28:59 +0000653 s = active_console;
thsaf3a9032007-07-11 23:14:59 +0000654 if (!s || (s->console_type == GRAPHIC_CONSOLE))
bellarde7f0ad52004-07-14 17:28:59 +0000655 return;
656
657 if (ydelta > 0) {
658 for(i = 0; i < ydelta; i++) {
659 if (s->y_displayed == s->y_base)
660 break;
661 if (++s->y_displayed == s->total_height)
662 s->y_displayed = 0;
663 }
664 } else {
665 ydelta = -ydelta;
666 i = s->backscroll_height;
667 if (i > s->total_height - s->height)
668 i = s->total_height - s->height;
669 y1 = s->y_base - i;
670 if (y1 < 0)
671 y1 += s->total_height;
672 for(i = 0; i < ydelta; i++) {
673 if (s->y_displayed == y1)
674 break;
675 if (--s->y_displayed < 0)
676 s->y_displayed = s->total_height - 1;
677 }
678 }
679 console_refresh(s);
680}
681
682static void console_put_lf(TextConsole *s)
683{
684 TextCell *c;
685 int x, y1;
686
bellarde7f0ad52004-07-14 17:28:59 +0000687 s->y++;
688 if (s->y >= s->height) {
689 s->y = s->height - 1;
pbrook6d6f7c22006-03-11 15:35:30 +0000690
bellarde7f0ad52004-07-14 17:28:59 +0000691 if (s->y_displayed == s->y_base) {
692 if (++s->y_displayed == s->total_height)
693 s->y_displayed = 0;
694 }
695 if (++s->y_base == s->total_height)
696 s->y_base = 0;
697 if (s->backscroll_height < s->total_height)
698 s->backscroll_height++;
699 y1 = (s->y_base + s->height - 1) % s->total_height;
700 c = &s->cells[y1 * s->width];
701 for(x = 0; x < s->width; x++) {
702 c->ch = ' ';
pbrook6d6f7c22006-03-11 15:35:30 +0000703 c->t_attrib = s->t_attrib_default;
bellarde7f0ad52004-07-14 17:28:59 +0000704 c++;
705 }
706 if (s == active_console && s->y_displayed == s->y_base) {
aliguori0e1f5a02008-11-24 19:29:13 +0000707 if (!ds_get_bits_per_pixel(s->ds)) {
balrog4d3b6f62008-02-10 16:33:14 +0000708 s->text_x[0] = 0;
709 s->text_y[0] = 0;
710 s->text_x[1] = s->width - 1;
711 s->text_y[1] = s->height - 1;
712 return;
713 }
714
ths5fafdf22007-09-16 21:08:06 +0000715 vga_bitblt(s->ds, 0, FONT_HEIGHT, 0, 0,
716 s->width * FONT_WIDTH,
bellarde7f0ad52004-07-14 17:28:59 +0000717 (s->height - 1) * FONT_HEIGHT);
718 vga_fill_rect(s->ds, 0, (s->height - 1) * FONT_HEIGHT,
ths5fafdf22007-09-16 21:08:06 +0000719 s->width * FONT_WIDTH, FONT_HEIGHT,
pbrook6d6f7c22006-03-11 15:35:30 +0000720 color_table[0][s->t_attrib_default.bgcol]);
pbrook14778c22009-01-21 03:02:52 +0000721 s->update_x0 = 0;
722 s->update_y0 = 0;
723 s->update_x1 = s->width * FONT_WIDTH;
724 s->update_y1 = s->height * FONT_HEIGHT;
bellarde7f0ad52004-07-14 17:28:59 +0000725 }
726 }
727}
728
pbrook6d6f7c22006-03-11 15:35:30 +0000729/* Set console attributes depending on the current escape codes.
730 * NOTE: I know this code is not very efficient (checking every color for it
731 * self) but it is more readable and better maintainable.
732 */
733static void console_handle_escape(TextConsole *s)
734{
735 int i;
736
pbrook6d6f7c22006-03-11 15:35:30 +0000737 for (i=0; i<s->nb_esc_params; i++) {
738 switch (s->esc_params[i]) {
739 case 0: /* reset all console attributes to default */
740 s->t_attrib = s->t_attrib_default;
741 break;
742 case 1:
743 s->t_attrib.bold = 1;
744 break;
745 case 4:
746 s->t_attrib.uline = 1;
747 break;
748 case 5:
749 s->t_attrib.blink = 1;
750 break;
751 case 7:
752 s->t_attrib.invers = 1;
753 break;
754 case 8:
755 s->t_attrib.unvisible = 1;
756 break;
757 case 22:
758 s->t_attrib.bold = 0;
759 break;
760 case 24:
761 s->t_attrib.uline = 0;
762 break;
763 case 25:
764 s->t_attrib.blink = 0;
765 break;
766 case 27:
767 s->t_attrib.invers = 0;
768 break;
769 case 28:
770 s->t_attrib.unvisible = 0;
771 break;
772 /* set foreground color */
773 case 30:
774 s->t_attrib.fgcol=COLOR_BLACK;
775 break;
776 case 31:
777 s->t_attrib.fgcol=COLOR_RED;
778 break;
779 case 32:
780 s->t_attrib.fgcol=COLOR_GREEN;
781 break;
782 case 33:
783 s->t_attrib.fgcol=COLOR_YELLOW;
784 break;
785 case 34:
786 s->t_attrib.fgcol=COLOR_BLUE;
787 break;
788 case 35:
789 s->t_attrib.fgcol=COLOR_MAGENTA;
790 break;
791 case 36:
792 s->t_attrib.fgcol=COLOR_CYAN;
793 break;
794 case 37:
795 s->t_attrib.fgcol=COLOR_WHITE;
796 break;
797 /* set background color */
798 case 40:
799 s->t_attrib.bgcol=COLOR_BLACK;
800 break;
801 case 41:
802 s->t_attrib.bgcol=COLOR_RED;
803 break;
804 case 42:
805 s->t_attrib.bgcol=COLOR_GREEN;
806 break;
807 case 43:
808 s->t_attrib.bgcol=COLOR_YELLOW;
809 break;
810 case 44:
811 s->t_attrib.bgcol=COLOR_BLUE;
812 break;
813 case 45:
814 s->t_attrib.bgcol=COLOR_MAGENTA;
815 break;
816 case 46:
817 s->t_attrib.bgcol=COLOR_CYAN;
818 break;
819 case 47:
820 s->t_attrib.bgcol=COLOR_WHITE;
821 break;
822 }
823 }
824}
825
thsadb47962007-01-16 23:02:36 +0000826static void console_clear_xy(TextConsole *s, int x, int y)
827{
828 int y1 = (s->y_base + y) % s->total_height;
829 TextCell *c = &s->cells[y1 * s->width + x];
830 c->ch = ' ';
831 c->t_attrib = s->t_attrib_default;
thsadb47962007-01-16 23:02:36 +0000832 update_xy(s, x, y);
833}
834
bellarde7f0ad52004-07-14 17:28:59 +0000835static void console_putchar(TextConsole *s, int ch)
836{
837 TextCell *c;
thsadb47962007-01-16 23:02:36 +0000838 int y1, i;
839 int x, y;
bellarde7f0ad52004-07-14 17:28:59 +0000840
841 switch(s->state) {
842 case TTY_STATE_NORM:
843 switch(ch) {
pbrook6d6f7c22006-03-11 15:35:30 +0000844 case '\r': /* carriage return */
bellarde7f0ad52004-07-14 17:28:59 +0000845 s->x = 0;
846 break;
pbrook6d6f7c22006-03-11 15:35:30 +0000847 case '\n': /* newline */
bellarde7f0ad52004-07-14 17:28:59 +0000848 console_put_lf(s);
849 break;
pbrook6d6f7c22006-03-11 15:35:30 +0000850 case '\b': /* backspace */
ths5fafdf22007-09-16 21:08:06 +0000851 if (s->x > 0)
bellarde15d7372006-06-25 16:26:29 +0000852 s->x--;
pbrook6d6f7c22006-03-11 15:35:30 +0000853 break;
854 case '\t': /* tabspace */
855 if (s->x + (8 - (s->x % 8)) > s->width) {
bellardbd468842006-07-14 20:24:31 +0000856 s->x = 0;
pbrook6d6f7c22006-03-11 15:35:30 +0000857 console_put_lf(s);
858 } else {
859 s->x = s->x + (8 - (s->x % 8));
860 }
861 break;
862 case '\a': /* alert aka. bell */
863 /* TODO: has to be implemented */
864 break;
thsadb47962007-01-16 23:02:36 +0000865 case 14:
866 /* SI (shift in), character set 0 (ignored) */
867 break;
868 case 15:
869 /* SO (shift out), character set 1 (ignored) */
870 break;
pbrook6d6f7c22006-03-11 15:35:30 +0000871 case 27: /* esc (introducing an escape sequence) */
bellarde7f0ad52004-07-14 17:28:59 +0000872 s->state = TTY_STATE_ESC;
873 break;
874 default:
thsed8276a2007-02-10 22:37:56 +0000875 if (s->x >= s->width) {
876 /* line wrap */
877 s->x = 0;
878 console_put_lf(s);
thsadb47962007-01-16 23:02:36 +0000879 }
bellarde7f0ad52004-07-14 17:28:59 +0000880 y1 = (s->y_base + s->y) % s->total_height;
881 c = &s->cells[y1 * s->width + s->x];
882 c->ch = ch;
pbrook6d6f7c22006-03-11 15:35:30 +0000883 c->t_attrib = s->t_attrib;
bellarde7f0ad52004-07-14 17:28:59 +0000884 update_xy(s, s->x, s->y);
885 s->x++;
bellarde7f0ad52004-07-14 17:28:59 +0000886 break;
887 }
888 break;
pbrook6d6f7c22006-03-11 15:35:30 +0000889 case TTY_STATE_ESC: /* check if it is a terminal escape sequence */
bellarde7f0ad52004-07-14 17:28:59 +0000890 if (ch == '[') {
891 for(i=0;i<MAX_ESC_PARAMS;i++)
892 s->esc_params[i] = 0;
893 s->nb_esc_params = 0;
894 s->state = TTY_STATE_CSI;
895 } else {
896 s->state = TTY_STATE_NORM;
897 }
898 break;
pbrook6d6f7c22006-03-11 15:35:30 +0000899 case TTY_STATE_CSI: /* handle escape sequence parameters */
bellarde7f0ad52004-07-14 17:28:59 +0000900 if (ch >= '0' && ch <= '9') {
901 if (s->nb_esc_params < MAX_ESC_PARAMS) {
ths5fafdf22007-09-16 21:08:06 +0000902 s->esc_params[s->nb_esc_params] =
bellarde7f0ad52004-07-14 17:28:59 +0000903 s->esc_params[s->nb_esc_params] * 10 + ch - '0';
904 }
905 } else {
906 s->nb_esc_params++;
907 if (ch == ';')
908 break;
thsadb47962007-01-16 23:02:36 +0000909#ifdef DEBUG_CONSOLE
910 fprintf(stderr, "escape sequence CSI%d;%d%c, %d parameters\n",
911 s->esc_params[0], s->esc_params[1], ch, s->nb_esc_params);
912#endif
bellarde7f0ad52004-07-14 17:28:59 +0000913 s->state = TTY_STATE_NORM;
914 switch(ch) {
thsadb47962007-01-16 23:02:36 +0000915 case 'A':
916 /* move cursor up */
917 if (s->esc_params[0] == 0) {
918 s->esc_params[0] = 1;
919 }
920 s->y -= s->esc_params[0];
921 if (s->y < 0) {
922 s->y = 0;
bellarde7f0ad52004-07-14 17:28:59 +0000923 }
924 break;
thsadb47962007-01-16 23:02:36 +0000925 case 'B':
926 /* move cursor down */
927 if (s->esc_params[0] == 0) {
928 s->esc_params[0] = 1;
929 }
930 s->y += s->esc_params[0];
931 if (s->y >= s->height) {
932 s->y = s->height - 1;
933 }
934 break;
935 case 'C':
936 /* move cursor right */
937 if (s->esc_params[0] == 0) {
938 s->esc_params[0] = 1;
939 }
940 s->x += s->esc_params[0];
941 if (s->x >= s->width) {
942 s->x = s->width - 1;
943 }
944 break;
945 case 'D':
946 /* move cursor left */
947 if (s->esc_params[0] == 0) {
948 s->esc_params[0] = 1;
949 }
950 s->x -= s->esc_params[0];
951 if (s->x < 0) {
952 s->x = 0;
953 }
954 break;
955 case 'G':
956 /* move cursor to column */
957 s->x = s->esc_params[0] - 1;
958 if (s->x < 0) {
959 s->x = 0;
960 }
961 break;
962 case 'f':
963 case 'H':
964 /* move cursor to row, column */
965 s->x = s->esc_params[1] - 1;
966 if (s->x < 0) {
967 s->x = 0;
968 }
969 s->y = s->esc_params[0] - 1;
970 if (s->y < 0) {
971 s->y = 0;
972 }
973 break;
974 case 'J':
975 switch (s->esc_params[0]) {
976 case 0:
977 /* clear to end of screen */
978 for (y = s->y; y < s->height; y++) {
979 for (x = 0; x < s->width; x++) {
980 if (y == s->y && x < s->x) {
981 continue;
982 }
983 console_clear_xy(s, x, y);
984 }
985 }
986 break;
987 case 1:
988 /* clear from beginning of screen */
989 for (y = 0; y <= s->y; y++) {
990 for (x = 0; x < s->width; x++) {
991 if (y == s->y && x > s->x) {
992 break;
993 }
994 console_clear_xy(s, x, y);
995 }
996 }
997 break;
998 case 2:
999 /* clear entire screen */
1000 for (y = 0; y <= s->height; y++) {
1001 for (x = 0; x < s->width; x++) {
1002 console_clear_xy(s, x, y);
1003 }
1004 }
1005 break;
1006 }
1007 case 'K':
1008 switch (s->esc_params[0]) {
1009 case 0:
1010 /* clear to eol */
1011 for(x = s->x; x < s->width; x++) {
1012 console_clear_xy(s, x, s->y);
1013 }
1014 break;
1015 case 1:
1016 /* clear from beginning of line */
1017 for (x = 0; x <= s->x; x++) {
1018 console_clear_xy(s, x, s->y);
1019 }
1020 break;
1021 case 2:
1022 /* clear entire line */
1023 for(x = 0; x < s->width; x++) {
1024 console_clear_xy(s, x, s->y);
1025 }
bellarde7f0ad52004-07-14 17:28:59 +00001026 break;
1027 }
thsadb47962007-01-16 23:02:36 +00001028 break;
1029 case 'm':
pbrook6d6f7c22006-03-11 15:35:30 +00001030 console_handle_escape(s);
bellarde7f0ad52004-07-14 17:28:59 +00001031 break;
thsadb47962007-01-16 23:02:36 +00001032 case 'n':
1033 /* report cursor position */
1034 /* TODO: send ESC[row;colR */
1035 break;
1036 case 's':
1037 /* save cursor position */
1038 s->x_saved = s->x;
1039 s->y_saved = s->y;
1040 break;
1041 case 'u':
1042 /* restore cursor position */
1043 s->x = s->x_saved;
1044 s->y = s->y_saved;
1045 break;
1046 default:
1047#ifdef DEBUG_CONSOLE
1048 fprintf(stderr, "unhandled escape character '%c'\n", ch);
1049#endif
1050 break;
1051 }
1052 break;
bellarde7f0ad52004-07-14 17:28:59 +00001053 }
1054 }
1055}
1056
1057void console_select(unsigned int index)
1058{
1059 TextConsole *s;
pbrook6d6f7c22006-03-11 15:35:30 +00001060
bellarde7f0ad52004-07-14 17:28:59 +00001061 if (index >= MAX_CONSOLES)
1062 return;
aliguori7d957bd2009-01-15 22:14:11 +00001063 active_console->g_width = ds_get_width(active_console->ds);
1064 active_console->g_height = ds_get_height(active_console->ds);
bellarde7f0ad52004-07-14 17:28:59 +00001065 s = consoles[index];
1066 if (s) {
aliguori7d957bd2009-01-15 22:14:11 +00001067 DisplayState *ds = s->ds;
bellarde7f0ad52004-07-14 17:28:59 +00001068 active_console = s;
aliguori68f00992009-01-21 18:59:12 +00001069 if (ds_get_bits_per_pixel(s->ds)) {
aliguori7b5d76d2009-03-13 15:02:13 +00001070 ds->surface = qemu_resize_displaysurface(ds, s->g_width, s->g_height);
aliguori68f00992009-01-21 18:59:12 +00001071 } else {
1072 s->ds->surface->width = s->width;
1073 s->ds->surface->height = s->height;
1074 }
aliguori7d957bd2009-01-15 22:14:11 +00001075 dpy_resize(s->ds);
balrog4d3b6f62008-02-10 16:33:14 +00001076 vga_hw_invalidate();
bellarde7f0ad52004-07-14 17:28:59 +00001077 }
1078}
1079
1080static int console_puts(CharDriverState *chr, const uint8_t *buf, int len)
1081{
1082 TextConsole *s = chr->opaque;
1083 int i;
1084
pbrook14778c22009-01-21 03:02:52 +00001085 s->update_x0 = s->width * FONT_WIDTH;
1086 s->update_y0 = s->height * FONT_HEIGHT;
1087 s->update_x1 = 0;
1088 s->update_y1 = 0;
bellarde7f0ad52004-07-14 17:28:59 +00001089 console_show_cursor(s, 0);
1090 for(i = 0; i < len; i++) {
1091 console_putchar(s, buf[i]);
1092 }
1093 console_show_cursor(s, 1);
pbrook14778c22009-01-21 03:02:52 +00001094 if (ds_get_bits_per_pixel(s->ds) && s->update_x0 < s->update_x1) {
1095 dpy_update(s->ds, s->update_x0, s->update_y0,
1096 s->update_x1 - s->update_x0,
1097 s->update_y1 - s->update_y0);
1098 }
bellarde7f0ad52004-07-14 17:28:59 +00001099 return len;
1100}
1101
bellard6fcfafb2004-08-01 21:48:30 +00001102static void console_send_event(CharDriverState *chr, int event)
1103{
1104 TextConsole *s = chr->opaque;
1105 int i;
1106
1107 if (event == CHR_EVENT_FOCUS) {
1108 for(i = 0; i < nb_consoles; i++) {
1109 if (consoles[i] == s) {
1110 console_select(i);
1111 break;
1112 }
1113 }
1114 }
1115}
1116
bellarde15d7372006-06-25 16:26:29 +00001117static void kbd_send_chars(void *opaque)
1118{
1119 TextConsole *s = opaque;
1120 int len;
1121 uint8_t buf[16];
ths3b46e622007-09-17 08:09:54 +00001122
pbrooke5b0bc42007-01-27 23:46:43 +00001123 len = qemu_chr_can_read(s->chr);
bellarde15d7372006-06-25 16:26:29 +00001124 if (len > s->out_fifo.count)
1125 len = s->out_fifo.count;
1126 if (len > 0) {
1127 if (len > sizeof(buf))
1128 len = sizeof(buf);
1129 qemu_fifo_read(&s->out_fifo, buf, len);
pbrooke5b0bc42007-01-27 23:46:43 +00001130 qemu_chr_read(s->chr, buf, len);
bellarde15d7372006-06-25 16:26:29 +00001131 }
1132 /* characters are pending: we send them a bit later (XXX:
1133 horrible, should change char device API) */
1134 if (s->out_fifo.count > 0) {
1135 qemu_mod_timer(s->kbd_timer, qemu_get_clock(rt_clock) + 1);
1136 }
1137}
1138
bellarde7f0ad52004-07-14 17:28:59 +00001139/* called when an ascii key is pressed */
1140void kbd_put_keysym(int keysym)
1141{
1142 TextConsole *s;
1143 uint8_t buf[16], *q;
1144 int c;
1145
1146 s = active_console;
thsaf3a9032007-07-11 23:14:59 +00001147 if (!s || (s->console_type == GRAPHIC_CONSOLE))
bellarde7f0ad52004-07-14 17:28:59 +00001148 return;
1149
1150 switch(keysym) {
1151 case QEMU_KEY_CTRL_UP:
1152 console_scroll(-1);
1153 break;
1154 case QEMU_KEY_CTRL_DOWN:
1155 console_scroll(1);
1156 break;
1157 case QEMU_KEY_CTRL_PAGEUP:
1158 console_scroll(-10);
1159 break;
1160 case QEMU_KEY_CTRL_PAGEDOWN:
1161 console_scroll(10);
1162 break;
1163 default:
bellarde15d7372006-06-25 16:26:29 +00001164 /* convert the QEMU keysym to VT100 key string */
1165 q = buf;
1166 if (keysym >= 0xe100 && keysym <= 0xe11f) {
1167 *q++ = '\033';
1168 *q++ = '[';
1169 c = keysym - 0xe100;
1170 if (c >= 10)
1171 *q++ = '0' + (c / 10);
1172 *q++ = '0' + (c % 10);
1173 *q++ = '~';
1174 } else if (keysym >= 0xe120 && keysym <= 0xe17f) {
1175 *q++ = '\033';
1176 *q++ = '[';
1177 *q++ = keysym & 0xff;
1178 } else {
bellarde7f0ad52004-07-14 17:28:59 +00001179 *q++ = keysym;
bellarde15d7372006-06-25 16:26:29 +00001180 }
pbrooke5b0bc42007-01-27 23:46:43 +00001181 if (s->chr->chr_read) {
bellarde15d7372006-06-25 16:26:29 +00001182 qemu_fifo_write(&s->out_fifo, buf, q - buf);
1183 kbd_send_chars(s);
bellarde7f0ad52004-07-14 17:28:59 +00001184 }
1185 break;
1186 }
1187}
1188
balrog4d3b6f62008-02-10 16:33:14 +00001189static void text_console_invalidate(void *opaque)
1190{
1191 TextConsole *s = (TextConsole *) opaque;
aliguori68f00992009-01-21 18:59:12 +00001192 if (!ds_get_bits_per_pixel(s->ds) && s->console_type == TEXT_CONSOLE) {
1193 s->g_width = ds_get_width(s->ds);
1194 s->g_height = ds_get_height(s->ds);
1195 text_console_resize(s);
1196 }
balrog4d3b6f62008-02-10 16:33:14 +00001197 console_refresh(s);
1198}
1199
Anthony Liguoric227f092009-10-01 16:12:16 -05001200static void text_console_update(void *opaque, console_ch_t *chardata)
balrog4d3b6f62008-02-10 16:33:14 +00001201{
1202 TextConsole *s = (TextConsole *) opaque;
1203 int i, j, src;
1204
1205 if (s->text_x[0] <= s->text_x[1]) {
1206 src = (s->y_base + s->text_y[0]) * s->width;
1207 chardata += s->text_y[0] * s->width;
1208 for (i = s->text_y[0]; i <= s->text_y[1]; i ++)
1209 for (j = 0; j < s->width; j ++, src ++)
1210 console_write_ch(chardata ++, s->cells[src].ch |
1211 (s->cells[src].t_attrib.fgcol << 12) |
1212 (s->cells[src].t_attrib.bgcol << 8) |
1213 (s->cells[src].t_attrib.bold << 21));
1214 dpy_update(s->ds, s->text_x[0], s->text_y[0],
1215 s->text_x[1] - s->text_x[0], i - s->text_y[0]);
1216 s->text_x[0] = s->width;
1217 s->text_y[0] = s->height;
1218 s->text_x[1] = 0;
1219 s->text_y[1] = 0;
1220 }
1221 if (s->cursor_invalidate) {
1222 dpy_cursor(s->ds, s->x, s->y);
1223 s->cursor_invalidate = 0;
1224 }
1225}
1226
aliguori42aa98e2009-01-16 21:01:48 +00001227static TextConsole *get_graphic_console(DisplayState *ds)
blueswir1a147d622009-01-16 19:41:04 +00001228{
aliguori3023f332009-01-16 19:04:14 +00001229 int i;
1230 TextConsole *s;
1231 for (i = 0; i < nb_consoles; i++) {
1232 s = consoles[i];
aliguori42aa98e2009-01-16 21:01:48 +00001233 if (s->console_type == GRAPHIC_CONSOLE && s->ds == ds)
aliguori3023f332009-01-16 19:04:14 +00001234 return s;
1235 }
1236 return NULL;
1237}
1238
Anthony Liguoric227f092009-10-01 16:12:16 -05001239static TextConsole *new_console(DisplayState *ds, console_type_t console_type)
bellarde7f0ad52004-07-14 17:28:59 +00001240{
1241 TextConsole *s;
pbrook95219892006-04-09 01:06:34 +00001242 int i;
bellarde7f0ad52004-07-14 17:28:59 +00001243
1244 if (nb_consoles >= MAX_CONSOLES)
1245 return NULL;
1246 s = qemu_mallocz(sizeof(TextConsole));
thsaf3a9032007-07-11 23:14:59 +00001247 if (!active_console || ((active_console->console_type != GRAPHIC_CONSOLE) &&
1248 (console_type == GRAPHIC_CONSOLE))) {
bellarde7f0ad52004-07-14 17:28:59 +00001249 active_console = s;
thsaf3a9032007-07-11 23:14:59 +00001250 }
bellarde7f0ad52004-07-14 17:28:59 +00001251 s->ds = ds;
thsaf3a9032007-07-11 23:14:59 +00001252 s->console_type = console_type;
1253 if (console_type != GRAPHIC_CONSOLE) {
pbrook95219892006-04-09 01:06:34 +00001254 consoles[nb_consoles++] = s;
1255 } else {
1256 /* HACK: Put graphical consoles before text consoles. */
1257 for (i = nb_consoles; i > 0; i--) {
thsaf3a9032007-07-11 23:14:59 +00001258 if (consoles[i - 1]->console_type == GRAPHIC_CONSOLE)
pbrook95219892006-04-09 01:06:34 +00001259 break;
1260 consoles[i] = consoles[i - 1];
1261 }
1262 consoles[i] = s;
aliguori3023f332009-01-16 19:04:14 +00001263 nb_consoles++;
pbrook95219892006-04-09 01:06:34 +00001264 }
bellarde7f0ad52004-07-14 17:28:59 +00001265 return s;
1266}
1267
Paolo Bonzini98b50082010-02-11 00:29:57 +01001268static DisplaySurface* defaultallocator_create_displaysurface(int width, int height)
1269{
1270 DisplaySurface *surface = (DisplaySurface*) qemu_mallocz(sizeof(DisplaySurface));
1271
1272 surface->width = width;
1273 surface->height = height;
1274 surface->linesize = width * 4;
1275 surface->pf = qemu_default_pixelformat(32);
1276#ifdef HOST_WORDS_BIGENDIAN
1277 surface->flags = QEMU_ALLOCATED_FLAG | QEMU_BIG_ENDIAN_FLAG;
1278#else
1279 surface->flags = QEMU_ALLOCATED_FLAG;
1280#endif
1281 surface->data = (uint8_t*) qemu_mallocz(surface->linesize * surface->height);
1282
1283 return surface;
1284}
1285
1286static DisplaySurface* defaultallocator_resize_displaysurface(DisplaySurface *surface,
1287 int width, int height)
1288{
1289 surface->width = width;
1290 surface->height = height;
1291 surface->linesize = width * 4;
1292 surface->pf = qemu_default_pixelformat(32);
1293 if (surface->flags & QEMU_ALLOCATED_FLAG)
1294 surface->data = (uint8_t*) qemu_realloc(surface->data, surface->linesize * surface->height);
1295 else
1296 surface->data = (uint8_t*) qemu_malloc(surface->linesize * surface->height);
1297#ifdef HOST_WORDS_BIGENDIAN
1298 surface->flags = QEMU_ALLOCATED_FLAG | QEMU_BIG_ENDIAN_FLAG;
1299#else
1300 surface->flags = QEMU_ALLOCATED_FLAG;
1301#endif
1302
1303 return surface;
1304}
1305
1306DisplaySurface* qemu_create_displaysurface_from(int width, int height, int bpp,
1307 int linesize, uint8_t *data)
1308{
1309 DisplaySurface *surface = (DisplaySurface*) qemu_mallocz(sizeof(DisplaySurface));
1310
1311 surface->width = width;
1312 surface->height = height;
1313 surface->linesize = linesize;
1314 surface->pf = qemu_default_pixelformat(bpp);
1315#ifdef HOST_WORDS_BIGENDIAN
1316 surface->flags = QEMU_BIG_ENDIAN_FLAG;
1317#endif
1318 surface->data = data;
1319
1320 return surface;
1321}
1322
1323static void defaultallocator_free_displaysurface(DisplaySurface *surface)
1324{
1325 if (surface == NULL)
1326 return;
1327 if (surface->flags & QEMU_ALLOCATED_FLAG)
1328 qemu_free(surface->data);
1329 qemu_free(surface);
1330}
1331
1332static struct DisplayAllocator default_allocator = {
1333 defaultallocator_create_displaysurface,
1334 defaultallocator_resize_displaysurface,
1335 defaultallocator_free_displaysurface
1336};
1337
1338static void dumb_display_init(void)
1339{
1340 DisplayState *ds = qemu_mallocz(sizeof(DisplayState));
1341 ds->allocator = &default_allocator;
1342 ds->surface = qemu_create_displaysurface(ds, 640, 480);
1343 register_displaystate(ds);
1344}
1345
1346/***********************************************************/
1347/* register display */
1348
1349void register_displaystate(DisplayState *ds)
1350{
1351 DisplayState **s;
1352 s = &display_state;
1353 while (*s != NULL)
1354 s = &(*s)->next;
1355 ds->next = NULL;
1356 *s = ds;
1357}
1358
1359DisplayState *get_displaystate(void)
1360{
1361 if (!display_state) {
1362 dumb_display_init ();
1363 }
1364 return display_state;
1365}
1366
1367DisplayAllocator *register_displayallocator(DisplayState *ds, DisplayAllocator *da)
1368{
1369 if(ds->allocator == &default_allocator) {
1370 DisplaySurface *surf;
1371 surf = da->create_displaysurface(ds_get_width(ds), ds_get_height(ds));
1372 defaultallocator_free_displaysurface(ds->surface);
1373 ds->surface = surf;
1374 ds->allocator = da;
1375 }
1376 return ds->allocator;
1377}
1378
aliguori3023f332009-01-16 19:04:14 +00001379DisplayState *graphic_console_init(vga_hw_update_ptr update,
1380 vga_hw_invalidate_ptr invalidate,
1381 vga_hw_screen_dump_ptr screen_dump,
1382 vga_hw_text_update_ptr text_update,
1383 void *opaque)
bellarde7f0ad52004-07-14 17:28:59 +00001384{
pbrook95219892006-04-09 01:06:34 +00001385 TextConsole *s;
aliguori3023f332009-01-16 19:04:14 +00001386 DisplayState *ds;
aurel32f0f2f972009-01-16 21:13:49 +00001387
aliguori3023f332009-01-16 19:04:14 +00001388 ds = (DisplayState *) qemu_mallocz(sizeof(DisplayState));
aliguori7b5d76d2009-03-13 15:02:13 +00001389 ds->allocator = &default_allocator;
1390 ds->surface = qemu_create_displaysurface(ds, 640, 480);
pbrook95219892006-04-09 01:06:34 +00001391
thsaf3a9032007-07-11 23:14:59 +00001392 s = new_console(ds, GRAPHIC_CONSOLE);
aliguori3023f332009-01-16 19:04:14 +00001393 if (s == NULL) {
aliguori7b5d76d2009-03-13 15:02:13 +00001394 qemu_free_displaysurface(ds);
aliguori3023f332009-01-16 19:04:14 +00001395 qemu_free(ds);
1396 return NULL;
1397 }
pbrook95219892006-04-09 01:06:34 +00001398 s->hw_update = update;
1399 s->hw_invalidate = invalidate;
1400 s->hw_screen_dump = screen_dump;
balrog4d3b6f62008-02-10 16:33:14 +00001401 s->hw_text_update = text_update;
pbrook95219892006-04-09 01:06:34 +00001402 s->hw = opaque;
aliguori3023f332009-01-16 19:04:14 +00001403
aurel32f0f2f972009-01-16 21:13:49 +00001404 register_displaystate(ds);
aliguori3023f332009-01-16 19:04:14 +00001405 return ds;
pbrook95219892006-04-09 01:06:34 +00001406}
1407
1408int is_graphic_console(void)
1409{
balrog4d3b6f62008-02-10 16:33:14 +00001410 return active_console && active_console->console_type == GRAPHIC_CONSOLE;
bellarde7f0ad52004-07-14 17:28:59 +00001411}
1412
balrogc21bbcf2008-09-24 03:32:33 +00001413int is_fixedsize_console(void)
1414{
1415 return active_console && active_console->console_type != TEXT_CONSOLE;
1416}
1417
balroga528b802007-10-30 22:38:53 +00001418void console_color_init(DisplayState *ds)
1419{
1420 int i, j;
1421 for (j = 0; j < 2; j++) {
1422 for (i = 0; i < 8; i++) {
aurel32f0f2f972009-01-16 21:13:49 +00001423 color_table[j][i] = col_expand(ds,
balroga528b802007-10-30 22:38:53 +00001424 vga_get_color(ds, color_table_rgb[j][i]));
1425 }
1426 }
1427}
1428
aliguori2796dae2009-01-16 20:23:27 +00001429static int n_text_consoles;
1430static CharDriverState *text_consoles[128];
Gerd Hoffmann6ea314d2009-09-10 10:58:49 +02001431static QemuOpts *text_console_opts[128];
aliguori2796dae2009-01-16 20:23:27 +00001432
Gerd Hoffmann6ea314d2009-09-10 10:58:49 +02001433static void text_console_do_init(CharDriverState *chr, DisplayState *ds, QemuOpts *opts)
bellarde7f0ad52004-07-14 17:28:59 +00001434{
bellarde7f0ad52004-07-14 17:28:59 +00001435 TextConsole *s;
thsaf3a9032007-07-11 23:14:59 +00001436 unsigned width;
1437 unsigned height;
bellarde7f0ad52004-07-14 17:28:59 +00001438 static int color_inited;
pbrook6d6f7c22006-03-11 15:35:30 +00001439
Gerd Hoffmann6ea314d2009-09-10 10:58:49 +02001440 width = qemu_opt_get_number(opts, "width", 0);
1441 if (width == 0)
1442 width = qemu_opt_get_number(opts, "cols", 0) * FONT_WIDTH;
1443
1444 height = qemu_opt_get_number(opts, "height", 0);
1445 if (height == 0)
1446 height = qemu_opt_get_number(opts, "rows", 0) * FONT_HEIGHT;
1447
1448 if (width == 0 || height == 0) {
1449 s = new_console(ds, TEXT_CONSOLE);
1450 width = ds_get_width(s->ds);
1451 height = ds_get_height(s->ds);
1452 } else {
1453 s = new_console(ds, TEXT_CONSOLE_FIXED_SIZE);
1454 }
1455
bellarde7f0ad52004-07-14 17:28:59 +00001456 if (!s) {
1457 free(chr);
aliguorifdb868e2009-01-16 21:06:20 +00001458 return;
bellarde7f0ad52004-07-14 17:28:59 +00001459 }
bellarde7f0ad52004-07-14 17:28:59 +00001460 chr->opaque = s;
1461 chr->chr_write = console_puts;
bellard6fcfafb2004-08-01 21:48:30 +00001462 chr->chr_send_event = console_send_event;
1463
pbrooke5b0bc42007-01-27 23:46:43 +00001464 s->chr = chr;
bellarde15d7372006-06-25 16:26:29 +00001465 s->out_fifo.buf = s->out_fifo_buf;
1466 s->out_fifo.buf_size = sizeof(s->out_fifo_buf);
1467 s->kbd_timer = qemu_new_timer(rt_clock, kbd_send_chars, s);
aliguori3023f332009-01-16 19:04:14 +00001468 s->ds = ds;
ths3b46e622007-09-17 08:09:54 +00001469
bellarde7f0ad52004-07-14 17:28:59 +00001470 if (!color_inited) {
1471 color_inited = 1;
balroga528b802007-10-30 22:38:53 +00001472 console_color_init(s->ds);
bellarde7f0ad52004-07-14 17:28:59 +00001473 }
1474 s->y_displayed = 0;
1475 s->y_base = 0;
1476 s->total_height = DEFAULT_BACKSCROLL;
1477 s->x = 0;
1478 s->y = 0;
thsaf3a9032007-07-11 23:14:59 +00001479 s->g_width = width;
1480 s->g_height = height;
pbrook6d6f7c22006-03-11 15:35:30 +00001481
balrog4d3b6f62008-02-10 16:33:14 +00001482 s->hw_invalidate = text_console_invalidate;
1483 s->hw_text_update = text_console_update;
1484 s->hw = s;
1485
pbrook6d6f7c22006-03-11 15:35:30 +00001486 /* Set text attribute defaults */
1487 s->t_attrib_default.bold = 0;
1488 s->t_attrib_default.uline = 0;
1489 s->t_attrib_default.blink = 0;
1490 s->t_attrib_default.invers = 0;
1491 s->t_attrib_default.unvisible = 0;
1492 s->t_attrib_default.fgcol = COLOR_WHITE;
1493 s->t_attrib_default.bgcol = COLOR_BLACK;
pbrook6d6f7c22006-03-11 15:35:30 +00001494 /* set current text attributes to default */
1495 s->t_attrib = s->t_attrib_default;
bellarde7f0ad52004-07-14 17:28:59 +00001496 text_console_resize(s);
1497
Gerd Hoffmann51bfa4d2009-12-08 13:11:39 +01001498 if (chr->label) {
1499 char msg[128];
1500 int len;
1501
Gerd Hoffmann735ba582009-12-08 13:11:40 +01001502 s->t_attrib.bgcol = COLOR_BLUE;
Gerd Hoffmann51bfa4d2009-12-08 13:11:39 +01001503 len = snprintf(msg, sizeof(msg), "%s console\r\n", chr->label);
1504 console_puts(chr, (uint8_t*)msg, len);
Gerd Hoffmann735ba582009-12-08 13:11:40 +01001505 s->t_attrib = s->t_attrib_default;
Gerd Hoffmann51bfa4d2009-12-08 13:11:39 +01001506 }
1507
Amit Shah127338e2009-11-03 19:59:56 +05301508 qemu_chr_generic_open(chr);
aurel32ceecf1d2009-01-18 14:08:04 +00001509 if (chr->init)
1510 chr->init(chr);
bellarde7f0ad52004-07-14 17:28:59 +00001511}
pbrookc60e08d2008-07-01 16:24:38 +00001512
Gerd Hoffmann6ea314d2009-09-10 10:58:49 +02001513CharDriverState *text_console_init(QemuOpts *opts)
aliguori2796dae2009-01-16 20:23:27 +00001514{
1515 CharDriverState *chr;
1516
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;
Gerd Hoffmann6ea314d2009-09-10 10:58:49 +02001524 text_console_opts[n_text_consoles] = opts;
aliguori2796dae2009-01-16 20:23:27 +00001525 n_text_consoles++;
1526
1527 return chr;
1528}
1529
1530void text_consoles_set_display(DisplayState *ds)
1531{
1532 int i;
1533
1534 for (i = 0; i < n_text_consoles; i++) {
Gerd Hoffmann6ea314d2009-09-10 10:58:49 +02001535 text_console_do_init(text_consoles[i], ds, text_console_opts[i]);
1536 qemu_opts_del(text_console_opts[i]);
1537 text_console_opts[i] = NULL;
aliguori2796dae2009-01-16 20:23:27 +00001538 }
1539
1540 n_text_consoles = 0;
1541}
1542
aliguori3023f332009-01-16 19:04:14 +00001543void qemu_console_resize(DisplayState *ds, int width, int height)
pbrookc60e08d2008-07-01 16:24:38 +00001544{
aliguori42aa98e2009-01-16 21:01:48 +00001545 TextConsole *s = get_graphic_console(ds);
aliguorif497f142009-01-21 19:18:00 +00001546 if (!s) return;
1547
aliguori3023f332009-01-16 19:04:14 +00001548 s->g_width = width;
1549 s->g_height = height;
1550 if (is_graphic_console()) {
aliguori7b5d76d2009-03-13 15:02:13 +00001551 ds->surface = qemu_resize_displaysurface(ds, width, height);
aliguori3023f332009-01-16 19:04:14 +00001552 dpy_resize(ds);
pbrookc60e08d2008-07-01 16:24:38 +00001553 }
1554}
balrog38334f72008-09-24 02:21:24 +00001555
aliguori3023f332009-01-16 19:04:14 +00001556void qemu_console_copy(DisplayState *ds, int src_x, int src_y,
1557 int dst_x, int dst_y, int w, int h)
balrogc21bbcf2008-09-24 03:32:33 +00001558{
aliguori3023f332009-01-16 19:04:14 +00001559 if (is_graphic_console()) {
1560 dpy_copy(ds, src_x, src_y, dst_x, dst_y, w, h);
balrog38334f72008-09-24 02:21:24 +00001561 }
1562}
aliguori7d957bd2009-01-15 22:14:11 +00001563
malc0da2ea12009-01-23 19:56:19 +00001564PixelFormat qemu_different_endianness_pixelformat(int bpp)
aliguori7d957bd2009-01-15 22:14:11 +00001565{
1566 PixelFormat pf;
1567
1568 memset(&pf, 0x00, sizeof(PixelFormat));
1569
1570 pf.bits_per_pixel = bpp;
1571 pf.bytes_per_pixel = bpp / 8;
1572 pf.depth = bpp == 32 ? 24 : bpp;
1573
1574 switch (bpp) {
malc0da2ea12009-01-23 19:56:19 +00001575 case 24:
1576 pf.rmask = 0x000000FF;
1577 pf.gmask = 0x0000FF00;
1578 pf.bmask = 0x00FF0000;
1579 pf.rmax = 255;
1580 pf.gmax = 255;
1581 pf.bmax = 255;
1582 pf.rshift = 0;
1583 pf.gshift = 8;
1584 pf.bshift = 16;
aliguori90a1e3c2009-01-26 15:37:30 +00001585 pf.rbits = 8;
1586 pf.gbits = 8;
1587 pf.bbits = 8;
aliguori7d957bd2009-01-15 22:14:11 +00001588 break;
malc0da2ea12009-01-23 19:56:19 +00001589 case 32:
1590 pf.rmask = 0x0000FF00;
1591 pf.gmask = 0x00FF0000;
1592 pf.bmask = 0xFF000000;
1593 pf.amask = 0x00000000;
1594 pf.amax = 255;
1595 pf.rmax = 255;
1596 pf.gmax = 255;
1597 pf.bmax = 255;
1598 pf.ashift = 0;
1599 pf.rshift = 8;
1600 pf.gshift = 16;
1601 pf.bshift = 24;
aliguori90a1e3c2009-01-26 15:37:30 +00001602 pf.rbits = 8;
1603 pf.gbits = 8;
1604 pf.bbits = 8;
1605 pf.abits = 8;
malc0da2ea12009-01-23 19:56:19 +00001606 break;
1607 default:
1608 break;
1609 }
1610 return pf;
1611}
1612
1613PixelFormat qemu_default_pixelformat(int bpp)
1614{
1615 PixelFormat pf;
1616
1617 memset(&pf, 0x00, sizeof(PixelFormat));
1618
1619 pf.bits_per_pixel = bpp;
1620 pf.bytes_per_pixel = bpp / 8;
1621 pf.depth = bpp == 32 ? 24 : bpp;
1622
1623 switch (bpp) {
Gerd Hoffmannb6278082010-05-21 11:59:14 +02001624 case 15:
1625 pf.bits_per_pixel = 16;
1626 pf.bytes_per_pixel = 2;
1627 pf.rmask = 0x00007c00;
1628 pf.gmask = 0x000003E0;
1629 pf.bmask = 0x0000001F;
1630 pf.rmax = 31;
1631 pf.gmax = 31;
1632 pf.bmax = 31;
1633 pf.rshift = 10;
1634 pf.gshift = 5;
1635 pf.bshift = 0;
1636 pf.rbits = 5;
1637 pf.gbits = 5;
1638 pf.bbits = 5;
1639 break;
aliguori7d957bd2009-01-15 22:14:11 +00001640 case 16:
1641 pf.rmask = 0x0000F800;
1642 pf.gmask = 0x000007E0;
1643 pf.bmask = 0x0000001F;
1644 pf.rmax = 31;
1645 pf.gmax = 63;
1646 pf.bmax = 31;
1647 pf.rshift = 11;
1648 pf.gshift = 5;
1649 pf.bshift = 0;
aliguori90a1e3c2009-01-26 15:37:30 +00001650 pf.rbits = 5;
1651 pf.gbits = 6;
1652 pf.bbits = 5;
aliguori7d957bd2009-01-15 22:14:11 +00001653 break;
1654 case 24:
aliguori7d957bd2009-01-15 22:14:11 +00001655 pf.rmask = 0x00FF0000;
1656 pf.gmask = 0x0000FF00;
1657 pf.bmask = 0x000000FF;
1658 pf.rmax = 255;
1659 pf.gmax = 255;
1660 pf.bmax = 255;
1661 pf.rshift = 16;
1662 pf.gshift = 8;
1663 pf.bshift = 0;
aliguori90a1e3c2009-01-26 15:37:30 +00001664 pf.rbits = 8;
1665 pf.gbits = 8;
1666 pf.bbits = 8;
malc0da2ea12009-01-23 19:56:19 +00001667 case 32:
1668 pf.rmask = 0x00FF0000;
1669 pf.gmask = 0x0000FF00;
1670 pf.bmask = 0x000000FF;
1671 pf.amax = 255;
1672 pf.rmax = 255;
1673 pf.gmax = 255;
1674 pf.bmax = 255;
1675 pf.ashift = 24;
1676 pf.rshift = 16;
1677 pf.gshift = 8;
1678 pf.bshift = 0;
aliguori90a1e3c2009-01-26 15:37:30 +00001679 pf.rbits = 8;
1680 pf.gbits = 8;
1681 pf.bbits = 8;
1682 pf.abits = 8;
aliguori7d957bd2009-01-15 22:14:11 +00001683 break;
1684 default:
1685 break;
1686 }
1687 return pf;
1688}