ia64/xen-unstable

view tools/xenfb/xenfb.c @ 15854:9071521d4864

xc_map_foreign_pages(), a convenient alternative to xc_map_foreign_batch()

xc_map_foreign_batch() can succeed partially. It is awkward to use
when you're only interested in complete success. Provide new
xc_map_foreign_pages() convenience function for that kind of use.
Also convert two obvious calls to use it.

Signed-off-by: Markus Armbruster <armbru@redhat.com>
author kfraser@localhost.localdomain
date Fri Sep 07 11:39:10 2007 +0100 (2007-09-07)
parents 1baac6716c62
children 290b460838a8
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/event_channel.h>
14 #include <sys/mman.h>
15 #include <errno.h>
16 #include <stdio.h>
17 #include <string.h>
18 #include <time.h>
19 #include <xs.h>
21 #include "xenfb.h"
23 // FIXME defend against malicious frontend?
25 struct xenfb_device {
26 const char *devicetype;
27 char nodename[64]; /* backend xenstore dir */
28 char otherend[64]; /* frontend xenstore dir */
29 int otherend_id; /* frontend domid */
30 enum xenbus_state state; /* backend state */
31 void *page; /* shared page */
32 evtchn_port_t port;
33 struct xenfb_private *xenfb;
34 };
36 struct xenfb_private {
37 struct xenfb pub;
38 int evt_xch; /* event channel driver handle */
39 int xc; /* hypervisor interface handle */
40 struct xs_handle *xsh; /* xs daemon handle */
41 struct xenfb_device fb, kbd;
42 size_t fb_len; /* size of framebuffer */
43 char protocol[64]; /* frontend protocol */
44 };
46 static void xenfb_detach_dom(struct xenfb_private *);
48 static char *xenfb_path_in_dom(struct xs_handle *xsh,
49 char *buf, size_t size,
50 unsigned domid, const char *fmt, ...)
51 {
52 va_list ap;
53 char *domp = xs_get_domain_path(xsh, domid);
54 int n;
56 if (domp == NULL)
57 return NULL;
59 n = snprintf(buf, size, "%s/", domp);
60 free(domp);
61 if (n >= size)
62 return NULL;
64 va_start(ap, fmt);
65 n += vsnprintf(buf + n, size - n, fmt, ap);
66 va_end(ap);
67 if (n >= size)
68 return NULL;
70 return buf;
71 }
73 static int xenfb_xs_scanf1(struct xs_handle *xsh,
74 const char *dir, const char *node,
75 const char *fmt, void *dest)
76 {
77 char buf[1024];
78 char *p;
79 int ret;
81 if (snprintf(buf, sizeof(buf), "%s/%s", dir, node) >= sizeof(buf)) {
82 errno = ENOENT;
83 return -1;
84 }
85 p = xs_read(xsh, XBT_NULL, buf, NULL);
86 if (!p) {
87 errno = ENOENT;
88 return -1;
89 }
90 ret = sscanf(p, fmt, dest);
91 free(p);
92 if (ret != 1) {
93 errno = EDOM;
94 return -1;
95 }
96 return ret;
97 }
99 static int xenfb_xs_printf(struct xs_handle *xsh,
100 const char *dir, const char *node, char *fmt, ...)
101 {
102 va_list ap;
103 char key[1024];
104 char val[1024];
105 int n;
107 if (snprintf(key, sizeof(key), "%s/%s", dir, node) >= sizeof(key)) {
108 errno = ENOENT;
109 return -1;
110 }
112 va_start(ap, fmt);
113 n = vsnprintf(val, sizeof(val), fmt, ap);
114 va_end(ap);
115 if (n >= sizeof(val)) {
116 errno = ENOSPC; /* close enough */
117 return -1;
118 }
120 if (!xs_write(xsh, XBT_NULL, key, val, n))
121 return -1;
122 return 0;
123 }
125 static void xenfb_device_init(struct xenfb_device *dev,
126 const char *type,
127 struct xenfb_private *xenfb)
128 {
129 dev->devicetype = type;
130 dev->otherend_id = -1;
131 dev->port = -1;
132 dev->xenfb = xenfb;
133 }
135 int xenfb_device_set_domain(struct xenfb_device *dev, int domid)
136 {
137 struct xenfb_private *xenfb = dev->xenfb;
139 dev->otherend_id = domid;
141 if (!xenfb_path_in_dom(xenfb->xsh,
142 dev->otherend, sizeof(dev->otherend),
143 domid, "device/%s/0", dev->devicetype)) {
144 errno = ENOENT;
145 return -1;
146 }
147 if (!xenfb_path_in_dom(xenfb->xsh,
148 dev->nodename, sizeof(dev->nodename),
149 0, "backend/%s/%d/0", dev->devicetype, domid)) {
150 errno = ENOENT;
151 return -1;
152 }
154 return 0;
155 }
157 struct xenfb *xenfb_new(void)
158 {
159 struct xenfb_private *xenfb = malloc(sizeof(*xenfb));
160 int serrno;
162 if (xenfb == NULL)
163 return NULL;
165 memset(xenfb, 0, sizeof(*xenfb));
166 xenfb->evt_xch = xenfb->xc = -1;
167 xenfb_device_init(&xenfb->fb, "vfb", xenfb);
168 xenfb_device_init(&xenfb->kbd, "vkbd", xenfb);
170 xenfb->evt_xch = xc_evtchn_open();
171 if (xenfb->evt_xch == -1)
172 goto fail;
174 xenfb->xc = xc_interface_open();
175 if (xenfb->xc == -1)
176 goto fail;
178 xenfb->xsh = xs_daemon_open();
179 if (!xenfb->xsh)
180 goto fail;
182 return &xenfb->pub;
184 fail:
185 serrno = errno;
186 xenfb_delete(&xenfb->pub);
187 errno = serrno;
188 return NULL;
189 }
191 /* Remove the backend area in xenbus since the framebuffer really is
192 going away. */
193 void xenfb_teardown(struct xenfb *xenfb_pub)
194 {
195 struct xenfb_private *xenfb = (struct xenfb_private *)xenfb_pub;
197 xs_rm(xenfb->xsh, XBT_NULL, xenfb->fb.nodename);
198 xs_rm(xenfb->xsh, XBT_NULL, xenfb->kbd.nodename);
199 }
202 void xenfb_delete(struct xenfb *xenfb_pub)
203 {
204 struct xenfb_private *xenfb = (struct xenfb_private *)xenfb_pub;
206 xenfb_detach_dom(xenfb);
207 if (xenfb->xc >= 0)
208 xc_interface_close(xenfb->xc);
209 if (xenfb->evt_xch >= 0)
210 xc_evtchn_close(xenfb->evt_xch);
211 if (xenfb->xsh)
212 xs_daemon_close(xenfb->xsh);
213 free(xenfb);
214 }
216 static enum xenbus_state xenfb_read_state(struct xs_handle *xsh,
217 const char *dir)
218 {
219 int ret, state;
221 ret = xenfb_xs_scanf1(xsh, dir, "state", "%d", &state);
222 if (ret < 0)
223 return XenbusStateUnknown;
225 if ((unsigned)state > XenbusStateClosed)
226 state = XenbusStateUnknown;
227 return state;
228 }
230 static int xenfb_switch_state(struct xenfb_device *dev,
231 enum xenbus_state state)
232 {
233 struct xs_handle *xsh = dev->xenfb->xsh;
235 if (xenfb_xs_printf(xsh, dev->nodename, "state", "%d", state) < 0)
236 return -1;
237 dev->state = state;
238 return 0;
239 }
241 static int xenfb_wait_for_state(struct xs_handle *xsh, const char *dir,
242 unsigned awaited)
243 {
244 unsigned state, dummy;
245 char **vec;
247 awaited |= 1 << XenbusStateUnknown;
249 for (;;) {
250 state = xenfb_read_state(xsh, dir);
251 if ((1 << state) & awaited)
252 return state;
254 vec = xs_read_watch(xsh, &dummy);
255 if (!vec)
256 return -1;
257 free(vec);
258 }
259 }
261 static int xenfb_wait_for_backend_creation(struct xenfb_device *dev)
262 {
263 struct xs_handle *xsh = dev->xenfb->xsh;
264 int state;
266 if (!xs_watch(xsh, dev->nodename, ""))
267 return -1;
268 state = xenfb_wait_for_state(xsh, dev->nodename,
269 (1 << XenbusStateInitialising)
270 | (1 << XenbusStateClosed)
271 #if 1 /* TODO fudging state to permit restarting; to be removed */
272 | (1 << XenbusStateInitWait)
273 | (1 << XenbusStateConnected)
274 | (1 << XenbusStateClosing)
275 #endif
276 );
277 xs_unwatch(xsh, dev->nodename, "");
279 switch (state) {
280 #if 1
281 case XenbusStateInitWait:
282 case XenbusStateConnected:
283 printf("Fudging state to %d\n", XenbusStateInitialising); /* FIXME */
284 #endif
285 case XenbusStateInitialising:
286 case XenbusStateClosing:
287 case XenbusStateClosed:
288 break;
289 default:
290 return -1;
291 }
293 return 0;
294 }
296 static int xenfb_hotplug(struct xenfb_device *dev)
297 {
298 if (xenfb_xs_printf(dev->xenfb->xsh, dev->nodename,
299 "hotplug-status", "connected"))
300 return -1;
301 return 0;
302 }
304 static int xenfb_wait_for_frontend_initialised(struct xenfb_device *dev)
305 {
306 switch (xenfb_wait_for_state(dev->xenfb->xsh, dev->otherend,
307 #if 1 /* TODO fudging state to permit restarting; to be removed */
308 (1 << XenbusStateInitialised)
309 | (1 << XenbusStateConnected)
310 #else
311 1 << XenbusStateInitialised,
312 #endif
313 )) {
314 #if 1
315 case XenbusStateConnected:
316 printf("Fudging state to %d\n", XenbusStateInitialised); /* FIXME */
317 #endif
318 case XenbusStateInitialised:
319 break;
320 default:
321 return -1;
322 }
324 return 0;
325 }
327 static void xenfb_copy_mfns(int mode, int count, unsigned long *dst, void *src)
328 {
329 uint32_t *src32 = src;
330 uint64_t *src64 = src;
331 int i;
333 for (i = 0; i < count; i++)
334 dst[i] = (mode == 32) ? src32[i] : src64[i];
335 }
337 static int xenfb_map_fb(struct xenfb_private *xenfb, int domid)
338 {
339 struct xenfb_page *page = xenfb->fb.page;
340 int n_fbmfns;
341 int n_fbdirs;
342 unsigned long *pgmfns = NULL;
343 unsigned long *fbmfns = NULL;
344 void *map, *pd;
345 int mode, ret = -1;
347 /* default to native */
348 pd = page->pd;
349 mode = sizeof(unsigned long) * 8;
351 if (0 == strlen(xenfb->protocol)) {
352 /*
353 * Undefined protocol, some guesswork needed.
354 *
355 * Old frontends which don't set the protocol use
356 * one page directory only, thus pd[1] must be zero.
357 * pd[1] of the 32bit struct layout and the lower
358 * 32 bits of pd[0] of the 64bit struct layout have
359 * the same location, so we can check that ...
360 */
361 uint32_t *ptr32 = NULL;
362 uint32_t *ptr64 = NULL;
363 #if defined(__i386__)
364 ptr32 = (void*)page->pd;
365 ptr64 = ((void*)page->pd) + 4;
366 #elif defined(__x86_64__)
367 ptr32 = ((void*)page->pd) - 4;
368 ptr64 = (void*)page->pd;
369 #endif
370 if (ptr32) {
371 if (0 == ptr32[1]) {
372 mode = 32;
373 pd = ptr32;
374 } else {
375 mode = 64;
376 pd = ptr64;
377 }
378 }
379 #if defined(__x86_64__)
380 } else if (0 == strcmp(xenfb->protocol, XEN_IO_PROTO_ABI_X86_32)) {
381 /* 64bit dom0, 32bit domU */
382 mode = 32;
383 pd = ((void*)page->pd) - 4;
384 #elif defined(__i386__)
385 } else if (0 == strcmp(xenfb->protocol, XEN_IO_PROTO_ABI_X86_64)) {
386 /* 32bit dom0, 64bit domU */
387 mode = 64;
388 pd = ((void*)page->pd) + 4;
389 #endif
390 }
392 n_fbmfns = (xenfb->fb_len + (XC_PAGE_SIZE - 1)) / XC_PAGE_SIZE;
393 n_fbdirs = n_fbmfns * mode / 8;
394 n_fbdirs = (n_fbdirs + (XC_PAGE_SIZE - 1)) / XC_PAGE_SIZE;
396 pgmfns = malloc(sizeof(unsigned long) * n_fbdirs);
397 fbmfns = malloc(sizeof(unsigned long) * n_fbmfns);
398 if (!pgmfns || !fbmfns)
399 goto out;
401 xenfb_copy_mfns(mode, n_fbdirs, pgmfns, pd);
402 map = xc_map_foreign_pages(xenfb->xc, domid,
403 PROT_READ, pgmfns, n_fbdirs);
404 if (map == NULL)
405 goto out;
406 xenfb_copy_mfns(mode, n_fbmfns, fbmfns, map);
407 munmap(map, n_fbdirs * XC_PAGE_SIZE);
409 xenfb->pub.pixels = xc_map_foreign_pages(xenfb->xc, domid,
410 PROT_READ | PROT_WRITE, fbmfns, n_fbmfns);
411 if (xenfb->pub.pixels == NULL)
412 goto out;
414 ret = 0; /* all is fine */
416 out:
417 if (pgmfns)
418 free(pgmfns);
419 if (fbmfns)
420 free(fbmfns);
421 return ret;
422 }
424 static int xenfb_bind(struct xenfb_device *dev)
425 {
426 struct xenfb_private *xenfb = dev->xenfb;
427 unsigned long mfn;
428 evtchn_port_t evtchn;
430 if (xenfb_xs_scanf1(xenfb->xsh, dev->otherend, "page-ref", "%lu",
431 &mfn) < 0)
432 return -1;
433 if (xenfb_xs_scanf1(xenfb->xsh, dev->otherend, "event-channel", "%u",
434 &evtchn) < 0)
435 return -1;
437 dev->port = xc_evtchn_bind_interdomain(xenfb->evt_xch,
438 dev->otherend_id, evtchn);
439 if (dev->port == -1)
440 return -1;
442 dev->page = xc_map_foreign_range(xenfb->xc, dev->otherend_id,
443 XC_PAGE_SIZE, PROT_READ | PROT_WRITE, mfn);
444 if (dev->page == NULL)
445 return -1;
447 return 0;
448 }
450 static void xenfb_unbind(struct xenfb_device *dev)
451 {
452 if (dev->page) {
453 munmap(dev->page, XC_PAGE_SIZE);
454 dev->page = NULL;
455 }
456 if (dev->port >= 0) {
457 xc_evtchn_unbind(dev->xenfb->evt_xch, dev->port);
458 dev->port = -1;
459 }
460 }
462 static int xenfb_wait_for_frontend_connected(struct xenfb_device *dev)
463 {
464 switch (xenfb_wait_for_state(dev->xenfb->xsh, dev->otherend,
465 1 << XenbusStateConnected)) {
466 case XenbusStateConnected:
467 break;
468 default:
469 return -1;
470 }
472 return 0;
473 }
475 static void xenfb_dev_fatal(struct xenfb_device *dev, int err,
476 const char *fmt, ...)
477 {
478 struct xs_handle *xsh = dev->xenfb->xsh;
479 va_list ap;
480 char errdir[80];
481 char buf[1024];
482 int n;
484 fprintf(stderr, "%s ", dev->nodename); /* somewhat crude */
485 va_start(ap, fmt);
486 vfprintf(stderr, fmt, ap);
487 va_end(ap);
488 if (err)
489 fprintf(stderr, " (%s)", strerror(err));
490 putc('\n', stderr);
492 if (!xenfb_path_in_dom(xsh, errdir, sizeof(errdir), 0,
493 "error/%s", dev->nodename))
494 goto out; /* FIXME complain */
496 va_start(ap, fmt);
497 n = snprintf(buf, sizeof(buf), "%d ", err);
498 snprintf(buf + n, sizeof(buf) - n, fmt, ap);
499 va_end(ap);
501 if (xenfb_xs_printf(xsh, buf, "error", "%s", buf) < 0)
502 goto out; /* FIXME complain */
504 out:
505 xenfb_switch_state(dev, XenbusStateClosing);
506 }
508 int xenfb_attach_dom(struct xenfb *xenfb_pub, int domid)
509 {
510 struct xenfb_private *xenfb = (struct xenfb_private *)xenfb_pub;
511 struct xs_handle *xsh = xenfb->xsh;
512 int val, serrno;
513 struct xenfb_page *fb_page;
515 xenfb_detach_dom(xenfb);
517 xenfb_device_set_domain(&xenfb->fb, domid);
518 xenfb_device_set_domain(&xenfb->kbd, domid);
520 if (xenfb_wait_for_backend_creation(&xenfb->fb) < 0)
521 goto error;
522 if (xenfb_wait_for_backend_creation(&xenfb->kbd) < 0)
523 goto error;
525 if (xenfb_xs_printf(xsh, xenfb->kbd.nodename, "feature-abs-pointer", "1"))
526 goto error;
527 if (xenfb_switch_state(&xenfb->fb, XenbusStateInitWait))
528 goto error;
529 if (xenfb_switch_state(&xenfb->kbd, XenbusStateInitWait))
530 goto error;
532 if (xenfb_hotplug(&xenfb->fb) < 0)
533 goto error;
534 if (xenfb_hotplug(&xenfb->kbd) < 0)
535 goto error;
537 if (!xs_watch(xsh, xenfb->fb.otherend, ""))
538 goto error;
539 if (!xs_watch(xsh, xenfb->kbd.otherend, ""))
540 goto error;
542 if (xenfb_wait_for_frontend_initialised(&xenfb->fb) < 0)
543 goto error;
544 if (xenfb_wait_for_frontend_initialised(&xenfb->kbd) < 0)
545 goto error;
547 if (xenfb_bind(&xenfb->fb) < 0)
548 goto error;
549 if (xenfb_bind(&xenfb->kbd) < 0)
550 goto error;
552 if (xenfb_xs_scanf1(xsh, xenfb->fb.otherend, "feature-update",
553 "%d", &val) < 0)
554 val = 0;
555 if (!val) {
556 errno = ENOTSUP;
557 goto error;
558 }
559 if (xenfb_xs_scanf1(xsh, xenfb->fb.otherend, "protocol", "%63s",
560 xenfb->protocol) < 0)
561 xenfb->protocol[0] = '\0';
562 xenfb_xs_printf(xsh, xenfb->fb.nodename, "request-update", "1");
564 /* TODO check for permitted ranges */
565 fb_page = xenfb->fb.page;
566 xenfb->pub.depth = fb_page->depth;
567 xenfb->pub.width = fb_page->width;
568 xenfb->pub.height = fb_page->height;
569 /* TODO check for consistency with the above */
570 xenfb->fb_len = fb_page->mem_length;
571 xenfb->pub.row_stride = fb_page->line_length;
573 if (xenfb_map_fb(xenfb, domid) < 0)
574 goto error;
576 if (xenfb_switch_state(&xenfb->fb, XenbusStateConnected))
577 goto error;
578 if (xenfb_switch_state(&xenfb->kbd, XenbusStateConnected))
579 goto error;
581 if (xenfb_wait_for_frontend_connected(&xenfb->kbd) < 0)
582 goto error;
583 if (xenfb_xs_scanf1(xsh, xenfb->kbd.otherend, "request-abs-pointer",
584 "%d", &val) < 0)
585 val = 0;
586 xenfb->pub.abs_pointer_wanted = val;
588 return 0;
590 error:
591 serrno = errno;
592 xenfb_detach_dom(xenfb);
593 xenfb_dev_fatal(&xenfb->fb, serrno, "on fire");
594 xenfb_dev_fatal(&xenfb->kbd, serrno, "on fire");
595 errno = serrno;
596 return -1;
597 }
599 static void xenfb_detach_dom(struct xenfb_private *xenfb)
600 {
601 xenfb_unbind(&xenfb->fb);
602 xenfb_unbind(&xenfb->kbd);
603 if (xenfb->pub.pixels) {
604 munmap(xenfb->pub.pixels, xenfb->fb_len);
605 xenfb->pub.pixels = NULL;
606 }
607 }
609 static void xenfb_on_fb_event(struct xenfb_private *xenfb)
610 {
611 uint32_t prod, cons;
612 struct xenfb_page *page = xenfb->fb.page;
614 prod = page->out_prod;
615 if (prod == page->out_cons)
616 return;
617 rmb(); /* ensure we see ring contents up to prod */
618 for (cons = page->out_cons; cons != prod; cons++) {
619 union xenfb_out_event *event = &XENFB_OUT_RING_REF(page, cons);
621 switch (event->type) {
622 case XENFB_TYPE_UPDATE:
623 if (xenfb->pub.update)
624 xenfb->pub.update(&xenfb->pub,
625 event->update.x, event->update.y,
626 event->update.width, event->update.height);
627 break;
628 }
629 }
630 mb(); /* ensure we're done with ring contents */
631 page->out_cons = cons;
632 xc_evtchn_notify(xenfb->evt_xch, xenfb->fb.port);
633 }
635 static void xenfb_on_kbd_event(struct xenfb_private *xenfb)
636 {
637 struct xenkbd_page *page = xenfb->kbd.page;
639 /* We don't understand any keyboard events, so just ignore them. */
640 if (page->out_prod == page->out_cons)
641 return;
642 page->out_cons = page->out_prod;
643 xc_evtchn_notify(xenfb->evt_xch, xenfb->kbd.port);
644 }
646 static int xenfb_on_state_change(struct xenfb_device *dev)
647 {
648 enum xenbus_state state;
650 state = xenfb_read_state(dev->xenfb->xsh, dev->otherend);
652 switch (state) {
653 case XenbusStateUnknown:
654 /* There was an error reading the frontend state. The
655 domain has probably gone away; in any case, there's
656 not much point in us continuing. */
657 return -1;
658 case XenbusStateInitialising:
659 case XenbusStateInitWait:
660 case XenbusStateInitialised:
661 case XenbusStateConnected:
662 break;
663 case XenbusStateClosing:
664 xenfb_unbind(dev);
665 xenfb_switch_state(dev, state);
666 break;
667 case XenbusStateClosed:
668 xenfb_switch_state(dev, state);
669 }
670 return 0;
671 }
673 /* Returns 0 normally, -1 on error, or -2 if the domain went away. */
674 int xenfb_poll(struct xenfb *xenfb_pub, fd_set *readfds)
675 {
676 struct xenfb_private *xenfb = (struct xenfb_private *)xenfb_pub;
677 evtchn_port_t port;
678 unsigned dummy;
679 char **vec;
680 int r;
682 if (FD_ISSET(xc_evtchn_fd(xenfb->evt_xch), readfds)) {
683 port = xc_evtchn_pending(xenfb->evt_xch);
684 if (port == -1)
685 return -1;
687 if (port == xenfb->fb.port)
688 xenfb_on_fb_event(xenfb);
689 else if (port == xenfb->kbd.port)
690 xenfb_on_kbd_event(xenfb);
692 if (xc_evtchn_unmask(xenfb->evt_xch, port) == -1)
693 return -1;
694 }
696 if (FD_ISSET(xs_fileno(xenfb->xsh), readfds)) {
697 vec = xs_read_watch(xenfb->xsh, &dummy);
698 free(vec);
699 r = xenfb_on_state_change(&xenfb->fb);
700 if (r == 0)
701 r = xenfb_on_state_change(&xenfb->kbd);
702 if (r == -1)
703 return -2;
704 }
706 return 0;
707 }
709 int xenfb_select_fds(struct xenfb *xenfb_pub, fd_set *readfds)
710 {
711 struct xenfb_private *xenfb = (struct xenfb_private *)xenfb_pub;
712 int fd1 = xc_evtchn_fd(xenfb->evt_xch);
713 int fd2 = xs_fileno(xenfb->xsh);
715 FD_SET(fd1, readfds);
716 FD_SET(fd2, readfds);
717 return fd1 > fd2 ? fd1 + 1 : fd2 + 1;
718 }
720 static int xenfb_kbd_event(struct xenfb_private *xenfb,
721 union xenkbd_in_event *event)
722 {
723 uint32_t prod;
724 struct xenkbd_page *page = xenfb->kbd.page;
726 if (xenfb->kbd.state != XenbusStateConnected)
727 return 0;
729 prod = page->in_prod;
730 if (prod - page->in_cons == XENKBD_IN_RING_LEN) {
731 errno = EAGAIN;
732 return -1;
733 }
735 mb(); /* ensure ring space available */
736 XENKBD_IN_RING_REF(page, prod) = *event;
737 wmb(); /* ensure ring contents visible */
738 page->in_prod = prod + 1;
739 return xc_evtchn_notify(xenfb->evt_xch, xenfb->kbd.port);
740 }
742 int xenfb_send_key(struct xenfb *xenfb_pub, bool down, int keycode)
743 {
744 struct xenfb_private *xenfb = (struct xenfb_private *)xenfb_pub;
745 union xenkbd_in_event event;
747 memset(&event, 0, XENKBD_IN_EVENT_SIZE);
748 event.type = XENKBD_TYPE_KEY;
749 event.key.pressed = down ? 1 : 0;
750 event.key.keycode = keycode;
752 return xenfb_kbd_event(xenfb, &event);
753 }
755 int xenfb_send_motion(struct xenfb *xenfb_pub, int rel_x, int rel_y)
756 {
757 struct xenfb_private *xenfb = (struct xenfb_private *)xenfb_pub;
758 union xenkbd_in_event event;
760 memset(&event, 0, XENKBD_IN_EVENT_SIZE);
761 event.type = XENKBD_TYPE_MOTION;
762 event.motion.rel_x = rel_x;
763 event.motion.rel_y = rel_y;
765 return xenfb_kbd_event(xenfb, &event);
766 }
768 int xenfb_send_position(struct xenfb *xenfb_pub, int abs_x, int abs_y)
769 {
770 struct xenfb_private *xenfb = (struct xenfb_private *)xenfb_pub;
771 union xenkbd_in_event event;
773 memset(&event, 0, XENKBD_IN_EVENT_SIZE);
774 event.type = XENKBD_TYPE_POS;
775 event.pos.abs_x = abs_x;
776 event.pos.abs_y = abs_y;
778 return xenfb_kbd_event(xenfb, &event);
779 }