Statistics
| Branch: | Revision:

root / hw / xenfb.c @ d9f75a4e

History | View | Annotate | Download (30.1 kB)

1 e7151f83 aliguori
/*
2 e7151f83 aliguori
 *  xen paravirt framebuffer backend
3 e7151f83 aliguori
 *
4 e7151f83 aliguori
 *  Copyright IBM, Corp. 2005-2006
5 e7151f83 aliguori
 *  Copyright Red Hat, Inc. 2006-2008
6 e7151f83 aliguori
 *
7 e7151f83 aliguori
 *  Authors:
8 e7151f83 aliguori
 *       Anthony Liguori <aliguori@us.ibm.com>,
9 e7151f83 aliguori
 *       Markus Armbruster <armbru@redhat.com>,
10 e7151f83 aliguori
 *       Daniel P. Berrange <berrange@redhat.com>,
11 e7151f83 aliguori
 *       Pat Campbell <plc@novell.com>,
12 e7151f83 aliguori
 *       Gerd Hoffmann <kraxel@redhat.com>
13 e7151f83 aliguori
 *
14 e7151f83 aliguori
 *  This program is free software; you can redistribute it and/or modify
15 e7151f83 aliguori
 *  it under the terms of the GNU General Public License as published by
16 e7151f83 aliguori
 *  the Free Software Foundation; under version 2 of the License.
17 e7151f83 aliguori
 *
18 e7151f83 aliguori
 *  This program is distributed in the hope that it will be useful,
19 e7151f83 aliguori
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
20 e7151f83 aliguori
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
21 e7151f83 aliguori
 *  GNU General Public License for more details.
22 e7151f83 aliguori
 *
23 e7151f83 aliguori
 *  You should have received a copy of the GNU General Public License along
24 e7151f83 aliguori
 *  with this program; if not, write to the Free Software Foundation, Inc.,
25 e7151f83 aliguori
 *  51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
26 e7151f83 aliguori
 */
27 e7151f83 aliguori
28 e7151f83 aliguori
#include <stdarg.h>
29 e7151f83 aliguori
#include <stdlib.h>
30 e7151f83 aliguori
#include <sys/types.h>
31 e7151f83 aliguori
#include <fcntl.h>
32 e7151f83 aliguori
#include <unistd.h>
33 e7151f83 aliguori
#include <stdbool.h>
34 e7151f83 aliguori
#include <sys/mman.h>
35 e7151f83 aliguori
#include <errno.h>
36 e7151f83 aliguori
#include <stdio.h>
37 e7151f83 aliguori
#include <string.h>
38 e7151f83 aliguori
#include <time.h>
39 e7151f83 aliguori
40 e7151f83 aliguori
#include <xs.h>
41 e7151f83 aliguori
#include <xenctrl.h>
42 e7151f83 aliguori
#include <xen/event_channel.h>
43 e7151f83 aliguori
#include <xen/io/xenbus.h>
44 e7151f83 aliguori
#include <xen/io/fbif.h>
45 e7151f83 aliguori
#include <xen/io/kbdif.h>
46 e7151f83 aliguori
#include <xen/io/protocols.h>
47 e7151f83 aliguori
48 e7151f83 aliguori
#include "hw.h"
49 e7151f83 aliguori
#include "sysemu.h"
50 e7151f83 aliguori
#include "console.h"
51 e7151f83 aliguori
#include "qemu-char.h"
52 e7151f83 aliguori
#include "xen_backend.h"
53 e7151f83 aliguori
54 e7151f83 aliguori
#ifndef BTN_LEFT
55 e7151f83 aliguori
#define BTN_LEFT 0x110 /* from <linux/input.h> */
56 e7151f83 aliguori
#endif
57 e7151f83 aliguori
58 e7151f83 aliguori
/* -------------------------------------------------------------------- */
59 e7151f83 aliguori
60 e7151f83 aliguori
struct common {
61 e7151f83 aliguori
    struct XenDevice  xendev;  /* must be first */
62 e7151f83 aliguori
    void              *page;
63 e7151f83 aliguori
    DisplayState      *ds;
64 e7151f83 aliguori
};
65 e7151f83 aliguori
66 e7151f83 aliguori
struct XenInput {
67 e7151f83 aliguori
    struct common c;
68 e7151f83 aliguori
    int abs_pointer_wanted; /* Whether guest supports absolute pointer */
69 e7151f83 aliguori
    int button_state;       /* Last seen pointer button state */
70 e7151f83 aliguori
    int extended;
71 e7151f83 aliguori
    QEMUPutMouseEntry *qmouse;
72 e7151f83 aliguori
};
73 e7151f83 aliguori
74 e7151f83 aliguori
#define UP_QUEUE 8
75 e7151f83 aliguori
76 e7151f83 aliguori
struct XenFB {
77 e7151f83 aliguori
    struct common     c;
78 e7151f83 aliguori
    size_t            fb_len;
79 e7151f83 aliguori
    int               row_stride;
80 e7151f83 aliguori
    int               depth;
81 e7151f83 aliguori
    int               width;
82 e7151f83 aliguori
    int               height;
83 e7151f83 aliguori
    int               offset;
84 e7151f83 aliguori
    void              *pixels;
85 e7151f83 aliguori
    int               fbpages;
86 e7151f83 aliguori
    int               feature_update;
87 e7151f83 aliguori
    int               refresh_period;
88 e7151f83 aliguori
    int               bug_trigger;
89 e7151f83 aliguori
    int               have_console;
90 e7151f83 aliguori
    int               do_resize;
91 e7151f83 aliguori
92 e7151f83 aliguori
    struct {
93 e7151f83 aliguori
        int x,y,w,h;
94 e7151f83 aliguori
    } up_rects[UP_QUEUE];
95 e7151f83 aliguori
    int               up_count;
96 e7151f83 aliguori
    int               up_fullscreen;
97 e7151f83 aliguori
};
98 e7151f83 aliguori
99 e7151f83 aliguori
/* -------------------------------------------------------------------- */
100 e7151f83 aliguori
101 e7151f83 aliguori
static int common_bind(struct common *c)
102 e7151f83 aliguori
{
103 e7151f83 aliguori
    int mfn;
104 e7151f83 aliguori
105 e7151f83 aliguori
    if (xenstore_read_fe_int(&c->xendev, "page-ref", &mfn) == -1)
106 e7151f83 aliguori
        return -1;
107 e7151f83 aliguori
    if (xenstore_read_fe_int(&c->xendev, "event-channel", &c->xendev.remote_port) == -1)
108 e7151f83 aliguori
        return -1;
109 e7151f83 aliguori
110 e7151f83 aliguori
    c->page = xc_map_foreign_range(xen_xc, c->xendev.dom,
111 e7151f83 aliguori
                                   XC_PAGE_SIZE,
112 e7151f83 aliguori
                                   PROT_READ | PROT_WRITE, mfn);
113 e7151f83 aliguori
    if (c->page == NULL)
114 e7151f83 aliguori
        return -1;
115 e7151f83 aliguori
116 e7151f83 aliguori
    xen_be_bind_evtchn(&c->xendev);
117 e7151f83 aliguori
    xen_be_printf(&c->xendev, 1, "ring mfn %d, remote-port %d, local-port %d\n",
118 e7151f83 aliguori
                  mfn, c->xendev.remote_port, c->xendev.local_port);
119 e7151f83 aliguori
120 e7151f83 aliguori
    return 0;
121 e7151f83 aliguori
}
122 e7151f83 aliguori
123 e7151f83 aliguori
static void common_unbind(struct common *c)
124 e7151f83 aliguori
{
125 e7151f83 aliguori
    xen_be_unbind_evtchn(&c->xendev);
126 e7151f83 aliguori
    if (c->page) {
127 e7151f83 aliguori
        munmap(c->page, XC_PAGE_SIZE);
128 e7151f83 aliguori
        c->page = NULL;
129 e7151f83 aliguori
    }
130 e7151f83 aliguori
}
131 e7151f83 aliguori
132 e7151f83 aliguori
/* -------------------------------------------------------------------- */
133 e7151f83 aliguori
134 e7151f83 aliguori
#if 0
135 e7151f83 aliguori
/*
136 e7151f83 aliguori
 * These two tables are not needed any more, but left in here
137 e7151f83 aliguori
 * intentionally as documentation, to show how scancode2linux[]
138 e7151f83 aliguori
 * was generated.
139 e7151f83 aliguori
 *
140 e7151f83 aliguori
 * Tables to map from scancode to Linux input layer keycode.
141 e7151f83 aliguori
 * Scancodes are hardware-specific.  These maps assumes a
142 e7151f83 aliguori
 * standard AT or PS/2 keyboard which is what QEMU feeds us.
143 e7151f83 aliguori
 */
144 e7151f83 aliguori
const unsigned char atkbd_set2_keycode[512] = {
145 e7151f83 aliguori

146 e7151f83 aliguori
     0, 67, 65, 63, 61, 59, 60, 88,  0, 68, 66, 64, 62, 15, 41,117,
147 e7151f83 aliguori
     0, 56, 42, 93, 29, 16,  2,  0,  0,  0, 44, 31, 30, 17,  3,  0,
148 e7151f83 aliguori
     0, 46, 45, 32, 18,  5,  4, 95,  0, 57, 47, 33, 20, 19,  6,183,
149 e7151f83 aliguori
     0, 49, 48, 35, 34, 21,  7,184,  0,  0, 50, 36, 22,  8,  9,185,
150 e7151f83 aliguori
     0, 51, 37, 23, 24, 11, 10,  0,  0, 52, 53, 38, 39, 25, 12,  0,
151 e7151f83 aliguori
     0, 89, 40,  0, 26, 13,  0,  0, 58, 54, 28, 27,  0, 43,  0, 85,
152 e7151f83 aliguori
     0, 86, 91, 90, 92,  0, 14, 94,  0, 79,124, 75, 71,121,  0,  0,
153 e7151f83 aliguori
    82, 83, 80, 76, 77, 72,  1, 69, 87, 78, 81, 74, 55, 73, 70, 99,
154 e7151f83 aliguori

155 e7151f83 aliguori
      0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
156 e7151f83 aliguori
    217,100,255,  0, 97,165,  0,  0,156,  0,  0,  0,  0,  0,  0,125,
157 e7151f83 aliguori
    173,114,  0,113,  0,  0,  0,126,128,  0,  0,140,  0,  0,  0,127,
158 e7151f83 aliguori
    159,  0,115,  0,164,  0,  0,116,158,  0,150,166,  0,  0,  0,142,
159 e7151f83 aliguori
    157,  0,  0,  0,  0,  0,  0,  0,155,  0, 98,  0,  0,163,  0,  0,
160 e7151f83 aliguori
    226,  0,  0,  0,  0,  0,  0,  0,  0,255, 96,  0,  0,  0,143,  0,
161 e7151f83 aliguori
      0,  0,  0,  0,  0,  0,  0,  0,  0,107,  0,105,102,  0,  0,112,
162 e7151f83 aliguori
    110,111,108,112,106,103,  0,119,  0,118,109,  0, 99,104,119,  0,
163 e7151f83 aliguori

164 e7151f83 aliguori
};
165 e7151f83 aliguori

166 e7151f83 aliguori
const unsigned char atkbd_unxlate_table[128] = {
167 e7151f83 aliguori

168 e7151f83 aliguori
      0,118, 22, 30, 38, 37, 46, 54, 61, 62, 70, 69, 78, 85,102, 13,
169 e7151f83 aliguori
     21, 29, 36, 45, 44, 53, 60, 67, 68, 77, 84, 91, 90, 20, 28, 27,
170 e7151f83 aliguori
     35, 43, 52, 51, 59, 66, 75, 76, 82, 14, 18, 93, 26, 34, 33, 42,
171 e7151f83 aliguori
     50, 49, 58, 65, 73, 74, 89,124, 17, 41, 88,  5,  6,  4, 12,  3,
172 e7151f83 aliguori
     11,  2, 10,  1,  9,119,126,108,117,125,123,107,115,116,121,105,
173 e7151f83 aliguori
    114,122,112,113,127, 96, 97,120,  7, 15, 23, 31, 39, 47, 55, 63,
174 e7151f83 aliguori
     71, 79, 86, 94,  8, 16, 24, 32, 40, 48, 56, 64, 72, 80, 87,111,
175 e7151f83 aliguori
     19, 25, 57, 81, 83, 92, 95, 98, 99,100,101,103,104,106,109,110
176 e7151f83 aliguori

177 e7151f83 aliguori
};
178 e7151f83 aliguori
#endif
179 e7151f83 aliguori
180 e7151f83 aliguori
/*
181 e7151f83 aliguori
 * for (i = 0; i < 128; i++) {
182 e7151f83 aliguori
 *     scancode2linux[i] = atkbd_set2_keycode[atkbd_unxlate_table[i]];
183 e7151f83 aliguori
 *     scancode2linux[i | 0x80] = atkbd_set2_keycode[atkbd_unxlate_table[i] | 0x80];
184 e7151f83 aliguori
 * }
185 e7151f83 aliguori
 */
186 e7151f83 aliguori
static const unsigned char scancode2linux[512] = {
187 e7151f83 aliguori
      0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14, 15,
188 e7151f83 aliguori
     16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,
189 e7151f83 aliguori
     32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,
190 e7151f83 aliguori
     48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,
191 e7151f83 aliguori
     64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79,
192 e7151f83 aliguori
     80, 81, 82, 83, 99,  0, 86, 87, 88,117,  0,  0, 95,183,184,185,
193 e7151f83 aliguori
      0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
194 e7151f83 aliguori
     93,  0,  0, 89,  0,  0, 85, 91, 90, 92,  0, 94,  0,124,121,  0,
195 e7151f83 aliguori
196 e7151f83 aliguori
      0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
197 e7151f83 aliguori
    165,  0,  0,  0,  0,  0,  0,  0,  0,163,  0,  0, 96, 97,  0,  0,
198 e7151f83 aliguori
    113,140,164,  0,166,  0,  0,  0,  0,  0,255,  0,  0,  0,114,  0,
199 e7151f83 aliguori
    115,  0,150,  0,  0, 98,255, 99,100,  0,  0,  0,  0,  0,  0,  0,
200 e7151f83 aliguori
      0,  0,  0,  0,  0,119,119,102,103,104,  0,105,112,106,118,107,
201 e7151f83 aliguori
    108,109,110,111,  0,  0,  0,  0,  0,  0,  0,125,126,127,116,142,
202 e7151f83 aliguori
      0,  0,  0,143,  0,217,156,173,128,159,158,157,155,226,  0,112,
203 e7151f83 aliguori
      0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,  0,
204 e7151f83 aliguori
};
205 e7151f83 aliguori
206 e7151f83 aliguori
/* Send an event to the keyboard frontend driver */
207 e7151f83 aliguori
static int xenfb_kbd_event(struct XenInput *xenfb,
208 e7151f83 aliguori
                           union xenkbd_in_event *event)
209 e7151f83 aliguori
{
210 e7151f83 aliguori
    struct xenkbd_page *page = xenfb->c.page;
211 e7151f83 aliguori
    uint32_t prod;
212 e7151f83 aliguori
213 e7151f83 aliguori
    if (xenfb->c.xendev.be_state != XenbusStateConnected)
214 e7151f83 aliguori
        return 0;
215 e7151f83 aliguori
    if (!page)
216 e7151f83 aliguori
        return 0;
217 e7151f83 aliguori
218 e7151f83 aliguori
    prod = page->in_prod;
219 e7151f83 aliguori
    if (prod - page->in_cons == XENKBD_IN_RING_LEN) {
220 e7151f83 aliguori
        errno = EAGAIN;
221 e7151f83 aliguori
        return -1;
222 e7151f83 aliguori
    }
223 e7151f83 aliguori
224 e7151f83 aliguori
    xen_mb();                /* ensure ring space available */
225 e7151f83 aliguori
    XENKBD_IN_RING_REF(page, prod) = *event;
226 e7151f83 aliguori
    xen_wmb();                /* ensure ring contents visible */
227 e7151f83 aliguori
    page->in_prod = prod + 1;
228 e7151f83 aliguori
    return xen_be_send_notify(&xenfb->c.xendev);
229 e7151f83 aliguori
}
230 e7151f83 aliguori
231 e7151f83 aliguori
/* Send a keyboard (or mouse button) event */
232 e7151f83 aliguori
static int xenfb_send_key(struct XenInput *xenfb, bool down, int keycode)
233 e7151f83 aliguori
{
234 e7151f83 aliguori
    union xenkbd_in_event event;
235 e7151f83 aliguori
236 e7151f83 aliguori
    memset(&event, 0, XENKBD_IN_EVENT_SIZE);
237 e7151f83 aliguori
    event.type = XENKBD_TYPE_KEY;
238 e7151f83 aliguori
    event.key.pressed = down ? 1 : 0;
239 e7151f83 aliguori
    event.key.keycode = keycode;
240 e7151f83 aliguori
241 e7151f83 aliguori
    return xenfb_kbd_event(xenfb, &event);
242 e7151f83 aliguori
}
243 e7151f83 aliguori
244 e7151f83 aliguori
/* Send a relative mouse movement event */
245 e7151f83 aliguori
static int xenfb_send_motion(struct XenInput *xenfb,
246 e7151f83 aliguori
                             int rel_x, int rel_y, int rel_z)
247 e7151f83 aliguori
{
248 e7151f83 aliguori
    union xenkbd_in_event event;
249 e7151f83 aliguori
250 e7151f83 aliguori
    memset(&event, 0, XENKBD_IN_EVENT_SIZE);
251 e7151f83 aliguori
    event.type = XENKBD_TYPE_MOTION;
252 e7151f83 aliguori
    event.motion.rel_x = rel_x;
253 e7151f83 aliguori
    event.motion.rel_y = rel_y;
254 e7151f83 aliguori
#if __XEN_LATEST_INTERFACE_VERSION__ >= 0x00030207
255 e7151f83 aliguori
    event.motion.rel_z = rel_z;
256 e7151f83 aliguori
#endif
257 e7151f83 aliguori
258 e7151f83 aliguori
    return xenfb_kbd_event(xenfb, &event);
259 e7151f83 aliguori
}
260 e7151f83 aliguori
261 e7151f83 aliguori
/* Send an absolute mouse movement event */
262 e7151f83 aliguori
static int xenfb_send_position(struct XenInput *xenfb,
263 e7151f83 aliguori
                               int abs_x, int abs_y, int z)
264 e7151f83 aliguori
{
265 e7151f83 aliguori
    union xenkbd_in_event event;
266 e7151f83 aliguori
267 e7151f83 aliguori
    memset(&event, 0, XENKBD_IN_EVENT_SIZE);
268 e7151f83 aliguori
    event.type = XENKBD_TYPE_POS;
269 e7151f83 aliguori
    event.pos.abs_x = abs_x;
270 e7151f83 aliguori
    event.pos.abs_y = abs_y;
271 e7151f83 aliguori
#if __XEN_LATEST_INTERFACE_VERSION__ == 0x00030207
272 e7151f83 aliguori
    event.pos.abs_z = z;
273 e7151f83 aliguori
#endif
274 e7151f83 aliguori
#if __XEN_LATEST_INTERFACE_VERSION__ >= 0x00030208
275 e7151f83 aliguori
    event.pos.rel_z = z;
276 e7151f83 aliguori
#endif
277 e7151f83 aliguori
278 e7151f83 aliguori
    return xenfb_kbd_event(xenfb, &event);
279 e7151f83 aliguori
}
280 e7151f83 aliguori
281 e7151f83 aliguori
/*
282 e7151f83 aliguori
 * Send a key event from the client to the guest OS
283 e7151f83 aliguori
 * QEMU gives us a raw scancode from an AT / PS/2 style keyboard.
284 e7151f83 aliguori
 * We have to turn this into a Linux Input layer keycode.
285 e7151f83 aliguori
 *
286 e7151f83 aliguori
 * Extra complexity from the fact that with extended scancodes
287 e7151f83 aliguori
 * (like those produced by arrow keys) this method gets called
288 e7151f83 aliguori
 * twice, but we only want to send a single event. So we have to
289 e7151f83 aliguori
 * track the '0xe0' scancode state & collapse the extended keys
290 e7151f83 aliguori
 * as needed.
291 e7151f83 aliguori
 *
292 e7151f83 aliguori
 * Wish we could just send scancodes straight to the guest which
293 e7151f83 aliguori
 * already has code for dealing with this...
294 e7151f83 aliguori
 */
295 e7151f83 aliguori
static void xenfb_key_event(void *opaque, int scancode)
296 e7151f83 aliguori
{
297 e7151f83 aliguori
    struct XenInput *xenfb = opaque;
298 e7151f83 aliguori
    int down = 1;
299 e7151f83 aliguori
300 e7151f83 aliguori
    if (scancode == 0xe0) {
301 e7151f83 aliguori
        xenfb->extended = 1;
302 e7151f83 aliguori
        return;
303 e7151f83 aliguori
    } else if (scancode & 0x80) {
304 e7151f83 aliguori
        scancode &= 0x7f;
305 e7151f83 aliguori
        down = 0;
306 e7151f83 aliguori
    }
307 e7151f83 aliguori
    if (xenfb->extended) {
308 e7151f83 aliguori
        scancode |= 0x80;
309 e7151f83 aliguori
        xenfb->extended = 0;
310 e7151f83 aliguori
    }
311 e7151f83 aliguori
    xenfb_send_key(xenfb, down, scancode2linux[scancode]);
312 e7151f83 aliguori
}
313 e7151f83 aliguori
314 e7151f83 aliguori
/*
315 e7151f83 aliguori
 * Send a mouse event from the client to the guest OS
316 e7151f83 aliguori
 *
317 e7151f83 aliguori
 * The QEMU mouse can be in either relative, or absolute mode.
318 e7151f83 aliguori
 * Movement is sent separately from button state, which has to
319 e7151f83 aliguori
 * be encoded as virtual key events. We also don't actually get
320 e7151f83 aliguori
 * given any button up/down events, so have to track changes in
321 e7151f83 aliguori
 * the button state.
322 e7151f83 aliguori
 */
323 e7151f83 aliguori
static void xenfb_mouse_event(void *opaque,
324 e7151f83 aliguori
                              int dx, int dy, int dz, int button_state)
325 e7151f83 aliguori
{
326 e7151f83 aliguori
    struct XenInput *xenfb = opaque;
327 e7151f83 aliguori
    int dw = ds_get_width(xenfb->c.ds);
328 e7151f83 aliguori
    int dh = ds_get_height(xenfb->c.ds);
329 e7151f83 aliguori
    int i;
330 e7151f83 aliguori
331 e7151f83 aliguori
    if (xenfb->abs_pointer_wanted)
332 e7151f83 aliguori
        xenfb_send_position(xenfb,
333 e7151f83 aliguori
                            dx * (dw - 1) / 0x7fff,
334 e7151f83 aliguori
                            dy * (dh - 1) / 0x7fff,
335 e7151f83 aliguori
                            dz);
336 e7151f83 aliguori
    else
337 e7151f83 aliguori
        xenfb_send_motion(xenfb, dx, dy, dz);
338 e7151f83 aliguori
339 e7151f83 aliguori
    for (i = 0 ; i < 8 ; i++) {
340 e7151f83 aliguori
        int lastDown = xenfb->button_state & (1 << i);
341 e7151f83 aliguori
        int down = button_state & (1 << i);
342 e7151f83 aliguori
        if (down == lastDown)
343 e7151f83 aliguori
            continue;
344 e7151f83 aliguori
345 e7151f83 aliguori
        if (xenfb_send_key(xenfb, down, BTN_LEFT+i) < 0)
346 e7151f83 aliguori
            return;
347 e7151f83 aliguori
    }
348 e7151f83 aliguori
    xenfb->button_state = button_state;
349 e7151f83 aliguori
}
350 e7151f83 aliguori
351 e7151f83 aliguori
static int input_init(struct XenDevice *xendev)
352 e7151f83 aliguori
{
353 e7151f83 aliguori
    struct XenInput *in = container_of(xendev, struct XenInput, c.xendev);
354 e7151f83 aliguori
355 e7151f83 aliguori
    if (!in->c.ds) {
356 e7151f83 aliguori
        xen_be_printf(xendev, 1, "ds not set (yet)\n");
357 e7151f83 aliguori
        return -1;
358 e7151f83 aliguori
    }
359 e7151f83 aliguori
360 e7151f83 aliguori
    xenstore_write_be_int(xendev, "feature-abs-pointer", 1);
361 e7151f83 aliguori
    return 0;
362 e7151f83 aliguori
}
363 e7151f83 aliguori
364 e7151f83 aliguori
static int input_connect(struct XenDevice *xendev)
365 e7151f83 aliguori
{
366 e7151f83 aliguori
    struct XenInput *in = container_of(xendev, struct XenInput, c.xendev);
367 e7151f83 aliguori
    int rc;
368 e7151f83 aliguori
369 e7151f83 aliguori
    if (xenstore_read_fe_int(xendev, "request-abs-pointer",
370 e7151f83 aliguori
                             &in->abs_pointer_wanted) == -1)
371 e7151f83 aliguori
        in->abs_pointer_wanted = 0;
372 e7151f83 aliguori
373 e7151f83 aliguori
    rc = common_bind(&in->c);
374 e7151f83 aliguori
    if (rc != 0)
375 e7151f83 aliguori
        return rc;
376 e7151f83 aliguori
377 e7151f83 aliguori
    qemu_add_kbd_event_handler(xenfb_key_event, in);
378 e7151f83 aliguori
    in->qmouse = qemu_add_mouse_event_handler(xenfb_mouse_event, in,
379 e7151f83 aliguori
                                              in->abs_pointer_wanted,
380 e7151f83 aliguori
                                              "Xen PVFB Mouse");
381 e7151f83 aliguori
    return 0;
382 e7151f83 aliguori
}
383 e7151f83 aliguori
384 e7151f83 aliguori
static void input_disconnect(struct XenDevice *xendev)
385 e7151f83 aliguori
{
386 e7151f83 aliguori
    struct XenInput *in = container_of(xendev, struct XenInput, c.xendev);
387 e7151f83 aliguori
388 e7151f83 aliguori
    if (in->qmouse) {
389 e7151f83 aliguori
        qemu_remove_mouse_event_handler(in->qmouse);
390 e7151f83 aliguori
        in->qmouse = NULL;
391 e7151f83 aliguori
    }
392 e7151f83 aliguori
    qemu_add_kbd_event_handler(NULL, NULL);
393 e7151f83 aliguori
    common_unbind(&in->c);
394 e7151f83 aliguori
}
395 e7151f83 aliguori
396 e7151f83 aliguori
static void input_event(struct XenDevice *xendev)
397 e7151f83 aliguori
{
398 e7151f83 aliguori
    struct XenInput *xenfb = container_of(xendev, struct XenInput, c.xendev);
399 e7151f83 aliguori
    struct xenkbd_page *page = xenfb->c.page;
400 e7151f83 aliguori
401 e7151f83 aliguori
    /* We don't understand any keyboard events, so just ignore them. */
402 e7151f83 aliguori
    if (page->out_prod == page->out_cons)
403 e7151f83 aliguori
        return;
404 e7151f83 aliguori
    page->out_cons = page->out_prod;
405 e7151f83 aliguori
    xen_be_send_notify(&xenfb->c.xendev);
406 e7151f83 aliguori
}
407 e7151f83 aliguori
408 e7151f83 aliguori
/* -------------------------------------------------------------------- */
409 e7151f83 aliguori
410 e7151f83 aliguori
static void xenfb_copy_mfns(int mode, int count, unsigned long *dst, void *src)
411 e7151f83 aliguori
{
412 e7151f83 aliguori
    uint32_t *src32 = src;
413 e7151f83 aliguori
    uint64_t *src64 = src;
414 e7151f83 aliguori
    int i;
415 e7151f83 aliguori
416 e7151f83 aliguori
    for (i = 0; i < count; i++)
417 e7151f83 aliguori
        dst[i] = (mode == 32) ? src32[i] : src64[i];
418 e7151f83 aliguori
}
419 e7151f83 aliguori
420 e7151f83 aliguori
static int xenfb_map_fb(struct XenFB *xenfb)
421 e7151f83 aliguori
{
422 e7151f83 aliguori
    struct xenfb_page *page = xenfb->c.page;
423 e7151f83 aliguori
    char *protocol = xenfb->c.xendev.protocol;
424 e7151f83 aliguori
    int n_fbdirs;
425 e7151f83 aliguori
    unsigned long *pgmfns = NULL;
426 e7151f83 aliguori
    unsigned long *fbmfns = NULL;
427 e7151f83 aliguori
    void *map, *pd;
428 e7151f83 aliguori
    int mode, ret = -1;
429 e7151f83 aliguori
430 e7151f83 aliguori
    /* default to native */
431 e7151f83 aliguori
    pd = page->pd;
432 e7151f83 aliguori
    mode = sizeof(unsigned long) * 8;
433 e7151f83 aliguori
434 e7151f83 aliguori
    if (!protocol) {
435 e7151f83 aliguori
        /*
436 e7151f83 aliguori
         * Undefined protocol, some guesswork needed.
437 e7151f83 aliguori
         *
438 e7151f83 aliguori
         * Old frontends which don't set the protocol use
439 e7151f83 aliguori
         * one page directory only, thus pd[1] must be zero.
440 e7151f83 aliguori
         * pd[1] of the 32bit struct layout and the lower
441 e7151f83 aliguori
         * 32 bits of pd[0] of the 64bit struct layout have
442 e7151f83 aliguori
         * the same location, so we can check that ...
443 e7151f83 aliguori
         */
444 e7151f83 aliguori
        uint32_t *ptr32 = NULL;
445 e7151f83 aliguori
        uint32_t *ptr64 = NULL;
446 e7151f83 aliguori
#if defined(__i386__)
447 e7151f83 aliguori
        ptr32 = (void*)page->pd;
448 e7151f83 aliguori
        ptr64 = ((void*)page->pd) + 4;
449 e7151f83 aliguori
#elif defined(__x86_64__)
450 e7151f83 aliguori
        ptr32 = ((void*)page->pd) - 4;
451 e7151f83 aliguori
        ptr64 = (void*)page->pd;
452 e7151f83 aliguori
#endif
453 e7151f83 aliguori
        if (ptr32) {
454 e7151f83 aliguori
            if (ptr32[1] == 0) {
455 e7151f83 aliguori
                mode = 32;
456 e7151f83 aliguori
                pd   = ptr32;
457 e7151f83 aliguori
            } else {
458 e7151f83 aliguori
                mode = 64;
459 e7151f83 aliguori
                pd   = ptr64;
460 e7151f83 aliguori
            }
461 e7151f83 aliguori
        }
462 e7151f83 aliguori
#if defined(__x86_64__)
463 e7151f83 aliguori
    } else if (strcmp(protocol, XEN_IO_PROTO_ABI_X86_32) == 0) {
464 e7151f83 aliguori
        /* 64bit dom0, 32bit domU */
465 e7151f83 aliguori
        mode = 32;
466 e7151f83 aliguori
        pd   = ((void*)page->pd) - 4;
467 e7151f83 aliguori
#elif defined(__i386__)
468 e7151f83 aliguori
    } else if (strcmp(protocol, XEN_IO_PROTO_ABI_X86_64) == 0) {
469 e7151f83 aliguori
        /* 32bit dom0, 64bit domU */
470 e7151f83 aliguori
        mode = 64;
471 e7151f83 aliguori
        pd   = ((void*)page->pd) + 4;
472 e7151f83 aliguori
#endif
473 e7151f83 aliguori
    }
474 e7151f83 aliguori
475 e7151f83 aliguori
    if (xenfb->pixels) {
476 e7151f83 aliguori
        munmap(xenfb->pixels, xenfb->fbpages * XC_PAGE_SIZE);
477 e7151f83 aliguori
        xenfb->pixels = NULL;
478 e7151f83 aliguori
    }
479 e7151f83 aliguori
480 e7151f83 aliguori
    xenfb->fbpages = (xenfb->fb_len + (XC_PAGE_SIZE - 1)) / XC_PAGE_SIZE;
481 e7151f83 aliguori
    n_fbdirs = xenfb->fbpages * mode / 8;
482 e7151f83 aliguori
    n_fbdirs = (n_fbdirs + (XC_PAGE_SIZE - 1)) / XC_PAGE_SIZE;
483 e7151f83 aliguori
484 e7151f83 aliguori
    pgmfns = qemu_mallocz(sizeof(unsigned long) * n_fbdirs);
485 e7151f83 aliguori
    fbmfns = qemu_mallocz(sizeof(unsigned long) * xenfb->fbpages);
486 e7151f83 aliguori
487 e7151f83 aliguori
    xenfb_copy_mfns(mode, n_fbdirs, pgmfns, pd);
488 e7151f83 aliguori
    map = xc_map_foreign_pages(xen_xc, xenfb->c.xendev.dom,
489 e7151f83 aliguori
                               PROT_READ, pgmfns, n_fbdirs);
490 e7151f83 aliguori
    if (map == NULL)
491 e7151f83 aliguori
        goto out;
492 e7151f83 aliguori
    xenfb_copy_mfns(mode, xenfb->fbpages, fbmfns, map);
493 e7151f83 aliguori
    munmap(map, n_fbdirs * XC_PAGE_SIZE);
494 e7151f83 aliguori
495 e7151f83 aliguori
    xenfb->pixels = xc_map_foreign_pages(xen_xc, xenfb->c.xendev.dom,
496 e7151f83 aliguori
                                         PROT_READ | PROT_WRITE, fbmfns, xenfb->fbpages);
497 e7151f83 aliguori
    if (xenfb->pixels == NULL)
498 e7151f83 aliguori
        goto out;
499 e7151f83 aliguori
500 e7151f83 aliguori
    ret = 0; /* all is fine */
501 e7151f83 aliguori
502 e7151f83 aliguori
out:
503 e7151f83 aliguori
    qemu_free(pgmfns);
504 e7151f83 aliguori
    qemu_free(fbmfns);
505 e7151f83 aliguori
    return ret;
506 e7151f83 aliguori
}
507 e7151f83 aliguori
508 e7151f83 aliguori
static int xenfb_configure_fb(struct XenFB *xenfb, size_t fb_len_lim,
509 e7151f83 aliguori
                              int width, int height, int depth,
510 e7151f83 aliguori
                              size_t fb_len, int offset, int row_stride)
511 e7151f83 aliguori
{
512 e7151f83 aliguori
    size_t mfn_sz = sizeof(*((struct xenfb_page *)0)->pd);
513 e7151f83 aliguori
    size_t pd_len = sizeof(((struct xenfb_page *)0)->pd) / mfn_sz;
514 e7151f83 aliguori
    size_t fb_pages = pd_len * XC_PAGE_SIZE / mfn_sz;
515 e7151f83 aliguori
    size_t fb_len_max = fb_pages * XC_PAGE_SIZE;
516 e7151f83 aliguori
    int max_width, max_height;
517 e7151f83 aliguori
518 e7151f83 aliguori
    if (fb_len_lim > fb_len_max) {
519 e7151f83 aliguori
        xen_be_printf(&xenfb->c.xendev, 0, "fb size limit %zu exceeds %zu, corrected\n",
520 e7151f83 aliguori
                      fb_len_lim, fb_len_max);
521 e7151f83 aliguori
        fb_len_lim = fb_len_max;
522 e7151f83 aliguori
    }
523 e7151f83 aliguori
    if (fb_len_lim && fb_len > fb_len_lim) {
524 e7151f83 aliguori
        xen_be_printf(&xenfb->c.xendev, 0, "frontend fb size %zu limited to %zu\n",
525 e7151f83 aliguori
                      fb_len, fb_len_lim);
526 e7151f83 aliguori
        fb_len = fb_len_lim;
527 e7151f83 aliguori
    }
528 e7151f83 aliguori
    if (depth != 8 && depth != 16 && depth != 24 && depth != 32) {
529 e7151f83 aliguori
        xen_be_printf(&xenfb->c.xendev, 0, "can't handle frontend fb depth %d\n",
530 e7151f83 aliguori
                      depth);
531 e7151f83 aliguori
        return -1;
532 e7151f83 aliguori
    }
533 e7151f83 aliguori
    if (row_stride <= 0 || row_stride > fb_len) {
534 e7151f83 aliguori
        xen_be_printf(&xenfb->c.xendev, 0, "invalid frontend stride %d\n", row_stride);
535 e7151f83 aliguori
        return -1;
536 e7151f83 aliguori
    }
537 e7151f83 aliguori
    max_width = row_stride / (depth / 8);
538 e7151f83 aliguori
    if (width < 0 || width > max_width) {
539 e7151f83 aliguori
        xen_be_printf(&xenfb->c.xendev, 0, "invalid frontend width %d limited to %d\n",
540 e7151f83 aliguori
                      width, max_width);
541 e7151f83 aliguori
        width = max_width;
542 e7151f83 aliguori
    }
543 e7151f83 aliguori
    if (offset < 0 || offset >= fb_len) {
544 e7151f83 aliguori
        xen_be_printf(&xenfb->c.xendev, 0, "invalid frontend offset %d (max %zu)\n",
545 e7151f83 aliguori
                      offset, fb_len - 1);
546 e7151f83 aliguori
        return -1;
547 e7151f83 aliguori
    }
548 e7151f83 aliguori
    max_height = (fb_len - offset) / row_stride;
549 e7151f83 aliguori
    if (height < 0 || height > max_height) {
550 e7151f83 aliguori
        xen_be_printf(&xenfb->c.xendev, 0, "invalid frontend height %d limited to %d\n",
551 e7151f83 aliguori
                      height, max_height);
552 e7151f83 aliguori
        height = max_height;
553 e7151f83 aliguori
    }
554 e7151f83 aliguori
    xenfb->fb_len = fb_len;
555 e7151f83 aliguori
    xenfb->row_stride = row_stride;
556 e7151f83 aliguori
    xenfb->depth = depth;
557 e7151f83 aliguori
    xenfb->width = width;
558 e7151f83 aliguori
    xenfb->height = height;
559 e7151f83 aliguori
    xenfb->offset = offset;
560 e7151f83 aliguori
    xenfb->up_fullscreen = 1;
561 e7151f83 aliguori
    xenfb->do_resize = 1;
562 e7151f83 aliguori
    xen_be_printf(&xenfb->c.xendev, 1, "framebuffer %dx%dx%d offset %d stride %d\n",
563 e7151f83 aliguori
                  width, height, depth, offset, row_stride);
564 e7151f83 aliguori
    return 0;
565 e7151f83 aliguori
}
566 e7151f83 aliguori
567 e7151f83 aliguori
/* A convenient function for munging pixels between different depths */
568 e7151f83 aliguori
#define BLT(SRC_T,DST_T,RSB,GSB,BSB,RDB,GDB,BDB)                        \
569 e7151f83 aliguori
    for (line = y ; line < (y+h) ; line++) {                                \
570 e7151f83 aliguori
        SRC_T *src = (SRC_T *)(xenfb->pixels                                \
571 e7151f83 aliguori
                               + xenfb->offset                                \
572 e7151f83 aliguori
                               + (line * xenfb->row_stride)                \
573 e7151f83 aliguori
                               + (x * xenfb->depth / 8));                \
574 e7151f83 aliguori
        DST_T *dst = (DST_T *)(data                                        \
575 e7151f83 aliguori
                               + (line * linesize)                        \
576 e7151f83 aliguori
                               + (x * bpp / 8));                        \
577 e7151f83 aliguori
        int col;                                                        \
578 e7151f83 aliguori
        const int RSS = 32 - (RSB + GSB + BSB);                                \
579 e7151f83 aliguori
        const int GSS = 32 - (GSB + BSB);                                \
580 e7151f83 aliguori
        const int BSS = 32 - (BSB);                                        \
581 e7151f83 aliguori
        const uint32_t RSM = (~0U) << (32 - RSB);                        \
582 e7151f83 aliguori
        const uint32_t GSM = (~0U) << (32 - GSB);                        \
583 e7151f83 aliguori
        const uint32_t BSM = (~0U) << (32 - BSB);                        \
584 e7151f83 aliguori
        const int RDS = 32 - (RDB + GDB + BDB);                                \
585 e7151f83 aliguori
        const int GDS = 32 - (GDB + BDB);                                \
586 e7151f83 aliguori
        const int BDS = 32 - (BDB);                                        \
587 e7151f83 aliguori
        const uint32_t RDM = (~0U) << (32 - RDB);                        \
588 e7151f83 aliguori
        const uint32_t GDM = (~0U) << (32 - GDB);                        \
589 e7151f83 aliguori
        const uint32_t BDM = (~0U) << (32 - BDB);                        \
590 e7151f83 aliguori
        for (col = x ; col < (x+w) ; col++) {                                \
591 e7151f83 aliguori
            uint32_t spix = *src;                                        \
592 e7151f83 aliguori
            *dst = (((spix << RSS) & RSM & RDM) >> RDS) |                \
593 e7151f83 aliguori
                (((spix << GSS) & GSM & GDM) >> GDS) |                        \
594 e7151f83 aliguori
                (((spix << BSS) & BSM & BDM) >> BDS);                        \
595 e7151f83 aliguori
            src = (SRC_T *) ((unsigned long) src + xenfb->depth / 8);        \
596 e7151f83 aliguori
            dst = (DST_T *) ((unsigned long) dst + bpp / 8);                \
597 e7151f83 aliguori
        }                                                                \
598 e7151f83 aliguori
    }
599 e7151f83 aliguori
600 e7151f83 aliguori
601 e7151f83 aliguori
/*
602 e7151f83 aliguori
 * This copies data from the guest framebuffer region, into QEMU's
603 e7151f83 aliguori
 * displaysurface. qemu uses 16 or 32 bpp.  In case the pv framebuffer
604 e7151f83 aliguori
 * uses something else we must convert and copy, otherwise we can
605 e7151f83 aliguori
 * supply the buffer directly and no thing here.
606 e7151f83 aliguori
 */
607 e7151f83 aliguori
static void xenfb_guest_copy(struct XenFB *xenfb, int x, int y, int w, int h)
608 e7151f83 aliguori
{
609 e7151f83 aliguori
    int line, oops = 0;
610 e7151f83 aliguori
    int bpp = ds_get_bits_per_pixel(xenfb->c.ds);
611 e7151f83 aliguori
    int linesize = ds_get_linesize(xenfb->c.ds);
612 e7151f83 aliguori
    uint8_t *data = ds_get_data(xenfb->c.ds);
613 e7151f83 aliguori
614 e7151f83 aliguori
    if (!is_buffer_shared(xenfb->c.ds->surface)) {
615 e7151f83 aliguori
        switch (xenfb->depth) {
616 e7151f83 aliguori
        case 8:
617 e7151f83 aliguori
            if (bpp == 16) {
618 e7151f83 aliguori
                BLT(uint8_t, uint16_t,   3, 3, 2,   5, 6, 5);
619 e7151f83 aliguori
            } else if (bpp == 32) {
620 e7151f83 aliguori
                BLT(uint8_t, uint32_t,   3, 3, 2,   8, 8, 8);
621 e7151f83 aliguori
            } else {
622 e7151f83 aliguori
                oops = 1;
623 e7151f83 aliguori
            }
624 e7151f83 aliguori
            break;
625 e7151f83 aliguori
        case 24:
626 e7151f83 aliguori
            if (bpp == 16) {
627 e7151f83 aliguori
                BLT(uint32_t, uint16_t,  8, 8, 8,   5, 6, 5);
628 e7151f83 aliguori
            } else if (bpp == 32) {
629 e7151f83 aliguori
                BLT(uint32_t, uint32_t,  8, 8, 8,   8, 8, 8);
630 e7151f83 aliguori
            } else {
631 e7151f83 aliguori
                oops = 1;
632 e7151f83 aliguori
            }
633 e7151f83 aliguori
            break;
634 e7151f83 aliguori
        default:
635 e7151f83 aliguori
            oops = 1;
636 e7151f83 aliguori
        }
637 e7151f83 aliguori
    }
638 e7151f83 aliguori
    if (oops) /* should not happen */
639 e7151f83 aliguori
        xen_be_printf(&xenfb->c.xendev, 0, "%s: oops: convert %d -> %d bpp?\n",
640 e7151f83 aliguori
                      __FUNCTION__, xenfb->depth, bpp);
641 e7151f83 aliguori
642 e7151f83 aliguori
    dpy_update(xenfb->c.ds, x, y, w, h);
643 e7151f83 aliguori
}
644 e7151f83 aliguori
645 e7151f83 aliguori
#ifdef XENFB_TYPE_REFRESH_PERIOD
646 e7151f83 aliguori
static int xenfb_queue_full(struct XenFB *xenfb)
647 e7151f83 aliguori
{
648 e7151f83 aliguori
    struct xenfb_page *page = xenfb->c.page;
649 e7151f83 aliguori
    uint32_t cons, prod;
650 e7151f83 aliguori
651 e7151f83 aliguori
    if (!page)
652 e7151f83 aliguori
        return 1;
653 e7151f83 aliguori
654 e7151f83 aliguori
    prod = page->in_prod;
655 e7151f83 aliguori
    cons = page->in_cons;
656 e7151f83 aliguori
    return prod - cons == XENFB_IN_RING_LEN;
657 e7151f83 aliguori
}
658 e7151f83 aliguori
659 e7151f83 aliguori
static void xenfb_send_event(struct XenFB *xenfb, union xenfb_in_event *event)
660 e7151f83 aliguori
{
661 e7151f83 aliguori
    uint32_t prod;
662 e7151f83 aliguori
    struct xenfb_page *page = xenfb->c.page;
663 e7151f83 aliguori
664 e7151f83 aliguori
    prod = page->in_prod;
665 e7151f83 aliguori
    /* caller ensures !xenfb_queue_full() */
666 e7151f83 aliguori
    xen_mb();                   /* ensure ring space available */
667 e7151f83 aliguori
    XENFB_IN_RING_REF(page, prod) = *event;
668 e7151f83 aliguori
    xen_wmb();                  /* ensure ring contents visible */
669 e7151f83 aliguori
    page->in_prod = prod + 1;
670 e7151f83 aliguori
671 e7151f83 aliguori
    xen_be_send_notify(&xenfb->c.xendev);
672 e7151f83 aliguori
}
673 e7151f83 aliguori
674 e7151f83 aliguori
static void xenfb_send_refresh_period(struct XenFB *xenfb, int period)
675 e7151f83 aliguori
{
676 e7151f83 aliguori
    union xenfb_in_event event;
677 e7151f83 aliguori
678 e7151f83 aliguori
    memset(&event, 0, sizeof(event));
679 e7151f83 aliguori
    event.type = XENFB_TYPE_REFRESH_PERIOD;
680 e7151f83 aliguori
    event.refresh_period.period = period;
681 e7151f83 aliguori
    xenfb_send_event(xenfb, &event);
682 e7151f83 aliguori
}
683 e7151f83 aliguori
#endif
684 e7151f83 aliguori
685 e7151f83 aliguori
/*
686 e7151f83 aliguori
 * Periodic update of display.
687 e7151f83 aliguori
 * Also transmit the refresh interval to the frontend.
688 e7151f83 aliguori
 *
689 e7151f83 aliguori
 * Never ever do any qemu display operations
690 e7151f83 aliguori
 * (resize, screen update) outside this function.
691 e7151f83 aliguori
 * Our screen might be inactive.  When asked for
692 e7151f83 aliguori
 * an update we know it is active.
693 e7151f83 aliguori
 */
694 e7151f83 aliguori
static void xenfb_update(void *opaque)
695 e7151f83 aliguori
{
696 e7151f83 aliguori
    struct XenFB *xenfb = opaque;
697 e7151f83 aliguori
    struct DisplayChangeListener *l;
698 e7151f83 aliguori
    int i;
699 e7151f83 aliguori
700 e7151f83 aliguori
    if (xenfb->c.xendev.be_state != XenbusStateConnected)
701 e7151f83 aliguori
        return;
702 e7151f83 aliguori
703 e7151f83 aliguori
    if (xenfb->feature_update) {
704 e7151f83 aliguori
#ifdef XENFB_TYPE_REFRESH_PERIOD
705 e7151f83 aliguori
        int period = 99999999;
706 e7151f83 aliguori
        int idle = 1;
707 e7151f83 aliguori
708 e7151f83 aliguori
        if (xenfb_queue_full(xenfb))
709 e7151f83 aliguori
            return;
710 e7151f83 aliguori
711 e7151f83 aliguori
        for (l = xenfb->c.ds->listeners; l != NULL; l = l->next) {
712 e7151f83 aliguori
            if (l->idle)
713 e7151f83 aliguori
                continue;
714 e7151f83 aliguori
            idle = 0;
715 e7151f83 aliguori
            if (!l->gui_timer_interval) {
716 e7151f83 aliguori
                if (period > GUI_REFRESH_INTERVAL)
717 e7151f83 aliguori
                    period = GUI_REFRESH_INTERVAL;
718 e7151f83 aliguori
            } else {
719 e7151f83 aliguori
                if (period > l->gui_timer_interval)
720 e7151f83 aliguori
                    period = l->gui_timer_interval;
721 e7151f83 aliguori
            }
722 e7151f83 aliguori
        }
723 e7151f83 aliguori
        if (idle)
724 e7151f83 aliguori
            period = XENFB_NO_REFRESH;
725 e7151f83 aliguori
726 e7151f83 aliguori
        if (xenfb->refresh_period != period) {
727 e7151f83 aliguori
            xenfb_send_refresh_period(xenfb, period);
728 e7151f83 aliguori
            xenfb->refresh_period = period;
729 e7151f83 aliguori
            xen_be_printf(&xenfb->c.xendev, 1, "refresh period: %d\n", period);
730 e7151f83 aliguori
        }
731 e7151f83 aliguori
#else
732 e7151f83 aliguori
        ; /* nothing */
733 e7151f83 aliguori
#endif
734 e7151f83 aliguori
    } else {
735 e7151f83 aliguori
        /* we don't get update notifications, thus use the
736 e7151f83 aliguori
         * sledge hammer approach ... */
737 e7151f83 aliguori
        xenfb->up_fullscreen = 1;
738 e7151f83 aliguori
    }
739 e7151f83 aliguori
740 e7151f83 aliguori
    /* resize if needed */
741 e7151f83 aliguori
    if (xenfb->do_resize) {
742 e7151f83 aliguori
        xenfb->do_resize = 0;
743 e7151f83 aliguori
        switch (xenfb->depth) {
744 e7151f83 aliguori
        case 16:
745 e7151f83 aliguori
        case 32:
746 e7151f83 aliguori
            /* console.c supported depth -> buffer can be used directly */
747 e7151f83 aliguori
            qemu_free_displaysurface(xenfb->c.ds);
748 e7151f83 aliguori
            xenfb->c.ds->surface = qemu_create_displaysurface_from
749 e7151f83 aliguori
                (xenfb->width, xenfb->height, xenfb->depth,
750 e7151f83 aliguori
                 xenfb->row_stride, xenfb->pixels + xenfb->offset);
751 e7151f83 aliguori
            break;
752 e7151f83 aliguori
        default:
753 e7151f83 aliguori
            /* we must convert stuff */
754 e7151f83 aliguori
            qemu_resize_displaysurface(xenfb->c.ds, xenfb->width, xenfb->height);
755 e7151f83 aliguori
            break;
756 e7151f83 aliguori
        }
757 e7151f83 aliguori
        xen_be_printf(&xenfb->c.xendev, 1, "update: resizing: %dx%d @ %d bpp%s\n",
758 e7151f83 aliguori
                      xenfb->width, xenfb->height, xenfb->depth,
759 e7151f83 aliguori
                      is_buffer_shared(xenfb->c.ds->surface) ? " (shared)" : "");
760 e7151f83 aliguori
        dpy_resize(xenfb->c.ds);
761 e7151f83 aliguori
        xenfb->up_fullscreen = 1;
762 e7151f83 aliguori
    }
763 e7151f83 aliguori
764 e7151f83 aliguori
    /* run queued updates */
765 e7151f83 aliguori
    if (xenfb->up_fullscreen) {
766 e7151f83 aliguori
        xen_be_printf(&xenfb->c.xendev, 3, "update: fullscreen\n");
767 e7151f83 aliguori
        xenfb_guest_copy(xenfb, 0, 0, xenfb->width, xenfb->height);
768 e7151f83 aliguori
    } else if (xenfb->up_count) {
769 e7151f83 aliguori
        xen_be_printf(&xenfb->c.xendev, 3, "update: %d rects\n", xenfb->up_count);
770 e7151f83 aliguori
        for (i = 0; i < xenfb->up_count; i++)
771 e7151f83 aliguori
            xenfb_guest_copy(xenfb,
772 e7151f83 aliguori
                             xenfb->up_rects[i].x,
773 e7151f83 aliguori
                             xenfb->up_rects[i].y,
774 e7151f83 aliguori
                             xenfb->up_rects[i].w,
775 e7151f83 aliguori
                             xenfb->up_rects[i].h);
776 e7151f83 aliguori
    } else {
777 e7151f83 aliguori
        xen_be_printf(&xenfb->c.xendev, 3, "update: nothing\n");
778 e7151f83 aliguori
    }
779 e7151f83 aliguori
    xenfb->up_count = 0;
780 e7151f83 aliguori
    xenfb->up_fullscreen = 0;
781 e7151f83 aliguori
}
782 e7151f83 aliguori
783 e7151f83 aliguori
/* QEMU display state changed, so refresh the framebuffer copy */
784 e7151f83 aliguori
static void xenfb_invalidate(void *opaque)
785 e7151f83 aliguori
{
786 e7151f83 aliguori
    struct XenFB *xenfb = opaque;
787 e7151f83 aliguori
    xenfb->up_fullscreen = 1;
788 e7151f83 aliguori
}
789 e7151f83 aliguori
790 e7151f83 aliguori
static void xenfb_handle_events(struct XenFB *xenfb)
791 e7151f83 aliguori
{
792 e7151f83 aliguori
    uint32_t prod, cons;
793 e7151f83 aliguori
    struct xenfb_page *page = xenfb->c.page;
794 e7151f83 aliguori
795 e7151f83 aliguori
    prod = page->out_prod;
796 e7151f83 aliguori
    if (prod == page->out_cons)
797 e7151f83 aliguori
        return;
798 e7151f83 aliguori
    xen_rmb();                /* ensure we see ring contents up to prod */
799 e7151f83 aliguori
    for (cons = page->out_cons; cons != prod; cons++) {
800 e7151f83 aliguori
        union xenfb_out_event *event = &XENFB_OUT_RING_REF(page, cons);
801 e7151f83 aliguori
        int x, y, w, h;
802 e7151f83 aliguori
803 e7151f83 aliguori
        switch (event->type) {
804 e7151f83 aliguori
        case XENFB_TYPE_UPDATE:
805 e7151f83 aliguori
            if (xenfb->up_count == UP_QUEUE)
806 e7151f83 aliguori
                xenfb->up_fullscreen = 1;
807 e7151f83 aliguori
            if (xenfb->up_fullscreen)
808 e7151f83 aliguori
                break;
809 e7151f83 aliguori
            x = MAX(event->update.x, 0);
810 e7151f83 aliguori
            y = MAX(event->update.y, 0);
811 e7151f83 aliguori
            w = MIN(event->update.width, xenfb->width - x);
812 e7151f83 aliguori
            h = MIN(event->update.height, xenfb->height - y);
813 e7151f83 aliguori
            if (w < 0 || h < 0) {
814 e7151f83 aliguori
                xen_be_printf(&xenfb->c.xendev, 1, "bogus update ignored\n");
815 e7151f83 aliguori
                break;
816 e7151f83 aliguori
            }
817 e7151f83 aliguori
            if (x != event->update.x ||
818 e7151f83 aliguori
                y != event->update.y ||
819 e7151f83 aliguori
                w != event->update.width ||
820 e7151f83 aliguori
                h != event->update.height) {
821 e7151f83 aliguori
                xen_be_printf(&xenfb->c.xendev, 1, "bogus update clipped\n");
822 e7151f83 aliguori
            }
823 e7151f83 aliguori
            if (w == xenfb->width && h > xenfb->height / 2) {
824 e7151f83 aliguori
                /* scroll detector: updated more than 50% of the lines,
825 e7151f83 aliguori
                 * don't bother keeping track of the rectangles then */
826 e7151f83 aliguori
                xenfb->up_fullscreen = 1;
827 e7151f83 aliguori
            } else {
828 e7151f83 aliguori
                xenfb->up_rects[xenfb->up_count].x = x;
829 e7151f83 aliguori
                xenfb->up_rects[xenfb->up_count].y = y;
830 e7151f83 aliguori
                xenfb->up_rects[xenfb->up_count].w = w;
831 e7151f83 aliguori
                xenfb->up_rects[xenfb->up_count].h = h;
832 e7151f83 aliguori
                xenfb->up_count++;
833 e7151f83 aliguori
            }
834 e7151f83 aliguori
            break;
835 e7151f83 aliguori
#ifdef XENFB_TYPE_RESIZE
836 e7151f83 aliguori
        case XENFB_TYPE_RESIZE:
837 e7151f83 aliguori
            if (xenfb_configure_fb(xenfb, xenfb->fb_len,
838 e7151f83 aliguori
                                   event->resize.width,
839 e7151f83 aliguori
                                   event->resize.height,
840 e7151f83 aliguori
                                   event->resize.depth,
841 e7151f83 aliguori
                                   xenfb->fb_len,
842 e7151f83 aliguori
                                   event->resize.offset,
843 e7151f83 aliguori
                                   event->resize.stride) < 0)
844 e7151f83 aliguori
                break;
845 e7151f83 aliguori
            xenfb_invalidate(xenfb);
846 e7151f83 aliguori
            break;
847 e7151f83 aliguori
#endif
848 e7151f83 aliguori
        }
849 e7151f83 aliguori
    }
850 e7151f83 aliguori
    xen_mb();                /* ensure we're done with ring contents */
851 e7151f83 aliguori
    page->out_cons = cons;
852 e7151f83 aliguori
}
853 e7151f83 aliguori
854 e7151f83 aliguori
static int fb_init(struct XenDevice *xendev)
855 e7151f83 aliguori
{
856 e7151f83 aliguori
    struct XenFB *fb = container_of(xendev, struct XenFB, c.xendev);
857 e7151f83 aliguori
858 e7151f83 aliguori
    fb->refresh_period = -1;
859 e7151f83 aliguori
860 e7151f83 aliguori
#ifdef XENFB_TYPE_RESIZE
861 e7151f83 aliguori
    xenstore_write_be_int(xendev, "feature-resize", 1);
862 e7151f83 aliguori
#endif
863 e7151f83 aliguori
    return 0;
864 e7151f83 aliguori
}
865 e7151f83 aliguori
866 e7151f83 aliguori
static int fb_connect(struct XenDevice *xendev)
867 e7151f83 aliguori
{
868 e7151f83 aliguori
    struct XenFB *fb = container_of(xendev, struct XenFB, c.xendev);
869 e7151f83 aliguori
    struct xenfb_page *fb_page;
870 e7151f83 aliguori
    int videoram;
871 e7151f83 aliguori
    int rc;
872 e7151f83 aliguori
873 e7151f83 aliguori
    if (xenstore_read_fe_int(xendev, "videoram", &videoram) == -1)
874 e7151f83 aliguori
        videoram = 0;
875 e7151f83 aliguori
876 e7151f83 aliguori
    rc = common_bind(&fb->c);
877 e7151f83 aliguori
    if (rc != 0)
878 e7151f83 aliguori
        return rc;
879 e7151f83 aliguori
880 e7151f83 aliguori
    fb_page = fb->c.page;
881 e7151f83 aliguori
    rc = xenfb_configure_fb(fb, videoram * 1024 * 1024U,
882 e7151f83 aliguori
                            fb_page->width, fb_page->height, fb_page->depth,
883 e7151f83 aliguori
                            fb_page->mem_length, 0, fb_page->line_length);
884 e7151f83 aliguori
    if (rc != 0)
885 e7151f83 aliguori
        return rc;
886 e7151f83 aliguori
887 e7151f83 aliguori
    rc = xenfb_map_fb(fb);
888 e7151f83 aliguori
    if (rc != 0)
889 e7151f83 aliguori
        return rc;
890 e7151f83 aliguori
891 e7151f83 aliguori
#if 0  /* handled in xen_init_display() for now */
892 e7151f83 aliguori
    if (!fb->have_console) {
893 e7151f83 aliguori
        fb->c.ds = graphic_console_init(xenfb_update,
894 e7151f83 aliguori
                                        xenfb_invalidate,
895 e7151f83 aliguori
                                        NULL,
896 e7151f83 aliguori
                                        NULL,
897 e7151f83 aliguori
                                        fb);
898 e7151f83 aliguori
        fb->have_console = 1;
899 e7151f83 aliguori
    }
900 e7151f83 aliguori
#endif
901 e7151f83 aliguori
902 e7151f83 aliguori
    if (xenstore_read_fe_int(xendev, "feature-update", &fb->feature_update) == -1)
903 e7151f83 aliguori
        fb->feature_update = 0;
904 e7151f83 aliguori
    if (fb->feature_update)
905 e7151f83 aliguori
        xenstore_write_be_int(xendev, "request-update", 1);
906 e7151f83 aliguori
907 e7151f83 aliguori
    xen_be_printf(xendev, 1, "feature-update=%d, videoram=%d\n",
908 e7151f83 aliguori
                  fb->feature_update, videoram);
909 e7151f83 aliguori
    return 0;
910 e7151f83 aliguori
}
911 e7151f83 aliguori
912 e7151f83 aliguori
static void fb_disconnect(struct XenDevice *xendev)
913 e7151f83 aliguori
{
914 e7151f83 aliguori
    struct XenFB *fb = container_of(xendev, struct XenFB, c.xendev);
915 e7151f83 aliguori
916 e7151f83 aliguori
    /*
917 e7151f83 aliguori
     * FIXME: qemu can't un-init gfx display (yet?).
918 e7151f83 aliguori
     *   Replacing the framebuffer with anonymous shared memory
919 e7151f83 aliguori
     *   instead.  This releases the guest pages and keeps qemu happy.
920 e7151f83 aliguori
     */
921 e7151f83 aliguori
    fb->pixels = mmap(fb->pixels, fb->fbpages * XC_PAGE_SIZE,
922 e7151f83 aliguori
                      PROT_READ | PROT_WRITE, MAP_SHARED | MAP_ANON,
923 e7151f83 aliguori
                      -1, 0);
924 e7151f83 aliguori
    common_unbind(&fb->c);
925 e7151f83 aliguori
    fb->feature_update = 0;
926 e7151f83 aliguori
    fb->bug_trigger    = 0;
927 e7151f83 aliguori
}
928 e7151f83 aliguori
929 e7151f83 aliguori
static void fb_frontend_changed(struct XenDevice *xendev, const char *node)
930 e7151f83 aliguori
{
931 e7151f83 aliguori
    struct XenFB *fb = container_of(xendev, struct XenFB, c.xendev);
932 e7151f83 aliguori
933 e7151f83 aliguori
    /*
934 e7151f83 aliguori
     * Set state to Connected *again* once the frontend switched
935 e7151f83 aliguori
     * to connected.  We must trigger the watch a second time to
936 e7151f83 aliguori
     * workaround a frontend bug.
937 e7151f83 aliguori
     */
938 e7151f83 aliguori
    if (fb->bug_trigger == 0 && strcmp(node, "state") == 0 &&
939 e7151f83 aliguori
        xendev->fe_state == XenbusStateConnected &&
940 e7151f83 aliguori
        xendev->be_state == XenbusStateConnected) {
941 e7151f83 aliguori
        xen_be_printf(xendev, 2, "re-trigger connected (frontend bug)\n");
942 e7151f83 aliguori
        xen_be_set_state(xendev, XenbusStateConnected);
943 e7151f83 aliguori
        fb->bug_trigger = 1; /* only once */
944 e7151f83 aliguori
    }
945 e7151f83 aliguori
}
946 e7151f83 aliguori
947 e7151f83 aliguori
static void fb_event(struct XenDevice *xendev)
948 e7151f83 aliguori
{
949 e7151f83 aliguori
    struct XenFB *xenfb = container_of(xendev, struct XenFB, c.xendev);
950 e7151f83 aliguori
951 e7151f83 aliguori
    xenfb_handle_events(xenfb);
952 e7151f83 aliguori
    xen_be_send_notify(&xenfb->c.xendev);
953 e7151f83 aliguori
}
954 e7151f83 aliguori
955 e7151f83 aliguori
/* -------------------------------------------------------------------- */
956 e7151f83 aliguori
957 e7151f83 aliguori
struct XenDevOps xen_kbdmouse_ops = {
958 e7151f83 aliguori
    .size       = sizeof(struct XenInput),
959 e7151f83 aliguori
    .init       = input_init,
960 e7151f83 aliguori
    .connect    = input_connect,
961 e7151f83 aliguori
    .disconnect = input_disconnect,
962 e7151f83 aliguori
    .event      = input_event,
963 e7151f83 aliguori
};
964 e7151f83 aliguori
965 e7151f83 aliguori
struct XenDevOps xen_framebuffer_ops = {
966 e7151f83 aliguori
    .size       = sizeof(struct XenFB),
967 e7151f83 aliguori
    .init       = fb_init,
968 e7151f83 aliguori
    .connect    = fb_connect,
969 e7151f83 aliguori
    .disconnect = fb_disconnect,
970 e7151f83 aliguori
    .event      = fb_event,
971 e7151f83 aliguori
    .frontend_changed = fb_frontend_changed,
972 e7151f83 aliguori
};
973 e7151f83 aliguori
974 e7151f83 aliguori
/*
975 e7151f83 aliguori
 * FIXME/TODO: Kill this.
976 e7151f83 aliguori
 * Temporary needed while DisplayState reorganization is in flight.
977 e7151f83 aliguori
 */
978 e7151f83 aliguori
void xen_init_display(int domid)
979 e7151f83 aliguori
{
980 e7151f83 aliguori
    struct XenDevice *xfb, *xin;
981 e7151f83 aliguori
    struct XenFB *fb;
982 e7151f83 aliguori
    struct XenInput *in;
983 e7151f83 aliguori
    int i = 0;
984 e7151f83 aliguori
985 e7151f83 aliguori
wait_more:
986 e7151f83 aliguori
    i++;
987 e7151f83 aliguori
    main_loop_wait(10); /* miliseconds */
988 e7151f83 aliguori
    xfb = xen_be_find_xendev("vfb", domid, 0);
989 e7151f83 aliguori
    xin = xen_be_find_xendev("vkbd", domid, 0);
990 e7151f83 aliguori
    if (!xfb || !xin) {
991 e7151f83 aliguori
        if (i < 256)
992 e7151f83 aliguori
            goto wait_more;
993 e7151f83 aliguori
        xen_be_printf(NULL, 1, "displaystate setup failed\n");
994 e7151f83 aliguori
        return;
995 e7151f83 aliguori
    }
996 e7151f83 aliguori
997 e7151f83 aliguori
    /* vfb */
998 e7151f83 aliguori
    fb = container_of(xfb, struct XenFB, c.xendev);
999 e7151f83 aliguori
    fb->c.ds = graphic_console_init(xenfb_update,
1000 e7151f83 aliguori
                                    xenfb_invalidate,
1001 e7151f83 aliguori
                                    NULL,
1002 e7151f83 aliguori
                                    NULL,
1003 e7151f83 aliguori
                                    fb);
1004 e7151f83 aliguori
    fb->have_console = 1;
1005 e7151f83 aliguori
1006 e7151f83 aliguori
    /* vkbd */
1007 e7151f83 aliguori
    in = container_of(xin, struct XenInput, c.xendev);
1008 e7151f83 aliguori
    in->c.ds = fb->c.ds;
1009 e7151f83 aliguori
1010 e7151f83 aliguori
    /* retry ->init() */
1011 e7151f83 aliguori
    xen_be_check_state(xin);
1012 e7151f83 aliguori
    xen_be_check_state(xfb);
1013 e7151f83 aliguori
}