From: Kamala Narasimhan Date: Fri, 8 Jan 2010 21:37:50 +0000 (-0500) Subject: Guest operating system driven brightness control support. X-Git-Url: http://xenbits.xensource.com/gitweb?a=commitdiff_plain;h=HEAD;p=xenclient%2Flinux-2.6.27-pq.git Guest operating system driven brightness control support. Xen acpi video driver implementation to interface between qemu and linux acpi video driver. --- diff --git a/master/guest-os-controlled-brightness-support b/master/guest-os-controlled-brightness-support new file mode 100644 index 0000000..bf12d2f --- /dev/null +++ b/master/guest-os-controlled-brightness-support @@ -0,0 +1,415 @@ +diff --git a/drivers/acpi/video.c b/drivers/acpi/video.c +index 8f2c530..a2c87d8 100644 +--- a/drivers/acpi/video.c ++++ b/drivers/acpi/video.c +@@ -283,6 +283,8 @@ static char device_decode[][30] = { + "UNKNOWN", + }; + ++static struct acpi_video_device_brightness lcd_device_brightness; ++ + static void acpi_video_device_notify(acpi_handle handle, u32 event, void *data); + static void acpi_video_device_rebind(struct acpi_video_bus *video); + static void acpi_video_device_bind(struct acpi_video_bus *video, +@@ -693,6 +695,14 @@ acpi_video_init_brightness(struct acpi_video_device *device) + count++; + } + ++ if ( count >=2 && lcd_device_brightness.levels == NULL ) { ++ lcd_device_brightness.levels = kmalloc(count * sizeof(int), GFP_KERNEL); ++ if ( lcd_device_brightness.levels ) { ++ memcpy(lcd_device_brightness.levels, br->levels, count * sizeof(int)); ++ lcd_device_brightness.count = count; ++ } ++ } ++ + /* don't sort the first two brightness levels */ + sort(&br->levels[2], count - 2, sizeof(br->levels[2]), + acpi_video_cmp_level, NULL); +@@ -2136,10 +2146,30 @@ static int acpi_video_bus_remove(struct acpi_device *device, int type) + return 0; + } + ++unsigned int acpi_video_get_num_brightness_levels(void) ++{ ++ return lcd_device_brightness.count; ++} ++EXPORT_SYMBOL(acpi_video_get_num_brightness_levels); ++ ++acpi_status acpi_video_get_brigtness_levels(unsigned int *levels, unsigned int size) ++{ ++ if ( lcd_device_brightness.levels == NULL) ++ return AE_ERROR; ++ ++ if ( (levels == NULL) || (size < lcd_device_brightness.count * sizeof(int)) ) ++ return AE_NO_MEMORY; ++ ++ memcpy(levels, lcd_device_brightness.levels, lcd_device_brightness.count * sizeof(int)); ++ return AE_OK; ++} ++EXPORT_SYMBOL(acpi_video_get_brigtness_levels); ++ + static int __init acpi_video_init(void) + { + int result = 0; + ++ memset(&lcd_device_brightness, 0, sizeof(lcd_device_brightness)); + + /* + acpi_dbg_level = 0xFFFFFFFF; +@@ -2167,6 +2197,11 @@ static void __exit acpi_video_exit(void) + + remove_proc_entry(ACPI_VIDEO_CLASS, acpi_root_dir); + ++ if ( lcd_device_brightness.levels != NULL ) { ++ kfree(lcd_device_brightness.levels); ++ lcd_device_brightness.count = 0; ++ } ++ + return; + } + +diff --git a/drivers/xen/Kconfig b/drivers/xen/Kconfig +index bc14812..86f1a2b 100644 +--- a/drivers/xen/Kconfig ++++ b/drivers/xen/Kconfig +@@ -325,6 +325,17 @@ config XEN_ACPI_WMI_WRAPPER + Facilitates OEM specific hotkey implementation within + guest space. + ++config XEN_ACPI_VIDEO ++ tristate "Xen Video" ++ depends on X86 && BACKLIGHT_CLASS_DEVICE && VIDEO_OUTPUT_CONTROL && XEN ++ depends on INPUT ++ depends on ACPI_VIDEO ++ help ++ Minimal Xen ACPI video driver implementation to query for a list of ++ brightness control levels from the firmware and communicate it to the ++ virtual firmware and to set and get current brightness level from the ++ firmware based on request from the virtual firmware. ++ + source "drivers/xen/v2v/Kconfig" + + choice +diff --git a/drivers/xen/Makefile b/drivers/xen/Makefile +index 465d341..6a7fc84 100644 +--- a/drivers/xen/Makefile ++++ b/drivers/xen/Makefile +@@ -31,5 +31,6 @@ obj-$(CONFIG_XEN_NETDEV_ACCEL_SFC_UTIL) += sfc_netutil/ + obj-$(CONFIG_XEN_NETDEV_ACCEL_SFC_FRONTEND) += sfc_netfront/ + obj-$(CONFIG_XEN_NETDEV_ACCEL_SFC_BACKEND) += sfc_netback/ + obj-$(CONFIG_XEN_ACPI_WMI_WRAPPER) += acpi-wmi/ ++obj-$(CONFIG_XEN_ACPI_VIDEO) += acpi-video/ + obj-$(CONFIG_XEN_NETCHANNEL2) += netchannel2/ + obj-$(CONFIG_XEN_V2V) += v2v/ +diff --git a/drivers/xen/acpi-video/Makefile b/drivers/xen/acpi-video/Makefile +new file mode 100644 +index 0000000..e54a29d +--- /dev/null ++++ b/drivers/xen/acpi-video/Makefile +@@ -0,0 +1,3 @@ ++ ++obj-y := acpi-video.o ++ +diff --git a/drivers/xen/acpi-video/acpi-video.c b/drivers/xen/acpi-video/acpi-video.c +new file mode 100644 +index 0000000..b9a1e3d +--- /dev/null ++++ b/drivers/xen/acpi-video/acpi-video.c +@@ -0,0 +1,213 @@ ++/****************************************************************************** ++ * drivers/xen/acpi-video/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 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. ++ */ ++ ++/* This module receives ioctl request from qemu xen-acpi-video implementation, ++ * talks to linux-acpi-video driver to get relevant firmware information ++ * and returns that to qemu which in turn responds back to the virtual firmware ++ * with the same information. Currently, we get request for brightness levels alone ++ * but this could be easily extended in future to support more output/video device ++ * level information. ++ */ ++ ++#include ++#include ++#include ++#include ++#include ++ ++/* #define XEN_VIDEO_DEBUG */ ++ ++static bool xen_video_misc_dev_registered = false; ++static int xen_video_ioctl(struct inode *inode, struct file *filp, ++ unsigned int cmd, unsigned long arg); ++ ++static struct file_operations xen_video_fops = { ++ .owner = THIS_MODULE, ++ .ioctl = xen_video_ioctl, ++}; ++ ++static struct miscdevice xen_video_misc = { ++ .minor = MISC_DYNAMIC_MINOR, ++ .name = XEN_VIDEO_DEVICE_NAME, ++ .fops = &xen_video_fops, ++}; ++ ++/* ++ * xen_video_num_brightness_levels ++ */ ++int xen_video_num_brightness_levels(xen_video_data_t *video_data) ++{ ++ unsigned int num_levels; ++ ++ if ( video_data->buffer_size < sizeof(unsigned int) ) ++ { ++ printk("Xen Video: Not enough memory!\n"); ++ return XEN_VIDEO_NOT_ENOUGH_MEMORY; ++ } ++ ++ num_levels = acpi_video_get_num_brightness_levels(); ++ if ( num_levels == 0 ) ++ { ++ printk("XEN Video: Unable to get brightness levels\n"); ++ return XEN_VIDEO_EFAULT; ++ } ++ ++ if ( copy_to_user((char __user *) video_data->out_buf, &num_levels, sizeof(unsigned int)) ) ++ { ++ printk("XEN Video: Invalid user buffer\n"); ++ return XEN_VIDEO_NOT_ENOUGH_MEMORY; ++ } ++ ++#ifdef XEN_VIDEO_DEBUG ++ printk("XEN Video: Returning number of brightness levels - %d\n", num_levels); ++#endif ++ return XEN_VIDEO_SUCCESS; ++} ++ ++/* ++ * xen_video_brightness_levels ++ */ ++int xen_video_brightness_levels(xen_video_data_t *video_data) ++{ ++ int ret; ++ unsigned int *levels, num_levels; ++ ++ if ( video_data->out_buf == NULL ) ++ { ++ printk("XEN Video: Output buffer is null!\n"); ++ return XEN_VIDEO_NOT_ENOUGH_MEMORY; ++ } ++ ++ num_levels = acpi_video_get_num_brightness_levels(); ++ if ( num_levels == 0 ) ++ return XEN_VIDEO_EFAULT; ++ ++ if ( video_data->buffer_size < num_levels * sizeof(unsigned int) ) ++ { ++ printk("Xen Video: Not enough memory!\n"); ++ return XEN_VIDEO_NOT_ENOUGH_MEMORY; ++ } ++ ++ levels = kmalloc(video_data->buffer_size, GFP_KERNEL); ++ if ( levels == NULL ) ++ { ++ printk("XEN Video: Allocation failure!\n"); ++ return XEN_VIDEO_NOT_ENOUGH_MEMORY; ++ } ++ ++ ret = acpi_video_get_brigtness_levels(levels, video_data->buffer_size); ++ if ( ret != XEN_VIDEO_SUCCESS ) ++ { ++ kfree(levels); ++ return ret; ++ } ++ ++ if ( copy_to_user((char __user *) video_data->out_buf, levels, video_data->buffer_size) ) ++ { ++ printk("XEN Video: Invalid user buffer\n"); ++ kfree(levels); ++ return XEN_VIDEO_NOT_ENOUGH_MEMORY; ++ } ++ ++ kfree(levels); ++#ifdef XEN_VIDEO_DEBUG ++ printk("XEN Video: xen_video_brightness_levels succeeded!\n"); ++#endif ++ return XEN_VIDEO_SUCCESS; ++} ++ ++/* ++ * xen_video_ioctl ++ */ ++static int xen_video_ioctl(struct inode *inode, struct file *filp, ++ unsigned int cmd, unsigned long arg) ++{ ++ xen_video_data_t video_data; ++ ++#ifdef XEN_VIDEO_DEBUG ++ printk("XEN VIDEO: In xen_video_ioctl - %d\n", cmd); ++#endif ++ ++ memset(&video_data, 0, sizeof(video_data)); ++ if ( copy_from_user(&video_data, (char __user *)arg, sizeof(xen_video_data_t)) ) ++ { ++ printk("XEN Video: Invalid object invocation parameter\n"); ++ return XEN_VIDEO_EFAULT; ++ } ++ ++ switch ( cmd ) ++ { ++ case XEN_VIDEO_IOCTL_NUM_BRIGHTNESS_LEVELS: ++ return xen_video_num_brightness_levels(&video_data); ++ case XEN_VIDEO_IOCTL_BRIGHTNESS_LEVELS: ++ return xen_video_brightness_levels(&video_data); ++ } ++ ++ return XEN_VIDEO_ENOIOCTLCMD; ++} ++ ++/* ++ * xen_video_init ++ */ ++static int __init xen_video_init(void) ++{ ++ int ret; ++ ++ ret = misc_register(&xen_video_misc); ++ if ( ret < 0 ) ++ printk("XEN Video: misc_register failed with error - %d\n", ret); ++ else ++ xen_video_misc_dev_registered = true; ++ ++#ifdef XEN_VIDEO_DEBUG ++ printk("XEN Video: xen-acpi-video misc_register succeeded!\n"); ++#endif ++ return ret; ++} ++ ++/* ++ * xen_video_exit ++ */ ++static void xen_video_exit(void) ++{ ++ int ret; ++ ++ if ( xen_video_misc_dev_registered == false ) ++ return; ++ ++ if ( (ret = misc_deregister(&xen_video_misc)) < 0 ) ++ printk("XEN VIDEO: misc_deregister failed with error - %d\n", ret); ++} ++ ++module_init(xen_video_init); ++module_exit(xen_video_exit); ++MODULE_LICENSE("Dual BSD/GPL"); ++ +diff --git a/include/linux/acpi.h b/include/linux/acpi.h +index cd5c2be..fcf11a7 100644 +--- a/include/linux/acpi.h ++++ b/include/linux/acpi.h +@@ -202,6 +202,13 @@ extern bool wmi_has_guid(const char *guid); + + #endif /* CONFIG_ACPI_WMI */ + ++#if defined(CONFIG_ACPI_VIDEO) ++ ++extern unsigned int acpi_video_get_num_brightness_levels(void); ++extern acpi_status acpi_video_get_brigtness_levels(unsigned int *levels, unsigned int size); ++ ++#endif /* CONFIG_ACPI_VIDEO */ ++ + #define ACPI_VIDEO_OUTPUT_SWITCHING 0x0001 + #define ACPI_VIDEO_DEVICE_POSTING 0x0002 + #define ACPI_VIDEO_ROM_AVAILABLE 0x0004 +diff --git a/include/xen/public/acpi-video.h b/include/xen/public/acpi-video.h +new file mode 100644 +index 0000000..3763241 +--- /dev/null ++++ b/include/xen/public/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/master/series b/master/series index 5a5c781..8d68cc4 100644 --- a/master/series +++ b/master/series @@ -360,3 +360,4 @@ v2v-dev v2v-fix-disconnect v2v-dev-ringsizes netback-tcpchecksum-fix +guest-os-controlled-brightness-support