direct-io.hg

view tools/xenfb/xenfb.c @ 15456:eb2b7ce05f97

hvm vlapic: Fix one_shot argument passed to create_periodic_time().
Signed-off-by: Yosuke Iwamatsu <y-iwamatsu@ab.jp.nec.com>
author kfraser@localhost.localdomain
date Tue Jul 03 11:47:08 2007 +0100 (2007-07-03)
parents 1baac6716c62
children
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 /*
402 * Bug alert: xc_map_foreign_batch() can fail partly and
403 * return a non-null value. This is a design flaw. When it
404 * happens, we happily continue here, and later crash on
405 * access.
406 */
407 xenfb_copy_mfns(mode, n_fbdirs, pgmfns, pd);
408 map = xc_map_foreign_batch(xenfb->xc, domid,
409 PROT_READ, pgmfns, n_fbdirs);
410 if (map == NULL)
411 goto out;
412 xenfb_copy_mfns(mode, n_fbmfns, fbmfns, map);
413 munmap(map, n_fbdirs * XC_PAGE_SIZE);
415 xenfb->pub.pixels = xc_map_foreign_batch(xenfb->xc, domid,
416 PROT_READ | PROT_WRITE, fbmfns, n_fbmfns);
417 if (xenfb->pub.pixels == NULL)
418 goto out;
420 ret = 0; /* all is fine */
422 out:
423 if (pgmfns)
424 free(pgmfns);
425 if (fbmfns)
426 free(fbmfns);
427 return ret;
428 }
430 static int xenfb_bind(struct xenfb_device *dev)
431 {
432 struct xenfb_private *xenfb = dev->xenfb;
433 unsigned long mfn;
434 evtchn_port_t evtchn;
436 if (xenfb_xs_scanf1(xenfb->xsh, dev->otherend, "page-ref", "%lu",
437 &mfn) < 0)
438 return -1;
439 if (xenfb_xs_scanf1(xenfb->xsh, dev->otherend, "event-channel", "%u",
440 &evtchn) < 0)
441 return -1;
443 dev->port = xc_evtchn_bind_interdomain(xenfb->evt_xch,
444 dev->otherend_id, evtchn);
445 if (dev->port == -1)
446 return -1;
448 dev->page = xc_map_foreign_range(xenfb->xc, dev->otherend_id,
449 XC_PAGE_SIZE, PROT_READ | PROT_WRITE, mfn);
450 if (dev->page == NULL)
451 return -1;
453 return 0;
454 }
456 static void xenfb_unbind(struct xenfb_device *dev)
457 {
458 if (dev->page) {
459 munmap(dev->page, XC_PAGE_SIZE);
460 dev->page = NULL;
461 }
462 if (dev->port >= 0) {
463 xc_evtchn_unbind(dev->xenfb->evt_xch, dev->port);
464 dev->port = -1;
465 }
466 }
468 static int xenfb_wait_for_frontend_connected(struct xenfb_device *dev)
469 {
470 switch (xenfb_wait_for_state(dev->xenfb->xsh, dev->otherend,
471 1 << XenbusStateConnected)) {
472 case XenbusStateConnected:
473 break;
474 default:
475 return -1;
476 }
478 return 0;
479 }
481 static void xenfb_dev_fatal(struct xenfb_device *dev, int err,
482 const char *fmt, ...)
483 {
484 struct xs_handle *xsh = dev->xenfb->xsh;
485 va_list ap;
486 char errdir[80];
487 char buf[1024];
488 int n;
490 fprintf(stderr, "%s ", dev->nodename); /* somewhat crude */
491 va_start(ap, fmt);
492 vfprintf(stderr, fmt, ap);
493 va_end(ap);
494 if (err)
495 fprintf(stderr, " (%s)", strerror(err));
496 putc('\n', stderr);
498 if (!xenfb_path_in_dom(xsh, errdir, sizeof(errdir), 0,
499 "error/%s", dev->nodename))
500 goto out; /* FIXME complain */
502 va_start(ap, fmt);
503 n = snprintf(buf, sizeof(buf), "%d ", err);
504 snprintf(buf + n, sizeof(buf) - n, fmt, ap);
505 va_end(ap);
507 if (xenfb_xs_printf(xsh, buf, "error", "%s", buf) < 0)
508 goto out; /* FIXME complain */
510 out:
511 xenfb_switch_state(dev, XenbusStateClosing);
512 }
514 int xenfb_attach_dom(struct xenfb *xenfb_pub, int domid)
515 {
516 struct xenfb_private *xenfb = (struct xenfb_private *)xenfb_pub;
517 struct xs_handle *xsh = xenfb->xsh;
518 int val, serrno;
519 struct xenfb_page *fb_page;
521 xenfb_detach_dom(xenfb);
523 xenfb_device_set_domain(&xenfb->fb, domid);
524 xenfb_device_set_domain(&xenfb->kbd, domid);
526 if (xenfb_wait_for_backend_creation(&xenfb->fb) < 0)
527 goto error;
528 if (xenfb_wait_for_backend_creation(&xenfb->kbd) < 0)
529 goto error;
531 if (xenfb_xs_printf(xsh, xenfb->kbd.nodename, "feature-abs-pointer", "1"))
532 goto error;
533 if (xenfb_switch_state(&xenfb->fb, XenbusStateInitWait))
534 goto error;
535 if (xenfb_switch_state(&xenfb->kbd, XenbusStateInitWait))
536 goto error;
538 if (xenfb_hotplug(&xenfb->fb) < 0)
539 goto error;
540 if (xenfb_hotplug(&xenfb->kbd) < 0)
541 goto error;
543 if (!xs_watch(xsh, xenfb->fb.otherend, ""))
544 goto error;
545 if (!xs_watch(xsh, xenfb->kbd.otherend, ""))
546 goto error;
548 if (xenfb_wait_for_frontend_initialised(&xenfb->fb) < 0)
549 goto error;
550 if (xenfb_wait_for_frontend_initialised(&xenfb->kbd) < 0)
551 goto error;
553 if (xenfb_bind(&xenfb->fb) < 0)
554 goto error;
555 if (xenfb_bind(&xenfb->kbd) < 0)
556 goto error;
558 if (xenfb_xs_scanf1(xsh, xenfb->fb.otherend, "feature-update",
559 "%d", &val) < 0)
560 val = 0;
561 if (!val) {
562 errno = ENOTSUP;
563 goto error;
564 }
565 if (xenfb_xs_scanf1(xsh, xenfb->fb.otherend, "protocol", "%63s",
566 xenfb->protocol) < 0)
567 xenfb->protocol[0] = '\0';
568 xenfb_xs_printf(xsh, xenfb->fb.nodename, "request-update", "1");
570 /* TODO check for permitted ranges */
571 fb_page = xenfb->fb.page;
572 xenfb->pub.depth = fb_page->depth;
573 xenfb->pub.width = fb_page->width;
574 xenfb->pub.height = fb_page->height;
575 /* TODO check for consistency with the above */
576 xenfb->fb_len = fb_page->mem_length;
577 xenfb->pub.row_stride = fb_page->line_length;
579 if (xenfb_map_fb(xenfb, domid) < 0)
580 goto error;
582 if (xenfb_switch_state(&xenfb->fb, XenbusStateConnected))
583 goto error;
584 if (xenfb_switch_state(&xenfb->kbd, XenbusStateConnected))
585 goto error;
587 if (xenfb_wait_for_frontend_connected(&xenfb->kbd) < 0)
588 goto error;
589 if (xenfb_xs_scanf1(xsh, xenfb->kbd.otherend, "request-abs-pointer",
590 "%d", &val) < 0)
591 val = 0;
592 xenfb->pub.abs_pointer_wanted = val;
594 return 0;
596 error:
597 serrno = errno;
598 xenfb_detach_dom(xenfb);
599 xenfb_dev_fatal(&xenfb->fb, serrno, "on fire");
600 xenfb_dev_fatal(&xenfb->kbd, serrno, "on fire");
601 errno = serrno;
602 return -1;
603 }
605 static void xenfb_detach_dom(struct xenfb_private *xenfb)
606 {
607 xenfb_unbind(&xenfb->fb);
608 xenfb_unbind(&xenfb->kbd);
609 if (xenfb->pub.pixels) {
610 munmap(xenfb->pub.pixels, xenfb->fb_len);
611 xenfb->pub.pixels = NULL;
612 }
613 }
615 static void xenfb_on_fb_event(struct xenfb_private *xenfb)
616 {
617 uint32_t prod, cons;
618 struct xenfb_page *page = xenfb->fb.page;
620 prod = page->out_prod;
621 if (prod == page->out_cons)
622 return;
623 rmb(); /* ensure we see ring contents up to prod */
624 for (cons = page->out_cons; cons != prod; cons++) {
625 union xenfb_out_event *event = &XENFB_OUT_RING_REF(page, cons);
627 switch (event->type) {
628 case XENFB_TYPE_UPDATE:
629 if (xenfb->pub.update)
630 xenfb->pub.update(&xenfb->pub,
631 event->update.x, event->update.y,
632 event->update.width, event->update.height);
633 break;
634 }
635 }
636 mb(); /* ensure we're done with ring contents */
637 page->out_cons = cons;
638 xc_evtchn_notify(xenfb->evt_xch, xenfb->fb.port);
639 }
641 static void xenfb_on_kbd_event(struct xenfb_private *xenfb)
642 {
643 struct xenkbd_page *page = xenfb->kbd.page;
645 /* We don't understand any keyboard events, so just ignore them. */
646 if (page->out_prod == page->out_cons)
647 return;
648 page->out_cons = page->out_prod;
649 xc_evtchn_notify(xenfb->evt_xch, xenfb->kbd.port);
650 }
652 static int xenfb_on_state_change(struct xenfb_device *dev)
653 {
654 enum xenbus_state state;
656 state = xenfb_read_state(dev->xenfb->xsh, dev->otherend);
658 switch (state) {
659 case XenbusStateUnknown:
660 /* There was an error reading the frontend state. The
661 domain has probably gone away; in any case, there's
662 not much point in us continuing. */
663 return -1;
664 case XenbusStateInitialising:
665 case XenbusStateInitWait:
666 case XenbusStateInitialised:
667 case XenbusStateConnected:
668 break;
669 case XenbusStateClosing:
670 xenfb_unbind(dev);
671 xenfb_switch_state(dev, state);
672 break;
673 case XenbusStateClosed:
674 xenfb_switch_state(dev, state);
675 }
676 return 0;
677 }
679 /* Returns 0 normally, -1 on error, or -2 if the domain went away. */
680 int xenfb_poll(struct xenfb *xenfb_pub, fd_set *readfds)
681 {
682 struct xenfb_private *xenfb = (struct xenfb_private *)xenfb_pub;
683 evtchn_port_t port;
684 unsigned dummy;
685 char **vec;
686 int r;
688 if (FD_ISSET(xc_evtchn_fd(xenfb->evt_xch), readfds)) {
689 port = xc_evtchn_pending(xenfb->evt_xch);
690 if (port == -1)
691 return -1;
693 if (port == xenfb->fb.port)
694 xenfb_on_fb_event(xenfb);
695 else if (port == xenfb->kbd.port)
696 xenfb_on_kbd_event(xenfb);
698 if (xc_evtchn_unmask(xenfb->evt_xch, port) == -1)
699 return -1;
700 }
702 if (FD_ISSET(xs_fileno(xenfb->xsh), readfds)) {
703 vec = xs_read_watch(xenfb->xsh, &dummy);
704 free(vec);
705 r = xenfb_on_state_change(&xenfb->fb);
706 if (r == 0)
707 r = xenfb_on_state_change(&xenfb->kbd);
708 if (r == -1)
709 return -2;
710 }
712 return 0;
713 }
715 int xenfb_select_fds(struct xenfb *xenfb_pub, fd_set *readfds)
716 {
717 struct xenfb_private *xenfb = (struct xenfb_private *)xenfb_pub;
718 int fd1 = xc_evtchn_fd(xenfb->evt_xch);
719 int fd2 = xs_fileno(xenfb->xsh);
721 FD_SET(fd1, readfds);
722 FD_SET(fd2, readfds);
723 return fd1 > fd2 ? fd1 + 1 : fd2 + 1;
724 }
726 static int xenfb_kbd_event(struct xenfb_private *xenfb,
727 union xenkbd_in_event *event)
728 {
729 uint32_t prod;
730 struct xenkbd_page *page = xenfb->kbd.page;
732 if (xenfb->kbd.state != XenbusStateConnected)
733 return 0;
735 prod = page->in_prod;
736 if (prod - page->in_cons == XENKBD_IN_RING_LEN) {
737 errno = EAGAIN;
738 return -1;
739 }
741 mb(); /* ensure ring space available */
742 XENKBD_IN_RING_REF(page, prod) = *event;
743 wmb(); /* ensure ring contents visible */
744 page->in_prod = prod + 1;
745 return xc_evtchn_notify(xenfb->evt_xch, xenfb->kbd.port);
746 }
748 int xenfb_send_key(struct xenfb *xenfb_pub, bool down, int keycode)
749 {
750 struct xenfb_private *xenfb = (struct xenfb_private *)xenfb_pub;
751 union xenkbd_in_event event;
753 memset(&event, 0, XENKBD_IN_EVENT_SIZE);
754 event.type = XENKBD_TYPE_KEY;
755 event.key.pressed = down ? 1 : 0;
756 event.key.keycode = keycode;
758 return xenfb_kbd_event(xenfb, &event);
759 }
761 int xenfb_send_motion(struct xenfb *xenfb_pub, int rel_x, int rel_y)
762 {
763 struct xenfb_private *xenfb = (struct xenfb_private *)xenfb_pub;
764 union xenkbd_in_event event;
766 memset(&event, 0, XENKBD_IN_EVENT_SIZE);
767 event.type = XENKBD_TYPE_MOTION;
768 event.motion.rel_x = rel_x;
769 event.motion.rel_y = rel_y;
771 return xenfb_kbd_event(xenfb, &event);
772 }
774 int xenfb_send_position(struct xenfb *xenfb_pub, int abs_x, int abs_y)
775 {
776 struct xenfb_private *xenfb = (struct xenfb_private *)xenfb_pub;
777 union xenkbd_in_event event;
779 memset(&event, 0, XENKBD_IN_EVENT_SIZE);
780 event.type = XENKBD_TYPE_POS;
781 event.pos.abs_x = abs_x;
782 event.pos.abs_y = abs_y;
784 return xenfb_kbd_event(xenfb, &event);
785 }