[Top][All Lists]
[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
Re: [Qemu-devel] [PATCH 3/4] fbdev: add linux framebuffer display driver
From: |
Markus Armbruster |
Subject: |
Re: [Qemu-devel] [PATCH 3/4] fbdev: add linux framebuffer display driver. |
Date: |
Tue, 11 Sep 2012 13:10:04 +0200 |
User-agent: |
Gnus/5.13 (Gnus v5.13) Emacs/24.1 (gnu/linux) |
Gerd Hoffmann <address@hidden> writes:
> 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 enougth to type monitor commands. Not goot enougth to
> work seriously on a serial terminal. But the qemu terminal emulation
> isn't good enougth for that anyway ;)
s/enougth/enough/g
>
> 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 <address@hidden>
> ---
> console.h | 4 +
> qemu-options.hx | 8 +
> sysemu.h | 1 +
> trace-events | 14 +
> ui/Makefile.objs | 1 +
> ui/fbdev.c | 953
> +++++++++++++++++++++++++++++++++++++++++++++++++++
> ui/linux-keynames.h | 388 +++++++++++++++++++++
> vl.c | 12 +
> 8 files changed, 1381 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 ddf3a3b..9d1fe72 100644
> --- a/console.h
> +++ b/console.h
> @@ -384,6 +384,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 3c411c4..b02dcbb 100644
> --- a/qemu-options.hx
> +++ b/qemu-options.hx
> @@ -923,6 +923,14 @@ Enable/disable audio stream compression (using celt
> 0.5.1). Default is on.
> @end table
> ETEXI
>
> +DEF("fbdev", 0, QEMU_OPTION_fbdev,
> + "-fbdev enable fbdev\n", QEMU_ARCH_ALL)
> +STEXI
> address@hidden -fbdev
> address@hidden -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 04b0723..3745db3 100644
> --- a/trace-events
> +++ b/trace-events
> @@ -978,3 +978,17 @@ 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)
> \ No newline at end of file
Please supply the newline.
> 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..32c0a3b
> --- /dev/null
> +++ b/ui/fbdev.c
> @@ -0,0 +1,953 @@
> +/*
> + * linux fbdev output driver.
> + *
> + * Author: Gerd Hoffmann <address@hidden>
> + *
> + * This work is licensed under the terms of the GNU GPL, version 2. 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 (-1 == mice) {
I'd prefer mice == -1. More of the same below.
> + return -1;
> + }
> + qemu_set_fd_handler(mice, read_mouse, NULL, NULL);
> + return 0;
> +}
> +
> +static void uninit_mouse(void)
> +{
> + if (-1 == mice) {
> + return;
> + }
> + qemu_set_fd_handler(mice, NULL, NULL, NULL);
> + close(mice);
> + mice = -1;
> +}
> +
> +/* -------------------------------------------------------------------- */
> +/* keyboard */
> +
> +static const char *keynames[] = {
> +#include "linux-keynames.h"
> +};
> +
> +static 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
Add a comment to explain what exactly needs fixing?
> + [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 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)
> +{
> + 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 signal)
> +{
> + fbdev_cleanup();
> + abort();
> +}
> +
> +static void fbdev_catch_exit_signals(void)
> +{
> + struct sigaction act, old;
> +
> + memset(&act, 0, sizeof(act));
> + act.sa_handler = fbdev_catch_fatal_signal;
> + sigemptyset(&act.sa_mask);
> + sigaction(SIGSEGV, &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_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_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);
Unlike the other display types, DT_FBDEV doesn't have its own
CONFIG_FBDEV, but uses CONFIG_LINUX instead.
configure --disable-fbdev would be nice.
- [Qemu-devel] [PATCH 0/4] linux framebuffer display driver, Gerd Hoffmann, 2012/09/10
- [Qemu-devel] [PATCH 4/4] fbdev: add monitor command to enable/disable, Gerd Hoffmann, 2012/09/10
- [Qemu-devel] [PATCH 1/4] QLIST-ify display change listeners., Gerd Hoffmann, 2012/09/10
- [Qemu-devel] [PATCH 2/4] add unregister_displaychangelistener, Gerd Hoffmann, 2012/09/10
- [Qemu-devel] [PATCH 3/4] fbdev: add linux framebuffer display driver., Gerd Hoffmann, 2012/09/10
- Re: [Qemu-devel] [PATCH 0/4] linux framebuffer display driver, Alon Levy, 2012/09/11