2 * QEMU graphical console
4 * Copyright (c) 2004 Fabrice Bellard
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:
13 * The above copyright notice and this permission notice shall be included in
14 * all copies or substantial portions of the Software.
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
26 #define DEFAULT_BACKSCROLL 512
27 #define MAX_CONSOLES 12
29 #define RGBA(r, g, b, a) (((a) << 24) | ((r) << 16) | ((g) << 8) | (b))
30 #define RGB(r, g, b) RGBA(r, g, b, 0xff)
32 typedef struct TextCell
{
38 #define MAX_ESC_PARAMS 3
47 int text_console
; /* true if text console */
49 int g_width
, g_height
;
53 int backscroll_height
;
62 int esc_params
[MAX_ESC_PARAMS
];
65 /* kbd read handler */
66 IOReadHandler
*fd_read
;
70 static TextConsole
*active_console
;
71 static TextConsole
*consoles
[MAX_CONSOLES
];
72 static int nb_consoles
= 0;
74 /* convert a RGBA color to a color index usable in graphic primitives */
75 static unsigned int vga_get_color(DisplayState
*ds
, unsigned int rgba
)
77 unsigned int r
, g
, b
, color
;
82 r
= (rgba
>> 16) & 0xff;
83 g
= (rgba
>> 8) & 0xff;
85 color
= (rgb_to_index
[r
] * 6 * 6) +
86 (rgb_to_index
[g
] * 6) +
91 r
= (rgba
>> 16) & 0xff;
92 g
= (rgba
>> 8) & 0xff;
94 color
= ((r
>> 3) << 10) | ((g
>> 3) << 5) | (b
>> 3);
97 r
= (rgba
>> 16) & 0xff;
98 g
= (rgba
>> 8) & 0xff;
100 color
= ((r
>> 3) << 11) | ((g
>> 2) << 5) | (b
>> 3);
110 static void vga_fill_rect (DisplayState
*ds
,
111 int posx
, int posy
, int width
, int height
, uint32_t color
)
116 bpp
= (ds
->depth
+ 7) >> 3;
118 ds
->linesize
* posy
+ bpp
* posx
;
119 for (y
= 0; y
< height
; y
++) {
123 for (x
= 0; x
< width
; x
++) {
124 *((uint8_t *)d
) = color
;
129 for (x
= 0; x
< width
; x
++) {
130 *((uint16_t *)d
) = color
;
135 for (x
= 0; x
< width
; x
++) {
136 *((uint32_t *)d
) = color
;
145 /* copy from (xs, ys) to (xd, yd) a rectangle of size (w, h) */
146 static void vga_bitblt(DisplayState
*ds
, int xs
, int ys
, int xd
, int yd
, int w
, int h
)
152 bpp
= (ds
->depth
+ 7) >> 3;
156 ds
->linesize
* ys
+ bpp
* xs
;
158 ds
->linesize
* yd
+ bpp
* xd
;
159 for (y
= 0; y
< h
; y
++) {
166 ds
->linesize
* (ys
+ h
- 1) + bpp
* xs
;
168 ds
->linesize
* (yd
+ h
- 1) + bpp
* xd
;
169 for (y
= 0; y
< h
; y
++) {
177 /***********************************************************/
178 /* basic char display */
180 #define FONT_HEIGHT 16
185 #define cbswap_32(__x) \
187 (((uint32_t)(__x) & (uint32_t)0x000000ffUL) << 24) | \
188 (((uint32_t)(__x) & (uint32_t)0x0000ff00UL) << 8) | \
189 (((uint32_t)(__x) & (uint32_t)0x00ff0000UL) >> 8) | \
190 (((uint32_t)(__x) & (uint32_t)0xff000000UL) >> 24) ))
192 #ifdef WORDS_BIGENDIAN
195 #define PAT(x) cbswap_32(x)
198 static const uint32_t dmask16
[16] = {
217 static const uint32_t dmask4
[4] = {
224 static uint32_t color_table
[8];
226 static const uint32_t color_table_rgb
[8] = {
227 RGB(0x00, 0x00, 0x00),
228 RGB(0xff, 0x00, 0x00),
229 RGB(0x00, 0xff, 0x00),
230 RGB(0xff, 0xff, 0x00),
231 RGB(0x00, 0x00, 0xff),
232 RGB(0xff, 0x00, 0xff),
233 RGB(0x00, 0xff, 0xff),
234 RGB(0xff, 0xff, 0xff),
237 static inline unsigned int col_expand(DisplayState
*ds
, unsigned int col
)
255 static void vga_putcharxy(DisplayState
*ds
, int x
, int y
, int ch
,
256 unsigned int fgcol
, unsigned int bgcol
)
259 const uint8_t *font_ptr
;
260 unsigned int font_data
, linesize
, xorcol
, bpp
;
263 bpp
= (ds
->depth
+ 7) >> 3;
265 ds
->linesize
* y
* FONT_HEIGHT
+ bpp
* x
* FONT_WIDTH
;
266 linesize
= ds
->linesize
;
267 font_ptr
= vgafont16
+ FONT_HEIGHT
* ch
;
268 xorcol
= bgcol
^ fgcol
;
271 for(i
= 0; i
< FONT_HEIGHT
; i
++) {
272 font_data
= *font_ptr
++;
273 ((uint32_t *)d
)[0] = (dmask16
[(font_data
>> 4)] & xorcol
) ^ bgcol
;
274 ((uint32_t *)d
)[1] = (dmask16
[(font_data
>> 0) & 0xf] & xorcol
) ^ bgcol
;
280 for(i
= 0; i
< FONT_HEIGHT
; i
++) {
281 font_data
= *font_ptr
++;
282 ((uint32_t *)d
)[0] = (dmask4
[(font_data
>> 6)] & xorcol
) ^ bgcol
;
283 ((uint32_t *)d
)[1] = (dmask4
[(font_data
>> 4) & 3] & xorcol
) ^ bgcol
;
284 ((uint32_t *)d
)[2] = (dmask4
[(font_data
>> 2) & 3] & xorcol
) ^ bgcol
;
285 ((uint32_t *)d
)[3] = (dmask4
[(font_data
>> 0) & 3] & xorcol
) ^ bgcol
;
290 for(i
= 0; i
< FONT_HEIGHT
; i
++) {
291 font_data
= *font_ptr
++;
292 ((uint32_t *)d
)[0] = (-((font_data
>> 7)) & xorcol
) ^ bgcol
;
293 ((uint32_t *)d
)[1] = (-((font_data
>> 6) & 1) & xorcol
) ^ bgcol
;
294 ((uint32_t *)d
)[2] = (-((font_data
>> 5) & 1) & xorcol
) ^ bgcol
;
295 ((uint32_t *)d
)[3] = (-((font_data
>> 4) & 1) & xorcol
) ^ bgcol
;
296 ((uint32_t *)d
)[4] = (-((font_data
>> 3) & 1) & xorcol
) ^ bgcol
;
297 ((uint32_t *)d
)[5] = (-((font_data
>> 2) & 1) & xorcol
) ^ bgcol
;
298 ((uint32_t *)d
)[6] = (-((font_data
>> 1) & 1) & xorcol
) ^ bgcol
;
299 ((uint32_t *)d
)[7] = (-((font_data
>> 0) & 1) & xorcol
) ^ bgcol
;
306 static void text_console_resize(TextConsole
*s
)
308 TextCell
*cells
, *c
, *c1
;
309 int w1
, x
, y
, last_width
;
311 last_width
= s
->width
;
312 s
->width
= s
->g_width
/ FONT_WIDTH
;
313 s
->height
= s
->g_height
/ FONT_HEIGHT
;
319 cells
= qemu_malloc(s
->width
* s
->total_height
* sizeof(TextCell
));
320 for(y
= 0; y
< s
->total_height
; y
++) {
321 c
= &cells
[y
* s
->width
];
323 c1
= &s
->cells
[y
* last_width
];
324 for(x
= 0; x
< w1
; x
++) {
328 for(x
= w1
; x
< s
->width
; x
++) {
339 static void update_xy(TextConsole
*s
, int x
, int y
)
344 if (s
== active_console
) {
345 y1
= (s
->y_base
+ y
) % s
->total_height
;
346 y2
= y1
- s
->y_displayed
;
348 y2
+= s
->total_height
;
349 if (y2
< s
->height
) {
350 c
= &s
->cells
[y1
* s
->width
+ x
];
351 vga_putcharxy(s
->ds
, x
, y2
, c
->ch
,
352 color_table
[c
->fgcol
], color_table
[c
->bgcol
]);
353 dpy_update(s
->ds
, x
* FONT_WIDTH
, y2
* FONT_HEIGHT
,
354 FONT_WIDTH
, FONT_HEIGHT
);
359 static void console_show_cursor(TextConsole
*s
, int show
)
364 if (s
== active_console
) {
365 y1
= (s
->y_base
+ s
->y
) % s
->total_height
;
366 y
= y1
- s
->y_displayed
;
368 y
+= s
->total_height
;
370 c
= &s
->cells
[y1
* s
->width
+ s
->x
];
372 vga_putcharxy(s
->ds
, s
->x
, y
, c
->ch
,
373 color_table
[0], color_table
[7]);
375 vga_putcharxy(s
->ds
, s
->x
, y
, c
->ch
,
376 color_table
[c
->fgcol
], color_table
[c
->bgcol
]);
378 dpy_update(s
->ds
, s
->x
* FONT_WIDTH
, y
* FONT_HEIGHT
,
379 FONT_WIDTH
, FONT_HEIGHT
);
384 static void console_refresh(TextConsole
*s
)
389 if (s
!= active_console
)
392 vga_fill_rect(s
->ds
, 0, 0, s
->ds
->width
, s
->ds
->height
,
395 for(y
= 0; y
< s
->height
; y
++) {
396 c
= s
->cells
+ y1
* s
->width
;
397 for(x
= 0; x
< s
->width
; x
++) {
398 vga_putcharxy(s
->ds
, x
, y
, c
->ch
,
399 color_table
[c
->fgcol
], color_table
[c
->bgcol
]);
402 if (++y1
== s
->total_height
)
405 dpy_update(s
->ds
, 0, 0, s
->ds
->width
, s
->ds
->height
);
406 console_show_cursor(s
, 1);
409 static void console_scroll(int ydelta
)
415 if (!s
|| !s
->text_console
)
419 for(i
= 0; i
< ydelta
; i
++) {
420 if (s
->y_displayed
== s
->y_base
)
422 if (++s
->y_displayed
== s
->total_height
)
427 i
= s
->backscroll_height
;
428 if (i
> s
->total_height
- s
->height
)
429 i
= s
->total_height
- s
->height
;
432 y1
+= s
->total_height
;
433 for(i
= 0; i
< ydelta
; i
++) {
434 if (s
->y_displayed
== y1
)
436 if (--s
->y_displayed
< 0)
437 s
->y_displayed
= s
->total_height
- 1;
443 static void console_put_lf(TextConsole
*s
)
450 if (s
->y
>= s
->height
) {
451 s
->y
= s
->height
- 1;
453 if (s
->y_displayed
== s
->y_base
) {
454 if (++s
->y_displayed
== s
->total_height
)
457 if (++s
->y_base
== s
->total_height
)
459 if (s
->backscroll_height
< s
->total_height
)
460 s
->backscroll_height
++;
461 y1
= (s
->y_base
+ s
->height
- 1) % s
->total_height
;
462 c
= &s
->cells
[y1
* s
->width
];
463 for(x
= 0; x
< s
->width
; x
++) {
469 if (s
== active_console
&& s
->y_displayed
== s
->y_base
) {
470 vga_bitblt(s
->ds
, 0, FONT_HEIGHT
, 0, 0,
471 s
->width
* FONT_WIDTH
,
472 (s
->height
- 1) * FONT_HEIGHT
);
473 vga_fill_rect(s
->ds
, 0, (s
->height
- 1) * FONT_HEIGHT
,
474 s
->width
* FONT_WIDTH
, FONT_HEIGHT
,
475 color_table
[s
->bgcol
]);
476 dpy_update(s
->ds
, 0, 0,
477 s
->width
* FONT_WIDTH
, s
->height
* FONT_HEIGHT
);
482 static void console_putchar(TextConsole
*s
, int ch
)
497 s
->state
= TTY_STATE_ESC
;
500 y1
= (s
->y_base
+ s
->y
) % s
->total_height
;
501 c
= &s
->cells
[y1
* s
->width
+ s
->x
];
505 update_xy(s
, s
->x
, s
->y
);
507 if (s
->x
>= s
->width
)
514 for(i
=0;i
<MAX_ESC_PARAMS
;i
++)
515 s
->esc_params
[i
] = 0;
516 s
->nb_esc_params
= 0;
517 s
->state
= TTY_STATE_CSI
;
519 s
->state
= TTY_STATE_NORM
;
523 if (ch
>= '0' && ch
<= '9') {
524 if (s
->nb_esc_params
< MAX_ESC_PARAMS
) {
525 s
->esc_params
[s
->nb_esc_params
] =
526 s
->esc_params
[s
->nb_esc_params
] * 10 + ch
- '0';
532 s
->state
= TTY_STATE_NORM
;
539 if (s
->x
< (s
->width
- 1))
544 y1
= (s
->y_base
+ s
->y
) % s
->total_height
;
545 for(x
= s
->x
; x
< s
->width
; x
++) {
546 c
= &s
->cells
[y1
* s
->width
+ x
];
551 update_xy(s
, x
, s
->y
);
562 void console_select(unsigned int index
)
566 if (index
>= MAX_CONSOLES
)
571 if (s
->text_console
) {
572 if (s
->g_width
!= s
->ds
->width
||
573 s
->g_height
!= s
->ds
->height
) {
574 s
->g_width
= s
->ds
->width
;
575 s
->g_height
= s
->ds
->height
;
576 text_console_resize(s
);
583 static int console_puts(CharDriverState
*chr
, const uint8_t *buf
, int len
)
585 TextConsole
*s
= chr
->opaque
;
588 console_show_cursor(s
, 0);
589 for(i
= 0; i
< len
; i
++) {
590 console_putchar(s
, buf
[i
]);
592 console_show_cursor(s
, 1);
596 static void console_chr_add_read_handler(CharDriverState
*chr
,
597 IOCanRWHandler
*fd_can_read
,
598 IOReadHandler
*fd_read
, void *opaque
)
600 TextConsole
*s
= chr
->opaque
;
601 s
->fd_read
= fd_read
;
602 s
->fd_opaque
= opaque
;
605 static void console_send_event(CharDriverState
*chr
, int event
)
607 TextConsole
*s
= chr
->opaque
;
610 if (event
== CHR_EVENT_FOCUS
) {
611 for(i
= 0; i
< nb_consoles
; i
++) {
612 if (consoles
[i
] == s
) {
620 /* called when an ascii key is pressed */
621 void kbd_put_keysym(int keysym
)
628 if (!s
|| !s
->text_console
)
632 case QEMU_KEY_CTRL_UP
:
635 case QEMU_KEY_CTRL_DOWN
:
638 case QEMU_KEY_CTRL_PAGEUP
:
641 case QEMU_KEY_CTRL_PAGEDOWN
:
646 /* convert the QEMU keysym to VT100 key string */
648 if (keysym
>= 0xe100 && keysym
<= 0xe11f) {
653 *q
++ = '0' + (c
/ 10);
654 *q
++ = '0' + (c
% 10);
656 } else if (keysym
>= 0xe120 && keysym
<= 0xe17f) {
659 *q
++ = keysym
& 0xff;
663 s
->fd_read(s
->fd_opaque
, buf
, q
- buf
);
669 TextConsole
*graphic_console_init(DisplayState
*ds
)
673 if (nb_consoles
>= MAX_CONSOLES
)
675 s
= qemu_mallocz(sizeof(TextConsole
));
682 consoles
[nb_consoles
++] = s
;
686 int is_active_console(TextConsole
*s
)
688 return s
== active_console
;
691 CharDriverState
*text_console_init(DisplayState
*ds
)
693 CharDriverState
*chr
;
696 static int color_inited
;
698 chr
= qemu_mallocz(sizeof(CharDriverState
));
701 s
= graphic_console_init(ds
);
708 chr
->chr_write
= console_puts
;
709 chr
->chr_add_read_handler
= console_chr_add_read_handler
;
710 chr
->chr_send_event
= console_send_event
;
714 for(i
= 0; i
< 8; i
++) {
715 color_table
[i
] = col_expand(s
->ds
,
716 vga_get_color(s
->ds
, color_table_rgb
[i
]));
721 s
->total_height
= DEFAULT_BACKSCROLL
;
726 s
->g_width
= s
->ds
->width
;
727 s
->g_height
= s
->ds
->height
;
728 text_console_resize(s
);