source: trunk/packages/xen-common/xen-common/tools/xenfb/xenfb.c @ 95

Last change on this file since 95 was 34, checked in by hartmans, 17 years ago

Add xen and xen-common

File size: 18.2 KB
Line 
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>
21
22#include "xenfb.h"
23
24// FIXME defend against malicious frontend?
25
26struct 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};
36
37struct 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};
46
47static void xenfb_detach_dom(struct xenfb_private *);
48
49static 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;
56
57        if (domp == NULL)
58                return NULL;
59
60        n = snprintf(buf, size, "%s/", domp);
61        free(domp);
62        if (n >= size)
63                return NULL;
64
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;
70
71        return buf;
72}
73
74static 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;
81
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}
99
100static 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;
107
108        if (snprintf(key, sizeof(key), "%s/%s", dir, node) >= sizeof(key)) {
109                errno = ENOENT;
110                return -1;
111        }
112
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        }
120
121        if (!xs_write(xsh, XBT_NULL, key, val, n))
122                return -1;
123        return 0;
124}
125
126static 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}
135
136int xenfb_device_set_domain(struct xenfb_device *dev, int domid)
137{
138        struct xenfb_private *xenfb = dev->xenfb;
139
140        dev->otherend_id = domid;
141
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        }
154
155        return 0;
156}
157
158struct xenfb *xenfb_new(void)
159{
160        struct xenfb_private *xenfb = malloc(sizeof(*xenfb));
161        int serrno;
162
163        if (xenfb == NULL)
164                return NULL;
165
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);
170
171        xenfb->evt_xch = xc_evtchn_open();
172        if (xenfb->evt_xch == -1)
173                goto fail;
174
175        xenfb->xc = xc_interface_open();
176        if (xenfb->xc == -1)
177                goto fail;
178
179        xenfb->xsh = xs_daemon_open();
180        if (!xenfb->xsh)
181                goto fail;
182
183        return &xenfb->pub;
184
185 fail:
186        serrno = errno;
187        xenfb_delete(&xenfb->pub);
188        errno = serrno;
189        return NULL;
190}
191
192/* Remove the backend area in xenbus since the framebuffer really is
193   going away. */
194void xenfb_teardown(struct xenfb *xenfb_pub)
195{
196       struct xenfb_private *xenfb = (struct xenfb_private *)xenfb_pub;
197
198       xs_rm(xenfb->xsh, XBT_NULL, xenfb->fb.nodename);
199       xs_rm(xenfb->xsh, XBT_NULL, xenfb->kbd.nodename);
200}
201
202
203void xenfb_delete(struct xenfb *xenfb_pub)
204{
205        struct xenfb_private *xenfb = (struct xenfb_private *)xenfb_pub;
206
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}
216
217static enum xenbus_state xenfb_read_state(struct xs_handle *xsh,
218                                          const char *dir)
219{
220        int ret, state;
221
222        ret = xenfb_xs_scanf1(xsh, dir, "state", "%d", &state);
223        if (ret < 0)
224                return XenbusStateUnknown;
225
226        if ((unsigned)state > XenbusStateClosed)
227                state = XenbusStateUnknown;
228        return state;
229}
230
231static int xenfb_switch_state(struct xenfb_device *dev,
232                              enum xenbus_state state)
233{
234        struct xs_handle *xsh = dev->xenfb->xsh;
235
236        if (xenfb_xs_printf(xsh, dev->nodename, "state", "%d", state) < 0)
237                return -1;
238        dev->state = state;
239        return 0;
240}
241
242static int xenfb_wait_for_state(struct xs_handle *xsh, const char *dir,
243                                unsigned awaited)
244{
245        unsigned state, dummy;
246        char **vec;
247
248        awaited |= 1 << XenbusStateUnknown;
249
250        for (;;) {
251                state = xenfb_read_state(xsh, dir);
252                if ((1 << state) & awaited)
253                        return state;
254
255                vec = xs_read_watch(xsh, &dummy);
256                if (!vec)
257                        return -1;
258                free(vec);
259        }
260}
261
262static int xenfb_wait_for_backend_creation(struct xenfb_device *dev)
263{
264        struct xs_handle *xsh = dev->xenfb->xsh;
265        int state;
266
267        if (!xs_watch(xsh, dev->nodename, ""))
268                return -1;
269        state = xenfb_wait_for_state(xsh, dev->nodename,
270                        (1 << XenbusStateInitialising)
271                        | (1 << XenbusStateClosed)
272#if 1 /* TODO fudging state to permit restarting; to be removed */
273                        | (1 << XenbusStateInitWait)
274                        | (1 << XenbusStateConnected)
275                        | (1 << XenbusStateClosing)
276#endif
277                        );
278        xs_unwatch(xsh, dev->nodename, "");
279
280        switch (state) {
281#if 1
282        case XenbusStateInitWait:
283        case XenbusStateConnected:
284                printf("Fudging state to %d\n", XenbusStateInitialising); /* FIXME */
285#endif
286        case XenbusStateInitialising:
287        case XenbusStateClosing:
288        case XenbusStateClosed:
289                break;
290        default:
291                return -1;
292        }
293
294        return 0;
295}
296
297static int xenfb_hotplug(struct xenfb_device *dev)
298{
299        if (xenfb_xs_printf(dev->xenfb->xsh, dev->nodename,
300                            "hotplug-status", "connected"))
301                return -1;
302        return 0;
303}
304
305static int xenfb_wait_for_frontend_initialised(struct xenfb_device *dev)
306{
307        switch (xenfb_wait_for_state(dev->xenfb->xsh, dev->otherend,
308#if 1 /* TODO fudging state to permit restarting; to be removed */
309                        (1 << XenbusStateInitialised)
310                        | (1 << XenbusStateConnected)
311#else
312                        1 << XenbusStateInitialised,
313#endif
314                        )) {
315#if 1
316        case XenbusStateConnected:
317                printf("Fudging state to %d\n", XenbusStateInitialised); /* FIXME */
318#endif
319        case XenbusStateInitialised:
320                break;
321        default:
322                return -1;
323        }
324
325        return 0;
326}
327
328static void xenfb_copy_mfns(int mode, int count, unsigned long *dst, void *src)
329{
330        uint32_t *src32 = src;
331        uint64_t *src64 = src;
332        int i;
333
334        for (i = 0; i < count; i++)
335                dst[i] = (mode == 32) ? src32[i] : src64[i];
336}
337
338static int xenfb_map_fb(struct xenfb_private *xenfb, int domid)
339{
340        struct xenfb_page *page = xenfb->fb.page;
341        int n_fbmfns;
342        int n_fbdirs;
343        unsigned long *pgmfns = NULL;
344        unsigned long *fbmfns = NULL;
345        void *map, *pd;
346        int mode, ret = -1;
347
348        /* default to native */
349        pd = page->pd;
350        mode = sizeof(unsigned long) * 8;
351
352        if (0 == strlen(xenfb->protocol)) {
353                /*
354                 * Undefined protocol, some guesswork needed.
355                 *
356                 * Old frontends which don't set the protocol use
357                 * one page directory only, thus pd[1] must be zero.
358                 * pd[1] of the 32bit struct layout and the lower
359                 * 32 bits of pd[0] of the 64bit struct layout have
360                 * the same location, so we can check that ...
361                 */
362                uint32_t *ptr32 = NULL;
363                uint32_t *ptr64 = NULL;
364#if defined(__i386__)
365                ptr32 = (void*)page->pd;
366                ptr64 = ((void*)page->pd) + 4;
367#elif defined(__x86_64__)
368                ptr32 = ((void*)page->pd) - 4;
369                ptr64 = (void*)page->pd;
370#endif
371                if (ptr32) {
372                        if (0 == ptr32[1]) {
373                                mode = 32;
374                                pd   = ptr32;
375                        } else {
376                                mode = 64;
377                                pd   = ptr64;
378                        }
379                }
380#if defined(__x86_64__)
381        } else if (0 == strcmp(xenfb->protocol, XEN_IO_PROTO_ABI_X86_32)) {
382                /* 64bit dom0, 32bit domU */
383                mode = 32;
384                pd   = ((void*)page->pd) - 4;
385#elif defined(__i386__)
386        } else if (0 == strcmp(xenfb->protocol, XEN_IO_PROTO_ABI_X86_64)) {
387                /* 32bit dom0, 64bit domU */
388                mode = 64;
389                pd   = ((void*)page->pd) + 4;
390#endif
391        }
392
393        n_fbmfns = (xenfb->fb_len + (XC_PAGE_SIZE - 1)) / XC_PAGE_SIZE;
394        n_fbdirs = n_fbmfns * mode / 8;
395        n_fbdirs = (n_fbdirs + (XC_PAGE_SIZE - 1)) / XC_PAGE_SIZE;
396
397        pgmfns = malloc(sizeof(unsigned long) * n_fbdirs);
398        fbmfns = malloc(sizeof(unsigned long) * n_fbmfns);
399        if (!pgmfns || !fbmfns)
400                goto out;
401
402        /*
403         * Bug alert: xc_map_foreign_batch() can fail partly and
404         * return a non-null value.  This is a design flaw.  When it
405         * happens, we happily continue here, and later crash on
406         * access.
407         */
408        xenfb_copy_mfns(mode, n_fbdirs, pgmfns, pd);
409        map = xc_map_foreign_batch(xenfb->xc, domid,
410                                   PROT_READ, pgmfns, n_fbdirs);
411        if (map == NULL)
412                goto out;
413        xenfb_copy_mfns(mode, n_fbmfns, fbmfns, map);
414        munmap(map, n_fbdirs * XC_PAGE_SIZE);
415
416        xenfb->pub.pixels = xc_map_foreign_batch(xenfb->xc, domid,
417                                PROT_READ | PROT_WRITE, fbmfns, n_fbmfns);
418        if (xenfb->pub.pixels == NULL)
419                goto out;
420
421        ret = 0; /* all is fine */
422
423 out:
424        if (pgmfns)
425                free(pgmfns);
426        if (fbmfns)
427                free(fbmfns);
428        return ret;
429}
430
431static int xenfb_bind(struct xenfb_device *dev)
432{
433        struct xenfb_private *xenfb = dev->xenfb;
434        unsigned long mfn;
435        evtchn_port_t evtchn;
436
437        if (xenfb_xs_scanf1(xenfb->xsh, dev->otherend, "page-ref", "%lu",
438                            &mfn) < 0)
439                return -1;
440        if (xenfb_xs_scanf1(xenfb->xsh, dev->otherend, "event-channel", "%u",
441                            &evtchn) < 0)
442                return -1;
443
444        dev->port = xc_evtchn_bind_interdomain(xenfb->evt_xch,
445                                               dev->otherend_id, evtchn);
446        if (dev->port == -1)
447                return -1;
448
449        dev->page = xc_map_foreign_range(xenfb->xc, dev->otherend_id,
450                        XC_PAGE_SIZE, PROT_READ | PROT_WRITE, mfn);
451        if (dev->page == NULL)
452                return -1;
453
454        return 0;
455}
456
457static void xenfb_unbind(struct xenfb_device *dev)
458{
459        if (dev->page) {
460                munmap(dev->page, XC_PAGE_SIZE);
461                dev->page = NULL;
462        }
463        if (dev->port >= 0) {
464                xc_evtchn_unbind(dev->xenfb->evt_xch, dev->port);
465                dev->port = -1;
466        }
467}
468
469static int xenfb_wait_for_frontend_connected(struct xenfb_device *dev)
470{
471        switch (xenfb_wait_for_state(dev->xenfb->xsh, dev->otherend,
472                                     1 << XenbusStateConnected)) {
473        case XenbusStateConnected:
474                break;
475        default:
476                return -1;
477        }
478
479        return 0;
480}
481
482static void xenfb_dev_fatal(struct xenfb_device *dev, int err,
483                            const char *fmt, ...)
484{
485        struct xs_handle *xsh = dev->xenfb->xsh;
486        va_list ap;
487        char errdir[80];
488        char buf[1024];
489        int n;
490
491        fprintf(stderr, "%s ", dev->nodename); /* somewhat crude */
492        va_start(ap, fmt);
493        vfprintf(stderr, fmt, ap);
494        va_end(ap);
495        if (err)
496                fprintf(stderr, " (%s)", strerror(err));
497        putc('\n', stderr);
498
499        if (!xenfb_path_in_dom(xsh, errdir, sizeof(errdir), 0,
500                               "error/%s", dev->nodename))
501                goto out;       /* FIXME complain */
502
503        va_start(ap, fmt);
504        n = snprintf(buf, sizeof(buf), "%d ", err);
505        snprintf(buf + n, sizeof(buf) - n, fmt, ap);
506        va_end(ap);
507
508        if (xenfb_xs_printf(xsh, buf, "error", "%s", buf) < 0)
509                goto out;       /* FIXME complain */
510
511 out:
512        xenfb_switch_state(dev, XenbusStateClosing);
513}
514
515int xenfb_attach_dom(struct xenfb *xenfb_pub, int domid)
516{
517        struct xenfb_private *xenfb = (struct xenfb_private *)xenfb_pub;
518        struct xs_handle *xsh = xenfb->xsh;
519        int val, serrno;
520        struct xenfb_page *fb_page;
521
522        xenfb_detach_dom(xenfb);
523
524        xenfb_device_set_domain(&xenfb->fb, domid);
525        xenfb_device_set_domain(&xenfb->kbd, domid);
526
527        if (xenfb_wait_for_backend_creation(&xenfb->fb) < 0)
528                goto error;
529        if (xenfb_wait_for_backend_creation(&xenfb->kbd) < 0)
530                goto error;
531
532        if (xenfb_xs_printf(xsh, xenfb->kbd.nodename, "feature-abs-pointer", "1"))
533                goto error;
534        if (xenfb_switch_state(&xenfb->fb, XenbusStateInitWait))
535                goto error;
536        if (xenfb_switch_state(&xenfb->kbd, XenbusStateInitWait))
537                goto error;
538
539        if (xenfb_hotplug(&xenfb->fb) < 0)
540                goto error;
541        if (xenfb_hotplug(&xenfb->kbd) < 0)
542                goto error;
543
544        if (!xs_watch(xsh, xenfb->fb.otherend, ""))
545                goto error;
546        if (!xs_watch(xsh, xenfb->kbd.otherend, ""))
547                goto error;
548
549        if (xenfb_wait_for_frontend_initialised(&xenfb->fb) < 0)
550                goto error;
551        if (xenfb_wait_for_frontend_initialised(&xenfb->kbd) < 0)
552                goto error;
553
554        if (xenfb_bind(&xenfb->fb) < 0)
555                goto error;
556        if (xenfb_bind(&xenfb->kbd) < 0)
557                goto error;
558
559        if (xenfb_xs_scanf1(xsh, xenfb->fb.otherend, "feature-update",
560                            "%d", &val) < 0)
561                val = 0;
562        if (!val) {
563                errno = ENOTSUP;
564                goto error;
565        }
566        if (xenfb_xs_scanf1(xsh, xenfb->fb.otherend, "protocol", "%63s",
567                            xenfb->protocol) < 0)
568                xenfb->protocol[0] = '\0';
569        xenfb_xs_printf(xsh, xenfb->fb.nodename, "request-update", "1");
570
571        /* TODO check for permitted ranges */
572        fb_page = xenfb->fb.page;
573        xenfb->pub.depth = fb_page->depth;
574        xenfb->pub.width = fb_page->width;
575        xenfb->pub.height = fb_page->height;
576        /* TODO check for consistency with the above */
577        xenfb->fb_len = fb_page->mem_length;
578        xenfb->pub.row_stride = fb_page->line_length;
579
580        if (xenfb_map_fb(xenfb, domid) < 0)
581                goto error;
582
583        if (xenfb_switch_state(&xenfb->fb, XenbusStateConnected))
584                goto error;
585        if (xenfb_switch_state(&xenfb->kbd, XenbusStateConnected))
586                goto error;
587
588        if (xenfb_wait_for_frontend_connected(&xenfb->kbd) < 0)
589                goto error;
590        if (xenfb_xs_scanf1(xsh, xenfb->kbd.otherend, "request-abs-pointer",
591                            "%d", &val) < 0)
592                val = 0;
593        xenfb->pub.abs_pointer_wanted = val;
594
595        return 0;
596
597 error:
598        serrno = errno;
599        xenfb_detach_dom(xenfb);
600        xenfb_dev_fatal(&xenfb->fb, serrno, "on fire");
601        xenfb_dev_fatal(&xenfb->kbd, serrno, "on fire");
602        errno = serrno;
603        return -1;
604}
605
606static void xenfb_detach_dom(struct xenfb_private *xenfb)
607{
608        xenfb_unbind(&xenfb->fb);
609        xenfb_unbind(&xenfb->kbd);
610        if (xenfb->pub.pixels) {
611                munmap(xenfb->pub.pixels, xenfb->fb_len);
612                xenfb->pub.pixels = NULL;
613        }
614}
615
616static void xenfb_on_fb_event(struct xenfb_private *xenfb)
617{
618        uint32_t prod, cons;
619        struct xenfb_page *page = xenfb->fb.page;
620
621        prod = page->out_prod;
622        if (prod == page->out_cons)
623                return;
624        rmb();                  /* ensure we see ring contents up to prod */
625        for (cons = page->out_cons; cons != prod; cons++) {
626                union xenfb_out_event *event = &XENFB_OUT_RING_REF(page, cons);
627
628                switch (event->type) {
629                case XENFB_TYPE_UPDATE:
630                    if (xenfb->pub.update)
631                        xenfb->pub.update(&xenfb->pub,
632                                          event->update.x, event->update.y,
633                                          event->update.width, event->update.height);
634                    break;
635                }
636        }
637        mb();                   /* ensure we're done with ring contents */
638        page->out_cons = cons;
639        xc_evtchn_notify(xenfb->evt_xch, xenfb->fb.port);
640}
641
642static void xenfb_on_kbd_event(struct xenfb_private *xenfb)
643{
644        struct xenkbd_page *page = xenfb->kbd.page;
645
646        /* We don't understand any keyboard events, so just ignore them. */
647        if (page->out_prod == page->out_cons)
648                return;
649        page->out_cons = page->out_prod;
650        xc_evtchn_notify(xenfb->evt_xch, xenfb->kbd.port);
651}
652
653static int xenfb_on_state_change(struct xenfb_device *dev)
654{
655        enum xenbus_state state;
656
657        state = xenfb_read_state(dev->xenfb->xsh, dev->otherend);
658
659        switch (state) {
660        case XenbusStateUnknown:
661                /* There was an error reading the frontend state.  The
662                   domain has probably gone away; in any case, there's
663                   not much point in us continuing. */
664                return -1;
665        case XenbusStateInitialising:
666        case XenbusStateInitWait:
667        case XenbusStateInitialised:
668        case XenbusStateConnected:
669                break;
670        case XenbusStateClosing:
671                xenfb_unbind(dev);
672                xenfb_switch_state(dev, state);
673                break;
674        case XenbusStateClosed:
675                xenfb_switch_state(dev, state);
676        }
677        return 0;
678}
679
680/* Returns 0 normally, -1 on error, or -2 if the domain went away. */
681int xenfb_poll(struct xenfb *xenfb_pub, fd_set *readfds)
682{
683        struct xenfb_private *xenfb = (struct xenfb_private *)xenfb_pub;
684        evtchn_port_t port;
685        unsigned dummy;
686        char **vec;
687        int r;
688
689        if (FD_ISSET(xc_evtchn_fd(xenfb->evt_xch), readfds)) {
690                port = xc_evtchn_pending(xenfb->evt_xch);
691                if (port == -1)
692                        return -1;
693
694                if (port == xenfb->fb.port)
695                        xenfb_on_fb_event(xenfb);
696                else if (port == xenfb->kbd.port)
697                        xenfb_on_kbd_event(xenfb);
698
699                if (xc_evtchn_unmask(xenfb->evt_xch, port) == -1)
700                        return -1;
701        }
702
703        if (FD_ISSET(xs_fileno(xenfb->xsh), readfds)) {
704                vec = xs_read_watch(xenfb->xsh, &dummy);
705                free(vec);
706                r = xenfb_on_state_change(&xenfb->fb);
707                if (r == 0)
708                        r = xenfb_on_state_change(&xenfb->kbd);
709                if (r == -1)
710                        return -2;
711        }
712
713        return 0;
714}
715
716int xenfb_select_fds(struct xenfb *xenfb_pub, fd_set *readfds)
717{
718        struct xenfb_private *xenfb = (struct xenfb_private *)xenfb_pub;
719        int fd1 = xc_evtchn_fd(xenfb->evt_xch);
720        int fd2 = xs_fileno(xenfb->xsh);
721
722        FD_SET(fd1, readfds);
723        FD_SET(fd2, readfds);
724        return fd1 > fd2 ? fd1 + 1 : fd2 + 1;
725}
726
727static int xenfb_kbd_event(struct xenfb_private *xenfb,
728                           union xenkbd_in_event *event)
729{
730        uint32_t prod;
731        struct xenkbd_page *page = xenfb->kbd.page;
732
733        if (xenfb->kbd.state != XenbusStateConnected)
734                return 0;
735
736        prod = page->in_prod;
737        if (prod - page->in_cons == XENKBD_IN_RING_LEN) {
738                errno = EAGAIN;
739                return -1;
740        }
741
742        mb();                   /* ensure ring space available */
743        XENKBD_IN_RING_REF(page, prod) = *event;
744        wmb();                  /* ensure ring contents visible */
745        page->in_prod = prod + 1;
746        return xc_evtchn_notify(xenfb->evt_xch, xenfb->kbd.port);
747}
748
749int xenfb_send_key(struct xenfb *xenfb_pub, bool down, int keycode)
750{
751        struct xenfb_private *xenfb = (struct xenfb_private *)xenfb_pub;
752        union xenkbd_in_event event;
753
754        memset(&event, 0, XENKBD_IN_EVENT_SIZE);
755        event.type = XENKBD_TYPE_KEY;
756        event.key.pressed = down ? 1 : 0;
757        event.key.keycode = keycode;
758
759        return xenfb_kbd_event(xenfb, &event);
760}
761
762int xenfb_send_motion(struct xenfb *xenfb_pub, int rel_x, int rel_y)
763{
764        struct xenfb_private *xenfb = (struct xenfb_private *)xenfb_pub;
765        union xenkbd_in_event event;
766
767        memset(&event, 0, XENKBD_IN_EVENT_SIZE);
768        event.type = XENKBD_TYPE_MOTION;
769        event.motion.rel_x = rel_x;
770        event.motion.rel_y = rel_y;
771
772        return xenfb_kbd_event(xenfb, &event);
773}
774
775int xenfb_send_position(struct xenfb *xenfb_pub, int abs_x, int abs_y)
776{
777        struct xenfb_private *xenfb = (struct xenfb_private *)xenfb_pub;
778        union xenkbd_in_event event;
779
780        memset(&event, 0, XENKBD_IN_EVENT_SIZE);
781        event.type = XENKBD_TYPE_POS;
782        event.pos.abs_x = abs_x;
783        event.pos.abs_y = abs_y;
784
785        return xenfb_kbd_event(xenfb, &event);
786}
Note: See TracBrowser for help on using the repository browser.