blob: f6694b2ae56285159328919ce1de88be4a5becae [file] [log] [blame]
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001/*
2 * QEMU graphical console
3 *
4 * Copyright (c) 2004 Fabrice Bellard
5 *
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 */
24#include "qemu-common.h"
25#include "console.h"
26#include "qemu-timer.h"
27
28//#define DEBUG_CONSOLE
29#define DEFAULT_BACKSCROLL 512
30#define MAX_CONSOLES 12
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -080031
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)
34
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
45typedef struct TextCell {
46 uint8_t ch;
47 TextAttributes t_attrib;
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
58typedef struct QEMUFIFO {
59 uint8_t *buf;
60 int buf_size;
61 int count, wptr, rptr;
62} QEMUFIFO;
63
64static int qemu_fifo_write(QEMUFIFO *f, const uint8_t *buf, int len1)
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
87static int qemu_fifo_read(QEMUFIFO *f, uint8_t *buf, int len1)
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
109typedef enum {
110 GRAPHIC_CONSOLE,
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700111 TEXT_CONSOLE,
112 TEXT_CONSOLE_FIXED_SIZE
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800113} console_type_t;
114
115/* ??? This is mis-named.
116 It is used for both text and graphical consoles. */
117struct TextConsole {
118 console_type_t console_type;
119 DisplayState *ds;
120 /* Graphic console state. */
121 vga_hw_update_ptr hw_update;
122 vga_hw_invalidate_ptr hw_invalidate;
123 vga_hw_screen_dump_ptr hw_screen_dump;
124 vga_hw_text_update_ptr hw_text_update;
125 void *hw;
126
127 int g_width, g_height;
128 int width;
129 int height;
130 int total_height;
131 int backscroll_height;
132 int x, y;
133 int x_saved, y_saved;
134 int y_displayed;
135 int y_base;
136 TextAttributes t_attrib_default; /* default text attributes */
137 TextAttributes t_attrib; /* currently active text attributes */
138 TextCell *cells;
139 int text_x[2], text_y[2], cursor_invalidate;
140
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700141 int update_x0;
142 int update_y0;
143 int update_x1;
144 int update_y1;
145
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800146 enum TTYState state;
147 int esc_params[MAX_ESC_PARAMS];
148 int nb_esc_params;
149
150 CharDriverState *chr;
151 /* fifo for key pressed */
152 QEMUFIFO out_fifo;
153 uint8_t out_fifo_buf[16];
154 QEMUTimer *kbd_timer;
155};
156
David Turnerf52506f2010-09-10 16:11:22 +0200157static DisplayState *display_state;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800158static TextConsole *active_console;
159static TextConsole *consoles[MAX_CONSOLES];
160static int nb_consoles = 0;
161
David Turnerf52506f2010-09-10 16:11:22 +0200162#ifdef CONFIG_ANDROID
Vladimir Chtchetkinedd50f7d2010-07-30 09:16:41 -0700163/* Graphic console width, height and bits per pixel.
164 * These default values can be changed with the "-android-gui" option.
165 */
166int android_display_width = 640;
167int android_display_height = 480;
168int android_display_bpp = 32;
David Turnerf52506f2010-09-10 16:11:22 +0200169#endif
Vladimir Chtchetkinedd50f7d2010-07-30 09:16:41 -0700170
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800171void vga_hw_update(void)
172{
173 if (active_console && active_console->hw_update)
174 active_console->hw_update(active_console->hw);
175}
176
177void vga_hw_invalidate(void)
178{
David Turner9d118822010-09-10 13:02:07 +0200179 if (active_console && active_console->hw_invalidate)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800180 active_console->hw_invalidate(active_console->hw);
181}
182
183void vga_hw_screen_dump(const char *filename)
184{
185 TextConsole *previous_active_console;
186
187 previous_active_console = active_console;
188 active_console = consoles[0];
189 /* There is currently no way of specifying which screen we want to dump,
190 so always dump the first one. */
191 if (consoles[0]->hw_screen_dump)
192 consoles[0]->hw_screen_dump(consoles[0]->hw, filename);
193 active_console = previous_active_console;
194}
195
196void vga_hw_text_update(console_ch_t *chardata)
197{
198 if (active_console && active_console->hw_text_update)
199 active_console->hw_text_update(active_console->hw, chardata);
200}
201
202/* convert a RGBA color to a color index usable in graphic primitives */
203static unsigned int vga_get_color(DisplayState *ds, unsigned int rgba)
204{
205 unsigned int r, g, b, color;
206
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700207 switch(ds_get_bits_per_pixel(ds)) {
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800208#if 0
209 case 8:
210 r = (rgba >> 16) & 0xff;
211 g = (rgba >> 8) & 0xff;
212 b = (rgba) & 0xff;
213 color = (rgb_to_index[r] * 6 * 6) +
214 (rgb_to_index[g] * 6) +
215 (rgb_to_index[b]);
216 break;
217#endif
218 case 15:
219 r = (rgba >> 16) & 0xff;
220 g = (rgba >> 8) & 0xff;
221 b = (rgba) & 0xff;
222 color = ((r >> 3) << 10) | ((g >> 3) << 5) | (b >> 3);
223 break;
224 case 16:
225 r = (rgba >> 16) & 0xff;
226 g = (rgba >> 8) & 0xff;
227 b = (rgba) & 0xff;
228 color = ((r >> 3) << 11) | ((g >> 2) << 5) | (b >> 3);
229 break;
230 case 32:
231 default:
232 color = rgba;
233 break;
234 }
235 return color;
236}
237
238static void vga_fill_rect (DisplayState *ds,
239 int posx, int posy, int width, int height, uint32_t color)
240{
241 uint8_t *d, *d1;
242 int x, y, bpp;
243
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700244 bpp = (ds_get_bits_per_pixel(ds) + 7) >> 3;
245 d1 = ds_get_data(ds) +
246 ds_get_linesize(ds) * posy + bpp * posx;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800247 for (y = 0; y < height; y++) {
248 d = d1;
249 switch(bpp) {
250 case 1:
251 for (x = 0; x < width; x++) {
252 *((uint8_t *)d) = color;
253 d++;
254 }
255 break;
256 case 2:
257 for (x = 0; x < width; x++) {
258 *((uint16_t *)d) = color;
259 d += 2;
260 }
261 break;
262 case 4:
263 for (x = 0; x < width; x++) {
264 *((uint32_t *)d) = color;
265 d += 4;
266 }
267 break;
268 }
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700269 d1 += ds_get_linesize(ds);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800270 }
271}
272
273/* copy from (xs, ys) to (xd, yd) a rectangle of size (w, h) */
274static void vga_bitblt(DisplayState *ds, int xs, int ys, int xd, int yd, int w, int h)
275{
276 const uint8_t *s;
277 uint8_t *d;
278 int wb, y, bpp;
279
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700280 bpp = (ds_get_bits_per_pixel(ds) + 7) >> 3;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800281 wb = w * bpp;
282 if (yd <= ys) {
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700283 s = ds_get_data(ds) +
284 ds_get_linesize(ds) * ys + bpp * xs;
285 d = ds_get_data(ds) +
286 ds_get_linesize(ds) * yd + bpp * xd;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800287 for (y = 0; y < h; y++) {
288 memmove(d, s, wb);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700289 d += ds_get_linesize(ds);
290 s += ds_get_linesize(ds);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800291 }
292 } else {
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700293 s = ds_get_data(ds) +
294 ds_get_linesize(ds) * (ys + h - 1) + bpp * xs;
295 d = ds_get_data(ds) +
296 ds_get_linesize(ds) * (yd + h - 1) + bpp * xd;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800297 for (y = 0; y < h; y++) {
298 memmove(d, s, wb);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700299 d -= ds_get_linesize(ds);
300 s -= ds_get_linesize(ds);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800301 }
302 }
303}
304
305/***********************************************************/
306/* basic char display */
307
308#define FONT_HEIGHT 16
309#define FONT_WIDTH 8
310
311#include "vgafont.h"
312
313#define cbswap_32(__x) \
314((uint32_t)( \
Vladimir Chtchetkine90c62352011-01-13 11:24:07 -0800315 (((uint32_t)(__x) & (uint32_t)0x000000ffUL) << 24) | \
316 (((uint32_t)(__x) & (uint32_t)0x0000ff00UL) << 8) | \
317 (((uint32_t)(__x) & (uint32_t)0x00ff0000UL) >> 8) | \
318 (((uint32_t)(__x) & (uint32_t)0xff000000UL) >> 24) ))
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800319
David 'Digit' Turner20894ae2010-05-10 17:07:36 -0700320#ifdef HOST_WORDS_BIGENDIAN
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800321#define PAT(x) x
322#else
323#define PAT(x) cbswap_32(x)
324#endif
325
326static const uint32_t dmask16[16] = {
327 PAT(0x00000000),
328 PAT(0x000000ff),
329 PAT(0x0000ff00),
330 PAT(0x0000ffff),
331 PAT(0x00ff0000),
332 PAT(0x00ff00ff),
333 PAT(0x00ffff00),
334 PAT(0x00ffffff),
335 PAT(0xff000000),
336 PAT(0xff0000ff),
337 PAT(0xff00ff00),
338 PAT(0xff00ffff),
339 PAT(0xffff0000),
340 PAT(0xffff00ff),
341 PAT(0xffffff00),
342 PAT(0xffffffff),
343};
344
345static const uint32_t dmask4[4] = {
346 PAT(0x00000000),
347 PAT(0x0000ffff),
348 PAT(0xffff0000),
349 PAT(0xffffffff),
350};
351
352static uint32_t color_table[2][8];
353
354enum color_names {
355 COLOR_BLACK = 0,
356 COLOR_RED = 1,
357 COLOR_GREEN = 2,
358 COLOR_YELLOW = 3,
359 COLOR_BLUE = 4,
360 COLOR_MAGENTA = 5,
361 COLOR_CYAN = 6,
362 COLOR_WHITE = 7
363};
364
365static const uint32_t color_table_rgb[2][8] = {
366 { /* dark */
367 QEMU_RGB(0x00, 0x00, 0x00), /* black */
368 QEMU_RGB(0xaa, 0x00, 0x00), /* red */
369 QEMU_RGB(0x00, 0xaa, 0x00), /* green */
370 QEMU_RGB(0xaa, 0xaa, 0x00), /* yellow */
371 QEMU_RGB(0x00, 0x00, 0xaa), /* blue */
372 QEMU_RGB(0xaa, 0x00, 0xaa), /* magenta */
373 QEMU_RGB(0x00, 0xaa, 0xaa), /* cyan */
374 QEMU_RGB(0xaa, 0xaa, 0xaa), /* white */
375 },
376 { /* bright */
377 QEMU_RGB(0x00, 0x00, 0x00), /* black */
378 QEMU_RGB(0xff, 0x00, 0x00), /* red */
379 QEMU_RGB(0x00, 0xff, 0x00), /* green */
380 QEMU_RGB(0xff, 0xff, 0x00), /* yellow */
381 QEMU_RGB(0x00, 0x00, 0xff), /* blue */
382 QEMU_RGB(0xff, 0x00, 0xff), /* magenta */
383 QEMU_RGB(0x00, 0xff, 0xff), /* cyan */
384 QEMU_RGB(0xff, 0xff, 0xff), /* white */
385 }
386};
387
388static inline unsigned int col_expand(DisplayState *ds, unsigned int col)
389{
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700390 switch(ds_get_bits_per_pixel(ds)) {
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800391 case 8:
392 col |= col << 8;
393 col |= col << 16;
394 break;
395 case 15:
396 case 16:
397 col |= col << 16;
398 break;
399 default:
400 break;
401 }
402
403 return col;
404}
405#ifdef DEBUG_CONSOLE
406static void console_print_text_attributes(TextAttributes *t_attrib, char ch)
407{
408 if (t_attrib->bold) {
409 printf("b");
410 } else {
411 printf(" ");
412 }
413 if (t_attrib->uline) {
414 printf("u");
415 } else {
416 printf(" ");
417 }
418 if (t_attrib->blink) {
419 printf("l");
420 } else {
421 printf(" ");
422 }
423 if (t_attrib->invers) {
424 printf("i");
425 } else {
426 printf(" ");
427 }
428 if (t_attrib->unvisible) {
429 printf("n");
430 } else {
431 printf(" ");
432 }
433
434 printf(" fg: %d bg: %d ch:'%2X' '%c'\n", t_attrib->fgcol, t_attrib->bgcol, ch, ch);
435}
436#endif
437
438static void vga_putcharxy(DisplayState *ds, int x, int y, int ch,
439 TextAttributes *t_attrib)
440{
441 uint8_t *d;
442 const uint8_t *font_ptr;
443 unsigned int font_data, linesize, xorcol, bpp;
444 int i;
445 unsigned int fgcol, bgcol;
446
447#ifdef DEBUG_CONSOLE
448 printf("x: %2i y: %2i", x, y);
449 console_print_text_attributes(t_attrib, ch);
450#endif
451
452 if (t_attrib->invers) {
453 bgcol = color_table[t_attrib->bold][t_attrib->fgcol];
454 fgcol = color_table[t_attrib->bold][t_attrib->bgcol];
455 } else {
456 fgcol = color_table[t_attrib->bold][t_attrib->fgcol];
457 bgcol = color_table[t_attrib->bold][t_attrib->bgcol];
458 }
459
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700460 bpp = (ds_get_bits_per_pixel(ds) + 7) >> 3;
461 d = ds_get_data(ds) +
462 ds_get_linesize(ds) * y * FONT_HEIGHT + bpp * x * FONT_WIDTH;
463 linesize = ds_get_linesize(ds);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800464 font_ptr = vgafont16 + FONT_HEIGHT * ch;
465 xorcol = bgcol ^ fgcol;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700466 switch(ds_get_bits_per_pixel(ds)) {
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800467 case 8:
468 for(i = 0; i < FONT_HEIGHT; i++) {
469 font_data = *font_ptr++;
470 if (t_attrib->uline
471 && ((i == FONT_HEIGHT - 2) || (i == FONT_HEIGHT - 3))) {
472 font_data = 0xFFFF;
473 }
474 ((uint32_t *)d)[0] = (dmask16[(font_data >> 4)] & xorcol) ^ bgcol;
475 ((uint32_t *)d)[1] = (dmask16[(font_data >> 0) & 0xf] & xorcol) ^ bgcol;
476 d += linesize;
477 }
478 break;
479 case 16:
480 case 15:
481 for(i = 0; i < FONT_HEIGHT; i++) {
482 font_data = *font_ptr++;
483 if (t_attrib->uline
484 && ((i == FONT_HEIGHT - 2) || (i == FONT_HEIGHT - 3))) {
485 font_data = 0xFFFF;
486 }
487 ((uint32_t *)d)[0] = (dmask4[(font_data >> 6)] & xorcol) ^ bgcol;
488 ((uint32_t *)d)[1] = (dmask4[(font_data >> 4) & 3] & xorcol) ^ bgcol;
489 ((uint32_t *)d)[2] = (dmask4[(font_data >> 2) & 3] & xorcol) ^ bgcol;
490 ((uint32_t *)d)[3] = (dmask4[(font_data >> 0) & 3] & xorcol) ^ bgcol;
491 d += linesize;
492 }
493 break;
494 case 32:
495 for(i = 0; i < FONT_HEIGHT; i++) {
496 font_data = *font_ptr++;
497 if (t_attrib->uline && ((i == FONT_HEIGHT - 2) || (i == FONT_HEIGHT - 3))) {
498 font_data = 0xFFFF;
499 }
500 ((uint32_t *)d)[0] = (-((font_data >> 7)) & xorcol) ^ bgcol;
501 ((uint32_t *)d)[1] = (-((font_data >> 6) & 1) & xorcol) ^ bgcol;
502 ((uint32_t *)d)[2] = (-((font_data >> 5) & 1) & xorcol) ^ bgcol;
503 ((uint32_t *)d)[3] = (-((font_data >> 4) & 1) & xorcol) ^ bgcol;
504 ((uint32_t *)d)[4] = (-((font_data >> 3) & 1) & xorcol) ^ bgcol;
505 ((uint32_t *)d)[5] = (-((font_data >> 2) & 1) & xorcol) ^ bgcol;
506 ((uint32_t *)d)[6] = (-((font_data >> 1) & 1) & xorcol) ^ bgcol;
507 ((uint32_t *)d)[7] = (-((font_data >> 0) & 1) & xorcol) ^ bgcol;
508 d += linesize;
509 }
510 break;
511 }
512}
513
514static void text_console_resize(TextConsole *s)
515{
516 TextCell *cells, *c, *c1;
517 int w1, x, y, last_width;
518
519 last_width = s->width;
520 s->width = s->g_width / FONT_WIDTH;
521 s->height = s->g_height / FONT_HEIGHT;
522
523 w1 = last_width;
524 if (s->width < w1)
525 w1 = s->width;
526
527 cells = qemu_malloc(s->width * s->total_height * sizeof(TextCell));
528 for(y = 0; y < s->total_height; y++) {
529 c = &cells[y * s->width];
530 if (w1 > 0) {
531 c1 = &s->cells[y * last_width];
532 for(x = 0; x < w1; x++) {
533 *c++ = *c1++;
534 }
535 }
536 for(x = w1; x < s->width; x++) {
537 c->ch = ' ';
538 c->t_attrib = s->t_attrib_default;
539 c++;
540 }
541 }
542 qemu_free(s->cells);
543 s->cells = cells;
544}
545
546static inline void text_update_xy(TextConsole *s, int x, int y)
547{
548 s->text_x[0] = MIN(s->text_x[0], x);
549 s->text_x[1] = MAX(s->text_x[1], x);
550 s->text_y[0] = MIN(s->text_y[0], y);
551 s->text_y[1] = MAX(s->text_y[1], y);
552}
553
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700554static void invalidate_xy(TextConsole *s, int x, int y)
555{
556 if (s->update_x0 > x * FONT_WIDTH)
557 s->update_x0 = x * FONT_WIDTH;
558 if (s->update_y0 > y * FONT_HEIGHT)
559 s->update_y0 = y * FONT_HEIGHT;
560 if (s->update_x1 < (x + 1) * FONT_WIDTH)
561 s->update_x1 = (x + 1) * FONT_WIDTH;
562 if (s->update_y1 < (y + 1) * FONT_HEIGHT)
563 s->update_y1 = (y + 1) * FONT_HEIGHT;
564}
565
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800566static void update_xy(TextConsole *s, int x, int y)
567{
568 TextCell *c;
569 int y1, y2;
570
571 if (s == active_console) {
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700572 if (!ds_get_bits_per_pixel(s->ds)) {
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800573 text_update_xy(s, x, y);
574 return;
575 }
576
577 y1 = (s->y_base + y) % s->total_height;
578 y2 = y1 - s->y_displayed;
579 if (y2 < 0)
580 y2 += s->total_height;
581 if (y2 < s->height) {
582 c = &s->cells[y1 * s->width + x];
583 vga_putcharxy(s->ds, x, y2, c->ch,
584 &(c->t_attrib));
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700585 invalidate_xy(s, x, y2);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800586 }
587 }
588}
589
590static void console_show_cursor(TextConsole *s, int show)
591{
592 TextCell *c;
593 int y, y1;
594
595 if (s == active_console) {
596 int x = s->x;
597
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700598 if (!ds_get_bits_per_pixel(s->ds)) {
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800599 s->cursor_invalidate = 1;
600 return;
601 }
602
603 if (x >= s->width) {
604 x = s->width - 1;
605 }
606 y1 = (s->y_base + s->y) % s->total_height;
607 y = y1 - s->y_displayed;
608 if (y < 0)
609 y += s->total_height;
610 if (y < s->height) {
611 c = &s->cells[y1 * s->width + x];
612 if (show) {
613 TextAttributes t_attrib = s->t_attrib_default;
614 t_attrib.invers = !(t_attrib.invers); /* invert fg and bg */
615 vga_putcharxy(s->ds, x, y, c->ch, &t_attrib);
616 } else {
617 vga_putcharxy(s->ds, x, y, c->ch, &(c->t_attrib));
618 }
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700619 invalidate_xy(s, x, y);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800620 }
621 }
622}
623
624static void console_refresh(TextConsole *s)
625{
626 TextCell *c;
627 int x, y, y1;
628
629 if (s != active_console)
630 return;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700631 if (!ds_get_bits_per_pixel(s->ds)) {
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800632 s->text_x[0] = 0;
633 s->text_y[0] = 0;
634 s->text_x[1] = s->width - 1;
635 s->text_y[1] = s->height - 1;
636 s->cursor_invalidate = 1;
637 return;
638 }
639
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700640 vga_fill_rect(s->ds, 0, 0, ds_get_width(s->ds), ds_get_height(s->ds),
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800641 color_table[0][COLOR_BLACK]);
642 y1 = s->y_displayed;
643 for(y = 0; y < s->height; y++) {
644 c = s->cells + y1 * s->width;
645 for(x = 0; x < s->width; x++) {
646 vga_putcharxy(s->ds, x, y, c->ch,
647 &(c->t_attrib));
648 c++;
649 }
650 if (++y1 == s->total_height)
651 y1 = 0;
652 }
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800653 console_show_cursor(s, 1);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700654 dpy_update(s->ds, 0, 0, ds_get_width(s->ds), ds_get_height(s->ds));
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800655}
656
657static void console_scroll(int ydelta)
658{
659 TextConsole *s;
660 int i, y1;
661
662 s = active_console;
663 if (!s || (s->console_type == GRAPHIC_CONSOLE))
664 return;
665
666 if (ydelta > 0) {
667 for(i = 0; i < ydelta; i++) {
668 if (s->y_displayed == s->y_base)
669 break;
670 if (++s->y_displayed == s->total_height)
671 s->y_displayed = 0;
672 }
673 } else {
674 ydelta = -ydelta;
675 i = s->backscroll_height;
676 if (i > s->total_height - s->height)
677 i = s->total_height - s->height;
678 y1 = s->y_base - i;
679 if (y1 < 0)
680 y1 += s->total_height;
681 for(i = 0; i < ydelta; i++) {
682 if (s->y_displayed == y1)
683 break;
684 if (--s->y_displayed < 0)
685 s->y_displayed = s->total_height - 1;
686 }
687 }
688 console_refresh(s);
689}
690
691static void console_put_lf(TextConsole *s)
692{
693 TextCell *c;
694 int x, y1;
695
696 s->y++;
697 if (s->y >= s->height) {
698 s->y = s->height - 1;
699
700 if (s->y_displayed == s->y_base) {
701 if (++s->y_displayed == s->total_height)
702 s->y_displayed = 0;
703 }
704 if (++s->y_base == s->total_height)
705 s->y_base = 0;
706 if (s->backscroll_height < s->total_height)
707 s->backscroll_height++;
708 y1 = (s->y_base + s->height - 1) % s->total_height;
709 c = &s->cells[y1 * s->width];
710 for(x = 0; x < s->width; x++) {
711 c->ch = ' ';
712 c->t_attrib = s->t_attrib_default;
713 c++;
714 }
715 if (s == active_console && s->y_displayed == s->y_base) {
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700716 if (!ds_get_bits_per_pixel(s->ds)) {
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800717 s->text_x[0] = 0;
718 s->text_y[0] = 0;
719 s->text_x[1] = s->width - 1;
720 s->text_y[1] = s->height - 1;
721 return;
722 }
723
724 vga_bitblt(s->ds, 0, FONT_HEIGHT, 0, 0,
725 s->width * FONT_WIDTH,
726 (s->height - 1) * FONT_HEIGHT);
727 vga_fill_rect(s->ds, 0, (s->height - 1) * FONT_HEIGHT,
728 s->width * FONT_WIDTH, FONT_HEIGHT,
729 color_table[0][s->t_attrib_default.bgcol]);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700730 s->update_x0 = 0;
731 s->update_y0 = 0;
732 s->update_x1 = s->width * FONT_WIDTH;
733 s->update_y1 = s->height * FONT_HEIGHT;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800734 }
735 }
736}
737
738/* Set console attributes depending on the current escape codes.
739 * NOTE: I know this code is not very efficient (checking every color for it
740 * self) but it is more readable and better maintainable.
741 */
742static void console_handle_escape(TextConsole *s)
743{
744 int i;
745
746 for (i=0; i<s->nb_esc_params; i++) {
747 switch (s->esc_params[i]) {
748 case 0: /* reset all console attributes to default */
749 s->t_attrib = s->t_attrib_default;
750 break;
751 case 1:
752 s->t_attrib.bold = 1;
753 break;
754 case 4:
755 s->t_attrib.uline = 1;
756 break;
757 case 5:
758 s->t_attrib.blink = 1;
759 break;
760 case 7:
761 s->t_attrib.invers = 1;
762 break;
763 case 8:
764 s->t_attrib.unvisible = 1;
765 break;
766 case 22:
767 s->t_attrib.bold = 0;
768 break;
769 case 24:
770 s->t_attrib.uline = 0;
771 break;
772 case 25:
773 s->t_attrib.blink = 0;
774 break;
775 case 27:
776 s->t_attrib.invers = 0;
777 break;
778 case 28:
779 s->t_attrib.unvisible = 0;
780 break;
781 /* set foreground color */
782 case 30:
783 s->t_attrib.fgcol=COLOR_BLACK;
784 break;
785 case 31:
786 s->t_attrib.fgcol=COLOR_RED;
787 break;
788 case 32:
789 s->t_attrib.fgcol=COLOR_GREEN;
790 break;
791 case 33:
792 s->t_attrib.fgcol=COLOR_YELLOW;
793 break;
794 case 34:
795 s->t_attrib.fgcol=COLOR_BLUE;
796 break;
797 case 35:
798 s->t_attrib.fgcol=COLOR_MAGENTA;
799 break;
800 case 36:
801 s->t_attrib.fgcol=COLOR_CYAN;
802 break;
803 case 37:
804 s->t_attrib.fgcol=COLOR_WHITE;
805 break;
806 /* set background color */
807 case 40:
808 s->t_attrib.bgcol=COLOR_BLACK;
809 break;
810 case 41:
811 s->t_attrib.bgcol=COLOR_RED;
812 break;
813 case 42:
814 s->t_attrib.bgcol=COLOR_GREEN;
815 break;
816 case 43:
817 s->t_attrib.bgcol=COLOR_YELLOW;
818 break;
819 case 44:
820 s->t_attrib.bgcol=COLOR_BLUE;
821 break;
822 case 45:
823 s->t_attrib.bgcol=COLOR_MAGENTA;
824 break;
825 case 46:
826 s->t_attrib.bgcol=COLOR_CYAN;
827 break;
828 case 47:
829 s->t_attrib.bgcol=COLOR_WHITE;
830 break;
831 }
832 }
833}
834
835static void console_clear_xy(TextConsole *s, int x, int y)
836{
837 int y1 = (s->y_base + y) % s->total_height;
838 TextCell *c = &s->cells[y1 * s->width + x];
839 c->ch = ' ';
840 c->t_attrib = s->t_attrib_default;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800841 update_xy(s, x, y);
842}
843
844static void console_putchar(TextConsole *s, int ch)
845{
846 TextCell *c;
847 int y1, i;
848 int x, y;
849
850 switch(s->state) {
851 case TTY_STATE_NORM:
852 switch(ch) {
853 case '\r': /* carriage return */
854 s->x = 0;
855 break;
856 case '\n': /* newline */
857 console_put_lf(s);
858 break;
859 case '\b': /* backspace */
860 if (s->x > 0)
861 s->x--;
862 break;
863 case '\t': /* tabspace */
864 if (s->x + (8 - (s->x % 8)) > s->width) {
865 s->x = 0;
866 console_put_lf(s);
867 } else {
868 s->x = s->x + (8 - (s->x % 8));
869 }
870 break;
871 case '\a': /* alert aka. bell */
872 /* TODO: has to be implemented */
873 break;
874 case 14:
875 /* SI (shift in), character set 0 (ignored) */
876 break;
877 case 15:
878 /* SO (shift out), character set 1 (ignored) */
879 break;
880 case 27: /* esc (introducing an escape sequence) */
881 s->state = TTY_STATE_ESC;
882 break;
883 default:
884 if (s->x >= s->width) {
885 /* line wrap */
886 s->x = 0;
887 console_put_lf(s);
888 }
889 y1 = (s->y_base + s->y) % s->total_height;
890 c = &s->cells[y1 * s->width + s->x];
891 c->ch = ch;
892 c->t_attrib = s->t_attrib;
893 update_xy(s, s->x, s->y);
894 s->x++;
895 break;
896 }
897 break;
898 case TTY_STATE_ESC: /* check if it is a terminal escape sequence */
899 if (ch == '[') {
900 for(i=0;i<MAX_ESC_PARAMS;i++)
901 s->esc_params[i] = 0;
902 s->nb_esc_params = 0;
903 s->state = TTY_STATE_CSI;
904 } else {
905 s->state = TTY_STATE_NORM;
906 }
907 break;
908 case TTY_STATE_CSI: /* handle escape sequence parameters */
909 if (ch >= '0' && ch <= '9') {
910 if (s->nb_esc_params < MAX_ESC_PARAMS) {
911 s->esc_params[s->nb_esc_params] =
912 s->esc_params[s->nb_esc_params] * 10 + ch - '0';
913 }
914 } else {
915 s->nb_esc_params++;
916 if (ch == ';')
917 break;
918#ifdef DEBUG_CONSOLE
919 fprintf(stderr, "escape sequence CSI%d;%d%c, %d parameters\n",
920 s->esc_params[0], s->esc_params[1], ch, s->nb_esc_params);
921#endif
922 s->state = TTY_STATE_NORM;
923 switch(ch) {
924 case 'A':
925 /* move cursor up */
926 if (s->esc_params[0] == 0) {
927 s->esc_params[0] = 1;
928 }
929 s->y -= s->esc_params[0];
930 if (s->y < 0) {
931 s->y = 0;
932 }
933 break;
934 case 'B':
935 /* move cursor down */
936 if (s->esc_params[0] == 0) {
937 s->esc_params[0] = 1;
938 }
939 s->y += s->esc_params[0];
940 if (s->y >= s->height) {
941 s->y = s->height - 1;
942 }
943 break;
944 case 'C':
945 /* move cursor right */
946 if (s->esc_params[0] == 0) {
947 s->esc_params[0] = 1;
948 }
949 s->x += s->esc_params[0];
950 if (s->x >= s->width) {
951 s->x = s->width - 1;
952 }
953 break;
954 case 'D':
955 /* move cursor left */
956 if (s->esc_params[0] == 0) {
957 s->esc_params[0] = 1;
958 }
959 s->x -= s->esc_params[0];
960 if (s->x < 0) {
961 s->x = 0;
962 }
963 break;
964 case 'G':
965 /* move cursor to column */
966 s->x = s->esc_params[0] - 1;
967 if (s->x < 0) {
968 s->x = 0;
969 }
970 break;
971 case 'f':
972 case 'H':
973 /* move cursor to row, column */
974 s->x = s->esc_params[1] - 1;
975 if (s->x < 0) {
976 s->x = 0;
977 }
978 s->y = s->esc_params[0] - 1;
979 if (s->y < 0) {
980 s->y = 0;
981 }
982 break;
983 case 'J':
984 switch (s->esc_params[0]) {
985 case 0:
986 /* clear to end of screen */
987 for (y = s->y; y < s->height; y++) {
988 for (x = 0; x < s->width; x++) {
989 if (y == s->y && x < s->x) {
990 continue;
991 }
992 console_clear_xy(s, x, y);
993 }
994 }
995 break;
996 case 1:
997 /* clear from beginning of screen */
998 for (y = 0; y <= s->y; y++) {
999 for (x = 0; x < s->width; x++) {
1000 if (y == s->y && x > s->x) {
1001 break;
1002 }
1003 console_clear_xy(s, x, y);
1004 }
1005 }
1006 break;
1007 case 2:
1008 /* clear entire screen */
1009 for (y = 0; y <= s->height; y++) {
1010 for (x = 0; x < s->width; x++) {
1011 console_clear_xy(s, x, y);
1012 }
1013 }
1014 break;
1015 }
1016 case 'K':
1017 switch (s->esc_params[0]) {
1018 case 0:
1019 /* clear to eol */
1020 for(x = s->x; x < s->width; x++) {
1021 console_clear_xy(s, x, s->y);
1022 }
1023 break;
1024 case 1:
1025 /* clear from beginning of line */
1026 for (x = 0; x <= s->x; x++) {
1027 console_clear_xy(s, x, s->y);
1028 }
1029 break;
1030 case 2:
1031 /* clear entire line */
1032 for(x = 0; x < s->width; x++) {
1033 console_clear_xy(s, x, s->y);
1034 }
1035 break;
1036 }
1037 break;
1038 case 'm':
1039 console_handle_escape(s);
1040 break;
1041 case 'n':
1042 /* report cursor position */
1043 /* TODO: send ESC[row;colR */
1044 break;
1045 case 's':
1046 /* save cursor position */
1047 s->x_saved = s->x;
1048 s->y_saved = s->y;
1049 break;
1050 case 'u':
1051 /* restore cursor position */
1052 s->x = s->x_saved;
1053 s->y = s->y_saved;
1054 break;
1055 default:
1056#ifdef DEBUG_CONSOLE
1057 fprintf(stderr, "unhandled escape character '%c'\n", ch);
1058#endif
1059 break;
1060 }
1061 break;
1062 }
1063 }
1064}
1065
1066void console_select(unsigned int index)
1067{
1068 TextConsole *s;
1069
1070 if (index >= MAX_CONSOLES)
1071 return;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001072 active_console->g_width = ds_get_width(active_console->ds);
1073 active_console->g_height = ds_get_height(active_console->ds);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001074 s = consoles[index];
1075 if (s) {
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001076 DisplayState *ds = s->ds;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001077 active_console = s;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001078 if (ds_get_bits_per_pixel(s->ds)) {
1079 ds->surface = qemu_resize_displaysurface(ds, s->g_width, s->g_height);
1080 } else {
1081 s->ds->surface->width = s->width;
1082 s->ds->surface->height = s->height;
1083 }
1084 dpy_resize(s->ds);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001085 vga_hw_invalidate();
1086 }
1087}
1088
1089static int console_puts(CharDriverState *chr, const uint8_t *buf, int len)
1090{
1091 TextConsole *s = chr->opaque;
1092 int i;
1093
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001094 s->update_x0 = s->width * FONT_WIDTH;
1095 s->update_y0 = s->height * FONT_HEIGHT;
1096 s->update_x1 = 0;
1097 s->update_y1 = 0;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001098 console_show_cursor(s, 0);
1099 for(i = 0; i < len; i++) {
1100 console_putchar(s, buf[i]);
1101 }
1102 console_show_cursor(s, 1);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001103 if (ds_get_bits_per_pixel(s->ds) && s->update_x0 < s->update_x1) {
1104 dpy_update(s->ds, s->update_x0, s->update_y0,
1105 s->update_x1 - s->update_x0,
1106 s->update_y1 - s->update_y0);
1107 }
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001108 return len;
1109}
1110
1111static void console_send_event(CharDriverState *chr, int event)
1112{
1113 TextConsole *s = chr->opaque;
1114 int i;
1115
1116 if (event == CHR_EVENT_FOCUS) {
1117 for(i = 0; i < nb_consoles; i++) {
1118 if (consoles[i] == s) {
1119 console_select(i);
1120 break;
1121 }
1122 }
1123 }
1124}
1125
1126static void kbd_send_chars(void *opaque)
1127{
1128 TextConsole *s = opaque;
1129 int len;
1130 uint8_t buf[16];
1131
1132 len = qemu_chr_can_read(s->chr);
1133 if (len > s->out_fifo.count)
1134 len = s->out_fifo.count;
1135 if (len > 0) {
1136 if (len > sizeof(buf))
1137 len = sizeof(buf);
1138 qemu_fifo_read(&s->out_fifo, buf, len);
1139 qemu_chr_read(s->chr, buf, len);
1140 }
1141 /* characters are pending: we send them a bit later (XXX:
1142 horrible, should change char device API) */
1143 if (s->out_fifo.count > 0) {
1144 qemu_mod_timer(s->kbd_timer, qemu_get_clock(rt_clock) + 1);
1145 }
1146}
1147
1148/* called when an ascii key is pressed */
1149void kbd_put_keysym(int keysym)
1150{
1151 TextConsole *s;
1152 uint8_t buf[16], *q;
1153 int c;
1154
1155 s = active_console;
1156 if (!s || (s->console_type == GRAPHIC_CONSOLE))
1157 return;
1158
1159 switch(keysym) {
1160 case QEMU_KEY_CTRL_UP:
1161 console_scroll(-1);
1162 break;
1163 case QEMU_KEY_CTRL_DOWN:
1164 console_scroll(1);
1165 break;
1166 case QEMU_KEY_CTRL_PAGEUP:
1167 console_scroll(-10);
1168 break;
1169 case QEMU_KEY_CTRL_PAGEDOWN:
1170 console_scroll(10);
1171 break;
1172 default:
1173 /* convert the QEMU keysym to VT100 key string */
1174 q = buf;
1175 if (keysym >= 0xe100 && keysym <= 0xe11f) {
1176 *q++ = '\033';
1177 *q++ = '[';
1178 c = keysym - 0xe100;
1179 if (c >= 10)
1180 *q++ = '0' + (c / 10);
1181 *q++ = '0' + (c % 10);
1182 *q++ = '~';
1183 } else if (keysym >= 0xe120 && keysym <= 0xe17f) {
1184 *q++ = '\033';
1185 *q++ = '[';
1186 *q++ = keysym & 0xff;
1187 } else {
1188 *q++ = keysym;
1189 }
1190 if (s->chr->chr_read) {
1191 qemu_fifo_write(&s->out_fifo, buf, q - buf);
1192 kbd_send_chars(s);
1193 }
1194 break;
1195 }
1196}
1197
1198static void text_console_invalidate(void *opaque)
1199{
1200 TextConsole *s = (TextConsole *) opaque;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001201 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 }
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001206 console_refresh(s);
1207}
1208
1209static void text_console_update(void *opaque, console_ch_t *chardata)
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
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001236static TextConsole *get_graphic_console(DisplayState *ds)
1237{
1238 int i;
1239 TextConsole *s;
1240 for (i = 0; i < nb_consoles; i++) {
1241 s = consoles[i];
1242 if (s->console_type == GRAPHIC_CONSOLE && s->ds == ds)
1243 return s;
1244 }
1245 return NULL;
1246}
1247
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001248static TextConsole *new_console(DisplayState *ds, console_type_t console_type)
1249{
1250 TextConsole *s;
1251 int i;
1252
1253 if (nb_consoles >= MAX_CONSOLES)
1254 return NULL;
1255 s = qemu_mallocz(sizeof(TextConsole));
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001256 if (!active_console || ((active_console->console_type != GRAPHIC_CONSOLE) &&
1257 (console_type == GRAPHIC_CONSOLE))) {
1258 active_console = s;
1259 }
1260 s->ds = ds;
1261 s->console_type = console_type;
1262 if (console_type != GRAPHIC_CONSOLE) {
1263 consoles[nb_consoles++] = s;
1264 } else {
1265 /* HACK: Put graphical consoles before text consoles. */
1266 for (i = nb_consoles; i > 0; i--) {
1267 if (consoles[i - 1]->console_type == GRAPHIC_CONSOLE)
1268 break;
1269 consoles[i] = consoles[i - 1];
1270 }
1271 consoles[i] = s;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001272 nb_consoles++;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001273 }
1274 return s;
1275}
1276
David Turnerf52506f2010-09-10 16:11:22 +02001277static DisplaySurface* defaultallocator_create_displaysurface(int width, int height)
1278{
1279 DisplaySurface *surface = (DisplaySurface*) qemu_mallocz(sizeof(DisplaySurface));
1280
1281 surface->width = width;
1282 surface->height = height;
1283 surface->linesize = width * 4;
1284 surface->pf = qemu_default_pixelformat(32);
1285#ifdef HOST_WORDS_BIGENDIAN
1286 surface->flags = QEMU_ALLOCATED_FLAG | QEMU_BIG_ENDIAN_FLAG;
1287#else
1288 surface->flags = QEMU_ALLOCATED_FLAG;
1289#endif
1290 surface->data = (uint8_t*) qemu_mallocz(surface->linesize * surface->height);
1291
1292 return surface;
1293}
1294
1295static DisplaySurface* defaultallocator_resize_displaysurface(DisplaySurface *surface,
1296 int width, int height)
1297{
1298 surface->width = width;
1299 surface->height = height;
1300 surface->linesize = width * 4;
1301 surface->pf = qemu_default_pixelformat(32);
1302 if (surface->flags & QEMU_ALLOCATED_FLAG)
1303 surface->data = (uint8_t*) qemu_realloc(surface->data, surface->linesize * surface->height);
1304 else
1305 surface->data = (uint8_t*) qemu_malloc(surface->linesize * surface->height);
1306#ifdef HOST_WORDS_BIGENDIAN
1307 surface->flags = QEMU_ALLOCATED_FLAG | QEMU_BIG_ENDIAN_FLAG;
1308#else
1309 surface->flags = QEMU_ALLOCATED_FLAG;
1310#endif
1311
1312 return surface;
1313}
1314
1315DisplaySurface* qemu_create_displaysurface_from(int width, int height, int bpp,
1316 int linesize, uint8_t *data)
1317{
1318 DisplaySurface *surface = (DisplaySurface*) qemu_mallocz(sizeof(DisplaySurface));
1319
1320 surface->width = width;
1321 surface->height = height;
1322 surface->linesize = linesize;
1323 surface->pf = qemu_default_pixelformat(bpp);
1324#ifdef HOST_WORDS_BIGENDIAN
1325 surface->flags = QEMU_BIG_ENDIAN_FLAG;
1326#endif
1327 surface->data = data;
1328
1329 return surface;
1330}
1331
1332static void defaultallocator_free_displaysurface(DisplaySurface *surface)
1333{
1334 if (surface == NULL)
1335 return;
1336 if (surface->flags & QEMU_ALLOCATED_FLAG)
1337 qemu_free(surface->data);
1338 qemu_free(surface);
1339}
1340
1341static struct DisplayAllocator default_allocator = {
1342 defaultallocator_create_displaysurface,
1343 defaultallocator_resize_displaysurface,
1344 defaultallocator_free_displaysurface
1345};
1346
1347static void dumb_display_init(void)
1348{
1349 DisplayState *ds = qemu_mallocz(sizeof(DisplayState));
1350 ds->allocator = &default_allocator;
1351 ds->surface = qemu_create_displaysurface(ds, 640, 480);
1352 register_displaystate(ds);
1353}
1354
1355/***********************************************************/
1356/* register display */
1357
1358void register_displaystate(DisplayState *ds)
1359{
1360 DisplayState **s;
1361 s = &display_state;
1362 while (*s != NULL)
1363 s = &(*s)->next;
1364 ds->next = NULL;
1365 *s = ds;
1366}
1367
1368DisplayState *get_displaystate(void)
1369{
1370 if (!display_state) {
1371 dumb_display_init ();
1372 }
1373 return display_state;
1374}
1375
1376DisplayAllocator *register_displayallocator(DisplayState *ds, DisplayAllocator *da)
1377{
1378 if(ds->allocator == &default_allocator) {
1379 DisplaySurface *surf;
1380 surf = da->create_displaysurface(ds_get_width(ds), ds_get_height(ds));
1381 defaultallocator_free_displaysurface(ds->surface);
1382 ds->surface = surf;
1383 ds->allocator = da;
1384 }
1385 return ds->allocator;
1386}
1387
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001388DisplayState *graphic_console_init(vga_hw_update_ptr update,
1389 vga_hw_invalidate_ptr invalidate,
1390 vga_hw_screen_dump_ptr screen_dump,
1391 vga_hw_text_update_ptr text_update,
1392 void *opaque)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001393{
1394 TextConsole *s;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001395 DisplayState *ds;
1396
1397 ds = (DisplayState *) qemu_mallocz(sizeof(DisplayState));
Vladimir Chtchetkine90c62352011-01-13 11:24:07 -08001398 ds->allocator = &default_allocator;
David Turnerf52506f2010-09-10 16:11:22 +02001399#ifdef CONFIG_ANDROID
Vladimir Chtchetkinedd50f7d2010-07-30 09:16:41 -07001400 ds->surface = qemu_create_displaysurface(ds, android_display_width, android_display_height);
David Turnerf52506f2010-09-10 16:11:22 +02001401#else
1402 ds->surface = qemu_create_displaysurface(ds, 640, 480);
1403#endif
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001404
1405 s = new_console(ds, GRAPHIC_CONSOLE);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001406 if (s == NULL) {
1407 qemu_free_displaysurface(ds);
1408 qemu_free(ds);
1409 return NULL;
1410 }
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001411 s->hw_update = update;
1412 s->hw_invalidate = invalidate;
1413 s->hw_screen_dump = screen_dump;
1414 s->hw_text_update = text_update;
1415 s->hw = opaque;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001416
1417 register_displaystate(ds);
1418 return ds;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001419}
1420
1421int is_graphic_console(void)
1422{
1423 return active_console && active_console->console_type == GRAPHIC_CONSOLE;
1424}
1425
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001426int is_fixedsize_console(void)
1427{
1428 return active_console && active_console->console_type != TEXT_CONSOLE;
1429}
1430
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001431void console_color_init(DisplayState *ds)
1432{
1433 int i, j;
1434 for (j = 0; j < 2; j++) {
1435 for (i = 0; i < 8; i++) {
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001436 color_table[j][i] = col_expand(ds,
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001437 vga_get_color(ds, color_table_rgb[j][i]));
1438 }
1439 }
1440}
1441
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001442static int n_text_consoles;
1443static CharDriverState *text_consoles[128];
David Turnerf52506f2010-09-10 16:11:22 +02001444static QemuOpts *text_console_opts[128];
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001445
David Turnerf52506f2010-09-10 16:11:22 +02001446static void text_console_do_init(CharDriverState *chr, DisplayState *ds, QemuOpts *opts)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001447{
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001448 TextConsole *s;
1449 unsigned width;
1450 unsigned height;
1451 static int color_inited;
1452
David Turnerf52506f2010-09-10 16:11:22 +02001453 width = qemu_opt_get_number(opts, "width", 0);
1454 if (width == 0)
1455 width = qemu_opt_get_number(opts, "cols", 0) * FONT_WIDTH;
1456
1457 height = qemu_opt_get_number(opts, "height", 0);
1458 if (height == 0)
1459 height = qemu_opt_get_number(opts, "rows", 0) * FONT_HEIGHT;
1460
1461 if (width == 0 || height == 0) {
1462 s = new_console(ds, TEXT_CONSOLE);
1463 width = ds_get_width(s->ds);
1464 height = ds_get_height(s->ds);
1465 } else {
1466 s = new_console(ds, TEXT_CONSOLE_FIXED_SIZE);
1467 }
1468
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001469 if (!s) {
1470 free(chr);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001471 return;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001472 }
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001473 chr->opaque = s;
1474 chr->chr_write = console_puts;
1475 chr->chr_send_event = console_send_event;
1476
1477 s->chr = chr;
1478 s->out_fifo.buf = s->out_fifo_buf;
1479 s->out_fifo.buf_size = sizeof(s->out_fifo_buf);
1480 s->kbd_timer = qemu_new_timer(rt_clock, kbd_send_chars, s);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001481 s->ds = ds;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001482
1483 if (!color_inited) {
1484 color_inited = 1;
1485 console_color_init(s->ds);
1486 }
1487 s->y_displayed = 0;
1488 s->y_base = 0;
1489 s->total_height = DEFAULT_BACKSCROLL;
1490 s->x = 0;
1491 s->y = 0;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001492 s->g_width = width;
1493 s->g_height = height;
1494
1495 s->hw_invalidate = text_console_invalidate;
1496 s->hw_text_update = text_console_update;
1497 s->hw = s;
1498
1499 /* Set text attribute defaults */
1500 s->t_attrib_default.bold = 0;
1501 s->t_attrib_default.uline = 0;
1502 s->t_attrib_default.blink = 0;
1503 s->t_attrib_default.invers = 0;
1504 s->t_attrib_default.unvisible = 0;
1505 s->t_attrib_default.fgcol = COLOR_WHITE;
1506 s->t_attrib_default.bgcol = COLOR_BLACK;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001507 /* set current text attributes to default */
1508 s->t_attrib = s->t_attrib_default;
1509 text_console_resize(s);
1510
David Turnerf52506f2010-09-10 16:11:22 +02001511 if (chr->label) {
1512 char msg[128];
1513 int len;
1514
1515 s->t_attrib.bgcol = COLOR_BLUE;
1516 len = snprintf(msg, sizeof(msg), "%s console\r\n", chr->label);
1517 console_puts(chr, (uint8_t*)msg, len);
1518 s->t_attrib = s->t_attrib_default;
1519 }
1520
David Turner9d118822010-09-10 13:02:07 +02001521 qemu_chr_generic_open(chr);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001522 if (chr->init)
1523 chr->init(chr);
1524}
1525
David Turnerf52506f2010-09-10 16:11:22 +02001526CharDriverState *text_console_init(QemuOpts *opts)
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001527{
1528 CharDriverState *chr;
1529
1530 chr = qemu_mallocz(sizeof(CharDriverState));
1531
1532 if (n_text_consoles == 128) {
1533 fprintf(stderr, "Too many text consoles\n");
1534 exit(1);
1535 }
1536 text_consoles[n_text_consoles] = chr;
David Turnerf52506f2010-09-10 16:11:22 +02001537 text_console_opts[n_text_consoles] = opts;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001538 n_text_consoles++;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001539
1540 return chr;
1541}
1542
David Turnerf52506f2010-09-10 16:11:22 +02001543CharDriverState* text_console_init_compat(const char *label, const char *p)
1544{
1545 QemuOpts *opts;
1546 int width, height;
1547 char temp[32];
1548
1549 opts = qemu_opts_create(qemu_find_opts("chardev"), label, 1);
1550 if (NULL == opts)
1551 return NULL;
1552
1553 if (p != NULL) {
1554 width = strtoul(p, (char **)&p, 10);
1555 if (*p == 'C') {
1556 p++;
1557 width *= FONT_WIDTH;
1558 }
1559 snprintf(temp, sizeof temp, "%d", width);
1560 qemu_opt_set(opts, "width", temp);
1561 if (*p == 'x') {
1562 p++;
1563 height = strtoul(p, (char **)&p, 10);
1564 if (*p == 'C') {
1565 p++;
1566 height *= FONT_HEIGHT;
1567 }
1568 snprintf(temp, sizeof temp, "%d", height);
1569 qemu_opt_set(opts, "height", temp);
1570 }
1571 }
1572 return text_console_init(opts);
1573}
1574
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001575void text_consoles_set_display(DisplayState *ds)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001576{
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001577 int i;
1578
1579 for (i = 0; i < n_text_consoles; i++) {
David Turnerf52506f2010-09-10 16:11:22 +02001580 text_console_do_init(text_consoles[i], ds, text_console_opts[i]);
1581 qemu_opts_del(text_console_opts[i]);
1582 text_console_opts[i] = NULL;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001583 }
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001584
1585 n_text_consoles = 0;
1586}
1587
1588void qemu_console_resize(DisplayState *ds, int width, int height)
1589{
1590 TextConsole *s = get_graphic_console(ds);
1591 if (!s) return;
1592
1593 s->g_width = width;
1594 s->g_height = height;
1595 if (is_graphic_console()) {
1596 ds->surface = qemu_resize_displaysurface(ds, width, height);
1597 dpy_resize(ds);
1598 }
1599}
1600
1601void qemu_console_copy(DisplayState *ds, int src_x, int src_y,
1602 int dst_x, int dst_y, int w, int h)
1603{
1604 if (is_graphic_console()) {
1605 dpy_copy(ds, src_x, src_y, dst_x, dst_y, w, h);
1606 }
1607}
1608
1609PixelFormat qemu_different_endianness_pixelformat(int bpp)
1610{
1611 PixelFormat pf;
1612
1613 memset(&pf, 0x00, sizeof(PixelFormat));
1614
1615 pf.bits_per_pixel = bpp;
1616 pf.bytes_per_pixel = bpp / 8;
1617 pf.depth = bpp == 32 ? 24 : bpp;
1618
1619 switch (bpp) {
1620 case 24:
1621 pf.rmask = 0x000000FF;
1622 pf.gmask = 0x0000FF00;
1623 pf.bmask = 0x00FF0000;
1624 pf.rmax = 255;
1625 pf.gmax = 255;
1626 pf.bmax = 255;
1627 pf.rshift = 0;
1628 pf.gshift = 8;
1629 pf.bshift = 16;
1630 pf.rbits = 8;
1631 pf.gbits = 8;
1632 pf.bbits = 8;
1633 break;
1634 case 32:
1635 pf.rmask = 0x0000FF00;
1636 pf.gmask = 0x00FF0000;
1637 pf.bmask = 0xFF000000;
1638 pf.amask = 0x00000000;
1639 pf.amax = 255;
1640 pf.rmax = 255;
1641 pf.gmax = 255;
1642 pf.bmax = 255;
1643 pf.ashift = 0;
1644 pf.rshift = 8;
1645 pf.gshift = 16;
1646 pf.bshift = 24;
1647 pf.rbits = 8;
1648 pf.gbits = 8;
1649 pf.bbits = 8;
1650 pf.abits = 8;
1651 break;
1652 default:
1653 break;
1654 }
1655 return pf;
1656}
1657
1658PixelFormat qemu_default_pixelformat(int bpp)
1659{
1660 PixelFormat pf;
1661
1662 memset(&pf, 0x00, sizeof(PixelFormat));
1663
1664 pf.bits_per_pixel = bpp;
1665 pf.bytes_per_pixel = bpp / 8;
1666 pf.depth = bpp == 32 ? 24 : bpp;
1667
1668 switch (bpp) {
David Turnerf52506f2010-09-10 16:11:22 +02001669 case 15:
1670 pf.bits_per_pixel = 16;
1671 pf.bytes_per_pixel = 2;
1672 pf.rmask = 0x00007c00;
1673 pf.gmask = 0x000003E0;
1674 pf.bmask = 0x0000001F;
1675 pf.rmax = 31;
1676 pf.gmax = 31;
1677 pf.bmax = 31;
1678 pf.rshift = 10;
1679 pf.gshift = 5;
1680 pf.bshift = 0;
1681 pf.rbits = 5;
1682 pf.gbits = 5;
1683 pf.bbits = 5;
1684 break;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001685 case 16:
1686 pf.rmask = 0x0000F800;
1687 pf.gmask = 0x000007E0;
1688 pf.bmask = 0x0000001F;
1689 pf.rmax = 31;
1690 pf.gmax = 63;
1691 pf.bmax = 31;
1692 pf.rshift = 11;
1693 pf.gshift = 5;
1694 pf.bshift = 0;
1695 pf.rbits = 5;
1696 pf.gbits = 6;
1697 pf.bbits = 5;
1698 break;
1699 case 24:
1700 pf.rmask = 0x00FF0000;
1701 pf.gmask = 0x0000FF00;
1702 pf.bmask = 0x000000FF;
1703 pf.rmax = 255;
1704 pf.gmax = 255;
1705 pf.bmax = 255;
1706 pf.rshift = 16;
1707 pf.gshift = 8;
1708 pf.bshift = 0;
1709 pf.rbits = 8;
1710 pf.gbits = 8;
1711 pf.bbits = 8;
1712 case 32:
1713 pf.rmask = 0x00FF0000;
1714 pf.gmask = 0x0000FF00;
1715 pf.bmask = 0x000000FF;
1716 pf.amax = 255;
1717 pf.rmax = 255;
1718 pf.gmax = 255;
1719 pf.bmax = 255;
1720 pf.ashift = 24;
1721 pf.rshift = 16;
1722 pf.gshift = 8;
1723 pf.bshift = 0;
1724 pf.rbits = 8;
1725 pf.gbits = 8;
1726 pf.bbits = 8;
1727 pf.abits = 8;
1728 break;
1729 default:
1730 break;
1731 }
1732 return pf;
1733}
1734
David Turnerf52506f2010-09-10 16:11:22 +02001735#ifdef CONFIG_ANDROID
David 'Digit' Turner7a5ee572011-02-02 15:58:45 +01001736
1737void
1738unregister_displayupdatelistener(DisplayState *ds, DisplayUpdateListener *dul)
1739{
1740 DisplayUpdateListener **pnode = &ds->update_listeners;
1741 for (;;) {
1742 if (*pnode == NULL)
1743 break;
1744 if (*pnode == dul) {
1745 *pnode = dul->next;
1746 break;
1747 }
1748 pnode = &(*pnode)->next;
1749 }
1750 dul->next = NULL;
1751}
1752
David Turnerf52506f2010-09-10 16:11:22 +02001753void
David 'Digit' Turner94702b02011-01-20 02:46:33 +01001754android_display_reset(DisplayState* ds, int width, int height, int bitspp)
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001755{
David 'Digit' Turner94702b02011-01-20 02:46:33 +01001756 DisplaySurface* surface;
1757 int bytespp = (bitspp+7)/8;
1758 int pitch = (bytespp*width + 3) & ~3;
1759
1760 qemu_free_displaysurface(ds);
1761
1762 surface = (DisplaySurface*) qemu_mallocz(sizeof(DisplaySurface));
1763
1764 surface->width = width;
1765 surface->height = height;
1766 surface->linesize = pitch;
1767 surface->pf = qemu_default_pixelformat(bitspp);
1768 surface->data = (uint8_t*) qemu_malloc(surface->linesize * surface->height);
1769#ifdef HOST_WORDS_BIGENDIAN
1770 surface->flags = QEMU_ALLOCATED_FLAG | QEMU_BIG_ENDIAN_FLAG;
1771#else
1772 surface->flags = QEMU_ALLOCATED_FLAG;
1773#endif
1774
1775 ds->surface = surface;
David Turnerf52506f2010-09-10 16:11:22 +02001776}
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001777#endif