ia64/xen-unstable

changeset 16232:54b72f14eb25

pv-qemu 5/10: Refactor QEMU console integration

This patch moves a bunch of code out of the xen_machine_pv.c file and
into the xenfb.c file. This is simply a re-factoring to facilitate the
two patches which follow.

Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
author Keir Fraser <keir@xensource.com>
date Thu Oct 25 14:39:33 2007 +0100 (2007-10-25)
parents 93938fee0bf5
children b760a4aa8dcf
files tools/ioemu/hw/xen_machine_pv.c tools/ioemu/hw/xenfb.c tools/ioemu/hw/xenfb.h
line diff
     1.1 --- a/tools/ioemu/hw/xen_machine_pv.c	Thu Oct 25 14:38:47 2007 +0100
     1.2 +++ b/tools/ioemu/hw/xen_machine_pv.c	Thu Oct 25 14:39:33 2007 +0100
     1.3 @@ -24,194 +24,6 @@
     1.4  
     1.5  #include "vl.h"
     1.6  #include "xenfb.h"
     1.7 -#include <linux/input.h>
     1.8 -
     1.9 -/*
    1.10 - * Tables to map from scancode to Linux input layer keycode.
    1.11 - * Scancodes are hardware-specific.  These maps assumes a 
    1.12 - * standard AT or PS/2 keyboard which is what QEMU feeds us.
    1.13 - */
    1.14 -static const unsigned char atkbd_set2_keycode[512] = {
    1.15 -
    1.16 -	  0, 67, 65, 63, 61, 59, 60, 88,  0, 68, 66, 64, 62, 15, 41,117,
    1.17 -	  0, 56, 42, 93, 29, 16,  2,  0,  0,  0, 44, 31, 30, 17,  3,  0,
    1.18 -	  0, 46, 45, 32, 18,  5,  4, 95,  0, 57, 47, 33, 20, 19,  6,183,
    1.19 -	  0, 49, 48, 35, 34, 21,  7,184,  0,  0, 50, 36, 22,  8,  9,185,
    1.20 -	  0, 51, 37, 23, 24, 11, 10,  0,  0, 52, 53, 38, 39, 25, 12,  0,
    1.21 -	  0, 89, 40,  0, 26, 13,  0,  0, 58, 54, 28, 27,  0, 43,  0, 85,
    1.22 -	  0, 86, 91, 90, 92,  0, 14, 94,  0, 79,124, 75, 71,121,  0,  0,
    1.23 -	 82, 83, 80, 76, 77, 72,  1, 69, 87, 78, 81, 74, 55, 73, 70, 99,
    1.24 -
    1.25 -	  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
    1.26 -	217,100,255,  0, 97,165,  0,  0,156,  0,  0,  0,  0,  0,  0,125,
    1.27 -	173,114,  0,113,  0,  0,  0,126,128,  0,  0,140,  0,  0,  0,127,
    1.28 -	159,  0,115,  0,164,  0,  0,116,158,  0,150,166,  0,  0,  0,142,
    1.29 -	157,  0,  0,  0,  0,  0,  0,  0,155,  0, 98,  0,  0,163,  0,  0,
    1.30 -	226,  0,  0,  0,  0,  0,  0,  0,  0,255, 96,  0,  0,  0,143,  0,
    1.31 -	  0,  0,  0,  0,  0,  0,  0,  0,  0,107,  0,105,102,  0,  0,112,
    1.32 -	110,111,108,112,106,103,  0,119,  0,118,109,  0, 99,104,119,  0,
    1.33 -
    1.34 -};
    1.35 -
    1.36 -static const unsigned char atkbd_unxlate_table[128] = {
    1.37 -
    1.38 -	  0,118, 22, 30, 38, 37, 46, 54, 61, 62, 70, 69, 78, 85,102, 13,
    1.39 -	 21, 29, 36, 45, 44, 53, 60, 67, 68, 77, 84, 91, 90, 20, 28, 27,
    1.40 -	 35, 43, 52, 51, 59, 66, 75, 76, 82, 14, 18, 93, 26, 34, 33, 42,
    1.41 -	 50, 49, 58, 65, 73, 74, 89,124, 17, 41, 88,  5,  6,  4, 12,  3,
    1.42 -	 11,  2, 10,  1,  9,119,126,108,117,125,123,107,115,116,121,105,
    1.43 -	114,122,112,113,127, 96, 97,120,  7, 15, 23, 31, 39, 47, 55, 63,
    1.44 -	 71, 79, 86, 94,  8, 16, 24, 32, 40, 48, 56, 64, 72, 80, 87,111,
    1.45 -	 19, 25, 57, 81, 83, 92, 95, 98, 99,100,101,103,104,106,109,110
    1.46 -
    1.47 -};
    1.48 -
    1.49 -static unsigned char scancode2linux[512];
    1.50 -
    1.51 -/* A convenient function for munging pixels between different depths */
    1.52 -#define BLT(SRC_T,DST_T,RLS,GLS,BLS,RRS,GRS,BRS,RM,GM,BM)               \
    1.53 -    for (line = y ; line < h ; line++) {                                \
    1.54 -        SRC_T *src = (SRC_T *)(xenfb->pixels                            \
    1.55 -                               + (line * xenfb->row_stride)             \
    1.56 -                               + (x * xenfb->depth / 8));               \
    1.57 -        DST_T *dst = (DST_T *)(ds->data                                 \
    1.58 -                               + (line * ds->linesize)                  \
    1.59 -                               + (x * ds->depth / 8));                  \
    1.60 -        int col;                                                        \
    1.61 -        for (col = x ; col < w ; col++) {                               \
    1.62 -            *dst = (((*src >> RRS) & RM) << RLS) |                      \
    1.63 -                (((*src >> GRS) & GM) << GLS) |                         \
    1.64 -                (((*src >> GRS) & BM) << BLS);                          \
    1.65 -            src++;                                                      \
    1.66 -            dst++;                                                      \
    1.67 -        }                                                               \
    1.68 -    }
    1.69 -
    1.70 -/* This copies data from the guest framebuffer region, into QEMU's copy
    1.71 - * NB. QEMU's copy is stored in the pixel format of a) the local X 
    1.72 - * server (SDL case) or b) the current VNC client pixel format.
    1.73 - */
    1.74 -static void xen_pvfb_guest_copy(struct xenfb *xenfb, int x, int y, int w, int h)
    1.75 -{
    1.76 -    DisplayState *ds = (DisplayState *)xenfb->user_data;
    1.77 -    int line;
    1.78 -
    1.79 -    if (xenfb->depth == ds->depth) { /* Perfect match can use fast path */
    1.80 -        for (line = y ; line < (y+h) ; line++) {
    1.81 -            memcpy(ds->data + (line * ds->linesize) + (x * ds->depth / 8),
    1.82 -                   xenfb->pixels + (line * xenfb->row_stride) + (x * xenfb->depth / 8),
    1.83 -                   w * xenfb->depth / 8);
    1.84 -        }
    1.85 -    } else { /* Mismatch requires slow pixel munging */
    1.86 -        if (xenfb->depth == 8) {
    1.87 -            /* 8 bit source == r:3 g:3 b:2 */
    1.88 -            if (ds->depth == 16) {
    1.89 -                BLT(uint8_t, uint16_t,   5, 2, 0,   11, 5, 0,   7, 7, 3);
    1.90 -            } else if (ds->depth == 32) {
    1.91 -                BLT(uint8_t, uint32_t,   5, 2, 0,   16, 8, 0,   7, 7, 3);
    1.92 -            }
    1.93 -        } else if (xenfb->depth == 16) {
    1.94 -            /* 16 bit source == r:5 g:6 b:5 */
    1.95 -            if (ds->depth == 8) {
    1.96 -                BLT(uint16_t, uint8_t,    11, 5, 0,   5, 2, 0,    31, 63, 31);
    1.97 -            } else if (ds->depth == 32) {
    1.98 -                BLT(uint16_t, uint32_t,   11, 5, 0,   16, 8, 0,   31, 63, 31);
    1.99 -            }
   1.100 -        } else if (xenfb->depth == 32) {
   1.101 -            /* 32 bit source == r:8 g:8 b:8 (padding:8) */
   1.102 -            if (ds->depth == 8) {
   1.103 -                BLT(uint32_t, uint8_t,    16, 8, 0,   5, 2, 0,    255, 255, 255);
   1.104 -            } else if (ds->depth == 16) {
   1.105 -                BLT(uint32_t, uint16_t,   16, 8, 0,   11, 5, 0,   255, 255, 255);
   1.106 -            }
   1.107 -        }
   1.108 -    }
   1.109 -    dpy_update(ds, x, y, w, h);
   1.110 -}
   1.111 -
   1.112 -/* 
   1.113 - * Send a key event from the client to the guest OS
   1.114 - * QEMU gives us a raw scancode from an AT / PS/2 style keyboard.
   1.115 - * We have to turn this into a Linux Input layer keycode.
   1.116 - * 
   1.117 - * Extra complexity from the fact that with extended scancodes 
   1.118 - * (like those produced by arrow keys) this method gets called
   1.119 - * twice, but we only want to send a single event. So we have to
   1.120 - * track the '0xe0' scancode state & collapse the extended keys
   1.121 - * as needed.
   1.122 - * 
   1.123 - * Wish we could just send scancodes straight to the guest which
   1.124 - * already has code for dealing with this...
   1.125 - */
   1.126 -static void xen_pvfb_key_event(void *opaque, int scancode)
   1.127 -{
   1.128 -    static int extended = 0;
   1.129 -    int down = 1;
   1.130 -    if (scancode == 0xe0) {
   1.131 -        extended = 1;
   1.132 -        return;
   1.133 -    } else if (scancode & 0x80) {
   1.134 -        scancode &= 0x7f;
   1.135 -        down = 0;
   1.136 -    }
   1.137 -    if (extended) {
   1.138 -        scancode |= 0x80;
   1.139 -        extended = 0;
   1.140 -    }
   1.141 -    xenfb_send_key(opaque, down, scancode2linux[scancode]);
   1.142 -}
   1.143 -
   1.144 -/*
   1.145 - * Send a mouse event from the client to the guest OS
   1.146 - * 
   1.147 - * The QEMU mouse can be in either relative, or absolute mode.
   1.148 - * Movement is sent separately from button state, which has to
   1.149 - * be encoded as virtual key events. We also don't actually get
   1.150 - * given any button up/down events, so have to track changes in
   1.151 - * the button state.
   1.152 - */
   1.153 -static void xen_pvfb_mouse_event(void *opaque,
   1.154 -                                 int dx, int dy, int dz, int button_state)
   1.155 -{
   1.156 -    static int old_state = 0;
   1.157 -    int i;
   1.158 -    struct xenfb *xenfb = opaque;
   1.159 -    DisplayState *ds = (DisplayState *)xenfb->user_data;
   1.160 -    if (xenfb->abs_pointer_wanted)
   1.161 -        xenfb_send_position(xenfb,
   1.162 -                            dx * ds->width / 0x7fff,
   1.163 -                            dy * ds->height / 0x7fff);
   1.164 -    else
   1.165 -        xenfb_send_motion(xenfb, dx, dy);
   1.166 -
   1.167 -	for (i = 0 ; i < 8 ; i++) {
   1.168 -		int lastDown = old_state & (1 << i);
   1.169 -		int down = button_state & (1 << i);
   1.170 -		if (down == lastDown)
   1.171 -			continue;
   1.172 -
   1.173 -		if (xenfb_send_key(xenfb, down, BTN_LEFT+i) < 0)
   1.174 -			return;
   1.175 -	}
   1.176 -    old_state = button_state;
   1.177 -}
   1.178 -
   1.179 -/* QEMU display state changed, so refresh the framebuffer copy */
   1.180 -/* XXX - can we optimize this, or the next func at all ? */ 
   1.181 -void xen_pvfb_update(void *opaque)
   1.182 -{
   1.183 -    struct xenfb *xenfb = opaque;
   1.184 -    xen_pvfb_guest_copy(xenfb, 0, 0, xenfb->width, xenfb->height);
   1.185 -}
   1.186 -
   1.187 -/* QEMU display state changed, so refresh the framebuffer copy */
   1.188 -void xen_pvfb_invalidate(void *opaque)
   1.189 -{
   1.190 -    xen_pvfb_update(opaque);
   1.191 -}
   1.192 -
   1.193 -/* Screen dump is not used in Xen, so no need to impl this ? */
   1.194 -void xen_pvfb_screen_dump(void *opaque, const char *name) { }
   1.195  
   1.196  /* The Xen PV machine currently provides
   1.197   *   - a virtual framebuffer
   1.198 @@ -226,14 +38,6 @@ static void xen_init_pv(uint64_t ram_siz
   1.199  {
   1.200      struct xenfb *xenfb;
   1.201      extern int domid;
   1.202 -    int i;
   1.203 -
   1.204 -    /* Prepare scancode mapping table */
   1.205 -	for (i = 0; i < 128; i++) {
   1.206 -		scancode2linux[i] = atkbd_set2_keycode[atkbd_unxlate_table[i]];
   1.207 -		scancode2linux[i | 0x80] = 
   1.208 -			atkbd_set2_keycode[atkbd_unxlate_table[i] | 0x80];
   1.209 -	}
   1.210  
   1.211      /* Prepare PVFB state */
   1.212      xenfb = xenfb_new();
   1.213 @@ -244,27 +48,11 @@ static void xen_init_pv(uint64_t ram_siz
   1.214      }
   1.215  
   1.216      /* Talk to the guest */
   1.217 -    if (xenfb_attach_dom(xenfb, domid) < 0) {
   1.218 +    if (xenfb_attach_dom(xenfb, domid, ds) < 0) {
   1.219          fprintf(stderr, "Could not connect to domain (%s)\n",
   1.220                  strerror(errno));
   1.221          exit(1);
   1.222      }
   1.223 -    xenfb->update = xen_pvfb_guest_copy;
   1.224 -    xenfb->user_data = ds;
   1.225 -
   1.226 -    /* Tell QEMU to allocate a graphical console */
   1.227 -    graphic_console_init(ds,
   1.228 -                         xen_pvfb_update,
   1.229 -                         xen_pvfb_invalidate,
   1.230 -                         xen_pvfb_screen_dump,
   1.231 -                         xenfb);
   1.232 -
   1.233 -    /* Register our keyboard & mouse handlers */
   1.234 -    qemu_add_kbd_event_handler(xen_pvfb_key_event, xenfb);
   1.235 -    qemu_add_mouse_event_handler(xen_pvfb_mouse_event, xenfb,
   1.236 -                                 xenfb->abs_pointer_wanted,
   1.237 -                                 "Xen PVFB Mouse");
   1.238 -
   1.239  
   1.240      /* Setup QEMU display */
   1.241      dpy_resize(ds, xenfb->width, xenfb->height);
     2.1 --- a/tools/ioemu/hw/xenfb.c	Thu Oct 25 14:38:47 2007 +0100
     2.2 +++ b/tools/ioemu/hw/xenfb.c	Thu Oct 25 14:39:33 2007 +0100
     2.3 @@ -16,8 +16,8 @@
     2.4  #include <string.h>
     2.5  #include <time.h>
     2.6  #include <xs.h>
     2.7 +#include <linux/input.h>
     2.8  
     2.9 -#include "vl.h"
    2.10  #include "xenfb.h"
    2.11  
    2.12  // FIXME defend against malicious frontend?
    2.13 @@ -43,6 +43,58 @@ struct xenfb_private {
    2.14  	char protocol[64];	/* frontend protocol */
    2.15  };
    2.16  
    2.17 +/* Functions which tie the PVFB into the QEMU device model */
    2.18 +static void xenfb_key_event(void *opaque, int keycode);
    2.19 +static void xenfb_mouse_event(void *opaque,
    2.20 +			      int dx, int dy, int dz, int button_state);
    2.21 +static void xenfb_guest_copy(struct xenfb *xenfb, int x, int y, int w, int h);
    2.22 +static void xenfb_update(void *opaque);
    2.23 +static void xenfb_invalidate(void *opaque);
    2.24 +static void xenfb_screen_dump(void *opaque, const char *name);
    2.25 +
    2.26 +/*
    2.27 + * Tables to map from scancode to Linux input layer keycode.
    2.28 + * Scancodes are hardware-specific.  These maps assumes a 
    2.29 + * standard AT or PS/2 keyboard which is what QEMU feeds us.
    2.30 + */
    2.31 +static const unsigned char atkbd_set2_keycode[512] = {
    2.32 +
    2.33 +	  0, 67, 65, 63, 61, 59, 60, 88,  0, 68, 66, 64, 62, 15, 41,117,
    2.34 +	  0, 56, 42, 93, 29, 16,  2,  0,  0,  0, 44, 31, 30, 17,  3,  0,
    2.35 +	  0, 46, 45, 32, 18,  5,  4, 95,  0, 57, 47, 33, 20, 19,  6,183,
    2.36 +	  0, 49, 48, 35, 34, 21,  7,184,  0,  0, 50, 36, 22,  8,  9,185,
    2.37 +	  0, 51, 37, 23, 24, 11, 10,  0,  0, 52, 53, 38, 39, 25, 12,  0,
    2.38 +	  0, 89, 40,  0, 26, 13,  0,  0, 58, 54, 28, 27,  0, 43,  0, 85,
    2.39 +	  0, 86, 91, 90, 92,  0, 14, 94,  0, 79,124, 75, 71,121,  0,  0,
    2.40 +	 82, 83, 80, 76, 77, 72,  1, 69, 87, 78, 81, 74, 55, 73, 70, 99,
    2.41 +
    2.42 +	  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
    2.43 +	217,100,255,  0, 97,165,  0,  0,156,  0,  0,  0,  0,  0,  0,125,
    2.44 +	173,114,  0,113,  0,  0,  0,126,128,  0,  0,140,  0,  0,  0,127,
    2.45 +	159,  0,115,  0,164,  0,  0,116,158,  0,150,166,  0,  0,  0,142,
    2.46 +	157,  0,  0,  0,  0,  0,  0,  0,155,  0, 98,  0,  0,163,  0,  0,
    2.47 +	226,  0,  0,  0,  0,  0,  0,  0,  0,255, 96,  0,  0,  0,143,  0,
    2.48 +	  0,  0,  0,  0,  0,  0,  0,  0,  0,107,  0,105,102,  0,  0,112,
    2.49 +	110,111,108,112,106,103,  0,119,  0,118,109,  0, 99,104,119,  0,
    2.50 +
    2.51 +};
    2.52 +
    2.53 +static const unsigned char atkbd_unxlate_table[128] = {
    2.54 +
    2.55 +	  0,118, 22, 30, 38, 37, 46, 54, 61, 62, 70, 69, 78, 85,102, 13,
    2.56 +	 21, 29, 36, 45, 44, 53, 60, 67, 68, 77, 84, 91, 90, 20, 28, 27,
    2.57 +	 35, 43, 52, 51, 59, 66, 75, 76, 82, 14, 18, 93, 26, 34, 33, 42,
    2.58 +	 50, 49, 58, 65, 73, 74, 89,124, 17, 41, 88,  5,  6,  4, 12,  3,
    2.59 +	 11,  2, 10,  1,  9,119,126,108,117,125,123,107,115,116,121,105,
    2.60 +	114,122,112,113,127, 96, 97,120,  7, 15, 23, 31, 39, 47, 55, 63,
    2.61 +	 71, 79, 86, 94,  8, 16, 24, 32, 40, 48, 56, 64, 72, 80, 87,111,
    2.62 +	 19, 25, 57, 81, 83, 92, 95, 98, 99,100,101,103,104,106,109,110
    2.63 +
    2.64 +};
    2.65 +
    2.66 +static unsigned char scancode2linux[512];
    2.67 +
    2.68 +
    2.69  static void xenfb_detach_dom(struct xenfb_private *);
    2.70  
    2.71  static char *xenfb_path_in_dom(struct xs_handle *xsh,
    2.72 @@ -158,10 +210,18 @@ struct xenfb *xenfb_new(void)
    2.73  {
    2.74  	struct xenfb_private *xenfb = malloc(sizeof(*xenfb));
    2.75  	int serrno;
    2.76 +	int i;
    2.77  
    2.78  	if (xenfb == NULL)
    2.79  		return NULL;
    2.80  
    2.81 +	/* Prepare scancode mapping table */
    2.82 +	for (i = 0; i < 128; i++) {
    2.83 +		scancode2linux[i] = atkbd_set2_keycode[atkbd_unxlate_table[i]];
    2.84 +		scancode2linux[i | 0x80] = 
    2.85 +			atkbd_set2_keycode[atkbd_unxlate_table[i] | 0x80];
    2.86 +	}
    2.87 +
    2.88  	memset(xenfb, 0, sizeof(*xenfb));
    2.89  	xenfb->evt_xch = xenfb->xc = -1;
    2.90  	xenfb_device_init(&xenfb->fb, "vfb", xenfb);
    2.91 @@ -580,6 +640,68 @@ static int xenfb_on_state_change(struct 
    2.92  	return 0;
    2.93  }
    2.94  
    2.95 +static int xenfb_kbd_event(struct xenfb_private *xenfb,
    2.96 +			   union xenkbd_in_event *event)
    2.97 +{
    2.98 +	uint32_t prod;
    2.99 +	struct xenkbd_page *page = xenfb->kbd.page;
   2.100 +
   2.101 +	if (xenfb->kbd.state != XenbusStateConnected)
   2.102 +		return 0;
   2.103 +
   2.104 +	prod = page->in_prod;
   2.105 +	if (prod - page->in_cons == XENKBD_IN_RING_LEN) {
   2.106 +		errno = EAGAIN;
   2.107 +		return -1;
   2.108 +	}
   2.109 +
   2.110 +	mb();			/* ensure ring space available */
   2.111 +	XENKBD_IN_RING_REF(page, prod) = *event;
   2.112 +	wmb();			/* ensure ring contents visible */
   2.113 +	page->in_prod = prod + 1;
   2.114 +	return xc_evtchn_notify(xenfb->evt_xch, xenfb->kbd.port);
   2.115 +}
   2.116 +
   2.117 +static int xenfb_send_key(struct xenfb *xenfb_pub, bool down, int keycode)
   2.118 +{
   2.119 +	struct xenfb_private *xenfb = (struct xenfb_private *)xenfb_pub;
   2.120 +	union xenkbd_in_event event;
   2.121 +
   2.122 +	memset(&event, 0, XENKBD_IN_EVENT_SIZE);
   2.123 +	event.type = XENKBD_TYPE_KEY;
   2.124 +	event.key.pressed = down ? 1 : 0;
   2.125 +	event.key.keycode = keycode;
   2.126 +
   2.127 +	return xenfb_kbd_event(xenfb, &event);
   2.128 +}
   2.129 +
   2.130 +static int xenfb_send_motion(struct xenfb *xenfb_pub, int rel_x, int rel_y)
   2.131 +{
   2.132 +	struct xenfb_private *xenfb = (struct xenfb_private *)xenfb_pub;
   2.133 +	union xenkbd_in_event event;
   2.134 +
   2.135 +	memset(&event, 0, XENKBD_IN_EVENT_SIZE);
   2.136 +	event.type = XENKBD_TYPE_MOTION;
   2.137 +	event.motion.rel_x = rel_x;
   2.138 +	event.motion.rel_y = rel_y;
   2.139 +
   2.140 +	return xenfb_kbd_event(xenfb, &event);
   2.141 +}
   2.142 +
   2.143 +static int xenfb_send_position(struct xenfb *xenfb_pub, int abs_x, int abs_y)
   2.144 +{
   2.145 +	struct xenfb_private *xenfb = (struct xenfb_private *)xenfb_pub;
   2.146 +	union xenkbd_in_event event;
   2.147 +
   2.148 +	memset(&event, 0, XENKBD_IN_EVENT_SIZE);
   2.149 +	event.type = XENKBD_TYPE_POS;
   2.150 +	event.pos.abs_x = abs_x;
   2.151 +	event.pos.abs_y = abs_y;
   2.152 +
   2.153 +	return xenfb_kbd_event(xenfb, &event);
   2.154 +}
   2.155 +
   2.156 +
   2.157  static void xenfb_dispatch_channel(void *xenfb_pub)
   2.158  {
   2.159  	struct xenfb_private *xenfb = (struct xenfb_private *)xenfb_pub;
   2.160 @@ -614,7 +736,7 @@ static void xenfb_dispatch_store(void *x
   2.161  }
   2.162  
   2.163  
   2.164 -int xenfb_attach_dom(struct xenfb *xenfb_pub, int domid)
   2.165 +int xenfb_attach_dom(struct xenfb *xenfb_pub, int domid, DisplayState *ds)
   2.166  {
   2.167  	struct xenfb_private *xenfb = (struct xenfb_private *)xenfb_pub;
   2.168  	struct xs_handle *xsh = xenfb->xsh;
   2.169 @@ -702,6 +824,23 @@ int xenfb_attach_dom(struct xenfb *xenfb
   2.170  	if (qemu_set_fd_handler2(xc_evtchn_fd(xenfb->evt_xch), NULL, xenfb_dispatch_channel, NULL, xenfb) < 0)
   2.171  		goto error;
   2.172  
   2.173 +	/* Register our keyboard & mouse handlers */
   2.174 +	qemu_add_kbd_event_handler(xenfb_key_event, xenfb);
   2.175 +	qemu_add_mouse_event_handler(xenfb_mouse_event, xenfb,
   2.176 +				     xenfb_pub->abs_pointer_wanted,
   2.177 +				     "Xen PVFB Mouse");
   2.178 +
   2.179 +	xenfb_pub->update = xenfb_guest_copy;
   2.180 +	xenfb_pub->user_data = ds;
   2.181 +
   2.182 +	/* Tell QEMU to allocate a graphical console */
   2.183 +	graphic_console_init(ds,
   2.184 +			     xenfb_update,
   2.185 +			     xenfb_invalidate,
   2.186 +			     xenfb_screen_dump,
   2.187 +			     xenfb_pub);
   2.188 +	dpy_resize(ds, xenfb_pub->width, xenfb_pub->height);
   2.189 +
   2.190  	return 0;
   2.191  
   2.192   error:
   2.193 @@ -713,66 +852,154 @@ int xenfb_attach_dom(struct xenfb *xenfb
   2.194          return -1;
   2.195  }
   2.196  
   2.197 -static int xenfb_kbd_event(struct xenfb_private *xenfb,
   2.198 -			   union xenkbd_in_event *event)
   2.199 +/* 
   2.200 + * Send a key event from the client to the guest OS
   2.201 + * QEMU gives us a raw scancode from an AT / PS/2 style keyboard.
   2.202 + * We have to turn this into a Linux Input layer keycode.
   2.203 + * 
   2.204 + * Extra complexity from the fact that with extended scancodes 
   2.205 + * (like those produced by arrow keys) this method gets called
   2.206 + * twice, but we only want to send a single event. So we have to
   2.207 + * track the '0xe0' scancode state & collapse the extended keys
   2.208 + * as needed.
   2.209 + * 
   2.210 + * Wish we could just send scancodes straight to the guest which
   2.211 + * already has code for dealing with this...
   2.212 + */
   2.213 +static void xenfb_key_event(void *opaque, int scancode)
   2.214  {
   2.215 -	uint32_t prod;
   2.216 -	struct xenkbd_page *page = xenfb->kbd.page;
   2.217 -
   2.218 -	if (xenfb->kbd.state != XenbusStateConnected)
   2.219 -		return 0;
   2.220 +    static int extended = 0;
   2.221 +    int down = 1;
   2.222 +    if (scancode == 0xe0) {
   2.223 +        extended = 1;
   2.224 +        return;
   2.225 +    } else if (scancode & 0x80) {
   2.226 +        scancode &= 0x7f;
   2.227 +        down = 0;
   2.228 +    }
   2.229 +    if (extended) {
   2.230 +        scancode |= 0x80;
   2.231 +        extended = 0;
   2.232 +    }
   2.233 +    xenfb_send_key(opaque, down, scancode2linux[scancode]);
   2.234 +}
   2.235  
   2.236 -	prod = page->in_prod;
   2.237 -	if (prod - page->in_cons == XENKBD_IN_RING_LEN) {
   2.238 -		errno = EAGAIN;
   2.239 -		return -1;
   2.240 -	}
   2.241 +/*
   2.242 + * Send a mouse event from the client to the guest OS
   2.243 + * 
   2.244 + * The QEMU mouse can be in either relative, or absolute mode.
   2.245 + * Movement is sent separately from button state, which has to
   2.246 + * be encoded as virtual key events. We also don't actually get
   2.247 + * given any button up/down events, so have to track changes in
   2.248 + * the button state.
   2.249 + */
   2.250 +static void xenfb_mouse_event(void *opaque,
   2.251 +			      int dx, int dy, int dz, int button_state)
   2.252 +{
   2.253 +    int i;
   2.254 +    struct xenfb *xenfb = opaque;
   2.255 +    DisplayState *ds = (DisplayState *)xenfb->user_data;
   2.256 +    if (xenfb->abs_pointer_wanted)
   2.257 +	    xenfb_send_position(xenfb,
   2.258 +				dx * ds->width / 0x7fff,
   2.259 +				dy * ds->height / 0x7fff);
   2.260 +    else
   2.261 +	    xenfb_send_motion(xenfb, dx, dy);
   2.262  
   2.263 -	mb();			/* ensure ring space available */
   2.264 -	XENKBD_IN_RING_REF(page, prod) = *event;
   2.265 -	wmb();			/* ensure ring contents visible */
   2.266 -	page->in_prod = prod + 1;
   2.267 -	return xc_evtchn_notify(xenfb->evt_xch, xenfb->kbd.port);
   2.268 +    for (i = 0 ; i < 8 ; i++) {
   2.269 +	    int lastDown = xenfb->button_state & (1 << i);
   2.270 +	    int down = button_state & (1 << i);
   2.271 +	    if (down == lastDown)
   2.272 +		    continue;
   2.273 +
   2.274 +	    if (xenfb_send_key(xenfb, down, BTN_LEFT+i) < 0)
   2.275 +		    return;
   2.276 +    }
   2.277 +    xenfb->button_state = button_state;
   2.278  }
   2.279  
   2.280 -int xenfb_send_key(struct xenfb *xenfb_pub, bool down, int keycode)
   2.281 +/* A convenient function for munging pixels between different depths */
   2.282 +#define BLT(SRC_T,DST_T,RLS,GLS,BLS,RRS,GRS,BRS,RM,GM,BM)               \
   2.283 +    for (line = y ; line < h ; line++) {                                \
   2.284 +        SRC_T *src = (SRC_T *)(xenfb->pixels                            \
   2.285 +                               + (line * xenfb->row_stride)             \
   2.286 +                               + (x * xenfb->depth / 8));               \
   2.287 +        DST_T *dst = (DST_T *)(ds->data                                 \
   2.288 +                               + (line * ds->linesize)                  \
   2.289 +                               + (x * ds->depth / 8));                  \
   2.290 +        int col;                                                        \
   2.291 +        for (col = x ; col < w ; col++) {                               \
   2.292 +            *dst = (((*src >> RRS) & RM) << RLS) |                      \
   2.293 +                (((*src >> GRS) & GM) << GLS) |                         \
   2.294 +                (((*src >> GRS) & BM) << BLS);                          \
   2.295 +            src++;                                                      \
   2.296 +            dst++;                                                      \
   2.297 +        }                                                               \
   2.298 +    }
   2.299 +
   2.300 +
   2.301 +/* This copies data from the guest framebuffer region, into QEMU's copy
   2.302 + * NB. QEMU's copy is stored in the pixel format of a) the local X 
   2.303 + * server (SDL case) or b) the current VNC client pixel format.
   2.304 + * When shifting between colour depths we preserve the MSB.
   2.305 + */
   2.306 +static void xenfb_guest_copy(struct xenfb *xenfb, int x, int y, int w, int h)
   2.307  {
   2.308 -	struct xenfb_private *xenfb = (struct xenfb_private *)xenfb_pub;
   2.309 -	union xenkbd_in_event event;
   2.310 +    DisplayState *ds = (DisplayState *)xenfb->user_data;
   2.311 +    int line;
   2.312  
   2.313 -	memset(&event, 0, XENKBD_IN_EVENT_SIZE);
   2.314 -	event.type = XENKBD_TYPE_KEY;
   2.315 -	event.key.pressed = down ? 1 : 0;
   2.316 -	event.key.keycode = keycode;
   2.317 -
   2.318 -	return xenfb_kbd_event(xenfb, &event);
   2.319 +    if (xenfb->depth == ds->depth) { /* Perfect match can use fast path */
   2.320 +        for (line = y ; line < (y+h) ; line++) {
   2.321 +            memcpy(ds->data + (line * ds->linesize) + (x * ds->depth / 8),
   2.322 +                   xenfb->pixels + (line * xenfb->row_stride) + (x * xenfb->depth / 8),
   2.323 +                   w * xenfb->depth / 8);
   2.324 +        }
   2.325 +    } else { /* Mismatch requires slow pixel munging */
   2.326 +        if (xenfb->depth == 8) {
   2.327 +            /* 8 bit source == r:3 g:3 b:2 */
   2.328 +            if (ds->depth == 16) {
   2.329 +                BLT(uint8_t, uint16_t,   5, 2, 0,   11, 5, 0,   7, 7, 3);
   2.330 +            } else if (ds->depth == 32) {
   2.331 +                BLT(uint8_t, uint32_t,   5, 2, 0,   16, 8, 0,   7, 7, 3);
   2.332 +            }
   2.333 +        } else if (xenfb->depth == 16) {
   2.334 +            /* 16 bit source == r:5 g:6 b:5 */
   2.335 +            if (ds->depth == 8) {
   2.336 +                BLT(uint16_t, uint8_t,    11, 5, 0,   5, 2, 0,    31, 63, 31);
   2.337 +            } else if (ds->depth == 32) {
   2.338 +                BLT(uint16_t, uint32_t,   11, 5, 0,   16, 8, 0,   31, 63, 31);
   2.339 +            }
   2.340 +        } else if (xenfb->depth == 32) {
   2.341 +            /* 32 bit source == r:8 g:8 b:8 (padding:8) */
   2.342 +            if (ds->depth == 8) {
   2.343 +                BLT(uint32_t, uint8_t,    16, 8, 0,   5, 2, 0,    255, 255, 255);
   2.344 +            } else if (ds->depth == 16) {
   2.345 +                BLT(uint32_t, uint16_t,   16, 8, 0,   11, 5, 0,   255, 255, 255);
   2.346 +            }
   2.347 +        }
   2.348 +    }
   2.349 +    dpy_update(ds, x, y, w, h);
   2.350  }
   2.351  
   2.352 -int xenfb_send_motion(struct xenfb *xenfb_pub, int rel_x, int rel_y)
   2.353 +/* QEMU display state changed, so refresh the framebuffer copy */
   2.354 +/* XXX - can we optimize this, or the next func at all ? */ 
   2.355 +static void xenfb_update(void *opaque)
   2.356  {
   2.357 -	struct xenfb_private *xenfb = (struct xenfb_private *)xenfb_pub;
   2.358 -	union xenkbd_in_event event;
   2.359 -
   2.360 -	memset(&event, 0, XENKBD_IN_EVENT_SIZE);
   2.361 -	event.type = XENKBD_TYPE_MOTION;
   2.362 -	event.motion.rel_x = rel_x;
   2.363 -	event.motion.rel_y = rel_y;
   2.364 -
   2.365 -	return xenfb_kbd_event(xenfb, &event);
   2.366 +    struct xenfb *xenfb = opaque;
   2.367 +    xenfb_guest_copy(xenfb, 0, 0, xenfb->width, xenfb->height);
   2.368  }
   2.369  
   2.370 -int xenfb_send_position(struct xenfb *xenfb_pub, int abs_x, int abs_y)
   2.371 +/* QEMU display state changed, so refresh the framebuffer copy */
   2.372 +static void xenfb_invalidate(void *opaque)
   2.373  {
   2.374 -	struct xenfb_private *xenfb = (struct xenfb_private *)xenfb_pub;
   2.375 -	union xenkbd_in_event event;
   2.376 +    struct xenfb *xenfb = opaque;
   2.377 +    xenfb_guest_copy(xenfb, 0, 0, xenfb->width, xenfb->height);
   2.378 +}
   2.379  
   2.380 -	memset(&event, 0, XENKBD_IN_EVENT_SIZE);
   2.381 -	event.type = XENKBD_TYPE_POS;
   2.382 -	event.pos.abs_x = abs_x;
   2.383 -	event.pos.abs_y = abs_y;
   2.384 +/* Screen dump is not used in Xen, so no need to impl this....yet */
   2.385 +static void xenfb_screen_dump(void *opaque, const char *name) { }
   2.386  
   2.387 -	return xenfb_kbd_event(xenfb, &event);
   2.388 -}
   2.389 +
   2.390  /*
   2.391   * Local variables:
   2.392   *  c-indent-level: 8
     3.1 --- a/tools/ioemu/hw/xenfb.h	Thu Oct 25 14:38:47 2007 +0100
     3.2 +++ b/tools/ioemu/hw/xenfb.h	Thu Oct 25 14:39:33 2007 +0100
     3.3 @@ -1,6 +1,7 @@
     3.4  #ifndef _XENFB_H_
     3.5  #define _XENFB_H_
     3.6  
     3.7 +#include "vl.h"
     3.8  #include <stdbool.h>
     3.9  #include <sys/types.h>
    3.10  
    3.11 @@ -13,6 +14,7 @@ struct xenfb
    3.12  	int width;
    3.13  	int height;
    3.14  	int abs_pointer_wanted;
    3.15 +	int button_state;
    3.16  
    3.17  	void *user_data;
    3.18  
    3.19 @@ -23,10 +25,6 @@ struct xenfb *xenfb_new(void);
    3.20  void xenfb_delete(struct xenfb *xenfb);
    3.21  void xenfb_teardown(struct xenfb *xenfb);
    3.22  
    3.23 -int xenfb_attach_dom(struct xenfb *xenfb, int domid);
    3.24 -
    3.25 -int xenfb_send_key(struct xenfb *xenfb, bool down, int keycode);
    3.26 -int xenfb_send_motion(struct xenfb *xenfb, int rel_x, int rel_y);
    3.27 -int xenfb_send_position(struct xenfb *xenfb, int abs_x, int abs_y);
    3.28 +int xenfb_attach_dom(struct xenfb *xenfb, int domid, DisplayState *ds);
    3.29  
    3.30  #endif