summaryrefslogtreecommitdiff
path: root/ui/console.c
diff options
context:
space:
mode:
Diffstat (limited to 'ui/console.c')
-rw-r--r--ui/console.c1561
1 files changed, 1002 insertions, 559 deletions
diff --git a/ui/console.c b/ui/console.c
index e3e82979d..53dee8e26 100644
--- a/ui/console.c
+++ b/ui/console.c
@@ -21,16 +21,22 @@
* OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
* THE SOFTWARE.
*/
-#include "qemu-common.h"
+
+#include "qemu/osdep.h"
#include "ui/console.h"
#include "hw/qdev-core.h"
+#include "qapi/error.h"
+#include "qapi/qapi-commands-ui.h"
+#include "qemu/module.h"
+#include "qemu/option.h"
#include "qemu/timer.h"
-#include "qmp-commands.h"
-#include "sysemu/char.h"
+#include "chardev/char-fe.h"
+#include "trace.h"
+#include "exec/memory.h"
+#include "io/channel-file.h"
+#include "qom/object.h"
-//#define DEBUG_CONSOLE
#define DEFAULT_BACKSCROLL 512
-#define MAX_CONSOLES 12
#define CONSOLE_CURSOR_PERIOD 500
typedef struct TextAttributes {
@@ -121,9 +127,15 @@ struct QemuConsole {
DisplayState *ds;
DisplaySurface *surface;
int dcls;
+ DisplayChangeListener *gl;
+ bool gl_block;
+ int window_id;
/* Graphic console state. */
Object *device;
+ uint32_t head;
+ QemuUIInfo ui_info;
+ QEMUTimer *ui_timer;
const GraphicHwOps *hw_ops;
void *hw;
@@ -141,8 +153,6 @@ struct QemuConsole {
TextCell *cells;
int text_x[2], text_y[2], cursor_invalidate;
int echo;
- bool cursor_visible_phase;
- QEMUTimer *cursor_timer;
int update_x0;
int update_y0;
@@ -153,15 +163,18 @@ struct QemuConsole {
int esc_params[MAX_ESC_PARAMS];
int nb_esc_params;
- CharDriverState *chr;
+ Chardev *chr;
/* fifo for key pressed */
QEMUFIFO out_fifo;
uint8_t out_fifo_buf[16];
QEMUTimer *kbd_timer;
+ CoQueue dump_queue;
+
+ QTAILQ_ENTRY(QemuConsole) next;
};
struct DisplayState {
- struct QEMUTimer *gui_timer;
+ QEMUTimer *gui_timer;
uint64_t last_update;
uint64_t update_interval;
bool refreshing;
@@ -173,12 +186,16 @@ struct DisplayState {
static DisplayState *display_state;
static QemuConsole *active_console;
-static QemuConsole *consoles[MAX_CONSOLES];
-static int nb_consoles = 0;
+static QTAILQ_HEAD(, QemuConsole) consoles =
+ QTAILQ_HEAD_INITIALIZER(consoles);
+static bool cursor_visible_phase;
+static QEMUTimer *cursor_timer;
-static void text_console_do_init(CharDriverState *chr, DisplayState *ds);
+static void text_console_do_init(Chardev *chr, DisplayState *ds);
static void dpy_refresh(DisplayState *s);
static DisplayState *get_alloc_displaystate(void);
+static void text_console_update_cursor_timer(void);
+static void text_console_update_cursor(void *opaque);
static void gui_update(void *opaque)
{
@@ -186,7 +203,7 @@ static void gui_update(void *opaque)
uint64_t dcl_interval;
DisplayState *ds = opaque;
DisplayChangeListener *dcl;
- int i;
+ QemuConsole *con;
ds->refreshing = true;
dpy_refresh(ds);
@@ -201,15 +218,15 @@ static void gui_update(void *opaque)
}
if (ds->update_interval != interval) {
ds->update_interval = interval;
- for (i = 0; i < nb_consoles; i++) {
- if (consoles[i]->hw_ops->update_interval) {
- consoles[i]->hw_ops->update_interval(consoles[i]->hw, interval);
+ QTAILQ_FOREACH(con, &consoles, next) {
+ if (con->hw_ops->update_interval) {
+ con->hw_ops->update_interval(con->hw, interval);
}
}
trace_console_refresh(interval);
}
- ds->last_update = qemu_get_clock_ms(rt_clock);
- qemu_mod_timer(ds->gui_timer, ds->last_update + interval);
+ ds->last_update = qemu_clock_get_ms(QEMU_CLOCK_REALTIME);
+ timer_mod(ds->gui_timer, ds->last_update + interval);
}
static void gui_setup_refresh(DisplayState *ds)
@@ -232,12 +249,12 @@ static void gui_setup_refresh(DisplayState *ds)
}
if (need_timer && ds->gui_timer == NULL) {
- ds->gui_timer = qemu_new_timer_ms(rt_clock, gui_update, ds);
- qemu_mod_timer(ds->gui_timer, qemu_get_clock_ms(rt_clock));
+ ds->gui_timer = timer_new_ms(QEMU_CLOCK_REALTIME, gui_update, ds);
+ timer_mod(ds->gui_timer, qemu_clock_get_ms(QEMU_CLOCK_REALTIME));
}
if (!need_timer && ds->gui_timer != NULL) {
- qemu_del_timer(ds->gui_timer);
- qemu_free_timer(ds->gui_timer);
+ timer_del(ds->gui_timer);
+ timer_free(ds->gui_timer);
ds->gui_timer = NULL;
}
@@ -245,16 +262,49 @@ static void gui_setup_refresh(DisplayState *ds)
ds->have_text = have_text;
}
+void graphic_hw_update_done(QemuConsole *con)
+{
+ if (con) {
+ qemu_co_queue_restart_all(&con->dump_queue);
+ }
+}
+
void graphic_hw_update(QemuConsole *con)
{
+ bool async = false;
+ con = con ? con : active_console;
if (!con) {
- con = active_console;
+ return;
}
- if (con && con->hw_ops->gfx_update) {
+ if (con->hw_ops->gfx_update) {
con->hw_ops->gfx_update(con->hw);
+ async = con->hw_ops->gfx_update_async;
+ }
+ if (!async) {
+ graphic_hw_update_done(con);
}
}
+void graphic_hw_gl_block(QemuConsole *con, bool block)
+{
+ assert(con != NULL);
+
+ con->gl_block = block;
+ if (con->hw_ops->gl_block) {
+ con->hw_ops->gl_block(con->hw, block);
+ }
+}
+
+int qemu_console_get_window_id(QemuConsole *con)
+{
+ return con->window_id;
+}
+
+void qemu_console_set_window_id(QemuConsole *con, int window_id)
+{
+ con->window_id = window_id;
+}
+
void graphic_hw_invalidate(QemuConsole *con)
{
if (!con) {
@@ -265,67 +315,103 @@ void graphic_hw_invalidate(QemuConsole *con)
}
}
-static void ppm_save(const char *filename, struct DisplaySurface *ds,
- Error **errp)
+static bool ppm_save(int fd, pixman_image_t *image, Error **errp)
{
- int width = pixman_image_get_width(ds->image);
- int height = pixman_image_get_height(ds->image);
- int fd;
- FILE *f;
+ int width = pixman_image_get_width(image);
+ int height = pixman_image_get_height(image);
+ g_autoptr(Object) ioc = OBJECT(qio_channel_file_new_fd(fd));
+ g_autofree char *header = NULL;
+ g_autoptr(pixman_image_t) linebuf = NULL;
int y;
- int ret;
- pixman_image_t *linebuf;
- trace_ppm_save(filename, ds);
- fd = qemu_open(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 0666);
- if (fd == -1) {
- error_setg(errp, "failed to open file '%s': %s", filename,
- strerror(errno));
- return;
- }
- f = fdopen(fd, "wb");
- ret = fprintf(f, "P6\n%d %d\n%d\n", width, height, 255);
- if (ret < 0) {
- linebuf = NULL;
- goto write_err;
+ trace_ppm_save(fd, image);
+
+ header = g_strdup_printf("P6\n%d %d\n%d\n", width, height, 255);
+ if (qio_channel_write_all(QIO_CHANNEL(ioc),
+ header, strlen(header), errp) < 0) {
+ return false;
}
+
linebuf = qemu_pixman_linebuf_create(PIXMAN_BE_r8g8b8, width);
for (y = 0; y < height; y++) {
- qemu_pixman_linebuf_fill(linebuf, ds->image, width, 0, y);
- clearerr(f);
- ret = fwrite(pixman_image_get_data(linebuf), 1,
- pixman_image_get_stride(linebuf), f);
- (void)ret;
- if (ferror(f)) {
- goto write_err;
+ qemu_pixman_linebuf_fill(linebuf, image, width, 0, y);
+ if (qio_channel_write_all(QIO_CHANNEL(ioc),
+ (char *)pixman_image_get_data(linebuf),
+ pixman_image_get_stride(linebuf), errp) < 0) {
+ return false;
}
}
-out:
- qemu_pixman_image_unref(linebuf);
- fclose(f);
- return;
+ return true;
+}
-write_err:
- error_setg(errp, "failed to write to file '%s': %s", filename,
- strerror(errno));
- unlink(filename);
- goto out;
+static void graphic_hw_update_bh(void *con)
+{
+ graphic_hw_update(con);
}
-void qmp_screendump(const char *filename, Error **errp)
+/* Safety: coroutine-only, concurrent-coroutine safe, main thread only */
+void coroutine_fn
+qmp_screendump(const char *filename, bool has_device, const char *device,
+ bool has_head, int64_t head, Error **errp)
{
- QemuConsole *con = qemu_console_lookup_by_index(0);
+ g_autoptr(pixman_image_t) image = NULL;
+ QemuConsole *con;
DisplaySurface *surface;
+ int fd;
- if (con == NULL) {
- error_setg(errp, "There is no QemuConsole I can screendump from.");
- return;
+ if (has_device) {
+ con = qemu_console_lookup_by_device_name(device, has_head ? head : 0,
+ errp);
+ if (!con) {
+ return;
+ }
+ } else {
+ if (has_head) {
+ error_setg(errp, "'head' must be specified together with 'device'");
+ return;
+ }
+ con = qemu_console_lookup_by_index(0);
+ if (!con) {
+ error_setg(errp, "There is no console to take a screendump from");
+ return;
+ }
}
- graphic_hw_update(con);
+ if (qemu_co_queue_empty(&con->dump_queue)) {
+ /* Defer the update, it will restart the pending coroutines */
+ aio_bh_schedule_oneshot(qemu_get_aio_context(),
+ graphic_hw_update_bh, con);
+ }
+ qemu_co_queue_wait(&con->dump_queue, NULL);
+
+ /*
+ * All pending coroutines are woken up, while the BQL is held. No
+ * further graphic update are possible until it is released. Take
+ * an image ref before that.
+ */
surface = qemu_console_surface(con);
- ppm_save(filename, surface, errp);
+ if (!surface) {
+ error_setg(errp, "no surface");
+ return;
+ }
+ image = pixman_image_ref(surface->image);
+
+ fd = qemu_open_old(filename, O_WRONLY | O_CREAT | O_TRUNC | O_BINARY, 0666);
+ if (fd == -1) {
+ error_setg(errp, "failed to open file '%s': %s", filename,
+ strerror(errno));
+ return;
+ }
+
+ /*
+ * The image content could potentially be updated as the coroutine
+ * yields and releases the BQL. It could produce corrupted dump, but
+ * it should be otherwise safe.
+ */
+ if (!ppm_save(fd, image, errp)) {
+ qemu_unlink(filename);
+ }
}
void graphic_hw_text_update(QemuConsole *con, console_ch_t *chardata)
@@ -370,78 +456,32 @@ static void vga_bitblt(QemuConsole *con,
#include "vgafont.h"
-#ifndef CONFIG_CURSES
-enum color_names {
- COLOR_BLACK = 0,
- COLOR_RED = 1,
- COLOR_GREEN = 2,
- COLOR_YELLOW = 3,
- COLOR_BLUE = 4,
- COLOR_MAGENTA = 5,
- COLOR_CYAN = 6,
- COLOR_WHITE = 7
-};
-#endif
-
#define QEMU_RGB(r, g, b) \
{ .red = r << 8, .green = g << 8, .blue = b << 8, .alpha = 0xffff }
static const pixman_color_t color_table_rgb[2][8] = {
{ /* dark */
- QEMU_RGB(0x00, 0x00, 0x00), /* black */
- QEMU_RGB(0xaa, 0x00, 0x00), /* red */
- QEMU_RGB(0x00, 0xaa, 0x00), /* green */
- QEMU_RGB(0xaa, 0xaa, 0x00), /* yellow */
- QEMU_RGB(0x00, 0x00, 0xaa), /* blue */
- QEMU_RGB(0xaa, 0x00, 0xaa), /* magenta */
- QEMU_RGB(0x00, 0xaa, 0xaa), /* cyan */
- QEMU_RGB(0xaa, 0xaa, 0xaa), /* white */
+ [QEMU_COLOR_BLACK] = QEMU_RGB(0x00, 0x00, 0x00), /* black */
+ [QEMU_COLOR_BLUE] = QEMU_RGB(0x00, 0x00, 0xaa), /* blue */
+ [QEMU_COLOR_GREEN] = QEMU_RGB(0x00, 0xaa, 0x00), /* green */
+ [QEMU_COLOR_CYAN] = QEMU_RGB(0x00, 0xaa, 0xaa), /* cyan */
+ [QEMU_COLOR_RED] = QEMU_RGB(0xaa, 0x00, 0x00), /* red */
+ [QEMU_COLOR_MAGENTA] = QEMU_RGB(0xaa, 0x00, 0xaa), /* magenta */
+ [QEMU_COLOR_YELLOW] = QEMU_RGB(0xaa, 0xaa, 0x00), /* yellow */
+ [QEMU_COLOR_WHITE] = QEMU_RGB(0xaa, 0xaa, 0xaa), /* white */
},
{ /* bright */
- QEMU_RGB(0x00, 0x00, 0x00), /* black */
- QEMU_RGB(0xff, 0x00, 0x00), /* red */
- QEMU_RGB(0x00, 0xff, 0x00), /* green */
- QEMU_RGB(0xff, 0xff, 0x00), /* yellow */
- QEMU_RGB(0x00, 0x00, 0xff), /* blue */
- QEMU_RGB(0xff, 0x00, 0xff), /* magenta */
- QEMU_RGB(0x00, 0xff, 0xff), /* cyan */
- QEMU_RGB(0xff, 0xff, 0xff), /* white */
+ [QEMU_COLOR_BLACK] = QEMU_RGB(0x00, 0x00, 0x00), /* black */
+ [QEMU_COLOR_BLUE] = QEMU_RGB(0x00, 0x00, 0xff), /* blue */
+ [QEMU_COLOR_GREEN] = QEMU_RGB(0x00, 0xff, 0x00), /* green */
+ [QEMU_COLOR_CYAN] = QEMU_RGB(0x00, 0xff, 0xff), /* cyan */
+ [QEMU_COLOR_RED] = QEMU_RGB(0xff, 0x00, 0x00), /* red */
+ [QEMU_COLOR_MAGENTA] = QEMU_RGB(0xff, 0x00, 0xff), /* magenta */
+ [QEMU_COLOR_YELLOW] = QEMU_RGB(0xff, 0xff, 0x00), /* yellow */
+ [QEMU_COLOR_WHITE] = QEMU_RGB(0xff, 0xff, 0xff), /* white */
}
};
-#ifdef DEBUG_CONSOLE
-static void console_print_text_attributes(TextAttributes *t_attrib, char ch)
-{
- if (t_attrib->bold) {
- printf("b");
- } else {
- printf(" ");
- }
- if (t_attrib->uline) {
- printf("u");
- } else {
- printf(" ");
- }
- if (t_attrib->blink) {
- printf("l");
- } else {
- printf(" ");
- }
- if (t_attrib->invers) {
- printf("i");
- } else {
- printf(" ");
- }
- if (t_attrib->unvisible) {
- printf("n");
- } else {
- printf(" ");
- }
-
- printf(" fg: %d bg: %d ch:'%2X' '%c'\n", t_attrib->fgcol, t_attrib->bgcol, ch, ch);
-}
-#endif
-
static void vga_putcharxy(QemuConsole *s, int x, int y, int ch,
TextAttributes *t_attrib)
{
@@ -477,7 +517,7 @@ static void text_console_resize(QemuConsole *s)
if (s->width < w1)
w1 = s->width;
- cells = g_malloc(s->width * s->total_height * sizeof(TextCell));
+ cells = g_new(TextCell, s->width * s->total_height + 1);
for(y = 0; y < s->total_height; y++) {
c = &cells[y * s->width];
if (w1 > 0) {
@@ -506,6 +546,9 @@ static inline void text_update_xy(QemuConsole *s, int x, int y)
static void invalidate_xy(QemuConsole *s, int x, int y)
{
+ if (!qemu_console_is_visible(s)) {
+ return;
+ }
if (s->update_x0 > x * FONT_WIDTH)
s->update_x0 = x * FONT_WIDTH;
if (s->update_y0 > y * FONT_HEIGHT)
@@ -521,25 +564,23 @@ static void update_xy(QemuConsole *s, int x, int y)
TextCell *c;
int y1, y2;
- if (!qemu_console_is_visible(s)) {
- return;
- }
-
if (s->ds->have_text) {
text_update_xy(s, x, y);
}
- if (s->ds->have_gfx) {
- y1 = (s->y_base + y) % s->total_height;
- y2 = y1 - s->y_displayed;
- if (y2 < 0)
- y2 += s->total_height;
- if (y2 < s->height) {
- c = &s->cells[y1 * s->width + x];
- vga_putcharxy(s, x, y2, c->ch,
- &(c->t_attrib));
- invalidate_xy(s, x, y2);
+ y1 = (s->y_base + y) % s->total_height;
+ y2 = y1 - s->y_displayed;
+ if (y2 < 0) {
+ y2 += s->total_height;
+ }
+ if (y2 < s->height) {
+ if (x >= s->width) {
+ x = s->width - 1;
}
+ c = &s->cells[y1 * s->width + x];
+ vga_putcharxy(s, x, y2, c->ch,
+ &(c->t_attrib));
+ invalidate_xy(s, x, y2);
}
}
@@ -549,33 +590,28 @@ static void console_show_cursor(QemuConsole *s, int show)
int y, y1;
int x = s->x;
- if (!qemu_console_is_visible(s)) {
- return;
- }
-
if (s->ds->have_text) {
s->cursor_invalidate = 1;
}
- if (s->ds->have_gfx) {
- 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 + x];
- if (show && s->cursor_visible_phase) {
- TextAttributes t_attrib = s->t_attrib_default;
- t_attrib.invers = !(t_attrib.invers); /* invert fg and bg */
- vga_putcharxy(s, x, y, c->ch, &t_attrib);
- } else {
- vga_putcharxy(s, x, y, c->ch, &(c->t_attrib));
- }
- invalidate_xy(s, x, y);
+ 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 + x];
+ if (show && cursor_visible_phase) {
+ TextAttributes t_attrib = s->t_attrib_default;
+ t_attrib.invers = !(t_attrib.invers); /* invert fg and bg */
+ vga_putcharxy(s, x, y, c->ch, &t_attrib);
+ } else {
+ vga_putcharxy(s, x, y, c->ch, &(c->t_attrib));
}
+ invalidate_xy(s, x, y);
}
}
@@ -585,10 +621,6 @@ static void console_refresh(QemuConsole *s)
TextCell *c;
int x, y, y1;
- if (!qemu_console_is_visible(s)) {
- return;
- }
-
if (s->ds->have_text) {
s->text_x[0] = 0;
s->text_y[0] = 0;
@@ -597,25 +629,23 @@ static void console_refresh(QemuConsole *s)
s->cursor_invalidate = 1;
}
- if (s->ds->have_gfx) {
- vga_fill_rect(s, 0, 0, surface_width(surface), surface_height(surface),
- color_table_rgb[0][COLOR_BLACK]);
- y1 = s->y_displayed;
- for (y = 0; y < s->height; y++) {
- c = s->cells + y1 * s->width;
- for (x = 0; x < s->width; x++) {
- vga_putcharxy(s, x, y, c->ch,
- &(c->t_attrib));
- c++;
- }
- if (++y1 == s->total_height) {
- y1 = 0;
- }
+ vga_fill_rect(s, 0, 0, surface_width(surface), surface_height(surface),
+ color_table_rgb[0][QEMU_COLOR_BLACK]);
+ y1 = s->y_displayed;
+ for (y = 0; y < s->height; y++) {
+ c = s->cells + y1 * s->width;
+ for (x = 0; x < s->width; x++) {
+ vga_putcharxy(s, x, y, c->ch,
+ &(c->t_attrib));
+ c++;
+ }
+ if (++y1 == s->total_height) {
+ y1 = 0;
}
- console_show_cursor(s, 1);
- dpy_gfx_update(s, 0, 0,
- surface_width(surface), surface_height(surface));
}
+ console_show_cursor(s, 1);
+ dpy_gfx_update(s, 0, 0,
+ surface_width(surface), surface_height(surface));
}
static void console_scroll(QemuConsole *s, int ydelta)
@@ -671,7 +701,7 @@ static void console_put_lf(QemuConsole *s)
c->t_attrib = s->t_attrib_default;
c++;
}
- if (qemu_console_is_visible(s) && s->y_displayed == s->y_base) {
+ if (s->y_displayed == s->y_base) {
if (s->ds->have_text) {
s->text_x[0] = 0;
s->text_y[0] = 0;
@@ -679,18 +709,16 @@ static void console_put_lf(QemuConsole *s)
s->text_y[1] = s->height - 1;
}
- if (s->ds->have_gfx) {
- vga_bitblt(s, 0, FONT_HEIGHT, 0, 0,
- s->width * FONT_WIDTH,
- (s->height - 1) * FONT_HEIGHT);
- vga_fill_rect(s, 0, (s->height - 1) * FONT_HEIGHT,
- s->width * FONT_WIDTH, FONT_HEIGHT,
- color_table_rgb[0][s->t_attrib_default.bgcol]);
- s->update_x0 = 0;
- s->update_y0 = 0;
- s->update_x1 = s->width * FONT_WIDTH;
- s->update_y1 = s->height * FONT_HEIGHT;
- }
+ vga_bitblt(s, 0, FONT_HEIGHT, 0, 0,
+ s->width * FONT_WIDTH,
+ (s->height - 1) * FONT_HEIGHT);
+ vga_fill_rect(s, 0, (s->height - 1) * FONT_HEIGHT,
+ s->width * FONT_WIDTH, FONT_HEIGHT,
+ color_table_rgb[0][s->t_attrib_default.bgcol]);
+ s->update_x0 = 0;
+ s->update_y0 = 0;
+ s->update_x1 = s->width * FONT_WIDTH;
+ s->update_y1 = s->height * FONT_HEIGHT;
}
}
}
@@ -740,53 +768,53 @@ static void console_handle_escape(QemuConsole *s)
break;
/* set foreground color */
case 30:
- s->t_attrib.fgcol=COLOR_BLACK;
+ s->t_attrib.fgcol = QEMU_COLOR_BLACK;
break;
case 31:
- s->t_attrib.fgcol=COLOR_RED;
+ s->t_attrib.fgcol = QEMU_COLOR_RED;
break;
case 32:
- s->t_attrib.fgcol=COLOR_GREEN;
+ s->t_attrib.fgcol = QEMU_COLOR_GREEN;
break;
case 33:
- s->t_attrib.fgcol=COLOR_YELLOW;
+ s->t_attrib.fgcol = QEMU_COLOR_YELLOW;
break;
case 34:
- s->t_attrib.fgcol=COLOR_BLUE;
+ s->t_attrib.fgcol = QEMU_COLOR_BLUE;
break;
case 35:
- s->t_attrib.fgcol=COLOR_MAGENTA;
+ s->t_attrib.fgcol = QEMU_COLOR_MAGENTA;
break;
case 36:
- s->t_attrib.fgcol=COLOR_CYAN;
+ s->t_attrib.fgcol = QEMU_COLOR_CYAN;
break;
case 37:
- s->t_attrib.fgcol=COLOR_WHITE;
+ s->t_attrib.fgcol = QEMU_COLOR_WHITE;
break;
/* set background color */
case 40:
- s->t_attrib.bgcol=COLOR_BLACK;
+ s->t_attrib.bgcol = QEMU_COLOR_BLACK;
break;
case 41:
- s->t_attrib.bgcol=COLOR_RED;
+ s->t_attrib.bgcol = QEMU_COLOR_RED;
break;
case 42:
- s->t_attrib.bgcol=COLOR_GREEN;
+ s->t_attrib.bgcol = QEMU_COLOR_GREEN;
break;
case 43:
- s->t_attrib.bgcol=COLOR_YELLOW;
+ s->t_attrib.bgcol = QEMU_COLOR_YELLOW;
break;
case 44:
- s->t_attrib.bgcol=COLOR_BLUE;
+ s->t_attrib.bgcol = QEMU_COLOR_BLUE;
break;
case 45:
- s->t_attrib.bgcol=COLOR_MAGENTA;
+ s->t_attrib.bgcol = QEMU_COLOR_MAGENTA;
break;
case 46:
- s->t_attrib.bgcol=COLOR_CYAN;
+ s->t_attrib.bgcol = QEMU_COLOR_CYAN;
break;
case 47:
- s->t_attrib.bgcol=COLOR_WHITE;
+ s->t_attrib.bgcol = QEMU_COLOR_WHITE;
break;
}
}
@@ -795,12 +823,40 @@ static void console_handle_escape(QemuConsole *s)
static void console_clear_xy(QemuConsole *s, int x, int y)
{
int y1 = (s->y_base + y) % s->total_height;
+ if (x >= s->width) {
+ x = s->width - 1;
+ }
TextCell *c = &s->cells[y1 * s->width + x];
c->ch = ' ';
c->t_attrib = s->t_attrib_default;
update_xy(s, x, y);
}
+static void console_put_one(QemuConsole *s, int ch)
+{
+ TextCell *c;
+ int y1;
+ 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++;
+}
+
+static void console_respond_str(QemuConsole *s, const char *buf)
+{
+ while (*buf) {
+ console_put_one(s, *buf);
+ buf++;
+ }
+}
+
/* set cursor, checking bounds */
static void set_cursor(QemuConsole *s, int x, int y)
{
@@ -823,9 +879,9 @@ static void set_cursor(QemuConsole *s, int x, int y)
static void console_putchar(QemuConsole *s, int ch)
{
- TextCell *c;
- int y1, i;
+ int i;
int x, y;
+ char response[40];
switch(s->state) {
case TTY_STATE_NORM:
@@ -861,17 +917,7 @@ static void console_putchar(QemuConsole *s, int ch)
s->state = TTY_STATE_ESC;
break;
default:
- 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++;
+ console_put_one(s, ch);
break;
}
break;
@@ -897,12 +943,11 @@ static void console_putchar(QemuConsole *s, int ch)
} else {
if (s->nb_esc_params < MAX_ESC_PARAMS)
s->nb_esc_params++;
- if (ch == ';')
+ if (ch == ';' || 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
+ }
+ trace_console_putchar_csi(s->esc_params[0], s->esc_params[1],
+ ch, s->nb_esc_params);
s->state = TTY_STATE_NORM;
switch(ch) {
case 'A':
@@ -986,7 +1031,7 @@ static void console_putchar(QemuConsole *s, int ch)
break;
case 1:
/* clear from beginning of line */
- for (x = 0; x <= s->x; x++) {
+ for (x = 0; x <= s->x && x < s->width; x++) {
console_clear_xy(s, x, s->y);
}
break;
@@ -1002,8 +1047,19 @@ static void console_putchar(QemuConsole *s, int ch)
console_handle_escape(s);
break;
case 'n':
- /* report cursor position */
- /* TODO: send ESC[row;colR */
+ switch (s->esc_params[0]) {
+ case 5:
+ /* report console status (always succeed)*/
+ console_respond_str(s, "\033[0n");
+ break;
+ case 6:
+ /* report cursor position */
+ sprintf(response, "\033[%d;%dR",
+ (s->y_base + s->y) % s->total_height + 1,
+ s->x + 1);
+ console_respond_str(s, response);
+ break;
+ }
break;
case 's':
/* save cursor position */
@@ -1016,9 +1072,7 @@ static void console_putchar(QemuConsole *s, int ch)
s->y = s->y_saved;
break;
default:
-#ifdef DEBUG_CONSOLE
- fprintf(stderr, "unhandled escape character '%c'\n", ch);
-#endif
+ trace_console_putchar_unhandled(ch);
break;
}
break;
@@ -1031,17 +1085,11 @@ void console_select(unsigned int index)
DisplayChangeListener *dcl;
QemuConsole *s;
- if (index >= MAX_CONSOLES)
- return;
-
trace_console_select(index);
s = qemu_console_lookup_by_index(index);
if (s) {
DisplayState *ds = s->ds;
- if (active_console && active_console->cursor_timer) {
- qemu_del_timer(active_console->cursor_timer);
- }
active_console = s;
if (ds->have_gfx) {
QLIST_FOREACH(dcl, &ds->listeners, next) {
@@ -1052,24 +1100,38 @@ void console_select(unsigned int index)
dcl->ops->dpy_gfx_switch(dcl, s->surface);
}
}
- dpy_gfx_update(s, 0, 0, surface_width(s->surface),
- surface_height(s->surface));
+ if (s->surface) {
+ dpy_gfx_update(s, 0, 0, surface_width(s->surface),
+ surface_height(s->surface));
+ }
}
if (ds->have_text) {
dpy_text_resize(s, s->width, s->height);
}
- if (s->cursor_timer) {
- qemu_mod_timer(s->cursor_timer,
- qemu_get_clock_ms(rt_clock) + CONSOLE_CURSOR_PERIOD / 2);
- }
+ text_console_update_cursor(NULL);
}
}
-static int console_puts(CharDriverState *chr, const uint8_t *buf, int len)
+struct VCChardev {
+ Chardev parent;
+ QemuConsole *console;
+};
+typedef struct VCChardev VCChardev;
+
+#define TYPE_CHARDEV_VC "chardev-vc"
+DECLARE_INSTANCE_CHECKER(VCChardev, VC_CHARDEV,
+ TYPE_CHARDEV_VC)
+
+static int vc_chr_write(Chardev *chr, const uint8_t *buf, int len)
{
- QemuConsole *s = chr->opaque;
+ VCChardev *drv = VC_CHARDEV(chr);
+ QemuConsole *s = drv->console;
int i;
+ if (!s->ds) {
+ return 0;
+ }
+
s->update_x0 = s->width * FONT_WIDTH;
s->update_y0 = s->height * FONT_HEIGHT;
s->update_x1 = 0;
@@ -1105,18 +1167,17 @@ 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_ms(rt_clock) + 1);
+ timer_mod(s->kbd_timer, qemu_clock_get_ms(QEMU_CLOCK_REALTIME) + 1);
}
}
/* called when an ascii key is pressed */
-void kbd_put_keysym(int keysym)
+void kbd_put_keysym_console(QemuConsole *s, int keysym)
{
- QemuConsole *s;
uint8_t buf[16], *q;
+ CharBackend *be;
int c;
- s = active_console;
if (!s || (s->console_type == GRAPHIC_CONSOLE))
return;
@@ -1149,15 +1210,16 @@ void kbd_put_keysym(int keysym)
*q++ = '[';
*q++ = keysym & 0xff;
} else if (s->echo && (keysym == '\r' || keysym == '\n')) {
- console_puts(s->chr, (const uint8_t *) "\r", 1);
+ vc_chr_write(s->chr, (const uint8_t *) "\r", 1);
*q++ = '\n';
} else {
*q++ = keysym;
}
if (s->echo) {
- console_puts(s->chr, buf, q - buf);
+ vc_chr_write(s->chr, buf, q - buf);
}
- if (s->chr->chr_read) {
+ be = s->chr->be;
+ if (be && be->chr_read) {
qemu_fifo_write(&s->out_fifo, buf, q - buf);
kbd_send_chars(s);
}
@@ -1165,6 +1227,56 @@ void kbd_put_keysym(int keysym)
}
}
+static const int qcode_to_keysym[Q_KEY_CODE__MAX] = {
+ [Q_KEY_CODE_UP] = QEMU_KEY_UP,
+ [Q_KEY_CODE_DOWN] = QEMU_KEY_DOWN,
+ [Q_KEY_CODE_RIGHT] = QEMU_KEY_RIGHT,
+ [Q_KEY_CODE_LEFT] = QEMU_KEY_LEFT,
+ [Q_KEY_CODE_HOME] = QEMU_KEY_HOME,
+ [Q_KEY_CODE_END] = QEMU_KEY_END,
+ [Q_KEY_CODE_PGUP] = QEMU_KEY_PAGEUP,
+ [Q_KEY_CODE_PGDN] = QEMU_KEY_PAGEDOWN,
+ [Q_KEY_CODE_DELETE] = QEMU_KEY_DELETE,
+ [Q_KEY_CODE_BACKSPACE] = QEMU_KEY_BACKSPACE,
+};
+
+static const int ctrl_qcode_to_keysym[Q_KEY_CODE__MAX] = {
+ [Q_KEY_CODE_UP] = QEMU_KEY_CTRL_UP,
+ [Q_KEY_CODE_DOWN] = QEMU_KEY_CTRL_DOWN,
+ [Q_KEY_CODE_RIGHT] = QEMU_KEY_CTRL_RIGHT,
+ [Q_KEY_CODE_LEFT] = QEMU_KEY_CTRL_LEFT,
+ [Q_KEY_CODE_HOME] = QEMU_KEY_CTRL_HOME,
+ [Q_KEY_CODE_END] = QEMU_KEY_CTRL_END,
+ [Q_KEY_CODE_PGUP] = QEMU_KEY_CTRL_PAGEUP,
+ [Q_KEY_CODE_PGDN] = QEMU_KEY_CTRL_PAGEDOWN,
+};
+
+bool kbd_put_qcode_console(QemuConsole *s, int qcode, bool ctrl)
+{
+ int keysym;
+
+ keysym = ctrl ? ctrl_qcode_to_keysym[qcode] : qcode_to_keysym[qcode];
+ if (keysym == 0) {
+ return false;
+ }
+ kbd_put_keysym_console(s, keysym);
+ return true;
+}
+
+void kbd_put_string_console(QemuConsole *s, const char *str, int len)
+{
+ int i;
+
+ for (i = 0; i < len && str[i]; i++) {
+ kbd_put_keysym_console(s, str[i]);
+ }
+}
+
+void kbd_put_keysym(int keysym)
+{
+ kbd_put_keysym_console(active_console, keysym);
+}
+
static void text_console_invalidate(void *opaque)
{
QemuConsole *s = (QemuConsole *) opaque;
@@ -1184,11 +1296,13 @@ static void text_console_update(void *opaque, console_ch_t *chardata)
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));
+ for (j = 0; j < s->width; j++, src++) {
+ console_write_ch(chardata ++,
+ ATTR2CHTYPE(s->cells[src].ch,
+ s->cells[src].t_attrib.fgcol,
+ s->cells[src].t_attrib.bgcol,
+ s->cells[src].t_attrib.bold));
+ }
dpy_text_update(s, 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;
@@ -1202,20 +1316,23 @@ static void text_console_update(void *opaque, console_ch_t *chardata)
}
}
-static QemuConsole *new_console(DisplayState *ds, console_type_t console_type)
+static QemuConsole *new_console(DisplayState *ds, console_type_t console_type,
+ uint32_t head)
{
- Error *local_err = NULL;
Object *obj;
QemuConsole *s;
int i;
- if (nb_consoles >= MAX_CONSOLES)
- return NULL;
-
obj = object_new(TYPE_QEMU_CONSOLE);
s = QEMU_CONSOLE(obj);
+ qemu_co_queue_init(&s->dump_queue);
+ s->head = head;
object_property_add_link(obj, "device", TYPE_DEVICE,
- (Object **)&s->device, &local_err);
+ (Object **)&s->device,
+ object_property_allow_set_link,
+ OBJ_PROP_LINK_STRONG);
+ object_property_add_uint32_ptr(obj, "head", &s->head,
+ OBJ_PROP_FLAG_READ);
if (!active_console || ((active_console->console_type != GRAPHIC_CONSOLE) &&
(console_type == GRAPHIC_CONSOLE))) {
@@ -1223,96 +1340,106 @@ static QemuConsole *new_console(DisplayState *ds, console_type_t console_type)
}
s->ds = ds;
s->console_type = console_type;
- if (console_type != GRAPHIC_CONSOLE) {
- s->index = nb_consoles;
- consoles[nb_consoles++] = s;
+ s->window_id = -1;
+
+ if (QTAILQ_EMPTY(&consoles)) {
+ s->index = 0;
+ QTAILQ_INSERT_TAIL(&consoles, s, next);
+ } else if (console_type != GRAPHIC_CONSOLE || qdev_hotplug) {
+ QemuConsole *last = QTAILQ_LAST(&consoles);
+ s->index = last->index + 1;
+ QTAILQ_INSERT_TAIL(&consoles, s, next);
} else {
- /* HACK: Put graphical consoles before text consoles. */
- for (i = nb_consoles; i > 0; i--) {
- if (consoles[i - 1]->console_type == GRAPHIC_CONSOLE)
- break;
- consoles[i] = consoles[i - 1];
- consoles[i]->index = i;
+ /*
+ * HACK: Put graphical consoles before text consoles.
+ *
+ * Only do that for coldplugged devices. After initial device
+ * initialization we will not renumber the consoles any more.
+ */
+ QemuConsole *c = QTAILQ_FIRST(&consoles);
+
+ while (QTAILQ_NEXT(c, next) != NULL &&
+ c->console_type == GRAPHIC_CONSOLE) {
+ c = QTAILQ_NEXT(c, next);
+ }
+ if (c->console_type == GRAPHIC_CONSOLE) {
+ /* have no text consoles */
+ s->index = c->index + 1;
+ QTAILQ_INSERT_AFTER(&consoles, c, s, next);
+ } else {
+ s->index = c->index;
+ QTAILQ_INSERT_BEFORE(c, s, next);
+ /* renumber text consoles */
+ for (i = s->index + 1; c != NULL; c = QTAILQ_NEXT(c, next), i++) {
+ c->index = i;
+ }
}
- s->index = i;
- consoles[i] = s;
- nb_consoles++;
}
return s;
}
-static void qemu_alloc_display(DisplaySurface *surface, int width, int height,
- int linesize, PixelFormat pf, int newflags)
+static void qemu_alloc_display(DisplaySurface *surface, int width, int height)
{
- surface->pf = pf;
-
qemu_pixman_image_unref(surface->image);
surface->image = NULL;
- surface->format = qemu_pixman_get_format(&pf);
- assert(surface->format != 0);
+ surface->format = PIXMAN_x8r8g8b8;
surface->image = pixman_image_create_bits(surface->format,
width, height,
- NULL, linesize);
+ NULL, width * 4);
assert(surface->image != NULL);
- surface->flags = newflags | QEMU_ALLOCATED_FLAG;
-#ifdef HOST_WORDS_BIGENDIAN
- surface->flags |= QEMU_BIG_ENDIAN_FLAG;
-#endif
+ surface->flags = QEMU_ALLOCATED_FLAG;
}
DisplaySurface *qemu_create_displaysurface(int width, int height)
{
DisplaySurface *surface = g_new0(DisplaySurface, 1);
- int linesize = width * 4;
trace_displaysurface_create(surface, width, height);
- qemu_alloc_display(surface, width, height, linesize,
- qemu_default_pixelformat(32), 0);
+ qemu_alloc_display(surface, width, height);
return surface;
}
-DisplaySurface *qemu_create_displaysurface_from(int width, int height, int bpp,
- int linesize, uint8_t *data,
- bool byteswap)
+DisplaySurface *qemu_create_displaysurface_from(int width, int height,
+ pixman_format_code_t format,
+ int linesize, uint8_t *data)
{
DisplaySurface *surface = g_new0(DisplaySurface, 1);
- trace_displaysurface_create_from(surface, width, height, bpp, byteswap);
- if (byteswap) {
- surface->pf = qemu_different_endianness_pixelformat(bpp);
- } else {
- surface->pf = qemu_default_pixelformat(bpp);
- }
-
- surface->format = qemu_pixman_get_format(&surface->pf);
- assert(surface->format != 0);
+ trace_displaysurface_create_from(surface, width, height, format);
+ surface->format = format;
surface->image = pixman_image_create_bits(surface->format,
width, height,
(void *)data, linesize);
assert(surface->image != NULL);
-#ifdef HOST_WORDS_BIGENDIAN
- surface->flags = QEMU_BIG_ENDIAN_FLAG;
-#endif
+ return surface;
+}
+
+DisplaySurface *qemu_create_displaysurface_pixman(pixman_image_t *image)
+{
+ DisplaySurface *surface = g_new0(DisplaySurface, 1);
+
+ trace_displaysurface_create_pixman(surface);
+ surface->format = pixman_image_get_format(image);
+ surface->image = pixman_image_ref(image);
return surface;
}
-static DisplaySurface *qemu_create_dummy_surface(void)
+DisplaySurface *qemu_create_message_surface(int w, int h,
+ const char *msg)
{
- static const char msg[] =
- "This VM has no graphic display device.";
- DisplaySurface *surface = qemu_create_displaysurface(640, 480);
- pixman_color_t bg = color_table_rgb[0][COLOR_BLACK];
- pixman_color_t fg = color_table_rgb[0][COLOR_WHITE];
+ DisplaySurface *surface = qemu_create_displaysurface(w, h);
+ pixman_color_t bg = color_table_rgb[0][QEMU_COLOR_BLACK];
+ pixman_color_t fg = color_table_rgb[0][QEMU_COLOR_WHITE];
pixman_image_t *glyph;
int len, x, y, i;
len = strlen(msg);
- x = (640/FONT_WIDTH - len) / 2;
- y = (480/FONT_HEIGHT - 1) / 2;
+ x = (w / FONT_WIDTH - len) / 2;
+ y = (h / FONT_HEIGHT - 1) / 2;
for (i = 0; i < len; i++) {
glyph = qemu_pixman_glyph_from_vgafont(FONT_HEIGHT, vgafont16, msg[i]);
qemu_pixman_glyph_render(glyph, surface->image, &fg, &bg,
@@ -1332,11 +1459,36 @@ void qemu_free_displaysurface(DisplaySurface *surface)
g_free(surface);
}
+bool console_has_gl(QemuConsole *con)
+{
+ return con->gl != NULL;
+}
+
+bool console_has_gl_dmabuf(QemuConsole *con)
+{
+ return con->gl != NULL && con->gl->ops->dpy_gl_scanout_dmabuf != NULL;
+}
+
void register_displaychangelistener(DisplayChangeListener *dcl)
{
+ static const char nodev[] =
+ "This VM has no graphic display device.";
static DisplaySurface *dummy;
QemuConsole *con;
+ assert(!dcl->ds);
+
+ if (dcl->ops->dpy_gl_ctx_create) {
+ /* display has opengl support */
+ assert(dcl->con);
+ if (dcl->con->gl) {
+ fprintf(stderr, "can't register two opengl displays (%s, %s)\n",
+ dcl->ops->dpy_name, dcl->con->gl->ops->dpy_name);
+ exit(1);
+ }
+ dcl->con->gl = dcl;
+ }
+
trace_displaychangelistener_register(dcl, dcl->ops->dpy_name);
dcl->ds = get_alloc_displaystate();
QLIST_INSERT_HEAD(&dcl->ds->listeners, dcl, next);
@@ -1352,11 +1504,12 @@ void register_displaychangelistener(DisplayChangeListener *dcl)
dcl->ops->dpy_gfx_switch(dcl, con->surface);
} else {
if (!dummy) {
- dummy = qemu_create_dummy_surface();
+ dummy = qemu_create_message_surface(640, 480, nodev);
}
dcl->ops->dpy_gfx_switch(dcl, dummy);
}
}
+ text_console_update_cursor(NULL);
}
void update_displaychangelistener(DisplayChangeListener *dcl,
@@ -1366,7 +1519,7 @@ void update_displaychangelistener(DisplayChangeListener *dcl,
dcl->update_interval = interval;
if (!ds->refreshing && ds->update_interval > interval) {
- qemu_mod_timer(ds->gui_timer, ds->last_update + interval);
+ timer_mod(ds->gui_timer, ds->last_update + interval);
}
}
@@ -1378,16 +1531,62 @@ void unregister_displaychangelistener(DisplayChangeListener *dcl)
dcl->con->dcls--;
}
QLIST_REMOVE(dcl, next);
+ dcl->ds = NULL;
gui_setup_refresh(ds);
}
+static void dpy_set_ui_info_timer(void *opaque)
+{
+ QemuConsole *con = opaque;
+
+ con->hw_ops->ui_info(con->hw, con->head, &con->ui_info);
+}
+
+bool dpy_ui_info_supported(QemuConsole *con)
+{
+ return con->hw_ops->ui_info != NULL;
+}
+
+const QemuUIInfo *dpy_get_ui_info(const QemuConsole *con)
+{
+ assert(con != NULL);
+
+ return &con->ui_info;
+}
+
+int dpy_set_ui_info(QemuConsole *con, QemuUIInfo *info)
+{
+ assert(con != NULL);
+
+ if (!dpy_ui_info_supported(con)) {
+ return -1;
+ }
+ if (memcmp(&con->ui_info, info, sizeof(con->ui_info)) == 0) {
+ /* nothing changed -- ignore */
+ return 0;
+ }
+
+ /*
+ * Typically we get a flood of these as the user resizes the window.
+ * Wait until the dust has settled (one second without updates), then
+ * go notify the guest.
+ */
+ con->ui_info = *info;
+ timer_mod(con->ui_timer, qemu_clock_get_ms(QEMU_CLOCK_REALTIME) + 1000);
+ return 0;
+}
+
void dpy_gfx_update(QemuConsole *con, int x, int y, int w, int h)
{
DisplayState *s = con->ds;
DisplayChangeListener *dcl;
- int width = surface_width(con->surface);
- int height = surface_height(con->surface);
+ int width = w;
+ int height = h;
+ if (con->surface) {
+ width = surface_width(con->surface);
+ height = surface_height(con->surface);
+ }
x = MAX(x, 0);
y = MAX(y, 0);
x = MIN(x, width);
@@ -1408,6 +1607,16 @@ void dpy_gfx_update(QemuConsole *con, int x, int y, int w, int h)
}
}
+void dpy_gfx_update_full(QemuConsole *con)
+{
+ if (!con->surface) {
+ return;
+ }
+ dpy_gfx_update(con, 0, 0,
+ surface_width(con->surface),
+ surface_height(con->surface));
+}
+
void dpy_gfx_replace_surface(QemuConsole *con,
DisplaySurface *surface)
{
@@ -1415,6 +1624,8 @@ void dpy_gfx_replace_surface(QemuConsole *con,
DisplaySurface *old_surface = con->surface;
DisplayChangeListener *dcl;
+ assert(old_surface != surface || surface == NULL);
+
con->surface = surface;
QLIST_FOREACH(dcl, &s->listeners, next) {
if (con != (dcl->con ? dcl->con : active_console)) {
@@ -1427,34 +1638,38 @@ void dpy_gfx_replace_surface(QemuConsole *con,
qemu_free_displaysurface(old_surface);
}
-void dpy_refresh(DisplayState *s)
+bool dpy_gfx_check_format(QemuConsole *con,
+ pixman_format_code_t format)
{
DisplayChangeListener *dcl;
+ DisplayState *s = con->ds;
QLIST_FOREACH(dcl, &s->listeners, next) {
- if (dcl->ops->dpy_refresh) {
- dcl->ops->dpy_refresh(dcl);
+ if (dcl->con && dcl->con != con) {
+ /* dcl bound to another console -> skip */
+ continue;
+ }
+ if (dcl->ops->dpy_gfx_check_format) {
+ if (!dcl->ops->dpy_gfx_check_format(dcl, format)) {
+ return false;
+ }
+ } else {
+ /* default is to whitelist native 32 bpp only */
+ if (format != qemu_default_pixman_format(32, true)) {
+ return false;
+ }
}
}
+ return true;
}
-void dpy_gfx_copy(QemuConsole *con, int src_x, int src_y,
- int dst_x, int dst_y, int w, int h)
+static void dpy_refresh(DisplayState *s)
{
- DisplayState *s = con->ds;
DisplayChangeListener *dcl;
- if (!qemu_console_is_visible(con)) {
- return;
- }
QLIST_FOREACH(dcl, &s->listeners, next) {
- if (con != (dcl->con ? dcl->con : active_console)) {
- continue;
- }
- if (dcl->ops->dpy_gfx_copy) {
- dcl->ops->dpy_gfx_copy(dcl, src_x, src_y, dst_x, dst_y, w, h);
- } else { /* TODO */
- dcl->ops->dpy_gfx_update(dcl, dst_x, dst_y, w, h);
+ if (dcl->ops->dpy_refresh) {
+ dcl->ops->dpy_refresh(dcl);
}
}
}
@@ -1498,7 +1713,7 @@ void dpy_text_update(QemuConsole *con, int x, int y, int w, int h)
void dpy_text_resize(QemuConsole *con, int w, int h)
{
DisplayState *s = con->ds;
- struct DisplayChangeListener *dcl;
+ DisplayChangeListener *dcl;
if (!qemu_console_is_visible(con)) {
return;
@@ -1562,6 +1777,102 @@ bool dpy_cursor_define_supported(QemuConsole *con)
return false;
}
+QEMUGLContext dpy_gl_ctx_create(QemuConsole *con,
+ struct QEMUGLParams *qparams)
+{
+ assert(con->gl);
+ return con->gl->ops->dpy_gl_ctx_create(con->gl, qparams);
+}
+
+void dpy_gl_ctx_destroy(QemuConsole *con, QEMUGLContext ctx)
+{
+ assert(con->gl);
+ con->gl->ops->dpy_gl_ctx_destroy(con->gl, ctx);
+}
+
+int dpy_gl_ctx_make_current(QemuConsole *con, QEMUGLContext ctx)
+{
+ assert(con->gl);
+ return con->gl->ops->dpy_gl_ctx_make_current(con->gl, ctx);
+}
+
+QEMUGLContext dpy_gl_ctx_get_current(QemuConsole *con)
+{
+ assert(con->gl);
+ return con->gl->ops->dpy_gl_ctx_get_current(con->gl);
+}
+
+void dpy_gl_scanout_disable(QemuConsole *con)
+{
+ assert(con->gl);
+ if (con->gl->ops->dpy_gl_scanout_disable) {
+ con->gl->ops->dpy_gl_scanout_disable(con->gl);
+ } else {
+ con->gl->ops->dpy_gl_scanout_texture(con->gl, 0, false, 0, 0,
+ 0, 0, 0, 0);
+ }
+}
+
+void dpy_gl_scanout_texture(QemuConsole *con,
+ uint32_t backing_id,
+ bool backing_y_0_top,
+ uint32_t backing_width,
+ uint32_t backing_height,
+ uint32_t x, uint32_t y,
+ uint32_t width, uint32_t height)
+{
+ assert(con->gl);
+ con->gl->ops->dpy_gl_scanout_texture(con->gl, backing_id,
+ backing_y_0_top,
+ backing_width, backing_height,
+ x, y, width, height);
+}
+
+void dpy_gl_scanout_dmabuf(QemuConsole *con,
+ QemuDmaBuf *dmabuf)
+{
+ assert(con->gl);
+ con->gl->ops->dpy_gl_scanout_dmabuf(con->gl, dmabuf);
+}
+
+void dpy_gl_cursor_dmabuf(QemuConsole *con, QemuDmaBuf *dmabuf,
+ bool have_hot, uint32_t hot_x, uint32_t hot_y)
+{
+ assert(con->gl);
+
+ if (con->gl->ops->dpy_gl_cursor_dmabuf) {
+ con->gl->ops->dpy_gl_cursor_dmabuf(con->gl, dmabuf,
+ have_hot, hot_x, hot_y);
+ }
+}
+
+void dpy_gl_cursor_position(QemuConsole *con,
+ uint32_t pos_x, uint32_t pos_y)
+{
+ assert(con->gl);
+
+ if (con->gl->ops->dpy_gl_cursor_position) {
+ con->gl->ops->dpy_gl_cursor_position(con->gl, pos_x, pos_y);
+ }
+}
+
+void dpy_gl_release_dmabuf(QemuConsole *con,
+ QemuDmaBuf *dmabuf)
+{
+ assert(con->gl);
+
+ if (con->gl->ops->dpy_gl_release_dmabuf) {
+ con->gl->ops->dpy_gl_release_dmabuf(con->gl, dmabuf);
+ }
+}
+
+void dpy_gl_update(QemuConsole *con,
+ uint32_t x, uint32_t y, uint32_t w, uint32_t h)
+{
+ assert(con->gl);
+ con->gl->ops->dpy_gl_update(con->gl, x, y, w, h);
+}
+
/***********************************************************/
/* register display */
@@ -1570,6 +1881,8 @@ static DisplayState *get_alloc_displaystate(void)
{
if (!display_state) {
display_state = g_new0(DisplayState, 1);
+ cursor_timer = timer_new_ms(QEMU_CLOCK_REALTIME,
+ text_console_update_cursor, NULL);
}
return display_state;
}
@@ -1580,79 +1893,173 @@ static DisplayState *get_alloc_displaystate(void)
*/
DisplayState *init_displaystate(void)
{
- Error *local_err = NULL;
gchar *name;
- int i;
-
- if (!display_state) {
- display_state = g_new0(DisplayState, 1);
- }
+ QemuConsole *con;
- for (i = 0; i < nb_consoles; i++) {
- if (consoles[i]->console_type != GRAPHIC_CONSOLE &&
- consoles[i]->ds == NULL) {
- text_console_do_init(consoles[i]->chr, display_state);
+ get_alloc_displaystate();
+ QTAILQ_FOREACH(con, &consoles, next) {
+ if (con->console_type != GRAPHIC_CONSOLE &&
+ con->ds == NULL) {
+ text_console_do_init(con->chr, display_state);
}
/* Hook up into the qom tree here (not in new_console()), once
* all QemuConsoles are created and the order / numbering
* doesn't change any more */
- name = g_strdup_printf("console[%d]", i);
+ name = g_strdup_printf("console[%d]", con->index);
object_property_add_child(container_get(object_get_root(), "/backend"),
- name, OBJECT(consoles[i]), &local_err);
+ name, OBJECT(con));
g_free(name);
}
return display_state;
}
-QemuConsole *graphic_console_init(DeviceState *dev,
+void graphic_console_set_hwops(QemuConsole *con,
+ const GraphicHwOps *hw_ops,
+ void *opaque)
+{
+ con->hw_ops = hw_ops;
+ con->hw = opaque;
+}
+
+QemuConsole *graphic_console_init(DeviceState *dev, uint32_t head,
const GraphicHwOps *hw_ops,
void *opaque)
{
- Error *local_err = NULL;
+ static const char noinit[] =
+ "Guest has not initialized the display (yet).";
int width = 640;
int height = 480;
QemuConsole *s;
DisplayState *ds;
+ DisplaySurface *surface;
ds = get_alloc_displaystate();
- trace_console_gfx_new();
- s = new_console(ds, GRAPHIC_CONSOLE);
- s->hw_ops = hw_ops;
- s->hw = opaque;
+ s = qemu_console_lookup_unused();
+ if (s) {
+ trace_console_gfx_reuse(s->index);
+ if (s->surface) {
+ width = surface_width(s->surface);
+ height = surface_height(s->surface);
+ }
+ } else {
+ trace_console_gfx_new();
+ s = new_console(ds, GRAPHIC_CONSOLE, head);
+ s->ui_timer = timer_new_ms(QEMU_CLOCK_REALTIME,
+ dpy_set_ui_info_timer, s);
+ }
+ graphic_console_set_hwops(s, hw_ops, opaque);
if (dev) {
- object_property_set_link(OBJECT(s), OBJECT(dev),
- "device", &local_err);
+ object_property_set_link(OBJECT(s), "device", OBJECT(dev),
+ &error_abort);
}
- s->surface = qemu_create_displaysurface(width, height);
+ surface = qemu_create_message_surface(width, height, noinit);
+ dpy_gfx_replace_surface(s, surface);
return s;
}
+static const GraphicHwOps unused_ops = {
+ /* no callbacks */
+};
+
+void graphic_console_close(QemuConsole *con)
+{
+ static const char unplugged[] =
+ "Guest display has been unplugged";
+ DisplaySurface *surface;
+ int width = 640;
+ int height = 480;
+
+ if (con->surface) {
+ width = surface_width(con->surface);
+ height = surface_height(con->surface);
+ }
+
+ trace_console_gfx_close(con->index);
+ object_property_set_link(OBJECT(con), "device", NULL, &error_abort);
+ graphic_console_set_hwops(con, &unused_ops, NULL);
+
+ if (con->gl) {
+ dpy_gl_scanout_disable(con);
+ }
+ surface = qemu_create_message_surface(width, height, unplugged);
+ dpy_gfx_replace_surface(con, surface);
+}
+
QemuConsole *qemu_console_lookup_by_index(unsigned int index)
{
- if (index >= MAX_CONSOLES) {
+ QemuConsole *con;
+
+ QTAILQ_FOREACH(con, &consoles, next) {
+ if (con->index == index) {
+ return con;
+ }
+ }
+ return NULL;
+}
+
+QemuConsole *qemu_console_lookup_by_device(DeviceState *dev, uint32_t head)
+{
+ QemuConsole *con;
+ Object *obj;
+ uint32_t h;
+
+ QTAILQ_FOREACH(con, &consoles, next) {
+ obj = object_property_get_link(OBJECT(con),
+ "device", &error_abort);
+ if (DEVICE(obj) != dev) {
+ continue;
+ }
+ h = object_property_get_uint(OBJECT(con),
+ "head", &error_abort);
+ if (h != head) {
+ continue;
+ }
+ return con;
+ }
+ return NULL;
+}
+
+QemuConsole *qemu_console_lookup_by_device_name(const char *device_id,
+ uint32_t head, Error **errp)
+{
+ DeviceState *dev;
+ QemuConsole *con;
+
+ dev = qdev_find_recursive(sysbus_get_default(), device_id);
+ if (dev == NULL) {
+ error_set(errp, ERROR_CLASS_DEVICE_NOT_FOUND,
+ "Device '%s' not found", device_id);
+ return NULL;
+ }
+
+ con = qemu_console_lookup_by_device(dev, head);
+ if (con == NULL) {
+ error_setg(errp, "Device %s (head %d) is not bound to a QemuConsole",
+ device_id, head);
return NULL;
}
- return consoles[index];
+
+ return con;
}
-QemuConsole *qemu_console_lookup_by_device(DeviceState *dev)
+QemuConsole *qemu_console_lookup_unused(void)
{
- Error *local_err = NULL;
+ QemuConsole *con;
Object *obj;
- int i;
- for (i = 0; i < nb_consoles; i++) {
- if (!consoles[i]) {
+ QTAILQ_FOREACH(con, &consoles, next) {
+ if (con->hw_ops != &unused_ops) {
continue;
}
- obj = object_property_get_link(OBJECT(consoles[i]),
- "device", &local_err);
- if (DEVICE(obj) == dev) {
- return consoles[i];
+ obj = object_property_get_link(OBJECT(con),
+ "device", &error_abort);
+ if (obj != NULL) {
+ continue;
}
+ return con;
}
return NULL;
}
@@ -1678,21 +2085,98 @@ bool qemu_console_is_fixedsize(QemuConsole *con)
return con && (con->console_type != TEXT_CONSOLE);
}
-static void text_console_set_echo(CharDriverState *chr, bool echo)
+bool qemu_console_is_gl_blocked(QemuConsole *con)
+{
+ assert(con != NULL);
+ return con->gl_block;
+}
+
+char *qemu_console_get_label(QemuConsole *con)
+{
+ if (con->console_type == GRAPHIC_CONSOLE) {
+ if (con->device) {
+ return g_strdup(object_get_typename(con->device));
+ }
+ return g_strdup("VGA");
+ } else {
+ if (con->chr && con->chr->label) {
+ return g_strdup(con->chr->label);
+ }
+ return g_strdup_printf("vc%d", con->index);
+ }
+}
+
+int qemu_console_get_index(QemuConsole *con)
+{
+ if (con == NULL) {
+ con = active_console;
+ }
+ return con ? con->index : -1;
+}
+
+uint32_t qemu_console_get_head(QemuConsole *con)
+{
+ if (con == NULL) {
+ con = active_console;
+ }
+ return con ? con->head : -1;
+}
+
+QemuUIInfo *qemu_console_get_ui_info(QemuConsole *con)
+{
+ assert(con != NULL);
+ return &con->ui_info;
+}
+
+int qemu_console_get_width(QemuConsole *con, int fallback)
+{
+ if (con == NULL) {
+ con = active_console;
+ }
+ return con ? surface_width(con->surface) : fallback;
+}
+
+int qemu_console_get_height(QemuConsole *con, int fallback)
+{
+ if (con == NULL) {
+ con = active_console;
+ }
+ return con ? surface_height(con->surface) : fallback;
+}
+
+static void vc_chr_set_echo(Chardev *chr, bool echo)
{
- QemuConsole *s = chr->opaque;
+ VCChardev *drv = VC_CHARDEV(chr);
+ QemuConsole *s = drv->console;
s->echo = echo;
}
+static void text_console_update_cursor_timer(void)
+{
+ timer_mod(cursor_timer, qemu_clock_get_ms(QEMU_CLOCK_REALTIME)
+ + CONSOLE_CURSOR_PERIOD / 2);
+}
+
static void text_console_update_cursor(void *opaque)
{
- QemuConsole *s = opaque;
+ QemuConsole *s;
+ int count = 0;
+
+ cursor_visible_phase = !cursor_visible_phase;
+
+ QTAILQ_FOREACH(s, &consoles, next) {
+ if (qemu_console_is_graphic(s) ||
+ !qemu_console_is_visible(s)) {
+ continue;
+ }
+ count++;
+ graphic_hw_invalidate(s);
+ }
- s->cursor_visible_phase = !s->cursor_visible_phase;
- graphic_hw_invalidate(s);
- qemu_mod_timer(s->cursor_timer,
- qemu_get_clock_ms(rt_clock) + CONSOLE_CURSOR_PERIOD / 2);
+ if (count) {
+ text_console_update_cursor_timer();
+ }
}
static const GraphicHwOps text_console_ops = {
@@ -1700,19 +2184,16 @@ static const GraphicHwOps text_console_ops = {
.text_update = text_console_update,
};
-static void text_console_do_init(CharDriverState *chr, DisplayState *ds)
+static void text_console_do_init(Chardev *chr, DisplayState *ds)
{
- QemuConsole *s;
+ VCChardev *drv = VC_CHARDEV(chr);
+ QemuConsole *s = drv->console;
int g_width = 80 * FONT_WIDTH;
int g_height = 24 * FONT_HEIGHT;
- s = chr->opaque;
-
- chr->chr_write = console_puts;
-
s->out_fifo.buf = s->out_fifo_buf;
s->out_fifo.buf_size = sizeof(s->out_fifo_buf);
- s->kbd_timer = qemu_new_timer_ms(rt_clock, kbd_send_chars, s);
+ s->kbd_timer = timer_new_ms(QEMU_CLOCK_REALTIME, kbd_send_chars, s);
s->ds = ds;
s->y_displayed = 0;
@@ -1728,9 +2209,6 @@ static void text_console_do_init(CharDriverState *chr, DisplayState *ds)
s->surface = qemu_create_displaysurface(g_width, g_height);
}
- s->cursor_timer =
- qemu_new_timer_ms(rt_clock, text_console_update_cursor, s);
-
s->hw_ops = &text_console_ops;
s->hw = s;
@@ -1740,36 +2218,36 @@ static void text_console_do_init(CharDriverState *chr, DisplayState *ds)
s->t_attrib_default.blink = 0;
s->t_attrib_default.invers = 0;
s->t_attrib_default.unvisible = 0;
- s->t_attrib_default.fgcol = COLOR_WHITE;
- s->t_attrib_default.bgcol = COLOR_BLACK;
+ s->t_attrib_default.fgcol = QEMU_COLOR_WHITE;
+ s->t_attrib_default.bgcol = QEMU_COLOR_BLACK;
/* set current text attributes to default */
s->t_attrib = s->t_attrib_default;
text_console_resize(s);
if (chr->label) {
- char msg[128];
- int len;
+ char *msg;
- 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.bgcol = QEMU_COLOR_BLUE;
+ msg = g_strdup_printf("%s console\r\n", chr->label);
+ vc_chr_write(chr, (uint8_t *)msg, strlen(msg));
+ g_free(msg);
s->t_attrib = s->t_attrib_default;
}
- qemu_chr_be_generic_open(chr);
- if (chr->init)
- chr->init(chr);
+ qemu_chr_be_event(chr, CHR_EVENT_OPENED);
}
-static CharDriverState *text_console_init(ChardevVC *vc)
+static void vc_chr_open(Chardev *chr,
+ ChardevBackend *backend,
+ bool *be_opened,
+ Error **errp)
{
- CharDriverState *chr;
+ ChardevVC *vc = backend->u.vc.data;
+ VCChardev *drv = VC_CHARDEV(chr);
QemuConsole *s;
unsigned width = 0;
unsigned height = 0;
- chr = g_malloc0(sizeof(CharDriverState));
-
if (vc->has_width) {
width = vc->width;
} else if (vc->has_cols) {
@@ -1784,41 +2262,28 @@ static CharDriverState *text_console_init(ChardevVC *vc)
trace_console_txt_new(width, height);
if (width == 0 || height == 0) {
- s = new_console(NULL, TEXT_CONSOLE);
+ s = new_console(NULL, TEXT_CONSOLE, 0);
} else {
- s = new_console(NULL, TEXT_CONSOLE_FIXED_SIZE);
+ s = new_console(NULL, TEXT_CONSOLE_FIXED_SIZE, 0);
s->surface = qemu_create_displaysurface(width, height);
}
if (!s) {
- g_free(chr);
- return NULL;
+ error_setg(errp, "cannot create text console");
+ return;
}
s->chr = chr;
- chr->opaque = s;
- chr->chr_set_echo = text_console_set_echo;
- /* console/chardev init sometimes completes elsewhere in a 2nd
- * stage, so defer OPENED events until they are fully initialized
- */
- chr->explicit_be_open = true;
+ drv->console = s;
if (display_state) {
text_console_do_init(chr, display_state);
}
- return chr;
-}
-
-static VcHandler *vc_handler = text_console_init;
-CharDriverState *vc_init(ChardevVC *vc)
-{
- return vc_handler(vc);
-}
-
-void register_vc_handler(VcHandler *handler)
-{
- vc_handler = handler;
+ /* console/chardev init sometimes completes elsewhere in a 2nd
+ * stage, so defer OPENED events until they are fully initialized
+ */
+ *be_opened = false;
}
void qemu_console_resize(QemuConsole *s, int width, int height)
@@ -1826,179 +2291,135 @@ void qemu_console_resize(QemuConsole *s, int width, int height)
DisplaySurface *surface;
assert(s->console_type == GRAPHIC_CONSOLE);
+
+ if (s->surface && (s->surface->flags & QEMU_ALLOCATED_FLAG) &&
+ pixman_image_get_width(s->surface->image) == width &&
+ pixman_image_get_height(s->surface->image) == height) {
+ return;
+ }
+
surface = qemu_create_displaysurface(width, height);
dpy_gfx_replace_surface(s, surface);
}
-void qemu_console_copy(QemuConsole *con, int src_x, int src_y,
- int dst_x, int dst_y, int w, int h)
-{
- assert(con->console_type == GRAPHIC_CONSOLE);
- dpy_gfx_copy(con, src_x, src_y, dst_x, dst_y, w, h);
-}
-
DisplaySurface *qemu_console_surface(QemuConsole *console)
{
return console->surface;
}
-DisplayState *qemu_console_displaystate(QemuConsole *console)
+PixelFormat qemu_default_pixelformat(int bpp)
{
- return console->ds;
+ pixman_format_code_t fmt = qemu_default_pixman_format(bpp, true);
+ PixelFormat pf = qemu_pixelformat_from_pixman(fmt);
+ return pf;
}
-PixelFormat qemu_different_endianness_pixelformat(int bpp)
-{
- PixelFormat pf;
+static QemuDisplay *dpys[DISPLAY_TYPE__MAX];
- memset(&pf, 0x00, sizeof(PixelFormat));
+void qemu_display_register(QemuDisplay *ui)
+{
+ assert(ui->type < DISPLAY_TYPE__MAX);
+ dpys[ui->type] = ui;
+}
- pf.bits_per_pixel = bpp;
- pf.bytes_per_pixel = DIV_ROUND_UP(bpp, 8);
- pf.depth = bpp == 32 ? 24 : bpp;
+bool qemu_display_find_default(DisplayOptions *opts)
+{
+ static DisplayType prio[] = {
+ DISPLAY_TYPE_GTK,
+ DISPLAY_TYPE_SDL,
+ DISPLAY_TYPE_COCOA
+ };
+ int i;
- switch (bpp) {
- 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;
+ for (i = 0; i < ARRAY_SIZE(prio); i++) {
+ if (dpys[prio[i]] == NULL) {
+ ui_module_load_one(DisplayType_str(prio[i]));
+ }
+ if (dpys[prio[i]] == NULL) {
+ continue;
+ }
+ opts->type = prio[i];
+ return true;
}
- return pf;
+ return false;
}
-PixelFormat qemu_default_pixelformat(int bpp)
+void qemu_display_early_init(DisplayOptions *opts)
{
- PixelFormat pf;
+ assert(opts->type < DISPLAY_TYPE__MAX);
+ if (opts->type == DISPLAY_TYPE_NONE) {
+ return;
+ }
+ if (dpys[opts->type] == NULL) {
+ ui_module_load_one(DisplayType_str(opts->type));
+ }
+ if (dpys[opts->type] == NULL) {
+ error_report("Display '%s' is not available.",
+ DisplayType_str(opts->type));
+ exit(1);
+ }
+ if (dpys[opts->type]->early_init) {
+ dpys[opts->type]->early_init(opts);
+ }
+}
- memset(&pf, 0x00, sizeof(PixelFormat));
+void qemu_display_init(DisplayState *ds, DisplayOptions *opts)
+{
+ assert(opts->type < DISPLAY_TYPE__MAX);
+ if (opts->type == DISPLAY_TYPE_NONE) {
+ return;
+ }
+ assert(dpys[opts->type] != NULL);
+ dpys[opts->type]->init(ds, opts);
+}
- pf.bits_per_pixel = bpp;
- pf.bytes_per_pixel = DIV_ROUND_UP(bpp, 8);
- pf.depth = bpp == 32 ? 24 : bpp;
+void qemu_display_help(void)
+{
+ int idx;
- switch (bpp) {
- case 15:
- pf.bits_per_pixel = 16;
- 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;
- pf.gmask = 0x000007E0;
- pf.bmask = 0x0000001F;
- pf.rmax = 31;
- pf.gmax = 63;
- pf.bmax = 31;
- 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;
- break;
- case 32:
- 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;
- break;
- default:
- break;
+ printf("Available display backend types:\n");
+ printf("none\n");
+ for (idx = DISPLAY_TYPE_NONE; idx < DISPLAY_TYPE__MAX; idx++) {
+ if (!dpys[idx]) {
+ ui_module_load_one(DisplayType_str(idx));
+ }
+ if (dpys[idx]) {
+ printf("%s\n", DisplayType_str(dpys[idx]->type));
+ }
}
- return pf;
}
-static void qemu_chr_parse_vc(QemuOpts *opts, ChardevBackend *backend,
- Error **errp)
+void qemu_chr_parse_vc(QemuOpts *opts, ChardevBackend *backend, Error **errp)
{
int val;
+ ChardevVC *vc;
- backend->vc = g_new0(ChardevVC, 1);
+ backend->type = CHARDEV_BACKEND_KIND_VC;
+ vc = backend->u.vc.data = g_new0(ChardevVC, 1);
+ qemu_chr_parse_common(opts, qapi_ChardevVC_base(vc));
val = qemu_opt_get_number(opts, "width", 0);
if (val != 0) {
- backend->vc->has_width = true;
- backend->vc->width = val;
+ vc->has_width = true;
+ vc->width = val;
}
val = qemu_opt_get_number(opts, "height", 0);
if (val != 0) {
- backend->vc->has_height = true;
- backend->vc->height = val;
+ vc->has_height = true;
+ vc->height = val;
}
val = qemu_opt_get_number(opts, "cols", 0);
if (val != 0) {
- backend->vc->has_cols = true;
- backend->vc->cols = val;
+ vc->has_cols = true;
+ vc->cols = val;
}
val = qemu_opt_get_number(opts, "rows", 0);
if (val != 0) {
- backend->vc->has_rows = true;
- backend->vc->rows = val;
+ vc->has_rows = true;
+ vc->rows = val;
}
}
@@ -2009,12 +2430,34 @@ static const TypeInfo qemu_console_info = {
.class_size = sizeof(QemuConsoleClass),
};
+static void char_vc_class_init(ObjectClass *oc, void *data)
+{
+ ChardevClass *cc = CHARDEV_CLASS(oc);
+
+ cc->parse = qemu_chr_parse_vc;
+ cc->open = vc_chr_open;
+ cc->chr_write = vc_chr_write;
+ cc->chr_set_echo = vc_chr_set_echo;
+}
+
+static const TypeInfo char_vc_type_info = {
+ .name = TYPE_CHARDEV_VC,
+ .parent = TYPE_CHARDEV,
+ .instance_size = sizeof(VCChardev),
+ .class_init = char_vc_class_init,
+};
+
+void qemu_console_early_init(void)
+{
+ /* set the default vc driver */
+ if (!object_class_by_name(TYPE_CHARDEV_VC)) {
+ type_register(&char_vc_type_info);
+ }
+}
static void register_types(void)
{
type_register_static(&qemu_console_info);
- register_char_driver_qapi("vc", CHARDEV_BACKEND_KIND_VC,
- qemu_chr_parse_vc);
}
type_init(register_types);