diff options
-rw-r--r-- | drivers/input/Kconfig | 9 | ||||
-rw-r--r-- | drivers/input/Makefile | 2 | ||||
-rw-r--r-- | drivers/input/xen-kbdfront.c | 340 | ||||
-rw-r--r-- | drivers/video/Kconfig | 14 | ||||
-rw-r--r-- | drivers/video/Makefile | 1 | ||||
-rw-r--r-- | drivers/video/xen-fbfront.c | 550 | ||||
-rw-r--r-- | include/xen/interface/io/fbif.h | 124 | ||||
-rw-r--r-- | include/xen/interface/io/kbdif.h | 114 |
8 files changed, 1154 insertions, 0 deletions
diff --git a/drivers/input/Kconfig b/drivers/input/Kconfig index 9dea14db724c..5f9d860925a1 100644 --- a/drivers/input/Kconfig +++ b/drivers/input/Kconfig | |||
@@ -149,6 +149,15 @@ config INPUT_APMPOWER | |||
149 | To compile this driver as a module, choose M here: the | 149 | To compile this driver as a module, choose M here: the |
150 | module will be called apm-power. | 150 | module will be called apm-power. |
151 | 151 | ||
152 | config XEN_KBDDEV_FRONTEND | ||
153 | tristate "Xen virtual keyboard and mouse support" | ||
154 | depends on XEN_FBDEV_FRONTEND | ||
155 | default y | ||
156 | help | ||
157 | This driver implements the front-end of the Xen virtual | ||
158 | keyboard and mouse device driver. It communicates with a back-end | ||
159 | in another domain. | ||
160 | |||
152 | comment "Input Device Drivers" | 161 | comment "Input Device Drivers" |
153 | 162 | ||
154 | source "drivers/input/keyboard/Kconfig" | 163 | source "drivers/input/keyboard/Kconfig" |
diff --git a/drivers/input/Makefile b/drivers/input/Makefile index 2ae87b19caa8..98c4f9a77876 100644 --- a/drivers/input/Makefile +++ b/drivers/input/Makefile | |||
@@ -23,3 +23,5 @@ obj-$(CONFIG_INPUT_TOUCHSCREEN) += touchscreen/ | |||
23 | obj-$(CONFIG_INPUT_MISC) += misc/ | 23 | obj-$(CONFIG_INPUT_MISC) += misc/ |
24 | 24 | ||
25 | obj-$(CONFIG_INPUT_APMPOWER) += apm-power.o | 25 | obj-$(CONFIG_INPUT_APMPOWER) += apm-power.o |
26 | |||
27 | obj-$(CONFIG_XEN_KBDDEV_FRONTEND) += xen-kbdfront.o | ||
diff --git a/drivers/input/xen-kbdfront.c b/drivers/input/xen-kbdfront.c new file mode 100644 index 000000000000..0f47f4697cdf --- /dev/null +++ b/drivers/input/xen-kbdfront.c | |||
@@ -0,0 +1,340 @@ | |||
1 | /* | ||
2 | * Xen para-virtual input device | ||
3 | * | ||
4 | * Copyright (C) 2005 Anthony Liguori <aliguori@us.ibm.com> | ||
5 | * Copyright (C) 2006-2008 Red Hat, Inc., Markus Armbruster <armbru@redhat.com> | ||
6 | * | ||
7 | * Based on linux/drivers/input/mouse/sermouse.c | ||
8 | * | ||
9 | * This file is subject to the terms and conditions of the GNU General Public | ||
10 | * License. See the file COPYING in the main directory of this archive for | ||
11 | * more details. | ||
12 | */ | ||
13 | |||
14 | /* | ||
15 | * TODO: | ||
16 | * | ||
17 | * Switch to grant tables together with xen-fbfront.c. | ||
18 | */ | ||
19 | |||
20 | #include <linux/kernel.h> | ||
21 | #include <linux/errno.h> | ||
22 | #include <linux/module.h> | ||
23 | #include <linux/input.h> | ||
24 | #include <asm/xen/hypervisor.h> | ||
25 | #include <xen/events.h> | ||
26 | #include <xen/page.h> | ||
27 | #include <xen/interface/io/fbif.h> | ||
28 | #include <xen/interface/io/kbdif.h> | ||
29 | #include <xen/xenbus.h> | ||
30 | |||
31 | struct xenkbd_info { | ||
32 | struct input_dev *kbd; | ||
33 | struct input_dev *ptr; | ||
34 | struct xenkbd_page *page; | ||
35 | int irq; | ||
36 | struct xenbus_device *xbdev; | ||
37 | char phys[32]; | ||
38 | }; | ||
39 | |||
40 | static int xenkbd_remove(struct xenbus_device *); | ||
41 | static int xenkbd_connect_backend(struct xenbus_device *, struct xenkbd_info *); | ||
42 | static void xenkbd_disconnect_backend(struct xenkbd_info *); | ||
43 | |||
44 | /* | ||
45 | * Note: if you need to send out events, see xenfb_do_update() for how | ||
46 | * to do that. | ||
47 | */ | ||
48 | |||
49 | static irqreturn_t input_handler(int rq, void *dev_id) | ||
50 | { | ||
51 | struct xenkbd_info *info = dev_id; | ||
52 | struct xenkbd_page *page = info->page; | ||
53 | __u32 cons, prod; | ||
54 | |||
55 | prod = page->in_prod; | ||
56 | if (prod == page->in_cons) | ||
57 | return IRQ_HANDLED; | ||
58 | rmb(); /* ensure we see ring contents up to prod */ | ||
59 | for (cons = page->in_cons; cons != prod; cons++) { | ||
60 | union xenkbd_in_event *event; | ||
61 | struct input_dev *dev; | ||
62 | event = &XENKBD_IN_RING_REF(page, cons); | ||
63 | |||
64 | dev = info->ptr; | ||
65 | switch (event->type) { | ||
66 | case XENKBD_TYPE_MOTION: | ||
67 | input_report_rel(dev, REL_X, event->motion.rel_x); | ||
68 | input_report_rel(dev, REL_Y, event->motion.rel_y); | ||
69 | break; | ||
70 | case XENKBD_TYPE_KEY: | ||
71 | dev = NULL; | ||
72 | if (test_bit(event->key.keycode, info->kbd->keybit)) | ||
73 | dev = info->kbd; | ||
74 | if (test_bit(event->key.keycode, info->ptr->keybit)) | ||
75 | dev = info->ptr; | ||
76 | if (dev) | ||
77 | input_report_key(dev, event->key.keycode, | ||
78 | event->key.pressed); | ||
79 | else | ||
80 | printk(KERN_WARNING | ||
81 | "xenkbd: unhandled keycode 0x%x\n", | ||
82 | event->key.keycode); | ||
83 | break; | ||
84 | case XENKBD_TYPE_POS: | ||
85 | input_report_abs(dev, ABS_X, event->pos.abs_x); | ||
86 | input_report_abs(dev, ABS_Y, event->pos.abs_y); | ||
87 | break; | ||
88 | } | ||
89 | if (dev) | ||
90 | input_sync(dev); | ||
91 | } | ||
92 | mb(); /* ensure we got ring contents */ | ||
93 | page->in_cons = cons; | ||
94 | notify_remote_via_irq(info->irq); | ||
95 | |||
96 | return IRQ_HANDLED; | ||
97 | } | ||
98 | |||
99 | static int __devinit xenkbd_probe(struct xenbus_device *dev, | ||
100 | const struct xenbus_device_id *id) | ||
101 | { | ||
102 | int ret, i; | ||
103 | struct xenkbd_info *info; | ||
104 | struct input_dev *kbd, *ptr; | ||
105 | |||
106 | info = kzalloc(sizeof(*info), GFP_KERNEL); | ||
107 | if (!info) { | ||
108 | xenbus_dev_fatal(dev, -ENOMEM, "allocating info structure"); | ||
109 | return -ENOMEM; | ||
110 | } | ||
111 | dev->dev.driver_data = info; | ||
112 | info->xbdev = dev; | ||
113 | info->irq = -1; | ||
114 | snprintf(info->phys, sizeof(info->phys), "xenbus/%s", dev->nodename); | ||
115 | |||
116 | info->page = (void *)__get_free_page(GFP_KERNEL | __GFP_ZERO); | ||
117 | if (!info->page) | ||
118 | goto error_nomem; | ||
119 | |||
120 | /* keyboard */ | ||
121 | kbd = input_allocate_device(); | ||
122 | if (!kbd) | ||
123 | goto error_nomem; | ||
124 | kbd->name = "Xen Virtual Keyboard"; | ||
125 | kbd->phys = info->phys; | ||
126 | kbd->id.bustype = BUS_PCI; | ||
127 | kbd->id.vendor = 0x5853; | ||
128 | kbd->id.product = 0xffff; | ||
129 | kbd->evbit[0] = BIT(EV_KEY); | ||
130 | for (i = KEY_ESC; i < KEY_UNKNOWN; i++) | ||
131 | set_bit(i, kbd->keybit); | ||
132 | for (i = KEY_OK; i < KEY_MAX; i++) | ||
133 | set_bit(i, kbd->keybit); | ||
134 | |||
135 | ret = input_register_device(kbd); | ||
136 | if (ret) { | ||
137 | input_free_device(kbd); | ||
138 | xenbus_dev_fatal(dev, ret, "input_register_device(kbd)"); | ||
139 | goto error; | ||
140 | } | ||
141 | info->kbd = kbd; | ||
142 | |||
143 | /* pointing device */ | ||
144 | ptr = input_allocate_device(); | ||
145 | if (!ptr) | ||
146 | goto error_nomem; | ||
147 | ptr->name = "Xen Virtual Pointer"; | ||
148 | ptr->phys = info->phys; | ||
149 | ptr->id.bustype = BUS_PCI; | ||
150 | ptr->id.vendor = 0x5853; | ||
151 | ptr->id.product = 0xfffe; | ||
152 | ptr->evbit[0] = BIT(EV_KEY) | BIT(EV_REL) | BIT(EV_ABS); | ||
153 | for (i = BTN_LEFT; i <= BTN_TASK; i++) | ||
154 | set_bit(i, ptr->keybit); | ||
155 | ptr->relbit[0] = BIT(REL_X) | BIT(REL_Y); | ||
156 | input_set_abs_params(ptr, ABS_X, 0, XENFB_WIDTH, 0, 0); | ||
157 | input_set_abs_params(ptr, ABS_Y, 0, XENFB_HEIGHT, 0, 0); | ||
158 | |||
159 | ret = input_register_device(ptr); | ||
160 | if (ret) { | ||
161 | input_free_device(ptr); | ||
162 | xenbus_dev_fatal(dev, ret, "input_register_device(ptr)"); | ||
163 | goto error; | ||
164 | } | ||
165 | info->ptr = ptr; | ||
166 | |||
167 | ret = xenkbd_connect_backend(dev, info); | ||
168 | if (ret < 0) | ||
169 | goto error; | ||
170 | |||
171 | return 0; | ||
172 | |||
173 | error_nomem: | ||
174 | ret = -ENOMEM; | ||
175 | xenbus_dev_fatal(dev, ret, "allocating device memory"); | ||
176 | error: | ||
177 | xenkbd_remove(dev); | ||
178 | return ret; | ||
179 | } | ||
180 | |||
181 | static int xenkbd_resume(struct xenbus_device *dev) | ||
182 | { | ||
183 | struct xenkbd_info *info = dev->dev.driver_data; | ||
184 | |||
185 | xenkbd_disconnect_backend(info); | ||
186 | memset(info->page, 0, PAGE_SIZE); | ||
187 | return xenkbd_connect_backend(dev, info); | ||
188 | } | ||
189 | |||
190 | static int xenkbd_remove(struct xenbus_device *dev) | ||
191 | { | ||
192 | struct xenkbd_info *info = dev->dev.driver_data; | ||
193 | |||
194 | xenkbd_disconnect_backend(info); | ||
195 | if (info->kbd) | ||
196 | input_unregister_device(info->kbd); | ||
197 | if (info->ptr) | ||
198 | input_unregister_device(info->ptr); | ||
199 | free_page((unsigned long)info->page); | ||
200 | kfree(info); | ||
201 | return 0; | ||
202 | } | ||
203 | |||
204 | static int xenkbd_connect_backend(struct xenbus_device *dev, | ||
205 | struct xenkbd_info *info) | ||
206 | { | ||
207 | int ret, evtchn; | ||
208 | struct xenbus_transaction xbt; | ||
209 | |||
210 | ret = xenbus_alloc_evtchn(dev, &evtchn); | ||
211 | if (ret) | ||
212 | return ret; | ||
213 | ret = bind_evtchn_to_irqhandler(evtchn, input_handler, | ||
214 | 0, dev->devicetype, info); | ||
215 | if (ret < 0) { | ||
216 | xenbus_free_evtchn(dev, evtchn); | ||
217 | xenbus_dev_fatal(dev, ret, "bind_evtchn_to_irqhandler"); | ||
218 | return ret; | ||
219 | } | ||
220 | info->irq = ret; | ||
221 | |||
222 | again: | ||
223 | ret = xenbus_transaction_start(&xbt); | ||
224 | if (ret) { | ||
225 | xenbus_dev_fatal(dev, ret, "starting transaction"); | ||
226 | return ret; | ||
227 | } | ||
228 | ret = xenbus_printf(xbt, dev->nodename, "page-ref", "%lu", | ||
229 | virt_to_mfn(info->page)); | ||
230 | if (ret) | ||
231 | goto error_xenbus; | ||
232 | ret = xenbus_printf(xbt, dev->nodename, "event-channel", "%u", | ||
233 | evtchn); | ||
234 | if (ret) | ||
235 | goto error_xenbus; | ||
236 | ret = xenbus_transaction_end(xbt, 0); | ||
237 | if (ret) { | ||
238 | if (ret == -EAGAIN) | ||
239 | goto again; | ||
240 | xenbus_dev_fatal(dev, ret, "completing transaction"); | ||
241 | return ret; | ||
242 | } | ||
243 | |||
244 | xenbus_switch_state(dev, XenbusStateInitialised); | ||
245 | return 0; | ||
246 | |||
247 | error_xenbus: | ||
248 | xenbus_transaction_end(xbt, 1); | ||
249 | xenbus_dev_fatal(dev, ret, "writing xenstore"); | ||
250 | return ret; | ||
251 | } | ||
252 | |||
253 | static void xenkbd_disconnect_backend(struct xenkbd_info *info) | ||
254 | { | ||
255 | if (info->irq >= 0) | ||
256 | unbind_from_irqhandler(info->irq, info); | ||
257 | info->irq = -1; | ||
258 | } | ||
259 | |||
260 | static void xenkbd_backend_changed(struct xenbus_device *dev, | ||
261 | enum xenbus_state backend_state) | ||
262 | { | ||
263 | struct xenkbd_info *info = dev->dev.driver_data; | ||
264 | int ret, val; | ||
265 | |||
266 | switch (backend_state) { | ||
267 | case XenbusStateInitialising: | ||
268 | case XenbusStateInitialised: | ||
269 | case XenbusStateUnknown: | ||
270 | case XenbusStateClosed: | ||
271 | break; | ||
272 | |||
273 | case XenbusStateInitWait: | ||
274 | InitWait: | ||
275 | ret = xenbus_scanf(XBT_NIL, info->xbdev->otherend, | ||
276 | "feature-abs-pointer", "%d", &val); | ||
277 | if (ret < 0) | ||
278 | val = 0; | ||
279 | if (val) { | ||
280 | ret = xenbus_printf(XBT_NIL, info->xbdev->nodename, | ||
281 | "request-abs-pointer", "1"); | ||
282 | if (ret) | ||
283 | printk(KERN_WARNING | ||
284 | "xenkbd: can't request abs-pointer"); | ||
285 | } | ||
286 | xenbus_switch_state(dev, XenbusStateConnected); | ||
287 | break; | ||
288 | |||
289 | case XenbusStateConnected: | ||
290 | /* | ||
291 | * Work around xenbus race condition: If backend goes | ||
292 | * through InitWait to Connected fast enough, we can | ||
293 | * get Connected twice here. | ||
294 | */ | ||
295 | if (dev->state != XenbusStateConnected) | ||
296 | goto InitWait; /* no InitWait seen yet, fudge it */ | ||
297 | break; | ||
298 | |||
299 | case XenbusStateClosing: | ||
300 | xenbus_frontend_closed(dev); | ||
301 | break; | ||
302 | } | ||
303 | } | ||
304 | |||
305 | static struct xenbus_device_id xenkbd_ids[] = { | ||
306 | { "vkbd" }, | ||
307 | { "" } | ||
308 | }; | ||
309 | |||
310 | static struct xenbus_driver xenkbd = { | ||
311 | .name = "vkbd", | ||
312 | .owner = THIS_MODULE, | ||
313 | .ids = xenkbd_ids, | ||
314 | .probe = xenkbd_probe, | ||
315 | .remove = xenkbd_remove, | ||
316 | .resume = xenkbd_resume, | ||
317 | .otherend_changed = xenkbd_backend_changed, | ||
318 | }; | ||
319 | |||
320 | static int __init xenkbd_init(void) | ||
321 | { | ||
322 | if (!is_running_on_xen()) | ||
323 | return -ENODEV; | ||
324 | |||
325 | /* Nothing to do if running in dom0. */ | ||
326 | if (is_initial_xendomain()) | ||
327 | return -ENODEV; | ||
328 | |||
329 | return xenbus_register_frontend(&xenkbd); | ||
330 | } | ||
331 | |||
332 | static void __exit xenkbd_cleanup(void) | ||
333 | { | ||
334 | xenbus_unregister_driver(&xenkbd); | ||
335 | } | ||
336 | |||
337 | module_init(xenkbd_init); | ||
338 | module_exit(xenkbd_cleanup); | ||
339 | |||
340 | MODULE_LICENSE("GPL"); | ||
diff --git a/drivers/video/Kconfig b/drivers/video/Kconfig index 1bd5fb30237d..e3dc8f8d0c3e 100644 --- a/drivers/video/Kconfig +++ b/drivers/video/Kconfig | |||
@@ -1930,6 +1930,20 @@ config FB_VIRTUAL | |||
1930 | 1930 | ||
1931 | If unsure, say N. | 1931 | If unsure, say N. |
1932 | 1932 | ||
1933 | config XEN_FBDEV_FRONTEND | ||
1934 | tristate "Xen virtual frame buffer support" | ||
1935 | depends on FB && XEN | ||
1936 | select FB_SYS_FILLRECT | ||
1937 | select FB_SYS_COPYAREA | ||
1938 | select FB_SYS_IMAGEBLIT | ||
1939 | select FB_SYS_FOPS | ||
1940 | select FB_DEFERRED_IO | ||
1941 | default y | ||
1942 | help | ||
1943 | This driver implements the front-end of the Xen virtual | ||
1944 | frame buffer driver. It communicates with a back-end | ||
1945 | in another domain. | ||
1946 | |||
1933 | source "drivers/video/omap/Kconfig" | 1947 | source "drivers/video/omap/Kconfig" |
1934 | 1948 | ||
1935 | source "drivers/video/backlight/Kconfig" | 1949 | source "drivers/video/backlight/Kconfig" |
diff --git a/drivers/video/Makefile b/drivers/video/Makefile index 11c0e5e05f21..f172b9b73314 100644 --- a/drivers/video/Makefile +++ b/drivers/video/Makefile | |||
@@ -114,6 +114,7 @@ obj-$(CONFIG_FB_PS3) += ps3fb.o | |||
114 | obj-$(CONFIG_FB_SM501) += sm501fb.o | 114 | obj-$(CONFIG_FB_SM501) += sm501fb.o |
115 | obj-$(CONFIG_FB_XILINX) += xilinxfb.o | 115 | obj-$(CONFIG_FB_XILINX) += xilinxfb.o |
116 | obj-$(CONFIG_FB_OMAP) += omap/ | 116 | obj-$(CONFIG_FB_OMAP) += omap/ |
117 | obj-$(CONFIG_XEN_FBDEV_FRONTEND) += xen-fbfront.o | ||
117 | 118 | ||
118 | # Platform or fallback drivers go here | 119 | # Platform or fallback drivers go here |
119 | obj-$(CONFIG_FB_UVESA) += uvesafb.o | 120 | obj-$(CONFIG_FB_UVESA) += uvesafb.o |
diff --git a/drivers/video/xen-fbfront.c b/drivers/video/xen-fbfront.c new file mode 100644 index 000000000000..619a6f8d65a2 --- /dev/null +++ b/drivers/video/xen-fbfront.c | |||
@@ -0,0 +1,550 @@ | |||
1 | /* | ||
2 | * Xen para-virtual frame buffer device | ||
3 | * | ||
4 | * Copyright (C) 2005-2006 Anthony Liguori <aliguori@us.ibm.com> | ||
5 | * Copyright (C) 2006-2008 Red Hat, Inc., Markus Armbruster <armbru@redhat.com> | ||
6 | * | ||
7 | * Based on linux/drivers/video/q40fb.c | ||
8 | * | ||
9 | * This file is subject to the terms and conditions of the GNU General Public | ||
10 | * License. See the file COPYING in the main directory of this archive for | ||
11 | * more details. | ||
12 | */ | ||
13 | |||
14 | /* | ||
15 | * TODO: | ||
16 | * | ||
17 | * Switch to grant tables when they become capable of dealing with the | ||
18 | * frame buffer. | ||
19 | */ | ||
20 | |||
21 | #include <linux/kernel.h> | ||
22 | #include <linux/errno.h> | ||
23 | #include <linux/fb.h> | ||
24 | #include <linux/module.h> | ||
25 | #include <linux/vmalloc.h> | ||
26 | #include <linux/mm.h> | ||
27 | #include <asm/xen/hypervisor.h> | ||
28 | #include <xen/events.h> | ||
29 | #include <xen/page.h> | ||
30 | #include <xen/interface/io/fbif.h> | ||
31 | #include <xen/interface/io/protocols.h> | ||
32 | #include <xen/xenbus.h> | ||
33 | |||
34 | struct xenfb_info { | ||
35 | unsigned char *fb; | ||
36 | struct fb_info *fb_info; | ||
37 | int x1, y1, x2, y2; /* dirty rectangle, | ||
38 | protected by dirty_lock */ | ||
39 | spinlock_t dirty_lock; | ||
40 | int nr_pages; | ||
41 | int irq; | ||
42 | struct xenfb_page *page; | ||
43 | unsigned long *mfns; | ||
44 | int update_wanted; /* XENFB_TYPE_UPDATE wanted */ | ||
45 | |||
46 | struct xenbus_device *xbdev; | ||
47 | }; | ||
48 | |||
49 | static u32 xenfb_mem_len = XENFB_WIDTH * XENFB_HEIGHT * XENFB_DEPTH / 8; | ||
50 | |||
51 | static int xenfb_remove(struct xenbus_device *); | ||
52 | static void xenfb_init_shared_page(struct xenfb_info *); | ||
53 | static int xenfb_connect_backend(struct xenbus_device *, struct xenfb_info *); | ||
54 | static void xenfb_disconnect_backend(struct xenfb_info *); | ||
55 | |||
56 | static void xenfb_do_update(struct xenfb_info *info, | ||
57 | int x, int y, int w, int h) | ||
58 | { | ||
59 | union xenfb_out_event event; | ||
60 | u32 prod; | ||
61 | |||
62 | event.type = XENFB_TYPE_UPDATE; | ||
63 | event.update.x = x; | ||
64 | event.update.y = y; | ||
65 | event.update.width = w; | ||
66 | event.update.height = h; | ||
67 | |||
68 | prod = info->page->out_prod; | ||
69 | /* caller ensures !xenfb_queue_full() */ | ||
70 | mb(); /* ensure ring space available */ | ||
71 | XENFB_OUT_RING_REF(info->page, prod) = event; | ||
72 | wmb(); /* ensure ring contents visible */ | ||
73 | info->page->out_prod = prod + 1; | ||
74 | |||
75 | notify_remote_via_irq(info->irq); | ||
76 | } | ||
77 | |||
78 | static int xenfb_queue_full(struct xenfb_info *info) | ||
79 | { | ||
80 | u32 cons, prod; | ||
81 | |||
82 | prod = info->page->out_prod; | ||
83 | cons = info->page->out_cons; | ||
84 | return prod - cons == XENFB_OUT_RING_LEN; | ||
85 | } | ||
86 | |||
87 | static void xenfb_refresh(struct xenfb_info *info, | ||
88 | int x1, int y1, int w, int h) | ||
89 | { | ||
90 | unsigned long flags; | ||
91 | int y2 = y1 + h - 1; | ||
92 | int x2 = x1 + w - 1; | ||
93 | |||
94 | if (!info->update_wanted) | ||
95 | return; | ||
96 | |||
97 | spin_lock_irqsave(&info->dirty_lock, flags); | ||
98 | |||
99 | /* Combine with dirty rectangle: */ | ||
100 | if (info->y1 < y1) | ||
101 | y1 = info->y1; | ||
102 | if (info->y2 > y2) | ||
103 | y2 = info->y2; | ||
104 | if (info->x1 < x1) | ||
105 | x1 = info->x1; | ||
106 | if (info->x2 > x2) | ||
107 | x2 = info->x2; | ||
108 | |||
109 | if (xenfb_queue_full(info)) { | ||
110 | /* Can't send right now, stash it in the dirty rectangle */ | ||
111 | info->x1 = x1; | ||
112 | info->x2 = x2; | ||
113 | info->y1 = y1; | ||
114 | info->y2 = y2; | ||
115 | spin_unlock_irqrestore(&info->dirty_lock, flags); | ||
116 | return; | ||
117 | } | ||
118 | |||
119 | /* Clear dirty rectangle: */ | ||
120 | info->x1 = info->y1 = INT_MAX; | ||
121 | info->x2 = info->y2 = 0; | ||
122 | |||
123 | spin_unlock_irqrestore(&info->dirty_lock, flags); | ||
124 | |||
125 | if (x1 <= x2 && y1 <= y2) | ||
126 | xenfb_do_update(info, x1, y1, x2 - x1 + 1, y2 - y1 + 1); | ||
127 | } | ||
128 | |||
129 | static void xenfb_deferred_io(struct fb_info *fb_info, | ||
130 | struct list_head *pagelist) | ||
131 | { | ||
132 | struct xenfb_info *info = fb_info->par; | ||
133 | struct page *page; | ||
134 | unsigned long beg, end; | ||
135 | int y1, y2, miny, maxy; | ||
136 | |||
137 | miny = INT_MAX; | ||
138 | maxy = 0; | ||
139 | list_for_each_entry(page, pagelist, lru) { | ||
140 | beg = page->index << PAGE_SHIFT; | ||
141 | end = beg + PAGE_SIZE - 1; | ||
142 | y1 = beg / fb_info->fix.line_length; | ||
143 | y2 = end / fb_info->fix.line_length; | ||
144 | if (y2 >= fb_info->var.yres) | ||
145 | y2 = fb_info->var.yres - 1; | ||
146 | if (miny > y1) | ||
147 | miny = y1; | ||
148 | if (maxy < y2) | ||
149 | maxy = y2; | ||
150 | } | ||
151 | xenfb_refresh(info, 0, miny, fb_info->var.xres, maxy - miny + 1); | ||
152 | } | ||
153 | |||
154 | static struct fb_deferred_io xenfb_defio = { | ||
155 | .delay = HZ / 20, | ||
156 | .deferred_io = xenfb_deferred_io, | ||
157 | }; | ||
158 | |||
159 | static int xenfb_setcolreg(unsigned regno, unsigned red, unsigned green, | ||
160 | unsigned blue, unsigned transp, | ||
161 | struct fb_info *info) | ||
162 | { | ||
163 | u32 v; | ||
164 | |||
165 | if (regno > info->cmap.len) | ||
166 | return 1; | ||
167 | |||
168 | #define CNVT_TOHW(val, width) ((((val)<<(width))+0x7FFF-(val))>>16) | ||
169 | red = CNVT_TOHW(red, info->var.red.length); | ||
170 | green = CNVT_TOHW(green, info->var.green.length); | ||
171 | blue = CNVT_TOHW(blue, info->var.blue.length); | ||
172 | transp = CNVT_TOHW(transp, info->var.transp.length); | ||
173 | #undef CNVT_TOHW | ||
174 | |||
175 | v = (red << info->var.red.offset) | | ||
176 | (green << info->var.green.offset) | | ||
177 | (blue << info->var.blue.offset); | ||
178 | |||
179 | switch (info->var.bits_per_pixel) { | ||
180 | case 16: | ||
181 | case 24: | ||
182 | case 32: | ||
183 | ((u32 *)info->pseudo_palette)[regno] = v; | ||
184 | break; | ||
185 | } | ||
186 | |||
187 | return 0; | ||
188 | } | ||
189 | |||
190 | static void xenfb_fillrect(struct fb_info *p, const struct fb_fillrect *rect) | ||
191 | { | ||
192 | struct xenfb_info *info = p->par; | ||
193 | |||
194 | sys_fillrect(p, rect); | ||
195 | xenfb_refresh(info, rect->dx, rect->dy, rect->width, rect->height); | ||
196 | } | ||
197 | |||
198 | static void xenfb_imageblit(struct fb_info *p, const struct fb_image *image) | ||
199 | { | ||
200 | struct xenfb_info *info = p->par; | ||
201 | |||
202 | sys_imageblit(p, image); | ||
203 | xenfb_refresh(info, image->dx, image->dy, image->width, image->height); | ||
204 | } | ||
205 | |||
206 | static void xenfb_copyarea(struct fb_info *p, const struct fb_copyarea *area) | ||
207 | { | ||
208 | struct xenfb_info *info = p->par; | ||
209 | |||
210 | sys_copyarea(p, area); | ||
211 | xenfb_refresh(info, area->dx, area->dy, area->width, area->height); | ||
212 | } | ||
213 | |||
214 | static ssize_t xenfb_write(struct fb_info *p, const char __user *buf, | ||
215 | size_t count, loff_t *ppos) | ||
216 | { | ||
217 | struct xenfb_info *info = p->par; | ||
218 | ssize_t res; | ||
219 | |||
220 | res = fb_sys_write(p, buf, count, ppos); | ||
221 | xenfb_refresh(info, 0, 0, info->page->width, info->page->height); | ||
222 | return res; | ||
223 | } | ||
224 | |||
225 | static struct fb_ops xenfb_fb_ops = { | ||
226 | .owner = THIS_MODULE, | ||
227 | .fb_read = fb_sys_read, | ||
228 | .fb_write = xenfb_write, | ||
229 | .fb_setcolreg = xenfb_setcolreg, | ||
230 | .fb_fillrect = xenfb_fillrect, | ||
231 | .fb_copyarea = xenfb_copyarea, | ||
232 | .fb_imageblit = xenfb_imageblit, | ||
233 | }; | ||
234 | |||
235 | static irqreturn_t xenfb_event_handler(int rq, void *dev_id) | ||
236 | { | ||
237 | /* | ||
238 | * No in events recognized, simply ignore them all. | ||
239 | * If you need to recognize some, see xen-kbdfront's | ||
240 | * input_handler() for how to do that. | ||
241 | */ | ||
242 | struct xenfb_info *info = dev_id; | ||
243 | struct xenfb_page *page = info->page; | ||
244 | |||
245 | if (page->in_cons != page->in_prod) { | ||
246 | info->page->in_cons = info->page->in_prod; | ||
247 | notify_remote_via_irq(info->irq); | ||
248 | } | ||
249 | |||
250 | /* Flush dirty rectangle: */ | ||
251 | xenfb_refresh(info, INT_MAX, INT_MAX, -INT_MAX, -INT_MAX); | ||
252 | |||
253 | return IRQ_HANDLED; | ||
254 | } | ||
255 | |||
256 | static int __devinit xenfb_probe(struct xenbus_device *dev, | ||
257 | const struct xenbus_device_id *id) | ||
258 | { | ||
259 | struct xenfb_info *info; | ||
260 | struct fb_info *fb_info; | ||
261 | int ret; | ||
262 | |||
263 | info = kzalloc(sizeof(*info), GFP_KERNEL); | ||
264 | if (info == NULL) { | ||
265 | xenbus_dev_fatal(dev, -ENOMEM, "allocating info structure"); | ||
266 | return -ENOMEM; | ||
267 | } | ||
268 | dev->dev.driver_data = info; | ||
269 | info->xbdev = dev; | ||
270 | info->irq = -1; | ||
271 | info->x1 = info->y1 = INT_MAX; | ||
272 | spin_lock_init(&info->dirty_lock); | ||
273 | |||
274 | info->fb = vmalloc(xenfb_mem_len); | ||
275 | if (info->fb == NULL) | ||
276 | goto error_nomem; | ||
277 | memset(info->fb, 0, xenfb_mem_len); | ||
278 | |||
279 | info->nr_pages = (xenfb_mem_len + PAGE_SIZE - 1) >> PAGE_SHIFT; | ||
280 | |||
281 | info->mfns = vmalloc(sizeof(unsigned long) * info->nr_pages); | ||
282 | if (!info->mfns) | ||
283 | goto error_nomem; | ||
284 | |||
285 | /* set up shared page */ | ||
286 | info->page = (void *)__get_free_page(GFP_KERNEL | __GFP_ZERO); | ||
287 | if (!info->page) | ||
288 | goto error_nomem; | ||
289 | |||
290 | xenfb_init_shared_page(info); | ||
291 | |||
292 | /* abusing framebuffer_alloc() to allocate pseudo_palette */ | ||
293 | fb_info = framebuffer_alloc(sizeof(u32) * 256, NULL); | ||
294 | if (fb_info == NULL) | ||
295 | goto error_nomem; | ||
296 | |||
297 | /* complete the abuse: */ | ||
298 | fb_info->pseudo_palette = fb_info->par; | ||
299 | fb_info->par = info; | ||
300 | |||
301 | fb_info->screen_base = info->fb; | ||
302 | |||
303 | fb_info->fbops = &xenfb_fb_ops; | ||
304 | fb_info->var.xres_virtual = fb_info->var.xres = info->page->width; | ||
305 | fb_info->var.yres_virtual = fb_info->var.yres = info->page->height; | ||
306 | fb_info->var.bits_per_pixel = info->page->depth; | ||
307 | |||
308 | fb_info->var.red = (struct fb_bitfield){16, 8, 0}; | ||
309 | fb_info->var.green = (struct fb_bitfield){8, 8, 0}; | ||
310 | fb_info->var.blue = (struct fb_bitfield){0, 8, 0}; | ||
311 | |||
312 | fb_info->var.activate = FB_ACTIVATE_NOW; | ||
313 | fb_info->var.height = -1; | ||
314 | fb_info->var.width = -1; | ||
315 | fb_info->var.vmode = FB_VMODE_NONINTERLACED; | ||
316 | |||
317 | fb_info->fix.visual = FB_VISUAL_TRUECOLOR; | ||
318 | fb_info->fix.line_length = info->page->line_length; | ||
319 | fb_info->fix.smem_start = 0; | ||
320 | fb_info->fix.smem_len = xenfb_mem_len; | ||
321 | strcpy(fb_info->fix.id, "xen"); | ||
322 | fb_info->fix.type = FB_TYPE_PACKED_PIXELS; | ||
323 | fb_info->fix.accel = FB_ACCEL_NONE; | ||
324 | |||
325 | fb_info->flags = FBINFO_FLAG_DEFAULT; | ||
326 | |||
327 | ret = fb_alloc_cmap(&fb_info->cmap, 256, 0); | ||
328 | if (ret < 0) { | ||
329 | framebuffer_release(fb_info); | ||
330 | xenbus_dev_fatal(dev, ret, "fb_alloc_cmap"); | ||
331 | goto error; | ||
332 | } | ||
333 | |||
334 | fb_info->fbdefio = &xenfb_defio; | ||
335 | fb_deferred_io_init(fb_info); | ||
336 | |||
337 | ret = register_framebuffer(fb_info); | ||
338 | if (ret) { | ||
339 | fb_deferred_io_cleanup(fb_info); | ||
340 | fb_dealloc_cmap(&fb_info->cmap); | ||
341 | framebuffer_release(fb_info); | ||
342 | xenbus_dev_fatal(dev, ret, "register_framebuffer"); | ||
343 | goto error; | ||
344 | } | ||
345 | info->fb_info = fb_info; | ||
346 | |||
347 | ret = xenfb_connect_backend(dev, info); | ||
348 | if (ret < 0) | ||
349 | goto error; | ||
350 | |||
351 | return 0; | ||
352 | |||
353 | error_nomem: | ||
354 | ret = -ENOMEM; | ||
355 | xenbus_dev_fatal(dev, ret, "allocating device memory"); | ||
356 | error: | ||
357 | xenfb_remove(dev); | ||
358 | return ret; | ||
359 | } | ||
360 | |||
361 | static int xenfb_resume(struct xenbus_device *dev) | ||
362 | { | ||
363 | struct xenfb_info *info = dev->dev.driver_data; | ||
364 | |||
365 | xenfb_disconnect_backend(info); | ||
366 | xenfb_init_shared_page(info); | ||
367 | return xenfb_connect_backend(dev, info); | ||
368 | } | ||
369 | |||
370 | static int xenfb_remove(struct xenbus_device *dev) | ||
371 | { | ||
372 | struct xenfb_info *info = dev->dev.driver_data; | ||
373 | |||
374 | xenfb_disconnect_backend(info); | ||
375 | if (info->fb_info) { | ||
376 | fb_deferred_io_cleanup(info->fb_info); | ||
377 | unregister_framebuffer(info->fb_info); | ||
378 | fb_dealloc_cmap(&info->fb_info->cmap); | ||
379 | framebuffer_release(info->fb_info); | ||
380 | } | ||
381 | free_page((unsigned long)info->page); | ||
382 | vfree(info->mfns); | ||
383 | vfree(info->fb); | ||
384 | kfree(info); | ||
385 | |||
386 | return 0; | ||
387 | } | ||
388 | |||
389 | static unsigned long vmalloc_to_mfn(void *address) | ||
390 | { | ||
391 | return pfn_to_mfn(vmalloc_to_pfn(address)); | ||
392 | } | ||
393 | |||
394 | static void xenfb_init_shared_page(struct xenfb_info *info) | ||
395 | { | ||
396 | int i; | ||
397 | |||
398 | for (i = 0; i < info->nr_pages; i++) | ||
399 | info->mfns[i] = vmalloc_to_mfn(info->fb + i * PAGE_SIZE); | ||
400 | |||
401 | info->page->pd[0] = vmalloc_to_mfn(info->mfns); | ||
402 | info->page->pd[1] = 0; | ||
403 | info->page->width = XENFB_WIDTH; | ||
404 | info->page->height = XENFB_HEIGHT; | ||
405 | info->page->depth = XENFB_DEPTH; | ||
406 | info->page->line_length = (info->page->depth / 8) * info->page->width; | ||
407 | info->page->mem_length = xenfb_mem_len; | ||
408 | info->page->in_cons = info->page->in_prod = 0; | ||
409 | info->page->out_cons = info->page->out_prod = 0; | ||
410 | } | ||
411 | |||
412 | static int xenfb_connect_backend(struct xenbus_device *dev, | ||
413 | struct xenfb_info *info) | ||
414 | { | ||
415 | int ret, evtchn; | ||
416 | struct xenbus_transaction xbt; | ||
417 | |||
418 | ret = xenbus_alloc_evtchn(dev, &evtchn); | ||
419 | if (ret) | ||
420 | return ret; | ||
421 | ret = bind_evtchn_to_irqhandler(evtchn, xenfb_event_handler, | ||
422 | 0, dev->devicetype, info); | ||
423 | if (ret < 0) { | ||
424 | xenbus_free_evtchn(dev, evtchn); | ||
425 | xenbus_dev_fatal(dev, ret, "bind_evtchn_to_irqhandler"); | ||
426 | return ret; | ||
427 | } | ||
428 | info->irq = ret; | ||
429 | |||
430 | again: | ||
431 | ret = xenbus_transaction_start(&xbt); | ||
432 | if (ret) { | ||
433 | xenbus_dev_fatal(dev, ret, "starting transaction"); | ||
434 | return ret; | ||
435 | } | ||
436 | ret = xenbus_printf(xbt, dev->nodename, "page-ref", "%lu", | ||
437 | virt_to_mfn(info->page)); | ||
438 | if (ret) | ||
439 | goto error_xenbus; | ||
440 | ret = xenbus_printf(xbt, dev->nodename, "event-channel", "%u", | ||
441 | evtchn); | ||
442 | if (ret) | ||
443 | goto error_xenbus; | ||
444 | ret = xenbus_printf(xbt, dev->nodename, "protocol", "%s", | ||
445 | XEN_IO_PROTO_ABI_NATIVE); | ||
446 | if (ret) | ||
447 | goto error_xenbus; | ||
448 | ret = xenbus_printf(xbt, dev->nodename, "feature-update", "1"); | ||
449 | if (ret) | ||
450 | goto error_xenbus; | ||
451 | ret = xenbus_transaction_end(xbt, 0); | ||
452 | if (ret) { | ||
453 | if (ret == -EAGAIN) | ||
454 | goto again; | ||
455 | xenbus_dev_fatal(dev, ret, "completing transaction"); | ||
456 | return ret; | ||
457 | } | ||
458 | |||
459 | xenbus_switch_state(dev, XenbusStateInitialised); | ||
460 | return 0; | ||
461 | |||
462 | error_xenbus: | ||
463 | xenbus_transaction_end(xbt, 1); | ||
464 | xenbus_dev_fatal(dev, ret, "writing xenstore"); | ||
465 | return ret; | ||
466 | } | ||
467 | |||
468 | static void xenfb_disconnect_backend(struct xenfb_info *info) | ||
469 | { | ||
470 | if (info->irq >= 0) | ||
471 | unbind_from_irqhandler(info->irq, info); | ||
472 | info->irq = -1; | ||
473 | } | ||
474 | |||
475 | static void xenfb_backend_changed(struct xenbus_device *dev, | ||
476 | enum xenbus_state backend_state) | ||
477 | { | ||
478 | struct xenfb_info *info = dev->dev.driver_data; | ||
479 | int val; | ||
480 | |||
481 | switch (backend_state) { | ||
482 | case XenbusStateInitialising: | ||
483 | case XenbusStateInitialised: | ||
484 | case XenbusStateUnknown: | ||
485 | case XenbusStateClosed: | ||
486 | break; | ||
487 | |||
488 | case XenbusStateInitWait: | ||
489 | InitWait: | ||
490 | xenbus_switch_state(dev, XenbusStateConnected); | ||
491 | break; | ||
492 | |||
493 | case XenbusStateConnected: | ||
494 | /* | ||
495 | * Work around xenbus race condition: If backend goes | ||
496 | * through InitWait to Connected fast enough, we can | ||
497 | * get Connected twice here. | ||
498 | */ | ||
499 | if (dev->state != XenbusStateConnected) | ||
500 | goto InitWait; /* no InitWait seen yet, fudge it */ | ||
501 | |||
502 | if (xenbus_scanf(XBT_NIL, info->xbdev->otherend, | ||
503 | "request-update", "%d", &val) < 0) | ||
504 | val = 0; | ||
505 | if (val) | ||
506 | info->update_wanted = 1; | ||
507 | break; | ||
508 | |||
509 | case XenbusStateClosing: | ||
510 | xenbus_frontend_closed(dev); | ||
511 | break; | ||
512 | } | ||
513 | } | ||
514 | |||
515 | static struct xenbus_device_id xenfb_ids[] = { | ||
516 | { "vfb" }, | ||
517 | { "" } | ||
518 | }; | ||
519 | |||
520 | static struct xenbus_driver xenfb = { | ||
521 | .name = "vfb", | ||
522 | .owner = THIS_MODULE, | ||
523 | .ids = xenfb_ids, | ||
524 | .probe = xenfb_probe, | ||
525 | .remove = xenfb_remove, | ||
526 | .resume = xenfb_resume, | ||
527 | .otherend_changed = xenfb_backend_changed, | ||
528 | }; | ||
529 | |||
530 | static int __init xenfb_init(void) | ||
531 | { | ||
532 | if (!is_running_on_xen()) | ||
533 | return -ENODEV; | ||
534 | |||
535 | /* Nothing to do if running in dom0. */ | ||
536 | if (is_initial_xendomain()) | ||
537 | return -ENODEV; | ||
538 | |||
539 | return xenbus_register_frontend(&xenfb); | ||
540 | } | ||
541 | |||
542 | static void __exit xenfb_cleanup(void) | ||
543 | { | ||
544 | xenbus_unregister_driver(&xenfb); | ||
545 | } | ||
546 | |||
547 | module_init(xenfb_init); | ||
548 | module_exit(xenfb_cleanup); | ||
549 | |||
550 | MODULE_LICENSE("GPL"); | ||
diff --git a/include/xen/interface/io/fbif.h b/include/xen/interface/io/fbif.h new file mode 100644 index 000000000000..5a934dd7796d --- /dev/null +++ b/include/xen/interface/io/fbif.h | |||
@@ -0,0 +1,124 @@ | |||
1 | /* | ||
2 | * fbif.h -- Xen virtual frame buffer device | ||
3 | * | ||
4 | * Permission is hereby granted, free of charge, to any person obtaining a copy | ||
5 | * of this software and associated documentation files (the "Software"), to | ||
6 | * deal in the Software without restriction, including without limitation the | ||
7 | * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or | ||
8 | * sell copies of the Software, and to permit persons to whom the Software is | ||
9 | * furnished to do so, subject to the following conditions: | ||
10 | * | ||
11 | * The above copyright notice and this permission notice shall be included in | ||
12 | * all copies or substantial portions of the Software. | ||
13 | * | ||
14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | ||
19 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER | ||
20 | * DEALINGS IN THE SOFTWARE. | ||
21 | * | ||
22 | * Copyright (C) 2005 Anthony Liguori <aliguori@us.ibm.com> | ||
23 | * Copyright (C) 2006 Red Hat, Inc., Markus Armbruster <armbru@redhat.com> | ||
24 | */ | ||
25 | |||
26 | #ifndef __XEN_PUBLIC_IO_FBIF_H__ | ||
27 | #define __XEN_PUBLIC_IO_FBIF_H__ | ||
28 | |||
29 | /* Out events (frontend -> backend) */ | ||
30 | |||
31 | /* | ||
32 | * Out events may be sent only when requested by backend, and receipt | ||
33 | * of an unknown out event is an error. | ||
34 | */ | ||
35 | |||
36 | /* Event type 1 currently not used */ | ||
37 | /* | ||
38 | * Framebuffer update notification event | ||
39 | * Capable frontend sets feature-update in xenstore. | ||
40 | * Backend requests it by setting request-update in xenstore. | ||
41 | */ | ||
42 | #define XENFB_TYPE_UPDATE 2 | ||
43 | |||
44 | struct xenfb_update { | ||
45 | uint8_t type; /* XENFB_TYPE_UPDATE */ | ||
46 | int32_t x; /* source x */ | ||
47 | int32_t y; /* source y */ | ||
48 | int32_t width; /* rect width */ | ||
49 | int32_t height; /* rect height */ | ||
50 | }; | ||
51 | |||
52 | #define XENFB_OUT_EVENT_SIZE 40 | ||
53 | |||
54 | union xenfb_out_event { | ||
55 | uint8_t type; | ||
56 | struct xenfb_update update; | ||
57 | char pad[XENFB_OUT_EVENT_SIZE]; | ||
58 | }; | ||
59 | |||
60 | /* In events (backend -> frontend) */ | ||
61 | |||
62 | /* | ||
63 | * Frontends should ignore unknown in events. | ||
64 | * No in events currently defined. | ||
65 | */ | ||
66 | |||
67 | #define XENFB_IN_EVENT_SIZE 40 | ||
68 | |||
69 | union xenfb_in_event { | ||
70 | uint8_t type; | ||
71 | char pad[XENFB_IN_EVENT_SIZE]; | ||
72 | }; | ||
73 | |||
74 | /* shared page */ | ||
75 | |||
76 | #define XENFB_IN_RING_SIZE 1024 | ||
77 | #define XENFB_IN_RING_LEN (XENFB_IN_RING_SIZE / XENFB_IN_EVENT_SIZE) | ||
78 | #define XENFB_IN_RING_OFFS 1024 | ||
79 | #define XENFB_IN_RING(page) \ | ||
80 | ((union xenfb_in_event *)((char *)(page) + XENFB_IN_RING_OFFS)) | ||
81 | #define XENFB_IN_RING_REF(page, idx) \ | ||
82 | (XENFB_IN_RING((page))[(idx) % XENFB_IN_RING_LEN]) | ||
83 | |||
84 | #define XENFB_OUT_RING_SIZE 2048 | ||
85 | #define XENFB_OUT_RING_LEN (XENFB_OUT_RING_SIZE / XENFB_OUT_EVENT_SIZE) | ||
86 | #define XENFB_OUT_RING_OFFS (XENFB_IN_RING_OFFS + XENFB_IN_RING_SIZE) | ||
87 | #define XENFB_OUT_RING(page) \ | ||
88 | ((union xenfb_out_event *)((char *)(page) + XENFB_OUT_RING_OFFS)) | ||
89 | #define XENFB_OUT_RING_REF(page, idx) \ | ||
90 | (XENFB_OUT_RING((page))[(idx) % XENFB_OUT_RING_LEN]) | ||
91 | |||
92 | struct xenfb_page { | ||
93 | uint32_t in_cons, in_prod; | ||
94 | uint32_t out_cons, out_prod; | ||
95 | |||
96 | int32_t width; /* width of the framebuffer (in pixels) */ | ||
97 | int32_t height; /* height of the framebuffer (in pixels) */ | ||
98 | uint32_t line_length; /* length of a row of pixels (in bytes) */ | ||
99 | uint32_t mem_length; /* length of the framebuffer (in bytes) */ | ||
100 | uint8_t depth; /* depth of a pixel (in bits) */ | ||
101 | |||
102 | /* | ||
103 | * Framebuffer page directory | ||
104 | * | ||
105 | * Each directory page holds PAGE_SIZE / sizeof(*pd) | ||
106 | * framebuffer pages, and can thus map up to PAGE_SIZE * | ||
107 | * PAGE_SIZE / sizeof(*pd) bytes. With PAGE_SIZE == 4096 and | ||
108 | * sizeof(unsigned long) == 4, that's 4 Megs. Two directory | ||
109 | * pages should be enough for a while. | ||
110 | */ | ||
111 | unsigned long pd[2]; | ||
112 | }; | ||
113 | |||
114 | /* | ||
115 | * Wart: xenkbd needs to know resolution. Put it here until a better | ||
116 | * solution is found, but don't leak it to the backend. | ||
117 | */ | ||
118 | #ifdef __KERNEL__ | ||
119 | #define XENFB_WIDTH 800 | ||
120 | #define XENFB_HEIGHT 600 | ||
121 | #define XENFB_DEPTH 32 | ||
122 | #endif | ||
123 | |||
124 | #endif | ||
diff --git a/include/xen/interface/io/kbdif.h b/include/xen/interface/io/kbdif.h new file mode 100644 index 000000000000..fb97f4284ffd --- /dev/null +++ b/include/xen/interface/io/kbdif.h | |||
@@ -0,0 +1,114 @@ | |||
1 | /* | ||
2 | * kbdif.h -- Xen virtual keyboard/mouse | ||
3 | * | ||
4 | * Permission is hereby granted, free of charge, to any person obtaining a copy | ||
5 | * of this software and associated documentation files (the "Software"), to | ||
6 | * deal in the Software without restriction, including without limitation the | ||
7 | * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or | ||
8 | * sell copies of the Software, and to permit persons to whom the Software is | ||
9 | * furnished to do so, subject to the following conditions: | ||
10 | * | ||
11 | * The above copyright notice and this permission notice shall be included in | ||
12 | * all copies or substantial portions of the Software. | ||
13 | * | ||
14 | * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR | ||
15 | * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, | ||
16 | * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE | ||
17 | * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER | ||
18 | * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING | ||
19 | * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER | ||
20 | * DEALINGS IN THE SOFTWARE. | ||
21 | * | ||
22 | * Copyright (C) 2005 Anthony Liguori <aliguori@us.ibm.com> | ||
23 | * Copyright (C) 2006 Red Hat, Inc., Markus Armbruster <armbru@redhat.com> | ||
24 | */ | ||
25 | |||
26 | #ifndef __XEN_PUBLIC_IO_KBDIF_H__ | ||
27 | #define __XEN_PUBLIC_IO_KBDIF_H__ | ||
28 | |||
29 | /* In events (backend -> frontend) */ | ||
30 | |||
31 | /* | ||
32 | * Frontends should ignore unknown in events. | ||
33 | */ | ||
34 | |||
35 | /* Pointer movement event */ | ||
36 | #define XENKBD_TYPE_MOTION 1 | ||
37 | /* Event type 2 currently not used */ | ||
38 | /* Key event (includes pointer buttons) */ | ||
39 | #define XENKBD_TYPE_KEY 3 | ||
40 | /* | ||
41 | * Pointer position event | ||
42 | * Capable backend sets feature-abs-pointer in xenstore. | ||
43 | * Frontend requests ot instead of XENKBD_TYPE_MOTION by setting | ||
44 | * request-abs-update in xenstore. | ||
45 | */ | ||
46 | #define XENKBD_TYPE_POS 4 | ||
47 | |||
48 | struct xenkbd_motion { | ||
49 | uint8_t type; /* XENKBD_TYPE_MOTION */ | ||
50 | int32_t rel_x; /* relative X motion */ | ||
51 | int32_t rel_y; /* relative Y motion */ | ||
52 | }; | ||
53 | |||
54 | struct xenkbd_key { | ||
55 | uint8_t type; /* XENKBD_TYPE_KEY */ | ||
56 | uint8_t pressed; /* 1 if pressed; 0 otherwise */ | ||
57 | uint32_t keycode; /* KEY_* from linux/input.h */ | ||
58 | }; | ||
59 | |||
60 | struct xenkbd_position { | ||
61 | uint8_t type; /* XENKBD_TYPE_POS */ | ||
62 | int32_t abs_x; /* absolute X position (in FB pixels) */ | ||
63 | int32_t abs_y; /* absolute Y position (in FB pixels) */ | ||
64 | }; | ||
65 | |||
66 | #define XENKBD_IN_EVENT_SIZE 40 | ||
67 | |||
68 | union xenkbd_in_event { | ||
69 | uint8_t type; | ||
70 | struct xenkbd_motion motion; | ||
71 | struct xenkbd_key key; | ||
72 | struct xenkbd_position pos; | ||
73 | char pad[XENKBD_IN_EVENT_SIZE]; | ||
74 | }; | ||
75 | |||
76 | /* Out events (frontend -> backend) */ | ||
77 | |||
78 | /* | ||
79 | * Out events may be sent only when requested by backend, and receipt | ||
80 | * of an unknown out event is an error. | ||
81 | * No out events currently defined. | ||
82 | */ | ||
83 | |||
84 | #define XENKBD_OUT_EVENT_SIZE 40 | ||
85 | |||
86 | union xenkbd_out_event { | ||
87 | uint8_t type; | ||
88 | char pad[XENKBD_OUT_EVENT_SIZE]; | ||
89 | }; | ||
90 | |||
91 | /* shared page */ | ||
92 | |||
93 | #define XENKBD_IN_RING_SIZE 2048 | ||
94 | #define XENKBD_IN_RING_LEN (XENKBD_IN_RING_SIZE / XENKBD_IN_EVENT_SIZE) | ||
95 | #define XENKBD_IN_RING_OFFS 1024 | ||
96 | #define XENKBD_IN_RING(page) \ | ||
97 | ((union xenkbd_in_event *)((char *)(page) + XENKBD_IN_RING_OFFS)) | ||
98 | #define XENKBD_IN_RING_REF(page, idx) \ | ||
99 | (XENKBD_IN_RING((page))[(idx) % XENKBD_IN_RING_LEN]) | ||
100 | |||
101 | #define XENKBD_OUT_RING_SIZE 1024 | ||
102 | #define XENKBD_OUT_RING_LEN (XENKBD_OUT_RING_SIZE / XENKBD_OUT_EVENT_SIZE) | ||
103 | #define XENKBD_OUT_RING_OFFS (XENKBD_IN_RING_OFFS + XENKBD_IN_RING_SIZE) | ||
104 | #define XENKBD_OUT_RING(page) \ | ||
105 | ((union xenkbd_out_event *)((char *)(page) + XENKBD_OUT_RING_OFFS)) | ||
106 | #define XENKBD_OUT_RING_REF(page, idx) \ | ||
107 | (XENKBD_OUT_RING((page))[(idx) % XENKBD_OUT_RING_LEN]) | ||
108 | |||
109 | struct xenkbd_page { | ||
110 | uint32_t in_cons, in_prod; | ||
111 | uint32_t out_cons, out_prod; | ||
112 | }; | ||
113 | |||
114 | #endif | ||