Statistics
| Branch: | Revision:

root / hw / xenfb.c @ 57c83dac

History | View | Annotate | Download (30.5 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 8167ee88 Blue Swirl
 *  with this program; if not, see <http://www.gnu.org/licenses/>.
25 e7151f83 aliguori
 */
26 e7151f83 aliguori
27 e7151f83 aliguori
#include <stdarg.h>
28 e7151f83 aliguori
#include <stdlib.h>
29 e7151f83 aliguori
#include <sys/types.h>
30 e7151f83 aliguori
#include <fcntl.h>
31 e7151f83 aliguori
#include <unistd.h>
32 e7151f83 aliguori
#include <sys/mman.h>
33 e7151f83 aliguori
#include <errno.h>
34 e7151f83 aliguori
#include <stdio.h>
35 e7151f83 aliguori
#include <string.h>
36 e7151f83 aliguori
#include <time.h>
37 e7151f83 aliguori
38 e7151f83 aliguori
#include <xs.h>
39 e7151f83 aliguori
#include <xenctrl.h>
40 e7151f83 aliguori
#include <xen/event_channel.h>
41 e7151f83 aliguori
#include <xen/io/xenbus.h>
42 e7151f83 aliguori
#include <xen/io/fbif.h>
43 e7151f83 aliguori
#include <xen/io/kbdif.h>
44 e7151f83 aliguori
#include <xen/io/protocols.h>
45 e7151f83 aliguori
46 e7151f83 aliguori
#include "hw.h"
47 e7151f83 aliguori
#include "console.h"
48 e7151f83 aliguori
#include "qemu-char.h"
49 e7151f83 aliguori
#include "xen_backend.h"
50 e7151f83 aliguori
51 e7151f83 aliguori
#ifndef BTN_LEFT
52 e7151f83 aliguori
#define BTN_LEFT 0x110 /* from <linux/input.h> */
53 e7151f83 aliguori
#endif
54 e7151f83 aliguori
55 e7151f83 aliguori
/* -------------------------------------------------------------------- */
56 e7151f83 aliguori
57 e7151f83 aliguori
struct common {
58 e7151f83 aliguori
    struct XenDevice  xendev;  /* must be first */
59 e7151f83 aliguori
    void              *page;
60 e7151f83 aliguori
    DisplayState      *ds;
61 e7151f83 aliguori
};
62 e7151f83 aliguori
63 e7151f83 aliguori
struct XenInput {
64 e7151f83 aliguori
    struct common c;
65 e7151f83 aliguori
    int abs_pointer_wanted; /* Whether guest supports absolute pointer */
66 e7151f83 aliguori
    int button_state;       /* Last seen pointer button state */
67 e7151f83 aliguori
    int extended;
68 e7151f83 aliguori
    QEMUPutMouseEntry *qmouse;
69 e7151f83 aliguori
};
70 e7151f83 aliguori
71 e7151f83 aliguori
#define UP_QUEUE 8
72 e7151f83 aliguori
73 e7151f83 aliguori
struct XenFB {
74 e7151f83 aliguori
    struct common     c;
75 e7151f83 aliguori
    size_t            fb_len;
76 e7151f83 aliguori
    int               row_stride;
77 e7151f83 aliguori
    int               depth;
78 e7151f83 aliguori
    int               width;
79 e7151f83 aliguori
    int               height;
80 e7151f83 aliguori
    int               offset;
81 e7151f83 aliguori
    void              *pixels;
82 e7151f83 aliguori
    int               fbpages;
83 e7151f83 aliguori
    int               feature_update;
84 e7151f83 aliguori
    int               refresh_period;
85 e7151f83 aliguori
    int               bug_trigger;
86 e7151f83 aliguori
    int               have_console;
87 e7151f83 aliguori
    int               do_resize;
88 e7151f83 aliguori
89 e7151f83 aliguori
    struct {
90 e7151f83 aliguori
        int x,y,w,h;
91 e7151f83 aliguori
    } up_rects[UP_QUEUE];
92 e7151f83 aliguori
    int               up_count;
93 e7151f83 aliguori
    int               up_fullscreen;
94 e7151f83 aliguori
};
95 e7151f83 aliguori
96 e7151f83 aliguori
/* -------------------------------------------------------------------- */
97 e7151f83 aliguori
98 e7151f83 aliguori
static int common_bind(struct common *c)
99 e7151f83 aliguori
{
100 e7151f83 aliguori
    int mfn;
101 e7151f83 aliguori
102 e7151f83 aliguori
    if (xenstore_read_fe_int(&c->xendev, "page-ref", &mfn) == -1)
103 e7151f83 aliguori
        return -1;
104 e7151f83 aliguori
    if (xenstore_read_fe_int(&c->xendev, "event-channel", &c->xendev.remote_port) == -1)
105 e7151f83 aliguori
        return -1;
106 e7151f83 aliguori
107 e7151f83 aliguori
    c->page = xc_map_foreign_range(xen_xc, c->xendev.dom,
108 e7151f83 aliguori
                                   XC_PAGE_SIZE,
109 e7151f83 aliguori
                                   PROT_READ | PROT_WRITE, mfn);
110 e7151f83 aliguori
    if (c->page == NULL)
111 e7151f83 aliguori
        return -1;
112 e7151f83 aliguori
113 e7151f83 aliguori
    xen_be_bind_evtchn(&c->xendev);
114 e7151f83 aliguori
    xen_be_printf(&c->xendev, 1, "ring mfn %d, remote-port %d, local-port %d\n",
115 e7151f83 aliguori
                  mfn, c->xendev.remote_port, c->xendev.local_port);
116 e7151f83 aliguori
117 e7151f83 aliguori
    return 0;
118 e7151f83 aliguori
}
119 e7151f83 aliguori
120 e7151f83 aliguori
static void common_unbind(struct common *c)
121 e7151f83 aliguori
{
122 e7151f83 aliguori
    xen_be_unbind_evtchn(&c->xendev);
123 e7151f83 aliguori
    if (c->page) {
124 e7151f83 aliguori
        munmap(c->page, XC_PAGE_SIZE);
125 e7151f83 aliguori
        c->page = NULL;
126 e7151f83 aliguori
    }
127 e7151f83 aliguori
}
128 e7151f83 aliguori
129 e7151f83 aliguori
/* -------------------------------------------------------------------- */
130 e7151f83 aliguori
131 e7151f83 aliguori
#if 0
132 e7151f83 aliguori
/*
133 e7151f83 aliguori
 * These two tables are not needed any more, but left in here
134 e7151f83 aliguori
 * intentionally as documentation, to show how scancode2linux[]
135 e7151f83 aliguori
 * was generated.
136 e7151f83 aliguori
 *
137 e7151f83 aliguori
 * Tables to map from scancode to Linux input layer keycode.
138 e7151f83 aliguori
 * Scancodes are hardware-specific.  These maps assumes a
139 e7151f83 aliguori
 * standard AT or PS/2 keyboard which is what QEMU feeds us.
140 e7151f83 aliguori
 */
141 e7151f83 aliguori
const unsigned char atkbd_set2_keycode[512] = {
142 e7151f83 aliguori

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

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

161 e7151f83 aliguori
};
162 e7151f83 aliguori

163 e7151f83 aliguori
const unsigned char atkbd_unxlate_table[128] = {
164 e7151f83 aliguori

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

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