From 7339f7ecf4dbf6c3648f62e59600bac09988a0b8 Mon Sep 17 00:00:00 2001 From: Kamala Narasimhan Date: Fri, 8 Jan 2010 15:12:22 -0500 Subject: [PATCH] Guest operating system driven brightness control support. Respond to requests from virtual acpi layer output device to get supported brightness levels from actual firmware. This can be extended to support more output device requests in future. --- master/guest-os-controlled-brightness-support | 406 ++++++++++++++++++ master/series | 1 + 2 files changed, 407 insertions(+) create mode 100644 master/guest-os-controlled-brightness-support diff --git a/master/guest-os-controlled-brightness-support b/master/guest-os-controlled-brightness-support new file mode 100644 index 0000000..ef76a78 --- /dev/null +++ b/master/guest-os-controlled-brightness-support @@ -0,0 +1,406 @@ +diff --git a/hw/acpi-video.h b/hw/acpi-video.h +new file mode 100644 +index 0000000..3763241 +--- /dev/null ++++ b/hw/acpi-video.h +@@ -0,0 +1,59 @@ ++/****************************************************************************** ++ * acpi-video.h ++ * ++ * Interface to /proc/misc/xen-acpi-video ++ * ++ * Copyright (c) 2009 Kamala Narasimhan ++ * Copyright (c) 2009 Citrix Systems, Inc. ++ * ++ * This program is free software; you can redistribute it and/or ++ * modify it under the terms of the GNU General Public License version 2 ++ * as published by the Free Software Foundation; or, when distributed ++ * separately from the Linux kernel or incorporated into other ++ * software packages, subject to the following license: ++ * ++ * Permission is hereby granted, free of charge, to any person obtaining a copy ++ * of this source file (the "Software"), to deal in the Software without ++ * restriction, including without limitation the rights to use, copy, modify, ++ * merge, publish, distribute, sublicense, and/or sell copies of the Software, ++ * and to permit persons to whom the Software is furnished to do so, subject to ++ * the following conditions: ++ * ++ * The above copyright notice and this permission notice shall be included in ++ * all copies or substantial portions of the Software. ++ * ++ * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR ++ * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, ++ * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE ++ * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER ++ * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING ++ * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS ++ * IN THE SOFTWARE. ++ */ ++ ++ ++#ifndef _XEN_ACPI_VIDEO ++#define _XEN_ACPI_VIDEO ++ ++/* ++ * Userspace Interface ++ */ ++ ++#define XEN_VIDEO_DEVICE_NAME "xen-acpi-video" ++#define XEN_VIDEO_GUID_SIZE 16 ++ ++#define XEN_VIDEO_SUCCESS 0 ++#define XEN_VIDEO_EFAULT -14 ++#define XEN_VIDEO_NOT_ENOUGH_MEMORY -12 ++#define XEN_VIDEO_ENOIOCTLCMD -515 ++ ++#define XEN_VIDEO_IOCTL_NUM_BRIGHTNESS_LEVELS 100 ++#define XEN_VIDEO_IOCTL_BRIGHTNESS_LEVELS 101 ++ ++typedef struct xen_video_data { ++ uint buffer_size; ++ uint *out_buf; ++} xen_video_data_t; ++ ++#endif /* _XEN_ACPI_VIDEO */ ++ +diff --git a/hw/piix4acpi.c b/hw/piix4acpi.c +index 3e48413..87fb2b3 100644 +--- a/hw/piix4acpi.c ++++ b/hw/piix4acpi.c +@@ -30,6 +30,7 @@ + #include "qemu-xen.h" + #include "battery_mgmt.h" + #include "xen_acpi_wmi.h" ++#include "xen_acpi_video.h" + #include "thermal_mgmt.h" + + #include "switcher.h" +@@ -213,6 +214,7 @@ static void acpi_map(PCIDevice *pci_dev, int region_num, + + battery_mgmt_init(pci_dev); + xen_acpi_wmi_init(pci_dev); ++ xen_acpi_video_init(pci_dev); + thermal_mgmt_init(pci_dev); + } + +diff --git a/hw/xen_acpi_video.c b/hw/xen_acpi_video.c +new file mode 100644 +index 0000000..ccef147 +--- /dev/null ++++ b/hw/xen_acpi_video.c +@@ -0,0 +1,247 @@ ++/* ++ * xen_acpi_video.c ++ * ++ * Copyright (c) 2009 Kamala Narasimhan ++ * Copyright (c) 2009 Citrix Systems, Inc. ++ * ++ * 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; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ++ */ ++ ++/* When well known output device object methods in virtual ACPI space are called, ++ * the guest delegate those requests to qemu and the below implementation in qemu ++ * talks to the actual firmware through dom0 kernel xen/acpi driver implementation ++ * to cater to those guest level acpi requests. ++ */ ++ ++#include "hw.h" ++#include "pc.h" ++#include "qemu-xen.h" ++#include "isa.h" ++#include "xen_acpi_video.h" ++#include ++ ++#ifndef CONFIG_NO_XEN_ACPI_VIDEO ++ ++static int xen_video_device = -ENODEV; ++extern FILE *logfile; ++ ++static enum XEN_ACPI_VIDEO_COMMAND video_cmd_type = XEN_ACPI_VIDEO_CMD_NONE; ++static unsigned int num_brightness_levels = 0; ++static unsigned int *brightness_levels = NULL; ++static unsigned int current_index = 0; ++ ++/* #define XEN_ACPI_VIDEO_DEBUG */ ++ ++/* ++ * xen_acpi_video_get_num_brightness_levels ++ */ ++unsigned int xen_acpi_video_get_num_brightness_levels(void) ++{ ++ /* Our virtual acpi layer can only accomodate a package of 11 elements ++ * at this point which appear to be enough with the firmwares we have ++ * checked so far. If that should change it is easy enough to ++ * accomodate more and if such change become common place, we can then ++ * make asl package creation dynamic too. ++ */ ++ ++ if ( num_brightness_levels > 11 ) ++ { ++ fprintf(logfile, "Truncating brightness levels to 11\n"); ++ return 11; ++ } ++ ++#ifdef XEN_ACPI_VIDEO_DEBUG ++ fprintf(logfile, "XEN VIDEO: Number of brightness levels - %d\n", num_brightness_levels); ++#endif ++ ++ return num_brightness_levels; ++} ++ ++/* ++ * xen_acpi_video_get_next_brightness_level ++ */ ++unsigned int xen_acpi_video_get_next_brightness_level(void) ++{ ++ if ( brightness_levels == NULL ) ++ { ++ fprintf(logfile, "XEN VIDEO: Brightness levels array empty!\n"); ++ return 0; ++ } ++ ++ if ( current_index >= num_brightness_levels ) ++ { ++ fprintf(logfile, "XEN VIDEO: Index overflow!\n"); ++ return 0; ++ } ++ ++#ifdef XEN_ACPI_VIDEO_DEBUG ++ fprintf(logfile, "XEN VIDEO: Level - %d\n", brightness_levels[current_index]); ++#endif ++ ++ return brightness_levels[current_index++]; ++} ++ ++/* ++ * xen_acpi_video_port_readb ++ */ ++static uint32_t xen_acpi_video_port_readb(void *opaque, uint32_t addr) ++{ ++#ifdef XEN_ACPI_VIDEO_DEBUG ++ fprintf(logfile, "XEN VIDEO: In video port read\n"); ++#endif ++ ++ switch ( video_cmd_type ) ++ { ++ case XEN_ACPI_VIDEO_GET_NUM_LEVELS: ++ return xen_acpi_video_get_num_brightness_levels(); ++ case XEN_ACPI_VIDEO_GET_LEVLES: ++ return xen_acpi_video_get_next_brightness_level(); ++ case XEN_ACPI_VIDEO_CMD_NONE: ++ default: ++ fprintf(logfile, "XEN VIDEO: Unknown request - %d\n", ++ video_cmd_type); ++ break; ++ } ++ ++ return 0; ++} ++ ++/* ++ * xen_acpi_video_port_writeb ++ */ ++static void xen_acpi_video_port_writeb(void *opaque, uint32_t addr, uint32_t val) ++{ ++ video_cmd_type = val; ++ if ( val == XEN_ACPI_VIDEO_CMD_NONE ) ++ current_index = 0; ++ ++#ifdef XEN_ACPI_VIDEO_DEBUG ++ fprintf(logfile, "XEN VIDEO: In video port write, command - %d\n", video_cmd_type); ++#endif ++} ++ ++/* ++ * xen_acpi_video_initialize_brightness_info ++ */ ++void xen_acpi_video_initialize_brightness_info(void) ++{ ++ int ret; ++ xen_video_data_t video_data; ++ ++#ifdef XEN_ACPI_VIDEO_DEBUG ++ unsigned int count; ++#endif ++ ++ video_data.buffer_size = sizeof(uint); ++ video_data.out_buf = malloc(video_data.buffer_size); ++ if (video_data.out_buf == NULL ) ++ { ++ fprintf(logfile, "XEN VIDEO: Allocation failure!\n"); ++ return; ++ } ++ ++ ret = ioctl(xen_video_device, XEN_ACPI_VIDEO_GET_NUM_LEVELS, &video_data); ++ if ( ret != XEN_VIDEO_SUCCESS || video_data.out_buf == NULL ) ++ { ++ fprintf(logfile, "XEN VIDEO: Unable to get number of brightness levels - %d\n", ++ ret); ++ free(video_data.out_buf); ++ video_data.out_buf = NULL; ++ return; ++ } ++ ++ num_brightness_levels = *video_data.out_buf; ++ free(video_data.out_buf); ++ ++ video_data.buffer_size = num_brightness_levels * sizeof(uint); ++ video_data.out_buf = malloc(video_data.buffer_size); ++ if ( video_data.out_buf == NULL ) ++ { ++ num_brightness_levels = 0; ++ fprintf(logfile, "XEN VIDEO: Allocation failure!\n"); ++ return; ++ } ++ ++ memset(video_data.out_buf, 0, video_data.buffer_size); ++ ret = ioctl(xen_video_device, XEN_ACPI_VIDEO_GET_LEVLES, &video_data); ++ if (ret != XEN_VIDEO_SUCCESS ) ++ { ++ num_brightness_levels = 0; ++ free(video_data.out_buf); ++ video_data.out_buf = NULL; ++ fprintf(logfile, "XEN VIDEO: Unable to get brigtness levels - %d\n"); ++ return; ++ } ++ ++ brightness_levels = video_data.out_buf; ++ ++#ifdef XEN_ACPI_VIDEO_DEBUG ++ fprintf(logfile, "XEN VIDEO: Initialize brightness info succeeded!\n"); ++ fprintf(logfile, "XEN VIDEO: Number of brightness levels - %d\n", num_brightness_levels); ++ fprintf(logfile, "XEN VIDEO: Brightness levels -"); ++ for (count = 0; count < num_brightness_levels; count++) ++ fprintf(logfile, " %d", brightness_levels[count]); ++ fprintf(logfile, "\n"); ++#endif ++} ++ ++/* ++ * xen_acpi_video_init ++ */ ++void xen_acpi_video_init(PCIDevice *device) ++{ ++ char dev_name[64]; ++ ++ sprintf(dev_name, "/dev/%s", XEN_VIDEO_DEVICE_NAME); ++ xen_video_device = open(dev_name, 0); ++ if ( xen_video_device < 0 ) ++ { ++ fprintf(logfile, "XEN VIDEO: Unable to open device - %s\n", XEN_VIDEO_DEVICE_NAME); ++ return; ++ } ++ ++ register_ioport_read(XEN_ACPI_VIDEO_PORTB, 1, 1, xen_acpi_video_port_readb, device); ++ register_ioport_write(XEN_ACPI_VIDEO_PORTB, 1, 1, xen_acpi_video_port_writeb, device); ++ ++ xen_acpi_video_initialize_brightness_info(); ++ ++#ifdef XEN_ACPI_VIDEO_DEBUG ++ fprintf(logfile, "XEN VIDEO: Xen acpi video registration succeeded!!!\n"); ++#endif ++} ++ ++/* ++ * xen_acpi_video_cleanup(void) ++ */ ++void xen_acpi_video_cleanup(void) ++{ ++ if ( xen_video_device > 0 ) ++ close(xen_video_device); ++ ++ num_brightness_levels = 0; ++ if ( brightness_levels != NULL ) ++ { ++ free(brightness_levels); ++ brightness_levels = NULL; ++ } ++} ++ ++#else ++ ++void xen_acpi_video_init(PCIDevice *device) { } ++void xen_acpi_video_cleanup(void) { } ++ ++#endif /* CONFIG_NO_XEN_ACPI_VIDEO */ ++ +diff --git a/hw/xen_acpi_video.h b/hw/xen_acpi_video.h +new file mode 100644 +index 0000000..fd77443 +--- /dev/null ++++ b/hw/xen_acpi_video.h +@@ -0,0 +1,50 @@ ++/* ++ * xen_acpi_video.h ++ * ++ * Copyright (c) 2009 Kamala Narasimhan ++ * Copyright (c) 2009 Citrix Systems, Inc. ++ * ++ * 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; either version 2 of the License, or ++ * (at your option) any later version. ++ * ++ * 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., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA ++ */ ++ ++#ifndef _XEN_ACPI_VIDEO_H ++#define _XEN_ACPI_VIDEO_H ++ ++#ifdef CONFIG_STUBDOM ++#define CONFIG_NO_XEN_ACPI_VIDEO ++#endif ++ ++#include "acpi-video.h" ++ ++#define XEN_ACPI_VIDEO_PORTB 0x94 ++ ++/* Values written to VIDEO command port */ ++enum XEN_ACPI_VIDEO_COMMAND ++{ ++ XEN_ACPI_VIDEO_GET_NUM_LEVELS = 100, ++ XEN_ACPI_VIDEO_GET_LEVLES, ++ XEN_ACPI_VIDEO_CMD_NONE, ++}; ++ ++void xen_acpi_video_init(PCIDevice *device); ++void xen_acpi_video_cleanup(void); ++ ++#ifndef CONFIG_NO_XEN_ACPI_VIDEO ++ void xen_acpi_video_initialize_brightness_info(void); ++ unsigned int xen_acpi_video_get_num_brightness_levels(void); ++ unsigned int xen_acpi_video_get_next_brightness_level(void); ++#endif ++ ++#endif /* _XEN_ACPI_VIDEO_H */ +diff --git a/xen-hooks.mak b/xen-hooks.mak +index 88aff50..546d37f 100644 +--- a/xen-hooks.mak ++++ b/xen-hooks.mak +@@ -36,6 +36,7 @@ OBJS += pci_emulation.o + OBJS += helper2.o + OBJS += battery_mgmt.o + OBJS += xen_acpi_wmi.o ++OBJS += xen_acpi_video.o + OBJS += thermal_mgmt.o + OBJS += switcher.o + OBJS += intel.o diff --git a/master/series b/master/series index 9abe27c..b08db33 100644 --- a/master/series +++ b/master/series @@ -33,3 +33,4 @@ hide-msi-capability-for-igfx vga-edid tidy-muticies-in-ata-pt alsa-fix-resume +guest-os-controlled-brightness-support -- 2.39.5