ia64/xen-unstable

view tools/xenfb/xenfb.c @ 13612:bc7363b9b892

bimodal xenfb daemon: Fixes and cleanups.
From: Gerd Hoffmann <kraxel@suse.de>
Signed-off-by: Keir Fraser <keir@xensource.com>
author kfraser@localhost.localdomain
date Wed Jan 24 18:23:23 2007 +0000 (2007-01-24)
parents d54c8dab1e64
children 0d5d7d472024
line source
1 #include <stdarg.h>
2 #include <stdlib.h>
3 #include <sys/types.h>
4 #include <fcntl.h>
5 #include <unistd.h>
6 #include <xenctrl.h>
7 #include <xen/io/xenbus.h>
8 #include <xen/io/fbif.h>
9 #include <xen/io/kbdif.h>
10 #include <xen/io/protocols.h>
11 #include <sys/select.h>
12 #include <stdbool.h>
13 #include <xen/linux/evtchn.h>
14 #include <xen/event_channel.h>
15 #include <sys/mman.h>
16 #include <errno.h>
17 #include <stdio.h>
18 #include <string.h>
19 #include <time.h>
20 #include <xs.h>
22 #include "xenfb.h"
24 // FIXME defend against malicious frontend?
26 struct xenfb_device {
27 const char *devicetype;
28 char nodename[64]; /* backend xenstore dir */
29 char otherend[64]; /* frontend xenstore dir */
30 int otherend_id; /* frontend domid */
31 enum xenbus_state state; /* backend state */
32 void *page; /* shared page */
33 evtchn_port_t port;
34 struct xenfb_private *xenfb;
35 };
37 struct xenfb_private {
38 struct xenfb pub;
39 int evt_xch; /* event channel driver handle */
40 int xc; /* hypervisor interface handle */
41 struct xs_handle *xsh; /* xs daemon handle */
42 struct xenfb_device fb, kbd;
43 size_t fb_len; /* size of framebuffer */
44 char protocol[64]; /* frontend protocol */
45 };
47 static void xenfb_detach_dom(struct xenfb_private *);
49 static char *xenfb_path_in_dom(struct xs_handle *xsh,
50 char *buf, size_t size,
51 unsigned domid, const char *fmt, ...)
52 {
53 va_list ap;
54 char *domp = xs_get_domain_path(xsh, domid);
55 int n;
57 if (domp == NULL)
58 return NULL;
60 n = snprintf(buf, size, "%s/", domp);
61 free(domp);
62 if (n >= size)
63 return NULL;
65 va_start(ap, fmt);
66 n += vsnprintf(buf + n, size - n, fmt, ap);
67 va_end(ap);
68 if (n >= size)
69 return NULL;
71 return buf;
72 }
74 static int xenfb_xs_scanf1(struct xs_handle *xsh,
75 const char *dir, const char *node,
76 const char *fmt, void *dest)
77 {
78 char buf[1024];
79 char *p;
80 int ret;
82 if (snprintf(buf, sizeof(buf), "%s/%s", dir, node) >= sizeof(buf)) {
83 errno = ENOENT;
84 return -1;
85 }
86 p = xs_read(xsh, XBT_NULL, buf, NULL);
87 if (!p) {
88 errno = ENOENT;
89 return -1;
90 }
91 ret = sscanf(p, fmt, dest);
92 free(p);
93 if (ret != 1) {
94 errno = EDOM;
95 return -1;
96 }
97 return ret;
98 }
100 static int xenfb_xs_printf(struct xs_handle *xsh,
101 const char *dir, const char *node, char *fmt, ...)
102 {
103 va_list ap;
104 char key[1024];
105 char val[1024];
106 int n;
108 if (snprintf(key, sizeof(key), "%s/%s", dir, node) >= sizeof(key)) {
109 errno = ENOENT;
110 return -1;
111 }
113 va_start(ap, fmt);
114 n = vsnprintf(val, sizeof(val), fmt, ap);
115 va_end(ap);
116 if (n >= sizeof(val)) {
117 errno = ENOSPC; /* close enough */
118 return -1;
119 }
121 if (!xs_write(xsh, XBT_NULL, key, val, n))
122 return -1;
123 return 0;
124 }
126 static void xenfb_device_init(struct xenfb_device *dev,
127 const char *type,
128 struct xenfb_private *xenfb)
129 {
130 dev->devicetype = type;
131 dev->otherend_id = -1;
132 dev->port = -1;
133 dev->xenfb = xenfb;
134 }
136 int xenfb_device_set_domain(struct xenfb_device *dev, int domid)
137 {
138 struct xenfb_private *xenfb = dev->xenfb;
140 dev->otherend_id = domid;
142 if (!xenfb_path_in_dom(xenfb->xsh,
143 dev->otherend, sizeof(dev->otherend),
144 domid, "device/%s/0", dev->devicetype)) {
145 errno = ENOENT;
146 return -1;
147 }
148 if (!xenfb_path_in_dom(xenfb->xsh,
149 dev->nodename, sizeof(dev->nodename),
150 0, "backend/%s/%d/0", dev->devicetype, domid)) {
151 errno = ENOENT;
152 return -1;
153 }
155 return 0;
156 }
158 struct xenfb *xenfb_new(void)
159 {
160 struct xenfb_private *xenfb = malloc(sizeof(*xenfb));
161 int serrno;
163 if (xenfb == NULL)
164 return NULL;
166 memset(xenfb, 0, sizeof(*xenfb));
167 xenfb->evt_xch = xenfb->xc = -1;
168 xenfb_device_init(&xenfb->fb, "vfb", xenfb);
169 xenfb_device_init(&xenfb->kbd, "vkbd", xenfb);
171 xenfb->evt_xch = xc_evtchn_open();
172 if (xenfb->evt_xch == -1)
173 goto fail;
175 xenfb->xc = xc_interface_open();
176 if (xenfb->xc == -1)
177 goto fail;
179 xenfb->xsh = xs_daemon_open();
180 if (!xenfb->xsh)
181 goto fail;
183 return &xenfb->pub;
185 fail:
186 serrno = errno;
187 xenfb_delete(&xenfb->pub);
188 errno = serrno;
189 return NULL;
190 }
192 /* Remove the backend area in xenbus since the framebuffer really is
193 going away. */
194 void xenfb_teardown(struct xenfb *xenfb_pub)
195 {
196 struct xenfb_private *xenfb = (struct xenfb_private *)xenfb_pub;
198 xs_rm(xenfb->xsh, XBT_NULL, xenfb->fb.nodename);
199 xs_rm(xenfb->xsh, XBT_NULL, xenfb->kbd.nodename);
200 }
203 void xenfb_delete(struct xenfb *xenfb_pub)
204 {
205 struct xenfb_private *xenfb = (struct xenfb_private *)xenfb_pub;
207 xenfb_detach_dom(xenfb);
208 if (xenfb->xc >= 0)
209 xc_interface_close(xenfb->xc);
210 if (xenfb->evt_xch >= 0)
211 xc_evtchn_close(xenfb->evt_xch);
212 if (xenfb->xsh)
213 xs_daemon_close(xenfb->xsh);
214 free(xenfb);
215 }
217 static enum xenbus_state xenfb_read_state(struct xs_handle *xsh,
218 const char *dir)
219 {
220 int ret, state;
222 ret = xenfb_xs_scanf1(xsh, dir, "state", "%d", &state);
223 if (ret < 0)
224 return XenbusStateUnknown;
226 if ((unsigned)state > XenbusStateClosed)
227 state = XenbusStateUnknown;
228 return state;
229 }
231 static int xenfb_switch_state(struct xenfb_device *dev,
232 enum xenbus_state state)
233 {
234 struct xs_handle *xsh = dev->xenfb->xsh;
236 if (xenfb_xs_printf(xsh, dev->nodename, "state", "%d", state) < 0)
237 return -1;
238 dev->state = state;
239 return 0;
240 }
242 static int xenfb_wait_for_state(struct xs_handle *xsh, const char *dir,
243 unsigned awaited)
244 {
245 unsigned state, dummy;
246 char **vec;
248 for (;;) {
249 state = xenfb_read_state(xsh, dir);
250 if (state < 0)
251 return -1;
253 if ((1 << state) & awaited)
254 return state;
256 vec = xs_read_watch(xsh, &dummy);
257 if (!vec)
258 return -1;
259 free(vec);
260 }
261 }
263 static int xenfb_wait_for_backend_creation(struct xenfb_device *dev)
264 {
265 struct xs_handle *xsh = dev->xenfb->xsh;
266 int state;
268 if (!xs_watch(xsh, dev->nodename, ""))
269 return -1;
270 state = xenfb_wait_for_state(xsh, dev->nodename,
271 (1 << XenbusStateInitialising)
272 | (1 << XenbusStateClosed)
273 #if 1 /* TODO fudging state to permit restarting; to be removed */
274 | (1 << XenbusStateInitWait)
275 | (1 << XenbusStateConnected)
276 | (1 << XenbusStateClosing)
277 #endif
278 );
279 xs_unwatch(xsh, dev->nodename, "");
281 switch (state) {
282 #if 1
283 case XenbusStateInitWait:
284 case XenbusStateConnected:
285 printf("Fudging state to %d\n", XenbusStateInitialising); /* FIXME */
286 #endif
287 case XenbusStateInitialising:
288 case XenbusStateClosing:
289 case XenbusStateClosed:
290 break;
291 default:
292 return -1;
293 }
295 return 0;
296 }
298 static int xenfb_hotplug(struct xenfb_device *dev)
299 {
300 if (xenfb_xs_printf(dev->xenfb->xsh, dev->nodename,
301 "hotplug-status", "connected"))
302 return -1;
303 return 0;
304 }
306 static int xenfb_wait_for_frontend_initialised(struct xenfb_device *dev)
307 {
308 switch (xenfb_wait_for_state(dev->xenfb->xsh, dev->otherend,
309 #if 1 /* TODO fudging state to permit restarting; to be removed */
310 (1 << XenbusStateInitialised)
311 | (1 << XenbusStateConnected)
312 #else
313 1 << XenbusStateInitialised,
314 #endif
315 )) {
316 #if 1
317 case XenbusStateConnected:
318 printf("Fudging state to %d\n", XenbusStateInitialised); /* FIXME */
319 #endif
320 case XenbusStateInitialised:
321 break;
322 default:
323 return -1;
324 }
326 return 0;
327 }
329 static void xenfb_copy_mfns(int mode, int count, unsigned long *dst, void *src)
330 {
331 uint32_t *src32 = src;
332 uint64_t *src64 = src;
333 int i;
335 for (i = 0; i < count; i++)
336 dst[i] = (mode == 32) ? src32[i] : src64[i];
337 }
339 static int xenfb_map_fb(struct xenfb_private *xenfb, int domid)
340 {
341 struct xenfb_page *page = xenfb->fb.page;
342 int n_fbmfns;
343 int n_fbdirs;
344 unsigned long *pgmfns = NULL;
345 unsigned long *fbmfns = NULL;
346 void *map, *pd;
347 int mode, ret = -1;
349 /* default to native */
350 pd = page->pd;
351 mode = sizeof(unsigned long) * 8;
353 if (0 == strlen(xenfb->protocol)) {
354 /*
355 * Undefined protocol, some guesswork needed.
356 *
357 * Old frontends which don't set the protocol use
358 * one page directory only, thus pd[1] must be zero.
359 * pd[1] of the 32bit struct layout and the lower
360 * 32 bits of pd[0] of the 64bit struct layout have
361 * the same location, so we can check that ...
362 */
363 uint32_t *ptr32 = NULL;
364 uint32_t *ptr64 = NULL;
365 #if defined(__i386__)
366 ptr32 = (void*)page->pd;
367 ptr64 = ((void*)page->pd) + 4;
368 #elif defined(__x86_64__)
369 ptr32 = ((void*)page->pd) - 4;
370 ptr64 = (void*)page->pd;
371 #endif
372 if (ptr32) {
373 if (0 == ptr32[1]) {
374 mode = 32;
375 pd = ptr32;
376 } else {
377 mode = 64;
378 pd = ptr64;
379 }
380 }
381 #if defined(__x86_64__)
382 } else if (0 == strcmp(xenfb->protocol, XEN_IO_PROTO_ABI_X86_32)) {
383 /* 64bit dom0, 32bit domU */
384 mode = 32;
385 pd = ((void*)page->pd) - 4;
386 #elif defined(__i386__)
387 } else if (0 == strcmp(xenfb->protocol, XEN_IO_PROTO_ABI_X86_64)) {
388 /* 32bit dom0, 64bit domU */
389 mode = 64;
390 pd = ((void*)page->pd) + 4;
391 #endif
392 }
394 n_fbmfns = (xenfb->fb_len + (XC_PAGE_SIZE - 1)) / XC_PAGE_SIZE;
395 n_fbdirs = n_fbmfns * mode / 8;
396 n_fbdirs = (n_fbdirs + (XC_PAGE_SIZE - 1)) / XC_PAGE_SIZE;
398 pgmfns = malloc(sizeof(unsigned long) * n_fbdirs);
399 fbmfns = malloc(sizeof(unsigned long) * n_fbmfns);
400 if (!pgmfns || !fbmfns)
401 goto out;
403 /*
404 * Bug alert: xc_map_foreign_batch() can fail partly and
405 * return a non-null value. This is a design flaw. When it
406 * happens, we happily continue here, and later crash on
407 * access.
408 */
409 xenfb_copy_mfns(mode, n_fbdirs, pgmfns, pd);
410 map = xc_map_foreign_batch(xenfb->xc, domid,
411 PROT_READ, pgmfns, n_fbdirs);
412 if (map == NULL)
413 goto out;
414 xenfb_copy_mfns(mode, n_fbmfns, fbmfns, map);
415 munmap(map, n_fbdirs * XC_PAGE_SIZE);
417 xenfb->pub.pixels = xc_map_foreign_batch(xenfb->xc, domid,
418 PROT_READ | PROT_WRITE, fbmfns, n_fbmfns);
419 if (xenfb->pub.pixels == NULL)
420 goto out;
422 ret = 0; /* all is fine */
424 out:
425 if (pgmfns)
426 free(pgmfns);
427 if (fbmfns)
428 free(fbmfns);
429 return ret;
430 }
432 static int xenfb_bind(struct xenfb_device *dev)
433 {
434 struct xenfb_private *xenfb = dev->xenfb;
435 unsigned long mfn;
436 evtchn_port_t evtchn;
438 if (xenfb_xs_scanf1(xenfb->xsh, dev->otherend, "page-ref", "%lu",
439 &mfn) < 0)
440 return -1;
441 if (xenfb_xs_scanf1(xenfb->xsh, dev->otherend, "event-channel", "%u",
442 &evtchn) < 0)
443 return -1;
445 dev->port = xc_evtchn_bind_interdomain(xenfb->evt_xch,
446 dev->otherend_id, evtchn);
447 if (dev->port == -1)
448 return -1;
450 dev->page = xc_map_foreign_range(xenfb->xc, dev->otherend_id,
451 XC_PAGE_SIZE, PROT_READ | PROT_WRITE, mfn);
452 if (dev->page == NULL)
453 return -1;
455 return 0;
456 }
458 static void xenfb_unbind(struct xenfb_device *dev)
459 {
460 if (dev->page) {
461 munmap(dev->page, XC_PAGE_SIZE);
462 dev->page = NULL;
463 }
464 if (dev->port >= 0) {
465 xc_evtchn_unbind(dev->xenfb->evt_xch, dev->port);
466 dev->port = -1;
467 }
468 }
470 static int xenfb_wait_for_frontend_connected(struct xenfb_device *dev)
471 {
472 switch (xenfb_wait_for_state(dev->xenfb->xsh, dev->otherend,
473 1 << XenbusStateConnected)) {
474 case XenbusStateConnected:
475 break;
476 default:
477 return -1;
478 }
480 return 0;
481 }
483 static void xenfb_dev_fatal(struct xenfb_device *dev, int err,
484 const char *fmt, ...)
485 {
486 struct xs_handle *xsh = dev->xenfb->xsh;
487 va_list ap;
488 char errdir[80];
489 char buf[1024];
490 int n;
492 fprintf(stderr, "%s ", dev->nodename); /* somewhat crude */
493 va_start(ap, fmt);
494 vfprintf(stderr, fmt, ap);
495 va_end(ap);
496 if (err)
497 fprintf(stderr, " (%s)", strerror(err));
498 putc('\n', stderr);
500 if (!xenfb_path_in_dom(xsh, errdir, sizeof(errdir), 0,
501 "error/%s", dev->nodename))
502 goto out; /* FIXME complain */
504 va_start(ap, fmt);
505 n = snprintf(buf, sizeof(buf), "%d ", err);
506 snprintf(buf + n, sizeof(buf) - n, fmt, ap);
507 va_end(ap);
509 if (xenfb_xs_printf(xsh, buf, "error", "%s", buf) < 0)
510 goto out; /* FIXME complain */
512 out:
513 xenfb_switch_state(dev, XenbusStateClosing);
514 }
516 int xenfb_attach_dom(struct xenfb *xenfb_pub, int domid)
517 {
518 struct xenfb_private *xenfb = (struct xenfb_private *)xenfb_pub;
519 struct xs_handle *xsh = xenfb->xsh;
520 int val, serrno;
521 struct xenfb_page *fb_page;
523 xenfb_detach_dom(xenfb);
525 xenfb_device_set_domain(&xenfb->fb, domid);
526 xenfb_device_set_domain(&xenfb->kbd, domid);
528 if (xenfb_wait_for_backend_creation(&xenfb->fb) < 0)
529 goto error;
530 if (xenfb_wait_for_backend_creation(&xenfb->kbd) < 0)
531 goto error;
533 if (xenfb_xs_printf(xsh, xenfb->kbd.nodename, "feature-abs-pointer", "1"))
534 goto error;
535 if (xenfb_switch_state(&xenfb->fb, XenbusStateInitWait))
536 goto error;
537 if (xenfb_switch_state(&xenfb->kbd, XenbusStateInitWait))
538 goto error;
540 if (xenfb_hotplug(&xenfb->fb) < 0)
541 goto error;
542 if (xenfb_hotplug(&xenfb->kbd) < 0)
543 goto error;
545 if (!xs_watch(xsh, xenfb->fb.otherend, ""))
546 goto error;
547 if (!xs_watch(xsh, xenfb->kbd.otherend, ""))
548 goto error;
550 if (xenfb_wait_for_frontend_initialised(&xenfb->fb) < 0)
551 goto error;
552 if (xenfb_wait_for_frontend_initialised(&xenfb->kbd) < 0)
553 goto error;
555 if (xenfb_bind(&xenfb->fb) < 0)
556 goto error;
557 if (xenfb_bind(&xenfb->kbd) < 0)
558 goto error;
560 if (xenfb_xs_scanf1(xsh, xenfb->fb.otherend, "feature-update",
561 "%d", &val) < 0)
562 val = 0;
563 if (!val) {
564 errno = ENOTSUP;
565 goto error;
566 }
567 if (xenfb_xs_scanf1(xsh, xenfb->fb.otherend, "protocol", "%63s",
568 xenfb->protocol) < 0)
569 xenfb->protocol[0] = '\0';
570 xenfb_xs_printf(xsh, xenfb->fb.nodename, "request-update", "1");
572 /* TODO check for permitted ranges */
573 fb_page = xenfb->fb.page;
574 xenfb->pub.depth = fb_page->depth;
575 xenfb->pub.width = fb_page->width;
576 xenfb->pub.height = fb_page->height;
577 /* TODO check for consistency with the above */
578 xenfb->fb_len = fb_page->mem_length;
579 xenfb->pub.row_stride = fb_page->line_length;
581 if (xenfb_map_fb(xenfb, domid) < 0)
582 goto error;
584 if (xenfb_switch_state(&xenfb->fb, XenbusStateConnected))
585 goto error;
586 if (xenfb_switch_state(&xenfb->kbd, XenbusStateConnected))
587 goto error;
589 if (xenfb_wait_for_frontend_connected(&xenfb->kbd) < 0)
590 goto error;
591 if (xenfb_xs_scanf1(xsh, xenfb->kbd.otherend, "request-abs-pointer",
592 "%d", &val) < 0)
593 val = 0;
594 xenfb->pub.abs_pointer_wanted = val;
596 return 0;
598 error:
599 serrno = errno;
600 xenfb_detach_dom(xenfb);
601 xenfb_dev_fatal(&xenfb->fb, serrno, "on fire");
602 xenfb_dev_fatal(&xenfb->kbd, serrno, "on fire");
603 errno = serrno;
604 return -1;
605 }
607 static void xenfb_detach_dom(struct xenfb_private *xenfb)
608 {
609 xenfb_unbind(&xenfb->fb);
610 xenfb_unbind(&xenfb->kbd);
611 if (xenfb->pub.pixels) {
612 munmap(xenfb->pub.pixels, xenfb->fb_len);
613 xenfb->pub.pixels = NULL;
614 }
615 }
617 static void xenfb_on_fb_event(struct xenfb_private *xenfb)
618 {
619 uint32_t prod, cons;
620 struct xenfb_page *page = xenfb->fb.page;
622 prod = page->out_prod;
623 if (prod == page->out_cons)
624 return;
625 rmb(); /* ensure we see ring contents up to prod */
626 for (cons = page->out_cons; cons != prod; cons++) {
627 union xenfb_out_event *event = &XENFB_OUT_RING_REF(page, cons);
629 switch (event->type) {
630 case XENFB_TYPE_UPDATE:
631 if (xenfb->pub.update)
632 xenfb->pub.update(&xenfb->pub,
633 event->update.x, event->update.y,
634 event->update.width, event->update.height);
635 break;
636 }
637 }
638 mb(); /* ensure we're done with ring contents */
639 page->out_cons = cons;
640 xc_evtchn_notify(xenfb->evt_xch, xenfb->fb.port);
641 }
643 static void xenfb_on_kbd_event(struct xenfb_private *xenfb)
644 {
645 struct xenkbd_page *page = xenfb->kbd.page;
647 /* We don't understand any keyboard events, so just ignore them. */
648 if (page->out_prod == page->out_cons)
649 return;
650 page->out_cons = page->out_prod;
651 xc_evtchn_notify(xenfb->evt_xch, xenfb->kbd.port);
652 }
654 static int xenfb_on_state_change(struct xenfb_device *dev)
655 {
656 enum xenbus_state state;
658 state = xenfb_read_state(dev->xenfb->xsh, dev->otherend);
660 switch (state) {
661 case XenbusStateUnknown:
662 /* There was an error reading the frontend state. The
663 domain has probably gone away; in any case, there's
664 not much point in us continuing. */
665 return -1;
666 case XenbusStateInitialising:
667 case XenbusStateInitWait:
668 case XenbusStateInitialised:
669 case XenbusStateConnected:
670 break;
671 case XenbusStateClosing:
672 xenfb_unbind(dev);
673 xenfb_switch_state(dev, state);
674 break;
675 case XenbusStateClosed:
676 xenfb_switch_state(dev, state);
677 }
678 return 0;
679 }
681 /* Returns 0 normally, -1 on error, or -2 if the domain went away. */
682 int xenfb_poll(struct xenfb *xenfb_pub, fd_set *readfds)
683 {
684 struct xenfb_private *xenfb = (struct xenfb_private *)xenfb_pub;
685 evtchn_port_t port;
686 unsigned dummy;
687 char **vec;
688 int r;
690 if (FD_ISSET(xc_evtchn_fd(xenfb->evt_xch), readfds)) {
691 port = xc_evtchn_pending(xenfb->evt_xch);
692 if (port == -1)
693 return -1;
695 if (port == xenfb->fb.port)
696 xenfb_on_fb_event(xenfb);
697 else if (port == xenfb->kbd.port)
698 xenfb_on_kbd_event(xenfb);
700 if (xc_evtchn_unmask(xenfb->evt_xch, port) == -1)
701 return -1;
702 }
704 if (FD_ISSET(xs_fileno(xenfb->xsh), readfds)) {
705 vec = xs_read_watch(xenfb->xsh, &dummy);
706 free(vec);
707 r = xenfb_on_state_change(&xenfb->fb);
708 if (r == 0)
709 r = xenfb_on_state_change(&xenfb->kbd);
710 if (r == -1)
711 return -2;
712 }
714 return 0;
715 }
717 int xenfb_select_fds(struct xenfb *xenfb_pub, fd_set *readfds)
718 {
719 struct xenfb_private *xenfb = (struct xenfb_private *)xenfb_pub;
720 int fd1 = xc_evtchn_fd(xenfb->evt_xch);
721 int fd2 = xs_fileno(xenfb->xsh);
723 FD_SET(fd1, readfds);
724 FD_SET(fd2, readfds);
725 return fd1 > fd2 ? fd1 + 1 : fd2 + 1;
726 }
728 static int xenfb_kbd_event(struct xenfb_private *xenfb,
729 union xenkbd_in_event *event)
730 {
731 uint32_t prod;
732 struct xenkbd_page *page = xenfb->kbd.page;
734 if (xenfb->kbd.state != XenbusStateConnected)
735 return 0;
737 prod = page->in_prod;
738 if (prod - page->in_cons == XENKBD_IN_RING_LEN) {
739 errno = EAGAIN;
740 return -1;
741 }
743 mb(); /* ensure ring space available */
744 XENKBD_IN_RING_REF(page, prod) = *event;
745 wmb(); /* ensure ring contents visible */
746 page->in_prod = prod + 1;
747 return xc_evtchn_notify(xenfb->evt_xch, xenfb->kbd.port);
748 }
750 int xenfb_send_key(struct xenfb *xenfb_pub, bool down, int keycode)
751 {
752 struct xenfb_private *xenfb = (struct xenfb_private *)xenfb_pub;
753 union xenkbd_in_event event;
755 memset(&event, 0, XENKBD_IN_EVENT_SIZE);
756 event.type = XENKBD_TYPE_KEY;
757 event.key.pressed = down ? 1 : 0;
758 event.key.keycode = keycode;
760 return xenfb_kbd_event(xenfb, &event);
761 }
763 int xenfb_send_motion(struct xenfb *xenfb_pub, int rel_x, int rel_y)
764 {
765 struct xenfb_private *xenfb = (struct xenfb_private *)xenfb_pub;
766 union xenkbd_in_event event;
768 memset(&event, 0, XENKBD_IN_EVENT_SIZE);
769 event.type = XENKBD_TYPE_MOTION;
770 event.motion.rel_x = rel_x;
771 event.motion.rel_y = rel_y;
773 return xenfb_kbd_event(xenfb, &event);
774 }
776 int xenfb_send_position(struct xenfb *xenfb_pub, int abs_x, int abs_y)
777 {
778 struct xenfb_private *xenfb = (struct xenfb_private *)xenfb_pub;
779 union xenkbd_in_event event;
781 memset(&event, 0, XENKBD_IN_EVENT_SIZE);
782 event.type = XENKBD_TYPE_POS;
783 event.pos.abs_x = abs_x;
784 event.pos.abs_y = abs_y;
786 return xenfb_kbd_event(xenfb, &event);
787 }