X-Git-Url: https://git.proxmox.com/?a=blobdiff_plain;f=console.c;h=acd8ca162cba55e6e1a59279c5dc3cbb505dce69;hb=9052ea6bf4962b1342aa56d4341bb55176ed9e45;hp=b452bca10267c28b8a3ea9a7a129bce8a92a891c;hpb=f0f2f976cf962a88f45d5c05e469e8acae8c4777;p=qemu.git diff --git a/console.c b/console.c index b452bca10..acd8ca162 100644 --- a/console.c +++ b/console.c @@ -28,7 +28,6 @@ //#define DEBUG_CONSOLE #define DEFAULT_BACKSCROLL 512 #define MAX_CONSOLES 12 -#define DEFAULT_MONITOR_SIZE "800x600" #define QEMU_RGBA(r, g, b, a) (((a) << 24) | ((r) << 16) | ((g) << 8) | (b)) #define QEMU_RGB(r, g, b) QEMU_RGBA(r, g, b, 0xff) @@ -138,6 +137,12 @@ struct TextConsole { TextAttributes t_attrib; /* currently active text attributes */ TextCell *cells; int text_x[2], text_y[2], cursor_invalidate; + int echo; + + int update_x0; + int update_y0; + int update_x1; + int update_y1; enum TTYState state; int esc_params[MAX_ESC_PARAMS]; @@ -150,6 +155,7 @@ struct TextConsole { QEMUTimer *kbd_timer; }; +static DisplayState *display_state; static TextConsole *active_console; static TextConsole *consoles[MAX_CONSOLES]; static int nb_consoles = 0; @@ -162,7 +168,7 @@ void vga_hw_update(void) void vga_hw_invalidate(void) { - if (active_console->hw_invalidate) + if (active_console && active_console->hw_invalidate) active_console->hw_invalidate(active_console->hw); } @@ -174,7 +180,7 @@ void vga_hw_screen_dump(const char *filename) active_console = consoles[0]; /* There is currently no way of specifying which screen we want to dump, so always dump the first one. */ - if (consoles[0]->hw_screen_dump) + if (consoles[0] && consoles[0]->hw_screen_dump) consoles[0]->hw_screen_dump(consoles[0]->hw, filename); active_console = previous_active_console; } @@ -303,7 +309,7 @@ static void vga_bitblt(DisplayState *ds, int xs, int ys, int xd, int yd, int w, (((uint32_t)(__x) & (uint32_t)0x00ff0000UL) >> 8) | \ (((uint32_t)(__x) & (uint32_t)0xff000000UL) >> 24) )) -#ifdef WORDS_BIGENDIAN +#ifdef HOST_WORDS_BIGENDIAN #define PAT(x) x #else #define PAT(x) cbswap_32(x) @@ -537,6 +543,18 @@ static inline void text_update_xy(TextConsole *s, int x, int y) s->text_y[1] = MAX(s->text_y[1], y); } +static void invalidate_xy(TextConsole *s, int x, int y) +{ + if (s->update_x0 > x * FONT_WIDTH) + s->update_x0 = x * FONT_WIDTH; + if (s->update_y0 > y * FONT_HEIGHT) + s->update_y0 = y * FONT_HEIGHT; + if (s->update_x1 < (x + 1) * FONT_WIDTH) + s->update_x1 = (x + 1) * FONT_WIDTH; + if (s->update_y1 < (y + 1) * FONT_HEIGHT) + s->update_y1 = (y + 1) * FONT_HEIGHT; +} + static void update_xy(TextConsole *s, int x, int y) { TextCell *c; @@ -556,8 +574,7 @@ static void update_xy(TextConsole *s, int x, int y) c = &s->cells[y1 * s->width + x]; vga_putcharxy(s->ds, x, y2, c->ch, &(c->t_attrib)); - dpy_update(s->ds, x * FONT_WIDTH, y2 * FONT_HEIGHT, - FONT_WIDTH, FONT_HEIGHT); + invalidate_xy(s, x, y2); } } } @@ -591,8 +608,7 @@ static void console_show_cursor(TextConsole *s, int show) } else { vga_putcharxy(s->ds, x, y, c->ch, &(c->t_attrib)); } - dpy_update(s->ds, x * FONT_WIDTH, y * FONT_HEIGHT, - FONT_WIDTH, FONT_HEIGHT); + invalidate_xy(s, x, y); } } } @@ -626,8 +642,8 @@ static void console_refresh(TextConsole *s) if (++y1 == s->total_height) y1 = 0; } - dpy_update(s->ds, 0, 0, ds_get_width(s->ds), ds_get_height(s->ds)); console_show_cursor(s, 1); + dpy_update(s->ds, 0, 0, ds_get_width(s->ds), ds_get_height(s->ds)); } static void console_scroll(int ydelta) @@ -703,8 +719,10 @@ static void console_put_lf(TextConsole *s) vga_fill_rect(s->ds, 0, (s->height - 1) * FONT_HEIGHT, s->width * FONT_WIDTH, FONT_HEIGHT, color_table[0][s->t_attrib_default.bgcol]); - dpy_update(s->ds, 0, 0, - s->width * FONT_WIDTH, s->height * FONT_HEIGHT); + s->update_x0 = 0; + s->update_y0 = 0; + s->update_x1 = s->width * FONT_WIDTH; + s->update_y1 = s->height * FONT_HEIGHT; } } } @@ -812,7 +830,6 @@ static void console_clear_xy(TextConsole *s, int x, int y) TextCell *c = &s->cells[y1 * s->width + x]; c->ch = ' '; c->t_attrib = s->t_attrib_default; - c++; update_xy(s, x, y); } @@ -1044,14 +1061,20 @@ void console_select(unsigned int index) if (index >= MAX_CONSOLES) return; - active_console->g_width = ds_get_width(active_console->ds); - active_console->g_height = ds_get_height(active_console->ds); + if (active_console) { + active_console->g_width = ds_get_width(active_console->ds); + active_console->g_height = ds_get_height(active_console->ds); + } s = consoles[index]; if (s) { DisplayState *ds = s->ds; active_console = s; - ds->surface = qemu_resize_displaysurface(ds->surface, s->g_width, - s->g_height, 32, 4 * s->g_width); + if (ds_get_bits_per_pixel(s->ds)) { + ds->surface = qemu_resize_displaysurface(ds, s->g_width, s->g_height); + } else { + s->ds->surface->width = s->width; + s->ds->surface->height = s->height; + } dpy_resize(s->ds); vga_hw_invalidate(); } @@ -1062,11 +1085,20 @@ static int console_puts(CharDriverState *chr, const uint8_t *buf, int len) TextConsole *s = chr->opaque; int i; + s->update_x0 = s->width * FONT_WIDTH; + s->update_y0 = s->height * FONT_HEIGHT; + s->update_x1 = 0; + s->update_y1 = 0; console_show_cursor(s, 0); for(i = 0; i < len; i++) { console_putchar(s, buf[i]); } console_show_cursor(s, 1); + if (ds_get_bits_per_pixel(s->ds) && s->update_x0 < s->update_x1) { + dpy_update(s->ds, s->update_x0, s->update_y0, + s->update_x1 - s->update_x0, + s->update_y1 - s->update_y0); + } return len; } @@ -1103,7 +1135,7 @@ static void kbd_send_chars(void *opaque) /* characters are pending: we send them a bit later (XXX: horrible, should change char device API) */ if (s->out_fifo.count > 0) { - qemu_mod_timer(s->kbd_timer, qemu_get_clock(rt_clock) + 1); + qemu_mod_timer(s->kbd_timer, qemu_get_clock_ms(rt_clock) + 1); } } @@ -1146,8 +1178,14 @@ void kbd_put_keysym(int keysym) *q++ = '\033'; *q++ = '['; *q++ = keysym & 0xff; + } else if (s->echo && (keysym == '\r' || keysym == '\n')) { + console_puts(s->chr, (const uint8_t *) "\r", 1); + *q++ = '\n'; } else { - *q++ = keysym; + *q++ = keysym; + } + if (s->echo) { + console_puts(s->chr, buf, q - buf); } if (s->chr->chr_read) { qemu_fifo_write(&s->out_fifo, buf, q - buf); @@ -1160,6 +1198,11 @@ void kbd_put_keysym(int keysym) static void text_console_invalidate(void *opaque) { TextConsole *s = (TextConsole *) opaque; + if (!ds_get_bits_per_pixel(s->ds) && s->console_type == TEXT_CONSOLE) { + s->g_width = ds_get_width(s->ds); + s->g_height = ds_get_height(s->ds); + text_console_resize(s); + } console_refresh(s); } @@ -1210,9 +1253,6 @@ static TextConsole *new_console(DisplayState *ds, console_type_t console_type) if (nb_consoles >= MAX_CONSOLES) return NULL; s = qemu_mallocz(sizeof(TextConsole)); - if (!s) { - return NULL; - } if (!active_console || ((active_console->console_type != GRAPHIC_CONSOLE) && (console_type == GRAPHIC_CONSOLE))) { active_console = s; @@ -1234,6 +1274,126 @@ static TextConsole *new_console(DisplayState *ds, console_type_t console_type) return s; } +static DisplaySurface* defaultallocator_create_displaysurface(int width, int height) +{ + DisplaySurface *surface = (DisplaySurface*) qemu_mallocz(sizeof(DisplaySurface)); + + int linesize = width * 4; + qemu_alloc_display(surface, width, height, linesize, + qemu_default_pixelformat(32), 0); + return surface; +} + +static DisplaySurface* defaultallocator_resize_displaysurface(DisplaySurface *surface, + int width, int height) +{ + int linesize = width * 4; + qemu_alloc_display(surface, width, height, linesize, + qemu_default_pixelformat(32), 0); + return surface; +} + +void qemu_alloc_display(DisplaySurface *surface, int width, int height, + int linesize, PixelFormat pf, int newflags) +{ + void *data; + surface->width = width; + surface->height = height; + surface->linesize = linesize; + surface->pf = pf; + if (surface->flags & QEMU_ALLOCATED_FLAG) { + data = qemu_realloc(surface->data, + surface->linesize * surface->height); + } else { + data = qemu_malloc(surface->linesize * surface->height); + } + surface->data = (uint8_t *)data; + surface->flags = newflags | QEMU_ALLOCATED_FLAG; +#ifdef HOST_WORDS_BIGENDIAN + surface->flags |= QEMU_BIG_ENDIAN_FLAG; +#endif +} + +DisplaySurface* qemu_create_displaysurface_from(int width, int height, int bpp, + int linesize, uint8_t *data) +{ + DisplaySurface *surface = (DisplaySurface*) qemu_mallocz(sizeof(DisplaySurface)); + + surface->width = width; + surface->height = height; + surface->linesize = linesize; + surface->pf = qemu_default_pixelformat(bpp); +#ifdef HOST_WORDS_BIGENDIAN + surface->flags = QEMU_BIG_ENDIAN_FLAG; +#endif + surface->data = data; + + return surface; +} + +static void defaultallocator_free_displaysurface(DisplaySurface *surface) +{ + if (surface == NULL) + return; + if (surface->flags & QEMU_ALLOCATED_FLAG) + qemu_free(surface->data); + qemu_free(surface); +} + +static struct DisplayAllocator default_allocator = { + defaultallocator_create_displaysurface, + defaultallocator_resize_displaysurface, + defaultallocator_free_displaysurface +}; + +static void dumb_display_init(void) +{ + DisplayState *ds = qemu_mallocz(sizeof(DisplayState)); + int width = 640; + int height = 480; + + ds->allocator = &default_allocator; + if (is_fixedsize_console()) { + width = active_console->g_width; + height = active_console->g_height; + } + ds->surface = qemu_create_displaysurface(ds, width, height); + register_displaystate(ds); +} + +/***********************************************************/ +/* register display */ + +void register_displaystate(DisplayState *ds) +{ + DisplayState **s; + s = &display_state; + while (*s != NULL) + s = &(*s)->next; + ds->next = NULL; + *s = ds; +} + +DisplayState *get_displaystate(void) +{ + if (!display_state) { + dumb_display_init (); + } + return display_state; +} + +DisplayAllocator *register_displayallocator(DisplayState *ds, DisplayAllocator *da) +{ + if(ds->allocator == &default_allocator) { + DisplaySurface *surf; + surf = da->create_displaysurface(ds_get_width(ds), ds_get_height(ds)); + defaultallocator_free_displaysurface(ds->surface); + ds->surface = surf; + ds->allocator = da; + } + return ds->allocator; +} + DisplayState *graphic_console_init(vga_hw_update_ptr update, vga_hw_invalidate_ptr invalidate, vga_hw_screen_dump_ptr screen_dump, @@ -1244,13 +1404,12 @@ DisplayState *graphic_console_init(vga_hw_update_ptr update, DisplayState *ds; ds = (DisplayState *) qemu_mallocz(sizeof(DisplayState)); - if (ds == NULL) - return NULL; - ds->surface = qemu_create_displaysurface(640, 480, 32, 640 * 4); + ds->allocator = &default_allocator; + ds->surface = qemu_create_displaysurface(ds, 640, 480); s = new_console(ds, GRAPHIC_CONSOLE); if (s == NULL) { - qemu_free_displaysurface(ds->surface); + qemu_free_displaysurface(ds); qemu_free(ds); return NULL; } @@ -1287,28 +1446,27 @@ void console_color_init(DisplayState *ds) static int n_text_consoles; static CharDriverState *text_consoles[128]; -static char *text_console_strs[128]; -static void text_console_do_init(CharDriverState *chr, DisplayState *ds, const char *p) +static void text_console_set_echo(CharDriverState *chr, bool echo) +{ + TextConsole *s = chr->opaque; + + s->echo = echo; +} + +static void text_console_do_init(CharDriverState *chr, DisplayState *ds) { TextConsole *s; - unsigned width; - unsigned height; static int color_inited; - s = new_console(ds, (p == 0) ? TEXT_CONSOLE : TEXT_CONSOLE_FIXED_SIZE); - if (!s) { - free(chr); - return; - } - chr->opaque = s; + s = chr->opaque; + chr->chr_write = console_puts; chr->chr_send_event = console_send_event; - s->chr = chr; s->out_fifo.buf = s->out_fifo_buf; s->out_fifo.buf_size = sizeof(s->out_fifo_buf); - s->kbd_timer = qemu_new_timer(rt_clock, kbd_send_chars, s); + s->kbd_timer = qemu_new_timer_ms(rt_clock, kbd_send_chars, s); s->ds = ds; if (!color_inited) { @@ -1320,25 +1478,10 @@ static void text_console_do_init(CharDriverState *chr, DisplayState *ds, const c s->total_height = DEFAULT_BACKSCROLL; s->x = 0; s->y = 0; - width = ds_get_width(s->ds); - height = ds_get_height(s->ds); - if (p != 0) { - width = strtoul(p, (char **)&p, 10); - if (*p == 'C') { - p++; - width *= FONT_WIDTH; - } - if (*p == 'x') { - p++; - height = strtoul(p, (char **)&p, 10); - if (*p == 'C') { - p++; - height *= FONT_HEIGHT; - } - } + if (s->console_type == TEXT_CONSOLE) { + s->g_width = ds_get_width(s->ds); + s->g_height = ds_get_height(s->ds); } - s->g_width = width; - s->g_height = height; s->hw_invalidate = text_console_invalidate; s->hw_text_update = text_console_update; @@ -1356,25 +1499,61 @@ static void text_console_do_init(CharDriverState *chr, DisplayState *ds, const c s->t_attrib = s->t_attrib_default; text_console_resize(s); - qemu_chr_reset(chr); + if (chr->label) { + char msg[128]; + int len; + + s->t_attrib.bgcol = COLOR_BLUE; + len = snprintf(msg, sizeof(msg), "%s console\r\n", chr->label); + console_puts(chr, (uint8_t*)msg, len); + s->t_attrib = s->t_attrib_default; + } + + qemu_chr_generic_open(chr); + if (chr->init) + chr->init(chr); } -CharDriverState *text_console_init(const char *p) +CharDriverState *text_console_init(QemuOpts *opts) { CharDriverState *chr; + TextConsole *s; + unsigned width; + unsigned height; chr = qemu_mallocz(sizeof(CharDriverState)); - if (!chr) - return NULL; if (n_text_consoles == 128) { fprintf(stderr, "Too many text consoles\n"); exit(1); } text_consoles[n_text_consoles] = chr; - text_console_strs[n_text_consoles] = p ? qemu_strdup(p) : NULL; n_text_consoles++; + width = qemu_opt_get_number(opts, "width", 0); + if (width == 0) + width = qemu_opt_get_number(opts, "cols", 0) * FONT_WIDTH; + + height = qemu_opt_get_number(opts, "height", 0); + if (height == 0) + height = qemu_opt_get_number(opts, "rows", 0) * FONT_HEIGHT; + + if (width == 0 || height == 0) { + s = new_console(NULL, TEXT_CONSOLE); + } else { + s = new_console(NULL, TEXT_CONSOLE_FIXED_SIZE); + } + + if (!s) { + free(chr); + return NULL; + } + + s->chr = chr; + s->g_width = width; + s->g_height = height; + chr->opaque = s; + chr->chr_set_echo = text_console_set_echo; return chr; } @@ -1383,8 +1562,7 @@ void text_consoles_set_display(DisplayState *ds) int i; for (i = 0; i < n_text_consoles; i++) { - text_console_do_init(text_consoles[i], ds, text_console_strs[i]); - qemu_free(text_console_strs[i]); + text_console_do_init(text_consoles[i], ds); } n_text_consoles = 0; @@ -1393,10 +1571,12 @@ void text_consoles_set_display(DisplayState *ds) void qemu_console_resize(DisplayState *ds, int width, int height) { TextConsole *s = get_graphic_console(ds); + if (!s) return; + s->g_width = width; s->g_height = height; if (is_graphic_console()) { - ds->surface = qemu_resize_displaysurface(ds->surface, width, height, 32, 4 * width); + ds->surface = qemu_resize_displaysurface(ds, width, height); dpy_resize(ds); } } @@ -1409,7 +1589,7 @@ void qemu_console_copy(DisplayState *ds, int src_x, int src_y, } } -static PixelFormat qemu_default_pixelformat(int bpp) +PixelFormat qemu_different_endianness_pixelformat(int bpp) { PixelFormat pf; @@ -1420,16 +1600,70 @@ static PixelFormat qemu_default_pixelformat(int bpp) pf.depth = bpp == 32 ? 24 : bpp; switch (bpp) { - case 8: - pf.rmask = 0x000000E0; - pf.gmask = 0x0000001C; - pf.bmask = 0x00000003; - pf.rmax = 7; - pf.gmax = 7; - pf.bmax = 3; - pf.rshift = 5; - pf.gshift = 2; + case 24: + pf.rmask = 0x000000FF; + pf.gmask = 0x0000FF00; + pf.bmask = 0x00FF0000; + pf.rmax = 255; + pf.gmax = 255; + pf.bmax = 255; + pf.rshift = 0; + pf.gshift = 8; + pf.bshift = 16; + pf.rbits = 8; + pf.gbits = 8; + pf.bbits = 8; + break; + case 32: + pf.rmask = 0x0000FF00; + pf.gmask = 0x00FF0000; + pf.bmask = 0xFF000000; + pf.amask = 0x00000000; + pf.amax = 255; + pf.rmax = 255; + pf.gmax = 255; + pf.bmax = 255; + pf.ashift = 0; + pf.rshift = 8; + pf.gshift = 16; + pf.bshift = 24; + pf.rbits = 8; + pf.gbits = 8; + pf.bbits = 8; + pf.abits = 8; + break; + default: + break; + } + return pf; +} + +PixelFormat qemu_default_pixelformat(int bpp) +{ + PixelFormat pf; + + memset(&pf, 0x00, sizeof(PixelFormat)); + + pf.bits_per_pixel = bpp; + pf.bytes_per_pixel = bpp / 8; + pf.depth = bpp == 32 ? 24 : bpp; + + switch (bpp) { + case 15: + pf.bits_per_pixel = 16; + pf.bytes_per_pixel = 2; + pf.rmask = 0x00007c00; + pf.gmask = 0x000003E0; + pf.bmask = 0x0000001F; + pf.rmax = 31; + pf.gmax = 31; + pf.bmax = 31; + pf.rshift = 10; + pf.gshift = 5; pf.bshift = 0; + pf.rbits = 5; + pf.gbits = 5; + pf.bbits = 5; break; case 16: pf.rmask = 0x0000F800; @@ -1441,101 +1675,42 @@ static PixelFormat qemu_default_pixelformat(int bpp) pf.rshift = 11; pf.gshift = 5; pf.bshift = 0; + pf.rbits = 5; + pf.gbits = 6; + pf.bbits = 5; break; case 24: + pf.rmask = 0x00FF0000; + pf.gmask = 0x0000FF00; + pf.bmask = 0x000000FF; + pf.rmax = 255; + pf.gmax = 255; + pf.bmax = 255; + pf.rshift = 16; + pf.gshift = 8; + pf.bshift = 0; + pf.rbits = 8; + pf.gbits = 8; + pf.bbits = 8; case 32: pf.rmask = 0x00FF0000; pf.gmask = 0x0000FF00; pf.bmask = 0x000000FF; + pf.amax = 255; pf.rmax = 255; pf.gmax = 255; pf.bmax = 255; + pf.ashift = 24; pf.rshift = 16; pf.gshift = 8; pf.bshift = 0; + pf.rbits = 8; + pf.gbits = 8; + pf.bbits = 8; + pf.abits = 8; break; default: break; } return pf; } - -DisplaySurface* qemu_create_displaysurface(int width, int height, int bpp, int linesize) -{ - DisplaySurface *surface = (DisplaySurface*) qemu_mallocz(sizeof(DisplaySurface)); - if (surface == NULL) { - fprintf(stderr, "qemu_create_displaysurface: malloc failed\n"); - exit(1); - } - - surface->width = width; - surface->height = height; - surface->linesize = linesize; - surface->pf = qemu_default_pixelformat(bpp); -#ifdef WORDS_BIGENDIAN - surface->flags = QEMU_ALLOCATED_FLAG | QEMU_BIG_ENDIAN_FLAG; -#else - surface->flags = QEMU_ALLOCATED_FLAG; -#endif - surface->data = (uint8_t*) qemu_mallocz(surface->linesize * surface->height); - if (surface->data == NULL) { - fprintf(stderr, "qemu_create_displaysurface: malloc failed\n"); - exit(1); - } - - return surface; -} - -DisplaySurface* qemu_resize_displaysurface(DisplaySurface *surface, - int width, int height, int bpp, int linesize) -{ - surface->width = width; - surface->height = height; - surface->linesize = linesize; - surface->pf = qemu_default_pixelformat(bpp); - if (surface->flags & QEMU_ALLOCATED_FLAG) - surface->data = (uint8_t*) qemu_realloc(surface->data, surface->linesize * surface->height); - else - surface->data = (uint8_t*) qemu_malloc(surface->linesize * surface->height); - if (surface->data == NULL) { - fprintf(stderr, "qemu_resize_displaysurface: malloc failed\n"); - exit(1); - } -#ifdef WORDS_BIGENDIAN - surface->flags = QEMU_ALLOCATED_FLAG | QEMU_BIG_ENDIAN_FLAG; -#else - surface->flags = QEMU_ALLOCATED_FLAG; -#endif - - return surface; -} - -DisplaySurface* qemu_create_displaysurface_from(int width, int height, int bpp, - int linesize, uint8_t *data) -{ - DisplaySurface *surface = (DisplaySurface*) qemu_mallocz(sizeof(DisplaySurface)); - if (surface == NULL) { - fprintf(stderr, "qemu_create_displaysurface_from: malloc failed\n"); - exit(1); - } - - surface->width = width; - surface->height = height; - surface->linesize = linesize; - surface->pf = qemu_default_pixelformat(bpp); -#ifdef WORDS_BIGENDIAN - surface->flags = QEMU_BIG_ENDIAN_FLAG; -#endif - surface->data = data; - - return surface; -} - -void qemu_free_displaysurface(DisplaySurface *surface) -{ - if (surface == NULL) - return; - if (surface->flags & QEMU_ALLOCATED_FLAG) - qemu_free(surface->data); - qemu_free(surface); -}