/[pkg-src]/trunk/kernel26-xen/patches-2.6.25-r1/1005-2.6.25-xen-pvfb-Para-virtual-framebuffer-keyboard-and-poi.patch |
Contents of /trunk/kernel26-xen/patches-2.6.25-r1/1005-2.6.25-xen-pvfb-Para-virtual-framebuffer-keyboard-and-poi.patch
Parent Directory | Revision Log
Revision 606 -
(show annotations)
(download)
Thu May 22 23:13:13 2008 UTC (15 years, 11 months ago) by niro
File size: 34593 byte(s)
Thu May 22 23:13:13 2008 UTC (15 years, 11 months ago) by niro
File size: 34593 byte(s)
-ver bump to 2.6.25-magellan-r1: - linux-2.6.25.4 - fbcondecor-0.9.4 - squashfs-3.3 - unionfs-2.3.3 - tuxonice-3.0-rc7 - linux-phc-0.3.0 - acpi-dstd-0.9a - reiser4 - xen-3.2.0 . ipw3945-1.2.2
1 | From ccda62aeb230f90c48ad54fa17ecc0950a7829b6 Mon Sep 17 00:00:00 2001 |
2 | From: Markus Armbruster <armbru@redhat.com> |
3 | Date: Mon, 25 Feb 2008 14:06:46 +0100 |
4 | Subject: [PATCH] xen pvfb: Para-virtual framebuffer, keyboard and pointer driver |
5 | |
6 | This is a pair of Xen para-virtual frontend device drivers: |
7 | drivers/video/xen-fbfront.c provides a framebuffer, and |
8 | drivers/input/xen-kbdfront provides keyboard and mouse. |
9 | |
10 | The backends run in dom0 user space. |
11 | |
12 | The two drivers are not in two separate patches, because the |
13 | intermediate step (one driver, not the other) is somewhat problematic: |
14 | the backend in dom0 needs both drivers, and will refuse to complete |
15 | device initialization unless they're both present. |
16 | |
17 | Signed-off-by: Markus Armbruster <armbru@redhat.com> |
18 | --- |
19 | drivers/input/Kconfig | 9 + |
20 | drivers/input/Makefile | 2 + |
21 | drivers/input/xen-kbdfront.c | 340 +++++++++++++++++++++++ |
22 | drivers/video/Kconfig | 14 + |
23 | drivers/video/Makefile | 1 + |
24 | drivers/video/xen-fbfront.c | 550 ++++++++++++++++++++++++++++++++++++++ |
25 | include/xen/interface/io/fbif.h | 124 +++++++++ |
26 | include/xen/interface/io/kbdif.h | 114 ++++++++ |
27 | 8 files changed, 1154 insertions(+), 0 deletions(-) |
28 | create mode 100644 drivers/input/xen-kbdfront.c |
29 | create mode 100644 drivers/video/xen-fbfront.c |
30 | create mode 100644 include/xen/interface/io/fbif.h |
31 | create mode 100644 include/xen/interface/io/kbdif.h |
32 | |
33 | diff --git a/drivers/input/Kconfig b/drivers/input/Kconfig |
34 | index d84ac4a..747633c 100644 |
35 | --- a/drivers/input/Kconfig |
36 | +++ b/drivers/input/Kconfig |
37 | @@ -149,6 +149,15 @@ config INPUT_APMPOWER |
38 | To compile this driver as a module, choose M here: the |
39 | module will be called apm-power. |
40 | |
41 | +config XEN_KBDDEV_FRONTEND |
42 | + tristate "Xen virtual keyboard and mouse support" |
43 | + depends on XEN_FBDEV_FRONTEND |
44 | + default y |
45 | + help |
46 | + This driver implements the front-end of the Xen virtual |
47 | + keyboard and mouse device driver. It communicates with a back-end |
48 | + in another domain. |
49 | + |
50 | comment "Input Device Drivers" |
51 | |
52 | source "drivers/input/keyboard/Kconfig" |
53 | diff --git a/drivers/input/Makefile b/drivers/input/Makefile |
54 | index 24bdec1..606e1b9 100644 |
55 | --- a/drivers/input/Makefile |
56 | +++ b/drivers/input/Makefile |
57 | @@ -24,3 +24,5 @@ obj-$(CONFIG_INPUT_MISC) += misc/ |
58 | obj-$(CONFIG_INPUT_LIRC) += lirc/ |
59 | |
60 | obj-$(CONFIG_INPUT_APMPOWER) += apm-power.o |
61 | + |
62 | +obj-$(CONFIG_XEN_KBDDEV_FRONTEND) += xen-kbdfront.o |
63 | diff --git a/drivers/input/xen-kbdfront.c b/drivers/input/xen-kbdfront.c |
64 | new file mode 100644 |
65 | index 0000000..0f47f46 |
66 | --- /dev/null |
67 | +++ b/drivers/input/xen-kbdfront.c |
68 | @@ -0,0 +1,340 @@ |
69 | +/* |
70 | + * Xen para-virtual input device |
71 | + * |
72 | + * Copyright (C) 2005 Anthony Liguori <aliguori@us.ibm.com> |
73 | + * Copyright (C) 2006-2008 Red Hat, Inc., Markus Armbruster <armbru@redhat.com> |
74 | + * |
75 | + * Based on linux/drivers/input/mouse/sermouse.c |
76 | + * |
77 | + * This file is subject to the terms and conditions of the GNU General Public |
78 | + * License. See the file COPYING in the main directory of this archive for |
79 | + * more details. |
80 | + */ |
81 | + |
82 | +/* |
83 | + * TODO: |
84 | + * |
85 | + * Switch to grant tables together with xen-fbfront.c. |
86 | + */ |
87 | + |
88 | +#include <linux/kernel.h> |
89 | +#include <linux/errno.h> |
90 | +#include <linux/module.h> |
91 | +#include <linux/input.h> |
92 | +#include <asm/xen/hypervisor.h> |
93 | +#include <xen/events.h> |
94 | +#include <xen/page.h> |
95 | +#include <xen/interface/io/fbif.h> |
96 | +#include <xen/interface/io/kbdif.h> |
97 | +#include <xen/xenbus.h> |
98 | + |
99 | +struct xenkbd_info { |
100 | + struct input_dev *kbd; |
101 | + struct input_dev *ptr; |
102 | + struct xenkbd_page *page; |
103 | + int irq; |
104 | + struct xenbus_device *xbdev; |
105 | + char phys[32]; |
106 | +}; |
107 | + |
108 | +static int xenkbd_remove(struct xenbus_device *); |
109 | +static int xenkbd_connect_backend(struct xenbus_device *, struct xenkbd_info *); |
110 | +static void xenkbd_disconnect_backend(struct xenkbd_info *); |
111 | + |
112 | +/* |
113 | + * Note: if you need to send out events, see xenfb_do_update() for how |
114 | + * to do that. |
115 | + */ |
116 | + |
117 | +static irqreturn_t input_handler(int rq, void *dev_id) |
118 | +{ |
119 | + struct xenkbd_info *info = dev_id; |
120 | + struct xenkbd_page *page = info->page; |
121 | + __u32 cons, prod; |
122 | + |
123 | + prod = page->in_prod; |
124 | + if (prod == page->in_cons) |
125 | + return IRQ_HANDLED; |
126 | + rmb(); /* ensure we see ring contents up to prod */ |
127 | + for (cons = page->in_cons; cons != prod; cons++) { |
128 | + union xenkbd_in_event *event; |
129 | + struct input_dev *dev; |
130 | + event = &XENKBD_IN_RING_REF(page, cons); |
131 | + |
132 | + dev = info->ptr; |
133 | + switch (event->type) { |
134 | + case XENKBD_TYPE_MOTION: |
135 | + input_report_rel(dev, REL_X, event->motion.rel_x); |
136 | + input_report_rel(dev, REL_Y, event->motion.rel_y); |
137 | + break; |
138 | + case XENKBD_TYPE_KEY: |
139 | + dev = NULL; |
140 | + if (test_bit(event->key.keycode, info->kbd->keybit)) |
141 | + dev = info->kbd; |
142 | + if (test_bit(event->key.keycode, info->ptr->keybit)) |
143 | + dev = info->ptr; |
144 | + if (dev) |
145 | + input_report_key(dev, event->key.keycode, |
146 | + event->key.pressed); |
147 | + else |
148 | + printk(KERN_WARNING |
149 | + "xenkbd: unhandled keycode 0x%x\n", |
150 | + event->key.keycode); |
151 | + break; |
152 | + case XENKBD_TYPE_POS: |
153 | + input_report_abs(dev, ABS_X, event->pos.abs_x); |
154 | + input_report_abs(dev, ABS_Y, event->pos.abs_y); |
155 | + break; |
156 | + } |
157 | + if (dev) |
158 | + input_sync(dev); |
159 | + } |
160 | + mb(); /* ensure we got ring contents */ |
161 | + page->in_cons = cons; |
162 | + notify_remote_via_irq(info->irq); |
163 | + |
164 | + return IRQ_HANDLED; |
165 | +} |
166 | + |
167 | +static int __devinit xenkbd_probe(struct xenbus_device *dev, |
168 | + const struct xenbus_device_id *id) |
169 | +{ |
170 | + int ret, i; |
171 | + struct xenkbd_info *info; |
172 | + struct input_dev *kbd, *ptr; |
173 | + |
174 | + info = kzalloc(sizeof(*info), GFP_KERNEL); |
175 | + if (!info) { |
176 | + xenbus_dev_fatal(dev, -ENOMEM, "allocating info structure"); |
177 | + return -ENOMEM; |
178 | + } |
179 | + dev->dev.driver_data = info; |
180 | + info->xbdev = dev; |
181 | + info->irq = -1; |
182 | + snprintf(info->phys, sizeof(info->phys), "xenbus/%s", dev->nodename); |
183 | + |
184 | + info->page = (void *)__get_free_page(GFP_KERNEL | __GFP_ZERO); |
185 | + if (!info->page) |
186 | + goto error_nomem; |
187 | + |
188 | + /* keyboard */ |
189 | + kbd = input_allocate_device(); |
190 | + if (!kbd) |
191 | + goto error_nomem; |
192 | + kbd->name = "Xen Virtual Keyboard"; |
193 | + kbd->phys = info->phys; |
194 | + kbd->id.bustype = BUS_PCI; |
195 | + kbd->id.vendor = 0x5853; |
196 | + kbd->id.product = 0xffff; |
197 | + kbd->evbit[0] = BIT(EV_KEY); |
198 | + for (i = KEY_ESC; i < KEY_UNKNOWN; i++) |
199 | + set_bit(i, kbd->keybit); |
200 | + for (i = KEY_OK; i < KEY_MAX; i++) |
201 | + set_bit(i, kbd->keybit); |
202 | + |
203 | + ret = input_register_device(kbd); |
204 | + if (ret) { |
205 | + input_free_device(kbd); |
206 | + xenbus_dev_fatal(dev, ret, "input_register_device(kbd)"); |
207 | + goto error; |
208 | + } |
209 | + info->kbd = kbd; |
210 | + |
211 | + /* pointing device */ |
212 | + ptr = input_allocate_device(); |
213 | + if (!ptr) |
214 | + goto error_nomem; |
215 | + ptr->name = "Xen Virtual Pointer"; |
216 | + ptr->phys = info->phys; |
217 | + ptr->id.bustype = BUS_PCI; |
218 | + ptr->id.vendor = 0x5853; |
219 | + ptr->id.product = 0xfffe; |
220 | + ptr->evbit[0] = BIT(EV_KEY) | BIT(EV_REL) | BIT(EV_ABS); |
221 | + for (i = BTN_LEFT; i <= BTN_TASK; i++) |
222 | + set_bit(i, ptr->keybit); |
223 | + ptr->relbit[0] = BIT(REL_X) | BIT(REL_Y); |
224 | + input_set_abs_params(ptr, ABS_X, 0, XENFB_WIDTH, 0, 0); |
225 | + input_set_abs_params(ptr, ABS_Y, 0, XENFB_HEIGHT, 0, 0); |
226 | + |
227 | + ret = input_register_device(ptr); |
228 | + if (ret) { |
229 | + input_free_device(ptr); |
230 | + xenbus_dev_fatal(dev, ret, "input_register_device(ptr)"); |
231 | + goto error; |
232 | + } |
233 | + info->ptr = ptr; |
234 | + |
235 | + ret = xenkbd_connect_backend(dev, info); |
236 | + if (ret < 0) |
237 | + goto error; |
238 | + |
239 | + return 0; |
240 | + |
241 | + error_nomem: |
242 | + ret = -ENOMEM; |
243 | + xenbus_dev_fatal(dev, ret, "allocating device memory"); |
244 | + error: |
245 | + xenkbd_remove(dev); |
246 | + return ret; |
247 | +} |
248 | + |
249 | +static int xenkbd_resume(struct xenbus_device *dev) |
250 | +{ |
251 | + struct xenkbd_info *info = dev->dev.driver_data; |
252 | + |
253 | + xenkbd_disconnect_backend(info); |
254 | + memset(info->page, 0, PAGE_SIZE); |
255 | + return xenkbd_connect_backend(dev, info); |
256 | +} |
257 | + |
258 | +static int xenkbd_remove(struct xenbus_device *dev) |
259 | +{ |
260 | + struct xenkbd_info *info = dev->dev.driver_data; |
261 | + |
262 | + xenkbd_disconnect_backend(info); |
263 | + if (info->kbd) |
264 | + input_unregister_device(info->kbd); |
265 | + if (info->ptr) |
266 | + input_unregister_device(info->ptr); |
267 | + free_page((unsigned long)info->page); |
268 | + kfree(info); |
269 | + return 0; |
270 | +} |
271 | + |
272 | +static int xenkbd_connect_backend(struct xenbus_device *dev, |
273 | + struct xenkbd_info *info) |
274 | +{ |
275 | + int ret, evtchn; |
276 | + struct xenbus_transaction xbt; |
277 | + |
278 | + ret = xenbus_alloc_evtchn(dev, &evtchn); |
279 | + if (ret) |
280 | + return ret; |
281 | + ret = bind_evtchn_to_irqhandler(evtchn, input_handler, |
282 | + 0, dev->devicetype, info); |
283 | + if (ret < 0) { |
284 | + xenbus_free_evtchn(dev, evtchn); |
285 | + xenbus_dev_fatal(dev, ret, "bind_evtchn_to_irqhandler"); |
286 | + return ret; |
287 | + } |
288 | + info->irq = ret; |
289 | + |
290 | + again: |
291 | + ret = xenbus_transaction_start(&xbt); |
292 | + if (ret) { |
293 | + xenbus_dev_fatal(dev, ret, "starting transaction"); |
294 | + return ret; |
295 | + } |
296 | + ret = xenbus_printf(xbt, dev->nodename, "page-ref", "%lu", |
297 | + virt_to_mfn(info->page)); |
298 | + if (ret) |
299 | + goto error_xenbus; |
300 | + ret = xenbus_printf(xbt, dev->nodename, "event-channel", "%u", |
301 | + evtchn); |
302 | + if (ret) |
303 | + goto error_xenbus; |
304 | + ret = xenbus_transaction_end(xbt, 0); |
305 | + if (ret) { |
306 | + if (ret == -EAGAIN) |
307 | + goto again; |
308 | + xenbus_dev_fatal(dev, ret, "completing transaction"); |
309 | + return ret; |
310 | + } |
311 | + |
312 | + xenbus_switch_state(dev, XenbusStateInitialised); |
313 | + return 0; |
314 | + |
315 | + error_xenbus: |
316 | + xenbus_transaction_end(xbt, 1); |
317 | + xenbus_dev_fatal(dev, ret, "writing xenstore"); |
318 | + return ret; |
319 | +} |
320 | + |
321 | +static void xenkbd_disconnect_backend(struct xenkbd_info *info) |
322 | +{ |
323 | + if (info->irq >= 0) |
324 | + unbind_from_irqhandler(info->irq, info); |
325 | + info->irq = -1; |
326 | +} |
327 | + |
328 | +static void xenkbd_backend_changed(struct xenbus_device *dev, |
329 | + enum xenbus_state backend_state) |
330 | +{ |
331 | + struct xenkbd_info *info = dev->dev.driver_data; |
332 | + int ret, val; |
333 | + |
334 | + switch (backend_state) { |
335 | + case XenbusStateInitialising: |
336 | + case XenbusStateInitialised: |
337 | + case XenbusStateUnknown: |
338 | + case XenbusStateClosed: |
339 | + break; |
340 | + |
341 | + case XenbusStateInitWait: |
342 | +InitWait: |
343 | + ret = xenbus_scanf(XBT_NIL, info->xbdev->otherend, |
344 | + "feature-abs-pointer", "%d", &val); |
345 | + if (ret < 0) |
346 | + val = 0; |
347 | + if (val) { |
348 | + ret = xenbus_printf(XBT_NIL, info->xbdev->nodename, |
349 | + "request-abs-pointer", "1"); |
350 | + if (ret) |
351 | + printk(KERN_WARNING |
352 | + "xenkbd: can't request abs-pointer"); |
353 | + } |
354 | + xenbus_switch_state(dev, XenbusStateConnected); |
355 | + break; |
356 | + |
357 | + case XenbusStateConnected: |
358 | + /* |
359 | + * Work around xenbus race condition: If backend goes |
360 | + * through InitWait to Connected fast enough, we can |
361 | + * get Connected twice here. |
362 | + */ |
363 | + if (dev->state != XenbusStateConnected) |
364 | + goto InitWait; /* no InitWait seen yet, fudge it */ |
365 | + break; |
366 | + |
367 | + case XenbusStateClosing: |
368 | + xenbus_frontend_closed(dev); |
369 | + break; |
370 | + } |
371 | +} |
372 | + |
373 | +static struct xenbus_device_id xenkbd_ids[] = { |
374 | + { "vkbd" }, |
375 | + { "" } |
376 | +}; |
377 | + |
378 | +static struct xenbus_driver xenkbd = { |
379 | + .name = "vkbd", |
380 | + .owner = THIS_MODULE, |
381 | + .ids = xenkbd_ids, |
382 | + .probe = xenkbd_probe, |
383 | + .remove = xenkbd_remove, |
384 | + .resume = xenkbd_resume, |
385 | + .otherend_changed = xenkbd_backend_changed, |
386 | +}; |
387 | + |
388 | +static int __init xenkbd_init(void) |
389 | +{ |
390 | + if (!is_running_on_xen()) |
391 | + return -ENODEV; |
392 | + |
393 | + /* Nothing to do if running in dom0. */ |
394 | + if (is_initial_xendomain()) |
395 | + return -ENODEV; |
396 | + |
397 | + return xenbus_register_frontend(&xenkbd); |
398 | +} |
399 | + |
400 | +static void __exit xenkbd_cleanup(void) |
401 | +{ |
402 | + xenbus_unregister_driver(&xenkbd); |
403 | +} |
404 | + |
405 | +module_init(xenkbd_init); |
406 | +module_exit(xenkbd_cleanup); |
407 | + |
408 | +MODULE_LICENSE("GPL"); |
409 | diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig |
410 | index 474c375..fa65342 100644 |
411 | --- a/drivers/video/Kconfig |
412 | +++ b/drivers/video/Kconfig |
413 | @@ -1921,6 +1921,20 @@ config FB_VIRTUAL |
414 | |
415 | If unsure, say N. |
416 | |
417 | +config XEN_FBDEV_FRONTEND |
418 | + tristate "Xen virtual frame buffer support" |
419 | + depends on FB && XEN |
420 | + select FB_SYS_FILLRECT |
421 | + select FB_SYS_COPYAREA |
422 | + select FB_SYS_IMAGEBLIT |
423 | + select FB_SYS_FOPS |
424 | + select FB_DEFERRED_IO |
425 | + default y |
426 | + help |
427 | + This driver implements the front-end of the Xen virtual |
428 | + frame buffer driver. It communicates with a back-end |
429 | + in another domain. |
430 | + |
431 | source "drivers/video/omap/Kconfig" |
432 | |
433 | source "drivers/video/backlight/Kconfig" |
434 | diff --git a/drivers/video/Makefile b/drivers/video/Makefile |
435 | index c789b01..48f7fd3 100644 |
436 | --- a/drivers/video/Makefile |
437 | +++ b/drivers/video/Makefile |
438 | @@ -114,6 +114,7 @@ obj-$(CONFIG_FB_PS3) += ps3fb.o |
439 | obj-$(CONFIG_FB_SM501) += sm501fb.o |
440 | obj-$(CONFIG_FB_XILINX) += xilinxfb.o |
441 | obj-$(CONFIG_FB_OMAP) += omap/ |
442 | +obj-$(CONFIG_XEN_FBDEV_FRONTEND) += xen-fbfront.o |
443 | |
444 | # Platform or fallback drivers go here |
445 | obj-$(CONFIG_FB_UVESA) += uvesafb.o |
446 | diff --git a/drivers/video/xen-fbfront.c b/drivers/video/xen-fbfront.c |
447 | new file mode 100644 |
448 | index 0000000..619a6f8 |
449 | --- /dev/null |
450 | +++ b/drivers/video/xen-fbfront.c |
451 | @@ -0,0 +1,550 @@ |
452 | +/* |
453 | + * Xen para-virtual frame buffer device |
454 | + * |
455 | + * Copyright (C) 2005-2006 Anthony Liguori <aliguori@us.ibm.com> |
456 | + * Copyright (C) 2006-2008 Red Hat, Inc., Markus Armbruster <armbru@redhat.com> |
457 | + * |
458 | + * Based on linux/drivers/video/q40fb.c |
459 | + * |
460 | + * This file is subject to the terms and conditions of the GNU General Public |
461 | + * License. See the file COPYING in the main directory of this archive for |
462 | + * more details. |
463 | + */ |
464 | + |
465 | +/* |
466 | + * TODO: |
467 | + * |
468 | + * Switch to grant tables when they become capable of dealing with the |
469 | + * frame buffer. |
470 | + */ |
471 | + |
472 | +#include <linux/kernel.h> |
473 | +#include <linux/errno.h> |
474 | +#include <linux/fb.h> |
475 | +#include <linux/module.h> |
476 | +#include <linux/vmalloc.h> |
477 | +#include <linux/mm.h> |
478 | +#include <asm/xen/hypervisor.h> |
479 | +#include <xen/events.h> |
480 | +#include <xen/page.h> |
481 | +#include <xen/interface/io/fbif.h> |
482 | +#include <xen/interface/io/protocols.h> |
483 | +#include <xen/xenbus.h> |
484 | + |
485 | +struct xenfb_info { |
486 | + unsigned char *fb; |
487 | + struct fb_info *fb_info; |
488 | + int x1, y1, x2, y2; /* dirty rectangle, |
489 | + protected by dirty_lock */ |
490 | + spinlock_t dirty_lock; |
491 | + int nr_pages; |
492 | + int irq; |
493 | + struct xenfb_page *page; |
494 | + unsigned long *mfns; |
495 | + int update_wanted; /* XENFB_TYPE_UPDATE wanted */ |
496 | + |
497 | + struct xenbus_device *xbdev; |
498 | +}; |
499 | + |
500 | +static u32 xenfb_mem_len = XENFB_WIDTH * XENFB_HEIGHT * XENFB_DEPTH / 8; |
501 | + |
502 | +static int xenfb_remove(struct xenbus_device *); |
503 | +static void xenfb_init_shared_page(struct xenfb_info *); |
504 | +static int xenfb_connect_backend(struct xenbus_device *, struct xenfb_info *); |
505 | +static void xenfb_disconnect_backend(struct xenfb_info *); |
506 | + |
507 | +static void xenfb_do_update(struct xenfb_info *info, |
508 | + int x, int y, int w, int h) |
509 | +{ |
510 | + union xenfb_out_event event; |
511 | + u32 prod; |
512 | + |
513 | + event.type = XENFB_TYPE_UPDATE; |
514 | + event.update.x = x; |
515 | + event.update.y = y; |
516 | + event.update.width = w; |
517 | + event.update.height = h; |
518 | + |
519 | + prod = info->page->out_prod; |
520 | + /* caller ensures !xenfb_queue_full() */ |
521 | + mb(); /* ensure ring space available */ |
522 | + XENFB_OUT_RING_REF(info->page, prod) = event; |
523 | + wmb(); /* ensure ring contents visible */ |
524 | + info->page->out_prod = prod + 1; |
525 | + |
526 | + notify_remote_via_irq(info->irq); |
527 | +} |
528 | + |
529 | +static int xenfb_queue_full(struct xenfb_info *info) |
530 | +{ |
531 | + u32 cons, prod; |
532 | + |
533 | + prod = info->page->out_prod; |
534 | + cons = info->page->out_cons; |
535 | + return prod - cons == XENFB_OUT_RING_LEN; |
536 | +} |
537 | + |
538 | +static void xenfb_refresh(struct xenfb_info *info, |
539 | + int x1, int y1, int w, int h) |
540 | +{ |
541 | + unsigned long flags; |
542 | + int y2 = y1 + h - 1; |
543 | + int x2 = x1 + w - 1; |
544 | + |
545 | + if (!info->update_wanted) |
546 | + return; |
547 | + |
548 | + spin_lock_irqsave(&info->dirty_lock, flags); |
549 | + |
550 | + /* Combine with dirty rectangle: */ |
551 | + if (info->y1 < y1) |
552 | + y1 = info->y1; |
553 | + if (info->y2 > y2) |
554 | + y2 = info->y2; |
555 | + if (info->x1 < x1) |
556 | + x1 = info->x1; |
557 | + if (info->x2 > x2) |
558 | + x2 = info->x2; |
559 | + |
560 | + if (xenfb_queue_full(info)) { |
561 | + /* Can't send right now, stash it in the dirty rectangle */ |
562 | + info->x1 = x1; |
563 | + info->x2 = x2; |
564 | + info->y1 = y1; |
565 | + info->y2 = y2; |
566 | + spin_unlock_irqrestore(&info->dirty_lock, flags); |
567 | + return; |
568 | + } |
569 | + |
570 | + /* Clear dirty rectangle: */ |
571 | + info->x1 = info->y1 = INT_MAX; |
572 | + info->x2 = info->y2 = 0; |
573 | + |
574 | + spin_unlock_irqrestore(&info->dirty_lock, flags); |
575 | + |
576 | + if (x1 <= x2 && y1 <= y2) |
577 | + xenfb_do_update(info, x1, y1, x2 - x1 + 1, y2 - y1 + 1); |
578 | +} |
579 | + |
580 | +static void xenfb_deferred_io(struct fb_info *fb_info, |
581 | + struct list_head *pagelist) |
582 | +{ |
583 | + struct xenfb_info *info = fb_info->par; |
584 | + struct page *page; |
585 | + unsigned long beg, end; |
586 | + int y1, y2, miny, maxy; |
587 | + |
588 | + miny = INT_MAX; |
589 | + maxy = 0; |
590 | + list_for_each_entry(page, pagelist, lru) { |
591 | + beg = page->index << PAGE_SHIFT; |
592 | + end = beg + PAGE_SIZE - 1; |
593 | + y1 = beg / fb_info->fix.line_length; |
594 | + y2 = end / fb_info->fix.line_length; |
595 | + if (y2 >= fb_info->var.yres) |
596 | + y2 = fb_info->var.yres - 1; |
597 | + if (miny > y1) |
598 | + miny = y1; |
599 | + if (maxy < y2) |
600 | + maxy = y2; |
601 | + } |
602 | + xenfb_refresh(info, 0, miny, fb_info->var.xres, maxy - miny + 1); |
603 | +} |
604 | + |
605 | +static struct fb_deferred_io xenfb_defio = { |
606 | + .delay = HZ / 20, |
607 | + .deferred_io = xenfb_deferred_io, |
608 | +}; |
609 | + |
610 | +static int xenfb_setcolreg(unsigned regno, unsigned red, unsigned green, |
611 | + unsigned blue, unsigned transp, |
612 | + struct fb_info *info) |
613 | +{ |
614 | + u32 v; |
615 | + |
616 | + if (regno > info->cmap.len) |
617 | + return 1; |
618 | + |
619 | +#define CNVT_TOHW(val, width) ((((val)<<(width))+0x7FFF-(val))>>16) |
620 | + red = CNVT_TOHW(red, info->var.red.length); |
621 | + green = CNVT_TOHW(green, info->var.green.length); |
622 | + blue = CNVT_TOHW(blue, info->var.blue.length); |
623 | + transp = CNVT_TOHW(transp, info->var.transp.length); |
624 | +#undef CNVT_TOHW |
625 | + |
626 | + v = (red << info->var.red.offset) | |
627 | + (green << info->var.green.offset) | |
628 | + (blue << info->var.blue.offset); |
629 | + |
630 | + switch (info->var.bits_per_pixel) { |
631 | + case 16: |
632 | + case 24: |
633 | + case 32: |
634 | + ((u32 *)info->pseudo_palette)[regno] = v; |
635 | + break; |
636 | + } |
637 | + |
638 | + return 0; |
639 | +} |
640 | + |
641 | +static void xenfb_fillrect(struct fb_info *p, const struct fb_fillrect *rect) |
642 | +{ |
643 | + struct xenfb_info *info = p->par; |
644 | + |
645 | + sys_fillrect(p, rect); |
646 | + xenfb_refresh(info, rect->dx, rect->dy, rect->width, rect->height); |
647 | +} |
648 | + |
649 | +static void xenfb_imageblit(struct fb_info *p, const struct fb_image *image) |
650 | +{ |
651 | + struct xenfb_info *info = p->par; |
652 | + |
653 | + sys_imageblit(p, image); |
654 | + xenfb_refresh(info, image->dx, image->dy, image->width, image->height); |
655 | +} |
656 | + |
657 | +static void xenfb_copyarea(struct fb_info *p, const struct fb_copyarea *area) |
658 | +{ |
659 | + struct xenfb_info *info = p->par; |
660 | + |
661 | + sys_copyarea(p, area); |
662 | + xenfb_refresh(info, area->dx, area->dy, area->width, area->height); |
663 | +} |
664 | + |
665 | +static ssize_t xenfb_write(struct fb_info *p, const char __user *buf, |
666 | + size_t count, loff_t *ppos) |
667 | +{ |
668 | + struct xenfb_info *info = p->par; |
669 | + ssize_t res; |
670 | + |
671 | + res = fb_sys_write(p, buf, count, ppos); |
672 | + xenfb_refresh(info, 0, 0, info->page->width, info->page->height); |
673 | + return res; |
674 | +} |
675 | + |
676 | +static struct fb_ops xenfb_fb_ops = { |
677 | + .owner = THIS_MODULE, |
678 | + .fb_read = fb_sys_read, |
679 | + .fb_write = xenfb_write, |
680 | + .fb_setcolreg = xenfb_setcolreg, |
681 | + .fb_fillrect = xenfb_fillrect, |
682 | + .fb_copyarea = xenfb_copyarea, |
683 | + .fb_imageblit = xenfb_imageblit, |
684 | +}; |
685 | + |
686 | +static irqreturn_t xenfb_event_handler(int rq, void *dev_id) |
687 | +{ |
688 | + /* |
689 | + * No in events recognized, simply ignore them all. |
690 | + * If you need to recognize some, see xen-kbdfront's |
691 | + * input_handler() for how to do that. |
692 | + */ |
693 | + struct xenfb_info *info = dev_id; |
694 | + struct xenfb_page *page = info->page; |
695 | + |
696 | + if (page->in_cons != page->in_prod) { |
697 | + info->page->in_cons = info->page->in_prod; |
698 | + notify_remote_via_irq(info->irq); |
699 | + } |
700 | + |
701 | + /* Flush dirty rectangle: */ |
702 | + xenfb_refresh(info, INT_MAX, INT_MAX, -INT_MAX, -INT_MAX); |
703 | + |
704 | + return IRQ_HANDLED; |
705 | +} |
706 | + |
707 | +static int __devinit xenfb_probe(struct xenbus_device *dev, |
708 | + const struct xenbus_device_id *id) |
709 | +{ |
710 | + struct xenfb_info *info; |
711 | + struct fb_info *fb_info; |
712 | + int ret; |
713 | + |
714 | + info = kzalloc(sizeof(*info), GFP_KERNEL); |
715 | + if (info == NULL) { |
716 | + xenbus_dev_fatal(dev, -ENOMEM, "allocating info structure"); |
717 | + return -ENOMEM; |
718 | + } |
719 | + dev->dev.driver_data = info; |
720 | + info->xbdev = dev; |
721 | + info->irq = -1; |
722 | + info->x1 = info->y1 = INT_MAX; |
723 | + spin_lock_init(&info->dirty_lock); |
724 | + |
725 | + info->fb = vmalloc(xenfb_mem_len); |
726 | + if (info->fb == NULL) |
727 | + goto error_nomem; |
728 | + memset(info->fb, 0, xenfb_mem_len); |
729 | + |
730 | + info->nr_pages = (xenfb_mem_len + PAGE_SIZE - 1) >> PAGE_SHIFT; |
731 | + |
732 | + info->mfns = vmalloc(sizeof(unsigned long) * info->nr_pages); |
733 | + if (!info->mfns) |
734 | + goto error_nomem; |
735 | + |
736 | + /* set up shared page */ |
737 | + info->page = (void *)__get_free_page(GFP_KERNEL | __GFP_ZERO); |
738 | + if (!info->page) |
739 | + goto error_nomem; |
740 | + |
741 | + xenfb_init_shared_page(info); |
742 | + |
743 | + /* abusing framebuffer_alloc() to allocate pseudo_palette */ |
744 | + fb_info = framebuffer_alloc(sizeof(u32) * 256, NULL); |
745 | + if (fb_info == NULL) |
746 | + goto error_nomem; |
747 | + |
748 | + /* complete the abuse: */ |
749 | + fb_info->pseudo_palette = fb_info->par; |
750 | + fb_info->par = info; |
751 | + |
752 | + fb_info->screen_base = info->fb; |
753 | + |
754 | + fb_info->fbops = &xenfb_fb_ops; |
755 | + fb_info->var.xres_virtual = fb_info->var.xres = info->page->width; |
756 | + fb_info->var.yres_virtual = fb_info->var.yres = info->page->height; |
757 | + fb_info->var.bits_per_pixel = info->page->depth; |
758 | + |
759 | + fb_info->var.red = (struct fb_bitfield){16, 8, 0}; |
760 | + fb_info->var.green = (struct fb_bitfield){8, 8, 0}; |
761 | + fb_info->var.blue = (struct fb_bitfield){0, 8, 0}; |
762 | + |
763 | + fb_info->var.activate = FB_ACTIVATE_NOW; |
764 | + fb_info->var.height = -1; |
765 | + fb_info->var.width = -1; |
766 | + fb_info->var.vmode = FB_VMODE_NONINTERLACED; |
767 | + |
768 | + fb_info->fix.visual = FB_VISUAL_TRUECOLOR; |
769 | + fb_info->fix.line_length = info->page->line_length; |
770 | + fb_info->fix.smem_start = 0; |
771 | + fb_info->fix.smem_len = xenfb_mem_len; |
772 | + strcpy(fb_info->fix.id, "xen"); |
773 | + fb_info->fix.type = FB_TYPE_PACKED_PIXELS; |
774 | + fb_info->fix.accel = FB_ACCEL_NONE; |
775 | + |
776 | + fb_info->flags = FBINFO_FLAG_DEFAULT; |
777 | + |
778 | + ret = fb_alloc_cmap(&fb_info->cmap, 256, 0); |
779 | + if (ret < 0) { |
780 | + framebuffer_release(fb_info); |
781 | + xenbus_dev_fatal(dev, ret, "fb_alloc_cmap"); |
782 | + goto error; |
783 | + } |
784 | + |
785 | + fb_info->fbdefio = &xenfb_defio; |
786 | + fb_deferred_io_init(fb_info); |
787 | + |
788 | + ret = register_framebuffer(fb_info); |
789 | + if (ret) { |
790 | + fb_deferred_io_cleanup(fb_info); |
791 | + fb_dealloc_cmap(&fb_info->cmap); |
792 | + framebuffer_release(fb_info); |
793 | + xenbus_dev_fatal(dev, ret, "register_framebuffer"); |
794 | + goto error; |
795 | + } |
796 | + info->fb_info = fb_info; |
797 | + |
798 | + ret = xenfb_connect_backend(dev, info); |
799 | + if (ret < 0) |
800 | + goto error; |
801 | + |
802 | + return 0; |
803 | + |
804 | + error_nomem: |
805 | + ret = -ENOMEM; |
806 | + xenbus_dev_fatal(dev, ret, "allocating device memory"); |
807 | + error: |
808 | + xenfb_remove(dev); |
809 | + return ret; |
810 | +} |
811 | + |
812 | +static int xenfb_resume(struct xenbus_device *dev) |
813 | +{ |
814 | + struct xenfb_info *info = dev->dev.driver_data; |
815 | + |
816 | + xenfb_disconnect_backend(info); |
817 | + xenfb_init_shared_page(info); |
818 | + return xenfb_connect_backend(dev, info); |
819 | +} |
820 | + |
821 | +static int xenfb_remove(struct xenbus_device *dev) |
822 | +{ |
823 | + struct xenfb_info *info = dev->dev.driver_data; |
824 | + |
825 | + xenfb_disconnect_backend(info); |
826 | + if (info->fb_info) { |
827 | + fb_deferred_io_cleanup(info->fb_info); |
828 | + unregister_framebuffer(info->fb_info); |
829 | + fb_dealloc_cmap(&info->fb_info->cmap); |
830 | + framebuffer_release(info->fb_info); |
831 | + } |
832 | + free_page((unsigned long)info->page); |
833 | + vfree(info->mfns); |
834 | + vfree(info->fb); |
835 | + kfree(info); |
836 | + |
837 | + return 0; |
838 | +} |
839 | + |
840 | +static unsigned long vmalloc_to_mfn(void *address) |
841 | +{ |
842 | + return pfn_to_mfn(vmalloc_to_pfn(address)); |
843 | +} |
844 | + |
845 | +static void xenfb_init_shared_page(struct xenfb_info *info) |
846 | +{ |
847 | + int i; |
848 | + |
849 | + for (i = 0; i < info->nr_pages; i++) |
850 | + info->mfns[i] = vmalloc_to_mfn(info->fb + i * PAGE_SIZE); |
851 | + |
852 | + info->page->pd[0] = vmalloc_to_mfn(info->mfns); |
853 | + info->page->pd[1] = 0; |
854 | + info->page->width = XENFB_WIDTH; |
855 | + info->page->height = XENFB_HEIGHT; |
856 | + info->page->depth = XENFB_DEPTH; |
857 | + info->page->line_length = (info->page->depth / 8) * info->page->width; |
858 | + info->page->mem_length = xenfb_mem_len; |
859 | + info->page->in_cons = info->page->in_prod = 0; |
860 | + info->page->out_cons = info->page->out_prod = 0; |
861 | +} |
862 | + |
863 | +static int xenfb_connect_backend(struct xenbus_device *dev, |
864 | + struct xenfb_info *info) |
865 | +{ |
866 | + int ret, evtchn; |
867 | + struct xenbus_transaction xbt; |
868 | + |
869 | + ret = xenbus_alloc_evtchn(dev, &evtchn); |
870 | + if (ret) |
871 | + return ret; |
872 | + ret = bind_evtchn_to_irqhandler(evtchn, xenfb_event_handler, |
873 | + 0, dev->devicetype, info); |
874 | + if (ret < 0) { |
875 | + xenbus_free_evtchn(dev, evtchn); |
876 | + xenbus_dev_fatal(dev, ret, "bind_evtchn_to_irqhandler"); |
877 | + return ret; |
878 | + } |
879 | + info->irq = ret; |
880 | + |
881 | + again: |
882 | + ret = xenbus_transaction_start(&xbt); |
883 | + if (ret) { |
884 | + xenbus_dev_fatal(dev, ret, "starting transaction"); |
885 | + return ret; |
886 | + } |
887 | + ret = xenbus_printf(xbt, dev->nodename, "page-ref", "%lu", |
888 | + virt_to_mfn(info->page)); |
889 | + if (ret) |
890 | + goto error_xenbus; |
891 | + ret = xenbus_printf(xbt, dev->nodename, "event-channel", "%u", |
892 | + evtchn); |
893 | + if (ret) |
894 | + goto error_xenbus; |
895 | + ret = xenbus_printf(xbt, dev->nodename, "protocol", "%s", |
896 | + XEN_IO_PROTO_ABI_NATIVE); |
897 | + if (ret) |
898 | + goto error_xenbus; |
899 | + ret = xenbus_printf(xbt, dev->nodename, "feature-update", "1"); |
900 | + if (ret) |
901 | + goto error_xenbus; |
902 | + ret = xenbus_transaction_end(xbt, 0); |
903 | + if (ret) { |
904 | + if (ret == -EAGAIN) |
905 | + goto again; |
906 | + xenbus_dev_fatal(dev, ret, "completing transaction"); |
907 | + return ret; |
908 | + } |
909 | + |
910 | + xenbus_switch_state(dev, XenbusStateInitialised); |
911 | + return 0; |
912 | + |
913 | + error_xenbus: |
914 | + xenbus_transaction_end(xbt, 1); |
915 | + xenbus_dev_fatal(dev, ret, "writing xenstore"); |
916 | + return ret; |
917 | +} |
918 | + |
919 | +static void xenfb_disconnect_backend(struct xenfb_info *info) |
920 | +{ |
921 | + if (info->irq >= 0) |
922 | + unbind_from_irqhandler(info->irq, info); |
923 | + info->irq = -1; |
924 | +} |
925 | + |
926 | +static void xenfb_backend_changed(struct xenbus_device *dev, |
927 | + enum xenbus_state backend_state) |
928 | +{ |
929 | + struct xenfb_info *info = dev->dev.driver_data; |
930 | + int val; |
931 | + |
932 | + switch (backend_state) { |
933 | + case XenbusStateInitialising: |
934 | + case XenbusStateInitialised: |
935 | + case XenbusStateUnknown: |
936 | + case XenbusStateClosed: |
937 | + break; |
938 | + |
939 | + case XenbusStateInitWait: |
940 | +InitWait: |
941 | + xenbus_switch_state(dev, XenbusStateConnected); |
942 | + break; |
943 | + |
944 | + case XenbusStateConnected: |
945 | + /* |
946 | + * Work around xenbus race condition: If backend goes |
947 | + * through InitWait to Connected fast enough, we can |
948 | + * get Connected twice here. |
949 | + */ |
950 | + if (dev->state != XenbusStateConnected) |
951 | + goto InitWait; /* no InitWait seen yet, fudge it */ |
952 | + |
953 | + if (xenbus_scanf(XBT_NIL, info->xbdev->otherend, |
954 | + "request-update", "%d", &val) < 0) |
955 | + val = 0; |
956 | + if (val) |
957 | + info->update_wanted = 1; |
958 | + break; |
959 | + |
960 | + case XenbusStateClosing: |
961 | + xenbus_frontend_closed(dev); |
962 | + break; |
963 | + } |
964 | +} |
965 | + |
966 | +static struct xenbus_device_id xenfb_ids[] = { |
967 | + { "vfb" }, |
968 | + { "" } |
969 | +}; |
970 | + |
971 | +static struct xenbus_driver xenfb = { |
972 | + .name = "vfb", |
973 | + .owner = THIS_MODULE, |
974 | + .ids = xenfb_ids, |
975 | + .probe = xenfb_probe, |
976 | + .remove = xenfb_remove, |
977 | + .resume = xenfb_resume, |
978 | + .otherend_changed = xenfb_backend_changed, |
979 | +}; |
980 | + |
981 | +static int __init xenfb_init(void) |
982 | +{ |
983 | + if (!is_running_on_xen()) |
984 | + return -ENODEV; |
985 | + |
986 | + /* Nothing to do if running in dom0. */ |
987 | + if (is_initial_xendomain()) |
988 | + return -ENODEV; |
989 | + |
990 | + return xenbus_register_frontend(&xenfb); |
991 | +} |
992 | + |
993 | +static void __exit xenfb_cleanup(void) |
994 | +{ |
995 | + xenbus_unregister_driver(&xenfb); |
996 | +} |
997 | + |
998 | +module_init(xenfb_init); |
999 | +module_exit(xenfb_cleanup); |
1000 | + |
1001 | +MODULE_LICENSE("GPL"); |
1002 | diff --git a/include/xen/interface/io/fbif.h b/include/xen/interface/io/fbif.h |
1003 | new file mode 100644 |
1004 | index 0000000..5a934dd |
1005 | --- /dev/null |
1006 | +++ b/include/xen/interface/io/fbif.h |
1007 | @@ -0,0 +1,124 @@ |
1008 | +/* |
1009 | + * fbif.h -- Xen virtual frame buffer device |
1010 | + * |
1011 | + * Permission is hereby granted, free of charge, to any person obtaining a copy |
1012 | + * of this software and associated documentation files (the "Software"), to |
1013 | + * deal in the Software without restriction, including without limitation the |
1014 | + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or |
1015 | + * sell copies of the Software, and to permit persons to whom the Software is |
1016 | + * furnished to do so, subject to the following conditions: |
1017 | + * |
1018 | + * The above copyright notice and this permission notice shall be included in |
1019 | + * all copies or substantial portions of the Software. |
1020 | + * |
1021 | + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
1022 | + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
1023 | + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
1024 | + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
1025 | + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING |
1026 | + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER |
1027 | + * DEALINGS IN THE SOFTWARE. |
1028 | + * |
1029 | + * Copyright (C) 2005 Anthony Liguori <aliguori@us.ibm.com> |
1030 | + * Copyright (C) 2006 Red Hat, Inc., Markus Armbruster <armbru@redhat.com> |
1031 | + */ |
1032 | + |
1033 | +#ifndef __XEN_PUBLIC_IO_FBIF_H__ |
1034 | +#define __XEN_PUBLIC_IO_FBIF_H__ |
1035 | + |
1036 | +/* Out events (frontend -> backend) */ |
1037 | + |
1038 | +/* |
1039 | + * Out events may be sent only when requested by backend, and receipt |
1040 | + * of an unknown out event is an error. |
1041 | + */ |
1042 | + |
1043 | +/* Event type 1 currently not used */ |
1044 | +/* |
1045 | + * Framebuffer update notification event |
1046 | + * Capable frontend sets feature-update in xenstore. |
1047 | + * Backend requests it by setting request-update in xenstore. |
1048 | + */ |
1049 | +#define XENFB_TYPE_UPDATE 2 |
1050 | + |
1051 | +struct xenfb_update { |
1052 | + uint8_t type; /* XENFB_TYPE_UPDATE */ |
1053 | + int32_t x; /* source x */ |
1054 | + int32_t y; /* source y */ |
1055 | + int32_t width; /* rect width */ |
1056 | + int32_t height; /* rect height */ |
1057 | +}; |
1058 | + |
1059 | +#define XENFB_OUT_EVENT_SIZE 40 |
1060 | + |
1061 | +union xenfb_out_event { |
1062 | + uint8_t type; |
1063 | + struct xenfb_update update; |
1064 | + char pad[XENFB_OUT_EVENT_SIZE]; |
1065 | +}; |
1066 | + |
1067 | +/* In events (backend -> frontend) */ |
1068 | + |
1069 | +/* |
1070 | + * Frontends should ignore unknown in events. |
1071 | + * No in events currently defined. |
1072 | + */ |
1073 | + |
1074 | +#define XENFB_IN_EVENT_SIZE 40 |
1075 | + |
1076 | +union xenfb_in_event { |
1077 | + uint8_t type; |
1078 | + char pad[XENFB_IN_EVENT_SIZE]; |
1079 | +}; |
1080 | + |
1081 | +/* shared page */ |
1082 | + |
1083 | +#define XENFB_IN_RING_SIZE 1024 |
1084 | +#define XENFB_IN_RING_LEN (XENFB_IN_RING_SIZE / XENFB_IN_EVENT_SIZE) |
1085 | +#define XENFB_IN_RING_OFFS 1024 |
1086 | +#define XENFB_IN_RING(page) \ |
1087 | + ((union xenfb_in_event *)((char *)(page) + XENFB_IN_RING_OFFS)) |
1088 | +#define XENFB_IN_RING_REF(page, idx) \ |
1089 | + (XENFB_IN_RING((page))[(idx) % XENFB_IN_RING_LEN]) |
1090 | + |
1091 | +#define XENFB_OUT_RING_SIZE 2048 |
1092 | +#define XENFB_OUT_RING_LEN (XENFB_OUT_RING_SIZE / XENFB_OUT_EVENT_SIZE) |
1093 | +#define XENFB_OUT_RING_OFFS (XENFB_IN_RING_OFFS + XENFB_IN_RING_SIZE) |
1094 | +#define XENFB_OUT_RING(page) \ |
1095 | + ((union xenfb_out_event *)((char *)(page) + XENFB_OUT_RING_OFFS)) |
1096 | +#define XENFB_OUT_RING_REF(page, idx) \ |
1097 | + (XENFB_OUT_RING((page))[(idx) % XENFB_OUT_RING_LEN]) |
1098 | + |
1099 | +struct xenfb_page { |
1100 | + uint32_t in_cons, in_prod; |
1101 | + uint32_t out_cons, out_prod; |
1102 | + |
1103 | + int32_t width; /* width of the framebuffer (in pixels) */ |
1104 | + int32_t height; /* height of the framebuffer (in pixels) */ |
1105 | + uint32_t line_length; /* length of a row of pixels (in bytes) */ |
1106 | + uint32_t mem_length; /* length of the framebuffer (in bytes) */ |
1107 | + uint8_t depth; /* depth of a pixel (in bits) */ |
1108 | + |
1109 | + /* |
1110 | + * Framebuffer page directory |
1111 | + * |
1112 | + * Each directory page holds PAGE_SIZE / sizeof(*pd) |
1113 | + * framebuffer pages, and can thus map up to PAGE_SIZE * |
1114 | + * PAGE_SIZE / sizeof(*pd) bytes. With PAGE_SIZE == 4096 and |
1115 | + * sizeof(unsigned long) == 4, that's 4 Megs. Two directory |
1116 | + * pages should be enough for a while. |
1117 | + */ |
1118 | + unsigned long pd[2]; |
1119 | +}; |
1120 | + |
1121 | +/* |
1122 | + * Wart: xenkbd needs to know resolution. Put it here until a better |
1123 | + * solution is found, but don't leak it to the backend. |
1124 | + */ |
1125 | +#ifdef __KERNEL__ |
1126 | +#define XENFB_WIDTH 800 |
1127 | +#define XENFB_HEIGHT 600 |
1128 | +#define XENFB_DEPTH 32 |
1129 | +#endif |
1130 | + |
1131 | +#endif |
1132 | diff --git a/include/xen/interface/io/kbdif.h b/include/xen/interface/io/kbdif.h |
1133 | new file mode 100644 |
1134 | index 0000000..fb97f42 |
1135 | --- /dev/null |
1136 | +++ b/include/xen/interface/io/kbdif.h |
1137 | @@ -0,0 +1,114 @@ |
1138 | +/* |
1139 | + * kbdif.h -- Xen virtual keyboard/mouse |
1140 | + * |
1141 | + * Permission is hereby granted, free of charge, to any person obtaining a copy |
1142 | + * of this software and associated documentation files (the "Software"), to |
1143 | + * deal in the Software without restriction, including without limitation the |
1144 | + * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or |
1145 | + * sell copies of the Software, and to permit persons to whom the Software is |
1146 | + * furnished to do so, subject to the following conditions: |
1147 | + * |
1148 | + * The above copyright notice and this permission notice shall be included in |
1149 | + * all copies or substantial portions of the Software. |
1150 | + * |
1151 | + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR |
1152 | + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, |
1153 | + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE |
1154 | + * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER |
1155 | + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING |
1156 | + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER |
1157 | + * DEALINGS IN THE SOFTWARE. |
1158 | + * |
1159 | + * Copyright (C) 2005 Anthony Liguori <aliguori@us.ibm.com> |
1160 | + * Copyright (C) 2006 Red Hat, Inc., Markus Armbruster <armbru@redhat.com> |
1161 | + */ |
1162 | + |
1163 | +#ifndef __XEN_PUBLIC_IO_KBDIF_H__ |
1164 | +#define __XEN_PUBLIC_IO_KBDIF_H__ |
1165 | + |
1166 | +/* In events (backend -> frontend) */ |
1167 | + |
1168 | +/* |
1169 | + * Frontends should ignore unknown in events. |
1170 | + */ |
1171 | + |
1172 | +/* Pointer movement event */ |
1173 | +#define XENKBD_TYPE_MOTION 1 |
1174 | +/* Event type 2 currently not used */ |
1175 | +/* Key event (includes pointer buttons) */ |
1176 | +#define XENKBD_TYPE_KEY 3 |
1177 | +/* |
1178 | + * Pointer position event |
1179 | + * Capable backend sets feature-abs-pointer in xenstore. |
1180 | + * Frontend requests ot instead of XENKBD_TYPE_MOTION by setting |
1181 | + * request-abs-update in xenstore. |
1182 | + */ |
1183 | +#define XENKBD_TYPE_POS 4 |
1184 | + |
1185 | +struct xenkbd_motion { |
1186 | + uint8_t type; /* XENKBD_TYPE_MOTION */ |
1187 | + int32_t rel_x; /* relative X motion */ |
1188 | + int32_t rel_y; /* relative Y motion */ |
1189 | +}; |
1190 | + |
1191 | +struct xenkbd_key { |
1192 | + uint8_t type; /* XENKBD_TYPE_KEY */ |
1193 | + uint8_t pressed; /* 1 if pressed; 0 otherwise */ |
1194 | + uint32_t keycode; /* KEY_* from linux/input.h */ |
1195 | +}; |
1196 | + |
1197 | +struct xenkbd_position { |
1198 | + uint8_t type; /* XENKBD_TYPE_POS */ |
1199 | + int32_t abs_x; /* absolute X position (in FB pixels) */ |
1200 | + int32_t abs_y; /* absolute Y position (in FB pixels) */ |
1201 | +}; |
1202 | + |
1203 | +#define XENKBD_IN_EVENT_SIZE 40 |
1204 | + |
1205 | +union xenkbd_in_event { |
1206 | + uint8_t type; |
1207 | + struct xenkbd_motion motion; |
1208 | + struct xenkbd_key key; |
1209 | + struct xenkbd_position pos; |
1210 | + char pad[XENKBD_IN_EVENT_SIZE]; |
1211 | +}; |
1212 | + |
1213 | +/* Out events (frontend -> backend) */ |
1214 | + |
1215 | +/* |
1216 | + * Out events may be sent only when requested by backend, and receipt |
1217 | + * of an unknown out event is an error. |
1218 | + * No out events currently defined. |
1219 | + */ |
1220 | + |
1221 | +#define XENKBD_OUT_EVENT_SIZE 40 |
1222 | + |
1223 | +union xenkbd_out_event { |
1224 | + uint8_t type; |
1225 | + char pad[XENKBD_OUT_EVENT_SIZE]; |
1226 | +}; |
1227 | + |
1228 | +/* shared page */ |
1229 | + |
1230 | +#define XENKBD_IN_RING_SIZE 2048 |
1231 | +#define XENKBD_IN_RING_LEN (XENKBD_IN_RING_SIZE / XENKBD_IN_EVENT_SIZE) |
1232 | +#define XENKBD_IN_RING_OFFS 1024 |
1233 | +#define XENKBD_IN_RING(page) \ |
1234 | + ((union xenkbd_in_event *)((char *)(page) + XENKBD_IN_RING_OFFS)) |
1235 | +#define XENKBD_IN_RING_REF(page, idx) \ |
1236 | + (XENKBD_IN_RING((page))[(idx) % XENKBD_IN_RING_LEN]) |
1237 | + |
1238 | +#define XENKBD_OUT_RING_SIZE 1024 |
1239 | +#define XENKBD_OUT_RING_LEN (XENKBD_OUT_RING_SIZE / XENKBD_OUT_EVENT_SIZE) |
1240 | +#define XENKBD_OUT_RING_OFFS (XENKBD_IN_RING_OFFS + XENKBD_IN_RING_SIZE) |
1241 | +#define XENKBD_OUT_RING(page) \ |
1242 | + ((union xenkbd_out_event *)((char *)(page) + XENKBD_OUT_RING_OFFS)) |
1243 | +#define XENKBD_OUT_RING_REF(page, idx) \ |
1244 | + (XENKBD_OUT_RING((page))[(idx) % XENKBD_OUT_RING_LEN]) |
1245 | + |
1246 | +struct xenkbd_page { |
1247 | + uint32_t in_cons, in_prod; |
1248 | + uint32_t out_cons, out_prod; |
1249 | +}; |
1250 | + |
1251 | +#endif |
1252 | -- |
1253 | 1.5.4.1 |
1254 |