* [Qemu-devel] [PULL 0/9] linux framebuffer display driver
@ 2012-09-18 7:17 Gerd Hoffmann
2012-09-18 7:17 ` [Qemu-devel] [PATCH 1/9] QLIST-ify display change listeners Gerd Hoffmann
` (8 more replies)
0 siblings, 9 replies; 29+ messages in thread
From: Gerd Hoffmann @ 2012-09-18 7:17 UTC (permalink / raw)
To: qemu-devel; +Cc: Gerd Hoffmann
Hi,
Third round of the framebuffer display driver patches, including git
tree for pull as I think it's ready now.
Changes: Addressed review comments from Markus. Catch a few more fatal
signals, especially SIGABRT, so fbdev restores your console when qemu
runs into an assert(). Misc little tweaks, no major changes.
cheers,
Gerd
The following changes since commit 6b80f7db8a7f84d21e46d01e30c8497733bb23a0:
Merge remote-tracking branch 'kiszka/queues/slirp' into staging (2012-09-17 10:23:20 -0500)
are available in the git repository at:
git://git.kraxel.org/qemu fbdev.1
Gerd Hoffmann (9):
QLIST-ify display change listeners.
add unregister_displaychangelistener
move set_mouse + cursor_define callbacks
fbdev: add linux framebuffer display driver.
fbdev: add monitor command to enable/disable
fbdev: make configurable at compile time.
fbdev: move to pixman
fbdev: add mouse pointer support
fbdev: add display scaling support
configure | 24 ++
console.c | 2 +-
console.h | 123 ++++--
hmp-commands.hx | 15 +
hmp.c | 9 +
hmp.h | 1 +
hw/jazz_led.c | 2 +-
hw/qxl-render.c | 2 +-
hw/vga.c | 10 +-
hw/vmware_vga.c | 11 +-
hw/xenfb.c | 2 +-
qapi-schema.json | 14 +
qemu-options.hx | 8 +
qmp-commands.hx | 6 +
qmp.c | 17 +
sysemu.h | 1 +
trace-events | 15 +
ui/Makefile.objs | 1 +
ui/fbdev.c | 1142 +++++++++++++++++++++++++++++++++++++++++++++++++++
ui/linux-keynames.h | 388 +++++++++++++++++
ui/sdl.c | 8 +-
ui/spice-display.c | 4 +-
ui/vnc.c | 8 +-
vl.c | 50 ++-
24 files changed, 1789 insertions(+), 74 deletions(-)
create mode 100644 ui/fbdev.c
create mode 100644 ui/linux-keynames.h
^ permalink raw reply [flat|nested] 29+ messages in thread
* [Qemu-devel] [PATCH 1/9] QLIST-ify display change listeners.
2012-09-18 7:17 [Qemu-devel] [PULL 0/9] linux framebuffer display driver Gerd Hoffmann
@ 2012-09-18 7:17 ` Gerd Hoffmann
2012-09-18 7:17 ` [Qemu-devel] [PATCH 2/9] add unregister_displaychangelistener Gerd Hoffmann
` (7 subsequent siblings)
8 siblings, 0 replies; 29+ messages in thread
From: Gerd Hoffmann @ 2012-09-18 7:17 UTC (permalink / raw)
To: qemu-devel; +Cc: Gerd Hoffmann
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
---
console.h | 72 +++++++++++++++++++++++++++++++----------------------------
hw/xenfb.c | 2 +-
vl.c | 9 ++-----
3 files changed, 42 insertions(+), 41 deletions(-)
diff --git a/console.h b/console.h
index f990684..646ad4b 100644
--- a/console.h
+++ b/console.h
@@ -164,7 +164,7 @@ struct DisplayChangeListener {
int w, int h, uint32_t c);
void (*dpy_text_cursor)(struct DisplayState *s, int x, int y);
- struct DisplayChangeListener *next;
+ QLIST_ENTRY(DisplayChangeListener) next;
};
struct DisplayAllocator {
@@ -179,7 +179,7 @@ struct DisplayState {
struct QEMUTimer *gui_timer;
struct DisplayAllocator* allocator;
- struct DisplayChangeListener* listeners;
+ QLIST_HEAD(, DisplayChangeListener) listeners;
void (*mouse_set)(int x, int y, int on);
void (*cursor_define)(QEMUCursor *cursor);
@@ -231,72 +231,76 @@ static inline int is_buffer_shared(DisplaySurface *surface)
static inline void register_displaychangelistener(DisplayState *ds, DisplayChangeListener *dcl)
{
- dcl->next = ds->listeners;
- ds->listeners = dcl;
+ QLIST_INSERT_HEAD(&ds->listeners, dcl, next);
}
static inline void dpy_update(DisplayState *s, int x, int y, int w, int h)
{
- struct DisplayChangeListener *dcl = s->listeners;
- while (dcl != NULL) {
+ struct DisplayChangeListener *dcl;
+ QLIST_FOREACH(dcl, &s->listeners, next) {
dcl->dpy_update(s, x, y, w, h);
- dcl = dcl->next;
}
}
static inline void dpy_resize(DisplayState *s)
{
- struct DisplayChangeListener *dcl = s->listeners;
- while (dcl != NULL) {
+ struct DisplayChangeListener *dcl;
+ QLIST_FOREACH(dcl, &s->listeners, next) {
dcl->dpy_resize(s);
- dcl = dcl->next;
}
}
static inline void dpy_setdata(DisplayState *s)
{
- struct DisplayChangeListener *dcl = s->listeners;
- while (dcl != NULL) {
- if (dcl->dpy_setdata) dcl->dpy_setdata(s);
- dcl = dcl->next;
+ struct DisplayChangeListener *dcl;
+ QLIST_FOREACH(dcl, &s->listeners, next) {
+ if (dcl->dpy_setdata) {
+ dcl->dpy_setdata(s);
+ }
}
}
static inline void dpy_refresh(DisplayState *s)
{
- struct DisplayChangeListener *dcl = s->listeners;
- while (dcl != NULL) {
- if (dcl->dpy_refresh) dcl->dpy_refresh(s);
- dcl = dcl->next;
+ struct DisplayChangeListener *dcl;
+ QLIST_FOREACH(dcl, &s->listeners, next) {
+ if (dcl->dpy_refresh) {
+ dcl->dpy_refresh(s);
+ }
}
}
static inline void dpy_copy(struct DisplayState *s, int src_x, int src_y,
- int dst_x, int dst_y, int w, int h) {
- struct DisplayChangeListener *dcl = s->listeners;
- while (dcl != NULL) {
- if (dcl->dpy_copy)
+ int dst_x, int dst_y, int w, int h)
+{
+ struct DisplayChangeListener *dcl;
+ QLIST_FOREACH(dcl, &s->listeners, next) {
+ if (dcl->dpy_copy) {
dcl->dpy_copy(s, src_x, src_y, dst_x, dst_y, w, h);
- else /* TODO */
+ } else { /* TODO */
dcl->dpy_update(s, dst_x, dst_y, w, h);
- dcl = dcl->next;
+ }
}
}
static inline void dpy_fill(struct DisplayState *s, int x, int y,
- int w, int h, uint32_t c) {
- struct DisplayChangeListener *dcl = s->listeners;
- while (dcl != NULL) {
- if (dcl->dpy_fill) dcl->dpy_fill(s, x, y, w, h, c);
- dcl = dcl->next;
+ int w, int h, uint32_t c)
+{
+ struct DisplayChangeListener *dcl;
+ QLIST_FOREACH(dcl, &s->listeners, next) {
+ if (dcl->dpy_fill) {
+ dcl->dpy_fill(s, x, y, w, h, c);
+ }
}
}
-static inline void dpy_cursor(struct DisplayState *s, int x, int y) {
- struct DisplayChangeListener *dcl = s->listeners;
- while (dcl != NULL) {
- if (dcl->dpy_text_cursor) dcl->dpy_text_cursor(s, x, y);
- dcl = dcl->next;
+static inline void dpy_cursor(struct DisplayState *s, int x, int y)
+{
+ struct DisplayChangeListener *dcl;
+ QLIST_FOREACH(dcl, &s->listeners, next) {
+ if (dcl->dpy_text_cursor) {
+ dcl->dpy_text_cursor(s, x, y);
+ }
}
}
diff --git a/hw/xenfb.c b/hw/xenfb.c
index 338800a..ef24c33 100644
--- a/hw/xenfb.c
+++ b/hw/xenfb.c
@@ -717,7 +717,7 @@ static void xenfb_update(void *opaque)
if (xenfb_queue_full(xenfb))
return;
- for (l = xenfb->c.ds->listeners; l != NULL; l = l->next) {
+ QLIST_FOREACH(l, &xenfb->c.ds->listeners, next) {
if (l->idle)
continue;
idle = 0;
diff --git a/vl.c b/vl.c
index 7c577fa..2a7c92a 100644
--- a/vl.c
+++ b/vl.c
@@ -1276,15 +1276,14 @@ static void gui_update(void *opaque)
{
uint64_t interval = GUI_REFRESH_INTERVAL;
DisplayState *ds = opaque;
- DisplayChangeListener *dcl = ds->listeners;
+ DisplayChangeListener *dcl;
dpy_refresh(ds);
- while (dcl != NULL) {
+ QLIST_FOREACH(dcl, &ds->listeners, next) {
if (dcl->gui_timer_interval &&
dcl->gui_timer_interval < interval)
interval = dcl->gui_timer_interval;
- dcl = dcl->next;
}
qemu_mod_timer(ds->gui_timer, interval + qemu_get_clock_ms(rt_clock));
}
@@ -3699,14 +3698,12 @@ int main(int argc, char **argv, char **envp)
/* display setup */
dpy_resize(ds);
- dcl = ds->listeners;
- while (dcl != NULL) {
+ QLIST_FOREACH(dcl, &ds->listeners, next) {
if (dcl->dpy_refresh != 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));
break;
}
- dcl = dcl->next;
}
text_consoles_set_display(ds);
--
1.7.1
^ permalink raw reply related [flat|nested] 29+ messages in thread
* [Qemu-devel] [PATCH 2/9] add unregister_displaychangelistener
2012-09-18 7:17 [Qemu-devel] [PULL 0/9] linux framebuffer display driver Gerd Hoffmann
2012-09-18 7:17 ` [Qemu-devel] [PATCH 1/9] QLIST-ify display change listeners Gerd Hoffmann
@ 2012-09-18 7:17 ` Gerd Hoffmann
2012-09-18 10:54 ` Stefano Stabellini
2012-09-18 7:17 ` [Qemu-devel] [PATCH 3/9] move set_mouse + cursor_define callbacks Gerd Hoffmann
` (6 subsequent siblings)
8 siblings, 1 reply; 29+ messages in thread
From: Gerd Hoffmann @ 2012-09-18 7:17 UTC (permalink / raw)
To: qemu-devel; +Cc: Gerd Hoffmann
Also change the way the gui_timer is initialized: each time a
displaychangelistener is registered or unregistered we'll check
whenever we need a timer (due to dpy_refresh callback being present)
and if so setup a timer, otherwise zap it. This way the gui timer works
correctly with displaychangelisteners coming and going.
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
---
console.h | 10 ++++++++++
vl.c | 31 +++++++++++++++++++++++--------
2 files changed, 33 insertions(+), 8 deletions(-)
diff --git a/console.h b/console.h
index 646ad4b..48fef22 100644
--- a/console.h
+++ b/console.h
@@ -229,9 +229,19 @@ static inline int is_buffer_shared(DisplaySurface *surface)
!(surface->flags & QEMU_REALPIXELS_FLAG));
}
+void gui_setup_refresh(DisplayState *ds);
+
static inline void register_displaychangelistener(DisplayState *ds, DisplayChangeListener *dcl)
{
QLIST_INSERT_HEAD(&ds->listeners, dcl, next);
+ gui_setup_refresh(ds);
+}
+
+static inline void unregister_displaychangelistener(DisplayState *ds,
+ DisplayChangeListener *dcl)
+{
+ QLIST_REMOVE(dcl, next);
+ gui_setup_refresh(ds);
}
static inline void dpy_update(DisplayState *s, int x, int y, int w, int h)
diff --git a/vl.c b/vl.c
index 2a7c92a..fbb77fe 100644
--- a/vl.c
+++ b/vl.c
@@ -1288,6 +1288,29 @@ static void gui_update(void *opaque)
qemu_mod_timer(ds->gui_timer, interval + qemu_get_clock_ms(rt_clock));
}
+void gui_setup_refresh(DisplayState *ds)
+{
+ DisplayChangeListener *dcl;
+ bool need_timer = false;
+
+ QLIST_FOREACH(dcl, &ds->listeners, next) {
+ if (dcl->dpy_refresh != NULL) {
+ need_timer = true;
+ break;
+ }
+ }
+
+ 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));
+ }
+ if (!need_timer && ds->gui_timer != NULL) {
+ qemu_del_timer(ds->gui_timer);
+ qemu_free_timer(ds->gui_timer);
+ ds->gui_timer = NULL;
+ }
+}
+
struct vm_change_state_entry {
VMChangeStateHandler *cb;
void *opaque;
@@ -2350,7 +2373,6 @@ int main(int argc, char **argv, char **envp)
const char *kernel_filename, *kernel_cmdline;
char boot_devices[33] = "cad"; /* default to HD->floppy->CD-ROM */
DisplayState *ds;
- DisplayChangeListener *dcl;
int cyls, heads, secs, translation;
QemuOpts *hda_opts = NULL, *opts, *machine_opts;
QemuOptsList *olist;
@@ -3698,13 +3720,6 @@ int main(int argc, char **argv, char **envp)
/* display setup */
dpy_resize(ds);
- QLIST_FOREACH(dcl, &ds->listeners, next) {
- if (dcl->dpy_refresh != 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));
- break;
- }
- }
text_consoles_set_display(ds);
if (foreach_device_config(DEV_GDB, gdbserver_start) < 0) {
--
1.7.1
^ permalink raw reply related [flat|nested] 29+ messages in thread
* [Qemu-devel] [PATCH 3/9] move set_mouse + cursor_define callbacks
2012-09-18 7:17 [Qemu-devel] [PULL 0/9] linux framebuffer display driver Gerd Hoffmann
2012-09-18 7:17 ` [Qemu-devel] [PATCH 1/9] QLIST-ify display change listeners Gerd Hoffmann
2012-09-18 7:17 ` [Qemu-devel] [PATCH 2/9] add unregister_displaychangelistener Gerd Hoffmann
@ 2012-09-18 7:17 ` Gerd Hoffmann
2012-09-18 14:10 ` Stefano Stabellini
2012-09-18 7:17 ` [Qemu-devel] [PATCH 4/9] fbdev: add linux framebuffer display driver Gerd Hoffmann
` (5 subsequent siblings)
8 siblings, 1 reply; 29+ messages in thread
From: Gerd Hoffmann @ 2012-09-18 7:17 UTC (permalink / raw)
To: qemu-devel; +Cc: Gerd Hoffmann
When adding DisplayChangeListeners the set_mouse and cursor_define
callbacks have been left in DisplayState for some reason. Fix it.
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
---
console.c | 2 +-
console.h | 39 +++++++++++++++++++++++++++++++++++----
hw/jazz_led.c | 2 +-
hw/qxl-render.c | 2 +-
hw/vga.c | 10 +++++-----
hw/vmware_vga.c | 11 ++++++-----
ui/sdl.c | 8 ++++----
ui/spice-display.c | 4 ++--
ui/vnc.c | 8 ++++----
9 files changed, 59 insertions(+), 27 deletions(-)
diff --git a/console.c b/console.c
index a8bcc42..cc0479b 100644
--- a/console.c
+++ b/console.c
@@ -1239,7 +1239,7 @@ static void text_console_update(void *opaque, console_ch_t *chardata)
s->text_y[1] = 0;
}
if (s->cursor_invalidate) {
- dpy_cursor(s->ds, s->x, s->y);
+ dpy_text_cursor(s->ds, s->x, s->y);
s->cursor_invalidate = 0;
}
}
diff --git a/console.h b/console.h
index 48fef22..bef2d2d 100644
--- a/console.h
+++ b/console.h
@@ -164,6 +164,9 @@ struct DisplayChangeListener {
int w, int h, uint32_t c);
void (*dpy_text_cursor)(struct DisplayState *s, int x, int y);
+ void (*dpy_mouse_set)(struct DisplayState *s, int x, int y, int on);
+ void (*dpy_cursor_define)(struct DisplayState *s, QEMUCursor *cursor);
+
QLIST_ENTRY(DisplayChangeListener) next;
};
@@ -181,9 +184,6 @@ struct DisplayState {
struct DisplayAllocator* allocator;
QLIST_HEAD(, DisplayChangeListener) listeners;
- void (*mouse_set)(int x, int y, int on);
- void (*cursor_define)(QEMUCursor *cursor);
-
struct DisplayState *next;
};
@@ -304,7 +304,7 @@ static inline void dpy_fill(struct DisplayState *s, int x, int y,
}
}
-static inline void dpy_cursor(struct DisplayState *s, int x, int y)
+static inline void dpy_text_cursor(struct DisplayState *s, int x, int y)
{
struct DisplayChangeListener *dcl;
QLIST_FOREACH(dcl, &s->listeners, next) {
@@ -314,6 +314,37 @@ static inline void dpy_cursor(struct DisplayState *s, int x, int y)
}
}
+static inline void dpy_mouse_set(struct DisplayState *s, int x, int y, int on)
+{
+ struct DisplayChangeListener *dcl;
+ QLIST_FOREACH(dcl, &s->listeners, next) {
+ if (dcl->dpy_mouse_set) {
+ dcl->dpy_mouse_set(s, x, y, on);
+ }
+ }
+}
+
+static inline void dpy_cursor_define(struct DisplayState *s, QEMUCursor *cursor)
+{
+ struct DisplayChangeListener *dcl;
+ QLIST_FOREACH(dcl, &s->listeners, next) {
+ if (dcl->dpy_cursor_define) {
+ dcl->dpy_cursor_define(s, cursor);
+ }
+ }
+}
+
+static inline bool dpy_cursor_define_supported(struct DisplayState *s)
+{
+ struct DisplayChangeListener *dcl;
+ QLIST_FOREACH(dcl, &s->listeners, next) {
+ if (dcl->dpy_cursor_define) {
+ return true;
+ }
+ }
+ return false;
+}
+
static inline int ds_get_linesize(DisplayState *ds)
{
return ds->surface->linesize;
diff --git a/hw/jazz_led.c b/hw/jazz_led.c
index 6486523..c4d54e2 100644
--- a/hw/jazz_led.c
+++ b/hw/jazz_led.c
@@ -210,7 +210,7 @@ static void jazz_led_text_update(void *opaque, console_ch_t *chardata)
LedState *s = opaque;
char buf[2];
- dpy_cursor(s->ds, -1, -1);
+ dpy_text_cursor(s->ds, -1, -1);
qemu_console_resize(s->ds, 2, 1);
/* TODO: draw the segments */
diff --git a/hw/qxl-render.c b/hw/qxl-render.c
index e2e3fe2..085a090 100644
--- a/hw/qxl-render.c
+++ b/hw/qxl-render.c
@@ -238,7 +238,7 @@ int qxl_render_cursor(PCIQXLDevice *qxl, QXLCommandExt *ext)
return 1;
}
- if (!qxl->ssd.ds->mouse_set || !qxl->ssd.ds->cursor_define) {
+ if (!dpy_cursor_define_supported(qxl->ssd.ds)) {
return 0;
}
diff --git a/hw/vga.c b/hw/vga.c
index afaef0d..ec4f0c5 100644
--- a/hw/vga.c
+++ b/hw/vga.c
@@ -2081,11 +2081,11 @@ static void vga_update_text(void *opaque, console_ch_t *chardata)
s->cr[VGA_CRTC_CURSOR_END] != s->cursor_end || full_update) {
cursor_visible = !(s->cr[VGA_CRTC_CURSOR_START] & 0x20);
if (cursor_visible && cursor_offset < size && cursor_offset >= 0)
- dpy_cursor(s->ds,
- TEXTMODE_X(cursor_offset),
- TEXTMODE_Y(cursor_offset));
+ dpy_text_cursor(s->ds,
+ TEXTMODE_X(cursor_offset),
+ TEXTMODE_Y(cursor_offset));
else
- dpy_cursor(s->ds, -1, -1);
+ dpy_text_cursor(s->ds, -1, -1);
s->cursor_offset = cursor_offset;
s->cursor_start = s->cr[VGA_CRTC_CURSOR_START];
s->cursor_end = s->cr[VGA_CRTC_CURSOR_END];
@@ -2146,7 +2146,7 @@ static void vga_update_text(void *opaque, console_ch_t *chardata)
/* Display a message */
s->last_width = 60;
s->last_height = height = 3;
- dpy_cursor(s->ds, -1, -1);
+ dpy_text_cursor(s->ds, -1, -1);
s->ds->surface->width = s->last_width;
s->ds->surface->height = height;
dpy_resize(s->ds);
diff --git a/hw/vmware_vga.c b/hw/vmware_vga.c
index e815a04..e105b5a 100644
--- a/hw/vmware_vga.c
+++ b/hw/vmware_vga.c
@@ -479,8 +479,7 @@ static inline void vmsvga_cursor_define(struct vmsvga_state_s *s,
qc = cursor_builtin_left_ptr();
}
- if (s->vga.ds->cursor_define)
- s->vga.ds->cursor_define(qc);
+ dpy_cursor_define(s->vga.ds, qc);
cursor_put(qc);
}
#endif
@@ -755,9 +754,10 @@ static uint32_t vmsvga_value_read(void *opaque, uint32_t address)
caps |= SVGA_CAP_RECT_FILL;
#endif
#ifdef HW_MOUSE_ACCEL
- if (s->vga.ds->mouse_set)
+ if (dpy_cursor_define_supported(s->vga.ds)) {
caps |= SVGA_CAP_CURSOR | SVGA_CAP_CURSOR_BYPASS_2 |
SVGA_CAP_CURSOR_BYPASS;
+ }
#endif
return caps;
@@ -904,8 +904,9 @@ static void vmsvga_value_write(void *opaque, uint32_t address, uint32_t value)
s->cursor.on |= (value == SVGA_CURSOR_ON_SHOW);
s->cursor.on &= (value != SVGA_CURSOR_ON_HIDE);
#ifdef HW_MOUSE_ACCEL
- if (s->vga.ds->mouse_set && value <= SVGA_CURSOR_ON_SHOW)
- s->vga.ds->mouse_set(s->cursor.x, s->cursor.y, s->cursor.on);
+ if (value <= SVGA_CURSOR_ON_SHOW) {
+ dpy_mouse_set(s->vga.ds, s->cursor.x, s->cursor.y, s->cursor.on);
+ }
#endif
break;
diff --git a/ui/sdl.c b/ui/sdl.c
index f6f711c..f8ead93 100644
--- a/ui/sdl.c
+++ b/ui/sdl.c
@@ -905,7 +905,7 @@ static void sdl_fill(DisplayState *ds, int x, int y, int w, int h, uint32_t c)
SDL_FillRect(real_screen, &dst, c);
}
-static void sdl_mouse_warp(int x, int y, int on)
+static void sdl_mouse_warp(DisplayState *ds, int x, int y, int on)
{
if (on) {
if (!guest_cursor)
@@ -921,7 +921,7 @@ static void sdl_mouse_warp(int x, int y, int on)
guest_x = x, guest_y = y;
}
-static void sdl_mouse_define(QEMUCursor *c)
+static void sdl_mouse_define(DisplayState *ds, QEMUCursor *c)
{
uint8_t *image, *mask;
int bpl;
@@ -1025,8 +1025,8 @@ void sdl_display_init(DisplayState *ds, int full_screen, int no_frame)
dcl->dpy_refresh = sdl_refresh;
dcl->dpy_setdata = sdl_setdata;
dcl->dpy_fill = sdl_fill;
- ds->mouse_set = sdl_mouse_warp;
- ds->cursor_define = sdl_mouse_define;
+ dcl->dpy_mouse_set = sdl_mouse_warp;
+ dcl->dpy_cursor_define = sdl_mouse_define;
register_displaychangelistener(ds, dcl);
da = g_malloc0(sizeof(DisplayAllocator));
diff --git a/ui/spice-display.c b/ui/spice-display.c
index 50fbefb..5180428 100644
--- a/ui/spice-display.c
+++ b/ui/spice-display.c
@@ -441,12 +441,12 @@ void qemu_spice_display_resize(SimpleSpiceDisplay *ssd)
void qemu_spice_cursor_refresh_unlocked(SimpleSpiceDisplay *ssd)
{
if (ssd->cursor) {
- ssd->ds->cursor_define(ssd->cursor);
+ dpy_cursor_define(ssd->ds, ssd->cursor);
cursor_put(ssd->cursor);
ssd->cursor = NULL;
}
if (ssd->mouse_x != -1 && ssd->mouse_y != -1) {
- ssd->ds->mouse_set(ssd->mouse_x, ssd->mouse_y, 1);
+ dpy_mouse_set(ssd->ds, ssd->mouse_x, ssd->mouse_y, 1);
ssd->mouse_x = -1;
ssd->mouse_y = -1;
}
diff --git a/ui/vnc.c b/ui/vnc.c
index 385e345..f8f058d 100644
--- a/ui/vnc.c
+++ b/ui/vnc.c
@@ -798,7 +798,7 @@ static void vnc_dpy_copy(DisplayState *ds, int src_x, int src_y, int dst_x, int
}
}
-static void vnc_mouse_set(int x, int y, int visible)
+static void vnc_mouse_set(DisplayState *ds, int x, int y, int visible)
{
/* can we ask the client(s) to move the pointer ??? */
}
@@ -825,7 +825,7 @@ static int vnc_cursor_define(VncState *vs)
return -1;
}
-static void vnc_dpy_cursor_define(QEMUCursor *c)
+static void vnc_dpy_cursor_define(DisplayState *ds, QEMUCursor *c)
{
VncDisplay *vd = vnc_display;
VncState *vs;
@@ -2751,9 +2751,9 @@ void vnc_display_init(DisplayState *ds)
dcl->dpy_update = vnc_dpy_update;
dcl->dpy_resize = vnc_dpy_resize;
dcl->dpy_setdata = vnc_dpy_setdata;
+ dcl->dpy_mouse_set = vnc_mouse_set;
+ dcl->dpy_cursor_define = vnc_dpy_cursor_define;
register_displaychangelistener(ds, dcl);
- ds->mouse_set = vnc_mouse_set;
- ds->cursor_define = vnc_dpy_cursor_define;
}
--
1.7.1
^ permalink raw reply related [flat|nested] 29+ messages in thread
* [Qemu-devel] [PATCH 4/9] fbdev: add linux framebuffer display driver.
2012-09-18 7:17 [Qemu-devel] [PULL 0/9] linux framebuffer display driver Gerd Hoffmann
` (2 preceding siblings ...)
2012-09-18 7:17 ` [Qemu-devel] [PATCH 3/9] move set_mouse + cursor_define callbacks Gerd Hoffmann
@ 2012-09-18 7:17 ` Gerd Hoffmann
2012-09-18 15:01 ` Stefano Stabellini
2012-09-19 18:37 ` Blue Swirl
2012-09-18 7:17 ` [Qemu-devel] [PATCH 5/9] fbdev: add monitor command to enable/disable Gerd Hoffmann
` (4 subsequent siblings)
8 siblings, 2 replies; 29+ messages in thread
From: Gerd Hoffmann @ 2012-09-18 7:17 UTC (permalink / raw)
To: qemu-devel; +Cc: Gerd Hoffmann
Display works, requires truecolor framebuffer with 16 or 32 bpp on the
host. 32bpp is recommended. The framebuffer is used as-is, qemu
doesn't try to switch modes. With LCD displays mode switching is pretty
pointless IMHO, also it wouldn't work anyway with the most common
fbdev drivers (vesafb, KMS). Guest display is centered on the host
screen.
Mouse works, uses /dev/input/mice.
Keyboard works. Guest screen has whatever keymap you load inside
the guest. Text windows (monitor, serial, ...) have a simple en-us
keymap. Good enough to type monitor commands. Not goot enough to
work seriously on a serial terminal. But the qemu terminal emulation
isn't good enough for that anyway ;)
Hot keys:
Ctrl-Alt-F<nr> -> host console switching.
Ctrl-Alt-<nr> -> qemu console switching.
Ctrl-Alt-ESC -> exit qemu.
Special feature: Sane console switching. Switching away stops screen
updates. Switching back redraws the screen. When started from the
linux console qemu uses the vt you've started it from (requires just
read/write access to /dev/fb0). When starting from somewhere else qemu
tries to open a unused virtual terminal and switch to it (usually
requires root privileges to open /dev/tty<nr>).
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
---
console.h | 4 +
qemu-options.hx | 8 +
sysemu.h | 1 +
trace-events | 15 +
ui/Makefile.objs | 1 +
ui/fbdev.c | 974 +++++++++++++++++++++++++++++++++++++++++++++++++++
ui/linux-keynames.h | 388 ++++++++++++++++++++
vl.c | 12 +
8 files changed, 1403 insertions(+), 0 deletions(-)
create mode 100644 ui/fbdev.c
create mode 100644 ui/linux-keynames.h
diff --git a/console.h b/console.h
index bef2d2d..0a3bae2 100644
--- a/console.h
+++ b/console.h
@@ -417,6 +417,10 @@ void qemu_console_copy(DisplayState *ds, int src_x, int src_y,
/* sdl.c */
void sdl_display_init(DisplayState *ds, int full_screen, int no_frame);
+/* fbdev.c */
+int fbdev_display_init(DisplayState *ds, const char *device);
+void fbdev_display_uninit(DisplayState *ds);
+
/* cocoa.m */
void cocoa_display_init(DisplayState *ds, int full_screen);
diff --git a/qemu-options.hx b/qemu-options.hx
index 09c86c4..3445655 100644
--- a/qemu-options.hx
+++ b/qemu-options.hx
@@ -947,6 +947,14 @@ Enable/disable spice seamless migration. Default is off.
@end table
ETEXI
+DEF("fbdev", 0, QEMU_OPTION_fbdev,
+ "-fbdev enable fbdev\n", QEMU_ARCH_ALL)
+STEXI
+@item -fbdev
+@findex -fbdev
+Enable fbdev (linux framebuffer).
+ETEXI
+
DEF("portrait", 0, QEMU_OPTION_portrait,
"-portrait rotate graphical output 90 deg left (only PXA LCD)\n",
QEMU_ARCH_ALL)
diff --git a/sysemu.h b/sysemu.h
index 65552ac..34e6bfa 100644
--- a/sysemu.h
+++ b/sysemu.h
@@ -93,6 +93,7 @@ typedef enum DisplayType
DT_DEFAULT,
DT_CURSES,
DT_SDL,
+ DT_FBDEV,
DT_NOGRAPHIC,
DT_NONE,
} DisplayType;
diff --git a/trace-events b/trace-events
index b48fe2d..0d0b7fa 100644
--- a/trace-events
+++ b/trace-events
@@ -994,3 +994,18 @@ spapr_pci_rtas_ibm_change_msi(unsigned func, unsigned req) "func %u, requested %
spapr_pci_rtas_ibm_query_interrupt_source_number(unsigned ioa, unsigned intr) "queries for #%u, IRQ%u"
spapr_pci_msi_write(uint64_t addr, uint64_t data, uint32_t dt_irq) "@%"PRIx64"<=%"PRIx64" IRQ %u"
spapr_pci_lsi_set(const char *busname, int pin, uint32_t irq) "%s PIN%d IRQ %u"
+
+# ui/fbdev.c
+fbdev_enabled(void) ""
+fbdev_cleanup(void) ""
+fbdev_vt_activate(int vtno, int wait) "vtno %d, wait %d"
+fbdev_vt_activated(void) ""
+fbdev_vt_release_request(void) ""
+fbdev_vt_released(void) ""
+fbdev_vt_aquire_request(void) ""
+fbdev_vt_aquired(void) ""
+fbdev_kbd_raw(int enable) "enable %d"
+fbdev_kbd_event(int keycode, const char *kname, int up) "keycode 0x%x [%s], down %d"
+fbdev_dpy_resize(int w, int h) "%dx%d"
+fbdev_dpy_redraw(void)
+
diff --git a/ui/Makefile.objs b/ui/Makefile.objs
index adc07be..55ddcf2 100644
--- a/ui/Makefile.objs
+++ b/ui/Makefile.objs
@@ -12,3 +12,4 @@ common-obj-$(CONFIG_SDL) += sdl.o sdl_zoom.o x_keymap.o
common-obj-$(CONFIG_COCOA) += cocoa.o
common-obj-$(CONFIG_CURSES) += curses.o
common-obj-$(CONFIG_VNC) += $(vnc-obj-y)
+common-obj-$(CONFIG_LINUX) += fbdev.o
diff --git a/ui/fbdev.c b/ui/fbdev.c
new file mode 100644
index 0000000..40fc7d4
--- /dev/null
+++ b/ui/fbdev.c
@@ -0,0 +1,974 @@
+/*
+ * linux fbdev output driver.
+ *
+ * Author: Gerd Hoffmann <kraxel@redhat.com>
+ *
+ * This work is licensed under the terms of the GNU GPL, version 2 or later.
+ * See the COPYING file in the top-level directory.
+ *
+ */
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdbool.h>
+#include <string.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <termios.h>
+
+#include <sys/ioctl.h>
+#include <sys/mman.h>
+
+#include <linux/kd.h>
+#include <linux/vt.h>
+#include <linux/fb.h>
+
+#include "qemu-common.h"
+#include "console.h"
+#include "keymaps.h"
+#include "sysemu.h"
+#include "pflib.h"
+
+/*
+ * must be last so we get the linux input layer
+ * KEY_* defines, not the ncurses ones.
+ */
+#include <linux/input.h>
+
+/* -------------------------------------------------------------------- */
+
+/* file handles */
+static int tty = -1, fb = -1, mice = -1;
+
+/* saved state, for restore on exit */
+static int orig_vtno;
+static int kd_omode;
+static struct vt_mode vt_omode;
+static struct fb_var_screeninfo fb_ovar;
+
+/* framebuffer */
+static struct fb_fix_screeninfo fb_fix;
+static struct fb_var_screeninfo fb_var;
+static uint8_t *fb_mem;
+static int fb_mem_offset;
+
+/* linux console */
+static int vtno;
+static struct vt_mode vt_mode;
+static struct termios tty_attributes;
+static unsigned long tty_mode;
+static unsigned int tty_flags;
+static bool tty_mediumraw;
+static bool key_down[KEY_CNT];
+
+/* console switching */
+#define SIG_ACQ (SIGRTMIN+6)
+#define SIG_REL (SIGRTMIN+7)
+#define FB_ACTIVE 0
+#define FB_REL_REQ 1
+#define FB_INACTIVE 2
+#define FB_ACQ_REQ 3
+static int fb_switch_state;
+
+/* qdev windup */
+static DisplayChangeListener *dcl;
+static QemuPfConv *conv;
+static PixelFormat fbpf;
+static int resize_screen;
+static int redraw_screen;
+static int cx, cy, cw, ch;
+static Notifier exit_notifier;
+
+/* fwd decls */
+static int fbdev_activate_vt(int tty, int vtno, bool wait);
+
+/* -------------------------------------------------------------------- */
+/* mouse */
+
+static void read_mouse(void *opaque)
+{
+ char buf[3];
+ int rc, x, y, b;
+
+ rc = read(mice, buf, sizeof(buf));
+ if (rc != sizeof(buf)) {
+ return;
+ }
+
+ if (fb_switch_state != FB_ACTIVE) {
+ return;
+ }
+
+ x = buf[1];
+ y = -buf[2];
+ b = buf[0] & 0x7;
+
+ if (kbd_mouse_is_absolute()) {
+ static int ax, ay;
+ ax += x; ay += y;
+ if (ax < 0) {
+ ax = 0;
+ }
+ if (ay < 0) {
+ ay = 0;
+ }
+ if (ax >= cw) {
+ ax = cw-1;
+ }
+ if (ay >= ch) {
+ ay = ch-1;
+ }
+ kbd_mouse_event(ax * 0x7FFF / cw, ay * 0x7FFF / ch, 0, b);
+ } else {
+ kbd_mouse_event(x, y, 0, b);
+ }
+}
+
+static int init_mouse(void)
+{
+ mice = open("/dev/input/mice", O_RDONLY);
+ if (mice == -1) {
+ return -1;
+ }
+ qemu_set_fd_handler(mice, read_mouse, NULL, NULL);
+ return 0;
+}
+
+static void uninit_mouse(void)
+{
+ if (mice == -1) {
+ return;
+ }
+ qemu_set_fd_handler(mice, NULL, NULL, NULL);
+ close(mice);
+ mice = -1;
+}
+
+/* -------------------------------------------------------------------- */
+/* keyboard */
+
+static const char *keynames[] = {
+#include "linux-keynames.h"
+};
+
+static const int scancode_map[KEY_CNT] = {
+ [KEY_ESC] = 0x01,
+ [KEY_1] = 0x02,
+ [KEY_2] = 0x03,
+ [KEY_3] = 0x04,
+ [KEY_4] = 0x05,
+ [KEY_5] = 0x06,
+ [KEY_6] = 0x07,
+ [KEY_7] = 0x08,
+ [KEY_8] = 0x09,
+ [KEY_9] = 0x0a,
+ [KEY_0] = 0x0b,
+ [KEY_MINUS] = 0x0c,
+ [KEY_EQUAL] = 0x0d,
+ [KEY_BACKSPACE] = 0x0e,
+
+ [KEY_TAB] = 0x0f,
+ [KEY_Q] = 0x10,
+ [KEY_W] = 0x11,
+ [KEY_E] = 0x12,
+ [KEY_R] = 0x13,
+ [KEY_T] = 0x14,
+ [KEY_Y] = 0x15,
+ [KEY_U] = 0x16,
+ [KEY_I] = 0x17,
+ [KEY_O] = 0x18,
+ [KEY_P] = 0x19,
+ [KEY_LEFTBRACE] = 0x1a,
+ [KEY_RIGHTBRACE] = 0x1b,
+ [KEY_ENTER] = 0x1c,
+
+ [KEY_A] = 0x1e,
+ [KEY_S] = 0x1f,
+ [KEY_D] = 0x20,
+ [KEY_F] = 0x21,
+ [KEY_G] = 0x22,
+ [KEY_H] = 0x23,
+ [KEY_J] = 0x24,
+ [KEY_K] = 0x25,
+ [KEY_L] = 0x26,
+ [KEY_SEMICOLON] = 0x27,
+ [KEY_APOSTROPHE] = 0x28,
+ [KEY_GRAVE] = 0x29,
+ [KEY_LEFTSHIFT] = 0x2a,
+ [KEY_BACKSLASH] = 0x2b,
+
+ [KEY_Z] = 0x2c,
+ [KEY_X] = 0x2d,
+ [KEY_C] = 0x2e,
+ [KEY_V] = 0x2f,
+ [KEY_B] = 0x30,
+ [KEY_N] = 0x31,
+ [KEY_M] = 0x32,
+ [KEY_COMMA] = 0x33,
+ [KEY_DOT] = 0x34,
+ [KEY_SLASH] = 0x35,
+ [KEY_RIGHTSHIFT] = 0x36,
+ [KEY_SPACE] = 0x39,
+
+ [KEY_F1] = 0x3b,
+ [KEY_F2] = 0x3c,
+ [KEY_F3] = 0x3d,
+ [KEY_F4] = 0x3e,
+ [KEY_F5] = 0x3f,
+ [KEY_F6] = 0x40,
+ [KEY_F7] = 0x41,
+ [KEY_F8] = 0x42,
+ [KEY_F9] = 0x43,
+ [KEY_F10] = 0x44,
+ [KEY_F11] = 0x57,
+ [KEY_F12] = 0x58,
+
+ [KEY_SYSRQ] = 0xb7,
+ [KEY_SCROLLLOCK] = 0x46,
+#if 0
+ [KEY_PAUSE] = FIXME,
+#endif
+ [KEY_CAPSLOCK] = 0x3a,
+ [KEY_102ND] = 0x56,
+
+ [KEY_LEFTCTRL] = 0x1d,
+ [KEY_LEFTMETA] = 0xdb,
+ [KEY_LEFTALT] = 0x38,
+ [KEY_RIGHTALT] = 0xb8,
+ [KEY_RIGHTMETA] = 0xdc,
+ [KEY_RIGHTCTRL] = 0x9d,
+ [KEY_COMPOSE] = 0xdd,
+
+ [KEY_INSERT] = 0xd2,
+ [KEY_DELETE] = 0xd3,
+ [KEY_HOME] = 0xc7,
+ [KEY_END] = 0xcf,
+ [KEY_PAGEUP] = 0xc9,
+ [KEY_PAGEDOWN] = 0xd1,
+
+ [KEY_UP] = 0xc8,
+ [KEY_LEFT] = 0xcb,
+ [KEY_RIGHT] = 0xcd,
+ [KEY_DOWN] = 0xd0,
+
+ [KEY_NUMLOCK] = 0x45,
+ [KEY_KPSLASH] = 0xb5,
+ [KEY_KPASTERISK] = 0x37,
+ [KEY_KP7] = 0x47,
+ [KEY_KP8] = 0x48,
+ [KEY_KP9] = 0x49,
+ [KEY_KPMINUS] = 0x4a,
+ [KEY_KP4] = 0x4b,
+ [KEY_KP5] = 0x4c,
+ [KEY_KP6] = 0x4d,
+ [KEY_KPPLUS] = 0x4e,
+ [KEY_KP1] = 0x4f,
+ [KEY_KP2] = 0x50,
+ [KEY_KP3] = 0x51,
+ [KEY_KP0] = 0x52,
+ [KEY_KPDOT] = 0x53,
+ [KEY_KPENTER] = 0x9c,
+};
+
+static const struct keysym_map {
+ int normal, shifted;
+} keysym_map_en_us[KEY_CNT] = {
+ [KEY_A] = { .normal = 'a', .shifted = 'A' },
+ [KEY_B] = { .normal = 'b', .shifted = 'B' },
+ [KEY_C] = { .normal = 'c', .shifted = 'C' },
+ [KEY_D] = { .normal = 'd', .shifted = 'D' },
+ [KEY_E] = { .normal = 'e', .shifted = 'E' },
+ [KEY_F] = { .normal = 'f', .shifted = 'F' },
+ [KEY_G] = { .normal = 'g', .shifted = 'G' },
+ [KEY_H] = { .normal = 'h', .shifted = 'H' },
+ [KEY_I] = { .normal = 'i', .shifted = 'I' },
+ [KEY_J] = { .normal = 'j', .shifted = 'J' },
+ [KEY_K] = { .normal = 'k', .shifted = 'K' },
+ [KEY_L] = { .normal = 'l', .shifted = 'L' },
+ [KEY_M] = { .normal = 'm', .shifted = 'M' },
+ [KEY_N] = { .normal = 'n', .shifted = 'N' },
+ [KEY_O] = { .normal = 'o', .shifted = 'O' },
+ [KEY_P] = { .normal = 'p', .shifted = 'P' },
+ [KEY_Q] = { .normal = 'q', .shifted = 'Q' },
+ [KEY_R] = { .normal = 'r', .shifted = 'R' },
+ [KEY_S] = { .normal = 's', .shifted = 'S' },
+ [KEY_T] = { .normal = 't', .shifted = 'T' },
+ [KEY_U] = { .normal = 'u', .shifted = 'U' },
+ [KEY_V] = { .normal = 'v', .shifted = 'V' },
+ [KEY_W] = { .normal = 'w', .shifted = 'W' },
+ [KEY_X] = { .normal = 'x', .shifted = 'X' },
+ [KEY_Y] = { .normal = 'y', .shifted = 'Y' },
+ [KEY_Z] = { .normal = 'z', .shifted = 'Z' },
+
+ [KEY_1] = { .normal = '1', .shifted = '!' },
+ [KEY_2] = { .normal = '2', .shifted = '@' },
+ [KEY_3] = { .normal = '3', .shifted = '#' },
+ [KEY_4] = { .normal = '4', .shifted = '$' },
+ [KEY_5] = { .normal = '5', .shifted = '%' },
+ [KEY_6] = { .normal = '6', .shifted = '^' },
+ [KEY_7] = { .normal = '7', .shifted = '&' },
+ [KEY_8] = { .normal = '8', .shifted = '*' },
+ [KEY_9] = { .normal = '9', .shifted = '(' },
+ [KEY_0] = { .normal = '0', .shifted = ')' },
+
+ [KEY_MINUS] = { .normal = '-', .shifted = '_' },
+ [KEY_EQUAL] = { .normal = '=', .shifted = '+' },
+ [KEY_TAB] = { .normal = '\t' },
+ [KEY_LEFTBRACE] = { .normal = '[', .shifted = '{' },
+ [KEY_RIGHTBRACE] = { .normal = ']', .shifted = '}' },
+ [KEY_ENTER] = { .normal = '\n', },
+ [KEY_SEMICOLON] = { .normal = ';', .shifted = ':' },
+ [KEY_APOSTROPHE] = { .normal = '"', .shifted = '\'' },
+ [KEY_BACKSLASH] = { .normal = '\\', .shifted = '|' },
+ [KEY_COMMA] = { .normal = ',', .shifted = '<' },
+ [KEY_DOT] = { .normal = '.', .shifted = '>' },
+ [KEY_SLASH] = { .normal = '/', .shifted = '?' },
+ [KEY_SPACE] = { .normal = ' ' },
+
+ [KEY_BACKSPACE] = { .normal = QEMU_KEY_BACKSPACE },
+ [KEY_UP] = { .normal = QEMU_KEY_UP },
+ [KEY_DOWN] = { .normal = QEMU_KEY_DOWN },
+ [KEY_LEFT] = { .normal = QEMU_KEY_LEFT },
+ [KEY_RIGHT] = { .normal = QEMU_KEY_RIGHT },
+};
+
+static void start_mediumraw(int tty)
+{
+ struct termios tattr;
+
+ if (tty_mediumraw) {
+ return;
+ }
+ trace_fbdev_kbd_raw(1);
+
+ /* save state */
+ tcgetattr(tty, &tty_attributes);
+ ioctl(tty, KDGKBMODE, &tty_mode);
+ tty_flags = fcntl(tty, F_GETFL, NULL);
+
+ /* setup */
+ tattr = tty_attributes;
+ tattr.c_cflag &= ~(IXON|IXOFF);
+ tattr.c_lflag &= ~(ICANON|ECHO|ISIG);
+ tattr.c_iflag = 0;
+ tattr.c_cc[VMIN] = 1;
+ tattr.c_cc[VTIME] = 0;
+ tcsetattr(tty, TCSAFLUSH, &tattr);
+ ioctl(tty, KDSKBMODE, K_MEDIUMRAW);
+ fcntl(tty, F_SETFL, tty_flags | O_NONBLOCK);
+
+ tty_mediumraw = true;
+}
+
+static void stop_mediumraw(int tty)
+{
+ if (!tty_mediumraw) {
+ return;
+ }
+ trace_fbdev_kbd_raw(0);
+
+ /* restore state */
+ tcsetattr(tty, TCSANOW, &tty_attributes);
+ ioctl(tty, KDSKBMODE, tty_mode);
+ fcntl(tty, F_SETFL, tty_flags);
+
+ tty_mediumraw = false;
+}
+
+static void send_scancode(int keycode, int up)
+{
+ int scancode = scancode_map[keycode];
+
+ if (!scancode) {
+ fprintf(stderr, "%s: unmapped key: 0x%x %s\n",
+ __func__, keycode, keynames[keycode]);
+ return;
+ }
+ if (scancode & SCANCODE_GREY) {
+ kbd_put_keycode(SCANCODE_EMUL0);
+ }
+ if (up) {
+ kbd_put_keycode(scancode | SCANCODE_UP);
+ } else {
+ kbd_put_keycode(scancode & SCANCODE_KEYCODEMASK);
+ }
+}
+
+static void send_keysym(int keycode, int shift)
+{
+ const struct keysym_map *keysym_map = keysym_map_en_us;
+ int keysym;
+
+ if (shift && keysym_map[keycode].shifted) {
+ keysym = keysym_map[keycode].shifted;
+ } else if (keysym_map[keycode].normal) {
+ keysym = keysym_map[keycode].normal;
+ } else {
+ fprintf(stderr, "%s: unmapped key: 0x%x %s\n",
+ __func__, keycode, keynames[keycode]);
+ return;
+ }
+ kbd_put_keysym(keysym);
+}
+
+static void reset_keys(void)
+{
+ int keycode;
+
+ for (keycode = 0; keycode < KEY_MAX; keycode++) {
+ if (key_down[keycode]) {
+ if (is_graphic_console()) {
+ send_scancode(keycode, 1);
+ }
+ key_down[keycode] = false;
+ }
+ }
+}
+
+static void read_mediumraw(void *opaque)
+{
+ uint8_t buf[32];
+ int i, rc, up, keycode;
+ bool ctrl, alt, shift;
+
+ rc = read(tty, buf, sizeof(buf));
+ switch (rc) {
+ case -1:
+ perror("read tty");
+ goto err;
+ case 0:
+ fprintf(stderr, "%s: eof\n", __func__);
+ goto err;
+ default:
+ for (i = 0; i < rc; i++) {
+ up = buf[i] & 0x80;
+ keycode = buf[i] & 0x7f;
+ if (keycode == 0) {
+ keycode = (buf[i+1] & 0x7f) << 7;
+ keycode |= buf[i+2] & 0x7f;
+ i += 2;
+ }
+ if (keycode > KEY_MAX) {
+ continue;
+ }
+
+ if (up) {
+ if (!key_down[keycode]) {
+ continue;
+ }
+ key_down[keycode] = false;
+ } else {
+ key_down[keycode] = true;
+ }
+
+ trace_fbdev_kbd_event(keycode, keynames[keycode], !up);
+
+ alt = key_down[KEY_LEFTALT] || key_down[KEY_RIGHTALT];
+ ctrl = key_down[KEY_LEFTCTRL] || key_down[KEY_RIGHTCTRL];
+ shift = key_down[KEY_LEFTSHIFT] || key_down[KEY_RIGHTSHIFT];
+
+ if (ctrl && alt && !up) {
+ if (keycode == KEY_ESC) {
+ fprintf(stderr, "=== fbdev emergency escape "
+ "(ctrl-alt-esc) ===\n");
+ exit(1);
+ }
+ if (keycode >= KEY_F1 && keycode <= KEY_F10) {
+ fbdev_activate_vt(tty, keycode+1-KEY_F1, false);
+ key_down[keycode] = false;
+ continue;
+ }
+ if (keycode >= KEY_1 && keycode <= KEY_9) {
+ console_select(keycode-KEY_1);
+ reset_keys();
+ continue;
+ }
+ }
+
+ if (is_graphic_console()) {
+ send_scancode(keycode, up);
+ } else if (!up) {
+ send_keysym(keycode, shift);
+ }
+ }
+ }
+ return;
+
+err:
+ exit(1);
+}
+
+/* -------------------------------------------------------------------- */
+
+static void fbdev_cls(void)
+{
+ memset(fb_mem + fb_mem_offset, 0, fb_fix.line_length * fb_var.yres);
+}
+
+static int fbdev_activate_vt(int tty, int vtno, bool wait)
+{
+ trace_fbdev_vt_activate(vtno, wait);
+
+ if (ioctl(tty, VT_ACTIVATE, vtno) < 0) {
+ perror("ioctl VT_ACTIVATE");
+ return -1;
+ }
+
+ if (wait) {
+ if (ioctl(tty, VT_WAITACTIVE, vtno) < 0) {
+ perror("ioctl VT_WAITACTIVE");
+ return -1;
+ }
+ trace_fbdev_vt_activated();
+ }
+
+ return 0;
+}
+
+static void fbdev_cleanup(void)
+{
+ trace_fbdev_cleanup();
+
+ /* restore console */
+ if (fb_mem != NULL) {
+ munmap(fb_mem, fb_fix.smem_len+fb_mem_offset);
+ fb_mem = NULL;
+ }
+ if (fb != -1) {
+ if (ioctl(fb, FBIOPUT_VSCREENINFO, &fb_ovar) < 0) {
+ perror("ioctl FBIOPUT_VSCREENINFO");
+ }
+ close(fb);
+ fb = -1;
+ }
+
+ if (tty != -1) {
+ stop_mediumraw(tty);
+ if (ioctl(tty, KDSETMODE, kd_omode) < 0) {
+ perror("ioctl KDSETMODE");
+ }
+ if (ioctl(tty, VT_SETMODE, &vt_omode) < 0) {
+ perror("ioctl VT_SETMODE");
+ }
+ if (orig_vtno) {
+ fbdev_activate_vt(tty, orig_vtno, true);
+ }
+ qemu_set_fd_handler(tty, NULL, NULL, NULL);
+ close(tty);
+ tty = -1;
+ }
+}
+
+static int fbdev_init(const char *device)
+{
+ struct vt_stat vts;
+ unsigned long page_mask;
+ char ttyname[32];
+
+ /* open framebuffer */
+ if (device == NULL) {
+ device = getenv("FRAMEBUFFER");
+ }
+ if (device == NULL) {
+ device = "/dev/fb0";
+ }
+ fb = open(device, O_RDWR);
+ if (fb == -1) {
+ fprintf(stderr, "open %s: %s\n", device, strerror(errno));
+ return -1;
+ }
+
+ /* open virtual console */
+ tty = 0;
+ if (ioctl(tty, VT_GETSTATE, &vts) < 0) {
+ fprintf(stderr, "Not started from virtual terminal, "
+ "trying to open one.\n");
+
+ snprintf(ttyname, sizeof(ttyname), "/dev/tty0");
+ tty = open(ttyname, O_RDWR);
+ if (tty == -1) {
+ fprintf(stderr, "open %s: %s\n", ttyname, strerror(errno));
+ goto err_early;
+ }
+ if (ioctl(tty, VT_OPENQRY, &vtno) < 0) {
+ perror("ioctl VT_OPENQRY");
+ goto err_early;
+ }
+ if (ioctl(tty, VT_GETSTATE, &vts) < 0) {
+ perror("ioctl VT_GETSTATE\n");
+ goto err_early;
+ }
+ close(tty);
+
+ snprintf(ttyname, sizeof(ttyname), "/dev/tty%d", vtno);
+ tty = open(ttyname, O_RDWR);
+ if (tty == -1) {
+ fprintf(stderr, "open %s: %s\n", ttyname, strerror(errno));
+ goto err_early;
+ }
+ orig_vtno = vts.v_active;
+ fprintf(stderr, "Switching to vt %d (current %d).\n", vtno, orig_vtno);
+ } else {
+ orig_vtno = 0;
+ vtno = vts.v_active;
+ fprintf(stderr, "Started at vt %d, using it.\n", vtno);
+ }
+ fbdev_activate_vt(tty, vtno, true);
+
+ /* get current settings (which we have to restore) */
+ if (ioctl(fb, FBIOGET_VSCREENINFO, &fb_ovar) < 0) {
+ perror("ioctl FBIOGET_VSCREENINFO");
+ goto err_early;
+ }
+ if (ioctl(tty, KDGETMODE, &kd_omode) < 0) {
+ perror("ioctl KDGETMODE");
+ goto err_early;
+ }
+ if (ioctl(tty, VT_GETMODE, &vt_omode) < 0) {
+ perror("ioctl VT_GETMODE");
+ goto err_early;
+ }
+
+ /* checks & initialisation */
+ if (ioctl(fb, FBIOGET_FSCREENINFO, &fb_fix) < 0) {
+ perror("ioctl FBIOGET_FSCREENINFO");
+ goto err;
+ }
+ if (ioctl(fb, FBIOGET_VSCREENINFO, &fb_var) < 0) {
+ perror("ioctl FBIOGET_VSCREENINFO");
+ goto err;
+ }
+ if (fb_fix.type != FB_TYPE_PACKED_PIXELS) {
+ fprintf(stderr, "can handle only packed pixel frame buffers\n");
+ goto err;
+ }
+ switch (fb_var.bits_per_pixel) {
+ case 32:
+ break;
+ default:
+ fprintf(stderr, "can't handle %d bpp frame buffers\n",
+ fb_var.bits_per_pixel);
+ goto err;
+ }
+
+ page_mask = getpagesize()-1;
+ fb_switch_state = FB_ACTIVE;
+ fb_mem_offset = (unsigned long)(fb_fix.smem_start) & page_mask;
+ fb_mem = mmap(NULL, fb_fix.smem_len+fb_mem_offset,
+ PROT_READ|PROT_WRITE, MAP_SHARED, fb, 0);
+ if (fb_mem == MAP_FAILED) {
+ perror("mmap");
+ goto err;
+ }
+ /* move viewport to upper left corner */
+ if (fb_var.xoffset != 0 || fb_var.yoffset != 0) {
+ fb_var.xoffset = 0;
+ fb_var.yoffset = 0;
+ if (ioctl(fb, FBIOPAN_DISPLAY, &fb_var) < 0) {
+ perror("ioctl FBIOPAN_DISPLAY");
+ goto err;
+ }
+ }
+ if (ioctl(tty, KDSETMODE, KD_GRAPHICS) < 0) {
+ perror("ioctl KDSETMODE");
+ goto err;
+ }
+ /* some fb drivers need this again after switching to graphics ... */
+ fbdev_activate_vt(tty, vtno, true);
+
+ fbdev_cls();
+
+ start_mediumraw(tty);
+ qemu_set_fd_handler(tty, read_mediumraw, NULL, NULL);
+
+ /* create PixelFormat from fbdev structs */
+ fbpf.bits_per_pixel = fb_var.bits_per_pixel;
+ fbpf.bytes_per_pixel = (fb_var.bits_per_pixel+7)/8;
+ fbpf.depth = fb_var.bits_per_pixel == 32
+ ? 24 : fb_var.bits_per_pixel;
+ fbpf.rshift = fb_var.red.offset;
+ fbpf.rbits = fb_var.red.length;
+ fbpf.gshift = fb_var.green.offset;
+ fbpf.gbits = fb_var.green.length;
+ fbpf.bshift = fb_var.blue.offset;
+ fbpf.bbits = fb_var.blue.length;
+ fbpf.ashift = fb_var.transp.offset;
+ fbpf.abits = fb_var.transp.length;
+
+ if (fbpf.rbits) {
+ fbpf.rmax = (1 << fbpf.rbits) - 1;
+ fbpf.rmask = fbpf.rmax << fbpf.rshift;
+ }
+ if (fbpf.gbits) {
+ fbpf.gmax = (1 << fbpf.gbits) - 1;
+ fbpf.gmask = fbpf.gmax << fbpf.gshift;
+ }
+ if (fbpf.bbits) {
+ fbpf.bmax = (1 << fbpf.bbits) - 1;
+ fbpf.bmask = fbpf.bmax << fbpf.bshift;
+ }
+ if (fbpf.abits) {
+ fbpf.amax = (1 << fbpf.abits) - 1;
+ fbpf.amask = fbpf.amax << fbpf.ashift;
+ }
+ return 0;
+
+err_early:
+ if (tty > 0) {
+ close(tty);
+ }
+ close(fb);
+ return -1;
+
+err:
+ fbdev_cleanup();
+ return -1;
+}
+
+static void
+fbdev_catch_fatal_signal(int signr)
+{
+ fprintf(stderr, "%s: %s, restoring linux console state ...\n",
+ __func__, strsignal(signr));
+ fbdev_cleanup();
+ signal(SIGABRT, SIG_DFL);
+ fprintf(stderr, "%s: ... done, going abort() now.\n", __func__);
+ abort();
+}
+
+static void fbdev_catch_exit_signals(void)
+{
+ static const int signals[] = {
+ SIGQUIT, SIGILL, SIGABRT, SIGFPE, SIGSEGV, SIGBUS
+ };
+ struct sigaction act, old;
+ int i;
+
+ memset(&act, 0, sizeof(act));
+ act.sa_handler = fbdev_catch_fatal_signal;
+ act.sa_flags = SA_RESETHAND;
+ sigemptyset(&act.sa_mask);
+ for (i = 0; i < ARRAY_SIZE(signals); i++) {
+ sigaction(signals[i], &act, &old);
+ }
+}
+
+/* -------------------------------------------------------------------- */
+/* console switching */
+
+static void fbdev_switch_signal(int signal)
+{
+ if (signal == SIG_REL) {
+ /* release */
+ trace_fbdev_vt_release_request();
+ fb_switch_state = FB_REL_REQ;
+ }
+ if (signal == SIG_ACQ) {
+ /* acquisition */
+ trace_fbdev_vt_aquire_request();
+ fb_switch_state = FB_ACQ_REQ;
+ }
+}
+
+static void fbdev_switch_release(void)
+{
+ stop_mediumraw(tty);
+ ioctl(tty, KDSETMODE, kd_omode);
+ ioctl(tty, VT_RELDISP, 1);
+ fb_switch_state = FB_INACTIVE;
+ trace_fbdev_vt_released();
+}
+
+static void fbdev_switch_acquire(void)
+{
+ ioctl(tty, VT_RELDISP, VT_ACKACQ);
+ start_mediumraw(tty);
+ reset_keys();
+ ioctl(tty, KDSETMODE, KD_GRAPHICS);
+ fb_switch_state = FB_ACTIVE;
+ trace_fbdev_vt_aquired();
+}
+
+static int fbdev_switch_init(void)
+{
+ struct sigaction act, old;
+
+ memset(&act, 0, sizeof(act));
+ act.sa_handler = fbdev_switch_signal;
+ sigemptyset(&act.sa_mask);
+ sigaction(SIG_REL, &act, &old);
+ sigaction(SIG_ACQ, &act, &old);
+
+ if (ioctl(tty, VT_GETMODE, &vt_mode) < 0) {
+ perror("ioctl VT_GETMODE");
+ exit(1);
+ }
+ vt_mode.mode = VT_PROCESS;
+ vt_mode.waitv = 0;
+ vt_mode.relsig = SIG_REL;
+ vt_mode.acqsig = SIG_ACQ;
+
+ if (ioctl(tty, VT_SETMODE, &vt_mode) < 0) {
+ perror("ioctl VT_SETMODE");
+ exit(1);
+ }
+ return 0;
+}
+
+/* -------------------------------------------------------------------- */
+/* rendering */
+
+static void fbdev_render(DisplayState *ds, int x, int y, int w, int h)
+{
+ uint8_t *dst;
+ uint8_t *src;
+ int line;
+
+ if (!conv) {
+ return;
+ }
+
+ src = ds_get_data(ds) + y * ds_get_linesize(ds)
+ + x * ds_get_bytes_per_pixel(ds);
+ dst = fb_mem + y * fb_fix.line_length
+ + x * fbpf.bytes_per_pixel;
+
+ dst += cy * fb_fix.line_length;
+ dst += cx * fbpf.bytes_per_pixel;
+
+ if (h > fb_var.yres - y) {
+ h = fb_var.yres - y;
+ }
+ if (w > fb_var.xres - x) {
+ w = fb_var.xres - x;
+ }
+
+ for (line = y; line < y+h; line++) {
+ qemu_pf_conv_run(conv, dst, src, w);
+ dst += fb_fix.line_length;
+ src += ds_get_linesize(ds);
+ }
+}
+
+/* -------------------------------------------------------------------- */
+/* qemu interfaces */
+
+static void fbdev_update(DisplayState *ds, int x, int y, int w, int h)
+{
+ if (fb_switch_state != FB_ACTIVE) {
+ return;
+ }
+
+ if (resize_screen) {
+ trace_fbdev_dpy_resize(ds_get_width(ds), ds_get_height(ds));
+ resize_screen = 0;
+ cx = 0; cy = 0;
+ cw = ds_get_width(ds);
+ ch = ds_get_height(ds);
+ if (ds_get_width(ds) < fb_var.xres) {
+ cx = (fb_var.xres - ds_get_width(ds)) / 2;
+ }
+ if (ds_get_height(ds) < fb_var.yres) {
+ cy = (fb_var.yres - ds_get_height(ds)) / 2;
+ }
+
+ if (conv) {
+ qemu_pf_conv_put(conv);
+ }
+ conv = qemu_pf_conv_get(&fbpf, &ds->surface->pf);
+ if (conv == NULL) {
+ fprintf(stderr, "fbdev: unsupported PixelFormat conversion\n");
+ }
+ }
+
+ if (redraw_screen) {
+ trace_fbdev_dpy_redraw();
+ redraw_screen = 0;
+ fbdev_cls();
+ x = 0; y = 0; w = ds_get_width(ds); h = ds_get_height(ds);
+ }
+
+ fbdev_render(ds, x, y, w, h);
+}
+
+static void fbdev_resize(DisplayState *ds)
+{
+ resize_screen++;
+ redraw_screen++;
+}
+
+static void fbdev_setdata(DisplayState *ds)
+{
+ if (surface) {
+ pixman_image_unref(surface);
+ }
+ surface = pixman_from_displaystate(ds);
+ redraw_screen++;
+}
+
+static void fbdev_refresh(DisplayState *ds)
+{
+ switch (fb_switch_state) {
+ case FB_REL_REQ:
+ fbdev_switch_release();
+ case FB_INACTIVE:
+ return;
+ case FB_ACQ_REQ:
+ fbdev_switch_acquire();
+ redraw_screen++;
+ case FB_ACTIVE:
+ break;
+ }
+
+ vga_hw_update();
+ if (redraw_screen) {
+ fbdev_update(ds, 0, 0, 0, 0);
+ }
+}
+
+static void fbdev_exit_notifier(Notifier *notifier, void *data)
+{
+ fbdev_cleanup();
+}
+
+int fbdev_display_init(DisplayState *ds, const char *device)
+{
+ if (dcl != NULL) {
+ return 0;
+ }
+
+ if (fbdev_init(device) != 0) {
+ return -1;
+ }
+ exit_notifier.notify = fbdev_exit_notifier;
+ qemu_add_exit_notifier(&exit_notifier);
+ fbdev_switch_init();
+ fbdev_catch_exit_signals();
+ init_mouse();
+
+ fbdev_resize(ds);
+ dcl = g_new0(DisplayChangeListener, 1);
+ dcl->dpy_update = fbdev_update;
+ dcl->dpy_resize = fbdev_resize;
+ dcl->dpy_setdata = fbdev_setdata;
+ dcl->dpy_refresh = fbdev_refresh;
+ register_displaychangelistener(ds, dcl);
+
+ trace_fbdev_enabled();
+ return 0;
+}
+
+void fbdev_display_uninit(DisplayState *ds)
+{
+ if (dcl == NULL) {
+ return;
+ }
+
+ unregister_displaychangelistener(ds, dcl);
+ g_free(dcl);
+ dcl = NULL;
+
+ fbdev_cleanup();
+ qemu_remove_exit_notifier(&exit_notifier);
+ uninit_mouse();
+}
diff --git a/ui/linux-keynames.h b/ui/linux-keynames.h
new file mode 100644
index 0000000..058af28
--- /dev/null
+++ b/ui/linux-keynames.h
@@ -0,0 +1,388 @@
+/*
+ * awk '/#define KEY_/ { printf(" [%s] = \"%s\",\n",$2,$2); }' \
+ * /usr/include/linux/input.h
+ */
+ [KEY_RESERVED] = "KEY_RESERVED",
+ [KEY_ESC] = "KEY_ESC",
+ [KEY_1] = "KEY_1",
+ [KEY_2] = "KEY_2",
+ [KEY_3] = "KEY_3",
+ [KEY_4] = "KEY_4",
+ [KEY_5] = "KEY_5",
+ [KEY_6] = "KEY_6",
+ [KEY_7] = "KEY_7",
+ [KEY_8] = "KEY_8",
+ [KEY_9] = "KEY_9",
+ [KEY_0] = "KEY_0",
+ [KEY_MINUS] = "KEY_MINUS",
+ [KEY_EQUAL] = "KEY_EQUAL",
+ [KEY_BACKSPACE] = "KEY_BACKSPACE",
+ [KEY_TAB] = "KEY_TAB",
+ [KEY_Q] = "KEY_Q",
+ [KEY_W] = "KEY_W",
+ [KEY_E] = "KEY_E",
+ [KEY_R] = "KEY_R",
+ [KEY_T] = "KEY_T",
+ [KEY_Y] = "KEY_Y",
+ [KEY_U] = "KEY_U",
+ [KEY_I] = "KEY_I",
+ [KEY_O] = "KEY_O",
+ [KEY_P] = "KEY_P",
+ [KEY_LEFTBRACE] = "KEY_LEFTBRACE",
+ [KEY_RIGHTBRACE] = "KEY_RIGHTBRACE",
+ [KEY_ENTER] = "KEY_ENTER",
+ [KEY_LEFTCTRL] = "KEY_LEFTCTRL",
+ [KEY_A] = "KEY_A",
+ [KEY_S] = "KEY_S",
+ [KEY_D] = "KEY_D",
+ [KEY_F] = "KEY_F",
+ [KEY_G] = "KEY_G",
+ [KEY_H] = "KEY_H",
+ [KEY_J] = "KEY_J",
+ [KEY_K] = "KEY_K",
+ [KEY_L] = "KEY_L",
+ [KEY_SEMICOLON] = "KEY_SEMICOLON",
+ [KEY_APOSTROPHE] = "KEY_APOSTROPHE",
+ [KEY_GRAVE] = "KEY_GRAVE",
+ [KEY_LEFTSHIFT] = "KEY_LEFTSHIFT",
+ [KEY_BACKSLASH] = "KEY_BACKSLASH",
+ [KEY_Z] = "KEY_Z",
+ [KEY_X] = "KEY_X",
+ [KEY_C] = "KEY_C",
+ [KEY_V] = "KEY_V",
+ [KEY_B] = "KEY_B",
+ [KEY_N] = "KEY_N",
+ [KEY_M] = "KEY_M",
+ [KEY_COMMA] = "KEY_COMMA",
+ [KEY_DOT] = "KEY_DOT",
+ [KEY_SLASH] = "KEY_SLASH",
+ [KEY_RIGHTSHIFT] = "KEY_RIGHTSHIFT",
+ [KEY_KPASTERISK] = "KEY_KPASTERISK",
+ [KEY_LEFTALT] = "KEY_LEFTALT",
+ [KEY_SPACE] = "KEY_SPACE",
+ [KEY_CAPSLOCK] = "KEY_CAPSLOCK",
+ [KEY_F1] = "KEY_F1",
+ [KEY_F2] = "KEY_F2",
+ [KEY_F3] = "KEY_F3",
+ [KEY_F4] = "KEY_F4",
+ [KEY_F5] = "KEY_F5",
+ [KEY_F6] = "KEY_F6",
+ [KEY_F7] = "KEY_F7",
+ [KEY_F8] = "KEY_F8",
+ [KEY_F9] = "KEY_F9",
+ [KEY_F10] = "KEY_F10",
+ [KEY_NUMLOCK] = "KEY_NUMLOCK",
+ [KEY_SCROLLLOCK] = "KEY_SCROLLLOCK",
+ [KEY_KP7] = "KEY_KP7",
+ [KEY_KP8] = "KEY_KP8",
+ [KEY_KP9] = "KEY_KP9",
+ [KEY_KPMINUS] = "KEY_KPMINUS",
+ [KEY_KP4] = "KEY_KP4",
+ [KEY_KP5] = "KEY_KP5",
+ [KEY_KP6] = "KEY_KP6",
+ [KEY_KPPLUS] = "KEY_KPPLUS",
+ [KEY_KP1] = "KEY_KP1",
+ [KEY_KP2] = "KEY_KP2",
+ [KEY_KP3] = "KEY_KP3",
+ [KEY_KP0] = "KEY_KP0",
+ [KEY_KPDOT] = "KEY_KPDOT",
+ [KEY_ZENKAKUHANKAKU] = "KEY_ZENKAKUHANKAKU",
+ [KEY_102ND] = "KEY_102ND",
+ [KEY_F11] = "KEY_F11",
+ [KEY_F12] = "KEY_F12",
+ [KEY_RO] = "KEY_RO",
+ [KEY_KATAKANA] = "KEY_KATAKANA",
+ [KEY_HIRAGANA] = "KEY_HIRAGANA",
+ [KEY_HENKAN] = "KEY_HENKAN",
+ [KEY_KATAKANAHIRAGANA] = "KEY_KATAKANAHIRAGANA",
+ [KEY_MUHENKAN] = "KEY_MUHENKAN",
+ [KEY_KPJPCOMMA] = "KEY_KPJPCOMMA",
+ [KEY_KPENTER] = "KEY_KPENTER",
+ [KEY_RIGHTCTRL] = "KEY_RIGHTCTRL",
+ [KEY_KPSLASH] = "KEY_KPSLASH",
+ [KEY_SYSRQ] = "KEY_SYSRQ",
+ [KEY_RIGHTALT] = "KEY_RIGHTALT",
+ [KEY_LINEFEED] = "KEY_LINEFEED",
+ [KEY_HOME] = "KEY_HOME",
+ [KEY_UP] = "KEY_UP",
+ [KEY_PAGEUP] = "KEY_PAGEUP",
+ [KEY_LEFT] = "KEY_LEFT",
+ [KEY_RIGHT] = "KEY_RIGHT",
+ [KEY_END] = "KEY_END",
+ [KEY_DOWN] = "KEY_DOWN",
+ [KEY_PAGEDOWN] = "KEY_PAGEDOWN",
+ [KEY_INSERT] = "KEY_INSERT",
+ [KEY_DELETE] = "KEY_DELETE",
+ [KEY_MACRO] = "KEY_MACRO",
+ [KEY_MUTE] = "KEY_MUTE",
+ [KEY_VOLUMEDOWN] = "KEY_VOLUMEDOWN",
+ [KEY_VOLUMEUP] = "KEY_VOLUMEUP",
+ [KEY_POWER] = "KEY_POWER",
+ [KEY_KPEQUAL] = "KEY_KPEQUAL",
+ [KEY_KPPLUSMINUS] = "KEY_KPPLUSMINUS",
+ [KEY_PAUSE] = "KEY_PAUSE",
+ [KEY_SCALE] = "KEY_SCALE",
+ [KEY_KPCOMMA] = "KEY_KPCOMMA",
+ [KEY_HANGEUL] = "KEY_HANGEUL",
+ [KEY_HANGUEL] = "KEY_HANGUEL",
+ [KEY_HANJA] = "KEY_HANJA",
+ [KEY_YEN] = "KEY_YEN",
+ [KEY_LEFTMETA] = "KEY_LEFTMETA",
+ [KEY_RIGHTMETA] = "KEY_RIGHTMETA",
+ [KEY_COMPOSE] = "KEY_COMPOSE",
+ [KEY_STOP] = "KEY_STOP",
+ [KEY_AGAIN] = "KEY_AGAIN",
+ [KEY_PROPS] = "KEY_PROPS",
+ [KEY_UNDO] = "KEY_UNDO",
+ [KEY_FRONT] = "KEY_FRONT",
+ [KEY_COPY] = "KEY_COPY",
+ [KEY_OPEN] = "KEY_OPEN",
+ [KEY_PASTE] = "KEY_PASTE",
+ [KEY_FIND] = "KEY_FIND",
+ [KEY_CUT] = "KEY_CUT",
+ [KEY_HELP] = "KEY_HELP",
+ [KEY_MENU] = "KEY_MENU",
+ [KEY_CALC] = "KEY_CALC",
+ [KEY_SETUP] = "KEY_SETUP",
+ [KEY_SLEEP] = "KEY_SLEEP",
+ [KEY_WAKEUP] = "KEY_WAKEUP",
+ [KEY_FILE] = "KEY_FILE",
+ [KEY_SENDFILE] = "KEY_SENDFILE",
+ [KEY_DELETEFILE] = "KEY_DELETEFILE",
+ [KEY_XFER] = "KEY_XFER",
+ [KEY_PROG1] = "KEY_PROG1",
+ [KEY_PROG2] = "KEY_PROG2",
+ [KEY_WWW] = "KEY_WWW",
+ [KEY_MSDOS] = "KEY_MSDOS",
+ [KEY_COFFEE] = "KEY_COFFEE",
+ [KEY_SCREENLOCK] = "KEY_SCREENLOCK",
+ [KEY_DIRECTION] = "KEY_DIRECTION",
+ [KEY_CYCLEWINDOWS] = "KEY_CYCLEWINDOWS",
+ [KEY_MAIL] = "KEY_MAIL",
+ [KEY_BOOKMARKS] = "KEY_BOOKMARKS",
+ [KEY_COMPUTER] = "KEY_COMPUTER",
+ [KEY_BACK] = "KEY_BACK",
+ [KEY_FORWARD] = "KEY_FORWARD",
+ [KEY_CLOSECD] = "KEY_CLOSECD",
+ [KEY_EJECTCD] = "KEY_EJECTCD",
+ [KEY_EJECTCLOSECD] = "KEY_EJECTCLOSECD",
+ [KEY_NEXTSONG] = "KEY_NEXTSONG",
+ [KEY_PLAYPAUSE] = "KEY_PLAYPAUSE",
+ [KEY_PREVIOUSSONG] = "KEY_PREVIOUSSONG",
+ [KEY_STOPCD] = "KEY_STOPCD",
+ [KEY_RECORD] = "KEY_RECORD",
+ [KEY_REWIND] = "KEY_REWIND",
+ [KEY_PHONE] = "KEY_PHONE",
+ [KEY_ISO] = "KEY_ISO",
+ [KEY_CONFIG] = "KEY_CONFIG",
+ [KEY_HOMEPAGE] = "KEY_HOMEPAGE",
+ [KEY_REFRESH] = "KEY_REFRESH",
+ [KEY_EXIT] = "KEY_EXIT",
+ [KEY_MOVE] = "KEY_MOVE",
+ [KEY_EDIT] = "KEY_EDIT",
+ [KEY_SCROLLUP] = "KEY_SCROLLUP",
+ [KEY_SCROLLDOWN] = "KEY_SCROLLDOWN",
+ [KEY_KPLEFTPAREN] = "KEY_KPLEFTPAREN",
+ [KEY_KPRIGHTPAREN] = "KEY_KPRIGHTPAREN",
+ [KEY_NEW] = "KEY_NEW",
+ [KEY_REDO] = "KEY_REDO",
+ [KEY_F13] = "KEY_F13",
+ [KEY_F14] = "KEY_F14",
+ [KEY_F15] = "KEY_F15",
+ [KEY_F16] = "KEY_F16",
+ [KEY_F17] = "KEY_F17",
+ [KEY_F18] = "KEY_F18",
+ [KEY_F19] = "KEY_F19",
+ [KEY_F20] = "KEY_F20",
+ [KEY_F21] = "KEY_F21",
+ [KEY_F22] = "KEY_F22",
+ [KEY_F23] = "KEY_F23",
+ [KEY_F24] = "KEY_F24",
+ [KEY_PLAYCD] = "KEY_PLAYCD",
+ [KEY_PAUSECD] = "KEY_PAUSECD",
+ [KEY_PROG3] = "KEY_PROG3",
+ [KEY_PROG4] = "KEY_PROG4",
+ [KEY_DASHBOARD] = "KEY_DASHBOARD",
+ [KEY_SUSPEND] = "KEY_SUSPEND",
+ [KEY_CLOSE] = "KEY_CLOSE",
+ [KEY_PLAY] = "KEY_PLAY",
+ [KEY_FASTFORWARD] = "KEY_FASTFORWARD",
+ [KEY_BASSBOOST] = "KEY_BASSBOOST",
+ [KEY_PRINT] = "KEY_PRINT",
+ [KEY_HP] = "KEY_HP",
+ [KEY_CAMERA] = "KEY_CAMERA",
+ [KEY_SOUND] = "KEY_SOUND",
+ [KEY_QUESTION] = "KEY_QUESTION",
+ [KEY_EMAIL] = "KEY_EMAIL",
+ [KEY_CHAT] = "KEY_CHAT",
+ [KEY_SEARCH] = "KEY_SEARCH",
+ [KEY_CONNECT] = "KEY_CONNECT",
+ [KEY_FINANCE] = "KEY_FINANCE",
+ [KEY_SPORT] = "KEY_SPORT",
+ [KEY_SHOP] = "KEY_SHOP",
+ [KEY_ALTERASE] = "KEY_ALTERASE",
+ [KEY_CANCEL] = "KEY_CANCEL",
+ [KEY_BRIGHTNESSDOWN] = "KEY_BRIGHTNESSDOWN",
+ [KEY_BRIGHTNESSUP] = "KEY_BRIGHTNESSUP",
+ [KEY_MEDIA] = "KEY_MEDIA",
+ [KEY_SWITCHVIDEOMODE] = "KEY_SWITCHVIDEOMODE",
+ [KEY_KBDILLUMTOGGLE] = "KEY_KBDILLUMTOGGLE",
+ [KEY_KBDILLUMDOWN] = "KEY_KBDILLUMDOWN",
+ [KEY_KBDILLUMUP] = "KEY_KBDILLUMUP",
+ [KEY_SEND] = "KEY_SEND",
+ [KEY_REPLY] = "KEY_REPLY",
+ [KEY_FORWARDMAIL] = "KEY_FORWARDMAIL",
+ [KEY_SAVE] = "KEY_SAVE",
+ [KEY_DOCUMENTS] = "KEY_DOCUMENTS",
+ [KEY_BATTERY] = "KEY_BATTERY",
+ [KEY_BLUETOOTH] = "KEY_BLUETOOTH",
+ [KEY_WLAN] = "KEY_WLAN",
+ [KEY_UWB] = "KEY_UWB",
+ [KEY_UNKNOWN] = "KEY_UNKNOWN",
+ [KEY_VIDEO_NEXT] = "KEY_VIDEO_NEXT",
+ [KEY_VIDEO_PREV] = "KEY_VIDEO_PREV",
+ [KEY_BRIGHTNESS_CYCLE] = "KEY_BRIGHTNESS_CYCLE",
+ [KEY_BRIGHTNESS_ZERO] = "KEY_BRIGHTNESS_ZERO",
+ [KEY_DISPLAY_OFF] = "KEY_DISPLAY_OFF",
+ [KEY_WIMAX] = "KEY_WIMAX",
+ [KEY_OK] = "KEY_OK",
+ [KEY_SELECT] = "KEY_SELECT",
+ [KEY_GOTO] = "KEY_GOTO",
+ [KEY_CLEAR] = "KEY_CLEAR",
+ [KEY_POWER2] = "KEY_POWER2",
+ [KEY_OPTION] = "KEY_OPTION",
+ [KEY_INFO] = "KEY_INFO",
+ [KEY_TIME] = "KEY_TIME",
+ [KEY_VENDOR] = "KEY_VENDOR",
+ [KEY_ARCHIVE] = "KEY_ARCHIVE",
+ [KEY_PROGRAM] = "KEY_PROGRAM",
+ [KEY_CHANNEL] = "KEY_CHANNEL",
+ [KEY_FAVORITES] = "KEY_FAVORITES",
+ [KEY_EPG] = "KEY_EPG",
+ [KEY_PVR] = "KEY_PVR",
+ [KEY_MHP] = "KEY_MHP",
+ [KEY_LANGUAGE] = "KEY_LANGUAGE",
+ [KEY_TITLE] = "KEY_TITLE",
+ [KEY_SUBTITLE] = "KEY_SUBTITLE",
+ [KEY_ANGLE] = "KEY_ANGLE",
+ [KEY_ZOOM] = "KEY_ZOOM",
+ [KEY_MODE] = "KEY_MODE",
+ [KEY_KEYBOARD] = "KEY_KEYBOARD",
+ [KEY_SCREEN] = "KEY_SCREEN",
+ [KEY_PC] = "KEY_PC",
+ [KEY_TV] = "KEY_TV",
+ [KEY_TV2] = "KEY_TV2",
+ [KEY_VCR] = "KEY_VCR",
+ [KEY_VCR2] = "KEY_VCR2",
+ [KEY_SAT] = "KEY_SAT",
+ [KEY_SAT2] = "KEY_SAT2",
+ [KEY_CD] = "KEY_CD",
+ [KEY_TAPE] = "KEY_TAPE",
+ [KEY_RADIO] = "KEY_RADIO",
+ [KEY_TUNER] = "KEY_TUNER",
+ [KEY_PLAYER] = "KEY_PLAYER",
+ [KEY_TEXT] = "KEY_TEXT",
+ [KEY_DVD] = "KEY_DVD",
+ [KEY_AUX] = "KEY_AUX",
+ [KEY_MP3] = "KEY_MP3",
+ [KEY_AUDIO] = "KEY_AUDIO",
+ [KEY_VIDEO] = "KEY_VIDEO",
+ [KEY_DIRECTORY] = "KEY_DIRECTORY",
+ [KEY_LIST] = "KEY_LIST",
+ [KEY_MEMO] = "KEY_MEMO",
+ [KEY_CALENDAR] = "KEY_CALENDAR",
+ [KEY_RED] = "KEY_RED",
+ [KEY_GREEN] = "KEY_GREEN",
+ [KEY_YELLOW] = "KEY_YELLOW",
+ [KEY_BLUE] = "KEY_BLUE",
+ [KEY_CHANNELUP] = "KEY_CHANNELUP",
+ [KEY_CHANNELDOWN] = "KEY_CHANNELDOWN",
+ [KEY_FIRST] = "KEY_FIRST",
+ [KEY_LAST] = "KEY_LAST",
+ [KEY_AB] = "KEY_AB",
+ [KEY_NEXT] = "KEY_NEXT",
+ [KEY_RESTART] = "KEY_RESTART",
+ [KEY_SLOW] = "KEY_SLOW",
+ [KEY_SHUFFLE] = "KEY_SHUFFLE",
+ [KEY_BREAK] = "KEY_BREAK",
+ [KEY_PREVIOUS] = "KEY_PREVIOUS",
+ [KEY_DIGITS] = "KEY_DIGITS",
+ [KEY_TEEN] = "KEY_TEEN",
+ [KEY_TWEN] = "KEY_TWEN",
+ [KEY_VIDEOPHONE] = "KEY_VIDEOPHONE",
+ [KEY_GAMES] = "KEY_GAMES",
+ [KEY_ZOOMIN] = "KEY_ZOOMIN",
+ [KEY_ZOOMOUT] = "KEY_ZOOMOUT",
+ [KEY_ZOOMRESET] = "KEY_ZOOMRESET",
+ [KEY_WORDPROCESSOR] = "KEY_WORDPROCESSOR",
+ [KEY_EDITOR] = "KEY_EDITOR",
+ [KEY_SPREADSHEET] = "KEY_SPREADSHEET",
+ [KEY_GRAPHICSEDITOR] = "KEY_GRAPHICSEDITOR",
+ [KEY_PRESENTATION] = "KEY_PRESENTATION",
+ [KEY_DATABASE] = "KEY_DATABASE",
+ [KEY_NEWS] = "KEY_NEWS",
+ [KEY_VOICEMAIL] = "KEY_VOICEMAIL",
+ [KEY_ADDRESSBOOK] = "KEY_ADDRESSBOOK",
+ [KEY_MESSENGER] = "KEY_MESSENGER",
+ [KEY_DISPLAYTOGGLE] = "KEY_DISPLAYTOGGLE",
+ [KEY_SPELLCHECK] = "KEY_SPELLCHECK",
+ [KEY_LOGOFF] = "KEY_LOGOFF",
+ [KEY_DOLLAR] = "KEY_DOLLAR",
+ [KEY_EURO] = "KEY_EURO",
+ [KEY_FRAMEBACK] = "KEY_FRAMEBACK",
+ [KEY_FRAMEFORWARD] = "KEY_FRAMEFORWARD",
+ [KEY_CONTEXT_MENU] = "KEY_CONTEXT_MENU",
+ [KEY_MEDIA_REPEAT] = "KEY_MEDIA_REPEAT",
+ [KEY_10CHANNELSUP] = "KEY_10CHANNELSUP",
+ [KEY_10CHANNELSDOWN] = "KEY_10CHANNELSDOWN",
+ [KEY_DEL_EOL] = "KEY_DEL_EOL",
+ [KEY_DEL_EOS] = "KEY_DEL_EOS",
+ [KEY_INS_LINE] = "KEY_INS_LINE",
+ [KEY_DEL_LINE] = "KEY_DEL_LINE",
+ [KEY_FN] = "KEY_FN",
+ [KEY_FN_ESC] = "KEY_FN_ESC",
+ [KEY_FN_F1] = "KEY_FN_F1",
+ [KEY_FN_F2] = "KEY_FN_F2",
+ [KEY_FN_F3] = "KEY_FN_F3",
+ [KEY_FN_F4] = "KEY_FN_F4",
+ [KEY_FN_F5] = "KEY_FN_F5",
+ [KEY_FN_F6] = "KEY_FN_F6",
+ [KEY_FN_F7] = "KEY_FN_F7",
+ [KEY_FN_F8] = "KEY_FN_F8",
+ [KEY_FN_F9] = "KEY_FN_F9",
+ [KEY_FN_F10] = "KEY_FN_F10",
+ [KEY_FN_F11] = "KEY_FN_F11",
+ [KEY_FN_F12] = "KEY_FN_F12",
+ [KEY_FN_1] = "KEY_FN_1",
+ [KEY_FN_2] = "KEY_FN_2",
+ [KEY_FN_D] = "KEY_FN_D",
+ [KEY_FN_E] = "KEY_FN_E",
+ [KEY_FN_F] = "KEY_FN_F",
+ [KEY_FN_S] = "KEY_FN_S",
+ [KEY_FN_B] = "KEY_FN_B",
+ [KEY_BRL_DOT1] = "KEY_BRL_DOT1",
+ [KEY_BRL_DOT2] = "KEY_BRL_DOT2",
+ [KEY_BRL_DOT3] = "KEY_BRL_DOT3",
+ [KEY_BRL_DOT4] = "KEY_BRL_DOT4",
+ [KEY_BRL_DOT5] = "KEY_BRL_DOT5",
+ [KEY_BRL_DOT6] = "KEY_BRL_DOT6",
+ [KEY_BRL_DOT7] = "KEY_BRL_DOT7",
+ [KEY_BRL_DOT8] = "KEY_BRL_DOT8",
+ [KEY_BRL_DOT9] = "KEY_BRL_DOT9",
+ [KEY_BRL_DOT10] = "KEY_BRL_DOT10",
+ [KEY_NUMERIC_0] = "KEY_NUMERIC_0",
+ [KEY_NUMERIC_1] = "KEY_NUMERIC_1",
+ [KEY_NUMERIC_2] = "KEY_NUMERIC_2",
+ [KEY_NUMERIC_3] = "KEY_NUMERIC_3",
+ [KEY_NUMERIC_4] = "KEY_NUMERIC_4",
+ [KEY_NUMERIC_5] = "KEY_NUMERIC_5",
+ [KEY_NUMERIC_6] = "KEY_NUMERIC_6",
+ [KEY_NUMERIC_7] = "KEY_NUMERIC_7",
+ [KEY_NUMERIC_8] = "KEY_NUMERIC_8",
+ [KEY_NUMERIC_9] = "KEY_NUMERIC_9",
+ [KEY_NUMERIC_STAR] = "KEY_NUMERIC_STAR",
+ [KEY_NUMERIC_POUND] = "KEY_NUMERIC_POUND",
+ [KEY_RFKILL] = "KEY_RFKILL",
+ [KEY_MIN_INTERESTING] = "KEY_MIN_INTERESTING",
+ [KEY_MAX] = "KEY_MAX",
+ [KEY_CNT] = "KEY_CNT",
diff --git a/vl.c b/vl.c
index fbb77fe..18982b2 100644
--- a/vl.c
+++ b/vl.c
@@ -3041,6 +3041,11 @@ int main(int argc, char **argv, char **envp)
fprintf(stderr, "SDL support is disabled\n");
exit(1);
#endif
+#ifdef CONFIG_LINUX
+ case QEMU_OPTION_fbdev:
+ display_type = DT_FBDEV;
+ break;
+#endif
case QEMU_OPTION_pidfile:
pid_file = optarg;
break;
@@ -3681,6 +3686,13 @@ int main(int argc, char **argv, char **envp)
curses_display_init(ds, full_screen);
break;
#endif
+#if defined(CONFIG_LINUX)
+ case DT_FBDEV:
+ if (fbdev_display_init(ds, NULL) != 0) {
+ exit(1);
+ }
+ break;
+#endif
#if defined(CONFIG_SDL)
case DT_SDL:
sdl_display_init(ds, full_screen, no_frame);
--
1.7.1
^ permalink raw reply related [flat|nested] 29+ messages in thread
* [Qemu-devel] [PATCH 5/9] fbdev: add monitor command to enable/disable
2012-09-18 7:17 [Qemu-devel] [PULL 0/9] linux framebuffer display driver Gerd Hoffmann
` (3 preceding siblings ...)
2012-09-18 7:17 ` [Qemu-devel] [PATCH 4/9] fbdev: add linux framebuffer display driver Gerd Hoffmann
@ 2012-09-18 7:17 ` Gerd Hoffmann
2012-09-18 12:47 ` Luiz Capitulino
2012-09-18 7:17 ` [Qemu-devel] [PATCH 6/9] fbdev: make configurable at compile time Gerd Hoffmann
` (3 subsequent siblings)
8 siblings, 1 reply; 29+ messages in thread
From: Gerd Hoffmann @ 2012-09-18 7:17 UTC (permalink / raw)
To: qemu-devel; +Cc: Gerd Hoffmann
This patch adds a fbdev monitor command to enable/disable
the fbdev display at runtime to both qmp and hmp.
qmp: fbdev enable=on|off
hmp: fbdev on|off
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
---
hmp-commands.hx | 15 +++++++++++++++
hmp.c | 9 +++++++++
hmp.h | 1 +
qapi-schema.json | 14 ++++++++++++++
qmp-commands.hx | 6 ++++++
qmp.c | 17 +++++++++++++++++
6 files changed, 62 insertions(+), 0 deletions(-)
diff --git a/hmp-commands.hx b/hmp-commands.hx
index ed67e99..366a92b 100644
--- a/hmp-commands.hx
+++ b/hmp-commands.hx
@@ -1377,6 +1377,21 @@ passed since 1970, i.e. unix epoch.
ETEXI
{
+ .name = "fbdev",
+ .args_type = "enable:b",
+ .params = "on|off",
+ .help = "enable/disable fbdev",
+ .mhandler.cmd = hmp_fbdev,
+ },
+
+STEXI
+@item fbdev on | off
+@findex fbdev
+
+enable/disable fbdev
+ETEXI
+
+ {
.name = "info",
.args_type = "item:s?",
.params = "[subcommand]",
diff --git a/hmp.c b/hmp.c
index ba6fbd3..a7feec5 100644
--- a/hmp.c
+++ b/hmp.c
@@ -1168,3 +1168,12 @@ void hmp_screen_dump(Monitor *mon, const QDict *qdict)
qmp_screendump(filename, &err);
hmp_handle_error(mon, &err);
}
+
+void hmp_fbdev(Monitor *mon, const QDict *qdict)
+{
+ int enable = qdict_get_bool(qdict, "enable");
+ Error *errp = NULL;
+
+ qmp_fbdev(enable, &errp);
+ hmp_handle_error(mon, &errp);
+}
diff --git a/hmp.h b/hmp.h
index 48b9c59..9c3d315 100644
--- a/hmp.h
+++ b/hmp.h
@@ -73,5 +73,6 @@ void hmp_getfd(Monitor *mon, const QDict *qdict);
void hmp_closefd(Monitor *mon, const QDict *qdict);
void hmp_send_key(Monitor *mon, const QDict *qdict);
void hmp_screen_dump(Monitor *mon, const QDict *qdict);
+void hmp_fbdev(Monitor *mon, const QDict *qdict);
#endif
diff --git a/qapi-schema.json b/qapi-schema.json
index 14e4419..901c2e8 100644
--- a/qapi-schema.json
+++ b/qapi-schema.json
@@ -2619,3 +2619,17 @@
# Since: 0.14.0
##
{ 'command': 'screendump', 'data': {'filename': 'str'} }
+
+# @fbdev:
+#
+# Enable/disable fbdev.
+#
+# @enable: whenever fbdev should be enabled or disabled.
+#
+# Returns: Nothing on success
+# GenericError on failure.
+#
+# Since: 1.3
+#
+##
+{ 'command': 'fbdev', 'data': {'enable': 'bool'} }
diff --git a/qmp-commands.hx b/qmp-commands.hx
index 6e21ddb..4b95fd0 100644
--- a/qmp-commands.hx
+++ b/qmp-commands.hx
@@ -2539,3 +2539,9 @@ EQMP
.args_type = "",
.mhandler.cmd_new = qmp_marshal_input_query_target,
},
+
+ {
+ .name = "fbdev",
+ .args_type = "enable:b",
+ .mhandler.cmd_new = qmp_marshal_input_fbdev,
+ },
diff --git a/qmp.c b/qmp.c
index 8463922..7f6cc0b 100644
--- a/qmp.c
+++ b/qmp.c
@@ -391,6 +391,23 @@ void qmp_change(const char *device, const char *target,
}
}
+void qmp_fbdev(bool enable, Error **errp)
+{
+#if defined(CONFIG_LINUX)
+ DisplayState *ds = get_displaystate();
+
+ if (enable) {
+ if (fbdev_display_init(ds, NULL) != 0) {
+ error_setg(errp, "fbdev initialization failed");
+ }
+ } else {
+ fbdev_display_uninit(ds);
+ }
+#else
+ error_set(errp, QERR_FEATURE_DISABLED, "fbdev");
+#endif
+}
+
static void qom_list_types_tramp(ObjectClass *klass, void *data)
{
ObjectTypeInfoList *e, **pret = data;
--
1.7.1
^ permalink raw reply related [flat|nested] 29+ messages in thread
* [Qemu-devel] [PATCH 6/9] fbdev: make configurable at compile time.
2012-09-18 7:17 [Qemu-devel] [PULL 0/9] linux framebuffer display driver Gerd Hoffmann
` (4 preceding siblings ...)
2012-09-18 7:17 ` [Qemu-devel] [PATCH 5/9] fbdev: add monitor command to enable/disable Gerd Hoffmann
@ 2012-09-18 7:17 ` Gerd Hoffmann
2012-09-18 7:17 ` [Qemu-devel] [PATCH 7/9] fbdev: move to pixman Gerd Hoffmann
` (2 subsequent siblings)
8 siblings, 0 replies; 29+ messages in thread
From: Gerd Hoffmann @ 2012-09-18 7:17 UTC (permalink / raw)
To: qemu-devel; +Cc: Gerd Hoffmann
Add CONFIG_FBDEV, add --enable-fbdev and --disable-fbdev
configure switches so fbdev can be enabled/disabled at
compile time.
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
---
configure | 12 ++++++++++++
qmp.c | 2 +-
ui/Makefile.objs | 2 +-
vl.c | 4 ++--
4 files changed, 16 insertions(+), 4 deletions(-)
diff --git a/configure b/configure
index 8564142..c4ba338 100755
--- a/configure
+++ b/configure
@@ -148,6 +148,7 @@ docs=""
fdt=""
nptl=""
sdl=""
+fbdev="no"
virtfs=""
vnc="yes"
sparse="no"
@@ -527,6 +528,7 @@ Haiku)
usb="linux"
kvm="yes"
vhost_net="yes"
+ fbdev="yes"
if [ "$cpu" = "i386" -o "$cpu" = "x86_64" ] ; then
audio_possible_drivers="$audio_possible_drivers fmod"
fi
@@ -658,6 +660,10 @@ for opt do
;;
--enable-sdl) sdl="yes"
;;
+ --disable-fbdev) fbdev="no"
+ ;;
+ --enable-fbdev) fbdev="yes"
+ ;;
--disable-virtfs) virtfs="no"
;;
--enable-virtfs) virtfs="yes"
@@ -1070,6 +1076,8 @@ echo " --disable-strip disable stripping binaries"
echo " --disable-werror disable compilation abort on warning"
echo " --disable-sdl disable SDL"
echo " --enable-sdl enable SDL"
+echo " --disable-fbdev disable linux framebuffer"
+echo " --enable-fbdev enable linux framebuffer"
echo " --disable-virtfs disable VirtFS"
echo " --enable-virtfs enable VirtFS"
echo " --disable-vnc disable VNC"
@@ -3159,6 +3167,7 @@ if test "$darwin" = "yes" ; then
echo "Cocoa support $cocoa"
fi
echo "SDL support $sdl"
+echo "fbdev support $fbdev"
echo "curses support $curses"
echo "curl support $curl"
echo "mingw32 support $mingw32"
@@ -3367,6 +3376,9 @@ if test "$sdl" = "yes" ; then
echo "CONFIG_SDL=y" >> $config_host_mak
echo "SDL_CFLAGS=$sdl_cflags" >> $config_host_mak
fi
+if test "$fbdev" = "yes" ; then
+ echo "CONFIG_FBDEV=y" >> $config_host_mak
+fi
if test "$cocoa" = "yes" ; then
echo "CONFIG_COCOA=y" >> $config_host_mak
fi
diff --git a/qmp.c b/qmp.c
index 7f6cc0b..060d804 100644
--- a/qmp.c
+++ b/qmp.c
@@ -393,7 +393,7 @@ void qmp_change(const char *device, const char *target,
void qmp_fbdev(bool enable, Error **errp)
{
-#if defined(CONFIG_LINUX)
+#if defined(CONFIG_FBDEV)
DisplayState *ds = get_displaystate();
if (enable) {
diff --git a/ui/Makefile.objs b/ui/Makefile.objs
index 55ddcf2..479cd01 100644
--- a/ui/Makefile.objs
+++ b/ui/Makefile.objs
@@ -12,4 +12,4 @@ common-obj-$(CONFIG_SDL) += sdl.o sdl_zoom.o x_keymap.o
common-obj-$(CONFIG_COCOA) += cocoa.o
common-obj-$(CONFIG_CURSES) += curses.o
common-obj-$(CONFIG_VNC) += $(vnc-obj-y)
-common-obj-$(CONFIG_LINUX) += fbdev.o
+common-obj-$(CONFIG_FBDEV) += fbdev.o
diff --git a/vl.c b/vl.c
index 18982b2..d39352c 100644
--- a/vl.c
+++ b/vl.c
@@ -3041,7 +3041,7 @@ int main(int argc, char **argv, char **envp)
fprintf(stderr, "SDL support is disabled\n");
exit(1);
#endif
-#ifdef CONFIG_LINUX
+#ifdef CONFIG_FBDEV
case QEMU_OPTION_fbdev:
display_type = DT_FBDEV;
break;
@@ -3686,7 +3686,7 @@ int main(int argc, char **argv, char **envp)
curses_display_init(ds, full_screen);
break;
#endif
-#if defined(CONFIG_LINUX)
+#if defined(CONFIG_FBDEV)
case DT_FBDEV:
if (fbdev_display_init(ds, NULL) != 0) {
exit(1);
--
1.7.1
^ permalink raw reply related [flat|nested] 29+ messages in thread
* [Qemu-devel] [PATCH 7/9] fbdev: move to pixman
2012-09-18 7:17 [Qemu-devel] [PULL 0/9] linux framebuffer display driver Gerd Hoffmann
` (5 preceding siblings ...)
2012-09-18 7:17 ` [Qemu-devel] [PATCH 6/9] fbdev: make configurable at compile time Gerd Hoffmann
@ 2012-09-18 7:17 ` Gerd Hoffmann
2012-09-18 15:01 ` Stefano Stabellini
` (2 more replies)
2012-09-18 7:17 ` [Qemu-devel] [PATCH 8/9] fbdev: add mouse pointer support Gerd Hoffmann
2012-09-18 7:17 ` [Qemu-devel] [PATCH 9/9] fbdev: add display scaling support Gerd Hoffmann
8 siblings, 3 replies; 29+ messages in thread
From: Gerd Hoffmann @ 2012-09-18 7:17 UTC (permalink / raw)
To: qemu-devel; +Cc: Gerd Hoffmann
Stop reinventing the wheel. Use the pixman library for raster ops.
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
---
configure | 12 ++++
ui/fbdev.c | 172 +++++++++++++++++++++++++++++++++++------------------------
2 files changed, 114 insertions(+), 70 deletions(-)
diff --git a/configure b/configure
index c4ba338..d10ff78 100755
--- a/configure
+++ b/configure
@@ -148,6 +148,7 @@ docs=""
fdt=""
nptl=""
sdl=""
+pixman=""
fbdev="no"
virtfs=""
vnc="yes"
@@ -2153,6 +2154,17 @@ else
exit 1
fi
+if $pkg_config pixman-1 > /dev/null 2>&1
+then
+ pixman="yes"
+ pixman_cflags=`$pkg_config --cflags pixman-1 2>/dev/null`
+ pixman_libs=`$pkg_config --libs pixman-1 2>/dev/null`
+ QEMU_CFLAGS="$QEMU_CFLAGS $pixman_cflags"
+ libs_softmmu="$libs_softmmu $pixman_libs"
+else
+ fbdev="no"
+fi
+
##########################################
# libcap probe
diff --git a/ui/fbdev.c b/ui/fbdev.c
index 40fc7d4..4cb4d1d 100644
--- a/ui/fbdev.c
+++ b/ui/fbdev.c
@@ -23,11 +23,12 @@
#include <linux/vt.h>
#include <linux/fb.h>
+#include <pixman.h>
+
#include "qemu-common.h"
#include "console.h"
#include "keymaps.h"
#include "sysemu.h"
-#include "pflib.h"
/*
* must be last so we get the linux input layer
@@ -70,19 +71,82 @@ static bool key_down[KEY_CNT];
#define FB_ACQ_REQ 3
static int fb_switch_state;
-/* qdev windup */
+/* qemu windup */
static DisplayChangeListener *dcl;
-static QemuPfConv *conv;
-static PixelFormat fbpf;
static int resize_screen;
static int redraw_screen;
static int cx, cy, cw, ch;
static Notifier exit_notifier;
+static pixman_image_t *surface;
+static pixman_image_t *framebuffer;
+static pixman_transform_t transform;
+static pixman_region16_t dirty;
/* fwd decls */
static int fbdev_activate_vt(int tty, int vtno, bool wait);
/* -------------------------------------------------------------------- */
+/* pixman helpers */
+
+static int pixman_shifts_to_type(int rshift, int gshift, int bshift)
+{
+ int type = PIXMAN_TYPE_OTHER;
+
+ if (rshift > gshift && gshift > bshift) {
+ if (bshift == 0) {
+ type = PIXMAN_TYPE_ARGB;
+ } else {
+#if PIXMAN_VERSION >= PIXMAN_VERSION_ENCODE(0, 21, 8)
+ type = PIXMAN_TYPE_RGBA;
+#endif
+ }
+ } else if (rshift < gshift && gshift < bshift) {
+ if (rshift == 0) {
+ type = PIXMAN_TYPE_ABGR;
+ } else {
+ type = PIXMAN_TYPE_BGRA;
+ }
+ }
+ return type;
+}
+
+static pixman_image_t *pixman_from_displaystate(DisplayState *ds)
+{
+ PixelFormat *pf = &ds->surface->pf;
+ pixman_format_code_t format;
+ pixman_image_t *image;
+ int type;
+
+ type = pixman_shifts_to_type(pf->rshift, pf->gshift, pf->bshift);
+ format = PIXMAN_FORMAT(pf->bits_per_pixel, type,
+ pf->abits, pf->rbits, pf->gbits, pf->bbits);
+ image = pixman_image_create_bits(format, ds_get_width(ds),
+ ds_get_height(ds),
+ (void *)ds_get_data(ds),
+ ds_get_linesize(ds));
+ return image;
+}
+
+static pixman_image_t *pixman_from_framebuffer(void)
+{
+ pixman_format_code_t format;
+ pixman_image_t *image;
+ int type;
+
+ type = pixman_shifts_to_type(fb_var.red.offset,
+ fb_var.green.offset,
+ fb_var.blue.offset);
+ format = PIXMAN_FORMAT(fb_var.bits_per_pixel, type,
+ fb_var.transp.length,
+ fb_var.red.length,
+ fb_var.green.length,
+ fb_var.blue.length);
+ image = pixman_image_create_bits(format, fb_var.xres, fb_var.yres,
+ (void *)fb_mem, fb_fix.line_length);
+ return image;
+}
+
+/* -------------------------------------------------------------------- */
/* mouse */
static void read_mouse(void *opaque)
@@ -529,6 +593,17 @@ static void fbdev_cleanup(void)
{
trace_fbdev_cleanup();
+ /* release pixman stuff */
+ pixman_region_fini(&dirty);
+ if (framebuffer) {
+ pixman_image_unref(framebuffer);
+ framebuffer = NULL;
+ }
+ if (surface) {
+ pixman_image_unref(surface);
+ surface = NULL;
+ }
+
/* restore console */
if (fb_mem != NULL) {
munmap(fb_mem, fb_fix.smem_len+fb_mem_offset);
@@ -681,36 +756,8 @@ static int fbdev_init(const char *device)
start_mediumraw(tty);
qemu_set_fd_handler(tty, read_mediumraw, NULL, NULL);
- /* create PixelFormat from fbdev structs */
- fbpf.bits_per_pixel = fb_var.bits_per_pixel;
- fbpf.bytes_per_pixel = (fb_var.bits_per_pixel+7)/8;
- fbpf.depth = fb_var.bits_per_pixel == 32
- ? 24 : fb_var.bits_per_pixel;
- fbpf.rshift = fb_var.red.offset;
- fbpf.rbits = fb_var.red.length;
- fbpf.gshift = fb_var.green.offset;
- fbpf.gbits = fb_var.green.length;
- fbpf.bshift = fb_var.blue.offset;
- fbpf.bbits = fb_var.blue.length;
- fbpf.ashift = fb_var.transp.offset;
- fbpf.abits = fb_var.transp.length;
-
- if (fbpf.rbits) {
- fbpf.rmax = (1 << fbpf.rbits) - 1;
- fbpf.rmask = fbpf.rmax << fbpf.rshift;
- }
- if (fbpf.gbits) {
- fbpf.gmax = (1 << fbpf.gbits) - 1;
- fbpf.gmask = fbpf.gmax << fbpf.gshift;
- }
- if (fbpf.bbits) {
- fbpf.bmax = (1 << fbpf.bbits) - 1;
- fbpf.bmask = fbpf.bmax << fbpf.bshift;
- }
- if (fbpf.abits) {
- fbpf.amax = (1 << fbpf.abits) - 1;
- fbpf.amask = fbpf.amax << fbpf.ashift;
- }
+ framebuffer = pixman_from_framebuffer();
+ pixman_region_init(&dirty);
return 0;
err_early:
@@ -818,36 +865,15 @@ static int fbdev_switch_init(void)
/* -------------------------------------------------------------------- */
/* rendering */
-static void fbdev_render(DisplayState *ds, int x, int y, int w, int h)
+static void fbdev_render(DisplayState *ds)
{
- uint8_t *dst;
- uint8_t *src;
- int line;
-
- if (!conv) {
- return;
- }
-
- src = ds_get_data(ds) + y * ds_get_linesize(ds)
- + x * ds_get_bytes_per_pixel(ds);
- dst = fb_mem + y * fb_fix.line_length
- + x * fbpf.bytes_per_pixel;
-
- dst += cy * fb_fix.line_length;
- dst += cx * fbpf.bytes_per_pixel;
+ assert(surface);
- if (h > fb_var.yres - y) {
- h = fb_var.yres - y;
- }
- if (w > fb_var.xres - x) {
- w = fb_var.xres - x;
- }
-
- for (line = y; line < y+h; line++) {
- qemu_pf_conv_run(conv, dst, src, w);
- dst += fb_fix.line_length;
- src += ds_get_linesize(ds);
- }
+ pixman_image_set_clip_region(surface, &dirty);
+ pixman_image_composite(PIXMAN_OP_SRC, surface, NULL, framebuffer,
+ 0, 0, 0, 0, 0, 0, fb_var.xres, fb_var.yres);
+ pixman_region_fini(&dirty);
+ pixman_region_init(&dirty);
}
/* -------------------------------------------------------------------- */
@@ -871,14 +897,16 @@ static void fbdev_update(DisplayState *ds, int x, int y, int w, int h)
if (ds_get_height(ds) < fb_var.yres) {
cy = (fb_var.yres - ds_get_height(ds)) / 2;
}
-
- if (conv) {
- qemu_pf_conv_put(conv);
- }
- conv = qemu_pf_conv_get(&fbpf, &ds->surface->pf);
- if (conv == NULL) {
- fprintf(stderr, "fbdev: unsupported PixelFormat conversion\n");
+ if (surface) {
+ pixman_image_unref(surface);
}
+ surface = pixman_from_displaystate(ds);
+
+ pixman_transform_init_identity(&transform);
+ pixman_transform_translate(&transform, NULL,
+ pixman_int_to_fixed(-cx),
+ pixman_int_to_fixed(-cy));
+ pixman_image_set_transform(surface, &transform);
}
if (redraw_screen) {
@@ -888,7 +916,7 @@ static void fbdev_update(DisplayState *ds, int x, int y, int w, int h)
x = 0; y = 0; w = ds_get_width(ds); h = ds_get_height(ds);
}
- fbdev_render(ds, x, y, w, h);
+ pixman_region_union_rect(&dirty, &dirty, x, y, w, h);
}
static void fbdev_resize(DisplayState *ds)
@@ -924,6 +952,10 @@ static void fbdev_refresh(DisplayState *ds)
if (redraw_screen) {
fbdev_update(ds, 0, 0, 0, 0);
}
+
+ if (pixman_region_not_empty(&dirty)) {
+ fbdev_render(ds);
+ }
}
static void fbdev_exit_notifier(Notifier *notifier, void *data)
--
1.7.1
^ permalink raw reply related [flat|nested] 29+ messages in thread
* [Qemu-devel] [PATCH 8/9] fbdev: add mouse pointer support
2012-09-18 7:17 [Qemu-devel] [PULL 0/9] linux framebuffer display driver Gerd Hoffmann
` (6 preceding siblings ...)
2012-09-18 7:17 ` [Qemu-devel] [PATCH 7/9] fbdev: move to pixman Gerd Hoffmann
@ 2012-09-18 7:17 ` Gerd Hoffmann
2012-09-18 7:17 ` [Qemu-devel] [PATCH 9/9] fbdev: add display scaling support Gerd Hoffmann
8 siblings, 0 replies; 29+ messages in thread
From: Gerd Hoffmann @ 2012-09-18 7:17 UTC (permalink / raw)
To: qemu-devel; +Cc: Gerd Hoffmann
Add mouse_set and cursor_define DisplayChangeListener callbacks
and mouse pointer rendering support.
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
---
ui/fbdev.c | 95 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
1 files changed, 95 insertions(+), 0 deletions(-)
diff --git a/ui/fbdev.c b/ui/fbdev.c
index 4cb4d1d..6835fef 100644
--- a/ui/fbdev.c
+++ b/ui/fbdev.c
@@ -82,6 +82,12 @@ static pixman_image_t *framebuffer;
static pixman_transform_t transform;
static pixman_region16_t dirty;
+static QEMUCursor *ptr_cursor;
+static pixman_image_t *ptr_image;
+static int ptr_refresh;
+static int px, py, pw, ph;
+static int mx, my, mon;
+
/* fwd decls */
static int fbdev_activate_vt(int tty, int vtno, bool wait);
@@ -876,6 +882,51 @@ static void fbdev_render(DisplayState *ds)
pixman_region_init(&dirty);
}
+static void fbdev_unrender_ptr(DisplayState *ds)
+{
+ if (!pw && !ph) {
+ return;
+ }
+ pixman_region_union_rect(&dirty, &dirty, px, py, pw, ph);
+ ph = pw = 0;
+}
+
+static void fbdev_render_ptr(DisplayState *ds)
+{
+ pixman_region16_t region;
+ pixman_transform_t transform;
+
+ if (!mon || !ptr_image) {
+ return;
+ }
+ if (mx < 0 || mx >= cw || my < 0 || my >= ch) {
+ return;
+ }
+
+ px = mx - ptr_cursor->hot_x;
+ py = my - ptr_cursor->hot_y;
+ pw = ptr_cursor->width;
+ ph = ptr_cursor->height;
+
+ pixman_transform_init_identity(&transform);
+ pixman_transform_translate(&transform, NULL,
+ pixman_int_to_fixed(-cx),
+ pixman_int_to_fixed(-cy));
+ pixman_transform_translate(&transform, NULL,
+ pixman_int_to_fixed(-px),
+ pixman_int_to_fixed(-py));
+ pixman_image_set_transform(ptr_image, &transform);
+
+ pixman_region_init_rect(®ion, 0, 0, pw, ph);
+ pixman_image_set_clip_region(ptr_image, ®ion);
+
+ pixman_image_composite(PIXMAN_OP_OVER, ptr_image, NULL, framebuffer,
+ 0, 0, 0, 0, 0, 0, fb_var.xres, fb_var.yres);
+
+ pixman_region_fini(®ion);
+ ptr_refresh = 0;
+}
+
/* -------------------------------------------------------------------- */
/* qemu interfaces */
@@ -917,6 +968,9 @@ static void fbdev_update(DisplayState *ds, int x, int y, int w, int h)
}
pixman_region_union_rect(&dirty, &dirty, x, y, w, h);
+ if (ptr_image && mon && pw && ph) {
+ ptr_refresh++;
+ }
}
static void fbdev_resize(DisplayState *ds)
@@ -953,9 +1007,48 @@ static void fbdev_refresh(DisplayState *ds)
fbdev_update(ds, 0, 0, 0, 0);
}
+ if (ptr_refresh) {
+ fbdev_unrender_ptr(ds);
+ }
if (pixman_region_not_empty(&dirty)) {
fbdev_render(ds);
}
+ if (ptr_refresh) {
+ fbdev_render_ptr(ds);
+ }
+}
+
+static void fbdev_mouse_set(DisplayState *ds, int x, int y, int on)
+{
+ ptr_refresh++;
+ mx = x;
+ my = y;
+ mon = on;
+}
+
+static void fbdev_cursor_define(DisplayState *ds, QEMUCursor *cursor)
+{
+ ptr_refresh++;
+
+ if (ptr_cursor) {
+ cursor_put(ptr_cursor);
+ ptr_cursor = NULL;
+ }
+ if (ptr_image) {
+ pixman_image_unref(ptr_image);
+ ptr_image = NULL;
+ }
+
+ if (!cursor) {
+ return;
+ }
+
+ ptr_cursor = cursor;
+ cursor_get(ptr_cursor);
+ ptr_image = pixman_image_create_bits(PIXMAN_a8r8g8b8,
+ cursor->width, cursor->height,
+ cursor->data,
+ cursor->width * 4);
}
static void fbdev_exit_notifier(Notifier *notifier, void *data)
@@ -984,6 +1077,8 @@ int fbdev_display_init(DisplayState *ds, const char *device)
dcl->dpy_resize = fbdev_resize;
dcl->dpy_setdata = fbdev_setdata;
dcl->dpy_refresh = fbdev_refresh;
+ dcl->dpy_mouse_set = fbdev_mouse_set;
+ dcl->dpy_cursor_define = fbdev_cursor_define;
register_displaychangelistener(ds, dcl);
trace_fbdev_enabled();
--
1.7.1
^ permalink raw reply related [flat|nested] 29+ messages in thread
* [Qemu-devel] [PATCH 9/9] fbdev: add display scaling support
2012-09-18 7:17 [Qemu-devel] [PULL 0/9] linux framebuffer display driver Gerd Hoffmann
` (7 preceding siblings ...)
2012-09-18 7:17 ` [Qemu-devel] [PATCH 8/9] fbdev: add mouse pointer support Gerd Hoffmann
@ 2012-09-18 7:17 ` Gerd Hoffmann
2012-09-18 15:02 ` Stefano Stabellini
8 siblings, 1 reply; 29+ messages in thread
From: Gerd Hoffmann @ 2012-09-18 7:17 UTC (permalink / raw)
To: qemu-devel; +Cc: Gerd Hoffmann
Add support for scaling the guest display.
Ctrl-Alt-S hotkey toggles scaling.
Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
---
ui/fbdev.c | 61 ++++++++++++++++++++++++++++++++++++++++++++++++++---------
1 files changed, 51 insertions(+), 10 deletions(-)
diff --git a/ui/fbdev.c b/ui/fbdev.c
index 6835fef..55793ab 100644
--- a/ui/fbdev.c
+++ b/ui/fbdev.c
@@ -81,6 +81,7 @@ static pixman_image_t *surface;
static pixman_image_t *framebuffer;
static pixman_transform_t transform;
static pixman_region16_t dirty;
+static double scale;
static QEMUCursor *ptr_cursor;
static pixman_image_t *ptr_image;
@@ -88,6 +89,10 @@ static int ptr_refresh;
static int px, py, pw, ph;
static int mx, my, mon;
+/* options */
+static int use_scale = 1;
+static pixman_filter_t pfilter = PIXMAN_FILTER_GOOD;
+
/* fwd decls */
static int fbdev_activate_vt(int tty, int vtno, bool wait);
@@ -182,13 +187,14 @@ static void read_mouse(void *opaque)
if (ay < 0) {
ay = 0;
}
- if (ax >= cw) {
- ax = cw-1;
+ if (ax >= cw*scale) {
+ ax = cw*scale-1;
}
- if (ay >= ch) {
- ay = ch-1;
+ if (ay >= ch*scale) {
+ ay = ch*scale-1;
}
- kbd_mouse_event(ax * 0x7FFF / cw, ay * 0x7FFF / ch, 0, b);
+ kbd_mouse_event(ax * 0x7FFF / (cw*scale),
+ ay * 0x7FFF / (ch*scale), 0, b);
} else {
kbd_mouse_event(x, y, 0, b);
}
@@ -543,6 +549,12 @@ static void read_mediumraw(void *opaque)
"(ctrl-alt-esc) ===\n");
exit(1);
}
+ if (keycode == KEY_S) {
+ use_scale = !use_scale;
+ resize_screen++;
+ redraw_screen++;
+ continue;
+ }
if (keycode >= KEY_F1 && keycode <= KEY_F10) {
fbdev_activate_vt(tty, keycode+1-KEY_F1, false);
key_down[keycode] = false;
@@ -912,6 +924,11 @@ static void fbdev_render_ptr(DisplayState *ds)
pixman_transform_translate(&transform, NULL,
pixman_int_to_fixed(-cx),
pixman_int_to_fixed(-cy));
+ if (use_scale) {
+ pixman_transform_scale(&transform, NULL,
+ pixman_double_to_fixed(1/scale),
+ pixman_double_to_fixed(1/scale));
+ }
pixman_transform_translate(&transform, NULL,
pixman_int_to_fixed(-px),
pixman_int_to_fixed(-py));
@@ -937,16 +954,32 @@ static void fbdev_update(DisplayState *ds, int x, int y, int w, int h)
}
if (resize_screen) {
+ double xs, ys;
+
trace_fbdev_dpy_resize(ds_get_width(ds), ds_get_height(ds));
resize_screen = 0;
cx = 0; cy = 0;
cw = ds_get_width(ds);
ch = ds_get_height(ds);
- if (ds_get_width(ds) < fb_var.xres) {
- cx = (fb_var.xres - ds_get_width(ds)) / 2;
- }
- if (ds_get_height(ds) < fb_var.yres) {
- cy = (fb_var.yres - ds_get_height(ds)) / 2;
+
+ if (use_scale) {
+ xs = (double)fb_var.xres / cw;
+ ys = (double)fb_var.yres / ch;
+ if (xs > ys) {
+ scale = ys;
+ cx = (fb_var.xres - ds_get_width(ds)*scale) / 2;
+ } else {
+ scale = xs;
+ cy = (fb_var.yres - ds_get_height(ds)*scale) / 2;
+ }
+ } else {
+ scale = 1;
+ if (ds_get_width(ds) < fb_var.xres) {
+ cx = (fb_var.xres - ds_get_width(ds)) / 2;
+ }
+ if (ds_get_height(ds) < fb_var.yres) {
+ cy = (fb_var.yres - ds_get_height(ds)) / 2;
+ }
}
if (surface) {
pixman_image_unref(surface);
@@ -957,7 +990,14 @@ static void fbdev_update(DisplayState *ds, int x, int y, int w, int h)
pixman_transform_translate(&transform, NULL,
pixman_int_to_fixed(-cx),
pixman_int_to_fixed(-cy));
+ if (use_scale) {
+ pixman_transform_scale(&transform, NULL,
+ pixman_double_to_fixed(1/scale),
+ pixman_double_to_fixed(1/scale));
+ }
pixman_image_set_transform(surface, &transform);
+
+ pixman_image_set_filter(surface, pfilter, NULL, 0);
}
if (redraw_screen) {
@@ -1049,6 +1089,7 @@ static void fbdev_cursor_define(DisplayState *ds, QEMUCursor *cursor)
cursor->width, cursor->height,
cursor->data,
cursor->width * 4);
+ pixman_image_set_filter(ptr_image, pfilter, NULL, 0);
}
static void fbdev_exit_notifier(Notifier *notifier, void *data)
--
1.7.1
^ permalink raw reply related [flat|nested] 29+ messages in thread
* Re: [Qemu-devel] [PATCH 2/9] add unregister_displaychangelistener
2012-09-18 7:17 ` [Qemu-devel] [PATCH 2/9] add unregister_displaychangelistener Gerd Hoffmann
@ 2012-09-18 10:54 ` Stefano Stabellini
0 siblings, 0 replies; 29+ messages in thread
From: Stefano Stabellini @ 2012-09-18 10:54 UTC (permalink / raw)
To: Gerd Hoffmann; +Cc: qemu-devel@nongnu.org
On Tue, 18 Sep 2012, Gerd Hoffmann wrote:
> Also change the way the gui_timer is initialized: each time a
> displaychangelistener is registered or unregistered we'll check
> whenever we need a timer (due to dpy_refresh callback being present)
> and if so setup a timer, otherwise zap it. This way the gui timer works
> correctly with displaychangelisteners coming and going.
>
> Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
Acked-by: Stefano Stabellini <stefano.stabellini@eu.citrix.com>
> console.h | 10 ++++++++++
> vl.c | 31 +++++++++++++++++++++++--------
> 2 files changed, 33 insertions(+), 8 deletions(-)
>
> diff --git a/console.h b/console.h
> index 646ad4b..48fef22 100644
> --- a/console.h
> +++ b/console.h
> @@ -229,9 +229,19 @@ static inline int is_buffer_shared(DisplaySurface *surface)
> !(surface->flags & QEMU_REALPIXELS_FLAG));
> }
>
> +void gui_setup_refresh(DisplayState *ds);
> +
> static inline void register_displaychangelistener(DisplayState *ds, DisplayChangeListener *dcl)
> {
> QLIST_INSERT_HEAD(&ds->listeners, dcl, next);
> + gui_setup_refresh(ds);
> +}
> +
> +static inline void unregister_displaychangelistener(DisplayState *ds,
> + DisplayChangeListener *dcl)
> +{
> + QLIST_REMOVE(dcl, next);
> + gui_setup_refresh(ds);
> }
>
> static inline void dpy_update(DisplayState *s, int x, int y, int w, int h)
> diff --git a/vl.c b/vl.c
> index 2a7c92a..fbb77fe 100644
> --- a/vl.c
> +++ b/vl.c
> @@ -1288,6 +1288,29 @@ static void gui_update(void *opaque)
> qemu_mod_timer(ds->gui_timer, interval + qemu_get_clock_ms(rt_clock));
> }
>
> +void gui_setup_refresh(DisplayState *ds)
> +{
> + DisplayChangeListener *dcl;
> + bool need_timer = false;
> +
> + QLIST_FOREACH(dcl, &ds->listeners, next) {
> + if (dcl->dpy_refresh != NULL) {
> + need_timer = true;
> + break;
> + }
> + }
> +
> + 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));
> + }
> + if (!need_timer && ds->gui_timer != NULL) {
> + qemu_del_timer(ds->gui_timer);
> + qemu_free_timer(ds->gui_timer);
> + ds->gui_timer = NULL;
> + }
> +}
> +
> struct vm_change_state_entry {
> VMChangeStateHandler *cb;
> void *opaque;
> @@ -2350,7 +2373,6 @@ int main(int argc, char **argv, char **envp)
> const char *kernel_filename, *kernel_cmdline;
> char boot_devices[33] = "cad"; /* default to HD->floppy->CD-ROM */
> DisplayState *ds;
> - DisplayChangeListener *dcl;
> int cyls, heads, secs, translation;
> QemuOpts *hda_opts = NULL, *opts, *machine_opts;
> QemuOptsList *olist;
> @@ -3698,13 +3720,6 @@ int main(int argc, char **argv, char **envp)
>
> /* display setup */
> dpy_resize(ds);
> - QLIST_FOREACH(dcl, &ds->listeners, next) {
> - if (dcl->dpy_refresh != 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));
> - break;
> - }
> - }
> text_consoles_set_display(ds);
>
> if (foreach_device_config(DEV_GDB, gdbserver_start) < 0) {
> --
> 1.7.1
>
>
^ permalink raw reply [flat|nested] 29+ messages in thread
* Re: [Qemu-devel] [PATCH 5/9] fbdev: add monitor command to enable/disable
2012-09-18 7:17 ` [Qemu-devel] [PATCH 5/9] fbdev: add monitor command to enable/disable Gerd Hoffmann
@ 2012-09-18 12:47 ` Luiz Capitulino
0 siblings, 0 replies; 29+ messages in thread
From: Luiz Capitulino @ 2012-09-18 12:47 UTC (permalink / raw)
To: Gerd Hoffmann; +Cc: qemu-devel
On Tue, 18 Sep 2012 09:17:10 +0200
Gerd Hoffmann <kraxel@redhat.com> wrote:
> This patch adds a fbdev monitor command to enable/disable
> the fbdev display at runtime to both qmp and hmp.
>
> qmp: fbdev enable=on|off
> hmp: fbdev on|off
>
> Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
> ---
> hmp-commands.hx | 15 +++++++++++++++
> hmp.c | 9 +++++++++
> hmp.h | 1 +
> qapi-schema.json | 14 ++++++++++++++
> qmp-commands.hx | 6 ++++++
> qmp.c | 17 +++++++++++++++++
> 6 files changed, 62 insertions(+), 0 deletions(-)
>
> diff --git a/hmp-commands.hx b/hmp-commands.hx
> index ed67e99..366a92b 100644
> --- a/hmp-commands.hx
> +++ b/hmp-commands.hx
> @@ -1377,6 +1377,21 @@ passed since 1970, i.e. unix epoch.
> ETEXI
>
> {
> + .name = "fbdev",
> + .args_type = "enable:b",
> + .params = "on|off",
> + .help = "enable/disable fbdev",
> + .mhandler.cmd = hmp_fbdev,
> + },
> +
> +STEXI
> +@item fbdev on | off
> +@findex fbdev
> +
> +enable/disable fbdev
> +ETEXI
> +
> + {
> .name = "info",
> .args_type = "item:s?",
> .params = "[subcommand]",
> diff --git a/hmp.c b/hmp.c
> index ba6fbd3..a7feec5 100644
> --- a/hmp.c
> +++ b/hmp.c
> @@ -1168,3 +1168,12 @@ void hmp_screen_dump(Monitor *mon, const QDict *qdict)
> qmp_screendump(filename, &err);
> hmp_handle_error(mon, &err);
> }
> +
> +void hmp_fbdev(Monitor *mon, const QDict *qdict)
> +{
> + int enable = qdict_get_bool(qdict, "enable");
> + Error *errp = NULL;
> +
> + qmp_fbdev(enable, &errp);
> + hmp_handle_error(mon, &errp);
> +}
> diff --git a/hmp.h b/hmp.h
> index 48b9c59..9c3d315 100644
> --- a/hmp.h
> +++ b/hmp.h
> @@ -73,5 +73,6 @@ void hmp_getfd(Monitor *mon, const QDict *qdict);
> void hmp_closefd(Monitor *mon, const QDict *qdict);
> void hmp_send_key(Monitor *mon, const QDict *qdict);
> void hmp_screen_dump(Monitor *mon, const QDict *qdict);
> +void hmp_fbdev(Monitor *mon, const QDict *qdict);
>
> #endif
> diff --git a/qapi-schema.json b/qapi-schema.json
> index 14e4419..901c2e8 100644
> --- a/qapi-schema.json
> +++ b/qapi-schema.json
> @@ -2619,3 +2619,17 @@
> # Since: 0.14.0
> ##
> { 'command': 'screendump', 'data': {'filename': 'str'} }
> +
> +# @fbdev:
Please, use more descriptive names for qmp. Maybe something
like frame-buffer-device-add/-enable.
> +#
> +# Enable/disable fbdev.
> +#
> +# @enable: whenever fbdev should be enabled or disabled.
> +#
> +# Returns: Nothing on success
> +# GenericError on failure.
It's not needed to list GenericError as an error.
> +#
> +# Since: 1.3
> +#
> +##
> +{ 'command': 'fbdev', 'data': {'enable': 'bool'} }
> diff --git a/qmp-commands.hx b/qmp-commands.hx
> index 6e21ddb..4b95fd0 100644
> --- a/qmp-commands.hx
> +++ b/qmp-commands.hx
> @@ -2539,3 +2539,9 @@ EQMP
> .args_type = "",
> .mhandler.cmd_new = qmp_marshal_input_query_target,
> },
> +
> + {
> + .name = "fbdev",
> + .args_type = "enable:b",
> + .mhandler.cmd_new = qmp_marshal_input_fbdev,
> + },
> diff --git a/qmp.c b/qmp.c
> index 8463922..7f6cc0b 100644
> --- a/qmp.c
> +++ b/qmp.c
> @@ -391,6 +391,23 @@ void qmp_change(const char *device, const char *target,
> }
> }
>
> +void qmp_fbdev(bool enable, Error **errp)
> +{
> +#if defined(CONFIG_LINUX)
> + DisplayState *ds = get_displaystate();
> +
> + if (enable) {
> + if (fbdev_display_init(ds, NULL) != 0) {
> + error_setg(errp, "fbdev initialization failed");
Would be nice to tell the reason if you have it (error_setg() has
printf()-likeformat).
> + }
> + } else {
> + fbdev_display_uninit(ds);
> + }
> +#else
> + error_set(errp, QERR_FEATURE_DISABLED, "fbdev");
We shouldn't use QERR_ macros in new code. You have two options:
1. use error_setg()
2. add error_set_disabled() in error.h, similar to error_setg(),
and use it
> +#endif
> +}
> +
> static void qom_list_types_tramp(ObjectClass *klass, void *data)
> {
> ObjectTypeInfoList *e, **pret = data;
^ permalink raw reply [flat|nested] 29+ messages in thread
* Re: [Qemu-devel] [PATCH 3/9] move set_mouse + cursor_define callbacks
2012-09-18 7:17 ` [Qemu-devel] [PATCH 3/9] move set_mouse + cursor_define callbacks Gerd Hoffmann
@ 2012-09-18 14:10 ` Stefano Stabellini
2012-09-18 16:31 ` Gerd Hoffmann
0 siblings, 1 reply; 29+ messages in thread
From: Stefano Stabellini @ 2012-09-18 14:10 UTC (permalink / raw)
To: Gerd Hoffmann; +Cc: qemu-devel@nongnu.org
On Tue, 18 Sep 2012, Gerd Hoffmann wrote:
> When adding DisplayChangeListeners the set_mouse and cursor_define
> callbacks have been left in DisplayState for some reason. Fix it.
>
> Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
This patch is good.
The one thing I don't like is dpy_cursor_define_supported, because it
enforces the idea that we cannot register/deregister
DisplayChangeListeners at run time. Theoretically a new
DisplayChangeListener that support cursor_define could show up at any
time.
Is dpy_cursor_define_supported really necessary?
> console.c | 2 +-
> console.h | 39 +++++++++++++++++++++++++++++++++++----
> hw/jazz_led.c | 2 +-
> hw/qxl-render.c | 2 +-
> hw/vga.c | 10 +++++-----
> hw/vmware_vga.c | 11 ++++++-----
> ui/sdl.c | 8 ++++----
> ui/spice-display.c | 4 ++--
> ui/vnc.c | 8 ++++----
> 9 files changed, 59 insertions(+), 27 deletions(-)
>
> diff --git a/console.c b/console.c
> index a8bcc42..cc0479b 100644
> --- a/console.c
> +++ b/console.c
> @@ -1239,7 +1239,7 @@ static void text_console_update(void *opaque, console_ch_t *chardata)
> s->text_y[1] = 0;
> }
> if (s->cursor_invalidate) {
> - dpy_cursor(s->ds, s->x, s->y);
> + dpy_text_cursor(s->ds, s->x, s->y);
> s->cursor_invalidate = 0;
> }
> }
> diff --git a/console.h b/console.h
> index 48fef22..bef2d2d 100644
> --- a/console.h
> +++ b/console.h
> @@ -164,6 +164,9 @@ struct DisplayChangeListener {
> int w, int h, uint32_t c);
> void (*dpy_text_cursor)(struct DisplayState *s, int x, int y);
>
> + void (*dpy_mouse_set)(struct DisplayState *s, int x, int y, int on);
> + void (*dpy_cursor_define)(struct DisplayState *s, QEMUCursor *cursor);
> +
> QLIST_ENTRY(DisplayChangeListener) next;
> };
>
> @@ -181,9 +184,6 @@ struct DisplayState {
> struct DisplayAllocator* allocator;
> QLIST_HEAD(, DisplayChangeListener) listeners;
>
> - void (*mouse_set)(int x, int y, int on);
> - void (*cursor_define)(QEMUCursor *cursor);
> -
> struct DisplayState *next;
> };
>
> @@ -304,7 +304,7 @@ static inline void dpy_fill(struct DisplayState *s, int x, int y,
> }
> }
>
> -static inline void dpy_cursor(struct DisplayState *s, int x, int y)
> +static inline void dpy_text_cursor(struct DisplayState *s, int x, int y)
> {
> struct DisplayChangeListener *dcl;
> QLIST_FOREACH(dcl, &s->listeners, next) {
> @@ -314,6 +314,37 @@ static inline void dpy_cursor(struct DisplayState *s, int x, int y)
> }
> }
>
> +static inline void dpy_mouse_set(struct DisplayState *s, int x, int y, int on)
> +{
> + struct DisplayChangeListener *dcl;
> + QLIST_FOREACH(dcl, &s->listeners, next) {
> + if (dcl->dpy_mouse_set) {
> + dcl->dpy_mouse_set(s, x, y, on);
> + }
> + }
> +}
> +
> +static inline void dpy_cursor_define(struct DisplayState *s, QEMUCursor *cursor)
> +{
> + struct DisplayChangeListener *dcl;
> + QLIST_FOREACH(dcl, &s->listeners, next) {
> + if (dcl->dpy_cursor_define) {
> + dcl->dpy_cursor_define(s, cursor);
> + }
> + }
> +}
> +
> +static inline bool dpy_cursor_define_supported(struct DisplayState *s)
> +{
> + struct DisplayChangeListener *dcl;
> + QLIST_FOREACH(dcl, &s->listeners, next) {
> + if (dcl->dpy_cursor_define) {
> + return true;
> + }
> + }
> + return false;
> +}
> +
> static inline int ds_get_linesize(DisplayState *ds)
> {
> return ds->surface->linesize;
> diff --git a/hw/jazz_led.c b/hw/jazz_led.c
> index 6486523..c4d54e2 100644
> --- a/hw/jazz_led.c
> +++ b/hw/jazz_led.c
> @@ -210,7 +210,7 @@ static void jazz_led_text_update(void *opaque, console_ch_t *chardata)
> LedState *s = opaque;
> char buf[2];
>
> - dpy_cursor(s->ds, -1, -1);
> + dpy_text_cursor(s->ds, -1, -1);
> qemu_console_resize(s->ds, 2, 1);
>
> /* TODO: draw the segments */
> diff --git a/hw/qxl-render.c b/hw/qxl-render.c
> index e2e3fe2..085a090 100644
> --- a/hw/qxl-render.c
> +++ b/hw/qxl-render.c
> @@ -238,7 +238,7 @@ int qxl_render_cursor(PCIQXLDevice *qxl, QXLCommandExt *ext)
> return 1;
> }
>
> - if (!qxl->ssd.ds->mouse_set || !qxl->ssd.ds->cursor_define) {
> + if (!dpy_cursor_define_supported(qxl->ssd.ds)) {
> return 0;
> }
>
> diff --git a/hw/vga.c b/hw/vga.c
> index afaef0d..ec4f0c5 100644
> --- a/hw/vga.c
> +++ b/hw/vga.c
> @@ -2081,11 +2081,11 @@ static void vga_update_text(void *opaque, console_ch_t *chardata)
> s->cr[VGA_CRTC_CURSOR_END] != s->cursor_end || full_update) {
> cursor_visible = !(s->cr[VGA_CRTC_CURSOR_START] & 0x20);
> if (cursor_visible && cursor_offset < size && cursor_offset >= 0)
> - dpy_cursor(s->ds,
> - TEXTMODE_X(cursor_offset),
> - TEXTMODE_Y(cursor_offset));
> + dpy_text_cursor(s->ds,
> + TEXTMODE_X(cursor_offset),
> + TEXTMODE_Y(cursor_offset));
> else
> - dpy_cursor(s->ds, -1, -1);
> + dpy_text_cursor(s->ds, -1, -1);
> s->cursor_offset = cursor_offset;
> s->cursor_start = s->cr[VGA_CRTC_CURSOR_START];
> s->cursor_end = s->cr[VGA_CRTC_CURSOR_END];
> @@ -2146,7 +2146,7 @@ static void vga_update_text(void *opaque, console_ch_t *chardata)
> /* Display a message */
> s->last_width = 60;
> s->last_height = height = 3;
> - dpy_cursor(s->ds, -1, -1);
> + dpy_text_cursor(s->ds, -1, -1);
> s->ds->surface->width = s->last_width;
> s->ds->surface->height = height;
> dpy_resize(s->ds);
> diff --git a/hw/vmware_vga.c b/hw/vmware_vga.c
> index e815a04..e105b5a 100644
> --- a/hw/vmware_vga.c
> +++ b/hw/vmware_vga.c
> @@ -479,8 +479,7 @@ static inline void vmsvga_cursor_define(struct vmsvga_state_s *s,
> qc = cursor_builtin_left_ptr();
> }
>
> - if (s->vga.ds->cursor_define)
> - s->vga.ds->cursor_define(qc);
> + dpy_cursor_define(s->vga.ds, qc);
> cursor_put(qc);
> }
> #endif
> @@ -755,9 +754,10 @@ static uint32_t vmsvga_value_read(void *opaque, uint32_t address)
> caps |= SVGA_CAP_RECT_FILL;
> #endif
> #ifdef HW_MOUSE_ACCEL
> - if (s->vga.ds->mouse_set)
> + if (dpy_cursor_define_supported(s->vga.ds)) {
> caps |= SVGA_CAP_CURSOR | SVGA_CAP_CURSOR_BYPASS_2 |
> SVGA_CAP_CURSOR_BYPASS;
> + }
> #endif
> return caps;
>
> @@ -904,8 +904,9 @@ static void vmsvga_value_write(void *opaque, uint32_t address, uint32_t value)
> s->cursor.on |= (value == SVGA_CURSOR_ON_SHOW);
> s->cursor.on &= (value != SVGA_CURSOR_ON_HIDE);
> #ifdef HW_MOUSE_ACCEL
> - if (s->vga.ds->mouse_set && value <= SVGA_CURSOR_ON_SHOW)
> - s->vga.ds->mouse_set(s->cursor.x, s->cursor.y, s->cursor.on);
> + if (value <= SVGA_CURSOR_ON_SHOW) {
> + dpy_mouse_set(s->vga.ds, s->cursor.x, s->cursor.y, s->cursor.on);
> + }
> #endif
> break;
>
> diff --git a/ui/sdl.c b/ui/sdl.c
> index f6f711c..f8ead93 100644
> --- a/ui/sdl.c
> +++ b/ui/sdl.c
> @@ -905,7 +905,7 @@ static void sdl_fill(DisplayState *ds, int x, int y, int w, int h, uint32_t c)
> SDL_FillRect(real_screen, &dst, c);
> }
>
> -static void sdl_mouse_warp(int x, int y, int on)
> +static void sdl_mouse_warp(DisplayState *ds, int x, int y, int on)
> {
> if (on) {
> if (!guest_cursor)
> @@ -921,7 +921,7 @@ static void sdl_mouse_warp(int x, int y, int on)
> guest_x = x, guest_y = y;
> }
>
> -static void sdl_mouse_define(QEMUCursor *c)
> +static void sdl_mouse_define(DisplayState *ds, QEMUCursor *c)
> {
> uint8_t *image, *mask;
> int bpl;
> @@ -1025,8 +1025,8 @@ void sdl_display_init(DisplayState *ds, int full_screen, int no_frame)
> dcl->dpy_refresh = sdl_refresh;
> dcl->dpy_setdata = sdl_setdata;
> dcl->dpy_fill = sdl_fill;
> - ds->mouse_set = sdl_mouse_warp;
> - ds->cursor_define = sdl_mouse_define;
> + dcl->dpy_mouse_set = sdl_mouse_warp;
> + dcl->dpy_cursor_define = sdl_mouse_define;
> register_displaychangelistener(ds, dcl);
>
> da = g_malloc0(sizeof(DisplayAllocator));
> diff --git a/ui/spice-display.c b/ui/spice-display.c
> index 50fbefb..5180428 100644
> --- a/ui/spice-display.c
> +++ b/ui/spice-display.c
> @@ -441,12 +441,12 @@ void qemu_spice_display_resize(SimpleSpiceDisplay *ssd)
> void qemu_spice_cursor_refresh_unlocked(SimpleSpiceDisplay *ssd)
> {
> if (ssd->cursor) {
> - ssd->ds->cursor_define(ssd->cursor);
> + dpy_cursor_define(ssd->ds, ssd->cursor);
> cursor_put(ssd->cursor);
> ssd->cursor = NULL;
> }
> if (ssd->mouse_x != -1 && ssd->mouse_y != -1) {
> - ssd->ds->mouse_set(ssd->mouse_x, ssd->mouse_y, 1);
> + dpy_mouse_set(ssd->ds, ssd->mouse_x, ssd->mouse_y, 1);
> ssd->mouse_x = -1;
> ssd->mouse_y = -1;
> }
> diff --git a/ui/vnc.c b/ui/vnc.c
> index 385e345..f8f058d 100644
> --- a/ui/vnc.c
> +++ b/ui/vnc.c
> @@ -798,7 +798,7 @@ static void vnc_dpy_copy(DisplayState *ds, int src_x, int src_y, int dst_x, int
> }
> }
>
> -static void vnc_mouse_set(int x, int y, int visible)
> +static void vnc_mouse_set(DisplayState *ds, int x, int y, int visible)
> {
> /* can we ask the client(s) to move the pointer ??? */
> }
> @@ -825,7 +825,7 @@ static int vnc_cursor_define(VncState *vs)
> return -1;
> }
>
> -static void vnc_dpy_cursor_define(QEMUCursor *c)
> +static void vnc_dpy_cursor_define(DisplayState *ds, QEMUCursor *c)
> {
> VncDisplay *vd = vnc_display;
> VncState *vs;
> @@ -2751,9 +2751,9 @@ void vnc_display_init(DisplayState *ds)
> dcl->dpy_update = vnc_dpy_update;
> dcl->dpy_resize = vnc_dpy_resize;
> dcl->dpy_setdata = vnc_dpy_setdata;
> + dcl->dpy_mouse_set = vnc_mouse_set;
> + dcl->dpy_cursor_define = vnc_dpy_cursor_define;
> register_displaychangelistener(ds, dcl);
> - ds->mouse_set = vnc_mouse_set;
> - ds->cursor_define = vnc_dpy_cursor_define;
> }
>
>
> --
> 1.7.1
>
>
^ permalink raw reply [flat|nested] 29+ messages in thread
* Re: [Qemu-devel] [PATCH 4/9] fbdev: add linux framebuffer display driver.
2012-09-18 7:17 ` [Qemu-devel] [PATCH 4/9] fbdev: add linux framebuffer display driver Gerd Hoffmann
@ 2012-09-18 15:01 ` Stefano Stabellini
2012-09-19 5:19 ` Gerd Hoffmann
2012-09-19 18:37 ` Blue Swirl
1 sibling, 1 reply; 29+ messages in thread
From: Stefano Stabellini @ 2012-09-18 15:01 UTC (permalink / raw)
To: Gerd Hoffmann; +Cc: qemu-devel@nongnu.org
On Tue, 18 Sep 2012, Gerd Hoffmann wrote:
> Display works, requires truecolor framebuffer with 16 or 32 bpp on the
> host. 32bpp is recommended. The framebuffer is used as-is, qemu
> doesn't try to switch modes. With LCD displays mode switching is pretty
> pointless IMHO, also it wouldn't work anyway with the most common
> fbdev drivers (vesafb, KMS). Guest display is centered on the host
> screen.
>
> Mouse works, uses /dev/input/mice.
>
> Keyboard works. Guest screen has whatever keymap you load inside
> the guest. Text windows (monitor, serial, ...) have a simple en-us
> keymap. Good enough to type monitor commands. Not goot enough to
> work seriously on a serial terminal. But the qemu terminal emulation
> isn't good enough for that anyway ;)
>
> Hot keys:
> Ctrl-Alt-F<nr> -> host console switching.
> Ctrl-Alt-<nr> -> qemu console switching.
> Ctrl-Alt-ESC -> exit qemu.
>
> Special feature: Sane console switching. Switching away stops screen
> updates. Switching back redraws the screen. When started from the
> linux console qemu uses the vt you've started it from (requires just
> read/write access to /dev/fb0). When starting from somewhere else qemu
> tries to open a unused virtual terminal and switch to it (usually
> requires root privileges to open /dev/tty<nr>).
>
> Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
This series is not bisectable: this patch references functions and
variables only defined in later patches (surface,
pixman_from_displaystate). Please make it bisectable.
It also makes it harder to review.
At the very least the Makefile changes should be in the last patch.
> console.h | 4 +
> qemu-options.hx | 8 +
> sysemu.h | 1 +
> trace-events | 15 +
> ui/Makefile.objs | 1 +
> ui/fbdev.c | 974 +++++++++++++++++++++++++++++++++++++++++++++++++++
> ui/linux-keynames.h | 388 ++++++++++++++++++++
> vl.c | 12 +
> 8 files changed, 1403 insertions(+), 0 deletions(-)
> create mode 100644 ui/fbdev.c
> create mode 100644 ui/linux-keynames.h
>
> diff --git a/console.h b/console.h
> index bef2d2d..0a3bae2 100644
> --- a/console.h
> +++ b/console.h
> @@ -417,6 +417,10 @@ void qemu_console_copy(DisplayState *ds, int src_x, int src_y,
> /* sdl.c */
> void sdl_display_init(DisplayState *ds, int full_screen, int no_frame);
>
> +/* fbdev.c */
> +int fbdev_display_init(DisplayState *ds, const char *device);
> +void fbdev_display_uninit(DisplayState *ds);
> +
> /* cocoa.m */
> void cocoa_display_init(DisplayState *ds, int full_screen);
>
> diff --git a/qemu-options.hx b/qemu-options.hx
> index 09c86c4..3445655 100644
> --- a/qemu-options.hx
> +++ b/qemu-options.hx
> @@ -947,6 +947,14 @@ Enable/disable spice seamless migration. Default is off.
> @end table
> ETEXI
>
> +DEF("fbdev", 0, QEMU_OPTION_fbdev,
> + "-fbdev enable fbdev\n", QEMU_ARCH_ALL)
> +STEXI
> +@item -fbdev
> +@findex -fbdev
> +Enable fbdev (linux framebuffer).
> +ETEXI
> +
> DEF("portrait", 0, QEMU_OPTION_portrait,
> "-portrait rotate graphical output 90 deg left (only PXA LCD)\n",
> QEMU_ARCH_ALL)
> diff --git a/sysemu.h b/sysemu.h
> index 65552ac..34e6bfa 100644
> --- a/sysemu.h
> +++ b/sysemu.h
> @@ -93,6 +93,7 @@ typedef enum DisplayType
> DT_DEFAULT,
> DT_CURSES,
> DT_SDL,
> + DT_FBDEV,
> DT_NOGRAPHIC,
> DT_NONE,
> } DisplayType;
> diff --git a/trace-events b/trace-events
> index b48fe2d..0d0b7fa 100644
> --- a/trace-events
> +++ b/trace-events
> @@ -994,3 +994,18 @@ spapr_pci_rtas_ibm_change_msi(unsigned func, unsigned req) "func %u, requested %
> spapr_pci_rtas_ibm_query_interrupt_source_number(unsigned ioa, unsigned intr) "queries for #%u, IRQ%u"
> spapr_pci_msi_write(uint64_t addr, uint64_t data, uint32_t dt_irq) "@%"PRIx64"<=%"PRIx64" IRQ %u"
> spapr_pci_lsi_set(const char *busname, int pin, uint32_t irq) "%s PIN%d IRQ %u"
> +
> +# ui/fbdev.c
> +fbdev_enabled(void) ""
> +fbdev_cleanup(void) ""
> +fbdev_vt_activate(int vtno, int wait) "vtno %d, wait %d"
> +fbdev_vt_activated(void) ""
> +fbdev_vt_release_request(void) ""
> +fbdev_vt_released(void) ""
> +fbdev_vt_aquire_request(void) ""
> +fbdev_vt_aquired(void) ""
> +fbdev_kbd_raw(int enable) "enable %d"
> +fbdev_kbd_event(int keycode, const char *kname, int up) "keycode 0x%x [%s], down %d"
> +fbdev_dpy_resize(int w, int h) "%dx%d"
> +fbdev_dpy_redraw(void)
> +
> diff --git a/ui/Makefile.objs b/ui/Makefile.objs
> index adc07be..55ddcf2 100644
> --- a/ui/Makefile.objs
> +++ b/ui/Makefile.objs
> @@ -12,3 +12,4 @@ common-obj-$(CONFIG_SDL) += sdl.o sdl_zoom.o x_keymap.o
> common-obj-$(CONFIG_COCOA) += cocoa.o
> common-obj-$(CONFIG_CURSES) += curses.o
> common-obj-$(CONFIG_VNC) += $(vnc-obj-y)
> +common-obj-$(CONFIG_LINUX) += fbdev.o
> diff --git a/ui/fbdev.c b/ui/fbdev.c
> new file mode 100644
> index 0000000..40fc7d4
> --- /dev/null
> +++ b/ui/fbdev.c
> @@ -0,0 +1,974 @@
> +/*
> + * linux fbdev output driver.
> + *
> + * Author: Gerd Hoffmann <kraxel@redhat.com>
> + *
> + * This work is licensed under the terms of the GNU GPL, version 2 or later.
> + * See the COPYING file in the top-level directory.
> + *
> + */
> +#include <stdio.h>
> +#include <stdlib.h>
> +#include <stdbool.h>
> +#include <string.h>
> +#include <unistd.h>
> +#include <fcntl.h>
> +#include <signal.h>
> +#include <termios.h>
> +
> +#include <sys/ioctl.h>
> +#include <sys/mman.h>
> +
> +#include <linux/kd.h>
> +#include <linux/vt.h>
> +#include <linux/fb.h>
> +
> +#include "qemu-common.h"
> +#include "console.h"
> +#include "keymaps.h"
> +#include "sysemu.h"
> +#include "pflib.h"
> +
> +/*
> + * must be last so we get the linux input layer
> + * KEY_* defines, not the ncurses ones.
> + */
> +#include <linux/input.h>
> +
> +/* -------------------------------------------------------------------- */
> +
> +/* file handles */
> +static int tty = -1, fb = -1, mice = -1;
> +
> +/* saved state, for restore on exit */
> +static int orig_vtno;
> +static int kd_omode;
> +static struct vt_mode vt_omode;
> +static struct fb_var_screeninfo fb_ovar;
> +
> +/* framebuffer */
> +static struct fb_fix_screeninfo fb_fix;
> +static struct fb_var_screeninfo fb_var;
> +static uint8_t *fb_mem;
> +static int fb_mem_offset;
> +
> +/* linux console */
> +static int vtno;
> +static struct vt_mode vt_mode;
> +static struct termios tty_attributes;
> +static unsigned long tty_mode;
> +static unsigned int tty_flags;
> +static bool tty_mediumraw;
> +static bool key_down[KEY_CNT];
> +
> +/* console switching */
> +#define SIG_ACQ (SIGRTMIN+6)
> +#define SIG_REL (SIGRTMIN+7)
> +#define FB_ACTIVE 0
> +#define FB_REL_REQ 1
> +#define FB_INACTIVE 2
> +#define FB_ACQ_REQ 3
> +static int fb_switch_state;
> +
> +/* qdev windup */
> +static DisplayChangeListener *dcl;
> +static QemuPfConv *conv;
> +static PixelFormat fbpf;
> +static int resize_screen;
> +static int redraw_screen;
> +static int cx, cy, cw, ch;
> +static Notifier exit_notifier;
> +
> +/* fwd decls */
> +static int fbdev_activate_vt(int tty, int vtno, bool wait);
> +
> +/* -------------------------------------------------------------------- */
> +/* mouse */
> +
> +static void read_mouse(void *opaque)
> +{
> + char buf[3];
> + int rc, x, y, b;
> +
> + rc = read(mice, buf, sizeof(buf));
> + if (rc != sizeof(buf)) {
> + return;
> + }
> +
> + if (fb_switch_state != FB_ACTIVE) {
> + return;
> + }
> +
> + x = buf[1];
> + y = -buf[2];
> + b = buf[0] & 0x7;
> +
> + if (kbd_mouse_is_absolute()) {
> + static int ax, ay;
> + ax += x; ay += y;
> + if (ax < 0) {
> + ax = 0;
> + }
> + if (ay < 0) {
> + ay = 0;
> + }
> + if (ax >= cw) {
> + ax = cw-1;
> + }
> + if (ay >= ch) {
> + ay = ch-1;
> + }
> + kbd_mouse_event(ax * 0x7FFF / cw, ay * 0x7FFF / ch, 0, b);
> + } else {
> + kbd_mouse_event(x, y, 0, b);
> + }
> +}
> +
> +static int init_mouse(void)
> +{
> + mice = open("/dev/input/mice", O_RDONLY);
> + if (mice == -1) {
> + return -1;
> + }
> + qemu_set_fd_handler(mice, read_mouse, NULL, NULL);
> + return 0;
> +}
> +
> +static void uninit_mouse(void)
> +{
> + if (mice == -1) {
> + return;
> + }
> + qemu_set_fd_handler(mice, NULL, NULL, NULL);
> + close(mice);
> + mice = -1;
> +}
> +
> +/* -------------------------------------------------------------------- */
> +/* keyboard */
> +
> +static const char *keynames[] = {
> +#include "linux-keynames.h"
> +};
> +
> +static const int scancode_map[KEY_CNT] = {
> + [KEY_ESC] = 0x01,
> + [KEY_1] = 0x02,
> + [KEY_2] = 0x03,
> + [KEY_3] = 0x04,
> + [KEY_4] = 0x05,
> + [KEY_5] = 0x06,
> + [KEY_6] = 0x07,
> + [KEY_7] = 0x08,
> + [KEY_8] = 0x09,
> + [KEY_9] = 0x0a,
> + [KEY_0] = 0x0b,
> + [KEY_MINUS] = 0x0c,
> + [KEY_EQUAL] = 0x0d,
> + [KEY_BACKSPACE] = 0x0e,
> +
> + [KEY_TAB] = 0x0f,
> + [KEY_Q] = 0x10,
> + [KEY_W] = 0x11,
> + [KEY_E] = 0x12,
> + [KEY_R] = 0x13,
> + [KEY_T] = 0x14,
> + [KEY_Y] = 0x15,
> + [KEY_U] = 0x16,
> + [KEY_I] = 0x17,
> + [KEY_O] = 0x18,
> + [KEY_P] = 0x19,
> + [KEY_LEFTBRACE] = 0x1a,
> + [KEY_RIGHTBRACE] = 0x1b,
> + [KEY_ENTER] = 0x1c,
> +
> + [KEY_A] = 0x1e,
> + [KEY_S] = 0x1f,
> + [KEY_D] = 0x20,
> + [KEY_F] = 0x21,
> + [KEY_G] = 0x22,
> + [KEY_H] = 0x23,
> + [KEY_J] = 0x24,
> + [KEY_K] = 0x25,
> + [KEY_L] = 0x26,
> + [KEY_SEMICOLON] = 0x27,
> + [KEY_APOSTROPHE] = 0x28,
> + [KEY_GRAVE] = 0x29,
> + [KEY_LEFTSHIFT] = 0x2a,
> + [KEY_BACKSLASH] = 0x2b,
> +
> + [KEY_Z] = 0x2c,
> + [KEY_X] = 0x2d,
> + [KEY_C] = 0x2e,
> + [KEY_V] = 0x2f,
> + [KEY_B] = 0x30,
> + [KEY_N] = 0x31,
> + [KEY_M] = 0x32,
> + [KEY_COMMA] = 0x33,
> + [KEY_DOT] = 0x34,
> + [KEY_SLASH] = 0x35,
> + [KEY_RIGHTSHIFT] = 0x36,
> + [KEY_SPACE] = 0x39,
> +
> + [KEY_F1] = 0x3b,
> + [KEY_F2] = 0x3c,
> + [KEY_F3] = 0x3d,
> + [KEY_F4] = 0x3e,
> + [KEY_F5] = 0x3f,
> + [KEY_F6] = 0x40,
> + [KEY_F7] = 0x41,
> + [KEY_F8] = 0x42,
> + [KEY_F9] = 0x43,
> + [KEY_F10] = 0x44,
> + [KEY_F11] = 0x57,
> + [KEY_F12] = 0x58,
> +
> + [KEY_SYSRQ] = 0xb7,
> + [KEY_SCROLLLOCK] = 0x46,
> +#if 0
> + [KEY_PAUSE] = FIXME,
> +#endif
> + [KEY_CAPSLOCK] = 0x3a,
> + [KEY_102ND] = 0x56,
> +
> + [KEY_LEFTCTRL] = 0x1d,
> + [KEY_LEFTMETA] = 0xdb,
> + [KEY_LEFTALT] = 0x38,
> + [KEY_RIGHTALT] = 0xb8,
> + [KEY_RIGHTMETA] = 0xdc,
> + [KEY_RIGHTCTRL] = 0x9d,
> + [KEY_COMPOSE] = 0xdd,
> +
> + [KEY_INSERT] = 0xd2,
> + [KEY_DELETE] = 0xd3,
> + [KEY_HOME] = 0xc7,
> + [KEY_END] = 0xcf,
> + [KEY_PAGEUP] = 0xc9,
> + [KEY_PAGEDOWN] = 0xd1,
> +
> + [KEY_UP] = 0xc8,
> + [KEY_LEFT] = 0xcb,
> + [KEY_RIGHT] = 0xcd,
> + [KEY_DOWN] = 0xd0,
> +
> + [KEY_NUMLOCK] = 0x45,
> + [KEY_KPSLASH] = 0xb5,
> + [KEY_KPASTERISK] = 0x37,
> + [KEY_KP7] = 0x47,
> + [KEY_KP8] = 0x48,
> + [KEY_KP9] = 0x49,
> + [KEY_KPMINUS] = 0x4a,
> + [KEY_KP4] = 0x4b,
> + [KEY_KP5] = 0x4c,
> + [KEY_KP6] = 0x4d,
> + [KEY_KPPLUS] = 0x4e,
> + [KEY_KP1] = 0x4f,
> + [KEY_KP2] = 0x50,
> + [KEY_KP3] = 0x51,
> + [KEY_KP0] = 0x52,
> + [KEY_KPDOT] = 0x53,
> + [KEY_KPENTER] = 0x9c,
> +};
> +
> +static const struct keysym_map {
> + int normal, shifted;
> +} keysym_map_en_us[KEY_CNT] = {
> + [KEY_A] = { .normal = 'a', .shifted = 'A' },
> + [KEY_B] = { .normal = 'b', .shifted = 'B' },
> + [KEY_C] = { .normal = 'c', .shifted = 'C' },
> + [KEY_D] = { .normal = 'd', .shifted = 'D' },
> + [KEY_E] = { .normal = 'e', .shifted = 'E' },
> + [KEY_F] = { .normal = 'f', .shifted = 'F' },
> + [KEY_G] = { .normal = 'g', .shifted = 'G' },
> + [KEY_H] = { .normal = 'h', .shifted = 'H' },
> + [KEY_I] = { .normal = 'i', .shifted = 'I' },
> + [KEY_J] = { .normal = 'j', .shifted = 'J' },
> + [KEY_K] = { .normal = 'k', .shifted = 'K' },
> + [KEY_L] = { .normal = 'l', .shifted = 'L' },
> + [KEY_M] = { .normal = 'm', .shifted = 'M' },
> + [KEY_N] = { .normal = 'n', .shifted = 'N' },
> + [KEY_O] = { .normal = 'o', .shifted = 'O' },
> + [KEY_P] = { .normal = 'p', .shifted = 'P' },
> + [KEY_Q] = { .normal = 'q', .shifted = 'Q' },
> + [KEY_R] = { .normal = 'r', .shifted = 'R' },
> + [KEY_S] = { .normal = 's', .shifted = 'S' },
> + [KEY_T] = { .normal = 't', .shifted = 'T' },
> + [KEY_U] = { .normal = 'u', .shifted = 'U' },
> + [KEY_V] = { .normal = 'v', .shifted = 'V' },
> + [KEY_W] = { .normal = 'w', .shifted = 'W' },
> + [KEY_X] = { .normal = 'x', .shifted = 'X' },
> + [KEY_Y] = { .normal = 'y', .shifted = 'Y' },
> + [KEY_Z] = { .normal = 'z', .shifted = 'Z' },
> +
> + [KEY_1] = { .normal = '1', .shifted = '!' },
> + [KEY_2] = { .normal = '2', .shifted = '@' },
> + [KEY_3] = { .normal = '3', .shifted = '#' },
> + [KEY_4] = { .normal = '4', .shifted = '$' },
> + [KEY_5] = { .normal = '5', .shifted = '%' },
> + [KEY_6] = { .normal = '6', .shifted = '^' },
> + [KEY_7] = { .normal = '7', .shifted = '&' },
> + [KEY_8] = { .normal = '8', .shifted = '*' },
> + [KEY_9] = { .normal = '9', .shifted = '(' },
> + [KEY_0] = { .normal = '0', .shifted = ')' },
> +
> + [KEY_MINUS] = { .normal = '-', .shifted = '_' },
> + [KEY_EQUAL] = { .normal = '=', .shifted = '+' },
> + [KEY_TAB] = { .normal = '\t' },
> + [KEY_LEFTBRACE] = { .normal = '[', .shifted = '{' },
> + [KEY_RIGHTBRACE] = { .normal = ']', .shifted = '}' },
> + [KEY_ENTER] = { .normal = '\n', },
> + [KEY_SEMICOLON] = { .normal = ';', .shifted = ':' },
> + [KEY_APOSTROPHE] = { .normal = '"', .shifted = '\'' },
> + [KEY_BACKSLASH] = { .normal = '\\', .shifted = '|' },
> + [KEY_COMMA] = { .normal = ',', .shifted = '<' },
> + [KEY_DOT] = { .normal = '.', .shifted = '>' },
> + [KEY_SLASH] = { .normal = '/', .shifted = '?' },
> + [KEY_SPACE] = { .normal = ' ' },
> +
> + [KEY_BACKSPACE] = { .normal = QEMU_KEY_BACKSPACE },
> + [KEY_UP] = { .normal = QEMU_KEY_UP },
> + [KEY_DOWN] = { .normal = QEMU_KEY_DOWN },
> + [KEY_LEFT] = { .normal = QEMU_KEY_LEFT },
> + [KEY_RIGHT] = { .normal = QEMU_KEY_RIGHT },
> +};
> +
> +static void start_mediumraw(int tty)
> +{
> + struct termios tattr;
> +
> + if (tty_mediumraw) {
> + return;
> + }
> + trace_fbdev_kbd_raw(1);
> +
> + /* save state */
> + tcgetattr(tty, &tty_attributes);
> + ioctl(tty, KDGKBMODE, &tty_mode);
> + tty_flags = fcntl(tty, F_GETFL, NULL);
> +
> + /* setup */
> + tattr = tty_attributes;
> + tattr.c_cflag &= ~(IXON|IXOFF);
> + tattr.c_lflag &= ~(ICANON|ECHO|ISIG);
> + tattr.c_iflag = 0;
> + tattr.c_cc[VMIN] = 1;
> + tattr.c_cc[VTIME] = 0;
> + tcsetattr(tty, TCSAFLUSH, &tattr);
> + ioctl(tty, KDSKBMODE, K_MEDIUMRAW);
> + fcntl(tty, F_SETFL, tty_flags | O_NONBLOCK);
> +
> + tty_mediumraw = true;
> +}
> +
> +static void stop_mediumraw(int tty)
> +{
> + if (!tty_mediumraw) {
> + return;
> + }
> + trace_fbdev_kbd_raw(0);
> +
> + /* restore state */
> + tcsetattr(tty, TCSANOW, &tty_attributes);
> + ioctl(tty, KDSKBMODE, tty_mode);
> + fcntl(tty, F_SETFL, tty_flags);
> +
> + tty_mediumraw = false;
> +}
> +
> +static void send_scancode(int keycode, int up)
> +{
> + int scancode = scancode_map[keycode];
> +
> + if (!scancode) {
> + fprintf(stderr, "%s: unmapped key: 0x%x %s\n",
> + __func__, keycode, keynames[keycode]);
> + return;
> + }
> + if (scancode & SCANCODE_GREY) {
> + kbd_put_keycode(SCANCODE_EMUL0);
> + }
> + if (up) {
> + kbd_put_keycode(scancode | SCANCODE_UP);
> + } else {
> + kbd_put_keycode(scancode & SCANCODE_KEYCODEMASK);
> + }
> +}
> +
> +static void send_keysym(int keycode, int shift)
> +{
> + const struct keysym_map *keysym_map = keysym_map_en_us;
> + int keysym;
> +
> + if (shift && keysym_map[keycode].shifted) {
> + keysym = keysym_map[keycode].shifted;
> + } else if (keysym_map[keycode].normal) {
> + keysym = keysym_map[keycode].normal;
> + } else {
> + fprintf(stderr, "%s: unmapped key: 0x%x %s\n",
> + __func__, keycode, keynames[keycode]);
> + return;
> + }
> + kbd_put_keysym(keysym);
> +}
> +
> +static void reset_keys(void)
> +{
> + int keycode;
> +
> + for (keycode = 0; keycode < KEY_MAX; keycode++) {
> + if (key_down[keycode]) {
> + if (is_graphic_console()) {
> + send_scancode(keycode, 1);
> + }
> + key_down[keycode] = false;
> + }
> + }
> +}
> +
> +static void read_mediumraw(void *opaque)
> +{
> + uint8_t buf[32];
> + int i, rc, up, keycode;
> + bool ctrl, alt, shift;
> +
> + rc = read(tty, buf, sizeof(buf));
> + switch (rc) {
> + case -1:
> + perror("read tty");
> + goto err;
> + case 0:
> + fprintf(stderr, "%s: eof\n", __func__);
> + goto err;
> + default:
> + for (i = 0; i < rc; i++) {
> + up = buf[i] & 0x80;
> + keycode = buf[i] & 0x7f;
> + if (keycode == 0) {
> + keycode = (buf[i+1] & 0x7f) << 7;
> + keycode |= buf[i+2] & 0x7f;
> + i += 2;
> + }
> + if (keycode > KEY_MAX) {
> + continue;
> + }
> +
> + if (up) {
> + if (!key_down[keycode]) {
> + continue;
> + }
> + key_down[keycode] = false;
> + } else {
> + key_down[keycode] = true;
> + }
> +
> + trace_fbdev_kbd_event(keycode, keynames[keycode], !up);
> +
> + alt = key_down[KEY_LEFTALT] || key_down[KEY_RIGHTALT];
> + ctrl = key_down[KEY_LEFTCTRL] || key_down[KEY_RIGHTCTRL];
> + shift = key_down[KEY_LEFTSHIFT] || key_down[KEY_RIGHTSHIFT];
> +
> + if (ctrl && alt && !up) {
> + if (keycode == KEY_ESC) {
> + fprintf(stderr, "=== fbdev emergency escape "
> + "(ctrl-alt-esc) ===\n");
> + exit(1);
> + }
> + if (keycode >= KEY_F1 && keycode <= KEY_F10) {
> + fbdev_activate_vt(tty, keycode+1-KEY_F1, false);
> + key_down[keycode] = false;
> + continue;
> + }
> + if (keycode >= KEY_1 && keycode <= KEY_9) {
> + console_select(keycode-KEY_1);
> + reset_keys();
> + continue;
> + }
> + }
> +
> + if (is_graphic_console()) {
> + send_scancode(keycode, up);
> + } else if (!up) {
> + send_keysym(keycode, shift);
> + }
> + }
> + }
> + return;
> +
> +err:
> + exit(1);
> +}
> +
> +/* -------------------------------------------------------------------- */
> +
> +static void fbdev_cls(void)
> +{
> + memset(fb_mem + fb_mem_offset, 0, fb_fix.line_length * fb_var.yres);
> +}
> +
> +static int fbdev_activate_vt(int tty, int vtno, bool wait)
> +{
> + trace_fbdev_vt_activate(vtno, wait);
> +
> + if (ioctl(tty, VT_ACTIVATE, vtno) < 0) {
> + perror("ioctl VT_ACTIVATE");
> + return -1;
> + }
> +
> + if (wait) {
> + if (ioctl(tty, VT_WAITACTIVE, vtno) < 0) {
> + perror("ioctl VT_WAITACTIVE");
> + return -1;
> + }
> + trace_fbdev_vt_activated();
> + }
> +
> + return 0;
> +}
> +
> +static void fbdev_cleanup(void)
> +{
> + trace_fbdev_cleanup();
> +
> + /* restore console */
> + if (fb_mem != NULL) {
> + munmap(fb_mem, fb_fix.smem_len+fb_mem_offset);
> + fb_mem = NULL;
> + }
> + if (fb != -1) {
> + if (ioctl(fb, FBIOPUT_VSCREENINFO, &fb_ovar) < 0) {
> + perror("ioctl FBIOPUT_VSCREENINFO");
> + }
> + close(fb);
> + fb = -1;
> + }
> +
> + if (tty != -1) {
> + stop_mediumraw(tty);
> + if (ioctl(tty, KDSETMODE, kd_omode) < 0) {
> + perror("ioctl KDSETMODE");
> + }
> + if (ioctl(tty, VT_SETMODE, &vt_omode) < 0) {
> + perror("ioctl VT_SETMODE");
> + }
> + if (orig_vtno) {
> + fbdev_activate_vt(tty, orig_vtno, true);
> + }
> + qemu_set_fd_handler(tty, NULL, NULL, NULL);
> + close(tty);
> + tty = -1;
> + }
> +}
> +
> +static int fbdev_init(const char *device)
> +{
> + struct vt_stat vts;
> + unsigned long page_mask;
> + char ttyname[32];
> +
> + /* open framebuffer */
> + if (device == NULL) {
> + device = getenv("FRAMEBUFFER");
> + }
> + if (device == NULL) {
> + device = "/dev/fb0";
> + }
> + fb = open(device, O_RDWR);
> + if (fb == -1) {
> + fprintf(stderr, "open %s: %s\n", device, strerror(errno));
> + return -1;
> + }
> +
> + /* open virtual console */
> + tty = 0;
> + if (ioctl(tty, VT_GETSTATE, &vts) < 0) {
> + fprintf(stderr, "Not started from virtual terminal, "
> + "trying to open one.\n");
> +
> + snprintf(ttyname, sizeof(ttyname), "/dev/tty0");
> + tty = open(ttyname, O_RDWR);
> + if (tty == -1) {
> + fprintf(stderr, "open %s: %s\n", ttyname, strerror(errno));
> + goto err_early;
> + }
> + if (ioctl(tty, VT_OPENQRY, &vtno) < 0) {
> + perror("ioctl VT_OPENQRY");
> + goto err_early;
> + }
> + if (ioctl(tty, VT_GETSTATE, &vts) < 0) {
> + perror("ioctl VT_GETSTATE\n");
> + goto err_early;
> + }
> + close(tty);
> +
> + snprintf(ttyname, sizeof(ttyname), "/dev/tty%d", vtno);
> + tty = open(ttyname, O_RDWR);
> + if (tty == -1) {
> + fprintf(stderr, "open %s: %s\n", ttyname, strerror(errno));
> + goto err_early;
> + }
> + orig_vtno = vts.v_active;
> + fprintf(stderr, "Switching to vt %d (current %d).\n", vtno, orig_vtno);
> + } else {
> + orig_vtno = 0;
> + vtno = vts.v_active;
> + fprintf(stderr, "Started at vt %d, using it.\n", vtno);
> + }
> + fbdev_activate_vt(tty, vtno, true);
> +
> + /* get current settings (which we have to restore) */
> + if (ioctl(fb, FBIOGET_VSCREENINFO, &fb_ovar) < 0) {
> + perror("ioctl FBIOGET_VSCREENINFO");
> + goto err_early;
> + }
> + if (ioctl(tty, KDGETMODE, &kd_omode) < 0) {
> + perror("ioctl KDGETMODE");
> + goto err_early;
> + }
> + if (ioctl(tty, VT_GETMODE, &vt_omode) < 0) {
> + perror("ioctl VT_GETMODE");
> + goto err_early;
> + }
> +
> + /* checks & initialisation */
> + if (ioctl(fb, FBIOGET_FSCREENINFO, &fb_fix) < 0) {
> + perror("ioctl FBIOGET_FSCREENINFO");
> + goto err;
> + }
> + if (ioctl(fb, FBIOGET_VSCREENINFO, &fb_var) < 0) {
> + perror("ioctl FBIOGET_VSCREENINFO");
> + goto err;
> + }
> + if (fb_fix.type != FB_TYPE_PACKED_PIXELS) {
> + fprintf(stderr, "can handle only packed pixel frame buffers\n");
> + goto err;
> + }
> + switch (fb_var.bits_per_pixel) {
> + case 32:
> + break;
> + default:
> + fprintf(stderr, "can't handle %d bpp frame buffers\n",
> + fb_var.bits_per_pixel);
> + goto err;
> + }
> +
> + page_mask = getpagesize()-1;
> + fb_switch_state = FB_ACTIVE;
> + fb_mem_offset = (unsigned long)(fb_fix.smem_start) & page_mask;
> + fb_mem = mmap(NULL, fb_fix.smem_len+fb_mem_offset,
> + PROT_READ|PROT_WRITE, MAP_SHARED, fb, 0);
> + if (fb_mem == MAP_FAILED) {
> + perror("mmap");
> + goto err;
> + }
> + /* move viewport to upper left corner */
> + if (fb_var.xoffset != 0 || fb_var.yoffset != 0) {
> + fb_var.xoffset = 0;
> + fb_var.yoffset = 0;
> + if (ioctl(fb, FBIOPAN_DISPLAY, &fb_var) < 0) {
> + perror("ioctl FBIOPAN_DISPLAY");
> + goto err;
> + }
> + }
> + if (ioctl(tty, KDSETMODE, KD_GRAPHICS) < 0) {
> + perror("ioctl KDSETMODE");
> + goto err;
> + }
> + /* some fb drivers need this again after switching to graphics ... */
> + fbdev_activate_vt(tty, vtno, true);
> +
> + fbdev_cls();
> +
> + start_mediumraw(tty);
> + qemu_set_fd_handler(tty, read_mediumraw, NULL, NULL);
> +
> + /* create PixelFormat from fbdev structs */
> + fbpf.bits_per_pixel = fb_var.bits_per_pixel;
> + fbpf.bytes_per_pixel = (fb_var.bits_per_pixel+7)/8;
> + fbpf.depth = fb_var.bits_per_pixel == 32
> + ? 24 : fb_var.bits_per_pixel;
> + fbpf.rshift = fb_var.red.offset;
> + fbpf.rbits = fb_var.red.length;
> + fbpf.gshift = fb_var.green.offset;
> + fbpf.gbits = fb_var.green.length;
> + fbpf.bshift = fb_var.blue.offset;
> + fbpf.bbits = fb_var.blue.length;
> + fbpf.ashift = fb_var.transp.offset;
> + fbpf.abits = fb_var.transp.length;
the conversion should probably be in an separate helper function
> + if (fbpf.rbits) {
> + fbpf.rmax = (1 << fbpf.rbits) - 1;
> + fbpf.rmask = fbpf.rmax << fbpf.rshift;
> + }
> + if (fbpf.gbits) {
> + fbpf.gmax = (1 << fbpf.gbits) - 1;
> + fbpf.gmask = fbpf.gmax << fbpf.gshift;
> + }
> + if (fbpf.bbits) {
> + fbpf.bmax = (1 << fbpf.bbits) - 1;
> + fbpf.bmask = fbpf.bmax << fbpf.bshift;
> + }
> + if (fbpf.abits) {
> + fbpf.amax = (1 << fbpf.abits) - 1;
> + fbpf.amask = fbpf.amax << fbpf.ashift;
> + }
> + return 0;
> +
> +err_early:
> + if (tty > 0) {
> + close(tty);
> + }
> + close(fb);
> + return -1;
> +
> +err:
> + fbdev_cleanup();
> + return -1;
> +}
> +
> +static void
> +fbdev_catch_fatal_signal(int signr)
> +{
> + fprintf(stderr, "%s: %s, restoring linux console state ...\n",
> + __func__, strsignal(signr));
> + fbdev_cleanup();
> + signal(SIGABRT, SIG_DFL);
> + fprintf(stderr, "%s: ... done, going abort() now.\n", __func__);
> + abort();
> +}
> +
> +static void fbdev_catch_exit_signals(void)
> +{
> + static const int signals[] = {
> + SIGQUIT, SIGILL, SIGABRT, SIGFPE, SIGSEGV, SIGBUS
> + };
> + struct sigaction act, old;
> + int i;
> +
> + memset(&act, 0, sizeof(act));
> + act.sa_handler = fbdev_catch_fatal_signal;
> + act.sa_flags = SA_RESETHAND;
> + sigemptyset(&act.sa_mask);
> + for (i = 0; i < ARRAY_SIZE(signals); i++) {
> + sigaction(signals[i], &act, &old);
> + }
> +}
> +
> +/* -------------------------------------------------------------------- */
> +/* console switching */
> +
> +static void fbdev_switch_signal(int signal)
> +{
> + if (signal == SIG_REL) {
> + /* release */
> + trace_fbdev_vt_release_request();
> + fb_switch_state = FB_REL_REQ;
> + }
> + if (signal == SIG_ACQ) {
> + /* acquisition */
> + trace_fbdev_vt_aquire_request();
> + fb_switch_state = FB_ACQ_REQ;
> + }
> +}
> +
> +static void fbdev_switch_release(void)
> +{
> + stop_mediumraw(tty);
> + ioctl(tty, KDSETMODE, kd_omode);
> + ioctl(tty, VT_RELDISP, 1);
> + fb_switch_state = FB_INACTIVE;
> + trace_fbdev_vt_released();
> +}
> +
> +static void fbdev_switch_acquire(void)
> +{
> + ioctl(tty, VT_RELDISP, VT_ACKACQ);
> + start_mediumraw(tty);
> + reset_keys();
> + ioctl(tty, KDSETMODE, KD_GRAPHICS);
> + fb_switch_state = FB_ACTIVE;
> + trace_fbdev_vt_aquired();
> +}
> +
> +static int fbdev_switch_init(void)
> +{
> + struct sigaction act, old;
> +
> + memset(&act, 0, sizeof(act));
> + act.sa_handler = fbdev_switch_signal;
> + sigemptyset(&act.sa_mask);
> + sigaction(SIG_REL, &act, &old);
> + sigaction(SIG_ACQ, &act, &old);
> +
> + if (ioctl(tty, VT_GETMODE, &vt_mode) < 0) {
> + perror("ioctl VT_GETMODE");
> + exit(1);
> + }
> + vt_mode.mode = VT_PROCESS;
> + vt_mode.waitv = 0;
> + vt_mode.relsig = SIG_REL;
> + vt_mode.acqsig = SIG_ACQ;
> +
> + if (ioctl(tty, VT_SETMODE, &vt_mode) < 0) {
> + perror("ioctl VT_SETMODE");
> + exit(1);
> + }
> + return 0;
> +}
> +
> +/* -------------------------------------------------------------------- */
> +/* rendering */
> +
> +static void fbdev_render(DisplayState *ds, int x, int y, int w, int h)
> +{
> + uint8_t *dst;
> + uint8_t *src;
> + int line;
> +
> + if (!conv) {
> + return;
> + }
> +
> + src = ds_get_data(ds) + y * ds_get_linesize(ds)
> + + x * ds_get_bytes_per_pixel(ds);
> + dst = fb_mem + y * fb_fix.line_length
> + + x * fbpf.bytes_per_pixel;
> +
> + dst += cy * fb_fix.line_length;
> + dst += cx * fbpf.bytes_per_pixel;
> +
> + if (h > fb_var.yres - y) {
> + h = fb_var.yres - y;
> + }
> + if (w > fb_var.xres - x) {
> + w = fb_var.xres - x;
> + }
> +
> + for (line = y; line < y+h; line++) {
> + qemu_pf_conv_run(conv, dst, src, w);
> + dst += fb_fix.line_length;
> + src += ds_get_linesize(ds);
> + }
> +}
> +
> +/* -------------------------------------------------------------------- */
> +/* qemu interfaces */
> +
> +static void fbdev_update(DisplayState *ds, int x, int y, int w, int h)
> +{
> + if (fb_switch_state != FB_ACTIVE) {
> + return;
> + }
> +
> + if (resize_screen) {
> + trace_fbdev_dpy_resize(ds_get_width(ds), ds_get_height(ds));
> + resize_screen = 0;
> + cx = 0; cy = 0;
> + cw = ds_get_width(ds);
> + ch = ds_get_height(ds);
> + if (ds_get_width(ds) < fb_var.xres) {
> + cx = (fb_var.xres - ds_get_width(ds)) / 2;
> + }
> + if (ds_get_height(ds) < fb_var.yres) {
> + cy = (fb_var.yres - ds_get_height(ds)) / 2;
> + }
> +
> + if (conv) {
> + qemu_pf_conv_put(conv);
> + }
> + conv = qemu_pf_conv_get(&fbpf, &ds->surface->pf);
> + if (conv == NULL) {
> + fprintf(stderr, "fbdev: unsupported PixelFormat conversion\n");
> + }
> + }
> +
> + if (redraw_screen) {
> + trace_fbdev_dpy_redraw();
> + redraw_screen = 0;
> + fbdev_cls();
> + x = 0; y = 0; w = ds_get_width(ds); h = ds_get_height(ds);
> + }
> +
> + fbdev_render(ds, x, y, w, h);
> +}
> +
> +static void fbdev_resize(DisplayState *ds)
> +{
> + resize_screen++;
> + redraw_screen++;
> +}
> +
> +static void fbdev_setdata(DisplayState *ds)
> +{
> + if (surface) {
^ where is this coming from?
> + pixman_image_unref(surface);
> + }
> + surface = pixman_from_displaystate(ds);
> + redraw_screen++;
> +}
> +
> +static void fbdev_refresh(DisplayState *ds)
> +{
> + switch (fb_switch_state) {
> + case FB_REL_REQ:
> + fbdev_switch_release();
> + case FB_INACTIVE:
> + return;
> + case FB_ACQ_REQ:
> + fbdev_switch_acquire();
> + redraw_screen++;
> + case FB_ACTIVE:
> + break;
> + }
> +
> + vga_hw_update();
> + if (redraw_screen) {
> + fbdev_update(ds, 0, 0, 0, 0);
> + }
> +}
> +
> +static void fbdev_exit_notifier(Notifier *notifier, void *data)
> +{
> + fbdev_cleanup();
> +}
> +
> +int fbdev_display_init(DisplayState *ds, const char *device)
> +{
> + if (dcl != NULL) {
> + return 0;
> + }
is it actually possible that fbdev_display_init gets called multiple
times?
> + if (fbdev_init(device) != 0) {
> + return -1;
> + }
> + exit_notifier.notify = fbdev_exit_notifier;
> + qemu_add_exit_notifier(&exit_notifier);
> + fbdev_switch_init();
> + fbdev_catch_exit_signals();
> + init_mouse();
> +
> + fbdev_resize(ds);
> + dcl = g_new0(DisplayChangeListener, 1);
> + dcl->dpy_update = fbdev_update;
> + dcl->dpy_resize = fbdev_resize;
> + dcl->dpy_setdata = fbdev_setdata;
> + dcl->dpy_refresh = fbdev_refresh;
> + register_displaychangelistener(ds, dcl);
>
The fbdev driver could benefit from registering a DisplayAllocator (see
sdl.c).
> + trace_fbdev_enabled();
> + return 0;
> +}
> +
> +void fbdev_display_uninit(DisplayState *ds)
> +{
> + if (dcl == NULL) {
> + return;
> + }
> +
> + unregister_displaychangelistener(ds, dcl);
> + g_free(dcl);
> + dcl = NULL;
> +
> + fbdev_cleanup();
> + qemu_remove_exit_notifier(&exit_notifier);
> + uninit_mouse();
> +}
^ permalink raw reply [flat|nested] 29+ messages in thread
* Re: [Qemu-devel] [PATCH 7/9] fbdev: move to pixman
2012-09-18 7:17 ` [Qemu-devel] [PATCH 7/9] fbdev: move to pixman Gerd Hoffmann
@ 2012-09-18 15:01 ` Stefano Stabellini
2012-09-19 5:51 ` Gerd Hoffmann
2012-09-18 19:14 ` Anthony Liguori
2012-09-18 20:30 ` Søren Sandmann
2 siblings, 1 reply; 29+ messages in thread
From: Stefano Stabellini @ 2012-09-18 15:01 UTC (permalink / raw)
To: Gerd Hoffmann; +Cc: qemu-devel@nongnu.org
On Tue, 18 Sep 2012, Gerd Hoffmann wrote:
> Stop reinventing the wheel. Use the pixman library for raster ops.
I would separate the pixmap changes from this series: either we use
this library everywhere or nowhere. At the very least vnc could use it.
Also considering that you only support 32bpp in fbdev, I am not sure
whether it actually is that useful in this case: you don't really need
to handle any pixel format conversions, at most you need to handle
differences in linesizes.
> Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
> ---
> configure | 12 ++++
> ui/fbdev.c | 172 +++++++++++++++++++++++++++++++++++------------------------
> 2 files changed, 114 insertions(+), 70 deletions(-)
>
> diff --git a/configure b/configure
> index c4ba338..d10ff78 100755
> --- a/configure
> +++ b/configure
> @@ -148,6 +148,7 @@ docs=""
> fdt=""
> nptl=""
> sdl=""
> +pixman=""
> fbdev="no"
> virtfs=""
> vnc="yes"
> @@ -2153,6 +2154,17 @@ else
> exit 1
> fi
>
> +if $pkg_config pixman-1 > /dev/null 2>&1
> +then
> + pixman="yes"
> + pixman_cflags=`$pkg_config --cflags pixman-1 2>/dev/null`
> + pixman_libs=`$pkg_config --libs pixman-1 2>/dev/null`
> + QEMU_CFLAGS="$QEMU_CFLAGS $pixman_cflags"
> + libs_softmmu="$libs_softmmu $pixman_libs"
> +else
> + fbdev="no"
> +fi
> +
> ##########################################
> # libcap probe
>
> diff --git a/ui/fbdev.c b/ui/fbdev.c
> index 40fc7d4..4cb4d1d 100644
> --- a/ui/fbdev.c
> +++ b/ui/fbdev.c
> @@ -23,11 +23,12 @@
> #include <linux/vt.h>
> #include <linux/fb.h>
>
> +#include <pixman.h>
> +
> #include "qemu-common.h"
> #include "console.h"
> #include "keymaps.h"
> #include "sysemu.h"
> -#include "pflib.h"
>
> /*
> * must be last so we get the linux input layer
> @@ -70,19 +71,82 @@ static bool key_down[KEY_CNT];
> #define FB_ACQ_REQ 3
> static int fb_switch_state;
>
> -/* qdev windup */
> +/* qemu windup */
> static DisplayChangeListener *dcl;
> -static QemuPfConv *conv;
> -static PixelFormat fbpf;
> static int resize_screen;
> static int redraw_screen;
> static int cx, cy, cw, ch;
> static Notifier exit_notifier;
> +static pixman_image_t *surface;
> +static pixman_image_t *framebuffer;
> +static pixman_transform_t transform;
> +static pixman_region16_t dirty;
>
> /* fwd decls */
> static int fbdev_activate_vt(int tty, int vtno, bool wait);
>
> /* -------------------------------------------------------------------- */
> +/* pixman helpers */
> +
> +static int pixman_shifts_to_type(int rshift, int gshift, int bshift)
> +{
> + int type = PIXMAN_TYPE_OTHER;
> +
> + if (rshift > gshift && gshift > bshift) {
> + if (bshift == 0) {
> + type = PIXMAN_TYPE_ARGB;
> + } else {
> +#if PIXMAN_VERSION >= PIXMAN_VERSION_ENCODE(0, 21, 8)
> + type = PIXMAN_TYPE_RGBA;
> +#endif
> + }
> + } else if (rshift < gshift && gshift < bshift) {
> + if (rshift == 0) {
> + type = PIXMAN_TYPE_ABGR;
> + } else {
> + type = PIXMAN_TYPE_BGRA;
> + }
> + }
> + return type;
> +}
> +
> +static pixman_image_t *pixman_from_displaystate(DisplayState *ds)
> +{
> + PixelFormat *pf = &ds->surface->pf;
> + pixman_format_code_t format;
> + pixman_image_t *image;
> + int type;
> +
> + type = pixman_shifts_to_type(pf->rshift, pf->gshift, pf->bshift);
> + format = PIXMAN_FORMAT(pf->bits_per_pixel, type,
> + pf->abits, pf->rbits, pf->gbits, pf->bbits);
> + image = pixman_image_create_bits(format, ds_get_width(ds),
> + ds_get_height(ds),
> + (void *)ds_get_data(ds),
> + ds_get_linesize(ds));
> + return image;
> +}
> +
> +static pixman_image_t *pixman_from_framebuffer(void)
> +{
> + pixman_format_code_t format;
> + pixman_image_t *image;
> + int type;
> +
> + type = pixman_shifts_to_type(fb_var.red.offset,
> + fb_var.green.offset,
> + fb_var.blue.offset);
> + format = PIXMAN_FORMAT(fb_var.bits_per_pixel, type,
> + fb_var.transp.length,
> + fb_var.red.length,
> + fb_var.green.length,
> + fb_var.blue.length);
> + image = pixman_image_create_bits(format, fb_var.xres, fb_var.yres,
> + (void *)fb_mem, fb_fix.line_length);
> + return image;
> +}
> +
> +/* -------------------------------------------------------------------- */
> /* mouse */
>
> static void read_mouse(void *opaque)
> @@ -529,6 +593,17 @@ static void fbdev_cleanup(void)
> {
> trace_fbdev_cleanup();
>
> + /* release pixman stuff */
> + pixman_region_fini(&dirty);
> + if (framebuffer) {
> + pixman_image_unref(framebuffer);
> + framebuffer = NULL;
> + }
> + if (surface) {
> + pixman_image_unref(surface);
> + surface = NULL;
> + }
> +
> /* restore console */
> if (fb_mem != NULL) {
> munmap(fb_mem, fb_fix.smem_len+fb_mem_offset);
> @@ -681,36 +756,8 @@ static int fbdev_init(const char *device)
> start_mediumraw(tty);
> qemu_set_fd_handler(tty, read_mediumraw, NULL, NULL);
>
> - /* create PixelFormat from fbdev structs */
> - fbpf.bits_per_pixel = fb_var.bits_per_pixel;
> - fbpf.bytes_per_pixel = (fb_var.bits_per_pixel+7)/8;
> - fbpf.depth = fb_var.bits_per_pixel == 32
> - ? 24 : fb_var.bits_per_pixel;
> - fbpf.rshift = fb_var.red.offset;
> - fbpf.rbits = fb_var.red.length;
> - fbpf.gshift = fb_var.green.offset;
> - fbpf.gbits = fb_var.green.length;
> - fbpf.bshift = fb_var.blue.offset;
> - fbpf.bbits = fb_var.blue.length;
> - fbpf.ashift = fb_var.transp.offset;
> - fbpf.abits = fb_var.transp.length;
> -
> - if (fbpf.rbits) {
> - fbpf.rmax = (1 << fbpf.rbits) - 1;
> - fbpf.rmask = fbpf.rmax << fbpf.rshift;
> - }
> - if (fbpf.gbits) {
> - fbpf.gmax = (1 << fbpf.gbits) - 1;
> - fbpf.gmask = fbpf.gmax << fbpf.gshift;
> - }
> - if (fbpf.bbits) {
> - fbpf.bmax = (1 << fbpf.bbits) - 1;
> - fbpf.bmask = fbpf.bmax << fbpf.bshift;
> - }
> - if (fbpf.abits) {
> - fbpf.amax = (1 << fbpf.abits) - 1;
> - fbpf.amask = fbpf.amax << fbpf.ashift;
> - }
> + framebuffer = pixman_from_framebuffer();
> + pixman_region_init(&dirty);
> return 0;
>
> err_early:
> @@ -818,36 +865,15 @@ static int fbdev_switch_init(void)
> /* -------------------------------------------------------------------- */
> /* rendering */
>
> -static void fbdev_render(DisplayState *ds, int x, int y, int w, int h)
> +static void fbdev_render(DisplayState *ds)
> {
> - uint8_t *dst;
> - uint8_t *src;
> - int line;
> -
> - if (!conv) {
> - return;
> - }
> -
> - src = ds_get_data(ds) + y * ds_get_linesize(ds)
> - + x * ds_get_bytes_per_pixel(ds);
> - dst = fb_mem + y * fb_fix.line_length
> - + x * fbpf.bytes_per_pixel;
> -
> - dst += cy * fb_fix.line_length;
> - dst += cx * fbpf.bytes_per_pixel;
> + assert(surface);
>
> - if (h > fb_var.yres - y) {
> - h = fb_var.yres - y;
> - }
> - if (w > fb_var.xres - x) {
> - w = fb_var.xres - x;
> - }
> -
> - for (line = y; line < y+h; line++) {
> - qemu_pf_conv_run(conv, dst, src, w);
> - dst += fb_fix.line_length;
> - src += ds_get_linesize(ds);
> - }
> + pixman_image_set_clip_region(surface, &dirty);
> + pixman_image_composite(PIXMAN_OP_SRC, surface, NULL, framebuffer,
> + 0, 0, 0, 0, 0, 0, fb_var.xres, fb_var.yres);
> + pixman_region_fini(&dirty);
> + pixman_region_init(&dirty);
> }
>
> /* -------------------------------------------------------------------- */
> @@ -871,14 +897,16 @@ static void fbdev_update(DisplayState *ds, int x, int y, int w, int h)
> if (ds_get_height(ds) < fb_var.yres) {
> cy = (fb_var.yres - ds_get_height(ds)) / 2;
> }
> -
> - if (conv) {
> - qemu_pf_conv_put(conv);
> - }
> - conv = qemu_pf_conv_get(&fbpf, &ds->surface->pf);
> - if (conv == NULL) {
> - fprintf(stderr, "fbdev: unsupported PixelFormat conversion\n");
> + if (surface) {
> + pixman_image_unref(surface);
> }
> + surface = pixman_from_displaystate(ds);
> +
> + pixman_transform_init_identity(&transform);
> + pixman_transform_translate(&transform, NULL,
> + pixman_int_to_fixed(-cx),
> + pixman_int_to_fixed(-cy));
> + pixman_image_set_transform(surface, &transform);
> }
>
> if (redraw_screen) {
> @@ -888,7 +916,7 @@ static void fbdev_update(DisplayState *ds, int x, int y, int w, int h)
> x = 0; y = 0; w = ds_get_width(ds); h = ds_get_height(ds);
> }
>
> - fbdev_render(ds, x, y, w, h);
> + pixman_region_union_rect(&dirty, &dirty, x, y, w, h);
> }
>
> static void fbdev_resize(DisplayState *ds)
> @@ -924,6 +952,10 @@ static void fbdev_refresh(DisplayState *ds)
> if (redraw_screen) {
> fbdev_update(ds, 0, 0, 0, 0);
> }
> +
> + if (pixman_region_not_empty(&dirty)) {
> + fbdev_render(ds);
> + }
> }
>
> static void fbdev_exit_notifier(Notifier *notifier, void *data)
> --
> 1.7.1
>
>
^ permalink raw reply [flat|nested] 29+ messages in thread
* Re: [Qemu-devel] [PATCH 9/9] fbdev: add display scaling support
2012-09-18 7:17 ` [Qemu-devel] [PATCH 9/9] fbdev: add display scaling support Gerd Hoffmann
@ 2012-09-18 15:02 ` Stefano Stabellini
2012-09-19 5:52 ` Gerd Hoffmann
0 siblings, 1 reply; 29+ messages in thread
From: Stefano Stabellini @ 2012-09-18 15:02 UTC (permalink / raw)
To: Gerd Hoffmann; +Cc: qemu-devel@nongnu.org
On Tue, 18 Sep 2012, Gerd Hoffmann wrote:
> Add support for scaling the guest display.
> Ctrl-Alt-S hotkey toggles scaling.
We could make sdl_zoom generic: sdl_zoom_blit doesn't actually depend on
sdl.
> Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
> ---
> ui/fbdev.c | 61 ++++++++++++++++++++++++++++++++++++++++++++++++++---------
> 1 files changed, 51 insertions(+), 10 deletions(-)
>
> diff --git a/ui/fbdev.c b/ui/fbdev.c
> index 6835fef..55793ab 100644
> --- a/ui/fbdev.c
> +++ b/ui/fbdev.c
> @@ -81,6 +81,7 @@ static pixman_image_t *surface;
> static pixman_image_t *framebuffer;
> static pixman_transform_t transform;
> static pixman_region16_t dirty;
> +static double scale;
>
> static QEMUCursor *ptr_cursor;
> static pixman_image_t *ptr_image;
> @@ -88,6 +89,10 @@ static int ptr_refresh;
> static int px, py, pw, ph;
> static int mx, my, mon;
>
> +/* options */
> +static int use_scale = 1;
> +static pixman_filter_t pfilter = PIXMAN_FILTER_GOOD;
> +
> /* fwd decls */
> static int fbdev_activate_vt(int tty, int vtno, bool wait);
>
> @@ -182,13 +187,14 @@ static void read_mouse(void *opaque)
> if (ay < 0) {
> ay = 0;
> }
> - if (ax >= cw) {
> - ax = cw-1;
> + if (ax >= cw*scale) {
> + ax = cw*scale-1;
> }
> - if (ay >= ch) {
> - ay = ch-1;
> + if (ay >= ch*scale) {
> + ay = ch*scale-1;
> }
> - kbd_mouse_event(ax * 0x7FFF / cw, ay * 0x7FFF / ch, 0, b);
> + kbd_mouse_event(ax * 0x7FFF / (cw*scale),
> + ay * 0x7FFF / (ch*scale), 0, b);
> } else {
> kbd_mouse_event(x, y, 0, b);
> }
> @@ -543,6 +549,12 @@ static void read_mediumraw(void *opaque)
> "(ctrl-alt-esc) ===\n");
> exit(1);
> }
> + if (keycode == KEY_S) {
> + use_scale = !use_scale;
> + resize_screen++;
> + redraw_screen++;
> + continue;
> + }
> if (keycode >= KEY_F1 && keycode <= KEY_F10) {
> fbdev_activate_vt(tty, keycode+1-KEY_F1, false);
> key_down[keycode] = false;
> @@ -912,6 +924,11 @@ static void fbdev_render_ptr(DisplayState *ds)
> pixman_transform_translate(&transform, NULL,
> pixman_int_to_fixed(-cx),
> pixman_int_to_fixed(-cy));
> + if (use_scale) {
> + pixman_transform_scale(&transform, NULL,
> + pixman_double_to_fixed(1/scale),
> + pixman_double_to_fixed(1/scale));
> + }
> pixman_transform_translate(&transform, NULL,
> pixman_int_to_fixed(-px),
> pixman_int_to_fixed(-py));
> @@ -937,16 +954,32 @@ static void fbdev_update(DisplayState *ds, int x, int y, int w, int h)
> }
>
> if (resize_screen) {
> + double xs, ys;
> +
> trace_fbdev_dpy_resize(ds_get_width(ds), ds_get_height(ds));
> resize_screen = 0;
> cx = 0; cy = 0;
> cw = ds_get_width(ds);
> ch = ds_get_height(ds);
> - if (ds_get_width(ds) < fb_var.xres) {
> - cx = (fb_var.xres - ds_get_width(ds)) / 2;
> - }
> - if (ds_get_height(ds) < fb_var.yres) {
> - cy = (fb_var.yres - ds_get_height(ds)) / 2;
> +
> + if (use_scale) {
> + xs = (double)fb_var.xres / cw;
> + ys = (double)fb_var.yres / ch;
> + if (xs > ys) {
> + scale = ys;
> + cx = (fb_var.xres - ds_get_width(ds)*scale) / 2;
> + } else {
> + scale = xs;
> + cy = (fb_var.yres - ds_get_height(ds)*scale) / 2;
> + }
> + } else {
> + scale = 1;
> + if (ds_get_width(ds) < fb_var.xres) {
> + cx = (fb_var.xres - ds_get_width(ds)) / 2;
> + }
> + if (ds_get_height(ds) < fb_var.yres) {
> + cy = (fb_var.yres - ds_get_height(ds)) / 2;
> + }
> }
> if (surface) {
> pixman_image_unref(surface);
> @@ -957,7 +990,14 @@ static void fbdev_update(DisplayState *ds, int x, int y, int w, int h)
> pixman_transform_translate(&transform, NULL,
> pixman_int_to_fixed(-cx),
> pixman_int_to_fixed(-cy));
> + if (use_scale) {
> + pixman_transform_scale(&transform, NULL,
> + pixman_double_to_fixed(1/scale),
> + pixman_double_to_fixed(1/scale));
> + }
> pixman_image_set_transform(surface, &transform);
> +
> + pixman_image_set_filter(surface, pfilter, NULL, 0);
> }
>
> if (redraw_screen) {
> @@ -1049,6 +1089,7 @@ static void fbdev_cursor_define(DisplayState *ds, QEMUCursor *cursor)
> cursor->width, cursor->height,
> cursor->data,
> cursor->width * 4);
> + pixman_image_set_filter(ptr_image, pfilter, NULL, 0);
> }
>
> static void fbdev_exit_notifier(Notifier *notifier, void *data)
> --
> 1.7.1
>
>
^ permalink raw reply [flat|nested] 29+ messages in thread
* Re: [Qemu-devel] [PATCH 3/9] move set_mouse + cursor_define callbacks
2012-09-18 14:10 ` Stefano Stabellini
@ 2012-09-18 16:31 ` Gerd Hoffmann
2012-09-18 16:44 ` Stefano Stabellini
0 siblings, 1 reply; 29+ messages in thread
From: Gerd Hoffmann @ 2012-09-18 16:31 UTC (permalink / raw)
To: Stefano Stabellini; +Cc: qemu-devel@nongnu.org
On 09/18/12 16:10, Stefano Stabellini wrote:
> On Tue, 18 Sep 2012, Gerd Hoffmann wrote:
>> When adding DisplayChangeListeners the set_mouse and cursor_define
>> callbacks have been left in DisplayState for some reason. Fix it.
>>
>> Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
>
> This patch is good.
> The one thing I don't like is dpy_cursor_define_supported, because it
> enforces the idea that we cannot register/deregister
> DisplayChangeListeners at run time. Theoretically a new
> DisplayChangeListener that support cursor_define could show up at any
> time.
Depends on how it is used.
qxl is fine, it uses dpy_cursor_define_supported only to skip some work
in case nobody cares anyway.
vmware_vga uses it to signal the capability to the guest, which
obviously doesn't fly with displaysurfaces coming & going ...
cheers,
Gerd
^ permalink raw reply [flat|nested] 29+ messages in thread
* Re: [Qemu-devel] [PATCH 3/9] move set_mouse + cursor_define callbacks
2012-09-18 16:31 ` Gerd Hoffmann
@ 2012-09-18 16:44 ` Stefano Stabellini
0 siblings, 0 replies; 29+ messages in thread
From: Stefano Stabellini @ 2012-09-18 16:44 UTC (permalink / raw)
To: Gerd Hoffmann; +Cc: qemu-devel@nongnu.org, Stefano Stabellini
On Tue, 18 Sep 2012, Gerd Hoffmann wrote:
> On 09/18/12 16:10, Stefano Stabellini wrote:
> > On Tue, 18 Sep 2012, Gerd Hoffmann wrote:
> >> When adding DisplayChangeListeners the set_mouse and cursor_define
> >> callbacks have been left in DisplayState for some reason. Fix it.
> >>
> >> Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
> >
> > This patch is good.
> > The one thing I don't like is dpy_cursor_define_supported, because it
> > enforces the idea that we cannot register/deregister
> > DisplayChangeListeners at run time. Theoretically a new
> > DisplayChangeListener that support cursor_define could show up at any
> > time.
>
> Depends on how it is used.
>
> qxl is fine, it uses dpy_cursor_define_supported only to skip some work
> in case nobody cares anyway.
>
> vmware_vga uses it to signal the capability to the guest, which
> obviously doesn't fly with displaysurfaces coming & going ...
yeah.. that is what I am talking about. Maybe adding a comment on top
the "offending code" in vmware_vga could suffice for now.
^ permalink raw reply [flat|nested] 29+ messages in thread
* Re: [Qemu-devel] [PATCH 7/9] fbdev: move to pixman
2012-09-18 7:17 ` [Qemu-devel] [PATCH 7/9] fbdev: move to pixman Gerd Hoffmann
2012-09-18 15:01 ` Stefano Stabellini
@ 2012-09-18 19:14 ` Anthony Liguori
2012-09-18 21:08 ` Anthony Liguori
2012-11-26 18:42 ` Alexander Graf
2012-09-18 20:30 ` Søren Sandmann
2 siblings, 2 replies; 29+ messages in thread
From: Anthony Liguori @ 2012-09-18 19:14 UTC (permalink / raw)
To: Gerd Hoffmann, qemu-devel
Gerd Hoffmann <kraxel@redhat.com> writes:
> Stop reinventing the wheel. Use the pixman library for raster ops.
>
> Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
Why not cairo? I already have a cairo backend that uses GTK that
supports scaling. That would be a good opportunity for sharing even
more code.
Regards,
Anthony Liguori
> ---
> configure | 12 ++++
> ui/fbdev.c | 172 +++++++++++++++++++++++++++++++++++------------------------
> 2 files changed, 114 insertions(+), 70 deletions(-)
>
> diff --git a/configure b/configure
> index c4ba338..d10ff78 100755
> --- a/configure
> +++ b/configure
> @@ -148,6 +148,7 @@ docs=""
> fdt=""
> nptl=""
> sdl=""
> +pixman=""
> fbdev="no"
> virtfs=""
> vnc="yes"
> @@ -2153,6 +2154,17 @@ else
> exit 1
> fi
>
> +if $pkg_config pixman-1 > /dev/null 2>&1
> +then
> + pixman="yes"
> + pixman_cflags=`$pkg_config --cflags pixman-1 2>/dev/null`
> + pixman_libs=`$pkg_config --libs pixman-1 2>/dev/null`
> + QEMU_CFLAGS="$QEMU_CFLAGS $pixman_cflags"
> + libs_softmmu="$libs_softmmu $pixman_libs"
> +else
> + fbdev="no"
> +fi
> +
> ##########################################
> # libcap probe
>
> diff --git a/ui/fbdev.c b/ui/fbdev.c
> index 40fc7d4..4cb4d1d 100644
> --- a/ui/fbdev.c
> +++ b/ui/fbdev.c
> @@ -23,11 +23,12 @@
> #include <linux/vt.h>
> #include <linux/fb.h>
>
> +#include <pixman.h>
> +
> #include "qemu-common.h"
> #include "console.h"
> #include "keymaps.h"
> #include "sysemu.h"
> -#include "pflib.h"
>
> /*
> * must be last so we get the linux input layer
> @@ -70,19 +71,82 @@ static bool key_down[KEY_CNT];
> #define FB_ACQ_REQ 3
> static int fb_switch_state;
>
> -/* qdev windup */
> +/* qemu windup */
> static DisplayChangeListener *dcl;
> -static QemuPfConv *conv;
> -static PixelFormat fbpf;
> static int resize_screen;
> static int redraw_screen;
> static int cx, cy, cw, ch;
> static Notifier exit_notifier;
> +static pixman_image_t *surface;
> +static pixman_image_t *framebuffer;
> +static pixman_transform_t transform;
> +static pixman_region16_t dirty;
>
> /* fwd decls */
> static int fbdev_activate_vt(int tty, int vtno, bool wait);
>
> /* -------------------------------------------------------------------- */
> +/* pixman helpers */
> +
> +static int pixman_shifts_to_type(int rshift, int gshift, int bshift)
> +{
> + int type = PIXMAN_TYPE_OTHER;
> +
> + if (rshift > gshift && gshift > bshift) {
> + if (bshift == 0) {
> + type = PIXMAN_TYPE_ARGB;
> + } else {
> +#if PIXMAN_VERSION >= PIXMAN_VERSION_ENCODE(0, 21, 8)
> + type = PIXMAN_TYPE_RGBA;
> +#endif
> + }
> + } else if (rshift < gshift && gshift < bshift) {
> + if (rshift == 0) {
> + type = PIXMAN_TYPE_ABGR;
> + } else {
> + type = PIXMAN_TYPE_BGRA;
> + }
> + }
> + return type;
> +}
> +
> +static pixman_image_t *pixman_from_displaystate(DisplayState *ds)
> +{
> + PixelFormat *pf = &ds->surface->pf;
> + pixman_format_code_t format;
> + pixman_image_t *image;
> + int type;
> +
> + type = pixman_shifts_to_type(pf->rshift, pf->gshift, pf->bshift);
> + format = PIXMAN_FORMAT(pf->bits_per_pixel, type,
> + pf->abits, pf->rbits, pf->gbits, pf->bbits);
> + image = pixman_image_create_bits(format, ds_get_width(ds),
> + ds_get_height(ds),
> + (void *)ds_get_data(ds),
> + ds_get_linesize(ds));
> + return image;
> +}
> +
> +static pixman_image_t *pixman_from_framebuffer(void)
> +{
> + pixman_format_code_t format;
> + pixman_image_t *image;
> + int type;
> +
> + type = pixman_shifts_to_type(fb_var.red.offset,
> + fb_var.green.offset,
> + fb_var.blue.offset);
> + format = PIXMAN_FORMAT(fb_var.bits_per_pixel, type,
> + fb_var.transp.length,
> + fb_var.red.length,
> + fb_var.green.length,
> + fb_var.blue.length);
> + image = pixman_image_create_bits(format, fb_var.xres, fb_var.yres,
> + (void *)fb_mem, fb_fix.line_length);
> + return image;
> +}
> +
> +/* -------------------------------------------------------------------- */
> /* mouse */
>
> static void read_mouse(void *opaque)
> @@ -529,6 +593,17 @@ static void fbdev_cleanup(void)
> {
> trace_fbdev_cleanup();
>
> + /* release pixman stuff */
> + pixman_region_fini(&dirty);
> + if (framebuffer) {
> + pixman_image_unref(framebuffer);
> + framebuffer = NULL;
> + }
> + if (surface) {
> + pixman_image_unref(surface);
> + surface = NULL;
> + }
> +
> /* restore console */
> if (fb_mem != NULL) {
> munmap(fb_mem, fb_fix.smem_len+fb_mem_offset);
> @@ -681,36 +756,8 @@ static int fbdev_init(const char *device)
> start_mediumraw(tty);
> qemu_set_fd_handler(tty, read_mediumraw, NULL, NULL);
>
> - /* create PixelFormat from fbdev structs */
> - fbpf.bits_per_pixel = fb_var.bits_per_pixel;
> - fbpf.bytes_per_pixel = (fb_var.bits_per_pixel+7)/8;
> - fbpf.depth = fb_var.bits_per_pixel == 32
> - ? 24 : fb_var.bits_per_pixel;
> - fbpf.rshift = fb_var.red.offset;
> - fbpf.rbits = fb_var.red.length;
> - fbpf.gshift = fb_var.green.offset;
> - fbpf.gbits = fb_var.green.length;
> - fbpf.bshift = fb_var.blue.offset;
> - fbpf.bbits = fb_var.blue.length;
> - fbpf.ashift = fb_var.transp.offset;
> - fbpf.abits = fb_var.transp.length;
> -
> - if (fbpf.rbits) {
> - fbpf.rmax = (1 << fbpf.rbits) - 1;
> - fbpf.rmask = fbpf.rmax << fbpf.rshift;
> - }
> - if (fbpf.gbits) {
> - fbpf.gmax = (1 << fbpf.gbits) - 1;
> - fbpf.gmask = fbpf.gmax << fbpf.gshift;
> - }
> - if (fbpf.bbits) {
> - fbpf.bmax = (1 << fbpf.bbits) - 1;
> - fbpf.bmask = fbpf.bmax << fbpf.bshift;
> - }
> - if (fbpf.abits) {
> - fbpf.amax = (1 << fbpf.abits) - 1;
> - fbpf.amask = fbpf.amax << fbpf.ashift;
> - }
> + framebuffer = pixman_from_framebuffer();
> + pixman_region_init(&dirty);
> return 0;
>
> err_early:
> @@ -818,36 +865,15 @@ static int fbdev_switch_init(void)
> /* -------------------------------------------------------------------- */
> /* rendering */
>
> -static void fbdev_render(DisplayState *ds, int x, int y, int w, int h)
> +static void fbdev_render(DisplayState *ds)
> {
> - uint8_t *dst;
> - uint8_t *src;
> - int line;
> -
> - if (!conv) {
> - return;
> - }
> -
> - src = ds_get_data(ds) + y * ds_get_linesize(ds)
> - + x * ds_get_bytes_per_pixel(ds);
> - dst = fb_mem + y * fb_fix.line_length
> - + x * fbpf.bytes_per_pixel;
> -
> - dst += cy * fb_fix.line_length;
> - dst += cx * fbpf.bytes_per_pixel;
> + assert(surface);
>
> - if (h > fb_var.yres - y) {
> - h = fb_var.yres - y;
> - }
> - if (w > fb_var.xres - x) {
> - w = fb_var.xres - x;
> - }
> -
> - for (line = y; line < y+h; line++) {
> - qemu_pf_conv_run(conv, dst, src, w);
> - dst += fb_fix.line_length;
> - src += ds_get_linesize(ds);
> - }
> + pixman_image_set_clip_region(surface, &dirty);
> + pixman_image_composite(PIXMAN_OP_SRC, surface, NULL, framebuffer,
> + 0, 0, 0, 0, 0, 0, fb_var.xres, fb_var.yres);
> + pixman_region_fini(&dirty);
> + pixman_region_init(&dirty);
> }
>
> /* -------------------------------------------------------------------- */
> @@ -871,14 +897,16 @@ static void fbdev_update(DisplayState *ds, int x, int y, int w, int h)
> if (ds_get_height(ds) < fb_var.yres) {
> cy = (fb_var.yres - ds_get_height(ds)) / 2;
> }
> -
> - if (conv) {
> - qemu_pf_conv_put(conv);
> - }
> - conv = qemu_pf_conv_get(&fbpf, &ds->surface->pf);
> - if (conv == NULL) {
> - fprintf(stderr, "fbdev: unsupported PixelFormat conversion\n");
> + if (surface) {
> + pixman_image_unref(surface);
> }
> + surface = pixman_from_displaystate(ds);
> +
> + pixman_transform_init_identity(&transform);
> + pixman_transform_translate(&transform, NULL,
> + pixman_int_to_fixed(-cx),
> + pixman_int_to_fixed(-cy));
> + pixman_image_set_transform(surface, &transform);
> }
>
> if (redraw_screen) {
> @@ -888,7 +916,7 @@ static void fbdev_update(DisplayState *ds, int x, int y, int w, int h)
> x = 0; y = 0; w = ds_get_width(ds); h = ds_get_height(ds);
> }
>
> - fbdev_render(ds, x, y, w, h);
> + pixman_region_union_rect(&dirty, &dirty, x, y, w, h);
> }
>
> static void fbdev_resize(DisplayState *ds)
> @@ -924,6 +952,10 @@ static void fbdev_refresh(DisplayState *ds)
> if (redraw_screen) {
> fbdev_update(ds, 0, 0, 0, 0);
> }
> +
> + if (pixman_region_not_empty(&dirty)) {
> + fbdev_render(ds);
> + }
> }
>
> static void fbdev_exit_notifier(Notifier *notifier, void *data)
> --
> 1.7.1
^ permalink raw reply [flat|nested] 29+ messages in thread
* Re: [Qemu-devel] [PATCH 7/9] fbdev: move to pixman
2012-09-18 7:17 ` [Qemu-devel] [PATCH 7/9] fbdev: move to pixman Gerd Hoffmann
2012-09-18 15:01 ` Stefano Stabellini
2012-09-18 19:14 ` Anthony Liguori
@ 2012-09-18 20:30 ` Søren Sandmann
2012-09-19 5:56 ` Gerd Hoffmann
2 siblings, 1 reply; 29+ messages in thread
From: Søren Sandmann @ 2012-09-18 20:30 UTC (permalink / raw)
To: Gerd Hoffmann; +Cc: qemu-devel
Gerd Hoffmann <kraxel@redhat.com> writes:
> +static pixman_image_t *pixman_from_displaystate(DisplayState *ds)
> +{
> + PixelFormat *pf = &ds->surface->pf;
> + pixman_format_code_t format;
> + pixman_image_t *image;
> + int type;
> +
> + type = pixman_shifts_to_type(pf->rshift, pf->gshift, pf->bshift);
> + format = PIXMAN_FORMAT(pf->bits_per_pixel, type,
> + pf->abits, pf->rbits, pf->gbits, pf->bbits);
> + image = pixman_image_create_bits(format, ds_get_width(ds),
> + ds_get_height(ds),
> + (void *)ds_get_data(ds),
> + ds_get_linesize(ds));
> + return image;
> +}
> +
> +static pixman_image_t *pixman_from_framebuffer(void)
> +{
> + pixman_format_code_t format;
> + pixman_image_t *image;
> + int type;
> +
> + type = pixman_shifts_to_type(fb_var.red.offset,
> + fb_var.green.offset,
> + fb_var.blue.offset);
> + format = PIXMAN_FORMAT(fb_var.bits_per_pixel, type,
> + fb_var.transp.length,
> + fb_var.red.length,
> + fb_var.green.length,
> + fb_var.blue.length);
> + image = pixman_image_create_bits(format, fb_var.xres, fb_var.yres,
> + (void *)fb_mem, fb_fix.line_length);
> + return image;
> +}
You may want to call pixman_format_supported_source/destination() here
to ensure that the format in question is supported by pixman.
> -static void fbdev_render(DisplayState *ds, int x, int y, int w, int h)
> +static void fbdev_render(DisplayState *ds)
> {
> - uint8_t *dst;
> - uint8_t *src;
> - int line;
> -
> - if (!conv) {
> - return;
> - }
> -
> - src = ds_get_data(ds) + y * ds_get_linesize(ds)
> - + x * ds_get_bytes_per_pixel(ds);
> - dst = fb_mem + y * fb_fix.line_length
> - + x * fbpf.bytes_per_pixel;
> -
> - dst += cy * fb_fix.line_length;
> - dst += cx * fbpf.bytes_per_pixel;
> + assert(surface);
>
> - if (h > fb_var.yres - y) {
> - h = fb_var.yres - y;
> - }
> - if (w > fb_var.xres - x) {
> - w = fb_var.xres - x;
> - }
> -
> - for (line = y; line < y+h; line++) {
> - qemu_pf_conv_run(conv, dst, src, w);
> - dst += fb_fix.line_length;
> - src += ds_get_linesize(ds);
> - }
> + pixman_image_set_clip_region(surface, &dirty);
> + pixman_image_composite(PIXMAN_OP_SRC, surface, NULL, framebuffer,
> + 0, 0, 0, 0, 0, 0, fb_var.xres, fb_var.yres);
> + pixman_region_fini(&dirty);
> + pixman_region_init(&dirty);
> }
The fini()/init() here could be done with pixman_region_clear() which
was introduced in 0.26.0.
Søren
^ permalink raw reply [flat|nested] 29+ messages in thread
* Re: [Qemu-devel] [PATCH 7/9] fbdev: move to pixman
2012-09-18 19:14 ` Anthony Liguori
@ 2012-09-18 21:08 ` Anthony Liguori
2012-11-26 18:42 ` Alexander Graf
1 sibling, 0 replies; 29+ messages in thread
From: Anthony Liguori @ 2012-09-18 21:08 UTC (permalink / raw)
To: Gerd Hoffmann, qemu-devel
Anthony Liguori <anthony@codemonkey.ws> writes:
> Gerd Hoffmann <kraxel@redhat.com> writes:
>
>> Stop reinventing the wheel. Use the pixman library for raster ops.
>>
>> Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
>
> Why not cairo? I already have a cairo backend that uses GTK that
> supports scaling. That would be a good opportunity for sharing even
> more code.
Nevermind, I see that cairo uses pixman under the covers...
Regards,
Anthony Liguori
>
> Regards,
>
> Anthony Liguori
>
>> ---
>> configure | 12 ++++
>> ui/fbdev.c | 172 +++++++++++++++++++++++++++++++++++------------------------
>> 2 files changed, 114 insertions(+), 70 deletions(-)
>>
>> diff --git a/configure b/configure
>> index c4ba338..d10ff78 100755
>> --- a/configure
>> +++ b/configure
>> @@ -148,6 +148,7 @@ docs=""
>> fdt=""
>> nptl=""
>> sdl=""
>> +pixman=""
>> fbdev="no"
>> virtfs=""
>> vnc="yes"
>> @@ -2153,6 +2154,17 @@ else
>> exit 1
>> fi
>>
>> +if $pkg_config pixman-1 > /dev/null 2>&1
>> +then
>> + pixman="yes"
>> + pixman_cflags=`$pkg_config --cflags pixman-1 2>/dev/null`
>> + pixman_libs=`$pkg_config --libs pixman-1 2>/dev/null`
>> + QEMU_CFLAGS="$QEMU_CFLAGS $pixman_cflags"
>> + libs_softmmu="$libs_softmmu $pixman_libs"
>> +else
>> + fbdev="no"
>> +fi
>> +
>> ##########################################
>> # libcap probe
>>
>> diff --git a/ui/fbdev.c b/ui/fbdev.c
>> index 40fc7d4..4cb4d1d 100644
>> --- a/ui/fbdev.c
>> +++ b/ui/fbdev.c
>> @@ -23,11 +23,12 @@
>> #include <linux/vt.h>
>> #include <linux/fb.h>
>>
>> +#include <pixman.h>
>> +
>> #include "qemu-common.h"
>> #include "console.h"
>> #include "keymaps.h"
>> #include "sysemu.h"
>> -#include "pflib.h"
>>
>> /*
>> * must be last so we get the linux input layer
>> @@ -70,19 +71,82 @@ static bool key_down[KEY_CNT];
>> #define FB_ACQ_REQ 3
>> static int fb_switch_state;
>>
>> -/* qdev windup */
>> +/* qemu windup */
>> static DisplayChangeListener *dcl;
>> -static QemuPfConv *conv;
>> -static PixelFormat fbpf;
>> static int resize_screen;
>> static int redraw_screen;
>> static int cx, cy, cw, ch;
>> static Notifier exit_notifier;
>> +static pixman_image_t *surface;
>> +static pixman_image_t *framebuffer;
>> +static pixman_transform_t transform;
>> +static pixman_region16_t dirty;
>>
>> /* fwd decls */
>> static int fbdev_activate_vt(int tty, int vtno, bool wait);
>>
>> /* -------------------------------------------------------------------- */
>> +/* pixman helpers */
>> +
>> +static int pixman_shifts_to_type(int rshift, int gshift, int bshift)
>> +{
>> + int type = PIXMAN_TYPE_OTHER;
>> +
>> + if (rshift > gshift && gshift > bshift) {
>> + if (bshift == 0) {
>> + type = PIXMAN_TYPE_ARGB;
>> + } else {
>> +#if PIXMAN_VERSION >= PIXMAN_VERSION_ENCODE(0, 21, 8)
>> + type = PIXMAN_TYPE_RGBA;
>> +#endif
>> + }
>> + } else if (rshift < gshift && gshift < bshift) {
>> + if (rshift == 0) {
>> + type = PIXMAN_TYPE_ABGR;
>> + } else {
>> + type = PIXMAN_TYPE_BGRA;
>> + }
>> + }
>> + return type;
>> +}
>> +
>> +static pixman_image_t *pixman_from_displaystate(DisplayState *ds)
>> +{
>> + PixelFormat *pf = &ds->surface->pf;
>> + pixman_format_code_t format;
>> + pixman_image_t *image;
>> + int type;
>> +
>> + type = pixman_shifts_to_type(pf->rshift, pf->gshift, pf->bshift);
>> + format = PIXMAN_FORMAT(pf->bits_per_pixel, type,
>> + pf->abits, pf->rbits, pf->gbits, pf->bbits);
>> + image = pixman_image_create_bits(format, ds_get_width(ds),
>> + ds_get_height(ds),
>> + (void *)ds_get_data(ds),
>> + ds_get_linesize(ds));
>> + return image;
>> +}
>> +
>> +static pixman_image_t *pixman_from_framebuffer(void)
>> +{
>> + pixman_format_code_t format;
>> + pixman_image_t *image;
>> + int type;
>> +
>> + type = pixman_shifts_to_type(fb_var.red.offset,
>> + fb_var.green.offset,
>> + fb_var.blue.offset);
>> + format = PIXMAN_FORMAT(fb_var.bits_per_pixel, type,
>> + fb_var.transp.length,
>> + fb_var.red.length,
>> + fb_var.green.length,
>> + fb_var.blue.length);
>> + image = pixman_image_create_bits(format, fb_var.xres, fb_var.yres,
>> + (void *)fb_mem, fb_fix.line_length);
>> + return image;
>> +}
>> +
>> +/* -------------------------------------------------------------------- */
>> /* mouse */
>>
>> static void read_mouse(void *opaque)
>> @@ -529,6 +593,17 @@ static void fbdev_cleanup(void)
>> {
>> trace_fbdev_cleanup();
>>
>> + /* release pixman stuff */
>> + pixman_region_fini(&dirty);
>> + if (framebuffer) {
>> + pixman_image_unref(framebuffer);
>> + framebuffer = NULL;
>> + }
>> + if (surface) {
>> + pixman_image_unref(surface);
>> + surface = NULL;
>> + }
>> +
>> /* restore console */
>> if (fb_mem != NULL) {
>> munmap(fb_mem, fb_fix.smem_len+fb_mem_offset);
>> @@ -681,36 +756,8 @@ static int fbdev_init(const char *device)
>> start_mediumraw(tty);
>> qemu_set_fd_handler(tty, read_mediumraw, NULL, NULL);
>>
>> - /* create PixelFormat from fbdev structs */
>> - fbpf.bits_per_pixel = fb_var.bits_per_pixel;
>> - fbpf.bytes_per_pixel = (fb_var.bits_per_pixel+7)/8;
>> - fbpf.depth = fb_var.bits_per_pixel == 32
>> - ? 24 : fb_var.bits_per_pixel;
>> - fbpf.rshift = fb_var.red.offset;
>> - fbpf.rbits = fb_var.red.length;
>> - fbpf.gshift = fb_var.green.offset;
>> - fbpf.gbits = fb_var.green.length;
>> - fbpf.bshift = fb_var.blue.offset;
>> - fbpf.bbits = fb_var.blue.length;
>> - fbpf.ashift = fb_var.transp.offset;
>> - fbpf.abits = fb_var.transp.length;
>> -
>> - if (fbpf.rbits) {
>> - fbpf.rmax = (1 << fbpf.rbits) - 1;
>> - fbpf.rmask = fbpf.rmax << fbpf.rshift;
>> - }
>> - if (fbpf.gbits) {
>> - fbpf.gmax = (1 << fbpf.gbits) - 1;
>> - fbpf.gmask = fbpf.gmax << fbpf.gshift;
>> - }
>> - if (fbpf.bbits) {
>> - fbpf.bmax = (1 << fbpf.bbits) - 1;
>> - fbpf.bmask = fbpf.bmax << fbpf.bshift;
>> - }
>> - if (fbpf.abits) {
>> - fbpf.amax = (1 << fbpf.abits) - 1;
>> - fbpf.amask = fbpf.amax << fbpf.ashift;
>> - }
>> + framebuffer = pixman_from_framebuffer();
>> + pixman_region_init(&dirty);
>> return 0;
>>
>> err_early:
>> @@ -818,36 +865,15 @@ static int fbdev_switch_init(void)
>> /* -------------------------------------------------------------------- */
>> /* rendering */
>>
>> -static void fbdev_render(DisplayState *ds, int x, int y, int w, int h)
>> +static void fbdev_render(DisplayState *ds)
>> {
>> - uint8_t *dst;
>> - uint8_t *src;
>> - int line;
>> -
>> - if (!conv) {
>> - return;
>> - }
>> -
>> - src = ds_get_data(ds) + y * ds_get_linesize(ds)
>> - + x * ds_get_bytes_per_pixel(ds);
>> - dst = fb_mem + y * fb_fix.line_length
>> - + x * fbpf.bytes_per_pixel;
>> -
>> - dst += cy * fb_fix.line_length;
>> - dst += cx * fbpf.bytes_per_pixel;
>> + assert(surface);
>>
>> - if (h > fb_var.yres - y) {
>> - h = fb_var.yres - y;
>> - }
>> - if (w > fb_var.xres - x) {
>> - w = fb_var.xres - x;
>> - }
>> -
>> - for (line = y; line < y+h; line++) {
>> - qemu_pf_conv_run(conv, dst, src, w);
>> - dst += fb_fix.line_length;
>> - src += ds_get_linesize(ds);
>> - }
>> + pixman_image_set_clip_region(surface, &dirty);
>> + pixman_image_composite(PIXMAN_OP_SRC, surface, NULL, framebuffer,
>> + 0, 0, 0, 0, 0, 0, fb_var.xres, fb_var.yres);
>> + pixman_region_fini(&dirty);
>> + pixman_region_init(&dirty);
>> }
>>
>> /* -------------------------------------------------------------------- */
>> @@ -871,14 +897,16 @@ static void fbdev_update(DisplayState *ds, int x, int y, int w, int h)
>> if (ds_get_height(ds) < fb_var.yres) {
>> cy = (fb_var.yres - ds_get_height(ds)) / 2;
>> }
>> -
>> - if (conv) {
>> - qemu_pf_conv_put(conv);
>> - }
>> - conv = qemu_pf_conv_get(&fbpf, &ds->surface->pf);
>> - if (conv == NULL) {
>> - fprintf(stderr, "fbdev: unsupported PixelFormat conversion\n");
>> + if (surface) {
>> + pixman_image_unref(surface);
>> }
>> + surface = pixman_from_displaystate(ds);
>> +
>> + pixman_transform_init_identity(&transform);
>> + pixman_transform_translate(&transform, NULL,
>> + pixman_int_to_fixed(-cx),
>> + pixman_int_to_fixed(-cy));
>> + pixman_image_set_transform(surface, &transform);
>> }
>>
>> if (redraw_screen) {
>> @@ -888,7 +916,7 @@ static void fbdev_update(DisplayState *ds, int x, int y, int w, int h)
>> x = 0; y = 0; w = ds_get_width(ds); h = ds_get_height(ds);
>> }
>>
>> - fbdev_render(ds, x, y, w, h);
>> + pixman_region_union_rect(&dirty, &dirty, x, y, w, h);
>> }
>>
>> static void fbdev_resize(DisplayState *ds)
>> @@ -924,6 +952,10 @@ static void fbdev_refresh(DisplayState *ds)
>> if (redraw_screen) {
>> fbdev_update(ds, 0, 0, 0, 0);
>> }
>> +
>> + if (pixman_region_not_empty(&dirty)) {
>> + fbdev_render(ds);
>> + }
>> }
>>
>> static void fbdev_exit_notifier(Notifier *notifier, void *data)
>> --
>> 1.7.1
^ permalink raw reply [flat|nested] 29+ messages in thread
* Re: [Qemu-devel] [PATCH 4/9] fbdev: add linux framebuffer display driver.
2012-09-18 15:01 ` Stefano Stabellini
@ 2012-09-19 5:19 ` Gerd Hoffmann
0 siblings, 0 replies; 29+ messages in thread
From: Gerd Hoffmann @ 2012-09-19 5:19 UTC (permalink / raw)
To: Stefano Stabellini; +Cc: qemu-devel@nongnu.org
On 09/18/12 17:01, Stefano Stabellini wrote:
> On Tue, 18 Sep 2012, Gerd Hoffmann wrote:
>> Display works, requires truecolor framebuffer with 16 or 32 bpp on the
>> host. 32bpp is recommended. The framebuffer is used as-is, qemu
>> doesn't try to switch modes. With LCD displays mode switching is pretty
>> pointless IMHO, also it wouldn't work anyway with the most common
>> fbdev drivers (vesafb, KMS). Guest display is centered on the host
>> screen.
>>
>> Mouse works, uses /dev/input/mice.
>>
>> Keyboard works. Guest screen has whatever keymap you load inside
>> the guest. Text windows (monitor, serial, ...) have a simple en-us
>> keymap. Good enough to type monitor commands. Not goot enough to
>> work seriously on a serial terminal. But the qemu terminal emulation
>> isn't good enough for that anyway ;)
>>
>> Hot keys:
>> Ctrl-Alt-F<nr> -> host console switching.
>> Ctrl-Alt-<nr> -> qemu console switching.
>> Ctrl-Alt-ESC -> exit qemu.
>>
>> Special feature: Sane console switching. Switching away stops screen
>> updates. Switching back redraws the screen. When started from the
>> linux console qemu uses the vt you've started it from (requires just
>> read/write access to /dev/fb0). When starting from somewhere else qemu
>> tries to open a unused virtual terminal and switch to it (usually
>> requires root privileges to open /dev/tty<nr>).
>>
>> Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
>
> This series is not bisectable: this patch references functions and
> variables only defined in later patches (surface,
> pixman_from_displaystate). Please make it bisectable.
Oops, that wasn't intentionally, squashed bugfix into the wrong patch,
will fixup.
>> +static void fbdev_setdata(DisplayState *ds)
>> +{
>> + if (surface) {
> ^ where is this coming from?
>
See above ;)
>> +int fbdev_display_init(DisplayState *ds, const char *device)
>> +{
>> + if (dcl != NULL) {
>> + return 0;
>> + }
>
> is it actually possible that fbdev_display_init gets called multiple
> times?
With the next patch (enable/disable fbdev via monitor) yes.
>> + fbdev_resize(ds);
>> + dcl = g_new0(DisplayChangeListener, 1);
>> + dcl->dpy_update = fbdev_update;
>> + dcl->dpy_resize = fbdev_resize;
>> + dcl->dpy_setdata = fbdev_setdata;
>> + dcl->dpy_refresh = fbdev_refresh;
>> + register_displaychangelistener(ds, dcl);
>
> The fbdev driver could benefit from registering a DisplayAllocator (see
> sdl.c).
I don't think so, at least not once the whole series is applied and
support for scaling & cursor rendering is there.
cheers,
Gerd
^ permalink raw reply [flat|nested] 29+ messages in thread
* Re: [Qemu-devel] [PATCH 7/9] fbdev: move to pixman
2012-09-18 15:01 ` Stefano Stabellini
@ 2012-09-19 5:51 ` Gerd Hoffmann
0 siblings, 0 replies; 29+ messages in thread
From: Gerd Hoffmann @ 2012-09-19 5:51 UTC (permalink / raw)
To: Stefano Stabellini; +Cc: qemu-devel@nongnu.org
On 09/18/12 17:01, Stefano Stabellini wrote:
> On Tue, 18 Sep 2012, Gerd Hoffmann wrote:
>> Stop reinventing the wheel. Use the pixman library for raster ops.
>
> I would separate the pixmap changes from this series: either we use
> this library everywhere or nowhere. At the very least vnc could use it.
The secret long term plan is to use pixman everywhere, but that is
certainly way to much for a single series anyway.
I have patches in the queue to switch over spice to pixman (and remove
pflib.[ch]).
vnc and sdl are obviously candidates. Possibly device emulation too:
vga textmode font rendering, cirrus 2d ops. But that is surely for
another discussion as this would make pixman a hard dependency for qemu.
> Also considering that you only support 32bpp in fbdev, I am not sure
> whether it actually is that useful in this case: you don't really need
> to handle any pixel format conversions, at most you need to handle
> differences in linesizes.
DisplaySurfaces can be 16bpp too. The limitation to 32bpp can go away,
that is just a leftover from earlier revisions, 15+16 bpp should just
work too. Also with the full series applied we let pixman do alot more
than just pixel copying: scaling, dirty area tracking, alpha bleeding.
cheers,
Gerd
^ permalink raw reply [flat|nested] 29+ messages in thread
* Re: [Qemu-devel] [PATCH 9/9] fbdev: add display scaling support
2012-09-18 15:02 ` Stefano Stabellini
@ 2012-09-19 5:52 ` Gerd Hoffmann
0 siblings, 0 replies; 29+ messages in thread
From: Gerd Hoffmann @ 2012-09-19 5:52 UTC (permalink / raw)
To: Stefano Stabellini; +Cc: qemu-devel@nongnu.org
On 09/18/12 17:02, Stefano Stabellini wrote:
> On Tue, 18 Sep 2012, Gerd Hoffmann wrote:
>> Add support for scaling the guest display.
>> Ctrl-Alt-S hotkey toggles scaling.
>
> We could make sdl_zoom generic: sdl_zoom_blit doesn't actually depend on
> sdl.
I'd rather go the other way around and make sdl zoom use pixman.
cheers,
Gerd
^ permalink raw reply [flat|nested] 29+ messages in thread
* Re: [Qemu-devel] [PATCH 7/9] fbdev: move to pixman
2012-09-18 20:30 ` Søren Sandmann
@ 2012-09-19 5:56 ` Gerd Hoffmann
0 siblings, 0 replies; 29+ messages in thread
From: Gerd Hoffmann @ 2012-09-19 5:56 UTC (permalink / raw)
To: Søren Sandmann; +Cc: qemu-devel
On 09/18/12 22:30, Søren Sandmann wrote:
> Gerd Hoffmann <kraxel@redhat.com> writes:
>
>> +static pixman_image_t *pixman_from_displaystate(DisplayState *ds)
>> +{
>> +static pixman_image_t *pixman_from_framebuffer(void)
>> +{
> You may want to call pixman_format_supported_source/destination() here
> to ensure that the format in question is supported by pixman.
Ok.
>> + pixman_region_fini(&dirty);
>> + pixman_region_init(&dirty);
>> }
>
> The fini()/init() here could be done with pixman_region_clear() which
> was introduced in 0.26.0.
Saw that, but rhel6 ships 0.18.something which hasn't this function yet.
cheers,
Gerd
^ permalink raw reply [flat|nested] 29+ messages in thread
* Re: [Qemu-devel] [PATCH 4/9] fbdev: add linux framebuffer display driver.
2012-09-18 7:17 ` [Qemu-devel] [PATCH 4/9] fbdev: add linux framebuffer display driver Gerd Hoffmann
2012-09-18 15:01 ` Stefano Stabellini
@ 2012-09-19 18:37 ` Blue Swirl
1 sibling, 0 replies; 29+ messages in thread
From: Blue Swirl @ 2012-09-19 18:37 UTC (permalink / raw)
To: Gerd Hoffmann; +Cc: qemu-devel
On Tue, Sep 18, 2012 at 7:17 AM, Gerd Hoffmann <kraxel@redhat.com> wrote:
> Display works, requires truecolor framebuffer with 16 or 32 bpp on the
> host. 32bpp is recommended. The framebuffer is used as-is, qemu
> doesn't try to switch modes. With LCD displays mode switching is pretty
> pointless IMHO, also it wouldn't work anyway with the most common
> fbdev drivers (vesafb, KMS). Guest display is centered on the host
> screen.
>
> Mouse works, uses /dev/input/mice.
>
> Keyboard works. Guest screen has whatever keymap you load inside
> the guest. Text windows (monitor, serial, ...) have a simple en-us
> keymap. Good enough to type monitor commands. Not goot enough to
> work seriously on a serial terminal. But the qemu terminal emulation
> isn't good enough for that anyway ;)
>
> Hot keys:
> Ctrl-Alt-F<nr> -> host console switching.
> Ctrl-Alt-<nr> -> qemu console switching.
> Ctrl-Alt-ESC -> exit qemu.
>
> Special feature: Sane console switching. Switching away stops screen
> updates. Switching back redraws the screen. When started from the
> linux console qemu uses the vt you've started it from (requires just
> read/write access to /dev/fb0). When starting from somewhere else qemu
> tries to open a unused virtual terminal and switch to it (usually
> requires root privileges to open /dev/tty<nr>).
>
> Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
> ---
> console.h | 4 +
> qemu-options.hx | 8 +
> sysemu.h | 1 +
> trace-events | 15 +
> ui/Makefile.objs | 1 +
> ui/fbdev.c | 974 +++++++++++++++++++++++++++++++++++++++++++++++++++
> ui/linux-keynames.h | 388 ++++++++++++++++++++
> vl.c | 12 +
> 8 files changed, 1403 insertions(+), 0 deletions(-)
> create mode 100644 ui/fbdev.c
> create mode 100644 ui/linux-keynames.h
>
> diff --git a/console.h b/console.h
> index bef2d2d..0a3bae2 100644
> --- a/console.h
> +++ b/console.h
> @@ -417,6 +417,10 @@ void qemu_console_copy(DisplayState *ds, int src_x, int src_y,
> /* sdl.c */
> void sdl_display_init(DisplayState *ds, int full_screen, int no_frame);
>
> +/* fbdev.c */
> +int fbdev_display_init(DisplayState *ds, const char *device);
> +void fbdev_display_uninit(DisplayState *ds);
> +
> /* cocoa.m */
> void cocoa_display_init(DisplayState *ds, int full_screen);
>
> diff --git a/qemu-options.hx b/qemu-options.hx
> index 09c86c4..3445655 100644
> --- a/qemu-options.hx
> +++ b/qemu-options.hx
> @@ -947,6 +947,14 @@ Enable/disable spice seamless migration. Default is off.
> @end table
> ETEXI
>
> +DEF("fbdev", 0, QEMU_OPTION_fbdev,
> + "-fbdev enable fbdev\n", QEMU_ARCH_ALL)
> +STEXI
> +@item -fbdev
> +@findex -fbdev
> +Enable fbdev (linux framebuffer).
> +ETEXI
> +
> DEF("portrait", 0, QEMU_OPTION_portrait,
> "-portrait rotate graphical output 90 deg left (only PXA LCD)\n",
> QEMU_ARCH_ALL)
> diff --git a/sysemu.h b/sysemu.h
> index 65552ac..34e6bfa 100644
> --- a/sysemu.h
> +++ b/sysemu.h
> @@ -93,6 +93,7 @@ typedef enum DisplayType
> DT_DEFAULT,
> DT_CURSES,
> DT_SDL,
> + DT_FBDEV,
> DT_NOGRAPHIC,
> DT_NONE,
> } DisplayType;
> diff --git a/trace-events b/trace-events
> index b48fe2d..0d0b7fa 100644
> --- a/trace-events
> +++ b/trace-events
> @@ -994,3 +994,18 @@ spapr_pci_rtas_ibm_change_msi(unsigned func, unsigned req) "func %u, requested %
> spapr_pci_rtas_ibm_query_interrupt_source_number(unsigned ioa, unsigned intr) "queries for #%u, IRQ%u"
> spapr_pci_msi_write(uint64_t addr, uint64_t data, uint32_t dt_irq) "@%"PRIx64"<=%"PRIx64" IRQ %u"
> spapr_pci_lsi_set(const char *busname, int pin, uint32_t irq) "%s PIN%d IRQ %u"
> +
> +# ui/fbdev.c
> +fbdev_enabled(void) ""
> +fbdev_cleanup(void) ""
> +fbdev_vt_activate(int vtno, int wait) "vtno %d, wait %d"
> +fbdev_vt_activated(void) ""
> +fbdev_vt_release_request(void) ""
> +fbdev_vt_released(void) ""
> +fbdev_vt_aquire_request(void) ""
> +fbdev_vt_aquired(void) ""
> +fbdev_kbd_raw(int enable) "enable %d"
> +fbdev_kbd_event(int keycode, const char *kname, int up) "keycode 0x%x [%s], down %d"
> +fbdev_dpy_resize(int w, int h) "%dx%d"
> +fbdev_dpy_redraw(void)
> +
> diff --git a/ui/Makefile.objs b/ui/Makefile.objs
> index adc07be..55ddcf2 100644
> --- a/ui/Makefile.objs
> +++ b/ui/Makefile.objs
> @@ -12,3 +12,4 @@ common-obj-$(CONFIG_SDL) += sdl.o sdl_zoom.o x_keymap.o
> common-obj-$(CONFIG_COCOA) += cocoa.o
> common-obj-$(CONFIG_CURSES) += curses.o
> common-obj-$(CONFIG_VNC) += $(vnc-obj-y)
> +common-obj-$(CONFIG_LINUX) += fbdev.o
> diff --git a/ui/fbdev.c b/ui/fbdev.c
> new file mode 100644
> index 0000000..40fc7d4
> --- /dev/null
> +++ b/ui/fbdev.c
> @@ -0,0 +1,974 @@
> +/*
> + * linux fbdev output driver.
> + *
> + * Author: Gerd Hoffmann <kraxel@redhat.com>
> + *
> + * This work is licensed under the terms of the GNU GPL, version 2 or later.
> + * See the COPYING file in the top-level directory.
> + *
> + */
> +#include <stdio.h>
> +#include <stdlib.h>
> +#include <stdbool.h>
> +#include <string.h>
> +#include <unistd.h>
> +#include <fcntl.h>
> +#include <signal.h>
> +#include <termios.h>
> +
> +#include <sys/ioctl.h>
> +#include <sys/mman.h>
> +
> +#include <linux/kd.h>
> +#include <linux/vt.h>
> +#include <linux/fb.h>
> +
> +#include "qemu-common.h"
> +#include "console.h"
> +#include "keymaps.h"
> +#include "sysemu.h"
> +#include "pflib.h"
> +
> +/*
> + * must be last so we get the linux input layer
> + * KEY_* defines, not the ncurses ones.
> + */
> +#include <linux/input.h>
> +
> +/* -------------------------------------------------------------------- */
> +
> +/* file handles */
> +static int tty = -1, fb = -1, mice = -1;
> +
> +/* saved state, for restore on exit */
> +static int orig_vtno;
> +static int kd_omode;
> +static struct vt_mode vt_omode;
> +static struct fb_var_screeninfo fb_ovar;
> +
> +/* framebuffer */
> +static struct fb_fix_screeninfo fb_fix;
> +static struct fb_var_screeninfo fb_var;
> +static uint8_t *fb_mem;
> +static int fb_mem_offset;
> +
> +/* linux console */
> +static int vtno;
> +static struct vt_mode vt_mode;
> +static struct termios tty_attributes;
> +static unsigned long tty_mode;
> +static unsigned int tty_flags;
> +static bool tty_mediumraw;
> +static bool key_down[KEY_CNT];
> +
> +/* console switching */
> +#define SIG_ACQ (SIGRTMIN+6)
> +#define SIG_REL (SIGRTMIN+7)
> +#define FB_ACTIVE 0
> +#define FB_REL_REQ 1
> +#define FB_INACTIVE 2
> +#define FB_ACQ_REQ 3
> +static int fb_switch_state;
> +
> +/* qdev windup */
> +static DisplayChangeListener *dcl;
> +static QemuPfConv *conv;
> +static PixelFormat fbpf;
> +static int resize_screen;
> +static int redraw_screen;
> +static int cx, cy, cw, ch;
> +static Notifier exit_notifier;
> +
> +/* fwd decls */
> +static int fbdev_activate_vt(int tty, int vtno, bool wait);
> +
> +/* -------------------------------------------------------------------- */
> +/* mouse */
> +
> +static void read_mouse(void *opaque)
> +{
> + char buf[3];
> + int rc, x, y, b;
> +
> + rc = read(mice, buf, sizeof(buf));
> + if (rc != sizeof(buf)) {
> + return;
> + }
> +
> + if (fb_switch_state != FB_ACTIVE) {
> + return;
> + }
> +
> + x = buf[1];
> + y = -buf[2];
> + b = buf[0] & 0x7;
> +
> + if (kbd_mouse_is_absolute()) {
> + static int ax, ay;
> + ax += x; ay += y;
> + if (ax < 0) {
> + ax = 0;
> + }
> + if (ay < 0) {
> + ay = 0;
> + }
> + if (ax >= cw) {
> + ax = cw-1;
> + }
> + if (ay >= ch) {
> + ay = ch-1;
> + }
> + kbd_mouse_event(ax * 0x7FFF / cw, ay * 0x7FFF / ch, 0, b);
> + } else {
> + kbd_mouse_event(x, y, 0, b);
> + }
> +}
> +
> +static int init_mouse(void)
> +{
> + mice = open("/dev/input/mice", O_RDONLY);
> + if (mice == -1) {
> + return -1;
> + }
> + qemu_set_fd_handler(mice, read_mouse, NULL, NULL);
> + return 0;
> +}
> +
> +static void uninit_mouse(void)
> +{
> + if (mice == -1) {
> + return;
> + }
> + qemu_set_fd_handler(mice, NULL, NULL, NULL);
> + close(mice);
> + mice = -1;
> +}
> +
> +/* -------------------------------------------------------------------- */
> +/* keyboard */
> +
> +static const char *keynames[] = {
> +#include "linux-keynames.h"
> +};
> +
> +static const int scancode_map[KEY_CNT] = {
> + [KEY_ESC] = 0x01,
> + [KEY_1] = 0x02,
> + [KEY_2] = 0x03,
> + [KEY_3] = 0x04,
> + [KEY_4] = 0x05,
> + [KEY_5] = 0x06,
> + [KEY_6] = 0x07,
> + [KEY_7] = 0x08,
> + [KEY_8] = 0x09,
> + [KEY_9] = 0x0a,
> + [KEY_0] = 0x0b,
> + [KEY_MINUS] = 0x0c,
> + [KEY_EQUAL] = 0x0d,
> + [KEY_BACKSPACE] = 0x0e,
> +
> + [KEY_TAB] = 0x0f,
> + [KEY_Q] = 0x10,
> + [KEY_W] = 0x11,
> + [KEY_E] = 0x12,
> + [KEY_R] = 0x13,
> + [KEY_T] = 0x14,
> + [KEY_Y] = 0x15,
> + [KEY_U] = 0x16,
> + [KEY_I] = 0x17,
> + [KEY_O] = 0x18,
> + [KEY_P] = 0x19,
> + [KEY_LEFTBRACE] = 0x1a,
> + [KEY_RIGHTBRACE] = 0x1b,
> + [KEY_ENTER] = 0x1c,
> +
> + [KEY_A] = 0x1e,
> + [KEY_S] = 0x1f,
> + [KEY_D] = 0x20,
> + [KEY_F] = 0x21,
> + [KEY_G] = 0x22,
> + [KEY_H] = 0x23,
> + [KEY_J] = 0x24,
> + [KEY_K] = 0x25,
> + [KEY_L] = 0x26,
> + [KEY_SEMICOLON] = 0x27,
> + [KEY_APOSTROPHE] = 0x28,
> + [KEY_GRAVE] = 0x29,
> + [KEY_LEFTSHIFT] = 0x2a,
> + [KEY_BACKSLASH] = 0x2b,
> +
> + [KEY_Z] = 0x2c,
> + [KEY_X] = 0x2d,
> + [KEY_C] = 0x2e,
> + [KEY_V] = 0x2f,
> + [KEY_B] = 0x30,
> + [KEY_N] = 0x31,
> + [KEY_M] = 0x32,
> + [KEY_COMMA] = 0x33,
> + [KEY_DOT] = 0x34,
> + [KEY_SLASH] = 0x35,
> + [KEY_RIGHTSHIFT] = 0x36,
> + [KEY_SPACE] = 0x39,
> +
> + [KEY_F1] = 0x3b,
> + [KEY_F2] = 0x3c,
> + [KEY_F3] = 0x3d,
> + [KEY_F4] = 0x3e,
> + [KEY_F5] = 0x3f,
> + [KEY_F6] = 0x40,
> + [KEY_F7] = 0x41,
> + [KEY_F8] = 0x42,
> + [KEY_F9] = 0x43,
> + [KEY_F10] = 0x44,
> + [KEY_F11] = 0x57,
> + [KEY_F12] = 0x58,
> +
> + [KEY_SYSRQ] = 0xb7,
> + [KEY_SCROLLLOCK] = 0x46,
> +#if 0
> + [KEY_PAUSE] = FIXME,
> +#endif
> + [KEY_CAPSLOCK] = 0x3a,
> + [KEY_102ND] = 0x56,
> +
> + [KEY_LEFTCTRL] = 0x1d,
> + [KEY_LEFTMETA] = 0xdb,
> + [KEY_LEFTALT] = 0x38,
> + [KEY_RIGHTALT] = 0xb8,
> + [KEY_RIGHTMETA] = 0xdc,
> + [KEY_RIGHTCTRL] = 0x9d,
> + [KEY_COMPOSE] = 0xdd,
> +
> + [KEY_INSERT] = 0xd2,
> + [KEY_DELETE] = 0xd3,
> + [KEY_HOME] = 0xc7,
> + [KEY_END] = 0xcf,
> + [KEY_PAGEUP] = 0xc9,
> + [KEY_PAGEDOWN] = 0xd1,
> +
> + [KEY_UP] = 0xc8,
> + [KEY_LEFT] = 0xcb,
> + [KEY_RIGHT] = 0xcd,
> + [KEY_DOWN] = 0xd0,
> +
> + [KEY_NUMLOCK] = 0x45,
> + [KEY_KPSLASH] = 0xb5,
> + [KEY_KPASTERISK] = 0x37,
> + [KEY_KP7] = 0x47,
> + [KEY_KP8] = 0x48,
> + [KEY_KP9] = 0x49,
> + [KEY_KPMINUS] = 0x4a,
> + [KEY_KP4] = 0x4b,
> + [KEY_KP5] = 0x4c,
> + [KEY_KP6] = 0x4d,
> + [KEY_KPPLUS] = 0x4e,
> + [KEY_KP1] = 0x4f,
> + [KEY_KP2] = 0x50,
> + [KEY_KP3] = 0x51,
> + [KEY_KP0] = 0x52,
> + [KEY_KPDOT] = 0x53,
> + [KEY_KPENTER] = 0x9c,
> +};
> +
> +static const struct keysym_map {
> + int normal, shifted;
> +} keysym_map_en_us[KEY_CNT] = {
> + [KEY_A] = { .normal = 'a', .shifted = 'A' },
> + [KEY_B] = { .normal = 'b', .shifted = 'B' },
> + [KEY_C] = { .normal = 'c', .shifted = 'C' },
> + [KEY_D] = { .normal = 'd', .shifted = 'D' },
> + [KEY_E] = { .normal = 'e', .shifted = 'E' },
> + [KEY_F] = { .normal = 'f', .shifted = 'F' },
> + [KEY_G] = { .normal = 'g', .shifted = 'G' },
> + [KEY_H] = { .normal = 'h', .shifted = 'H' },
> + [KEY_I] = { .normal = 'i', .shifted = 'I' },
> + [KEY_J] = { .normal = 'j', .shifted = 'J' },
> + [KEY_K] = { .normal = 'k', .shifted = 'K' },
> + [KEY_L] = { .normal = 'l', .shifted = 'L' },
> + [KEY_M] = { .normal = 'm', .shifted = 'M' },
> + [KEY_N] = { .normal = 'n', .shifted = 'N' },
> + [KEY_O] = { .normal = 'o', .shifted = 'O' },
> + [KEY_P] = { .normal = 'p', .shifted = 'P' },
> + [KEY_Q] = { .normal = 'q', .shifted = 'Q' },
> + [KEY_R] = { .normal = 'r', .shifted = 'R' },
> + [KEY_S] = { .normal = 's', .shifted = 'S' },
> + [KEY_T] = { .normal = 't', .shifted = 'T' },
> + [KEY_U] = { .normal = 'u', .shifted = 'U' },
> + [KEY_V] = { .normal = 'v', .shifted = 'V' },
> + [KEY_W] = { .normal = 'w', .shifted = 'W' },
> + [KEY_X] = { .normal = 'x', .shifted = 'X' },
> + [KEY_Y] = { .normal = 'y', .shifted = 'Y' },
> + [KEY_Z] = { .normal = 'z', .shifted = 'Z' },
> +
> + [KEY_1] = { .normal = '1', .shifted = '!' },
> + [KEY_2] = { .normal = '2', .shifted = '@' },
> + [KEY_3] = { .normal = '3', .shifted = '#' },
> + [KEY_4] = { .normal = '4', .shifted = '$' },
> + [KEY_5] = { .normal = '5', .shifted = '%' },
> + [KEY_6] = { .normal = '6', .shifted = '^' },
> + [KEY_7] = { .normal = '7', .shifted = '&' },
> + [KEY_8] = { .normal = '8', .shifted = '*' },
> + [KEY_9] = { .normal = '9', .shifted = '(' },
> + [KEY_0] = { .normal = '0', .shifted = ')' },
> +
> + [KEY_MINUS] = { .normal = '-', .shifted = '_' },
> + [KEY_EQUAL] = { .normal = '=', .shifted = '+' },
> + [KEY_TAB] = { .normal = '\t' },
> + [KEY_LEFTBRACE] = { .normal = '[', .shifted = '{' },
> + [KEY_RIGHTBRACE] = { .normal = ']', .shifted = '}' },
> + [KEY_ENTER] = { .normal = '\n', },
> + [KEY_SEMICOLON] = { .normal = ';', .shifted = ':' },
> + [KEY_APOSTROPHE] = { .normal = '"', .shifted = '\'' },
> + [KEY_BACKSLASH] = { .normal = '\\', .shifted = '|' },
> + [KEY_COMMA] = { .normal = ',', .shifted = '<' },
> + [KEY_DOT] = { .normal = '.', .shifted = '>' },
> + [KEY_SLASH] = { .normal = '/', .shifted = '?' },
> + [KEY_SPACE] = { .normal = ' ' },
> +
> + [KEY_BACKSPACE] = { .normal = QEMU_KEY_BACKSPACE },
> + [KEY_UP] = { .normal = QEMU_KEY_UP },
> + [KEY_DOWN] = { .normal = QEMU_KEY_DOWN },
> + [KEY_LEFT] = { .normal = QEMU_KEY_LEFT },
> + [KEY_RIGHT] = { .normal = QEMU_KEY_RIGHT },
> +};
> +
> +static void start_mediumraw(int tty)
> +{
> + struct termios tattr;
> +
> + if (tty_mediumraw) {
> + return;
> + }
> + trace_fbdev_kbd_raw(1);
> +
> + /* save state */
> + tcgetattr(tty, &tty_attributes);
> + ioctl(tty, KDGKBMODE, &tty_mode);
> + tty_flags = fcntl(tty, F_GETFL, NULL);
> +
> + /* setup */
> + tattr = tty_attributes;
> + tattr.c_cflag &= ~(IXON|IXOFF);
> + tattr.c_lflag &= ~(ICANON|ECHO|ISIG);
> + tattr.c_iflag = 0;
> + tattr.c_cc[VMIN] = 1;
> + tattr.c_cc[VTIME] = 0;
> + tcsetattr(tty, TCSAFLUSH, &tattr);
> + ioctl(tty, KDSKBMODE, K_MEDIUMRAW);
> + fcntl(tty, F_SETFL, tty_flags | O_NONBLOCK);
> +
> + tty_mediumraw = true;
> +}
> +
> +static void stop_mediumraw(int tty)
> +{
> + if (!tty_mediumraw) {
> + return;
> + }
> + trace_fbdev_kbd_raw(0);
> +
> + /* restore state */
> + tcsetattr(tty, TCSANOW, &tty_attributes);
> + ioctl(tty, KDSKBMODE, tty_mode);
> + fcntl(tty, F_SETFL, tty_flags);
> +
> + tty_mediumraw = false;
> +}
> +
> +static void send_scancode(int keycode, int up)
> +{
> + int scancode = scancode_map[keycode];
> +
> + if (!scancode) {
> + fprintf(stderr, "%s: unmapped key: 0x%x %s\n",
> + __func__, keycode, keynames[keycode]);
> + return;
> + }
> + if (scancode & SCANCODE_GREY) {
> + kbd_put_keycode(SCANCODE_EMUL0);
> + }
> + if (up) {
> + kbd_put_keycode(scancode | SCANCODE_UP);
> + } else {
> + kbd_put_keycode(scancode & SCANCODE_KEYCODEMASK);
> + }
> +}
> +
> +static void send_keysym(int keycode, int shift)
> +{
> + const struct keysym_map *keysym_map = keysym_map_en_us;
> + int keysym;
> +
> + if (shift && keysym_map[keycode].shifted) {
> + keysym = keysym_map[keycode].shifted;
> + } else if (keysym_map[keycode].normal) {
> + keysym = keysym_map[keycode].normal;
> + } else {
> + fprintf(stderr, "%s: unmapped key: 0x%x %s\n",
> + __func__, keycode, keynames[keycode]);
> + return;
> + }
> + kbd_put_keysym(keysym);
> +}
> +
> +static void reset_keys(void)
> +{
> + int keycode;
> +
> + for (keycode = 0; keycode < KEY_MAX; keycode++) {
> + if (key_down[keycode]) {
> + if (is_graphic_console()) {
> + send_scancode(keycode, 1);
> + }
> + key_down[keycode] = false;
> + }
> + }
> +}
> +
> +static void read_mediumraw(void *opaque)
> +{
> + uint8_t buf[32];
> + int i, rc, up, keycode;
> + bool ctrl, alt, shift;
> +
> + rc = read(tty, buf, sizeof(buf));
> + switch (rc) {
> + case -1:
> + perror("read tty");
> + goto err;
> + case 0:
> + fprintf(stderr, "%s: eof\n", __func__);
> + goto err;
> + default:
> + for (i = 0; i < rc; i++) {
> + up = buf[i] & 0x80;
> + keycode = buf[i] & 0x7f;
> + if (keycode == 0) {
> + keycode = (buf[i+1] & 0x7f) << 7;
> + keycode |= buf[i+2] & 0x7f;
> + i += 2;
> + }
> + if (keycode > KEY_MAX) {
> + continue;
> + }
> +
> + if (up) {
> + if (!key_down[keycode]) {
> + continue;
> + }
> + key_down[keycode] = false;
> + } else {
> + key_down[keycode] = true;
> + }
> +
> + trace_fbdev_kbd_event(keycode, keynames[keycode], !up);
> +
> + alt = key_down[KEY_LEFTALT] || key_down[KEY_RIGHTALT];
> + ctrl = key_down[KEY_LEFTCTRL] || key_down[KEY_RIGHTCTRL];
> + shift = key_down[KEY_LEFTSHIFT] || key_down[KEY_RIGHTSHIFT];
> +
> + if (ctrl && alt && !up) {
> + if (keycode == KEY_ESC) {
> + fprintf(stderr, "=== fbdev emergency escape "
> + "(ctrl-alt-esc) ===\n");
> + exit(1);
> + }
> + if (keycode >= KEY_F1 && keycode <= KEY_F10) {
> + fbdev_activate_vt(tty, keycode+1-KEY_F1, false);
> + key_down[keycode] = false;
> + continue;
> + }
> + if (keycode >= KEY_1 && keycode <= KEY_9) {
> + console_select(keycode-KEY_1);
> + reset_keys();
> + continue;
> + }
> + }
> +
> + if (is_graphic_console()) {
> + send_scancode(keycode, up);
> + } else if (!up) {
> + send_keysym(keycode, shift);
> + }
> + }
> + }
> + return;
> +
> +err:
> + exit(1);
> +}
> +
> +/* -------------------------------------------------------------------- */
> +
> +static void fbdev_cls(void)
> +{
> + memset(fb_mem + fb_mem_offset, 0, fb_fix.line_length * fb_var.yres);
> +}
> +
> +static int fbdev_activate_vt(int tty, int vtno, bool wait)
> +{
> + trace_fbdev_vt_activate(vtno, wait);
> +
> + if (ioctl(tty, VT_ACTIVATE, vtno) < 0) {
> + perror("ioctl VT_ACTIVATE");
> + return -1;
> + }
> +
> + if (wait) {
> + if (ioctl(tty, VT_WAITACTIVE, vtno) < 0) {
> + perror("ioctl VT_WAITACTIVE");
> + return -1;
> + }
> + trace_fbdev_vt_activated();
> + }
> +
> + return 0;
> +}
> +
> +static void fbdev_cleanup(void)
> +{
> + trace_fbdev_cleanup();
> +
> + /* restore console */
> + if (fb_mem != NULL) {
> + munmap(fb_mem, fb_fix.smem_len+fb_mem_offset);
> + fb_mem = NULL;
> + }
> + if (fb != -1) {
> + if (ioctl(fb, FBIOPUT_VSCREENINFO, &fb_ovar) < 0) {
> + perror("ioctl FBIOPUT_VSCREENINFO");
> + }
> + close(fb);
> + fb = -1;
> + }
> +
> + if (tty != -1) {
> + stop_mediumraw(tty);
> + if (ioctl(tty, KDSETMODE, kd_omode) < 0) {
> + perror("ioctl KDSETMODE");
> + }
> + if (ioctl(tty, VT_SETMODE, &vt_omode) < 0) {
> + perror("ioctl VT_SETMODE");
> + }
> + if (orig_vtno) {
> + fbdev_activate_vt(tty, orig_vtno, true);
> + }
> + qemu_set_fd_handler(tty, NULL, NULL, NULL);
> + close(tty);
> + tty = -1;
> + }
> +}
> +
> +static int fbdev_init(const char *device)
> +{
> + struct vt_stat vts;
> + unsigned long page_mask;
> + char ttyname[32];
> +
> + /* open framebuffer */
> + if (device == NULL) {
> + device = getenv("FRAMEBUFFER");
> + }
> + if (device == NULL) {
> + device = "/dev/fb0";
> + }
> + fb = open(device, O_RDWR);
> + if (fb == -1) {
> + fprintf(stderr, "open %s: %s\n", device, strerror(errno));
> + return -1;
> + }
> +
> + /* open virtual console */
> + tty = 0;
> + if (ioctl(tty, VT_GETSTATE, &vts) < 0) {
> + fprintf(stderr, "Not started from virtual terminal, "
> + "trying to open one.\n");
> +
> + snprintf(ttyname, sizeof(ttyname), "/dev/tty0");
> + tty = open(ttyname, O_RDWR);
> + if (tty == -1) {
> + fprintf(stderr, "open %s: %s\n", ttyname, strerror(errno));
> + goto err_early;
> + }
> + if (ioctl(tty, VT_OPENQRY, &vtno) < 0) {
> + perror("ioctl VT_OPENQRY");
> + goto err_early;
> + }
> + if (ioctl(tty, VT_GETSTATE, &vts) < 0) {
> + perror("ioctl VT_GETSTATE\n");
> + goto err_early;
> + }
> + close(tty);
> +
> + snprintf(ttyname, sizeof(ttyname), "/dev/tty%d", vtno);
> + tty = open(ttyname, O_RDWR);
> + if (tty == -1) {
> + fprintf(stderr, "open %s: %s\n", ttyname, strerror(errno));
> + goto err_early;
> + }
> + orig_vtno = vts.v_active;
> + fprintf(stderr, "Switching to vt %d (current %d).\n", vtno, orig_vtno);
> + } else {
> + orig_vtno = 0;
> + vtno = vts.v_active;
> + fprintf(stderr, "Started at vt %d, using it.\n", vtno);
> + }
> + fbdev_activate_vt(tty, vtno, true);
> +
> + /* get current settings (which we have to restore) */
> + if (ioctl(fb, FBIOGET_VSCREENINFO, &fb_ovar) < 0) {
> + perror("ioctl FBIOGET_VSCREENINFO");
> + goto err_early;
> + }
> + if (ioctl(tty, KDGETMODE, &kd_omode) < 0) {
> + perror("ioctl KDGETMODE");
> + goto err_early;
> + }
> + if (ioctl(tty, VT_GETMODE, &vt_omode) < 0) {
> + perror("ioctl VT_GETMODE");
> + goto err_early;
> + }
> +
> + /* checks & initialisation */
> + if (ioctl(fb, FBIOGET_FSCREENINFO, &fb_fix) < 0) {
> + perror("ioctl FBIOGET_FSCREENINFO");
> + goto err;
> + }
> + if (ioctl(fb, FBIOGET_VSCREENINFO, &fb_var) < 0) {
> + perror("ioctl FBIOGET_VSCREENINFO");
> + goto err;
> + }
> + if (fb_fix.type != FB_TYPE_PACKED_PIXELS) {
> + fprintf(stderr, "can handle only packed pixel frame buffers\n");
> + goto err;
> + }
> + switch (fb_var.bits_per_pixel) {
> + case 32:
> + break;
> + default:
> + fprintf(stderr, "can't handle %d bpp frame buffers\n",
> + fb_var.bits_per_pixel);
> + goto err;
> + }
> +
> + page_mask = getpagesize()-1;
> + fb_switch_state = FB_ACTIVE;
> + fb_mem_offset = (unsigned long)(fb_fix.smem_start) & page_mask;
> + fb_mem = mmap(NULL, fb_fix.smem_len+fb_mem_offset,
> + PROT_READ|PROT_WRITE, MAP_SHARED, fb, 0);
> + if (fb_mem == MAP_FAILED) {
> + perror("mmap");
> + goto err;
> + }
> + /* move viewport to upper left corner */
> + if (fb_var.xoffset != 0 || fb_var.yoffset != 0) {
> + fb_var.xoffset = 0;
> + fb_var.yoffset = 0;
> + if (ioctl(fb, FBIOPAN_DISPLAY, &fb_var) < 0) {
> + perror("ioctl FBIOPAN_DISPLAY");
> + goto err;
> + }
> + }
> + if (ioctl(tty, KDSETMODE, KD_GRAPHICS) < 0) {
> + perror("ioctl KDSETMODE");
> + goto err;
> + }
> + /* some fb drivers need this again after switching to graphics ... */
> + fbdev_activate_vt(tty, vtno, true);
> +
> + fbdev_cls();
> +
> + start_mediumraw(tty);
> + qemu_set_fd_handler(tty, read_mediumraw, NULL, NULL);
> +
> + /* create PixelFormat from fbdev structs */
> + fbpf.bits_per_pixel = fb_var.bits_per_pixel;
> + fbpf.bytes_per_pixel = (fb_var.bits_per_pixel+7)/8;
> + fbpf.depth = fb_var.bits_per_pixel == 32
> + ? 24 : fb_var.bits_per_pixel;
> + fbpf.rshift = fb_var.red.offset;
> + fbpf.rbits = fb_var.red.length;
> + fbpf.gshift = fb_var.green.offset;
> + fbpf.gbits = fb_var.green.length;
> + fbpf.bshift = fb_var.blue.offset;
> + fbpf.bbits = fb_var.blue.length;
> + fbpf.ashift = fb_var.transp.offset;
> + fbpf.abits = fb_var.transp.length;
> +
> + if (fbpf.rbits) {
> + fbpf.rmax = (1 << fbpf.rbits) - 1;
> + fbpf.rmask = fbpf.rmax << fbpf.rshift;
> + }
> + if (fbpf.gbits) {
> + fbpf.gmax = (1 << fbpf.gbits) - 1;
> + fbpf.gmask = fbpf.gmax << fbpf.gshift;
> + }
> + if (fbpf.bbits) {
> + fbpf.bmax = (1 << fbpf.bbits) - 1;
> + fbpf.bmask = fbpf.bmax << fbpf.bshift;
> + }
> + if (fbpf.abits) {
> + fbpf.amax = (1 << fbpf.abits) - 1;
> + fbpf.amask = fbpf.amax << fbpf.ashift;
> + }
> + return 0;
> +
> +err_early:
> + if (tty > 0) {
> + close(tty);
> + }
> + close(fb);
> + return -1;
> +
> +err:
> + fbdev_cleanup();
> + return -1;
> +}
> +
> +static void
> +fbdev_catch_fatal_signal(int signr)
> +{
> + fprintf(stderr, "%s: %s, restoring linux console state ...\n",
> + __func__, strsignal(signr));
> + fbdev_cleanup();
> + signal(SIGABRT, SIG_DFL);
> + fprintf(stderr, "%s: ... done, going abort() now.\n", __func__);
> + abort();
> +}
> +
> +static void fbdev_catch_exit_signals(void)
> +{
> + static const int signals[] = {
> + SIGQUIT, SIGILL, SIGABRT, SIGFPE, SIGSEGV, SIGBUS
> + };
> + struct sigaction act, old;
> + int i;
> +
> + memset(&act, 0, sizeof(act));
> + act.sa_handler = fbdev_catch_fatal_signal;
> + act.sa_flags = SA_RESETHAND;
> + sigemptyset(&act.sa_mask);
> + for (i = 0; i < ARRAY_SIZE(signals); i++) {
> + sigaction(signals[i], &act, &old);
> + }
> +}
> +
> +/* -------------------------------------------------------------------- */
> +/* console switching */
> +
> +static void fbdev_switch_signal(int signal)
> +{
> + if (signal == SIG_REL) {
> + /* release */
> + trace_fbdev_vt_release_request();
> + fb_switch_state = FB_REL_REQ;
> + }
> + if (signal == SIG_ACQ) {
> + /* acquisition */
> + trace_fbdev_vt_aquire_request();
> + fb_switch_state = FB_ACQ_REQ;
> + }
> +}
> +
> +static void fbdev_switch_release(void)
> +{
> + stop_mediumraw(tty);
> + ioctl(tty, KDSETMODE, kd_omode);
> + ioctl(tty, VT_RELDISP, 1);
> + fb_switch_state = FB_INACTIVE;
> + trace_fbdev_vt_released();
> +}
> +
> +static void fbdev_switch_acquire(void)
> +{
> + ioctl(tty, VT_RELDISP, VT_ACKACQ);
> + start_mediumraw(tty);
> + reset_keys();
> + ioctl(tty, KDSETMODE, KD_GRAPHICS);
> + fb_switch_state = FB_ACTIVE;
> + trace_fbdev_vt_aquired();
> +}
> +
> +static int fbdev_switch_init(void)
> +{
> + struct sigaction act, old;
> +
> + memset(&act, 0, sizeof(act));
> + act.sa_handler = fbdev_switch_signal;
> + sigemptyset(&act.sa_mask);
> + sigaction(SIG_REL, &act, &old);
> + sigaction(SIG_ACQ, &act, &old);
> +
> + if (ioctl(tty, VT_GETMODE, &vt_mode) < 0) {
> + perror("ioctl VT_GETMODE");
> + exit(1);
> + }
> + vt_mode.mode = VT_PROCESS;
> + vt_mode.waitv = 0;
> + vt_mode.relsig = SIG_REL;
> + vt_mode.acqsig = SIG_ACQ;
> +
> + if (ioctl(tty, VT_SETMODE, &vt_mode) < 0) {
> + perror("ioctl VT_SETMODE");
> + exit(1);
> + }
> + return 0;
> +}
> +
> +/* -------------------------------------------------------------------- */
> +/* rendering */
> +
> +static void fbdev_render(DisplayState *ds, int x, int y, int w, int h)
> +{
> + uint8_t *dst;
> + uint8_t *src;
> + int line;
> +
> + if (!conv) {
> + return;
> + }
> +
> + src = ds_get_data(ds) + y * ds_get_linesize(ds)
> + + x * ds_get_bytes_per_pixel(ds);
> + dst = fb_mem + y * fb_fix.line_length
> + + x * fbpf.bytes_per_pixel;
> +
> + dst += cy * fb_fix.line_length;
> + dst += cx * fbpf.bytes_per_pixel;
> +
> + if (h > fb_var.yres - y) {
> + h = fb_var.yres - y;
> + }
> + if (w > fb_var.xres - x) {
> + w = fb_var.xres - x;
> + }
> +
> + for (line = y; line < y+h; line++) {
> + qemu_pf_conv_run(conv, dst, src, w);
> + dst += fb_fix.line_length;
> + src += ds_get_linesize(ds);
> + }
> +}
> +
> +/* -------------------------------------------------------------------- */
> +/* qemu interfaces */
> +
> +static void fbdev_update(DisplayState *ds, int x, int y, int w, int h)
> +{
> + if (fb_switch_state != FB_ACTIVE) {
> + return;
> + }
> +
> + if (resize_screen) {
> + trace_fbdev_dpy_resize(ds_get_width(ds), ds_get_height(ds));
> + resize_screen = 0;
> + cx = 0; cy = 0;
> + cw = ds_get_width(ds);
> + ch = ds_get_height(ds);
> + if (ds_get_width(ds) < fb_var.xres) {
> + cx = (fb_var.xres - ds_get_width(ds)) / 2;
> + }
> + if (ds_get_height(ds) < fb_var.yres) {
> + cy = (fb_var.yres - ds_get_height(ds)) / 2;
> + }
> +
> + if (conv) {
> + qemu_pf_conv_put(conv);
> + }
> + conv = qemu_pf_conv_get(&fbpf, &ds->surface->pf);
> + if (conv == NULL) {
> + fprintf(stderr, "fbdev: unsupported PixelFormat conversion\n");
> + }
> + }
> +
> + if (redraw_screen) {
> + trace_fbdev_dpy_redraw();
> + redraw_screen = 0;
> + fbdev_cls();
> + x = 0; y = 0; w = ds_get_width(ds); h = ds_get_height(ds);
> + }
> +
> + fbdev_render(ds, x, y, w, h);
> +}
> +
> +static void fbdev_resize(DisplayState *ds)
> +{
> + resize_screen++;
> + redraw_screen++;
> +}
> +
> +static void fbdev_setdata(DisplayState *ds)
> +{
> + if (surface) {
> + pixman_image_unref(surface);
> + }
> + surface = pixman_from_displaystate(ds);
> + redraw_screen++;
> +}
> +
> +static void fbdev_refresh(DisplayState *ds)
> +{
> + switch (fb_switch_state) {
> + case FB_REL_REQ:
> + fbdev_switch_release();
Missing comment about fallthrough or 'break'.
> + case FB_INACTIVE:
> + return;
> + case FB_ACQ_REQ:
> + fbdev_switch_acquire();
> + redraw_screen++;
Also here.
> + case FB_ACTIVE:
> + break;
> + }
> +
> + vga_hw_update();
> + if (redraw_screen) {
> + fbdev_update(ds, 0, 0, 0, 0);
> + }
> +}
> +
> +static void fbdev_exit_notifier(Notifier *notifier, void *data)
> +{
> + fbdev_cleanup();
> +}
> +
> +int fbdev_display_init(DisplayState *ds, const char *device)
> +{
> + if (dcl != NULL) {
> + return 0;
> + }
> +
> + if (fbdev_init(device) != 0) {
> + return -1;
> + }
> + exit_notifier.notify = fbdev_exit_notifier;
> + qemu_add_exit_notifier(&exit_notifier);
> + fbdev_switch_init();
> + fbdev_catch_exit_signals();
> + init_mouse();
> +
> + fbdev_resize(ds);
> + dcl = g_new0(DisplayChangeListener, 1);
> + dcl->dpy_update = fbdev_update;
> + dcl->dpy_resize = fbdev_resize;
> + dcl->dpy_setdata = fbdev_setdata;
> + dcl->dpy_refresh = fbdev_refresh;
> + register_displaychangelistener(ds, dcl);
> +
> + trace_fbdev_enabled();
> + return 0;
> +}
> +
> +void fbdev_display_uninit(DisplayState *ds)
> +{
> + if (dcl == NULL) {
> + return;
> + }
> +
> + unregister_displaychangelistener(ds, dcl);
> + g_free(dcl);
> + dcl = NULL;
> +
> + fbdev_cleanup();
> + qemu_remove_exit_notifier(&exit_notifier);
> + uninit_mouse();
> +}
> diff --git a/ui/linux-keynames.h b/ui/linux-keynames.h
> new file mode 100644
> index 0000000..058af28
> --- /dev/null
> +++ b/ui/linux-keynames.h
> @@ -0,0 +1,388 @@
> +/*
> + * awk '/#define KEY_/ { printf(" [%s] = \"%s\",\n",$2,$2); }' \
> + * /usr/include/linux/input.h
> + */
> + [KEY_RESERVED] = "KEY_RESERVED",
> + [KEY_ESC] = "KEY_ESC",
> + [KEY_1] = "KEY_1",
> + [KEY_2] = "KEY_2",
> + [KEY_3] = "KEY_3",
> + [KEY_4] = "KEY_4",
> + [KEY_5] = "KEY_5",
> + [KEY_6] = "KEY_6",
> + [KEY_7] = "KEY_7",
> + [KEY_8] = "KEY_8",
> + [KEY_9] = "KEY_9",
> + [KEY_0] = "KEY_0",
> + [KEY_MINUS] = "KEY_MINUS",
> + [KEY_EQUAL] = "KEY_EQUAL",
> + [KEY_BACKSPACE] = "KEY_BACKSPACE",
> + [KEY_TAB] = "KEY_TAB",
> + [KEY_Q] = "KEY_Q",
> + [KEY_W] = "KEY_W",
> + [KEY_E] = "KEY_E",
> + [KEY_R] = "KEY_R",
> + [KEY_T] = "KEY_T",
> + [KEY_Y] = "KEY_Y",
> + [KEY_U] = "KEY_U",
> + [KEY_I] = "KEY_I",
> + [KEY_O] = "KEY_O",
> + [KEY_P] = "KEY_P",
> + [KEY_LEFTBRACE] = "KEY_LEFTBRACE",
> + [KEY_RIGHTBRACE] = "KEY_RIGHTBRACE",
> + [KEY_ENTER] = "KEY_ENTER",
> + [KEY_LEFTCTRL] = "KEY_LEFTCTRL",
> + [KEY_A] = "KEY_A",
> + [KEY_S] = "KEY_S",
> + [KEY_D] = "KEY_D",
> + [KEY_F] = "KEY_F",
> + [KEY_G] = "KEY_G",
> + [KEY_H] = "KEY_H",
> + [KEY_J] = "KEY_J",
> + [KEY_K] = "KEY_K",
> + [KEY_L] = "KEY_L",
> + [KEY_SEMICOLON] = "KEY_SEMICOLON",
> + [KEY_APOSTROPHE] = "KEY_APOSTROPHE",
> + [KEY_GRAVE] = "KEY_GRAVE",
> + [KEY_LEFTSHIFT] = "KEY_LEFTSHIFT",
> + [KEY_BACKSLASH] = "KEY_BACKSLASH",
> + [KEY_Z] = "KEY_Z",
> + [KEY_X] = "KEY_X",
> + [KEY_C] = "KEY_C",
> + [KEY_V] = "KEY_V",
> + [KEY_B] = "KEY_B",
> + [KEY_N] = "KEY_N",
> + [KEY_M] = "KEY_M",
> + [KEY_COMMA] = "KEY_COMMA",
> + [KEY_DOT] = "KEY_DOT",
> + [KEY_SLASH] = "KEY_SLASH",
> + [KEY_RIGHTSHIFT] = "KEY_RIGHTSHIFT",
> + [KEY_KPASTERISK] = "KEY_KPASTERISK",
> + [KEY_LEFTALT] = "KEY_LEFTALT",
> + [KEY_SPACE] = "KEY_SPACE",
> + [KEY_CAPSLOCK] = "KEY_CAPSLOCK",
> + [KEY_F1] = "KEY_F1",
> + [KEY_F2] = "KEY_F2",
> + [KEY_F3] = "KEY_F3",
> + [KEY_F4] = "KEY_F4",
> + [KEY_F5] = "KEY_F5",
> + [KEY_F6] = "KEY_F6",
> + [KEY_F7] = "KEY_F7",
> + [KEY_F8] = "KEY_F8",
> + [KEY_F9] = "KEY_F9",
> + [KEY_F10] = "KEY_F10",
> + [KEY_NUMLOCK] = "KEY_NUMLOCK",
> + [KEY_SCROLLLOCK] = "KEY_SCROLLLOCK",
> + [KEY_KP7] = "KEY_KP7",
> + [KEY_KP8] = "KEY_KP8",
> + [KEY_KP9] = "KEY_KP9",
> + [KEY_KPMINUS] = "KEY_KPMINUS",
> + [KEY_KP4] = "KEY_KP4",
> + [KEY_KP5] = "KEY_KP5",
> + [KEY_KP6] = "KEY_KP6",
> + [KEY_KPPLUS] = "KEY_KPPLUS",
> + [KEY_KP1] = "KEY_KP1",
> + [KEY_KP2] = "KEY_KP2",
> + [KEY_KP3] = "KEY_KP3",
> + [KEY_KP0] = "KEY_KP0",
> + [KEY_KPDOT] = "KEY_KPDOT",
> + [KEY_ZENKAKUHANKAKU] = "KEY_ZENKAKUHANKAKU",
> + [KEY_102ND] = "KEY_102ND",
> + [KEY_F11] = "KEY_F11",
> + [KEY_F12] = "KEY_F12",
> + [KEY_RO] = "KEY_RO",
> + [KEY_KATAKANA] = "KEY_KATAKANA",
> + [KEY_HIRAGANA] = "KEY_HIRAGANA",
> + [KEY_HENKAN] = "KEY_HENKAN",
> + [KEY_KATAKANAHIRAGANA] = "KEY_KATAKANAHIRAGANA",
> + [KEY_MUHENKAN] = "KEY_MUHENKAN",
> + [KEY_KPJPCOMMA] = "KEY_KPJPCOMMA",
> + [KEY_KPENTER] = "KEY_KPENTER",
> + [KEY_RIGHTCTRL] = "KEY_RIGHTCTRL",
> + [KEY_KPSLASH] = "KEY_KPSLASH",
> + [KEY_SYSRQ] = "KEY_SYSRQ",
> + [KEY_RIGHTALT] = "KEY_RIGHTALT",
> + [KEY_LINEFEED] = "KEY_LINEFEED",
> + [KEY_HOME] = "KEY_HOME",
> + [KEY_UP] = "KEY_UP",
> + [KEY_PAGEUP] = "KEY_PAGEUP",
> + [KEY_LEFT] = "KEY_LEFT",
> + [KEY_RIGHT] = "KEY_RIGHT",
> + [KEY_END] = "KEY_END",
> + [KEY_DOWN] = "KEY_DOWN",
> + [KEY_PAGEDOWN] = "KEY_PAGEDOWN",
> + [KEY_INSERT] = "KEY_INSERT",
> + [KEY_DELETE] = "KEY_DELETE",
> + [KEY_MACRO] = "KEY_MACRO",
> + [KEY_MUTE] = "KEY_MUTE",
> + [KEY_VOLUMEDOWN] = "KEY_VOLUMEDOWN",
> + [KEY_VOLUMEUP] = "KEY_VOLUMEUP",
> + [KEY_POWER] = "KEY_POWER",
> + [KEY_KPEQUAL] = "KEY_KPEQUAL",
> + [KEY_KPPLUSMINUS] = "KEY_KPPLUSMINUS",
> + [KEY_PAUSE] = "KEY_PAUSE",
> + [KEY_SCALE] = "KEY_SCALE",
> + [KEY_KPCOMMA] = "KEY_KPCOMMA",
> + [KEY_HANGEUL] = "KEY_HANGEUL",
> + [KEY_HANGUEL] = "KEY_HANGUEL",
> + [KEY_HANJA] = "KEY_HANJA",
> + [KEY_YEN] = "KEY_YEN",
> + [KEY_LEFTMETA] = "KEY_LEFTMETA",
> + [KEY_RIGHTMETA] = "KEY_RIGHTMETA",
> + [KEY_COMPOSE] = "KEY_COMPOSE",
> + [KEY_STOP] = "KEY_STOP",
> + [KEY_AGAIN] = "KEY_AGAIN",
> + [KEY_PROPS] = "KEY_PROPS",
> + [KEY_UNDO] = "KEY_UNDO",
> + [KEY_FRONT] = "KEY_FRONT",
> + [KEY_COPY] = "KEY_COPY",
> + [KEY_OPEN] = "KEY_OPEN",
> + [KEY_PASTE] = "KEY_PASTE",
> + [KEY_FIND] = "KEY_FIND",
> + [KEY_CUT] = "KEY_CUT",
> + [KEY_HELP] = "KEY_HELP",
> + [KEY_MENU] = "KEY_MENU",
> + [KEY_CALC] = "KEY_CALC",
> + [KEY_SETUP] = "KEY_SETUP",
> + [KEY_SLEEP] = "KEY_SLEEP",
> + [KEY_WAKEUP] = "KEY_WAKEUP",
> + [KEY_FILE] = "KEY_FILE",
> + [KEY_SENDFILE] = "KEY_SENDFILE",
> + [KEY_DELETEFILE] = "KEY_DELETEFILE",
> + [KEY_XFER] = "KEY_XFER",
> + [KEY_PROG1] = "KEY_PROG1",
> + [KEY_PROG2] = "KEY_PROG2",
> + [KEY_WWW] = "KEY_WWW",
> + [KEY_MSDOS] = "KEY_MSDOS",
> + [KEY_COFFEE] = "KEY_COFFEE",
> + [KEY_SCREENLOCK] = "KEY_SCREENLOCK",
> + [KEY_DIRECTION] = "KEY_DIRECTION",
> + [KEY_CYCLEWINDOWS] = "KEY_CYCLEWINDOWS",
> + [KEY_MAIL] = "KEY_MAIL",
> + [KEY_BOOKMARKS] = "KEY_BOOKMARKS",
> + [KEY_COMPUTER] = "KEY_COMPUTER",
> + [KEY_BACK] = "KEY_BACK",
> + [KEY_FORWARD] = "KEY_FORWARD",
> + [KEY_CLOSECD] = "KEY_CLOSECD",
> + [KEY_EJECTCD] = "KEY_EJECTCD",
> + [KEY_EJECTCLOSECD] = "KEY_EJECTCLOSECD",
> + [KEY_NEXTSONG] = "KEY_NEXTSONG",
> + [KEY_PLAYPAUSE] = "KEY_PLAYPAUSE",
> + [KEY_PREVIOUSSONG] = "KEY_PREVIOUSSONG",
> + [KEY_STOPCD] = "KEY_STOPCD",
> + [KEY_RECORD] = "KEY_RECORD",
> + [KEY_REWIND] = "KEY_REWIND",
> + [KEY_PHONE] = "KEY_PHONE",
> + [KEY_ISO] = "KEY_ISO",
> + [KEY_CONFIG] = "KEY_CONFIG",
> + [KEY_HOMEPAGE] = "KEY_HOMEPAGE",
> + [KEY_REFRESH] = "KEY_REFRESH",
> + [KEY_EXIT] = "KEY_EXIT",
> + [KEY_MOVE] = "KEY_MOVE",
> + [KEY_EDIT] = "KEY_EDIT",
> + [KEY_SCROLLUP] = "KEY_SCROLLUP",
> + [KEY_SCROLLDOWN] = "KEY_SCROLLDOWN",
> + [KEY_KPLEFTPAREN] = "KEY_KPLEFTPAREN",
> + [KEY_KPRIGHTPAREN] = "KEY_KPRIGHTPAREN",
> + [KEY_NEW] = "KEY_NEW",
> + [KEY_REDO] = "KEY_REDO",
> + [KEY_F13] = "KEY_F13",
> + [KEY_F14] = "KEY_F14",
> + [KEY_F15] = "KEY_F15",
> + [KEY_F16] = "KEY_F16",
> + [KEY_F17] = "KEY_F17",
> + [KEY_F18] = "KEY_F18",
> + [KEY_F19] = "KEY_F19",
> + [KEY_F20] = "KEY_F20",
> + [KEY_F21] = "KEY_F21",
> + [KEY_F22] = "KEY_F22",
> + [KEY_F23] = "KEY_F23",
> + [KEY_F24] = "KEY_F24",
> + [KEY_PLAYCD] = "KEY_PLAYCD",
> + [KEY_PAUSECD] = "KEY_PAUSECD",
> + [KEY_PROG3] = "KEY_PROG3",
> + [KEY_PROG4] = "KEY_PROG4",
> + [KEY_DASHBOARD] = "KEY_DASHBOARD",
> + [KEY_SUSPEND] = "KEY_SUSPEND",
> + [KEY_CLOSE] = "KEY_CLOSE",
> + [KEY_PLAY] = "KEY_PLAY",
> + [KEY_FASTFORWARD] = "KEY_FASTFORWARD",
> + [KEY_BASSBOOST] = "KEY_BASSBOOST",
> + [KEY_PRINT] = "KEY_PRINT",
> + [KEY_HP] = "KEY_HP",
> + [KEY_CAMERA] = "KEY_CAMERA",
> + [KEY_SOUND] = "KEY_SOUND",
> + [KEY_QUESTION] = "KEY_QUESTION",
> + [KEY_EMAIL] = "KEY_EMAIL",
> + [KEY_CHAT] = "KEY_CHAT",
> + [KEY_SEARCH] = "KEY_SEARCH",
> + [KEY_CONNECT] = "KEY_CONNECT",
> + [KEY_FINANCE] = "KEY_FINANCE",
> + [KEY_SPORT] = "KEY_SPORT",
> + [KEY_SHOP] = "KEY_SHOP",
> + [KEY_ALTERASE] = "KEY_ALTERASE",
> + [KEY_CANCEL] = "KEY_CANCEL",
> + [KEY_BRIGHTNESSDOWN] = "KEY_BRIGHTNESSDOWN",
> + [KEY_BRIGHTNESSUP] = "KEY_BRIGHTNESSUP",
> + [KEY_MEDIA] = "KEY_MEDIA",
> + [KEY_SWITCHVIDEOMODE] = "KEY_SWITCHVIDEOMODE",
> + [KEY_KBDILLUMTOGGLE] = "KEY_KBDILLUMTOGGLE",
> + [KEY_KBDILLUMDOWN] = "KEY_KBDILLUMDOWN",
> + [KEY_KBDILLUMUP] = "KEY_KBDILLUMUP",
> + [KEY_SEND] = "KEY_SEND",
> + [KEY_REPLY] = "KEY_REPLY",
> + [KEY_FORWARDMAIL] = "KEY_FORWARDMAIL",
> + [KEY_SAVE] = "KEY_SAVE",
> + [KEY_DOCUMENTS] = "KEY_DOCUMENTS",
> + [KEY_BATTERY] = "KEY_BATTERY",
> + [KEY_BLUETOOTH] = "KEY_BLUETOOTH",
> + [KEY_WLAN] = "KEY_WLAN",
> + [KEY_UWB] = "KEY_UWB",
> + [KEY_UNKNOWN] = "KEY_UNKNOWN",
> + [KEY_VIDEO_NEXT] = "KEY_VIDEO_NEXT",
> + [KEY_VIDEO_PREV] = "KEY_VIDEO_PREV",
> + [KEY_BRIGHTNESS_CYCLE] = "KEY_BRIGHTNESS_CYCLE",
> + [KEY_BRIGHTNESS_ZERO] = "KEY_BRIGHTNESS_ZERO",
> + [KEY_DISPLAY_OFF] = "KEY_DISPLAY_OFF",
> + [KEY_WIMAX] = "KEY_WIMAX",
> + [KEY_OK] = "KEY_OK",
> + [KEY_SELECT] = "KEY_SELECT",
> + [KEY_GOTO] = "KEY_GOTO",
> + [KEY_CLEAR] = "KEY_CLEAR",
> + [KEY_POWER2] = "KEY_POWER2",
> + [KEY_OPTION] = "KEY_OPTION",
> + [KEY_INFO] = "KEY_INFO",
> + [KEY_TIME] = "KEY_TIME",
> + [KEY_VENDOR] = "KEY_VENDOR",
> + [KEY_ARCHIVE] = "KEY_ARCHIVE",
> + [KEY_PROGRAM] = "KEY_PROGRAM",
> + [KEY_CHANNEL] = "KEY_CHANNEL",
> + [KEY_FAVORITES] = "KEY_FAVORITES",
> + [KEY_EPG] = "KEY_EPG",
> + [KEY_PVR] = "KEY_PVR",
> + [KEY_MHP] = "KEY_MHP",
> + [KEY_LANGUAGE] = "KEY_LANGUAGE",
> + [KEY_TITLE] = "KEY_TITLE",
> + [KEY_SUBTITLE] = "KEY_SUBTITLE",
> + [KEY_ANGLE] = "KEY_ANGLE",
> + [KEY_ZOOM] = "KEY_ZOOM",
> + [KEY_MODE] = "KEY_MODE",
> + [KEY_KEYBOARD] = "KEY_KEYBOARD",
> + [KEY_SCREEN] = "KEY_SCREEN",
> + [KEY_PC] = "KEY_PC",
> + [KEY_TV] = "KEY_TV",
> + [KEY_TV2] = "KEY_TV2",
> + [KEY_VCR] = "KEY_VCR",
> + [KEY_VCR2] = "KEY_VCR2",
> + [KEY_SAT] = "KEY_SAT",
> + [KEY_SAT2] = "KEY_SAT2",
> + [KEY_CD] = "KEY_CD",
> + [KEY_TAPE] = "KEY_TAPE",
> + [KEY_RADIO] = "KEY_RADIO",
> + [KEY_TUNER] = "KEY_TUNER",
> + [KEY_PLAYER] = "KEY_PLAYER",
> + [KEY_TEXT] = "KEY_TEXT",
> + [KEY_DVD] = "KEY_DVD",
> + [KEY_AUX] = "KEY_AUX",
> + [KEY_MP3] = "KEY_MP3",
> + [KEY_AUDIO] = "KEY_AUDIO",
> + [KEY_VIDEO] = "KEY_VIDEO",
> + [KEY_DIRECTORY] = "KEY_DIRECTORY",
> + [KEY_LIST] = "KEY_LIST",
> + [KEY_MEMO] = "KEY_MEMO",
> + [KEY_CALENDAR] = "KEY_CALENDAR",
> + [KEY_RED] = "KEY_RED",
> + [KEY_GREEN] = "KEY_GREEN",
> + [KEY_YELLOW] = "KEY_YELLOW",
> + [KEY_BLUE] = "KEY_BLUE",
> + [KEY_CHANNELUP] = "KEY_CHANNELUP",
> + [KEY_CHANNELDOWN] = "KEY_CHANNELDOWN",
> + [KEY_FIRST] = "KEY_FIRST",
> + [KEY_LAST] = "KEY_LAST",
> + [KEY_AB] = "KEY_AB",
> + [KEY_NEXT] = "KEY_NEXT",
> + [KEY_RESTART] = "KEY_RESTART",
> + [KEY_SLOW] = "KEY_SLOW",
> + [KEY_SHUFFLE] = "KEY_SHUFFLE",
> + [KEY_BREAK] = "KEY_BREAK",
> + [KEY_PREVIOUS] = "KEY_PREVIOUS",
> + [KEY_DIGITS] = "KEY_DIGITS",
> + [KEY_TEEN] = "KEY_TEEN",
> + [KEY_TWEN] = "KEY_TWEN",
> + [KEY_VIDEOPHONE] = "KEY_VIDEOPHONE",
> + [KEY_GAMES] = "KEY_GAMES",
> + [KEY_ZOOMIN] = "KEY_ZOOMIN",
> + [KEY_ZOOMOUT] = "KEY_ZOOMOUT",
> + [KEY_ZOOMRESET] = "KEY_ZOOMRESET",
> + [KEY_WORDPROCESSOR] = "KEY_WORDPROCESSOR",
> + [KEY_EDITOR] = "KEY_EDITOR",
> + [KEY_SPREADSHEET] = "KEY_SPREADSHEET",
> + [KEY_GRAPHICSEDITOR] = "KEY_GRAPHICSEDITOR",
> + [KEY_PRESENTATION] = "KEY_PRESENTATION",
> + [KEY_DATABASE] = "KEY_DATABASE",
> + [KEY_NEWS] = "KEY_NEWS",
> + [KEY_VOICEMAIL] = "KEY_VOICEMAIL",
> + [KEY_ADDRESSBOOK] = "KEY_ADDRESSBOOK",
> + [KEY_MESSENGER] = "KEY_MESSENGER",
> + [KEY_DISPLAYTOGGLE] = "KEY_DISPLAYTOGGLE",
> + [KEY_SPELLCHECK] = "KEY_SPELLCHECK",
> + [KEY_LOGOFF] = "KEY_LOGOFF",
> + [KEY_DOLLAR] = "KEY_DOLLAR",
> + [KEY_EURO] = "KEY_EURO",
> + [KEY_FRAMEBACK] = "KEY_FRAMEBACK",
> + [KEY_FRAMEFORWARD] = "KEY_FRAMEFORWARD",
> + [KEY_CONTEXT_MENU] = "KEY_CONTEXT_MENU",
> + [KEY_MEDIA_REPEAT] = "KEY_MEDIA_REPEAT",
> + [KEY_10CHANNELSUP] = "KEY_10CHANNELSUP",
> + [KEY_10CHANNELSDOWN] = "KEY_10CHANNELSDOWN",
> + [KEY_DEL_EOL] = "KEY_DEL_EOL",
> + [KEY_DEL_EOS] = "KEY_DEL_EOS",
> + [KEY_INS_LINE] = "KEY_INS_LINE",
> + [KEY_DEL_LINE] = "KEY_DEL_LINE",
> + [KEY_FN] = "KEY_FN",
> + [KEY_FN_ESC] = "KEY_FN_ESC",
> + [KEY_FN_F1] = "KEY_FN_F1",
> + [KEY_FN_F2] = "KEY_FN_F2",
> + [KEY_FN_F3] = "KEY_FN_F3",
> + [KEY_FN_F4] = "KEY_FN_F4",
> + [KEY_FN_F5] = "KEY_FN_F5",
> + [KEY_FN_F6] = "KEY_FN_F6",
> + [KEY_FN_F7] = "KEY_FN_F7",
> + [KEY_FN_F8] = "KEY_FN_F8",
> + [KEY_FN_F9] = "KEY_FN_F9",
> + [KEY_FN_F10] = "KEY_FN_F10",
> + [KEY_FN_F11] = "KEY_FN_F11",
> + [KEY_FN_F12] = "KEY_FN_F12",
> + [KEY_FN_1] = "KEY_FN_1",
> + [KEY_FN_2] = "KEY_FN_2",
> + [KEY_FN_D] = "KEY_FN_D",
> + [KEY_FN_E] = "KEY_FN_E",
> + [KEY_FN_F] = "KEY_FN_F",
> + [KEY_FN_S] = "KEY_FN_S",
> + [KEY_FN_B] = "KEY_FN_B",
> + [KEY_BRL_DOT1] = "KEY_BRL_DOT1",
> + [KEY_BRL_DOT2] = "KEY_BRL_DOT2",
> + [KEY_BRL_DOT3] = "KEY_BRL_DOT3",
> + [KEY_BRL_DOT4] = "KEY_BRL_DOT4",
> + [KEY_BRL_DOT5] = "KEY_BRL_DOT5",
> + [KEY_BRL_DOT6] = "KEY_BRL_DOT6",
> + [KEY_BRL_DOT7] = "KEY_BRL_DOT7",
> + [KEY_BRL_DOT8] = "KEY_BRL_DOT8",
> + [KEY_BRL_DOT9] = "KEY_BRL_DOT9",
> + [KEY_BRL_DOT10] = "KEY_BRL_DOT10",
> + [KEY_NUMERIC_0] = "KEY_NUMERIC_0",
> + [KEY_NUMERIC_1] = "KEY_NUMERIC_1",
> + [KEY_NUMERIC_2] = "KEY_NUMERIC_2",
> + [KEY_NUMERIC_3] = "KEY_NUMERIC_3",
> + [KEY_NUMERIC_4] = "KEY_NUMERIC_4",
> + [KEY_NUMERIC_5] = "KEY_NUMERIC_5",
> + [KEY_NUMERIC_6] = "KEY_NUMERIC_6",
> + [KEY_NUMERIC_7] = "KEY_NUMERIC_7",
> + [KEY_NUMERIC_8] = "KEY_NUMERIC_8",
> + [KEY_NUMERIC_9] = "KEY_NUMERIC_9",
> + [KEY_NUMERIC_STAR] = "KEY_NUMERIC_STAR",
> + [KEY_NUMERIC_POUND] = "KEY_NUMERIC_POUND",
> + [KEY_RFKILL] = "KEY_RFKILL",
> + [KEY_MIN_INTERESTING] = "KEY_MIN_INTERESTING",
> + [KEY_MAX] = "KEY_MAX",
> + [KEY_CNT] = "KEY_CNT",
> diff --git a/vl.c b/vl.c
> index fbb77fe..18982b2 100644
> --- a/vl.c
> +++ b/vl.c
> @@ -3041,6 +3041,11 @@ int main(int argc, char **argv, char **envp)
> fprintf(stderr, "SDL support is disabled\n");
> exit(1);
> #endif
> +#ifdef CONFIG_LINUX
> + case QEMU_OPTION_fbdev:
> + display_type = DT_FBDEV;
> + break;
> +#endif
> case QEMU_OPTION_pidfile:
> pid_file = optarg;
> break;
> @@ -3681,6 +3686,13 @@ int main(int argc, char **argv, char **envp)
> curses_display_init(ds, full_screen);
> break;
> #endif
> +#if defined(CONFIG_LINUX)
> + case DT_FBDEV:
> + if (fbdev_display_init(ds, NULL) != 0) {
> + exit(1);
> + }
> + break;
> +#endif
> #if defined(CONFIG_SDL)
> case DT_SDL:
> sdl_display_init(ds, full_screen, no_frame);
> --
> 1.7.1
>
>
^ permalink raw reply [flat|nested] 29+ messages in thread
* Re: [Qemu-devel] [PATCH 7/9] fbdev: move to pixman
2012-09-18 19:14 ` Anthony Liguori
2012-09-18 21:08 ` Anthony Liguori
@ 2012-11-26 18:42 ` Alexander Graf
2012-11-26 20:01 ` Gerd Hoffmann
1 sibling, 1 reply; 29+ messages in thread
From: Alexander Graf @ 2012-11-26 18:42 UTC (permalink / raw)
To: Anthony Liguori; +Cc: Gerd Hoffmann, qemu-devel
Replying here because my INBOX doesn't contain the original message.
On 18.09.2012, at 21:14, Anthony Liguori wrote:
> Gerd Hoffmann <kraxel@redhat.com> writes:
>
>> Stop reinventing the wheel. Use the pixman library for raster ops.
>>
>> Signed-off-by: Gerd Hoffmann <kraxel@redhat.com>
>
> Why not cairo? I already have a cairo backend that uses GTK that
> supports scaling. That would be a good opportunity for sharing even
> more code.
>
> Regards,
>
> Anthony Liguori
>
>> ---
>> configure | 12 ++++
>> ui/fbdev.c | 172 +++++++++++++++++++++++++++++++++++------------------------
>> 2 files changed, 114 insertions(+), 70 deletions(-)
>>
>> diff --git a/configure b/configure
>> index c4ba338..d10ff78 100755
>> --- a/configure
>> +++ b/configure
>> @@ -148,6 +148,7 @@ docs=""
>> fdt=""
>> nptl=""
>> sdl=""
>> +pixman=""
>> fbdev="no"
>> virtfs=""
>> vnc="yes"
>> @@ -2153,6 +2154,17 @@ else
>> exit 1
>> fi
>>
>> +if $pkg_config pixman-1 > /dev/null 2>&1
>> +then
>> + pixman="yes"
>> + pixman_cflags=`$pkg_config --cflags pixman-1 2>/dev/null`
>> + pixman_libs=`$pkg_config --libs pixman-1 2>/dev/null`
>> + QEMU_CFLAGS="$QEMU_CFLAGS $pixman_cflags"
>> + libs_softmmu="$libs_softmmu $pixman_libs"
>> +else
>> + fbdev="no"
>> +fi
>> +
>> ##########################################
>> # libcap probe
>>
>> diff --git a/ui/fbdev.c b/ui/fbdev.c
>> index 40fc7d4..4cb4d1d 100644
>> --- a/ui/fbdev.c
>> +++ b/ui/fbdev.c
>> @@ -23,11 +23,12 @@
>> #include <linux/vt.h>
>> #include <linux/fb.h>
>>
>> +#include <pixman.h>
>> +
>> #include "qemu-common.h"
>> #include "console.h"
>> #include "keymaps.h"
>> #include "sysemu.h"
>> -#include "pflib.h"
>>
>> /*
>> * must be last so we get the linux input layer
>> @@ -70,19 +71,82 @@ static bool key_down[KEY_CNT];
>> #define FB_ACQ_REQ 3
>> static int fb_switch_state;
>>
>> -/* qdev windup */
>> +/* qemu windup */
>> static DisplayChangeListener *dcl;
>> -static QemuPfConv *conv;
>> -static PixelFormat fbpf;
>> static int resize_screen;
>> static int redraw_screen;
>> static int cx, cy, cw, ch;
>> static Notifier exit_notifier;
>> +static pixman_image_t *surface;
>> +static pixman_image_t *framebuffer;
>> +static pixman_transform_t transform;
>> +static pixman_region16_t dirty;
>>
>> /* fwd decls */
>> static int fbdev_activate_vt(int tty, int vtno, bool wait);
>>
>> /* -------------------------------------------------------------------- */
>> +/* pixman helpers */
>> +
>> +static int pixman_shifts_to_type(int rshift, int gshift, int bshift)
>> +{
>> + int type = PIXMAN_TYPE_OTHER;
>> +
>> + if (rshift > gshift && gshift > bshift) {
>> + if (bshift == 0) {
>> + type = PIXMAN_TYPE_ARGB;
>> + } else {
>> +#if PIXMAN_VERSION >= PIXMAN_VERSION_ENCODE(0, 21, 8)
>> + type = PIXMAN_TYPE_RGBA;
>> +#endif
>> + }
>> + } else if (rshift < gshift && gshift < bshift) {
>> + if (rshift == 0) {
>> + type = PIXMAN_TYPE_ABGR;
>> + } else {
>> + type = PIXMAN_TYPE_BGRA;
This breaks for me:
qemu-pixman.c: In function ‘qemu_pixman_get_type’:
qemu-pixman.c:24: error: ‘PIXMAN_TYPE_BGRA’ undeclared (first use in this function)
qemu-pixman.c:24: error: (Each undeclared identifier is reported only once
qemu-pixman.c:24: error: for each function it appears in.)
Alex
^ permalink raw reply [flat|nested] 29+ messages in thread
* Re: [Qemu-devel] [PATCH 7/9] fbdev: move to pixman
2012-11-26 18:42 ` Alexander Graf
@ 2012-11-26 20:01 ` Gerd Hoffmann
2012-11-26 20:05 ` Alexander Graf
0 siblings, 1 reply; 29+ messages in thread
From: Gerd Hoffmann @ 2012-11-26 20:01 UTC (permalink / raw)
To: Alexander Graf; +Cc: qemu-devel, Anthony Liguori
On 11/26/12 19:42, Alexander Graf wrote:
> Replying here because my INBOX doesn't contain the original message.
>
>>> +#if PIXMAN_VERSION >= PIXMAN_VERSION_ENCODE(0, 21, 8)
>>> + type = PIXMAN_TYPE_RGBA;
>>> +#endif
>>> + }
>>> + } else if (rshift < gshift && gshift < bshift) {
>>> + if (rshift == 0) {
>>> + type = PIXMAN_TYPE_ABGR;
>>> + } else {
>>> + type = PIXMAN_TYPE_BGRA;
>
> This breaks for me:
>
> qemu-pixman.c: In function ‘qemu_pixman_get_type’:
> qemu-pixman.c:24: error: ‘PIXMAN_TYPE_BGRA’ undeclared (first use in this function)
> qemu-pixman.c:24: error: (Each undeclared identifier is reported only once
> qemu-pixman.c:24: error: for each function it appears in.)
Which pixman version is this?
cheers,
Gerd
^ permalink raw reply [flat|nested] 29+ messages in thread
* Re: [Qemu-devel] [PATCH 7/9] fbdev: move to pixman
2012-11-26 20:01 ` Gerd Hoffmann
@ 2012-11-26 20:05 ` Alexander Graf
0 siblings, 0 replies; 29+ messages in thread
From: Alexander Graf @ 2012-11-26 20:05 UTC (permalink / raw)
To: Gerd Hoffmann; +Cc: qemu-devel, Anthony Liguori
On 26.11.2012, at 21:01, Gerd Hoffmann wrote:
> On 11/26/12 19:42, Alexander Graf wrote:
>> Replying here because my INBOX doesn't contain the original message.
>>
>>>> +#if PIXMAN_VERSION >= PIXMAN_VERSION_ENCODE(0, 21, 8)
>>>> + type = PIXMAN_TYPE_RGBA;
>>>> +#endif
>>>> + }
>>>> + } else if (rshift < gshift && gshift < bshift) {
>>>> + if (rshift == 0) {
>>>> + type = PIXMAN_TYPE_ABGR;
>>>> + } else {
>>>> + type = PIXMAN_TYPE_BGRA;
>>
>> This breaks for me:
>>
>> qemu-pixman.c: In function ‘qemu_pixman_get_type’:
>> qemu-pixman.c:24: error: ‘PIXMAN_TYPE_BGRA’ undeclared (first use in this function)
>> qemu-pixman.c:24: error: (Each undeclared identifier is reported only once
>> qemu-pixman.c:24: error: for each function it appears in.)
>
> Which pixman version is this?
#define PIXMAN_VERSION_STRING "0.12.0"
Alex
^ permalink raw reply [flat|nested] 29+ messages in thread
end of thread, other threads:[~2012-11-26 20:05 UTC | newest]
Thread overview: 29+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2012-09-18 7:17 [Qemu-devel] [PULL 0/9] linux framebuffer display driver Gerd Hoffmann
2012-09-18 7:17 ` [Qemu-devel] [PATCH 1/9] QLIST-ify display change listeners Gerd Hoffmann
2012-09-18 7:17 ` [Qemu-devel] [PATCH 2/9] add unregister_displaychangelistener Gerd Hoffmann
2012-09-18 10:54 ` Stefano Stabellini
2012-09-18 7:17 ` [Qemu-devel] [PATCH 3/9] move set_mouse + cursor_define callbacks Gerd Hoffmann
2012-09-18 14:10 ` Stefano Stabellini
2012-09-18 16:31 ` Gerd Hoffmann
2012-09-18 16:44 ` Stefano Stabellini
2012-09-18 7:17 ` [Qemu-devel] [PATCH 4/9] fbdev: add linux framebuffer display driver Gerd Hoffmann
2012-09-18 15:01 ` Stefano Stabellini
2012-09-19 5:19 ` Gerd Hoffmann
2012-09-19 18:37 ` Blue Swirl
2012-09-18 7:17 ` [Qemu-devel] [PATCH 5/9] fbdev: add monitor command to enable/disable Gerd Hoffmann
2012-09-18 12:47 ` Luiz Capitulino
2012-09-18 7:17 ` [Qemu-devel] [PATCH 6/9] fbdev: make configurable at compile time Gerd Hoffmann
2012-09-18 7:17 ` [Qemu-devel] [PATCH 7/9] fbdev: move to pixman Gerd Hoffmann
2012-09-18 15:01 ` Stefano Stabellini
2012-09-19 5:51 ` Gerd Hoffmann
2012-09-18 19:14 ` Anthony Liguori
2012-09-18 21:08 ` Anthony Liguori
2012-11-26 18:42 ` Alexander Graf
2012-11-26 20:01 ` Gerd Hoffmann
2012-11-26 20:05 ` Alexander Graf
2012-09-18 20:30 ` Søren Sandmann
2012-09-19 5:56 ` Gerd Hoffmann
2012-09-18 7:17 ` [Qemu-devel] [PATCH 8/9] fbdev: add mouse pointer support Gerd Hoffmann
2012-09-18 7:17 ` [Qemu-devel] [PATCH 9/9] fbdev: add display scaling support Gerd Hoffmann
2012-09-18 15:02 ` Stefano Stabellini
2012-09-19 5:52 ` Gerd Hoffmann
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).