]> xenbits.xen.org Git - xenclient/kernel.git/commitdiff
Xen acpi-wmi implementation.
authorKamala Narasimhan <kamala.narasimhan@citrix.com>
Tue, 10 Feb 2009 02:42:53 +0000 (21:42 -0500)
committerKamala Narasimhan <kamala.narasimhan@citrix.com>
Tue, 10 Feb 2009 02:42:53 +0000 (21:42 -0500)
Xen acpi-wmi driver provides the necessary interface for userspace
module (qemu) to communicate with acpi wmi wrapper kernel driver
which then communicates with the base firmware.  The result
returned by the base firmware is communicated back to the userspace
module (qemu) through this driver.

drivers/xen/Kconfig
drivers/xen/Makefile
drivers/xen/acpi-wmi/Makefile [new file with mode: 0644]
drivers/xen/acpi-wmi/acpi-wmi.c [new file with mode: 0644]
include/xen/public/acpi-wmi.h [new file with mode: 0644]

index 1abc0d4e37236a4311e75467ca666ca5a11589e7..f3e019276e365083be4a9a236a6dcc6913aac8fe 100644 (file)
@@ -263,6 +263,13 @@ config XEN_SYSFS
        help
          Xen hypervisor attributes will show up under /sys/hypervisor/.
 
+config XEN_ACPI_WMI_WRAPPER
+        tristate "Xen ACPI WMI wrapper driver"
+        depends on ACPI_WMI
+        help
+          Facilitates OEM specific hotkey implementation within
+          guest space.
+
 choice
        prompt "Xen version compatibility"
        default XEN_COMPAT_030002_AND_LATER
@@ -310,5 +317,4 @@ config XEN_XENCOMM
 
 config XEN_DEVMEM
        def_bool y
-
 endif
index 56fc080ba74b8de6bf47edba4d7f8bac62850d4b..1107421280a5cd5967b7a8f91daeee679aa4876b 100644 (file)
@@ -24,3 +24,4 @@ obj-$(CONFIG_XEN_GRANT_DEV)   += gntdev/
 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/
diff --git a/drivers/xen/acpi-wmi/Makefile b/drivers/xen/acpi-wmi/Makefile
new file mode 100644 (file)
index 0000000..afe5d9d
--- /dev/null
@@ -0,0 +1,2 @@
+
+obj-y := acpi-wmi.o
diff --git a/drivers/xen/acpi-wmi/acpi-wmi.c b/drivers/xen/acpi-wmi/acpi-wmi.c
new file mode 100644 (file)
index 0000000..e1f0416
--- /dev/null
@@ -0,0 +1,345 @@
+/******************************************************************************
+ * drivers/xen/acpi-wmi/acpi-wmi.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.
+ */
+
+/* Xen acpi-wmi implementation provides the interface required for userspace 
+ * module (qemu) to communicate with acpi wmi wrapper kernel driver.
+ * Upon receiving request from qemu to call a WMI method or query or set WMI
+ * data, it communicates the request to kernel acpi wmi layer which then 
+ * interacts with the base firmware to get the necessary information/execute
+ * relevant AML method etc.  The result returned by the base firmware is then
+ * communicated back to the userspace module (qemu). 
+ */
+
+#include <linux/module.h>
+#include <linux/miscdevice.h>
+#include <linux/acpi.h>
+#include <asm/uaccess.h>
+#include <xen/public/acpi-wmi.h>
+
+/* #define XEN_WMI_DEBUG */
+
+static bool xen_wmi_misc_dev_registered = false;
+static int xen_wmi_ioctl(struct inode *inode, struct file *filp, 
+                         unsigned int cmd, unsigned long arg);
+
+static struct file_operations xen_wmi_fops = {
+    .owner = THIS_MODULE,
+    .ioctl = xen_wmi_ioctl,
+};
+
+static struct miscdevice xen_wmi_misc = {
+        .minor    = MISC_DYNAMIC_MINOR,
+        .name     = XEN_WMI_DEVICE_NAME,
+        .fops     = &xen_wmi_fops,
+};
+
+/*
+ * xen_wmi_copy_input_buffer
+ */
+int xen_wmi_copy_input_buffer(xen_wmi_buffer_t *user_buf, struct acpi_buffer *acpi_buf)
+{
+    if ( user_buf->length <= 0 )
+        return XEN_WMI_SUCCESS; 
+
+    acpi_buf->pointer = kmalloc(user_buf->length, GFP_KERNEL);
+    if ( acpi_buf->pointer == NULL )
+    {
+        printk("XEN WMI: xen_wmi_copy_input_buffer - Buffer allocation failure\n");
+        return XEN_WMI_NOT_ENOUGH_MEMORY; 
+    }
+
+    if ( copy_from_user(acpi_buf->pointer,
+                        (char __user *)user_buf->pointer,
+                        user_buf->length) )
+    {
+        printk("XEN WMI: Unable to copy input buffer argument\n");
+        kfree(acpi_buf->pointer);
+        return XEN_WMI_EFAULT;
+    }
+
+    acpi_buf->length = user_buf->length; 
+    return XEN_WMI_SUCCESS; 
+}
+
+/*
+ * xen_wmi_copy_output_buffer
+ */
+int xen_wmi_copy_output_buffer(struct acpi_buffer *acpi_buf, xen_wmi_buffer_t *user_buf)
+{
+    /* IMPORTANT NOTE:  It is a little short sighted to assume that the return type
+     * will not be anything other than buffer type.  A follow-up check-in will
+     * cover more types. 
+     */
+
+    union acpi_object *acpi_obj = acpi_buf->pointer;
+
+    if ( acpi_obj == NULL )
+    {
+        printk("XEN WMI: Invalid acpi buffer!\n");
+        return XEN_WMI_EFAULT;
+    }
+
+    if ( acpi_obj->type != ACPI_TYPE_BUFFER )
+    {
+        printk("XEN WMI: Unsupported acpi return object type - %d\n", acpi_obj->type);
+        return XEN_WMI_UNSUPPORTED_TYPE;
+    }
+
+    if ( copy_to_user((char __user *) user_buf->copied_length, &acpi_obj->buffer.length, sizeof(size_t)) )
+    {
+        printk("XEN WMI: Invalid copied length user buffer!\n");
+        return XEN_WMI_INVALID_ARGUMENT;
+    }
+
+    if ( user_buf->length < acpi_obj->buffer.length ) 
+    {
+        printk("XEN WMI: Required buffer length is - %d\n", acpi_obj->buffer.length);
+        printk("XEN WMI: Passed in length is - %d\n", user_buf->length);
+        return XEN_WMI_BUFFER_TOO_SMALL;
+    }
+
+    if ( copy_to_user((char __user *) user_buf->pointer, acpi_obj->buffer.pointer, acpi_obj->buffer.length) )
+    {
+        printk("XEN WMI: Invalid user output buffer\n");
+        return XEN_WMI_NOT_ENOUGH_MEMORY; 
+    }
+
+    return XEN_WMI_SUCCESS; 
+} 
+
+#ifdef XEN_WMI_DEBUG
+
+/*
+ * xen_wmi_print_buffer
+ */
+void xen_wmi_print_buffer(struct acpi_buffer *acpi_buf)
+{
+    int count;
+
+    printk("XEN WMI: Output buffer length is - %d\n", acpi_buf->buffer.length);
+    printk("XEN WMI:  Buffer:  ");
+    for (count=0; count < acpi_buf->buffer.length; count++)
+        printk("%d  ", ((byte *)(acpi_buf->buffer.pointer))[count]);
+    printk("\n");
+}
+
+#endif /* XEN_WMI_DEBUG */
+
+/*
+ * xen_wmi_invoke_method 
+ */
+int xen_wmi_invoke_method(xen_wmi_obj_invocation_data_t *obj_inv_data)
+{
+    int result;
+    struct acpi_buffer in_buf, *in_arg = NULL, out_buf = {ACPI_ALLOCATE_BUFFER, NULL};
+
+    result = xen_wmi_copy_input_buffer(&obj_inv_data->xen_wmi_arg.xen_wmi_method_arg.in_buf,
+                                       &in_buf); 
+    if ( result != XEN_WMI_SUCCESS )
+        return result;
+
+    if ( in_buf.length > 0 ) 
+        in_arg = &in_buf;
+
+    result = wmi_evaluate_method(obj_inv_data->guid, 
+                 obj_inv_data->xen_wmi_arg.xen_wmi_method_arg.instance, 
+                 obj_inv_data->xen_wmi_arg.xen_wmi_method_arg.method_id, 
+                 in_arg, &out_buf);
+
+    if ( in_arg != NULL )
+        kfree(in_buf.pointer);
+
+    if ( out_buf.length > 0  && result == XEN_WMI_SUCCESS )
+    {
+#ifdef XEN_WMI_DEBUG
+        xen_wmi_print_buffer(&out_buf);
+#endif
+        result = xen_wmi_copy_output_buffer(&out_buf,
+                                            &obj_inv_data->xen_wmi_arg.xen_wmi_method_arg.out_buf);
+        kfree(out_buf.pointer); 
+    }
+    else if ( result != XEN_WMI_SUCCESS )
+        printk("XEN WMI- Invoke WMI method failed with error - %d\n", result);
+
+    return result;
+} 
+
+/*
+ * xen_wmi_query_object
+ */
+int xen_wmi_query_object(xen_wmi_obj_invocation_data_t *obj_inv_data)
+{
+    int result; 
+    struct acpi_buffer out_buf = {ACPI_ALLOCATE_BUFFER, NULL};
+
+    result = wmi_query_block(obj_inv_data->guid, 
+                             obj_inv_data->xen_wmi_arg.xen_wmi_query_obj_arg.instance,
+                             &out_buf);
+
+    if ( out_buf.length > 0 && result == XEN_WMI_SUCCESS )
+    {
+#ifdef XEN_WMI_DEBUG
+        xen_wmi_print_buffer(&out_buf);
+#endif
+        result = xen_wmi_copy_output_buffer(&out_buf,
+                                            &obj_inv_data->xen_wmi_arg.xen_wmi_query_obj_arg.out_buf);
+        kfree(out_buf.pointer);
+    }
+    else
+        printk("XEN WMI - Query WMI object failed with error - %d; output buffer length - %d\n",
+               result, out_buf.length);
+
+    return result;
+}
+
+/*
+ * xen_wmi_set_object
+ */
+int xen_wmi_set_object(xen_wmi_obj_invocation_data_t *obj_inv_data) 
+{
+    int result;
+    struct acpi_buffer in_buf;
+
+    if ( obj_inv_data->xen_wmi_arg.xen_wmi_set_obj_arg.in_buf.length <= 0 )
+        return XEN_WMI_INVALID_ARGUMENT;
+
+    result = xen_wmi_copy_input_buffer(&obj_inv_data->xen_wmi_arg.xen_wmi_set_obj_arg.in_buf,
+                                       &in_buf);
+    if ( result != XEN_WMI_SUCCESS )
+        return result;
+
+    result = wmi_set_block(obj_inv_data->guid, 
+                           obj_inv_data->xen_wmi_arg.xen_wmi_set_obj_arg.instance,
+                           &in_buf); 
+    if ( result != XEN_WMI_SUCCESS )
+        printk("XEN WMI: Set object failed with error - %d\n", result);
+
+    kfree(in_buf.pointer);
+    return result;
+}
+
+/*
+ * xen_wmi_get_event_data 
+ */
+int xen_wmi_get_event_data(xen_wmi_obj_invocation_data_t *obj_inv_data) 
+{
+    int result;
+    struct acpi_buffer out_buf = {ACPI_ALLOCATE_BUFFER, NULL};
+
+    result = wmi_get_event_data(obj_inv_data->xen_wmi_arg.xen_wmi_event_data_arg.event_id,
+                       &out_buf);
+
+    if ( out_buf.length > 0 && result == XEN_WMI_SUCCESS )
+    {
+#ifdef XEN_WMI_DEBUG
+        xen_wmi_print_buffer(&out_buf);
+#endif
+        result = xen_wmi_copy_output_buffer(&out_buf,
+                                            &obj_inv_data->xen_wmi_arg.xen_wmi_event_data_arg.out_buf);
+        kfree(out_buf.pointer);
+    }
+    else
+        printk("XEN WMI: Get event data failed with error - %d\n", result);
+
+    return result;
+}
+
+/*
+ * xen_wmi_ioctl 
+ */
+static int xen_wmi_ioctl(struct inode *inode, struct file *filp,
+                         unsigned int cmd, unsigned long arg)
+{
+    xen_wmi_obj_invocation_data_t obj_inv_data;
+
+#ifdef XEN_WMI_DEBUG
+    printk("XEN WMI:  In xen_wmi_ioctl - %d\n", cmd);
+#endif
+
+    memset(&obj_inv_data, 0, sizeof(obj_inv_data));
+    if ( copy_from_user(&obj_inv_data, (char __user *)arg, sizeof(obj_inv_data)) )
+    {
+        printk("XEN WMI: Invalid object invocation parameter\n");
+        return XEN_WMI_EFAULT;
+    }
+    switch ( cmd ) 
+    {
+        case XEN_WMI_IOCTL_CALL_METHOD:
+            return xen_wmi_invoke_method(&obj_inv_data);
+        case XEN_WMI_IOCTL_QUERY_OBJECT:
+            return xen_wmi_query_object(&obj_inv_data); 
+        case XEN_WMI_IOCTL_SET_OBJECT:
+            return xen_wmi_set_object(&obj_inv_data); 
+        case XEN_WMI_IOCTL_GET_EVENT_DATA:
+            return xen_wmi_get_event_data(&obj_inv_data); 
+    }
+
+    return XEN_WMI_ENOIOCTLCMD;
+}
+
+/*
+ * xen_wmi_init 
+ */
+static int __init xen_wmi_init(void)
+{
+    int ret;
+
+    ret = misc_register(&xen_wmi_misc);
+    if ( ret < 0 )
+        printk("XEN WMI: misc_register failed with error - %d\n", ret);
+    else
+        xen_wmi_misc_dev_registered = true;
+
+#ifdef XEN_WMI_DEBUG
+    printk("XEN WMI: xen-acpi-wmi misc_register succeeded!\n"); 
+#endif
+    return ret;
+}
+
+/*
+ * xen_wmi_exit 
+ */
+static void xen_wmi_exit(void)
+{
+    int ret;
+
+    if ( xen_wmi_misc_dev_registered == false )
+        return;
+
+    if ( (ret = misc_deregister(&xen_wmi_misc)) < 0 )
+        printk("XEN WMI: misc_deregister failed with error - %d\n", ret); 
+}
+
+module_init(xen_wmi_init);
+module_exit(xen_wmi_exit);
+MODULE_LICENSE("Dual BSD/GPL");
+
diff --git a/include/xen/public/acpi-wmi.h b/include/xen/public/acpi-wmi.h
new file mode 100644 (file)
index 0000000..097639b
--- /dev/null
@@ -0,0 +1,94 @@
+/******************************************************************************
+ * acpi-wmi.h
+ *
+ * Interface to /proc/misc/xen-acpi-wmi
+ *
+ * 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_WMI_ACPI
+#define _XEN_WMI_ACPI
+
+/*
+ * Userspace Interface
+ */
+
+#define XEN_WMI_DEVICE_NAME              "xen-acpi-wmi"
+#define XEN_WMI_GUID_SIZE                16
+
+#define XEN_WMI_SUCCESS                  0
+#define XEN_WMI_UNSUPPORTED_TYPE        -1
+#define XEN_WMI_BUFFER_TOO_SMALL        -11
+#define XEN_WMI_NOT_ENOUGH_MEMORY       -12
+#define XEN_WMI_EFAULT                  -14
+#define XEN_WMI_INVALID_ARGUMENT        -22
+#define XEN_WMI_ENOIOCTLCMD             -515
+#define XEN_WMI_IOCTL_CALL_METHOD        100
+#define XEN_WMI_IOCTL_QUERY_OBJECT       101
+#define XEN_WMI_IOCTL_SET_OBJECT         102
+#define XEN_WMI_IOCTL_GET_EVENT_DATA     103
+
+typedef unsigned char byte;
+
+typedef struct xen_wmi_buffer {
+    size_t       length; 
+    void        *pointer;
+    size_t      *copied_length;
+} xen_wmi_buffer_t;
+
+typedef struct xen_wmi_obj_invocation_data { 
+    byte                       guid[XEN_WMI_GUID_SIZE];
+    union {
+        struct {
+            ushort             instance;
+            uint               method_id;
+            xen_wmi_buffer_t   in_buf;
+            xen_wmi_buffer_t   out_buf;
+        } xen_wmi_method_arg;
+
+        struct {
+            ushort             instance;
+            xen_wmi_buffer_t   out_buf;
+        } xen_wmi_query_obj_arg;
+
+        struct {
+            ushort             instance;
+            xen_wmi_buffer_t   in_buf;
+        } xen_wmi_set_obj_arg;
+
+        struct {
+            ushort             event_id;
+            xen_wmi_buffer_t   out_buf;
+        } xen_wmi_event_data_arg;
+    } xen_wmi_arg;
+} xen_wmi_obj_invocation_data_t;
+
+#endif /* _XEN_WMI_ACPI */
+