aboutsummaryrefslogtreecommitdiffstats
path: root/console.c
diff options
context:
space:
mode:
authorThe Android Open Source Project <initial-contribution@android.com>2009-02-10 15:43:59 -0800
committerThe Android Open Source Project <initial-contribution@android.com>2009-02-10 15:43:59 -0800
commitc27f813900a3c114562efbb8df1065e94766fc48 (patch)
treed95919283707dcab61009e27007374a745c9541e /console.c
parent0852ad57fa372f9b2854e4df685eaba8d8ef6790 (diff)
downloadexternal_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.c427
1 files changed, 340 insertions, 87 deletions
diff --git a/console.c b/console.c
index e9e2fe6..785710a 100644
--- a/console.c
+++ b/console.c
@@ -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);
+ }
+ }
+}