root / hw / xenfb.c @ 2afee49f
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 | } |