/** * @file * @section AUTHORS * * Copyright IBM, Corp. 2005-2006 * Copyright Red Hat, Inc. 2006-2008 * * Authors: * Anthony Liguori , * Markus Armbruster , * Daniel P. Berrange , * Pat Campbell , * Gerd Hoffmann * Eamon Walsh * * @section LICENSE * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation; under version 2 of the License. * * This program is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * GNU General Public License for more details. * * You should have received a copy of the GNU General Public License along * with this program; if not, write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. * * @section DESCRIPTION * * This is the stock framebuffer and input backend code from QEMU, * modified to call Linpicker instead of QEMU functions. * * This is the code for linpicker-monitor, which is responsible for setting * up the framebuffer and input device backends in XenStore. This code * acutally only handles XenStore writes during frontend state transitions; * the initial setup is done using functions from libxenlight. No actual * servicing of the devices are done here, that is linpicker-server's job. */ #include #include #include #include #include #include #include #include #include #include "xen_backend.h" #include "xen_linpicker.h" #include "display.h" static int width, height; int xenfb_monitor_init(void) { struct fb_var_screeninfo fvs; int rc, fd; /* XXX test this failure case */ width = 800; height = 600; fd = open("/dev/fb0", O_RDONLY); if (fd < 0) return -1; rc = ioctl(fd, FBIOGET_VSCREENINFO, &fvs); if (rc == 0) { width = fvs.xres_virtual; height = fvs.yres_virtual - SECLABEL_HEIGHT; } close(fd); return 0; } /* -------------------------------------------------------------------- */ static int input_init(struct XenDevice *xendev) { xenstore_write_be_int(xendev, "feature-abs-pointer", 1); xenstore_write_be_int(xendev, "width", width); xenstore_write_be_int(xendev, "height", height); return 0; } /* -------------------------------------------------------------------- */ static int fb_init(struct XenDevice *xendev) { #ifdef XENFB_TYPE_RESIZE xenstore_write_be_int(xendev, "feature-resize", 1); #endif xenstore_write_be_int(xendev, "feature-grants", 1); xenstore_write_be_int(xendev, "width", width); xenstore_write_be_int(xendev, "height", height); return 0; } static int fb_initialise(struct XenDevice *xendev) { int videoram, update; if (xenstore_read_fe_int(xendev, "videoram", &videoram) == -1) videoram = 0; if (xenstore_read_fe_int(xendev, "feature-update", &update) == -1) update = 0; if (update) xenstore_write_be_int(xendev, "request-update", 1); XEN_BE_LOG(xendev, 1, "feature-update=%d, videoram=%d\n", update, videoram); return 0; } static void fb_frontend_changed(struct XenDevice *xendev, const char *node) { struct XenFB *fb = (struct XenFB *)xendev; /* * Set state to Connected *again* once the frontend switched * to connected. We must trigger the watch a second time to * workaround a frontend bug. */ if (fb->bug_trigger == 0 && strcmp(node, "state") == 0 && xendev->fe_state == XenbusStateConnected && xendev->be_state == XenbusStateConnected) { XEN_BE_LOG(xendev, 2, "re-trigger connected (frontend bug)\n"); xen_be_set_state(xendev, XenbusStateConnected); fb->bug_trigger = 1; /* only once */ } } static void fb_disconnect(struct XenDevice *xendev) { struct XenFB *fb = (struct XenFB *)xendev; fb->feature_update = 0; fb->bug_trigger = 0; } /* -------------------------------------------------------------------- */ struct XenDevOps xen_kbdmouse_ops = { .size = sizeof(struct XenInput), .init = input_init, }; struct XenDevOps xen_framebuffer_ops = { .size = sizeof(struct XenFB), .init = fb_init, .initialise = fb_initialise, .disconnect = fb_disconnect, .frontend_changed = fb_frontend_changed, };