diff options
author | The Android Open Source Project <initial-contribution@android.com> | 2009-02-10 15:43:59 -0800 |
---|---|---|
committer | The Android Open Source Project <initial-contribution@android.com> | 2009-02-10 15:43:59 -0800 |
commit | c27f813900a3c114562efbb8df1065e94766fc48 (patch) | |
tree | d95919283707dcab61009e27007374a745c9541e /console.c | |
parent | 0852ad57fa372f9b2854e4df685eaba8d8ef6790 (diff) | |
download | external_qemu-c27f813900a3c114562efbb8df1065e94766fc48.zip external_qemu-c27f813900a3c114562efbb8df1065e94766fc48.tar.gz external_qemu-c27f813900a3c114562efbb8df1065e94766fc48.tar.bz2 |
auto import from //branches/cupcake/...@130745
Diffstat (limited to 'console.c')
-rw-r--r-- | console.c | 427 |
1 files changed, 340 insertions, 87 deletions
@@ -21,11 +21,14 @@ * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. */ -#include "vl.h" +#include "qemu-common.h" +#include "console.h" +#include "qemu-timer.h" //#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) @@ -59,7 +62,7 @@ typedef struct QEMUFIFO { int count, wptr, rptr; } QEMUFIFO; -int qemu_fifo_write(QEMUFIFO *f, const uint8_t *buf, int len1) +static int qemu_fifo_write(QEMUFIFO *f, const uint8_t *buf, int len1) { int l, len; @@ -82,7 +85,7 @@ int qemu_fifo_write(QEMUFIFO *f, const uint8_t *buf, int len1) return len1; } -int qemu_fifo_read(QEMUFIFO *f, uint8_t *buf, int len1) +static int qemu_fifo_read(QEMUFIFO *f, uint8_t *buf, int len1) { int l, len; @@ -104,15 +107,21 @@ int qemu_fifo_read(QEMUFIFO *f, uint8_t *buf, int len1) return len1; } +typedef enum { + GRAPHIC_CONSOLE, + TEXT_CONSOLE +} console_type_t; + /* ??? This is mis-named. It is used for both text and graphical consoles. */ struct TextConsole { - int text_console; /* true if text console */ + console_type_t console_type; DisplayState *ds; /* Graphic console state. */ vga_hw_update_ptr hw_update; vga_hw_invalidate_ptr hw_invalidate; vga_hw_screen_dump_ptr hw_screen_dump; + vga_hw_text_update_ptr hw_text_update; void *hw; int g_width, g_height; @@ -121,20 +130,19 @@ struct TextConsole { int total_height; int backscroll_height; int x, y; + int x_saved, y_saved; int y_displayed; int y_base; TextAttributes t_attrib_default; /* default text attributes */ TextAttributes t_attrib; /* currently active text attributes */ TextCell *cells; + int text_x[2], text_y[2], cursor_invalidate; enum TTYState state; int esc_params[MAX_ESC_PARAMS]; int nb_esc_params; - /* kbd read handler */ - IOCanRWHandler *fd_can_read; - IOReadHandler *fd_read; - void *fd_opaque; + CharDriverState *chr; /* fifo for key pressed */ QEMUFIFO out_fifo; uint8_t out_fifo_buf[16]; @@ -147,7 +155,7 @@ static int nb_consoles = 0; void vga_hw_update(void) { - if (active_console->hw_update) + if (active_console && active_console->hw_update) active_console->hw_update(active_console->hw); } @@ -159,10 +167,21 @@ void vga_hw_invalidate(void) void vga_hw_screen_dump(const char *filename) { - /* There is currently no was of specifying which screen we want to dump, - so always dump the dirst one. */ + TextConsole *previous_active_console; + + previous_active_console = active_console; + 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) consoles[0]->hw_screen_dump(consoles[0]->hw, filename); + active_console = previous_active_console; +} + +void vga_hw_text_update(console_ch_t *chardata) +{ + if (active_console && active_console->hw_text_update) + active_console->hw_text_update(active_console->hw, chardata); } /* convert a RGBA color to a color index usable in graphic primitives */ @@ -505,16 +524,29 @@ static void text_console_resize(TextConsole *s) c++; } } - free(s->cells); + qemu_free(s->cells); s->cells = cells; } +static inline void text_update_xy(TextConsole *s, int x, int y) +{ + s->text_x[0] = MIN(s->text_x[0], x); + s->text_x[1] = MAX(s->text_x[1], x); + s->text_y[0] = MIN(s->text_y[0], y); + s->text_y[1] = MAX(s->text_y[1], y); +} + static void update_xy(TextConsole *s, int x, int y) { TextCell *c; int y1, y2; if (s == active_console) { + if (!s->ds->depth) { + text_update_xy(s, x, y); + return; + } + y1 = (s->y_base + y) % s->total_height; y2 = y1 - s->y_displayed; if (y2 < 0) @@ -535,21 +567,30 @@ static void console_show_cursor(TextConsole *s, int show) int y, y1; if (s == active_console) { + int x = s->x; + + if (!s->ds->depth) { + s->cursor_invalidate = 1; + return; + } + + if (x >= s->width) { + x = s->width - 1; + } y1 = (s->y_base + s->y) % s->total_height; y = y1 - s->y_displayed; if (y < 0) y += s->total_height; if (y < s->height) { - c = &s->cells[y1 * s->width + s->x]; + c = &s->cells[y1 * s->width + x]; if (show) { TextAttributes t_attrib = s->t_attrib_default; t_attrib.invers = !(t_attrib.invers); /* invert fg and bg */ - vga_putcharxy(s->ds, s->x, y, c->ch, &t_attrib); + vga_putcharxy(s->ds, x, y, c->ch, &t_attrib); } else { - vga_putcharxy(s->ds, s->x, y, c->ch, - &(c->t_attrib)); + vga_putcharxy(s->ds, x, y, c->ch, &(c->t_attrib)); } - dpy_update(s->ds, s->x * FONT_WIDTH, y * FONT_HEIGHT, + dpy_update(s->ds, x * FONT_WIDTH, y * FONT_HEIGHT, FONT_WIDTH, FONT_HEIGHT); } } @@ -562,6 +603,14 @@ static void console_refresh(TextConsole *s) if (s != active_console) return; + if (!s->ds->depth) { + s->text_x[0] = 0; + s->text_y[0] = 0; + s->text_x[1] = s->width - 1; + s->text_y[1] = s->height - 1; + s->cursor_invalidate = 1; + return; + } vga_fill_rect(s->ds, 0, 0, s->ds->width, s->ds->height, color_table[0][COLOR_BLACK]); @@ -586,7 +635,7 @@ static void console_scroll(int ydelta) int i, y1; s = active_console; - if (!s || !s->text_console) + if (!s || (s->console_type == GRAPHIC_CONSOLE)) return; if (ydelta > 0) { @@ -639,6 +688,14 @@ static void console_put_lf(TextConsole *s) c++; } if (s == active_console && s->y_displayed == s->y_base) { + if (!s->ds->depth) { + s->text_x[0] = 0; + s->text_y[0] = 0; + s->text_x[1] = s->width - 1; + s->text_y[1] = s->height - 1; + return; + } + vga_bitblt(s->ds, 0, FONT_HEIGHT, 0, 0, s->width * FONT_WIDTH, (s->height - 1) * FONT_HEIGHT); @@ -659,10 +716,6 @@ static void console_handle_escape(TextConsole *s) { int i; - if (s->nb_esc_params == 0) { /* ESC[m sets all attributes to default */ - s->t_attrib = s->t_attrib_default; - return; - } for (i=0; i<s->nb_esc_params; i++) { switch (s->esc_params[i]) { case 0: /* reset all console attributes to default */ @@ -752,10 +805,21 @@ static void console_handle_escape(TextConsole *s) } } +static void console_clear_xy(TextConsole *s, int x, int y) +{ + int y1 = (s->y_base + y) % s->total_height; + TextCell *c = &s->cells[y1 * s->width + x]; + c->ch = ' '; + c->t_attrib = s->t_attrib_default; + c++; + update_xy(s, x, y); +} + static void console_putchar(TextConsole *s, int ch) { TextCell *c; - int y1, i, x; + int y1, i; + int x, y; switch(s->state) { case TTY_STATE_NORM: @@ -781,22 +845,27 @@ static void console_putchar(TextConsole *s, int ch) case '\a': /* alert aka. bell */ /* TODO: has to be implemented */ break; + case 14: + /* SI (shift in), character set 0 (ignored) */ + break; + case 15: + /* SO (shift out), character set 1 (ignored) */ + break; case 27: /* esc (introducing an escape sequence) */ s->state = TTY_STATE_ESC; break; default: - y1 = (s->y_base + s->y) % s->total_height; - if (s->x < s->width) { - c = &s->cells[y1 * s->width + s->x]; - c->ch = ch; - c->t_attrib = s->t_attrib; - } - update_xy(s, s->x, s->y); - s->x++; if (s->x >= s->width) { + /* line wrap */ s->x = 0; console_put_lf(s); } + y1 = (s->y_base + s->y) % s->total_height; + c = &s->cells[y1 * s->width + s->x]; + c->ch = ch; + c->t_attrib = s->t_attrib; + update_xy(s, s->x, s->y); + s->x++; break; } break; @@ -820,32 +889,150 @@ static void console_putchar(TextConsole *s, int ch) s->nb_esc_params++; if (ch == ';') break; +#ifdef DEBUG_CONSOLE + fprintf(stderr, "escape sequence CSI%d;%d%c, %d parameters\n", + s->esc_params[0], s->esc_params[1], ch, s->nb_esc_params); +#endif s->state = TTY_STATE_NORM; switch(ch) { - case 'D': - if (s->x > 0) - s->x--; + case 'A': + /* move cursor up */ + if (s->esc_params[0] == 0) { + s->esc_params[0] = 1; + } + s->y -= s->esc_params[0]; + if (s->y < 0) { + s->y = 0; + } + break; + case 'B': + /* move cursor down */ + if (s->esc_params[0] == 0) { + s->esc_params[0] = 1; + } + s->y += s->esc_params[0]; + if (s->y >= s->height) { + s->y = s->height - 1; + } break; case 'C': - if (s->x < (s->width - 1)) - s->x++; + /* move cursor right */ + if (s->esc_params[0] == 0) { + s->esc_params[0] = 1; + } + s->x += s->esc_params[0]; + if (s->x >= s->width) { + s->x = s->width - 1; + } + break; + case 'D': + /* move cursor left */ + if (s->esc_params[0] == 0) { + s->esc_params[0] = 1; + } + s->x -= s->esc_params[0]; + if (s->x < 0) { + s->x = 0; + } + break; + case 'G': + /* move cursor to column */ + s->x = s->esc_params[0] - 1; + if (s->x < 0) { + s->x = 0; + } break; + case 'f': + case 'H': + /* move cursor to row, column */ + s->x = s->esc_params[1] - 1; + if (s->x < 0) { + s->x = 0; + } + s->y = s->esc_params[0] - 1; + if (s->y < 0) { + s->y = 0; + } + break; + case 'J': + switch (s->esc_params[0]) { + case 0: + /* clear to end of screen */ + for (y = s->y; y < s->height; y++) { + for (x = 0; x < s->width; x++) { + if (y == s->y && x < s->x) { + continue; + } + console_clear_xy(s, x, y); + } + } + break; + case 1: + /* clear from beginning of screen */ + for (y = 0; y <= s->y; y++) { + for (x = 0; x < s->width; x++) { + if (y == s->y && x > s->x) { + break; + } + console_clear_xy(s, x, y); + } + } + break; + case 2: + /* clear entire screen */ + for (y = 0; y <= s->height; y++) { + for (x = 0; x < s->width; x++) { + console_clear_xy(s, x, y); + } + } + break; + } case 'K': + switch (s->esc_params[0]) { + case 0: /* clear to eol */ - y1 = (s->y_base + s->y) % s->total_height; for(x = s->x; x < s->width; x++) { - c = &s->cells[y1 * s->width + x]; - c->ch = ' '; - c->t_attrib = s->t_attrib_default; - c++; - update_xy(s, x, s->y); + console_clear_xy(s, x, s->y); } break; - default: + case 1: + /* clear from beginning of line */ + for (x = 0; x <= s->x; x++) { + console_clear_xy(s, x, s->y); + } + break; + case 2: + /* clear entire line */ + for(x = 0; x < s->width; x++) { + console_clear_xy(s, x, s->y); + } break; } + break; + case 'm': console_handle_escape(s); break; + case 'n': + /* report cursor position */ + /* TODO: send ESC[row;colR */ + break; + case 's': + /* save cursor position */ + s->x_saved = s->x; + s->y_saved = s->y; + break; + case 'u': + /* restore cursor position */ + s->x = s->x_saved; + s->y = s->y_saved; + break; + default: +#ifdef DEBUG_CONSOLE + fprintf(stderr, "unhandled escape character '%c'\n", ch); +#endif + break; + } + break; } } } @@ -859,17 +1046,10 @@ void console_select(unsigned int index) s = consoles[index]; if (s) { active_console = s; - if (s->text_console) { - if (s->g_width != s->ds->width || - s->g_height != s->ds->height) { - s->g_width = s->ds->width; - s->g_height = s->ds->height; - text_console_resize(s); - } - console_refresh(s); - } else { - vga_hw_invalidate(); - } + if (s->g_width && s->g_height + && (s->g_width != s->ds->width || s->g_height != s->ds->height)) + dpy_resize(s->ds, s->g_width, s->g_height); + vga_hw_invalidate(); } } @@ -886,16 +1066,6 @@ static int console_puts(CharDriverState *chr, const uint8_t *buf, int len) return len; } -static void console_chr_add_read_handler(CharDriverState *chr, - IOCanRWHandler *fd_can_read, - IOReadHandler *fd_read, void *opaque) -{ - TextConsole *s = chr->opaque; - s->fd_can_read = fd_can_read; - s->fd_read = fd_read; - s->fd_opaque = opaque; -} - static void console_send_event(CharDriverState *chr, int event) { TextConsole *s = chr->opaque; @@ -917,14 +1087,14 @@ static void kbd_send_chars(void *opaque) int len; uint8_t buf[16]; - len = s->fd_can_read(s->fd_opaque); + len = qemu_chr_can_read(s->chr); if (len > s->out_fifo.count) len = s->out_fifo.count; if (len > 0) { if (len > sizeof(buf)) len = sizeof(buf); qemu_fifo_read(&s->out_fifo, buf, len); - s->fd_read(s->fd_opaque, buf, len); + qemu_chr_read(s->chr, buf, len); } /* characters are pending: we send them a bit later (XXX: horrible, should change char device API) */ @@ -941,7 +1111,7 @@ void kbd_put_keysym(int keysym) int c; s = active_console; - if (!s || !s->text_console) + if (!s || (s->console_type == GRAPHIC_CONSOLE)) return; switch(keysym) { @@ -975,7 +1145,7 @@ void kbd_put_keysym(int keysym) } else { *q++ = keysym; } - if (s->fd_read) { + if (s->chr->chr_read) { qemu_fifo_write(&s->out_fifo, buf, q - buf); kbd_send_chars(s); } @@ -983,7 +1153,41 @@ void kbd_put_keysym(int keysym) } } -static TextConsole *new_console(DisplayState *ds, int text) +static void text_console_invalidate(void *opaque) +{ + TextConsole *s = (TextConsole *) opaque; + + console_refresh(s); +} + +static void text_console_update(void *opaque, console_ch_t *chardata) +{ + TextConsole *s = (TextConsole *) opaque; + int i, j, src; + + if (s->text_x[0] <= s->text_x[1]) { + src = (s->y_base + s->text_y[0]) * s->width; + chardata += s->text_y[0] * s->width; + for (i = s->text_y[0]; i <= s->text_y[1]; i ++) + for (j = 0; j < s->width; j ++, src ++) + console_write_ch(chardata ++, s->cells[src].ch | + (s->cells[src].t_attrib.fgcol << 12) | + (s->cells[src].t_attrib.bgcol << 8) | + (s->cells[src].t_attrib.bold << 21)); + dpy_update(s->ds, s->text_x[0], s->text_y[0], + s->text_x[1] - s->text_x[0], i - s->text_y[0]); + s->text_x[0] = s->width; + s->text_y[0] = s->height; + s->text_x[1] = 0; + s->text_y[1] = 0; + } + if (s->cursor_invalidate) { + dpy_cursor(s->ds, s->x, s->y); + s->cursor_invalidate = 0; + } +} + +static TextConsole *new_console(DisplayState *ds, console_type_t console_type) { TextConsole *s; int i; @@ -994,16 +1198,18 @@ static TextConsole *new_console(DisplayState *ds, int text) if (!s) { return NULL; } - if (!active_console || (active_console->text_console && !text)) + if (!active_console || ((active_console->console_type != GRAPHIC_CONSOLE) && + (console_type == GRAPHIC_CONSOLE))) { active_console = s; + } s->ds = ds; - s->text_console = text; - if (text) { + s->console_type = console_type; + if (console_type != GRAPHIC_CONSOLE) { consoles[nb_consoles++] = s; } else { /* HACK: Put graphical consoles before text consoles. */ for (i = nb_consoles; i > 0; i--) { - if (!consoles[i - 1]->text_console) + if (consoles[i - 1]->console_type == GRAPHIC_CONSOLE) break; consoles[i] = consoles[i - 1]; } @@ -1015,65 +1221,98 @@ static TextConsole *new_console(DisplayState *ds, int text) TextConsole *graphic_console_init(DisplayState *ds, vga_hw_update_ptr update, vga_hw_invalidate_ptr invalidate, vga_hw_screen_dump_ptr screen_dump, + vga_hw_text_update_ptr text_update, void *opaque) { TextConsole *s; - s = new_console(ds, 0); + s = new_console(ds, GRAPHIC_CONSOLE); if (!s) return NULL; s->hw_update = update; s->hw_invalidate = invalidate; s->hw_screen_dump = screen_dump; + s->hw_text_update = text_update; s->hw = opaque; return s; } int is_graphic_console(void) { - return !active_console->text_console; + return active_console && active_console->console_type == GRAPHIC_CONSOLE; } -CharDriverState *text_console_init(DisplayState *ds) +void console_color_init(DisplayState *ds) +{ + int i, j; + for (j = 0; j < 2; j++) { + for (i = 0; i < 8; i++) { + color_table[j][i] = col_expand(ds, + vga_get_color(ds, color_table_rgb[j][i])); + } + } +} + +CharDriverState *text_console_init(DisplayState *ds, const char *p) { CharDriverState *chr; TextConsole *s; - int i,j; + unsigned width; + unsigned height; static int color_inited; chr = qemu_mallocz(sizeof(CharDriverState)); if (!chr) return NULL; - s = new_console(ds, 1); + s = new_console(ds, TEXT_CONSOLE); if (!s) { free(chr); return NULL; } + if (!p) + p = DEFAULT_MONITOR_SIZE; + chr->opaque = s; chr->chr_write = console_puts; - chr->chr_add_read_handler = console_chr_add_read_handler; 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); if (!color_inited) { color_inited = 1; - for(j = 0; j < 2; j++) { - for(i = 0; i < 8; i++) { - color_table[j][i] = col_expand(s->ds, - vga_get_color(s->ds, color_table_rgb[j][i])); - } - } + console_color_init(s->ds); } s->y_displayed = 0; s->y_base = 0; s->total_height = DEFAULT_BACKSCROLL; s->x = 0; s->y = 0; - s->g_width = s->ds->width; - s->g_height = s->ds->height; + width = s->ds->width; + height = s->ds->height; + 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; + } + } + } + s->g_width = width; + s->g_height = height; + + s->hw_invalidate = text_console_invalidate; + s->hw_text_update = text_console_update; + s->hw = s; /* Set text attribute defaults */ s->t_attrib_default.bold = 0; @@ -1088,5 +1327,19 @@ CharDriverState *text_console_init(DisplayState *ds) s->t_attrib = s->t_attrib_default; text_console_resize(s); + qemu_chr_reset(chr); + return chr; } + +void qemu_console_resize(QEMUConsole *console, int width, int height) +{ + if (console->g_width != width || console->g_height != height + || !console->ds->data) { + console->g_width = width; + console->g_height = height; + if (active_console == console) { + dpy_resize(console->ds, width, height); + } + } +} |