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