]> git.proxmox.com Git - qemu.git/blame - console.c
acpi_piix4: Re-define PCI hotplug eject register read
[qemu.git] / console.c
CommitLineData
e7f0ad58
FB
1/*
2 * QEMU graphical console
5fafdf24 3 *
e7f0ad58 4 * Copyright (c) 2004 Fabrice Bellard
5fafdf24 5 *
e7f0ad58
FB
6 * 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 */
87ecb68b
PB
24#include "qemu-common.h"
25#include "console.h"
26#include "qemu-timer.h"
e7f0ad58 27
6d6f7c28 28//#define DEBUG_CONSOLE
e7f0ad58
FB
29#define DEFAULT_BACKSCROLL 512
30#define MAX_CONSOLES 12
31
26489844
FB
32#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)
e7f0ad58 34
6d6f7c28
PB
35typedef 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
e7f0ad58
FB
45typedef struct TextCell {
46 uint8_t ch;
6d6f7c28 47 TextAttributes t_attrib;
e7f0ad58
FB
48} 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
e15d7371
FB
58typedef struct QEMUFIFO {
59 uint8_t *buf;
60 int buf_size;
61 int count, wptr, rptr;
62} QEMUFIFO;
63
9596ebb7 64static int qemu_fifo_write(QEMUFIFO *f, const uint8_t *buf, int len1)
e15d7371
FB
65{
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
9596ebb7 87static int qemu_fifo_read(QEMUFIFO *f, uint8_t *buf, int len1)
e15d7371
FB
88{
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
af3a9031
TS
109typedef enum {
110 GRAPHIC_CONSOLE,
c21bbcfa
AZ
111 TEXT_CONSOLE,
112 TEXT_CONSOLE_FIXED_SIZE
c227f099 113} console_type_t;
af3a9031 114
95219897
PB
115/* ??? This is mis-named.
116 It is used for both text and graphical consoles. */
e7f0ad58 117struct TextConsole {
f81bdefb 118 int index;
c227f099 119 console_type_t console_type;
e7f0ad58 120 DisplayState *ds;
95219897
PB
121 /* Graphic console state. */
122 vga_hw_update_ptr hw_update;
123 vga_hw_invalidate_ptr hw_invalidate;
124 vga_hw_screen_dump_ptr hw_screen_dump;
4d3b6f6e 125 vga_hw_text_update_ptr hw_text_update;
95219897
PB
126 void *hw;
127
e7f0ad58
FB
128 int g_width, g_height;
129 int width;
130 int height;
131 int total_height;
132 int backscroll_height;
e7f0ad58 133 int x, y;
adb47967 134 int x_saved, y_saved;
e7f0ad58
FB
135 int y_displayed;
136 int y_base;
6d6f7c28
PB
137 TextAttributes t_attrib_default; /* default text attributes */
138 TextAttributes t_attrib; /* currently active text attributes */
e7f0ad58 139 TextCell *cells;
4d3b6f6e 140 int text_x[2], text_y[2], cursor_invalidate;
4104833f 141 int echo;
e7f0ad58 142
14778c20
PB
143 int update_x0;
144 int update_y0;
145 int update_x1;
146 int update_y1;
147
e7f0ad58
FB
148 enum TTYState state;
149 int esc_params[MAX_ESC_PARAMS];
150 int nb_esc_params;
151
e5b0bc44 152 CharDriverState *chr;
e15d7371
FB
153 /* fifo for key pressed */
154 QEMUFIFO out_fifo;
155 uint8_t out_fifo_buf[16];
156 QEMUTimer *kbd_timer;
e7f0ad58
FB
157};
158
98b50080 159static DisplayState *display_state;
e7f0ad58
FB
160static TextConsole *active_console;
161static TextConsole *consoles[MAX_CONSOLES];
162static int nb_consoles = 0;
163
95219897
PB
164void vga_hw_update(void)
165{
adb47967 166 if (active_console && active_console->hw_update)
95219897
PB
167 active_console->hw_update(active_console->hw);
168}
169
170void vga_hw_invalidate(void)
171{
26572b8a 172 if (active_console && active_console->hw_invalidate)
95219897
PB
173 active_console->hw_invalidate(active_console->hw);
174}
175
176void vga_hw_screen_dump(const char *filename)
177{
8571c055 178 TextConsole *previous_active_console;
45efb161 179 bool cswitch;
8571c055
AZ
180
181 previous_active_console = active_console;
45efb161 182 cswitch = previous_active_console && previous_active_console->index != 0;
f81bdefb 183
8571c055 184 /* There is currently no way of specifying which screen we want to dump,
7b455225 185 so always dump the first one. */
45efb161
GH
186 if (cswitch) {
187 console_select(0);
188 }
f81bdefb 189 if (consoles[0] && consoles[0]->hw_screen_dump) {
45efb161 190 consoles[0]->hw_screen_dump(consoles[0]->hw, filename, cswitch);
16735102
GH
191 } else {
192 error_report("screen dump not implemented");
f81bdefb
JK
193 }
194
45efb161 195 if (cswitch) {
33bcd98c
AG
196 console_select(previous_active_console->index);
197 }
95219897
PB
198}
199
c227f099 200void vga_hw_text_update(console_ch_t *chardata)
4d3b6f6e
AZ
201{
202 if (active_console && active_console->hw_text_update)
203 active_console->hw_text_update(active_console->hw, chardata);
204}
205
e7f0ad58
FB
206/* convert a RGBA color to a color index usable in graphic primitives */
207static unsigned int vga_get_color(DisplayState *ds, unsigned int rgba)
208{
209 unsigned int r, g, b, color;
210
0e1f5a0c 211 switch(ds_get_bits_per_pixel(ds)) {
e7f0ad58
FB
212#if 0
213 case 8:
214 r = (rgba >> 16) & 0xff;
215 g = (rgba >> 8) & 0xff;
216 b = (rgba) & 0xff;
5fafdf24
TS
217 color = (rgb_to_index[r] * 6 * 6) +
218 (rgb_to_index[g] * 6) +
e7f0ad58
FB
219 (rgb_to_index[b]);
220 break;
221#endif
222 case 15:
223 r = (rgba >> 16) & 0xff;
224 g = (rgba >> 8) & 0xff;
225 b = (rgba) & 0xff;
226 color = ((r >> 3) << 10) | ((g >> 3) << 5) | (b >> 3);
227 break;
228 case 16:
229 r = (rgba >> 16) & 0xff;
230 g = (rgba >> 8) & 0xff;
231 b = (rgba) & 0xff;
232 color = ((r >> 3) << 11) | ((g >> 2) << 5) | (b >> 3);
233 break;
234 case 32:
235 default:
236 color = rgba;
237 break;
238 }
239 return color;
240}
241
5fafdf24 242static void vga_fill_rect (DisplayState *ds,
e7f0ad58
FB
243 int posx, int posy, int width, int height, uint32_t color)
244{
245 uint8_t *d, *d1;
246 int x, y, bpp;
3b46e624 247
0e1f5a0c
AL
248 bpp = (ds_get_bits_per_pixel(ds) + 7) >> 3;
249 d1 = ds_get_data(ds) +
250 ds_get_linesize(ds) * posy + bpp * posx;
e7f0ad58
FB
251 for (y = 0; y < height; y++) {
252 d = d1;
253 switch(bpp) {
254 case 1:
255 for (x = 0; x < width; x++) {
256 *((uint8_t *)d) = color;
257 d++;
258 }
259 break;
260 case 2:
261 for (x = 0; x < width; x++) {
262 *((uint16_t *)d) = color;
263 d += 2;
264 }
265 break;
266 case 4:
267 for (x = 0; x < width; x++) {
268 *((uint32_t *)d) = color;
269 d += 4;
270 }
271 break;
272 }
0e1f5a0c 273 d1 += ds_get_linesize(ds);
e7f0ad58
FB
274 }
275}
276
277/* copy from (xs, ys) to (xd, yd) a rectangle of size (w, h) */
278static void vga_bitblt(DisplayState *ds, int xs, int ys, int xd, int yd, int w, int h)
279{
280 const uint8_t *s;
281 uint8_t *d;
282 int wb, y, bpp;
283
0e1f5a0c 284 bpp = (ds_get_bits_per_pixel(ds) + 7) >> 3;
e7f0ad58
FB
285 wb = w * bpp;
286 if (yd <= ys) {
0e1f5a0c
AL
287 s = ds_get_data(ds) +
288 ds_get_linesize(ds) * ys + bpp * xs;
289 d = ds_get_data(ds) +
290 ds_get_linesize(ds) * yd + bpp * xd;
e7f0ad58
FB
291 for (y = 0; y < h; y++) {
292 memmove(d, s, wb);
0e1f5a0c
AL
293 d += ds_get_linesize(ds);
294 s += ds_get_linesize(ds);
e7f0ad58
FB
295 }
296 } else {
0e1f5a0c
AL
297 s = ds_get_data(ds) +
298 ds_get_linesize(ds) * (ys + h - 1) + bpp * xs;
299 d = ds_get_data(ds) +
300 ds_get_linesize(ds) * (yd + h - 1) + bpp * xd;
e7f0ad58
FB
301 for (y = 0; y < h; y++) {
302 memmove(d, s, wb);
0e1f5a0c
AL
303 d -= ds_get_linesize(ds);
304 s -= ds_get_linesize(ds);
e7f0ad58
FB
305 }
306 }
307}
308
309/***********************************************************/
310/* basic char display */
311
312#define FONT_HEIGHT 16
313#define FONT_WIDTH 8
314
315#include "vgafont.h"
316
317#define cbswap_32(__x) \
318((uint32_t)( \
319 (((uint32_t)(__x) & (uint32_t)0x000000ffUL) << 24) | \
320 (((uint32_t)(__x) & (uint32_t)0x0000ff00UL) << 8) | \
321 (((uint32_t)(__x) & (uint32_t)0x00ff0000UL) >> 8) | \
322 (((uint32_t)(__x) & (uint32_t)0xff000000UL) >> 24) ))
323
e2542fe2 324#ifdef HOST_WORDS_BIGENDIAN
e7f0ad58
FB
325#define PAT(x) x
326#else
327#define PAT(x) cbswap_32(x)
328#endif
329
330static const uint32_t dmask16[16] = {
331 PAT(0x00000000),
332 PAT(0x000000ff),
333 PAT(0x0000ff00),
334 PAT(0x0000ffff),
335 PAT(0x00ff0000),
336 PAT(0x00ff00ff),
337 PAT(0x00ffff00),
338 PAT(0x00ffffff),
339 PAT(0xff000000),
340 PAT(0xff0000ff),
341 PAT(0xff00ff00),
342 PAT(0xff00ffff),
343 PAT(0xffff0000),
344 PAT(0xffff00ff),
345 PAT(0xffffff00),
346 PAT(0xffffffff),
347};
348
349static const uint32_t dmask4[4] = {
350 PAT(0x00000000),
351 PAT(0x0000ffff),
352 PAT(0xffff0000),
353 PAT(0xffffffff),
354};
355
6d6f7c28
PB
356static uint32_t color_table[2][8];
357
df00bed0 358#ifndef CONFIG_CURSES
6d6f7c28
PB
359enum color_names {
360 COLOR_BLACK = 0,
361 COLOR_RED = 1,
362 COLOR_GREEN = 2,
363 COLOR_YELLOW = 3,
364 COLOR_BLUE = 4,
365 COLOR_MAGENTA = 5,
366 COLOR_CYAN = 6,
367 COLOR_WHITE = 7
368};
df00bed0 369#endif
6d6f7c28
PB
370
371static const uint32_t color_table_rgb[2][8] = {
372 { /* dark */
26489844
FB
373 QEMU_RGB(0x00, 0x00, 0x00), /* black */
374 QEMU_RGB(0xaa, 0x00, 0x00), /* red */
375 QEMU_RGB(0x00, 0xaa, 0x00), /* green */
376 QEMU_RGB(0xaa, 0xaa, 0x00), /* yellow */
377 QEMU_RGB(0x00, 0x00, 0xaa), /* blue */
378 QEMU_RGB(0xaa, 0x00, 0xaa), /* magenta */
379 QEMU_RGB(0x00, 0xaa, 0xaa), /* cyan */
380 QEMU_RGB(0xaa, 0xaa, 0xaa), /* white */
6d6f7c28
PB
381 },
382 { /* bright */
26489844
FB
383 QEMU_RGB(0x00, 0x00, 0x00), /* black */
384 QEMU_RGB(0xff, 0x00, 0x00), /* red */
385 QEMU_RGB(0x00, 0xff, 0x00), /* green */
386 QEMU_RGB(0xff, 0xff, 0x00), /* yellow */
387 QEMU_RGB(0x00, 0x00, 0xff), /* blue */
388 QEMU_RGB(0xff, 0x00, 0xff), /* magenta */
389 QEMU_RGB(0x00, 0xff, 0xff), /* cyan */
390 QEMU_RGB(0xff, 0xff, 0xff), /* white */
6d6f7c28 391 }
e7f0ad58
FB
392};
393
394static inline unsigned int col_expand(DisplayState *ds, unsigned int col)
395{
0e1f5a0c 396 switch(ds_get_bits_per_pixel(ds)) {
e7f0ad58
FB
397 case 8:
398 col |= col << 8;
399 col |= col << 16;
400 break;
401 case 15:
402 case 16:
403 col |= col << 16;
404 break;
405 default:
406 break;
407 }
408
409 return col;
410}
6d6f7c28
PB
411#ifdef DEBUG_CONSOLE
412static void console_print_text_attributes(TextAttributes *t_attrib, char ch)
413{
414 if (t_attrib->bold) {
415 printf("b");
416 } else {
417 printf(" ");
418 }
419 if (t_attrib->uline) {
420 printf("u");
421 } else {
422 printf(" ");
423 }
424 if (t_attrib->blink) {
425 printf("l");
426 } else {
427 printf(" ");
428 }
429 if (t_attrib->invers) {
430 printf("i");
431 } else {
432 printf(" ");
433 }
434 if (t_attrib->unvisible) {
435 printf("n");
436 } else {
437 printf(" ");
438 }
439
440 printf(" fg: %d bg: %d ch:'%2X' '%c'\n", t_attrib->fgcol, t_attrib->bgcol, ch, ch);
441}
442#endif
e7f0ad58 443
5fafdf24 444static void vga_putcharxy(DisplayState *ds, int x, int y, int ch,
6d6f7c28 445 TextAttributes *t_attrib)
e7f0ad58
FB
446{
447 uint8_t *d;
448 const uint8_t *font_ptr;
449 unsigned int font_data, linesize, xorcol, bpp;
450 int i;
6d6f7c28
PB
451 unsigned int fgcol, bgcol;
452
453#ifdef DEBUG_CONSOLE
454 printf("x: %2i y: %2i", x, y);
455 console_print_text_attributes(t_attrib, ch);
456#endif
457
458 if (t_attrib->invers) {
459 bgcol = color_table[t_attrib->bold][t_attrib->fgcol];
460 fgcol = color_table[t_attrib->bold][t_attrib->bgcol];
461 } else {
462 fgcol = color_table[t_attrib->bold][t_attrib->fgcol];
463 bgcol = color_table[t_attrib->bold][t_attrib->bgcol];
464 }
e7f0ad58 465
0e1f5a0c
AL
466 bpp = (ds_get_bits_per_pixel(ds) + 7) >> 3;
467 d = ds_get_data(ds) +
468 ds_get_linesize(ds) * y * FONT_HEIGHT + bpp * x * FONT_WIDTH;
469 linesize = ds_get_linesize(ds);
e7f0ad58
FB
470 font_ptr = vgafont16 + FONT_HEIGHT * ch;
471 xorcol = bgcol ^ fgcol;
0e1f5a0c 472 switch(ds_get_bits_per_pixel(ds)) {
e7f0ad58
FB
473 case 8:
474 for(i = 0; i < FONT_HEIGHT; i++) {
475 font_data = *font_ptr++;
6d6f7c28
PB
476 if (t_attrib->uline
477 && ((i == FONT_HEIGHT - 2) || (i == FONT_HEIGHT - 3))) {
439229c7 478 font_data = 0xFF;
6d6f7c28 479 }
e7f0ad58
FB
480 ((uint32_t *)d)[0] = (dmask16[(font_data >> 4)] & xorcol) ^ bgcol;
481 ((uint32_t *)d)[1] = (dmask16[(font_data >> 0) & 0xf] & xorcol) ^ bgcol;
482 d += linesize;
483 }
484 break;
485 case 16:
486 case 15:
487 for(i = 0; i < FONT_HEIGHT; i++) {
488 font_data = *font_ptr++;
6d6f7c28
PB
489 if (t_attrib->uline
490 && ((i == FONT_HEIGHT - 2) || (i == FONT_HEIGHT - 3))) {
439229c7 491 font_data = 0xFF;
6d6f7c28 492 }
e7f0ad58
FB
493 ((uint32_t *)d)[0] = (dmask4[(font_data >> 6)] & xorcol) ^ bgcol;
494 ((uint32_t *)d)[1] = (dmask4[(font_data >> 4) & 3] & xorcol) ^ bgcol;
495 ((uint32_t *)d)[2] = (dmask4[(font_data >> 2) & 3] & xorcol) ^ bgcol;
496 ((uint32_t *)d)[3] = (dmask4[(font_data >> 0) & 3] & xorcol) ^ bgcol;
497 d += linesize;
498 }
499 break;
500 case 32:
501 for(i = 0; i < FONT_HEIGHT; i++) {
502 font_data = *font_ptr++;
6d6f7c28 503 if (t_attrib->uline && ((i == FONT_HEIGHT - 2) || (i == FONT_HEIGHT - 3))) {
439229c7 504 font_data = 0xFF;
6d6f7c28 505 }
e7f0ad58
FB
506 ((uint32_t *)d)[0] = (-((font_data >> 7)) & xorcol) ^ bgcol;
507 ((uint32_t *)d)[1] = (-((font_data >> 6) & 1) & xorcol) ^ bgcol;
508 ((uint32_t *)d)[2] = (-((font_data >> 5) & 1) & xorcol) ^ bgcol;
509 ((uint32_t *)d)[3] = (-((font_data >> 4) & 1) & xorcol) ^ bgcol;
510 ((uint32_t *)d)[4] = (-((font_data >> 3) & 1) & xorcol) ^ bgcol;
511 ((uint32_t *)d)[5] = (-((font_data >> 2) & 1) & xorcol) ^ bgcol;
512 ((uint32_t *)d)[6] = (-((font_data >> 1) & 1) & xorcol) ^ bgcol;
513 ((uint32_t *)d)[7] = (-((font_data >> 0) & 1) & xorcol) ^ bgcol;
514 d += linesize;
515 }
516 break;
517 }
518}
519
520static void text_console_resize(TextConsole *s)
521{
522 TextCell *cells, *c, *c1;
523 int w1, x, y, last_width;
524
525 last_width = s->width;
526 s->width = s->g_width / FONT_WIDTH;
527 s->height = s->g_height / FONT_HEIGHT;
528
529 w1 = last_width;
530 if (s->width < w1)
531 w1 = s->width;
532
7267c094 533 cells = g_malloc(s->width * s->total_height * sizeof(TextCell));
e7f0ad58
FB
534 for(y = 0; y < s->total_height; y++) {
535 c = &cells[y * s->width];
536 if (w1 > 0) {
537 c1 = &s->cells[y * last_width];
538 for(x = 0; x < w1; x++) {
539 *c++ = *c1++;
540 }
541 }
542 for(x = w1; x < s->width; x++) {
543 c->ch = ' ';
6d6f7c28 544 c->t_attrib = s->t_attrib_default;
e7f0ad58
FB
545 c++;
546 }
547 }
7267c094 548 g_free(s->cells);
e7f0ad58
FB
549 s->cells = cells;
550}
551
4d3b6f6e
AZ
552static inline void text_update_xy(TextConsole *s, int x, int y)
553{
554 s->text_x[0] = MIN(s->text_x[0], x);
555 s->text_x[1] = MAX(s->text_x[1], x);
556 s->text_y[0] = MIN(s->text_y[0], y);
557 s->text_y[1] = MAX(s->text_y[1], y);
558}
559
14778c20
PB
560static void invalidate_xy(TextConsole *s, int x, int y)
561{
562 if (s->update_x0 > x * FONT_WIDTH)
563 s->update_x0 = x * FONT_WIDTH;
564 if (s->update_y0 > y * FONT_HEIGHT)
565 s->update_y0 = y * FONT_HEIGHT;
566 if (s->update_x1 < (x + 1) * FONT_WIDTH)
567 s->update_x1 = (x + 1) * FONT_WIDTH;
568 if (s->update_y1 < (y + 1) * FONT_HEIGHT)
569 s->update_y1 = (y + 1) * FONT_HEIGHT;
570}
571
e7f0ad58
FB
572static void update_xy(TextConsole *s, int x, int y)
573{
574 TextCell *c;
575 int y1, y2;
576
577 if (s == active_console) {
0e1f5a0c 578 if (!ds_get_bits_per_pixel(s->ds)) {
4d3b6f6e
AZ
579 text_update_xy(s, x, y);
580 return;
581 }
582
e7f0ad58
FB
583 y1 = (s->y_base + y) % s->total_height;
584 y2 = y1 - s->y_displayed;
585 if (y2 < 0)
586 y2 += s->total_height;
587 if (y2 < s->height) {
588 c = &s->cells[y1 * s->width + x];
5fafdf24 589 vga_putcharxy(s->ds, x, y2, c->ch,
6d6f7c28 590 &(c->t_attrib));
14778c20 591 invalidate_xy(s, x, y2);
e7f0ad58
FB
592 }
593 }
594}
595
596static void console_show_cursor(TextConsole *s, int show)
597{
598 TextCell *c;
599 int y, y1;
600
601 if (s == active_console) {
ed8276ac 602 int x = s->x;
4d3b6f6e 603
0e1f5a0c 604 if (!ds_get_bits_per_pixel(s->ds)) {
4d3b6f6e
AZ
605 s->cursor_invalidate = 1;
606 return;
607 }
608
ed8276ac
TS
609 if (x >= s->width) {
610 x = s->width - 1;
611 }
e7f0ad58
FB
612 y1 = (s->y_base + s->y) % s->total_height;
613 y = y1 - s->y_displayed;
614 if (y < 0)
615 y += s->total_height;
616 if (y < s->height) {
ed8276ac 617 c = &s->cells[y1 * s->width + x];
e7f0ad58 618 if (show) {
6d6f7c28
PB
619 TextAttributes t_attrib = s->t_attrib_default;
620 t_attrib.invers = !(t_attrib.invers); /* invert fg and bg */
ed8276ac 621 vga_putcharxy(s->ds, x, y, c->ch, &t_attrib);
e7f0ad58 622 } else {
ed8276ac 623 vga_putcharxy(s->ds, x, y, c->ch, &(c->t_attrib));
e7f0ad58 624 }
14778c20 625 invalidate_xy(s, x, y);
e7f0ad58
FB
626 }
627 }
628}
629
630static void console_refresh(TextConsole *s)
631{
632 TextCell *c;
633 int x, y, y1;
634
5fafdf24 635 if (s != active_console)
e7f0ad58 636 return;
0e1f5a0c 637 if (!ds_get_bits_per_pixel(s->ds)) {
4d3b6f6e
AZ
638 s->text_x[0] = 0;
639 s->text_y[0] = 0;
640 s->text_x[1] = s->width - 1;
641 s->text_y[1] = s->height - 1;
642 s->cursor_invalidate = 1;
643 return;
644 }
e7f0ad58 645
0e1f5a0c 646 vga_fill_rect(s->ds, 0, 0, ds_get_width(s->ds), ds_get_height(s->ds),
6d6f7c28 647 color_table[0][COLOR_BLACK]);
e7f0ad58
FB
648 y1 = s->y_displayed;
649 for(y = 0; y < s->height; y++) {
650 c = s->cells + y1 * s->width;
651 for(x = 0; x < s->width; x++) {
5fafdf24 652 vga_putcharxy(s->ds, x, y, c->ch,
6d6f7c28 653 &(c->t_attrib));
e7f0ad58
FB
654 c++;
655 }
656 if (++y1 == s->total_height)
657 y1 = 0;
658 }
e7f0ad58 659 console_show_cursor(s, 1);
14778c20 660 dpy_update(s->ds, 0, 0, ds_get_width(s->ds), ds_get_height(s->ds));
e7f0ad58
FB
661}
662
663static void console_scroll(int ydelta)
664{
665 TextConsole *s;
666 int i, y1;
3b46e624 667
e7f0ad58 668 s = active_console;
af3a9031 669 if (!s || (s->console_type == GRAPHIC_CONSOLE))
e7f0ad58
FB
670 return;
671
672 if (ydelta > 0) {
673 for(i = 0; i < ydelta; i++) {
674 if (s->y_displayed == s->y_base)
675 break;
676 if (++s->y_displayed == s->total_height)
677 s->y_displayed = 0;
678 }
679 } else {
680 ydelta = -ydelta;
681 i = s->backscroll_height;
682 if (i > s->total_height - s->height)
683 i = s->total_height - s->height;
684 y1 = s->y_base - i;
685 if (y1 < 0)
686 y1 += s->total_height;
687 for(i = 0; i < ydelta; i++) {
688 if (s->y_displayed == y1)
689 break;
690 if (--s->y_displayed < 0)
691 s->y_displayed = s->total_height - 1;
692 }
693 }
694 console_refresh(s);
695}
696
697static void console_put_lf(TextConsole *s)
698{
699 TextCell *c;
700 int x, y1;
701
e7f0ad58
FB
702 s->y++;
703 if (s->y >= s->height) {
704 s->y = s->height - 1;
6d6f7c28 705
e7f0ad58
FB
706 if (s->y_displayed == s->y_base) {
707 if (++s->y_displayed == s->total_height)
708 s->y_displayed = 0;
709 }
710 if (++s->y_base == s->total_height)
711 s->y_base = 0;
712 if (s->backscroll_height < s->total_height)
713 s->backscroll_height++;
714 y1 = (s->y_base + s->height - 1) % s->total_height;
715 c = &s->cells[y1 * s->width];
716 for(x = 0; x < s->width; x++) {
717 c->ch = ' ';
6d6f7c28 718 c->t_attrib = s->t_attrib_default;
e7f0ad58
FB
719 c++;
720 }
721 if (s == active_console && s->y_displayed == s->y_base) {
0e1f5a0c 722 if (!ds_get_bits_per_pixel(s->ds)) {
4d3b6f6e
AZ
723 s->text_x[0] = 0;
724 s->text_y[0] = 0;
725 s->text_x[1] = s->width - 1;
726 s->text_y[1] = s->height - 1;
727 return;
728 }
729
5fafdf24
TS
730 vga_bitblt(s->ds, 0, FONT_HEIGHT, 0, 0,
731 s->width * FONT_WIDTH,
e7f0ad58
FB
732 (s->height - 1) * FONT_HEIGHT);
733 vga_fill_rect(s->ds, 0, (s->height - 1) * FONT_HEIGHT,
5fafdf24 734 s->width * FONT_WIDTH, FONT_HEIGHT,
6d6f7c28 735 color_table[0][s->t_attrib_default.bgcol]);
14778c20
PB
736 s->update_x0 = 0;
737 s->update_y0 = 0;
738 s->update_x1 = s->width * FONT_WIDTH;
739 s->update_y1 = s->height * FONT_HEIGHT;
e7f0ad58
FB
740 }
741 }
742}
743
6d6f7c28
PB
744/* Set console attributes depending on the current escape codes.
745 * NOTE: I know this code is not very efficient (checking every color for it
746 * self) but it is more readable and better maintainable.
747 */
748static void console_handle_escape(TextConsole *s)
749{
750 int i;
751
6d6f7c28
PB
752 for (i=0; i<s->nb_esc_params; i++) {
753 switch (s->esc_params[i]) {
754 case 0: /* reset all console attributes to default */
755 s->t_attrib = s->t_attrib_default;
756 break;
757 case 1:
758 s->t_attrib.bold = 1;
759 break;
760 case 4:
761 s->t_attrib.uline = 1;
762 break;
763 case 5:
764 s->t_attrib.blink = 1;
765 break;
766 case 7:
767 s->t_attrib.invers = 1;
768 break;
769 case 8:
770 s->t_attrib.unvisible = 1;
771 break;
772 case 22:
773 s->t_attrib.bold = 0;
774 break;
775 case 24:
776 s->t_attrib.uline = 0;
777 break;
778 case 25:
779 s->t_attrib.blink = 0;
780 break;
781 case 27:
782 s->t_attrib.invers = 0;
783 break;
784 case 28:
785 s->t_attrib.unvisible = 0;
786 break;
787 /* set foreground color */
788 case 30:
789 s->t_attrib.fgcol=COLOR_BLACK;
790 break;
791 case 31:
792 s->t_attrib.fgcol=COLOR_RED;
793 break;
794 case 32:
795 s->t_attrib.fgcol=COLOR_GREEN;
796 break;
797 case 33:
798 s->t_attrib.fgcol=COLOR_YELLOW;
799 break;
800 case 34:
801 s->t_attrib.fgcol=COLOR_BLUE;
802 break;
803 case 35:
804 s->t_attrib.fgcol=COLOR_MAGENTA;
805 break;
806 case 36:
807 s->t_attrib.fgcol=COLOR_CYAN;
808 break;
809 case 37:
810 s->t_attrib.fgcol=COLOR_WHITE;
811 break;
812 /* set background color */
813 case 40:
814 s->t_attrib.bgcol=COLOR_BLACK;
815 break;
816 case 41:
817 s->t_attrib.bgcol=COLOR_RED;
818 break;
819 case 42:
820 s->t_attrib.bgcol=COLOR_GREEN;
821 break;
822 case 43:
823 s->t_attrib.bgcol=COLOR_YELLOW;
824 break;
825 case 44:
826 s->t_attrib.bgcol=COLOR_BLUE;
827 break;
828 case 45:
829 s->t_attrib.bgcol=COLOR_MAGENTA;
830 break;
831 case 46:
832 s->t_attrib.bgcol=COLOR_CYAN;
833 break;
834 case 47:
835 s->t_attrib.bgcol=COLOR_WHITE;
836 break;
837 }
838 }
839}
840
adb47967
TS
841static void console_clear_xy(TextConsole *s, int x, int y)
842{
843 int y1 = (s->y_base + y) % s->total_height;
844 TextCell *c = &s->cells[y1 * s->width + x];
845 c->ch = ' ';
846 c->t_attrib = s->t_attrib_default;
adb47967
TS
847 update_xy(s, x, y);
848}
849
e7f0ad58
FB
850static void console_putchar(TextConsole *s, int ch)
851{
852 TextCell *c;
adb47967
TS
853 int y1, i;
854 int x, y;
e7f0ad58
FB
855
856 switch(s->state) {
857 case TTY_STATE_NORM:
858 switch(ch) {
6d6f7c28 859 case '\r': /* carriage return */
e7f0ad58
FB
860 s->x = 0;
861 break;
6d6f7c28 862 case '\n': /* newline */
e7f0ad58
FB
863 console_put_lf(s);
864 break;
6d6f7c28 865 case '\b': /* backspace */
5fafdf24 866 if (s->x > 0)
e15d7371 867 s->x--;
6d6f7c28
PB
868 break;
869 case '\t': /* tabspace */
870 if (s->x + (8 - (s->x % 8)) > s->width) {
bd468840 871 s->x = 0;
6d6f7c28
PB
872 console_put_lf(s);
873 } else {
874 s->x = s->x + (8 - (s->x % 8));
875 }
876 break;
877 case '\a': /* alert aka. bell */
878 /* TODO: has to be implemented */
879 break;
adb47967
TS
880 case 14:
881 /* SI (shift in), character set 0 (ignored) */
882 break;
883 case 15:
884 /* SO (shift out), character set 1 (ignored) */
885 break;
6d6f7c28 886 case 27: /* esc (introducing an escape sequence) */
e7f0ad58
FB
887 s->state = TTY_STATE_ESC;
888 break;
889 default:
ed8276ac
TS
890 if (s->x >= s->width) {
891 /* line wrap */
892 s->x = 0;
893 console_put_lf(s);
adb47967 894 }
e7f0ad58
FB
895 y1 = (s->y_base + s->y) % s->total_height;
896 c = &s->cells[y1 * s->width + s->x];
897 c->ch = ch;
6d6f7c28 898 c->t_attrib = s->t_attrib;
e7f0ad58
FB
899 update_xy(s, s->x, s->y);
900 s->x++;
e7f0ad58
FB
901 break;
902 }
903 break;
6d6f7c28 904 case TTY_STATE_ESC: /* check if it is a terminal escape sequence */
e7f0ad58
FB
905 if (ch == '[') {
906 for(i=0;i<MAX_ESC_PARAMS;i++)
907 s->esc_params[i] = 0;
908 s->nb_esc_params = 0;
909 s->state = TTY_STATE_CSI;
910 } else {
911 s->state = TTY_STATE_NORM;
912 }
913 break;
6d6f7c28 914 case TTY_STATE_CSI: /* handle escape sequence parameters */
e7f0ad58
FB
915 if (ch >= '0' && ch <= '9') {
916 if (s->nb_esc_params < MAX_ESC_PARAMS) {
5fafdf24 917 s->esc_params[s->nb_esc_params] =
e7f0ad58
FB
918 s->esc_params[s->nb_esc_params] * 10 + ch - '0';
919 }
920 } else {
921 s->nb_esc_params++;
922 if (ch == ';')
923 break;
adb47967
TS
924#ifdef DEBUG_CONSOLE
925 fprintf(stderr, "escape sequence CSI%d;%d%c, %d parameters\n",
926 s->esc_params[0], s->esc_params[1], ch, s->nb_esc_params);
927#endif
e7f0ad58
FB
928 s->state = TTY_STATE_NORM;
929 switch(ch) {
adb47967
TS
930 case 'A':
931 /* move cursor up */
932 if (s->esc_params[0] == 0) {
933 s->esc_params[0] = 1;
934 }
935 s->y -= s->esc_params[0];
936 if (s->y < 0) {
937 s->y = 0;
938 }
939 break;
940 case 'B':
941 /* move cursor down */
942 if (s->esc_params[0] == 0) {
943 s->esc_params[0] = 1;
944 }
945 s->y += s->esc_params[0];
946 if (s->y >= s->height) {
947 s->y = s->height - 1;
948 }
e7f0ad58
FB
949 break;
950 case 'C':
adb47967
TS
951 /* move cursor right */
952 if (s->esc_params[0] == 0) {
953 s->esc_params[0] = 1;
954 }
955 s->x += s->esc_params[0];
956 if (s->x >= s->width) {
957 s->x = s->width - 1;
958 }
e7f0ad58 959 break;
adb47967
TS
960 case 'D':
961 /* move cursor left */
962 if (s->esc_params[0] == 0) {
963 s->esc_params[0] = 1;
964 }
965 s->x -= s->esc_params[0];
966 if (s->x < 0) {
967 s->x = 0;
968 }
969 break;
970 case 'G':
971 /* move cursor to column */
972 s->x = s->esc_params[0] - 1;
973 if (s->x < 0) {
974 s->x = 0;
975 }
976 break;
977 case 'f':
978 case 'H':
979 /* move cursor to row, column */
980 s->x = s->esc_params[1] - 1;
981 if (s->x < 0) {
982 s->x = 0;
983 }
984 s->y = s->esc_params[0] - 1;
985 if (s->y < 0) {
986 s->y = 0;
987 }
988 break;
989 case 'J':
990 switch (s->esc_params[0]) {
991 case 0:
992 /* clear to end of screen */
993 for (y = s->y; y < s->height; y++) {
994 for (x = 0; x < s->width; x++) {
995 if (y == s->y && x < s->x) {
996 continue;
997 }
998 console_clear_xy(s, x, y);
999 }
1000 }
1001 break;
1002 case 1:
1003 /* clear from beginning of screen */
1004 for (y = 0; y <= s->y; y++) {
1005 for (x = 0; x < s->width; x++) {
1006 if (y == s->y && x > s->x) {
1007 break;
1008 }
1009 console_clear_xy(s, x, y);
1010 }
1011 }
1012 break;
1013 case 2:
1014 /* clear entire screen */
1015 for (y = 0; y <= s->height; y++) {
1016 for (x = 0; x < s->width; x++) {
1017 console_clear_xy(s, x, y);
1018 }
1019 }
f94a950f 1020 break;
adb47967 1021 }
95d8f9f4 1022 break;
e7f0ad58 1023 case 'K':
adb47967
TS
1024 switch (s->esc_params[0]) {
1025 case 0:
f94a950f
MA
1026 /* clear to eol */
1027 for(x = s->x; x < s->width; x++) {
adb47967 1028 console_clear_xy(s, x, s->y);
f94a950f
MA
1029 }
1030 break;
adb47967
TS
1031 case 1:
1032 /* clear from beginning of line */
1033 for (x = 0; x <= s->x; x++) {
1034 console_clear_xy(s, x, s->y);
1035 }
1036 break;
1037 case 2:
1038 /* clear entire line */
1039 for(x = 0; x < s->width; x++) {
1040 console_clear_xy(s, x, s->y);
1041 }
f94a950f
MA
1042 break;
1043 }
adb47967
TS
1044 break;
1045 case 'm':
f94a950f
MA
1046 console_handle_escape(s);
1047 break;
adb47967
TS
1048 case 'n':
1049 /* report cursor position */
1050 /* TODO: send ESC[row;colR */
1051 break;
1052 case 's':
1053 /* save cursor position */
1054 s->x_saved = s->x;
1055 s->y_saved = s->y;
1056 break;
1057 case 'u':
1058 /* restore cursor position */
1059 s->x = s->x_saved;
1060 s->y = s->y_saved;
1061 break;
1062 default:
1063#ifdef DEBUG_CONSOLE
1064 fprintf(stderr, "unhandled escape character '%c'\n", ch);
1065#endif
1066 break;
1067 }
1068 break;
e7f0ad58
FB
1069 }
1070 }
1071}
1072
1073void console_select(unsigned int index)
1074{
1075 TextConsole *s;
6d6f7c28 1076
e7f0ad58
FB
1077 if (index >= MAX_CONSOLES)
1078 return;
358664cc
SH
1079 if (active_console) {
1080 active_console->g_width = ds_get_width(active_console->ds);
1081 active_console->g_height = ds_get_height(active_console->ds);
1082 }
e7f0ad58
FB
1083 s = consoles[index];
1084 if (s) {
7d957bd8 1085 DisplayState *ds = s->ds;
e7f0ad58 1086 active_console = s;
68f00996 1087 if (ds_get_bits_per_pixel(s->ds)) {
7b5d76da 1088 ds->surface = qemu_resize_displaysurface(ds, s->g_width, s->g_height);
68f00996
AL
1089 } else {
1090 s->ds->surface->width = s->width;
1091 s->ds->surface->height = s->height;
1092 }
7d957bd8 1093 dpy_resize(s->ds);
4d3b6f6e 1094 vga_hw_invalidate();
e7f0ad58
FB
1095 }
1096}
1097
1098static int console_puts(CharDriverState *chr, const uint8_t *buf, int len)
1099{
1100 TextConsole *s = chr->opaque;
1101 int i;
1102
14778c20
PB
1103 s->update_x0 = s->width * FONT_WIDTH;
1104 s->update_y0 = s->height * FONT_HEIGHT;
1105 s->update_x1 = 0;
1106 s->update_y1 = 0;
e7f0ad58
FB
1107 console_show_cursor(s, 0);
1108 for(i = 0; i < len; i++) {
1109 console_putchar(s, buf[i]);
1110 }
1111 console_show_cursor(s, 1);
14778c20
PB
1112 if (ds_get_bits_per_pixel(s->ds) && s->update_x0 < s->update_x1) {
1113 dpy_update(s->ds, s->update_x0, s->update_y0,
1114 s->update_x1 - s->update_x0,
1115 s->update_y1 - s->update_y0);
1116 }
e7f0ad58
FB
1117 return len;
1118}
1119
e15d7371
FB
1120static void kbd_send_chars(void *opaque)
1121{
1122 TextConsole *s = opaque;
1123 int len;
1124 uint8_t buf[16];
3b46e624 1125
909cda12 1126 len = qemu_chr_be_can_write(s->chr);
e15d7371
FB
1127 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);
fa5efccb 1133 qemu_chr_be_write(s->chr, buf, len);
e15d7371
FB
1134 }
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) {
7bd427d8 1138 qemu_mod_timer(s->kbd_timer, qemu_get_clock_ms(rt_clock) + 1);
e15d7371
FB
1139 }
1140}
1141
e7f0ad58
FB
1142/* 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;
af3a9031 1150 if (!s || (s->console_type == GRAPHIC_CONSOLE))
e7f0ad58
FB
1151 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:
e15d7371
FB
1167 /* 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;
4104833f
PB
1181 } else if (s->echo && (keysym == '\r' || keysym == '\n')) {
1182 console_puts(s->chr, (const uint8_t *) "\r", 1);
1183 *q++ = '\n';
e15d7371 1184 } else {
4104833f
PB
1185 *q++ = keysym;
1186 }
1187 if (s->echo) {
1188 console_puts(s->chr, buf, q - buf);
e15d7371 1189 }
e5b0bc44 1190 if (s->chr->chr_read) {
e15d7371
FB
1191 qemu_fifo_write(&s->out_fifo, buf, q - buf);
1192 kbd_send_chars(s);
e7f0ad58
FB
1193 }
1194 break;
1195 }
1196}
1197
4d3b6f6e
AZ
1198static void text_console_invalidate(void *opaque)
1199{
1200 TextConsole *s = (TextConsole *) opaque;
68f00996
AL
1201 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 }
4d3b6f6e
AZ
1206 console_refresh(s);
1207}
1208
c227f099 1209static void text_console_update(void *opaque, console_ch_t *chardata)
4d3b6f6e
AZ
1210{
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
42aa98e8 1236static TextConsole *get_graphic_console(DisplayState *ds)
a147d62b 1237{
3023f332
AL
1238 int i;
1239 TextConsole *s;
1240 for (i = 0; i < nb_consoles; i++) {
1241 s = consoles[i];
42aa98e8 1242 if (s->console_type == GRAPHIC_CONSOLE && s->ds == ds)
3023f332
AL
1243 return s;
1244 }
1245 return NULL;
1246}
1247
c227f099 1248static TextConsole *new_console(DisplayState *ds, console_type_t console_type)
e7f0ad58
FB
1249{
1250 TextConsole *s;
95219897 1251 int i;
e7f0ad58
FB
1252
1253 if (nb_consoles >= MAX_CONSOLES)
1254 return NULL;
7267c094 1255 s = g_malloc0(sizeof(TextConsole));
af3a9031
TS
1256 if (!active_console || ((active_console->console_type != GRAPHIC_CONSOLE) &&
1257 (console_type == GRAPHIC_CONSOLE))) {
e7f0ad58 1258 active_console = s;
af3a9031 1259 }
e7f0ad58 1260 s->ds = ds;
af3a9031
TS
1261 s->console_type = console_type;
1262 if (console_type != GRAPHIC_CONSOLE) {
f81bdefb 1263 s->index = nb_consoles;
95219897
PB
1264 consoles[nb_consoles++] = s;
1265 } else {
1266 /* HACK: Put graphical consoles before text consoles. */
1267 for (i = nb_consoles; i > 0; i--) {
af3a9031 1268 if (consoles[i - 1]->console_type == GRAPHIC_CONSOLE)
95219897
PB
1269 break;
1270 consoles[i] = consoles[i - 1];
f81bdefb 1271 consoles[i]->index = i;
95219897 1272 }
f81bdefb 1273 s->index = i;
95219897 1274 consoles[i] = s;
3023f332 1275 nb_consoles++;
95219897
PB
1276 }
1277 return s;
1278}
1279
98b50080
PB
1280static DisplaySurface* defaultallocator_create_displaysurface(int width, int height)
1281{
7267c094 1282 DisplaySurface *surface = (DisplaySurface*) g_malloc0(sizeof(DisplaySurface));
98b50080 1283
ffe8b821
JS
1284 int linesize = width * 4;
1285 qemu_alloc_display(surface, width, height, linesize,
1286 qemu_default_pixelformat(32), 0);
98b50080
PB
1287 return surface;
1288}
1289
1290static DisplaySurface* defaultallocator_resize_displaysurface(DisplaySurface *surface,
1291 int width, int height)
1292{
ffe8b821
JS
1293 int linesize = width * 4;
1294 qemu_alloc_display(surface, width, height, linesize,
1295 qemu_default_pixelformat(32), 0);
1296 return surface;
1297}
1298
1299void qemu_alloc_display(DisplaySurface *surface, int width, int height,
1300 int linesize, PixelFormat pf, int newflags)
1301{
1302 void *data;
98b50080
PB
1303 surface->width = width;
1304 surface->height = height;
ffe8b821
JS
1305 surface->linesize = linesize;
1306 surface->pf = pf;
1307 if (surface->flags & QEMU_ALLOCATED_FLAG) {
7267c094 1308 data = g_realloc(surface->data,
ffe8b821
JS
1309 surface->linesize * surface->height);
1310 } else {
7267c094 1311 data = g_malloc(surface->linesize * surface->height);
ffe8b821
JS
1312 }
1313 surface->data = (uint8_t *)data;
1314 surface->flags = newflags | QEMU_ALLOCATED_FLAG;
98b50080 1315#ifdef HOST_WORDS_BIGENDIAN
ffe8b821 1316 surface->flags |= QEMU_BIG_ENDIAN_FLAG;
98b50080 1317#endif
98b50080
PB
1318}
1319
1320DisplaySurface* qemu_create_displaysurface_from(int width, int height, int bpp,
1321 int linesize, uint8_t *data)
1322{
7267c094 1323 DisplaySurface *surface = (DisplaySurface*) g_malloc0(sizeof(DisplaySurface));
98b50080
PB
1324
1325 surface->width = width;
1326 surface->height = height;
1327 surface->linesize = linesize;
1328 surface->pf = qemu_default_pixelformat(bpp);
1329#ifdef HOST_WORDS_BIGENDIAN
1330 surface->flags = QEMU_BIG_ENDIAN_FLAG;
1331#endif
1332 surface->data = data;
1333
1334 return surface;
1335}
1336
1337static void defaultallocator_free_displaysurface(DisplaySurface *surface)
1338{
1339 if (surface == NULL)
1340 return;
1341 if (surface->flags & QEMU_ALLOCATED_FLAG)
7267c094
AL
1342 g_free(surface->data);
1343 g_free(surface);
98b50080
PB
1344}
1345
1346static struct DisplayAllocator default_allocator = {
1347 defaultallocator_create_displaysurface,
1348 defaultallocator_resize_displaysurface,
1349 defaultallocator_free_displaysurface
1350};
1351
1352static void dumb_display_init(void)
1353{
7267c094 1354 DisplayState *ds = g_malloc0(sizeof(DisplayState));
1802651c
JK
1355 int width = 640;
1356 int height = 480;
1357
98b50080 1358 ds->allocator = &default_allocator;
1802651c
JK
1359 if (is_fixedsize_console()) {
1360 width = active_console->g_width;
1361 height = active_console->g_height;
1362 }
1363 ds->surface = qemu_create_displaysurface(ds, width, height);
98b50080
PB
1364 register_displaystate(ds);
1365}
1366
1367/***********************************************************/
1368/* register display */
1369
1370void register_displaystate(DisplayState *ds)
1371{
1372 DisplayState **s;
1373 s = &display_state;
1374 while (*s != NULL)
1375 s = &(*s)->next;
1376 ds->next = NULL;
1377 *s = ds;
1378}
1379
1380DisplayState *get_displaystate(void)
1381{
1382 if (!display_state) {
1383 dumb_display_init ();
1384 }
1385 return display_state;
1386}
1387
1388DisplayAllocator *register_displayallocator(DisplayState *ds, DisplayAllocator *da)
1389{
1390 if(ds->allocator == &default_allocator) {
1391 DisplaySurface *surf;
1392 surf = da->create_displaysurface(ds_get_width(ds), ds_get_height(ds));
1393 defaultallocator_free_displaysurface(ds->surface);
1394 ds->surface = surf;
1395 ds->allocator = da;
1396 }
1397 return ds->allocator;
1398}
1399
3023f332
AL
1400DisplayState *graphic_console_init(vga_hw_update_ptr update,
1401 vga_hw_invalidate_ptr invalidate,
1402 vga_hw_screen_dump_ptr screen_dump,
1403 vga_hw_text_update_ptr text_update,
1404 void *opaque)
95219897
PB
1405{
1406 TextConsole *s;
3023f332 1407 DisplayState *ds;
f0f2f976 1408
7267c094 1409 ds = (DisplayState *) g_malloc0(sizeof(DisplayState));
7b5d76da
AL
1410 ds->allocator = &default_allocator;
1411 ds->surface = qemu_create_displaysurface(ds, 640, 480);
95219897 1412
af3a9031 1413 s = new_console(ds, GRAPHIC_CONSOLE);
3023f332 1414 if (s == NULL) {
7b5d76da 1415 qemu_free_displaysurface(ds);
7267c094 1416 g_free(ds);
3023f332
AL
1417 return NULL;
1418 }
95219897
PB
1419 s->hw_update = update;
1420 s->hw_invalidate = invalidate;
1421 s->hw_screen_dump = screen_dump;
4d3b6f6e 1422 s->hw_text_update = text_update;
95219897 1423 s->hw = opaque;
3023f332 1424
f0f2f976 1425 register_displaystate(ds);
3023f332 1426 return ds;
e7f0ad58
FB
1427}
1428
95219897 1429int is_graphic_console(void)
e7f0ad58 1430{
4d3b6f6e 1431 return active_console && active_console->console_type == GRAPHIC_CONSOLE;
e7f0ad58
FB
1432}
1433
c21bbcfa
AZ
1434int is_fixedsize_console(void)
1435{
1436 return active_console && active_console->console_type != TEXT_CONSOLE;
1437}
1438
a528b80c
AZ
1439void console_color_init(DisplayState *ds)
1440{
1441 int i, j;
1442 for (j = 0; j < 2; j++) {
1443 for (i = 0; i < 8; i++) {
f0f2f976 1444 color_table[j][i] = col_expand(ds,
a528b80c
AZ
1445 vga_get_color(ds, color_table_rgb[j][i]));
1446 }
1447 }
1448}
1449
4104833f
PB
1450static void text_console_set_echo(CharDriverState *chr, bool echo)
1451{
1452 TextConsole *s = chr->opaque;
1453
1454 s->echo = echo;
1455}
1456
44b37b93 1457static void text_console_do_init(CharDriverState *chr, DisplayState *ds)
e7f0ad58 1458{
e7f0ad58 1459 TextConsole *s;
e7f0ad58 1460 static int color_inited;
6d6f7c28 1461
491e114a 1462 s = chr->opaque;
6ea314d9 1463
e7f0ad58 1464 chr->chr_write = console_puts;
6fcfafb7 1465
e15d7371
FB
1466 s->out_fifo.buf = s->out_fifo_buf;
1467 s->out_fifo.buf_size = sizeof(s->out_fifo_buf);
7bd427d8 1468 s->kbd_timer = qemu_new_timer_ms(rt_clock, kbd_send_chars, s);
3023f332 1469 s->ds = ds;
3b46e624 1470
e7f0ad58
FB
1471 if (!color_inited) {
1472 color_inited = 1;
a528b80c 1473 console_color_init(s->ds);
e7f0ad58
FB
1474 }
1475 s->y_displayed = 0;
1476 s->y_base = 0;
1477 s->total_height = DEFAULT_BACKSCROLL;
1478 s->x = 0;
1479 s->y = 0;
491e114a
PB
1480 if (s->console_type == TEXT_CONSOLE) {
1481 s->g_width = ds_get_width(s->ds);
1482 s->g_height = ds_get_height(s->ds);
1483 }
6d6f7c28 1484
4d3b6f6e
AZ
1485 s->hw_invalidate = text_console_invalidate;
1486 s->hw_text_update = text_console_update;
1487 s->hw = s;
1488
6d6f7c28
PB
1489 /* Set text attribute defaults */
1490 s->t_attrib_default.bold = 0;
1491 s->t_attrib_default.uline = 0;
1492 s->t_attrib_default.blink = 0;
1493 s->t_attrib_default.invers = 0;
1494 s->t_attrib_default.unvisible = 0;
1495 s->t_attrib_default.fgcol = COLOR_WHITE;
1496 s->t_attrib_default.bgcol = COLOR_BLACK;
6d6f7c28
PB
1497 /* set current text attributes to default */
1498 s->t_attrib = s->t_attrib_default;
e7f0ad58
FB
1499 text_console_resize(s);
1500
51bfa4d3
GH
1501 if (chr->label) {
1502 char msg[128];
1503 int len;
1504
735ba588 1505 s->t_attrib.bgcol = COLOR_BLUE;
51bfa4d3
GH
1506 len = snprintf(msg, sizeof(msg), "%s console\r\n", chr->label);
1507 console_puts(chr, (uint8_t*)msg, len);
735ba588 1508 s->t_attrib = s->t_attrib_default;
51bfa4d3
GH
1509 }
1510
127338e6 1511 qemu_chr_generic_open(chr);
ceecf1d1
AJ
1512 if (chr->init)
1513 chr->init(chr);
e7f0ad58 1514}
c60e08d9 1515
1f51470d 1516CharDriverState *text_console_init(QemuOpts *opts)
2796dae0
AL
1517{
1518 CharDriverState *chr;
491e114a
PB
1519 TextConsole *s;
1520 unsigned width;
1521 unsigned height;
2796dae0 1522
7267c094 1523 chr = g_malloc0(sizeof(CharDriverState));
2796dae0 1524
491e114a
PB
1525 width = qemu_opt_get_number(opts, "width", 0);
1526 if (width == 0)
1527 width = qemu_opt_get_number(opts, "cols", 0) * FONT_WIDTH;
1528
1529 height = qemu_opt_get_number(opts, "height", 0);
1530 if (height == 0)
1531 height = qemu_opt_get_number(opts, "rows", 0) * FONT_HEIGHT;
1532
1533 if (width == 0 || height == 0) {
1534 s = new_console(NULL, TEXT_CONSOLE);
1535 } else {
1536 s = new_console(NULL, TEXT_CONSOLE_FIXED_SIZE);
1537 }
1538
1539 if (!s) {
5354d083 1540 g_free(chr);
1f51470d 1541 return NULL;
491e114a
PB
1542 }
1543
1544 s->chr = chr;
1545 s->g_width = width;
1546 s->g_height = height;
1547 chr->opaque = s;
4104833f 1548 chr->chr_set_echo = text_console_set_echo;
1f51470d 1549 return chr;
2796dae0
AL
1550}
1551
1552void text_consoles_set_display(DisplayState *ds)
1553{
1554 int i;
1555
8811e1e1
MA
1556 for (i = 0; i < nb_consoles; i++) {
1557 if (consoles[i]->console_type != GRAPHIC_CONSOLE) {
1558 text_console_do_init(consoles[i]->chr, ds);
1559 }
2796dae0 1560 }
2796dae0
AL
1561}
1562
3023f332 1563void qemu_console_resize(DisplayState *ds, int width, int height)
c60e08d9 1564{
42aa98e8 1565 TextConsole *s = get_graphic_console(ds);
f497f140
AL
1566 if (!s) return;
1567
3023f332
AL
1568 s->g_width = width;
1569 s->g_height = height;
1570 if (is_graphic_console()) {
7b5d76da 1571 ds->surface = qemu_resize_displaysurface(ds, width, height);
3023f332 1572 dpy_resize(ds);
c60e08d9
PB
1573 }
1574}
38334f76 1575
3023f332
AL
1576void qemu_console_copy(DisplayState *ds, int src_x, int src_y,
1577 int dst_x, int dst_y, int w, int h)
c21bbcfa 1578{
3023f332
AL
1579 if (is_graphic_console()) {
1580 dpy_copy(ds, src_x, src_y, dst_x, dst_y, w, h);
38334f76
AZ
1581 }
1582}
7d957bd8 1583
0da2ea1b 1584PixelFormat qemu_different_endianness_pixelformat(int bpp)
7d957bd8
AL
1585{
1586 PixelFormat pf;
1587
1588 memset(&pf, 0x00, sizeof(PixelFormat));
1589
1590 pf.bits_per_pixel = bpp;
1591 pf.bytes_per_pixel = bpp / 8;
1592 pf.depth = bpp == 32 ? 24 : bpp;
1593
1594 switch (bpp) {
0da2ea1b 1595 case 24:
1596 pf.rmask = 0x000000FF;
1597 pf.gmask = 0x0000FF00;
1598 pf.bmask = 0x00FF0000;
1599 pf.rmax = 255;
1600 pf.gmax = 255;
1601 pf.bmax = 255;
1602 pf.rshift = 0;
1603 pf.gshift = 8;
1604 pf.bshift = 16;
90a1e3c0
AL
1605 pf.rbits = 8;
1606 pf.gbits = 8;
1607 pf.bbits = 8;
7d957bd8 1608 break;
0da2ea1b 1609 case 32:
1610 pf.rmask = 0x0000FF00;
1611 pf.gmask = 0x00FF0000;
1612 pf.bmask = 0xFF000000;
1613 pf.amask = 0x00000000;
1614 pf.amax = 255;
1615 pf.rmax = 255;
1616 pf.gmax = 255;
1617 pf.bmax = 255;
1618 pf.ashift = 0;
1619 pf.rshift = 8;
1620 pf.gshift = 16;
1621 pf.bshift = 24;
90a1e3c0
AL
1622 pf.rbits = 8;
1623 pf.gbits = 8;
1624 pf.bbits = 8;
1625 pf.abits = 8;
0da2ea1b 1626 break;
1627 default:
1628 break;
1629 }
1630 return pf;
1631}
1632
1633PixelFormat qemu_default_pixelformat(int bpp)
1634{
1635 PixelFormat pf;
1636
1637 memset(&pf, 0x00, sizeof(PixelFormat));
1638
1639 pf.bits_per_pixel = bpp;
1640 pf.bytes_per_pixel = bpp / 8;
1641 pf.depth = bpp == 32 ? 24 : bpp;
1642
1643 switch (bpp) {
b6278084
GH
1644 case 15:
1645 pf.bits_per_pixel = 16;
1646 pf.bytes_per_pixel = 2;
1647 pf.rmask = 0x00007c00;
1648 pf.gmask = 0x000003E0;
1649 pf.bmask = 0x0000001F;
1650 pf.rmax = 31;
1651 pf.gmax = 31;
1652 pf.bmax = 31;
1653 pf.rshift = 10;
1654 pf.gshift = 5;
1655 pf.bshift = 0;
1656 pf.rbits = 5;
1657 pf.gbits = 5;
1658 pf.bbits = 5;
1659 break;
7d957bd8
AL
1660 case 16:
1661 pf.rmask = 0x0000F800;
1662 pf.gmask = 0x000007E0;
1663 pf.bmask = 0x0000001F;
1664 pf.rmax = 31;
1665 pf.gmax = 63;
1666 pf.bmax = 31;
1667 pf.rshift = 11;
1668 pf.gshift = 5;
1669 pf.bshift = 0;
90a1e3c0
AL
1670 pf.rbits = 5;
1671 pf.gbits = 6;
1672 pf.bbits = 5;
7d957bd8
AL
1673 break;
1674 case 24:
0da2ea1b 1675 pf.rmask = 0x00FF0000;
1676 pf.gmask = 0x0000FF00;
1677 pf.bmask = 0x000000FF;
1678 pf.rmax = 255;
1679 pf.gmax = 255;
1680 pf.bmax = 255;
1681 pf.rshift = 16;
1682 pf.gshift = 8;
1683 pf.bshift = 0;
90a1e3c0
AL
1684 pf.rbits = 8;
1685 pf.gbits = 8;
1686 pf.bbits = 8;
0eba62e0 1687 break;
7d957bd8
AL
1688 case 32:
1689 pf.rmask = 0x00FF0000;
1690 pf.gmask = 0x0000FF00;
1691 pf.bmask = 0x000000FF;
0da2ea1b 1692 pf.amax = 255;
7d957bd8
AL
1693 pf.rmax = 255;
1694 pf.gmax = 255;
1695 pf.bmax = 255;
0da2ea1b 1696 pf.ashift = 24;
7d957bd8
AL
1697 pf.rshift = 16;
1698 pf.gshift = 8;
1699 pf.bshift = 0;
90a1e3c0
AL
1700 pf.rbits = 8;
1701 pf.gbits = 8;
1702 pf.bbits = 8;
1703 pf.abits = 8;
7d957bd8
AL
1704 break;
1705 default:
1706 break;
1707 }
1708 return pf;
1709}