blob: 50dda6c024b08c59ca1609af4fa6f9aaa40fcd66 [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
157static TextConsole *active_console;
158static TextConsole *consoles[MAX_CONSOLES];
159static int nb_consoles = 0;
160
Vladimir Chtchetkinedd50f7d2010-07-30 09:16:41 -0700161/* Graphic console width, height and bits per pixel.
162 * These default values can be changed with the "-android-gui" option.
163 */
164int android_display_width = 640;
165int android_display_height = 480;
166int android_display_bpp = 32;
167
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800168void vga_hw_update(void)
169{
170 if (active_console && active_console->hw_update)
171 active_console->hw_update(active_console->hw);
172}
173
174void vga_hw_invalidate(void)
175{
David Turner9d118822010-09-10 13:02:07 +0200176 if (active_console && active_console->hw_invalidate)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800177 active_console->hw_invalidate(active_console->hw);
178}
179
180void vga_hw_screen_dump(const char *filename)
181{
182 TextConsole *previous_active_console;
183
184 previous_active_console = active_console;
185 active_console = consoles[0];
186 /* There is currently no way of specifying which screen we want to dump,
187 so always dump the first one. */
188 if (consoles[0]->hw_screen_dump)
189 consoles[0]->hw_screen_dump(consoles[0]->hw, filename);
190 active_console = previous_active_console;
191}
192
193void vga_hw_text_update(console_ch_t *chardata)
194{
195 if (active_console && active_console->hw_text_update)
196 active_console->hw_text_update(active_console->hw, chardata);
197}
198
199/* convert a RGBA color to a color index usable in graphic primitives */
200static unsigned int vga_get_color(DisplayState *ds, unsigned int rgba)
201{
202 unsigned int r, g, b, color;
203
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700204 switch(ds_get_bits_per_pixel(ds)) {
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800205#if 0
206 case 8:
207 r = (rgba >> 16) & 0xff;
208 g = (rgba >> 8) & 0xff;
209 b = (rgba) & 0xff;
210 color = (rgb_to_index[r] * 6 * 6) +
211 (rgb_to_index[g] * 6) +
212 (rgb_to_index[b]);
213 break;
214#endif
215 case 15:
216 r = (rgba >> 16) & 0xff;
217 g = (rgba >> 8) & 0xff;
218 b = (rgba) & 0xff;
219 color = ((r >> 3) << 10) | ((g >> 3) << 5) | (b >> 3);
220 break;
221 case 16:
222 r = (rgba >> 16) & 0xff;
223 g = (rgba >> 8) & 0xff;
224 b = (rgba) & 0xff;
225 color = ((r >> 3) << 11) | ((g >> 2) << 5) | (b >> 3);
226 break;
227 case 32:
228 default:
229 color = rgba;
230 break;
231 }
232 return color;
233}
234
235static void vga_fill_rect (DisplayState *ds,
236 int posx, int posy, int width, int height, uint32_t color)
237{
238 uint8_t *d, *d1;
239 int x, y, bpp;
240
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700241 bpp = (ds_get_bits_per_pixel(ds) + 7) >> 3;
242 d1 = ds_get_data(ds) +
243 ds_get_linesize(ds) * posy + bpp * posx;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800244 for (y = 0; y < height; y++) {
245 d = d1;
246 switch(bpp) {
247 case 1:
248 for (x = 0; x < width; x++) {
249 *((uint8_t *)d) = color;
250 d++;
251 }
252 break;
253 case 2:
254 for (x = 0; x < width; x++) {
255 *((uint16_t *)d) = color;
256 d += 2;
257 }
258 break;
259 case 4:
260 for (x = 0; x < width; x++) {
261 *((uint32_t *)d) = color;
262 d += 4;
263 }
264 break;
265 }
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700266 d1 += ds_get_linesize(ds);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800267 }
268}
269
270/* copy from (xs, ys) to (xd, yd) a rectangle of size (w, h) */
271static void vga_bitblt(DisplayState *ds, int xs, int ys, int xd, int yd, int w, int h)
272{
273 const uint8_t *s;
274 uint8_t *d;
275 int wb, y, bpp;
276
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700277 bpp = (ds_get_bits_per_pixel(ds) + 7) >> 3;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800278 wb = w * bpp;
279 if (yd <= ys) {
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700280 s = ds_get_data(ds) +
281 ds_get_linesize(ds) * ys + bpp * xs;
282 d = ds_get_data(ds) +
283 ds_get_linesize(ds) * yd + bpp * xd;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800284 for (y = 0; y < h; y++) {
285 memmove(d, s, wb);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700286 d += ds_get_linesize(ds);
287 s += ds_get_linesize(ds);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800288 }
289 } else {
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700290 s = ds_get_data(ds) +
291 ds_get_linesize(ds) * (ys + h - 1) + bpp * xs;
292 d = ds_get_data(ds) +
293 ds_get_linesize(ds) * (yd + h - 1) + bpp * xd;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800294 for (y = 0; y < h; y++) {
295 memmove(d, s, wb);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700296 d -= ds_get_linesize(ds);
297 s -= ds_get_linesize(ds);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800298 }
299 }
300}
301
302/***********************************************************/
303/* basic char display */
304
305#define FONT_HEIGHT 16
306#define FONT_WIDTH 8
307
308#include "vgafont.h"
309
310#define cbswap_32(__x) \
311((uint32_t)( \
312 (((uint32_t)(__x) & (uint32_t)0x000000ffUL) << 24) | \
313 (((uint32_t)(__x) & (uint32_t)0x0000ff00UL) << 8) | \
314 (((uint32_t)(__x) & (uint32_t)0x00ff0000UL) >> 8) | \
315 (((uint32_t)(__x) & (uint32_t)0xff000000UL) >> 24) ))
316
David 'Digit' Turner20894ae2010-05-10 17:07:36 -0700317#ifdef HOST_WORDS_BIGENDIAN
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800318#define PAT(x) x
319#else
320#define PAT(x) cbswap_32(x)
321#endif
322
323static const uint32_t dmask16[16] = {
324 PAT(0x00000000),
325 PAT(0x000000ff),
326 PAT(0x0000ff00),
327 PAT(0x0000ffff),
328 PAT(0x00ff0000),
329 PAT(0x00ff00ff),
330 PAT(0x00ffff00),
331 PAT(0x00ffffff),
332 PAT(0xff000000),
333 PAT(0xff0000ff),
334 PAT(0xff00ff00),
335 PAT(0xff00ffff),
336 PAT(0xffff0000),
337 PAT(0xffff00ff),
338 PAT(0xffffff00),
339 PAT(0xffffffff),
340};
341
342static const uint32_t dmask4[4] = {
343 PAT(0x00000000),
344 PAT(0x0000ffff),
345 PAT(0xffff0000),
346 PAT(0xffffffff),
347};
348
349static uint32_t color_table[2][8];
350
351enum color_names {
352 COLOR_BLACK = 0,
353 COLOR_RED = 1,
354 COLOR_GREEN = 2,
355 COLOR_YELLOW = 3,
356 COLOR_BLUE = 4,
357 COLOR_MAGENTA = 5,
358 COLOR_CYAN = 6,
359 COLOR_WHITE = 7
360};
361
362static const uint32_t color_table_rgb[2][8] = {
363 { /* dark */
364 QEMU_RGB(0x00, 0x00, 0x00), /* black */
365 QEMU_RGB(0xaa, 0x00, 0x00), /* red */
366 QEMU_RGB(0x00, 0xaa, 0x00), /* green */
367 QEMU_RGB(0xaa, 0xaa, 0x00), /* yellow */
368 QEMU_RGB(0x00, 0x00, 0xaa), /* blue */
369 QEMU_RGB(0xaa, 0x00, 0xaa), /* magenta */
370 QEMU_RGB(0x00, 0xaa, 0xaa), /* cyan */
371 QEMU_RGB(0xaa, 0xaa, 0xaa), /* white */
372 },
373 { /* bright */
374 QEMU_RGB(0x00, 0x00, 0x00), /* black */
375 QEMU_RGB(0xff, 0x00, 0x00), /* red */
376 QEMU_RGB(0x00, 0xff, 0x00), /* green */
377 QEMU_RGB(0xff, 0xff, 0x00), /* yellow */
378 QEMU_RGB(0x00, 0x00, 0xff), /* blue */
379 QEMU_RGB(0xff, 0x00, 0xff), /* magenta */
380 QEMU_RGB(0x00, 0xff, 0xff), /* cyan */
381 QEMU_RGB(0xff, 0xff, 0xff), /* white */
382 }
383};
384
385static inline unsigned int col_expand(DisplayState *ds, unsigned int col)
386{
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700387 switch(ds_get_bits_per_pixel(ds)) {
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800388 case 8:
389 col |= col << 8;
390 col |= col << 16;
391 break;
392 case 15:
393 case 16:
394 col |= col << 16;
395 break;
396 default:
397 break;
398 }
399
400 return col;
401}
402#ifdef DEBUG_CONSOLE
403static void console_print_text_attributes(TextAttributes *t_attrib, char ch)
404{
405 if (t_attrib->bold) {
406 printf("b");
407 } else {
408 printf(" ");
409 }
410 if (t_attrib->uline) {
411 printf("u");
412 } else {
413 printf(" ");
414 }
415 if (t_attrib->blink) {
416 printf("l");
417 } else {
418 printf(" ");
419 }
420 if (t_attrib->invers) {
421 printf("i");
422 } else {
423 printf(" ");
424 }
425 if (t_attrib->unvisible) {
426 printf("n");
427 } else {
428 printf(" ");
429 }
430
431 printf(" fg: %d bg: %d ch:'%2X' '%c'\n", t_attrib->fgcol, t_attrib->bgcol, ch, ch);
432}
433#endif
434
435static void vga_putcharxy(DisplayState *ds, int x, int y, int ch,
436 TextAttributes *t_attrib)
437{
438 uint8_t *d;
439 const uint8_t *font_ptr;
440 unsigned int font_data, linesize, xorcol, bpp;
441 int i;
442 unsigned int fgcol, bgcol;
443
444#ifdef DEBUG_CONSOLE
445 printf("x: %2i y: %2i", x, y);
446 console_print_text_attributes(t_attrib, ch);
447#endif
448
449 if (t_attrib->invers) {
450 bgcol = color_table[t_attrib->bold][t_attrib->fgcol];
451 fgcol = color_table[t_attrib->bold][t_attrib->bgcol];
452 } else {
453 fgcol = color_table[t_attrib->bold][t_attrib->fgcol];
454 bgcol = color_table[t_attrib->bold][t_attrib->bgcol];
455 }
456
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700457 bpp = (ds_get_bits_per_pixel(ds) + 7) >> 3;
458 d = ds_get_data(ds) +
459 ds_get_linesize(ds) * y * FONT_HEIGHT + bpp * x * FONT_WIDTH;
460 linesize = ds_get_linesize(ds);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800461 font_ptr = vgafont16 + FONT_HEIGHT * ch;
462 xorcol = bgcol ^ fgcol;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700463 switch(ds_get_bits_per_pixel(ds)) {
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800464 case 8:
465 for(i = 0; i < FONT_HEIGHT; i++) {
466 font_data = *font_ptr++;
467 if (t_attrib->uline
468 && ((i == FONT_HEIGHT - 2) || (i == FONT_HEIGHT - 3))) {
469 font_data = 0xFFFF;
470 }
471 ((uint32_t *)d)[0] = (dmask16[(font_data >> 4)] & xorcol) ^ bgcol;
472 ((uint32_t *)d)[1] = (dmask16[(font_data >> 0) & 0xf] & xorcol) ^ bgcol;
473 d += linesize;
474 }
475 break;
476 case 16:
477 case 15:
478 for(i = 0; i < FONT_HEIGHT; i++) {
479 font_data = *font_ptr++;
480 if (t_attrib->uline
481 && ((i == FONT_HEIGHT - 2) || (i == FONT_HEIGHT - 3))) {
482 font_data = 0xFFFF;
483 }
484 ((uint32_t *)d)[0] = (dmask4[(font_data >> 6)] & xorcol) ^ bgcol;
485 ((uint32_t *)d)[1] = (dmask4[(font_data >> 4) & 3] & xorcol) ^ bgcol;
486 ((uint32_t *)d)[2] = (dmask4[(font_data >> 2) & 3] & xorcol) ^ bgcol;
487 ((uint32_t *)d)[3] = (dmask4[(font_data >> 0) & 3] & xorcol) ^ bgcol;
488 d += linesize;
489 }
490 break;
491 case 32:
492 for(i = 0; i < FONT_HEIGHT; i++) {
493 font_data = *font_ptr++;
494 if (t_attrib->uline && ((i == FONT_HEIGHT - 2) || (i == FONT_HEIGHT - 3))) {
495 font_data = 0xFFFF;
496 }
497 ((uint32_t *)d)[0] = (-((font_data >> 7)) & xorcol) ^ bgcol;
498 ((uint32_t *)d)[1] = (-((font_data >> 6) & 1) & xorcol) ^ bgcol;
499 ((uint32_t *)d)[2] = (-((font_data >> 5) & 1) & xorcol) ^ bgcol;
500 ((uint32_t *)d)[3] = (-((font_data >> 4) & 1) & xorcol) ^ bgcol;
501 ((uint32_t *)d)[4] = (-((font_data >> 3) & 1) & xorcol) ^ bgcol;
502 ((uint32_t *)d)[5] = (-((font_data >> 2) & 1) & xorcol) ^ bgcol;
503 ((uint32_t *)d)[6] = (-((font_data >> 1) & 1) & xorcol) ^ bgcol;
504 ((uint32_t *)d)[7] = (-((font_data >> 0) & 1) & xorcol) ^ bgcol;
505 d += linesize;
506 }
507 break;
508 }
509}
510
511static void text_console_resize(TextConsole *s)
512{
513 TextCell *cells, *c, *c1;
514 int w1, x, y, last_width;
515
516 last_width = s->width;
517 s->width = s->g_width / FONT_WIDTH;
518 s->height = s->g_height / FONT_HEIGHT;
519
520 w1 = last_width;
521 if (s->width < w1)
522 w1 = s->width;
523
524 cells = qemu_malloc(s->width * s->total_height * sizeof(TextCell));
525 for(y = 0; y < s->total_height; y++) {
526 c = &cells[y * s->width];
527 if (w1 > 0) {
528 c1 = &s->cells[y * last_width];
529 for(x = 0; x < w1; x++) {
530 *c++ = *c1++;
531 }
532 }
533 for(x = w1; x < s->width; x++) {
534 c->ch = ' ';
535 c->t_attrib = s->t_attrib_default;
536 c++;
537 }
538 }
539 qemu_free(s->cells);
540 s->cells = cells;
541}
542
543static inline void text_update_xy(TextConsole *s, int x, int y)
544{
545 s->text_x[0] = MIN(s->text_x[0], x);
546 s->text_x[1] = MAX(s->text_x[1], x);
547 s->text_y[0] = MIN(s->text_y[0], y);
548 s->text_y[1] = MAX(s->text_y[1], y);
549}
550
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700551static void invalidate_xy(TextConsole *s, int x, int y)
552{
553 if (s->update_x0 > x * FONT_WIDTH)
554 s->update_x0 = x * FONT_WIDTH;
555 if (s->update_y0 > y * FONT_HEIGHT)
556 s->update_y0 = y * FONT_HEIGHT;
557 if (s->update_x1 < (x + 1) * FONT_WIDTH)
558 s->update_x1 = (x + 1) * FONT_WIDTH;
559 if (s->update_y1 < (y + 1) * FONT_HEIGHT)
560 s->update_y1 = (y + 1) * FONT_HEIGHT;
561}
562
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800563static void update_xy(TextConsole *s, int x, int y)
564{
565 TextCell *c;
566 int y1, y2;
567
568 if (s == active_console) {
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700569 if (!ds_get_bits_per_pixel(s->ds)) {
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800570 text_update_xy(s, x, y);
571 return;
572 }
573
574 y1 = (s->y_base + y) % s->total_height;
575 y2 = y1 - s->y_displayed;
576 if (y2 < 0)
577 y2 += s->total_height;
578 if (y2 < s->height) {
579 c = &s->cells[y1 * s->width + x];
580 vga_putcharxy(s->ds, x, y2, c->ch,
581 &(c->t_attrib));
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700582 invalidate_xy(s, x, y2);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800583 }
584 }
585}
586
587static void console_show_cursor(TextConsole *s, int show)
588{
589 TextCell *c;
590 int y, y1;
591
592 if (s == active_console) {
593 int x = s->x;
594
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700595 if (!ds_get_bits_per_pixel(s->ds)) {
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800596 s->cursor_invalidate = 1;
597 return;
598 }
599
600 if (x >= s->width) {
601 x = s->width - 1;
602 }
603 y1 = (s->y_base + s->y) % s->total_height;
604 y = y1 - s->y_displayed;
605 if (y < 0)
606 y += s->total_height;
607 if (y < s->height) {
608 c = &s->cells[y1 * s->width + x];
609 if (show) {
610 TextAttributes t_attrib = s->t_attrib_default;
611 t_attrib.invers = !(t_attrib.invers); /* invert fg and bg */
612 vga_putcharxy(s->ds, x, y, c->ch, &t_attrib);
613 } else {
614 vga_putcharxy(s->ds, x, y, c->ch, &(c->t_attrib));
615 }
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700616 invalidate_xy(s, x, y);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800617 }
618 }
619}
620
621static void console_refresh(TextConsole *s)
622{
623 TextCell *c;
624 int x, y, y1;
625
626 if (s != active_console)
627 return;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700628 if (!ds_get_bits_per_pixel(s->ds)) {
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800629 s->text_x[0] = 0;
630 s->text_y[0] = 0;
631 s->text_x[1] = s->width - 1;
632 s->text_y[1] = s->height - 1;
633 s->cursor_invalidate = 1;
634 return;
635 }
636
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700637 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 -0800638 color_table[0][COLOR_BLACK]);
639 y1 = s->y_displayed;
640 for(y = 0; y < s->height; y++) {
641 c = s->cells + y1 * s->width;
642 for(x = 0; x < s->width; x++) {
643 vga_putcharxy(s->ds, x, y, c->ch,
644 &(c->t_attrib));
645 c++;
646 }
647 if (++y1 == s->total_height)
648 y1 = 0;
649 }
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800650 console_show_cursor(s, 1);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700651 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 -0800652}
653
654static void console_scroll(int ydelta)
655{
656 TextConsole *s;
657 int i, y1;
658
659 s = active_console;
660 if (!s || (s->console_type == GRAPHIC_CONSOLE))
661 return;
662
663 if (ydelta > 0) {
664 for(i = 0; i < ydelta; i++) {
665 if (s->y_displayed == s->y_base)
666 break;
667 if (++s->y_displayed == s->total_height)
668 s->y_displayed = 0;
669 }
670 } else {
671 ydelta = -ydelta;
672 i = s->backscroll_height;
673 if (i > s->total_height - s->height)
674 i = s->total_height - s->height;
675 y1 = s->y_base - i;
676 if (y1 < 0)
677 y1 += s->total_height;
678 for(i = 0; i < ydelta; i++) {
679 if (s->y_displayed == y1)
680 break;
681 if (--s->y_displayed < 0)
682 s->y_displayed = s->total_height - 1;
683 }
684 }
685 console_refresh(s);
686}
687
688static void console_put_lf(TextConsole *s)
689{
690 TextCell *c;
691 int x, y1;
692
693 s->y++;
694 if (s->y >= s->height) {
695 s->y = s->height - 1;
696
697 if (s->y_displayed == s->y_base) {
698 if (++s->y_displayed == s->total_height)
699 s->y_displayed = 0;
700 }
701 if (++s->y_base == s->total_height)
702 s->y_base = 0;
703 if (s->backscroll_height < s->total_height)
704 s->backscroll_height++;
705 y1 = (s->y_base + s->height - 1) % s->total_height;
706 c = &s->cells[y1 * s->width];
707 for(x = 0; x < s->width; x++) {
708 c->ch = ' ';
709 c->t_attrib = s->t_attrib_default;
710 c++;
711 }
712 if (s == active_console && s->y_displayed == s->y_base) {
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700713 if (!ds_get_bits_per_pixel(s->ds)) {
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800714 s->text_x[0] = 0;
715 s->text_y[0] = 0;
716 s->text_x[1] = s->width - 1;
717 s->text_y[1] = s->height - 1;
718 return;
719 }
720
721 vga_bitblt(s->ds, 0, FONT_HEIGHT, 0, 0,
722 s->width * FONT_WIDTH,
723 (s->height - 1) * FONT_HEIGHT);
724 vga_fill_rect(s->ds, 0, (s->height - 1) * FONT_HEIGHT,
725 s->width * FONT_WIDTH, FONT_HEIGHT,
726 color_table[0][s->t_attrib_default.bgcol]);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -0700727 s->update_x0 = 0;
728 s->update_y0 = 0;
729 s->update_x1 = s->width * FONT_WIDTH;
730 s->update_y1 = s->height * FONT_HEIGHT;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800731 }
732 }
733}
734
735/* Set console attributes depending on the current escape codes.
736 * NOTE: I know this code is not very efficient (checking every color for it
737 * self) but it is more readable and better maintainable.
738 */
739static void console_handle_escape(TextConsole *s)
740{
741 int i;
742
743 for (i=0; i<s->nb_esc_params; i++) {
744 switch (s->esc_params[i]) {
745 case 0: /* reset all console attributes to default */
746 s->t_attrib = s->t_attrib_default;
747 break;
748 case 1:
749 s->t_attrib.bold = 1;
750 break;
751 case 4:
752 s->t_attrib.uline = 1;
753 break;
754 case 5:
755 s->t_attrib.blink = 1;
756 break;
757 case 7:
758 s->t_attrib.invers = 1;
759 break;
760 case 8:
761 s->t_attrib.unvisible = 1;
762 break;
763 case 22:
764 s->t_attrib.bold = 0;
765 break;
766 case 24:
767 s->t_attrib.uline = 0;
768 break;
769 case 25:
770 s->t_attrib.blink = 0;
771 break;
772 case 27:
773 s->t_attrib.invers = 0;
774 break;
775 case 28:
776 s->t_attrib.unvisible = 0;
777 break;
778 /* set foreground color */
779 case 30:
780 s->t_attrib.fgcol=COLOR_BLACK;
781 break;
782 case 31:
783 s->t_attrib.fgcol=COLOR_RED;
784 break;
785 case 32:
786 s->t_attrib.fgcol=COLOR_GREEN;
787 break;
788 case 33:
789 s->t_attrib.fgcol=COLOR_YELLOW;
790 break;
791 case 34:
792 s->t_attrib.fgcol=COLOR_BLUE;
793 break;
794 case 35:
795 s->t_attrib.fgcol=COLOR_MAGENTA;
796 break;
797 case 36:
798 s->t_attrib.fgcol=COLOR_CYAN;
799 break;
800 case 37:
801 s->t_attrib.fgcol=COLOR_WHITE;
802 break;
803 /* set background color */
804 case 40:
805 s->t_attrib.bgcol=COLOR_BLACK;
806 break;
807 case 41:
808 s->t_attrib.bgcol=COLOR_RED;
809 break;
810 case 42:
811 s->t_attrib.bgcol=COLOR_GREEN;
812 break;
813 case 43:
814 s->t_attrib.bgcol=COLOR_YELLOW;
815 break;
816 case 44:
817 s->t_attrib.bgcol=COLOR_BLUE;
818 break;
819 case 45:
820 s->t_attrib.bgcol=COLOR_MAGENTA;
821 break;
822 case 46:
823 s->t_attrib.bgcol=COLOR_CYAN;
824 break;
825 case 47:
826 s->t_attrib.bgcol=COLOR_WHITE;
827 break;
828 }
829 }
830}
831
832static void console_clear_xy(TextConsole *s, int x, int y)
833{
834 int y1 = (s->y_base + y) % s->total_height;
835 TextCell *c = &s->cells[y1 * s->width + x];
836 c->ch = ' ';
837 c->t_attrib = s->t_attrib_default;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -0800838 update_xy(s, x, y);
839}
840
841static void console_putchar(TextConsole *s, int ch)
842{
843 TextCell *c;
844 int y1, i;
845 int x, y;
846
847 switch(s->state) {
848 case TTY_STATE_NORM:
849 switch(ch) {
850 case '\r': /* carriage return */
851 s->x = 0;
852 break;
853 case '\n': /* newline */
854 console_put_lf(s);
855 break;
856 case '\b': /* backspace */
857 if (s->x > 0)
858 s->x--;
859 break;
860 case '\t': /* tabspace */
861 if (s->x + (8 - (s->x % 8)) > s->width) {
862 s->x = 0;
863 console_put_lf(s);
864 } else {
865 s->x = s->x + (8 - (s->x % 8));
866 }
867 break;
868 case '\a': /* alert aka. bell */
869 /* TODO: has to be implemented */
870 break;
871 case 14:
872 /* SI (shift in), character set 0 (ignored) */
873 break;
874 case 15:
875 /* SO (shift out), character set 1 (ignored) */
876 break;
877 case 27: /* esc (introducing an escape sequence) */
878 s->state = TTY_STATE_ESC;
879 break;
880 default:
881 if (s->x >= s->width) {
882 /* line wrap */
883 s->x = 0;
884 console_put_lf(s);
885 }
886 y1 = (s->y_base + s->y) % s->total_height;
887 c = &s->cells[y1 * s->width + s->x];
888 c->ch = ch;
889 c->t_attrib = s->t_attrib;
890 update_xy(s, s->x, s->y);
891 s->x++;
892 break;
893 }
894 break;
895 case TTY_STATE_ESC: /* check if it is a terminal escape sequence */
896 if (ch == '[') {
897 for(i=0;i<MAX_ESC_PARAMS;i++)
898 s->esc_params[i] = 0;
899 s->nb_esc_params = 0;
900 s->state = TTY_STATE_CSI;
901 } else {
902 s->state = TTY_STATE_NORM;
903 }
904 break;
905 case TTY_STATE_CSI: /* handle escape sequence parameters */
906 if (ch >= '0' && ch <= '9') {
907 if (s->nb_esc_params < MAX_ESC_PARAMS) {
908 s->esc_params[s->nb_esc_params] =
909 s->esc_params[s->nb_esc_params] * 10 + ch - '0';
910 }
911 } else {
912 s->nb_esc_params++;
913 if (ch == ';')
914 break;
915#ifdef DEBUG_CONSOLE
916 fprintf(stderr, "escape sequence CSI%d;%d%c, %d parameters\n",
917 s->esc_params[0], s->esc_params[1], ch, s->nb_esc_params);
918#endif
919 s->state = TTY_STATE_NORM;
920 switch(ch) {
921 case 'A':
922 /* move cursor up */
923 if (s->esc_params[0] == 0) {
924 s->esc_params[0] = 1;
925 }
926 s->y -= s->esc_params[0];
927 if (s->y < 0) {
928 s->y = 0;
929 }
930 break;
931 case 'B':
932 /* move cursor down */
933 if (s->esc_params[0] == 0) {
934 s->esc_params[0] = 1;
935 }
936 s->y += s->esc_params[0];
937 if (s->y >= s->height) {
938 s->y = s->height - 1;
939 }
940 break;
941 case 'C':
942 /* move cursor right */
943 if (s->esc_params[0] == 0) {
944 s->esc_params[0] = 1;
945 }
946 s->x += s->esc_params[0];
947 if (s->x >= s->width) {
948 s->x = s->width - 1;
949 }
950 break;
951 case 'D':
952 /* move cursor left */
953 if (s->esc_params[0] == 0) {
954 s->esc_params[0] = 1;
955 }
956 s->x -= s->esc_params[0];
957 if (s->x < 0) {
958 s->x = 0;
959 }
960 break;
961 case 'G':
962 /* move cursor to column */
963 s->x = s->esc_params[0] - 1;
964 if (s->x < 0) {
965 s->x = 0;
966 }
967 break;
968 case 'f':
969 case 'H':
970 /* move cursor to row, column */
971 s->x = s->esc_params[1] - 1;
972 if (s->x < 0) {
973 s->x = 0;
974 }
975 s->y = s->esc_params[0] - 1;
976 if (s->y < 0) {
977 s->y = 0;
978 }
979 break;
980 case 'J':
981 switch (s->esc_params[0]) {
982 case 0:
983 /* clear to end of screen */
984 for (y = s->y; y < s->height; y++) {
985 for (x = 0; x < s->width; x++) {
986 if (y == s->y && x < s->x) {
987 continue;
988 }
989 console_clear_xy(s, x, y);
990 }
991 }
992 break;
993 case 1:
994 /* clear from beginning of screen */
995 for (y = 0; y <= s->y; y++) {
996 for (x = 0; x < s->width; x++) {
997 if (y == s->y && x > s->x) {
998 break;
999 }
1000 console_clear_xy(s, x, y);
1001 }
1002 }
1003 break;
1004 case 2:
1005 /* clear entire screen */
1006 for (y = 0; y <= s->height; y++) {
1007 for (x = 0; x < s->width; x++) {
1008 console_clear_xy(s, x, y);
1009 }
1010 }
1011 break;
1012 }
1013 case 'K':
1014 switch (s->esc_params[0]) {
1015 case 0:
1016 /* clear to eol */
1017 for(x = s->x; x < s->width; x++) {
1018 console_clear_xy(s, x, s->y);
1019 }
1020 break;
1021 case 1:
1022 /* clear from beginning of line */
1023 for (x = 0; x <= s->x; x++) {
1024 console_clear_xy(s, x, s->y);
1025 }
1026 break;
1027 case 2:
1028 /* clear entire line */
1029 for(x = 0; x < s->width; x++) {
1030 console_clear_xy(s, x, s->y);
1031 }
1032 break;
1033 }
1034 break;
1035 case 'm':
1036 console_handle_escape(s);
1037 break;
1038 case 'n':
1039 /* report cursor position */
1040 /* TODO: send ESC[row;colR */
1041 break;
1042 case 's':
1043 /* save cursor position */
1044 s->x_saved = s->x;
1045 s->y_saved = s->y;
1046 break;
1047 case 'u':
1048 /* restore cursor position */
1049 s->x = s->x_saved;
1050 s->y = s->y_saved;
1051 break;
1052 default:
1053#ifdef DEBUG_CONSOLE
1054 fprintf(stderr, "unhandled escape character '%c'\n", ch);
1055#endif
1056 break;
1057 }
1058 break;
1059 }
1060 }
1061}
1062
1063void console_select(unsigned int index)
1064{
1065 TextConsole *s;
1066
1067 if (index >= MAX_CONSOLES)
1068 return;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001069 active_console->g_width = ds_get_width(active_console->ds);
1070 active_console->g_height = ds_get_height(active_console->ds);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001071 s = consoles[index];
1072 if (s) {
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001073 DisplayState *ds = s->ds;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001074 active_console = s;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001075 if (ds_get_bits_per_pixel(s->ds)) {
1076 ds->surface = qemu_resize_displaysurface(ds, s->g_width, s->g_height);
1077 } else {
1078 s->ds->surface->width = s->width;
1079 s->ds->surface->height = s->height;
1080 }
1081 dpy_resize(s->ds);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001082 vga_hw_invalidate();
1083 }
1084}
1085
1086static int console_puts(CharDriverState *chr, const uint8_t *buf, int len)
1087{
1088 TextConsole *s = chr->opaque;
1089 int i;
1090
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001091 s->update_x0 = s->width * FONT_WIDTH;
1092 s->update_y0 = s->height * FONT_HEIGHT;
1093 s->update_x1 = 0;
1094 s->update_y1 = 0;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001095 console_show_cursor(s, 0);
1096 for(i = 0; i < len; i++) {
1097 console_putchar(s, buf[i]);
1098 }
1099 console_show_cursor(s, 1);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001100 if (ds_get_bits_per_pixel(s->ds) && s->update_x0 < s->update_x1) {
1101 dpy_update(s->ds, s->update_x0, s->update_y0,
1102 s->update_x1 - s->update_x0,
1103 s->update_y1 - s->update_y0);
1104 }
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001105 return len;
1106}
1107
1108static void console_send_event(CharDriverState *chr, int event)
1109{
1110 TextConsole *s = chr->opaque;
1111 int i;
1112
1113 if (event == CHR_EVENT_FOCUS) {
1114 for(i = 0; i < nb_consoles; i++) {
1115 if (consoles[i] == s) {
1116 console_select(i);
1117 break;
1118 }
1119 }
1120 }
1121}
1122
1123static void kbd_send_chars(void *opaque)
1124{
1125 TextConsole *s = opaque;
1126 int len;
1127 uint8_t buf[16];
1128
1129 len = qemu_chr_can_read(s->chr);
1130 if (len > s->out_fifo.count)
1131 len = s->out_fifo.count;
1132 if (len > 0) {
1133 if (len > sizeof(buf))
1134 len = sizeof(buf);
1135 qemu_fifo_read(&s->out_fifo, buf, len);
1136 qemu_chr_read(s->chr, buf, len);
1137 }
1138 /* characters are pending: we send them a bit later (XXX:
1139 horrible, should change char device API) */
1140 if (s->out_fifo.count > 0) {
1141 qemu_mod_timer(s->kbd_timer, qemu_get_clock(rt_clock) + 1);
1142 }
1143}
1144
1145/* called when an ascii key is pressed */
1146void kbd_put_keysym(int keysym)
1147{
1148 TextConsole *s;
1149 uint8_t buf[16], *q;
1150 int c;
1151
1152 s = active_console;
1153 if (!s || (s->console_type == GRAPHIC_CONSOLE))
1154 return;
1155
1156 switch(keysym) {
1157 case QEMU_KEY_CTRL_UP:
1158 console_scroll(-1);
1159 break;
1160 case QEMU_KEY_CTRL_DOWN:
1161 console_scroll(1);
1162 break;
1163 case QEMU_KEY_CTRL_PAGEUP:
1164 console_scroll(-10);
1165 break;
1166 case QEMU_KEY_CTRL_PAGEDOWN:
1167 console_scroll(10);
1168 break;
1169 default:
1170 /* convert the QEMU keysym to VT100 key string */
1171 q = buf;
1172 if (keysym >= 0xe100 && keysym <= 0xe11f) {
1173 *q++ = '\033';
1174 *q++ = '[';
1175 c = keysym - 0xe100;
1176 if (c >= 10)
1177 *q++ = '0' + (c / 10);
1178 *q++ = '0' + (c % 10);
1179 *q++ = '~';
1180 } else if (keysym >= 0xe120 && keysym <= 0xe17f) {
1181 *q++ = '\033';
1182 *q++ = '[';
1183 *q++ = keysym & 0xff;
1184 } else {
1185 *q++ = keysym;
1186 }
1187 if (s->chr->chr_read) {
1188 qemu_fifo_write(&s->out_fifo, buf, q - buf);
1189 kbd_send_chars(s);
1190 }
1191 break;
1192 }
1193}
1194
1195static void text_console_invalidate(void *opaque)
1196{
1197 TextConsole *s = (TextConsole *) opaque;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001198 if (!ds_get_bits_per_pixel(s->ds) && s->console_type == TEXT_CONSOLE) {
1199 s->g_width = ds_get_width(s->ds);
1200 s->g_height = ds_get_height(s->ds);
1201 text_console_resize(s);
1202 }
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001203 console_refresh(s);
1204}
1205
1206static void text_console_update(void *opaque, console_ch_t *chardata)
1207{
1208 TextConsole *s = (TextConsole *) opaque;
1209 int i, j, src;
1210
1211 if (s->text_x[0] <= s->text_x[1]) {
1212 src = (s->y_base + s->text_y[0]) * s->width;
1213 chardata += s->text_y[0] * s->width;
1214 for (i = s->text_y[0]; i <= s->text_y[1]; i ++)
1215 for (j = 0; j < s->width; j ++, src ++)
1216 console_write_ch(chardata ++, s->cells[src].ch |
1217 (s->cells[src].t_attrib.fgcol << 12) |
1218 (s->cells[src].t_attrib.bgcol << 8) |
1219 (s->cells[src].t_attrib.bold << 21));
1220 dpy_update(s->ds, s->text_x[0], s->text_y[0],
1221 s->text_x[1] - s->text_x[0], i - s->text_y[0]);
1222 s->text_x[0] = s->width;
1223 s->text_y[0] = s->height;
1224 s->text_x[1] = 0;
1225 s->text_y[1] = 0;
1226 }
1227 if (s->cursor_invalidate) {
1228 dpy_cursor(s->ds, s->x, s->y);
1229 s->cursor_invalidate = 0;
1230 }
1231}
1232
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001233static TextConsole *get_graphic_console(DisplayState *ds)
1234{
1235 int i;
1236 TextConsole *s;
1237 for (i = 0; i < nb_consoles; i++) {
1238 s = consoles[i];
1239 if (s->console_type == GRAPHIC_CONSOLE && s->ds == ds)
1240 return s;
1241 }
1242 return NULL;
1243}
1244
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001245static TextConsole *new_console(DisplayState *ds, console_type_t console_type)
1246{
1247 TextConsole *s;
1248 int i;
1249
1250 if (nb_consoles >= MAX_CONSOLES)
1251 return NULL;
1252 s = qemu_mallocz(sizeof(TextConsole));
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001253 if (!active_console || ((active_console->console_type != GRAPHIC_CONSOLE) &&
1254 (console_type == GRAPHIC_CONSOLE))) {
1255 active_console = s;
1256 }
1257 s->ds = ds;
1258 s->console_type = console_type;
1259 if (console_type != GRAPHIC_CONSOLE) {
1260 consoles[nb_consoles++] = s;
1261 } else {
1262 /* HACK: Put graphical consoles before text consoles. */
1263 for (i = nb_consoles; i > 0; i--) {
1264 if (consoles[i - 1]->console_type == GRAPHIC_CONSOLE)
1265 break;
1266 consoles[i] = consoles[i - 1];
1267 }
1268 consoles[i] = s;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001269 nb_consoles++;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001270 }
1271 return s;
1272}
1273
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001274DisplayState *graphic_console_init(vga_hw_update_ptr update,
1275 vga_hw_invalidate_ptr invalidate,
1276 vga_hw_screen_dump_ptr screen_dump,
1277 vga_hw_text_update_ptr text_update,
1278 void *opaque)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001279{
1280 TextConsole *s;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001281 DisplayState *ds;
1282
1283 ds = (DisplayState *) qemu_mallocz(sizeof(DisplayState));
Vladimir Chtchetkinedd50f7d2010-07-30 09:16:41 -07001284 ds->allocator = &default_allocator;
1285 ds->surface = qemu_create_displaysurface(ds, android_display_width, android_display_height);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001286
1287 s = new_console(ds, GRAPHIC_CONSOLE);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001288 if (s == NULL) {
1289 qemu_free_displaysurface(ds);
1290 qemu_free(ds);
1291 return NULL;
1292 }
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001293 s->hw_update = update;
1294 s->hw_invalidate = invalidate;
1295 s->hw_screen_dump = screen_dump;
1296 s->hw_text_update = text_update;
1297 s->hw = opaque;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001298
1299 register_displaystate(ds);
1300 return ds;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001301}
1302
1303int is_graphic_console(void)
1304{
1305 return active_console && active_console->console_type == GRAPHIC_CONSOLE;
1306}
1307
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001308int is_fixedsize_console(void)
1309{
1310 return active_console && active_console->console_type != TEXT_CONSOLE;
1311}
1312
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001313void console_color_init(DisplayState *ds)
1314{
1315 int i, j;
1316 for (j = 0; j < 2; j++) {
1317 for (i = 0; i < 8; i++) {
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001318 color_table[j][i] = col_expand(ds,
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001319 vga_get_color(ds, color_table_rgb[j][i]));
1320 }
1321 }
1322}
1323
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001324static int n_text_consoles;
1325static CharDriverState *text_consoles[128];
1326static char *text_console_strs[128];
1327
1328static void text_console_do_init(CharDriverState *chr, DisplayState *ds, const char *p)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001329{
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001330 TextConsole *s;
1331 unsigned width;
1332 unsigned height;
1333 static int color_inited;
1334
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001335 s = new_console(ds, (p == NULL) ? TEXT_CONSOLE : TEXT_CONSOLE_FIXED_SIZE);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001336 if (!s) {
1337 free(chr);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001338 return;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001339 }
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001340 chr->opaque = s;
1341 chr->chr_write = console_puts;
1342 chr->chr_send_event = console_send_event;
1343
1344 s->chr = chr;
1345 s->out_fifo.buf = s->out_fifo_buf;
1346 s->out_fifo.buf_size = sizeof(s->out_fifo_buf);
1347 s->kbd_timer = qemu_new_timer(rt_clock, kbd_send_chars, s);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001348 s->ds = ds;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001349
1350 if (!color_inited) {
1351 color_inited = 1;
1352 console_color_init(s->ds);
1353 }
1354 s->y_displayed = 0;
1355 s->y_base = 0;
1356 s->total_height = DEFAULT_BACKSCROLL;
1357 s->x = 0;
1358 s->y = 0;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001359 width = ds_get_width(s->ds);
1360 height = ds_get_height(s->ds);
1361 if (p != NULL) {
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001362 width = strtoul(p, (char **)&p, 10);
1363 if (*p == 'C') {
1364 p++;
1365 width *= FONT_WIDTH;
1366 }
1367 if (*p == 'x') {
1368 p++;
1369 height = strtoul(p, (char **)&p, 10);
1370 if (*p == 'C') {
1371 p++;
1372 height *= FONT_HEIGHT;
1373 }
1374 }
1375 }
1376 s->g_width = width;
1377 s->g_height = height;
1378
1379 s->hw_invalidate = text_console_invalidate;
1380 s->hw_text_update = text_console_update;
1381 s->hw = s;
1382
1383 /* Set text attribute defaults */
1384 s->t_attrib_default.bold = 0;
1385 s->t_attrib_default.uline = 0;
1386 s->t_attrib_default.blink = 0;
1387 s->t_attrib_default.invers = 0;
1388 s->t_attrib_default.unvisible = 0;
1389 s->t_attrib_default.fgcol = COLOR_WHITE;
1390 s->t_attrib_default.bgcol = COLOR_BLACK;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001391 /* set current text attributes to default */
1392 s->t_attrib = s->t_attrib_default;
1393 text_console_resize(s);
1394
David Turner9d118822010-09-10 13:02:07 +02001395 qemu_chr_generic_open(chr);
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001396 if (chr->init)
1397 chr->init(chr);
1398}
1399
1400CharDriverState *text_console_init(const char *p)
1401{
1402 CharDriverState *chr;
1403
1404 chr = qemu_mallocz(sizeof(CharDriverState));
1405
1406 if (n_text_consoles == 128) {
1407 fprintf(stderr, "Too many text consoles\n");
1408 exit(1);
1409 }
1410 text_consoles[n_text_consoles] = chr;
1411 text_console_strs[n_text_consoles] = p ? qemu_strdup(p) : NULL;
1412 n_text_consoles++;
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001413
1414 return chr;
1415}
1416
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001417void text_consoles_set_display(DisplayState *ds)
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001418{
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001419 int i;
1420
1421 for (i = 0; i < n_text_consoles; i++) {
1422 text_console_do_init(text_consoles[i], ds, text_console_strs[i]);
1423 qemu_free(text_console_strs[i]);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001424 }
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001425
1426 n_text_consoles = 0;
1427}
1428
1429void qemu_console_resize(DisplayState *ds, int width, int height)
1430{
1431 TextConsole *s = get_graphic_console(ds);
1432 if (!s) return;
1433
1434 s->g_width = width;
1435 s->g_height = height;
1436 if (is_graphic_console()) {
1437 ds->surface = qemu_resize_displaysurface(ds, width, height);
1438 dpy_resize(ds);
1439 }
1440}
1441
1442void qemu_console_copy(DisplayState *ds, int src_x, int src_y,
1443 int dst_x, int dst_y, int w, int h)
1444{
1445 if (is_graphic_console()) {
1446 dpy_copy(ds, src_x, src_y, dst_x, dst_y, w, h);
1447 }
1448}
1449
1450PixelFormat qemu_different_endianness_pixelformat(int bpp)
1451{
1452 PixelFormat pf;
1453
1454 memset(&pf, 0x00, sizeof(PixelFormat));
1455
1456 pf.bits_per_pixel = bpp;
1457 pf.bytes_per_pixel = bpp / 8;
1458 pf.depth = bpp == 32 ? 24 : bpp;
1459
1460 switch (bpp) {
1461 case 24:
1462 pf.rmask = 0x000000FF;
1463 pf.gmask = 0x0000FF00;
1464 pf.bmask = 0x00FF0000;
1465 pf.rmax = 255;
1466 pf.gmax = 255;
1467 pf.bmax = 255;
1468 pf.rshift = 0;
1469 pf.gshift = 8;
1470 pf.bshift = 16;
1471 pf.rbits = 8;
1472 pf.gbits = 8;
1473 pf.bbits = 8;
1474 break;
1475 case 32:
1476 pf.rmask = 0x0000FF00;
1477 pf.gmask = 0x00FF0000;
1478 pf.bmask = 0xFF000000;
1479 pf.amask = 0x00000000;
1480 pf.amax = 255;
1481 pf.rmax = 255;
1482 pf.gmax = 255;
1483 pf.bmax = 255;
1484 pf.ashift = 0;
1485 pf.rshift = 8;
1486 pf.gshift = 16;
1487 pf.bshift = 24;
1488 pf.rbits = 8;
1489 pf.gbits = 8;
1490 pf.bbits = 8;
1491 pf.abits = 8;
1492 break;
1493 default:
1494 break;
1495 }
1496 return pf;
1497}
1498
1499PixelFormat qemu_default_pixelformat(int bpp)
1500{
1501 PixelFormat pf;
1502
1503 memset(&pf, 0x00, sizeof(PixelFormat));
1504
1505 pf.bits_per_pixel = bpp;
1506 pf.bytes_per_pixel = bpp / 8;
1507 pf.depth = bpp == 32 ? 24 : bpp;
1508
1509 switch (bpp) {
1510 case 16:
1511 pf.rmask = 0x0000F800;
1512 pf.gmask = 0x000007E0;
1513 pf.bmask = 0x0000001F;
1514 pf.rmax = 31;
1515 pf.gmax = 63;
1516 pf.bmax = 31;
1517 pf.rshift = 11;
1518 pf.gshift = 5;
1519 pf.bshift = 0;
1520 pf.rbits = 5;
1521 pf.gbits = 6;
1522 pf.bbits = 5;
1523 break;
1524 case 24:
1525 pf.rmask = 0x00FF0000;
1526 pf.gmask = 0x0000FF00;
1527 pf.bmask = 0x000000FF;
1528 pf.rmax = 255;
1529 pf.gmax = 255;
1530 pf.bmax = 255;
1531 pf.rshift = 16;
1532 pf.gshift = 8;
1533 pf.bshift = 0;
1534 pf.rbits = 8;
1535 pf.gbits = 8;
1536 pf.bbits = 8;
1537 case 32:
1538 pf.rmask = 0x00FF0000;
1539 pf.gmask = 0x0000FF00;
1540 pf.bmask = 0x000000FF;
1541 pf.amax = 255;
1542 pf.rmax = 255;
1543 pf.gmax = 255;
1544 pf.bmax = 255;
1545 pf.ashift = 24;
1546 pf.rshift = 16;
1547 pf.gshift = 8;
1548 pf.bshift = 0;
1549 pf.rbits = 8;
1550 pf.gbits = 8;
1551 pf.bbits = 8;
1552 pf.abits = 8;
1553 break;
1554 default:
1555 break;
1556 }
1557 return pf;
1558}
1559
1560DisplaySurface* defaultallocator_create_displaysurface(int width, int height)
1561{
1562 DisplaySurface *surface = (DisplaySurface*) qemu_mallocz(sizeof(DisplaySurface));
1563
1564 surface->width = width;
1565 surface->height = height;
Vladimir Chtchetkinedd50f7d2010-07-30 09:16:41 -07001566 surface->pf = qemu_default_pixelformat(android_display_bpp);
1567 surface->linesize = width * surface->pf.bytes_per_pixel;
David 'Digit' Turner20894ae2010-05-10 17:07:36 -07001568#ifdef HOST_WORDS_BIGENDIAN
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001569 surface->flags = QEMU_ALLOCATED_FLAG | QEMU_BIG_ENDIAN_FLAG;
1570#else
1571 surface->flags = QEMU_ALLOCATED_FLAG;
1572#endif
1573 surface->data = (uint8_t*) qemu_mallocz(surface->linesize * surface->height);
1574
1575 return surface;
1576}
1577
1578DisplaySurface* defaultallocator_resize_displaysurface(DisplaySurface *surface,
Vladimir Chtchetkinedd50f7d2010-07-30 09:16:41 -07001579 int width, int height)
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001580{
1581 surface->width = width;
1582 surface->height = height;
Vladimir Chtchetkinedd50f7d2010-07-30 09:16:41 -07001583 surface->pf = qemu_default_pixelformat(android_display_bpp);
1584 surface->linesize = width * surface->pf.bytes_per_pixel;
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001585 if (surface->flags & QEMU_ALLOCATED_FLAG)
1586 surface->data = (uint8_t*) qemu_realloc(surface->data, surface->linesize * surface->height);
1587 else
1588 surface->data = (uint8_t*) qemu_malloc(surface->linesize * surface->height);
David 'Digit' Turner20894ae2010-05-10 17:07:36 -07001589#ifdef HOST_WORDS_BIGENDIAN
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001590 surface->flags = QEMU_ALLOCATED_FLAG | QEMU_BIG_ENDIAN_FLAG;
1591#else
1592 surface->flags = QEMU_ALLOCATED_FLAG;
1593#endif
1594
1595 return surface;
1596}
1597
1598DisplaySurface* qemu_create_displaysurface_from(int width, int height, int bpp,
1599 int linesize, uint8_t *data)
1600{
1601 DisplaySurface *surface = (DisplaySurface*) qemu_mallocz(sizeof(DisplaySurface));
1602
1603 surface->width = width;
1604 surface->height = height;
1605 surface->linesize = linesize;
1606 surface->pf = qemu_default_pixelformat(bpp);
David 'Digit' Turner20894ae2010-05-10 17:07:36 -07001607#ifdef HOST_WORDS_BIGENDIAN
David 'Digit' Turner5d8f37a2009-09-14 14:32:27 -07001608 surface->flags = QEMU_BIG_ENDIAN_FLAG;
1609#endif
1610 surface->data = data;
1611
1612 return surface;
1613}
1614
1615void defaultallocator_free_displaysurface(DisplaySurface *surface)
1616{
1617 if (surface == NULL)
1618 return;
1619 if (surface->flags & QEMU_ALLOCATED_FLAG)
1620 qemu_free(surface->data);
1621 qemu_free(surface);
The Android Open Source Project8b23a6c2009-03-03 19:30:32 -08001622}