]> xenbits.xensource.com Git - xenclient/ioemu.git/commitdiff
OEM specific hotkeys/special button support (patch 3/5).
authorKamala Narasimhan <kamala.narasimhan@citrix.com>
Wed, 11 Feb 2009 22:23:56 +0000 (17:23 -0500)
committerKamala Narasimhan <kamala.narasimhan@citrix.com>
Wed, 11 Feb 2009 22:23:56 +0000 (17:23 -0500)
ACPI WMI psuedo objects exposed through our guest vACPI layer
relies on this implementation to talk to our kernel WMI module
and get necessary WMI information from the base firmware.

hw/acpi-wmi.h [new file with mode: 0644]
hw/pc.h
hw/piix4acpi.c
hw/xen_acpi_wmi.c [new file with mode: 0644]
hw/xen_acpi_wmi.h [new file with mode: 0644]
qemu-xen.h
xen-hooks.mak
xenstore.c

diff --git a/hw/acpi-wmi.h b/hw/acpi-wmi.h
new file mode 100644 (file)
index 0000000..af99c1c
--- /dev/null
@@ -0,0 +1,99 @@
+/******************************************************************************
+ * 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.
+ */
+
+/*  NOTE:  This header is a duplicate of drivers/xen/acpi-wmi/acpi-wmi.h in our
+ *  kernel repo.  As we don't share headers between kernel and userspace, we have
+ *  the same header in two places.  It is important to keep the two headers in sync
+ *  to avoid incompatibilities.
+ */ 
+
+#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 */
+
diff --git a/hw/pc.h b/hw/pc.h
index 55cf3199b66eb118cf4441b0e3b9b324c7bf351b..a4ffc3893aae4c01c9dbe7f5f360ea651bb6d3b9 100644 (file)
--- a/hw/pc.h
+++ b/hw/pc.h
@@ -106,6 +106,8 @@ void acpi_ac_adapter_state_changed(void);
 void acpi_power_button_pressed(void);
 void acpi_lid_state_changed(void);
 
+void acpi_oem_event(void);
+
 /* pcspk.c */
 void pcspk_init(PITState *);
 int pcspk_audio_init(AudioState *, qemu_irq *pic);
index 7ae65323c85d8b24759044f924133b4abe25b5ae..c661fa65ed092a53bb3c46e24251e0b649158867 100644 (file)
@@ -29,6 +29,7 @@
 #include "sysemu.h"
 #include "qemu-xen.h"
 #include "battery_mgmt.h"
+#include "xen_acpi_wmi.h"
 
 #include <xen/hvm/ioreq.h>
 #include <xen/hvm/params.h>
@@ -56,6 +57,7 @@
 #define ACPI_AC_POWER_STATE_BIT 0x1c
 #define ACPI_POWER_BUTTON_BIT 0x1
 #define ACPI_LID_STATE_BIT 0x17 
+#define ACPI_OEM_EVENT_BIT 0x18
 #define ACPI_PHP_SLOT_NUM PHP_SLOT_LEN
 
 typedef struct AcpiDeviceState AcpiDeviceState;
@@ -193,6 +195,7 @@ static void acpi_map(PCIDevice *pci_dev, int region_num,
     register_ioport_read(addr + 4, 2, 2, acpiPm1Control_readw, d);
 
     battery_mgmt_init(pci_dev);
+    xen_acpi_wmi_init(pci_dev);
 }
 
 static inline int test_bit(uint8_t *map, int bit)
@@ -247,6 +250,19 @@ void acpi_lid_state_changed(void)
     }
 }
 
+void acpi_oem_event(void)
+{
+    GPEState *s = &gpe_state;
+
+    if ( !test_bit(&s->gpe0_sts[0], ACPI_OEM_EVENT_BIT) &&
+         test_bit(&s->gpe0_en[0], ACPI_OEM_EVENT_BIT) ) {
+        set_bit(&s->gpe0_sts[0], ACPI_OEM_EVENT_BIT);
+        s->sci_asserted = 1;
+        fprintf(logfile, "Raising oem event irq\n");
+        qemu_irq_raise(sci_irq);
+    }
+}
+
 /* GPEx_STS occupy 1st half of the block, while GPEx_EN 2nd half */
 static uint32_t gpe_sts_read(void *opaque, uint32_t addr)
 {
diff --git a/hw/xen_acpi_wmi.c b/hw/xen_acpi_wmi.c
new file mode 100644 (file)
index 0000000..47de7db
--- /dev/null
@@ -0,0 +1,654 @@
+/*
+ * xen_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 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
+ */
+
+/* Xen ACPI WMI implementation - 
+ * OEMs expose their value add functionalites through firmware level WMI 
+ * acpi objects.  To support the underlying OEM value add within guest 
+ * space, we expose a WMI psuedo device object at our vACPI layer.  That 
+ * vACPI layer relies on the below implementation to communication to the
+ * base firmware (through xen wmi module and linux acpi wmi wrapper 
+ * driver) either it be to execute a WMI method or query or set 
+ * data or recieve wmi event data. 
+ */
+
+/* NOTE:  As the vACPI layer is written to send request and take response in a 
+ * synchronized way, there isn't a need to add synchronization logic here.
+ */
+
+#include "hw.h"
+#include "pc.h"
+#include "qemu-xen.h"
+#include "isa.h" 
+#include "xen_acpi_wmi.h"
+
+#ifndef CONFIG_NO_XEN_ACPI_WMI
+
+#define XEN_WMI_DEFAULT_OUTPUT_BUFFER_SIZE 256
+
+static xen_acpi_wmi_cmd_info_t cmd_info;
+static int xen_wmi_device = -ENODEV;  
+extern FILE *logfile;
+extern int domid;
+
+/* #define XEN_ACPI_WMI_DEBUG */
+/* #define XEN_ACPI_WMI_DEBUG_EXT */
+
+/*
+ * xen_acpi_wmi_set_guid
+ */
+void xen_acpi_wmi_set_guid(uint8_t val)
+{
+    if ( cmd_info.invocation_type == XEN_ACPI_WMI_UNDEFINED )
+    {
+        fprintf(logfile, 
+            "XEN WMI: Unable to set guid with invalid invocation type!\n");
+        return;
+    }
+
+    if ( cmd_info.current_index >= XEN_WMI_GUID_SIZE )
+    {
+        fprintf(logfile, "XEN WMI: Guid array index out of range - %d!!!\n", 
+                cmd_info.current_index);
+        cmd_info.invocation_type = XEN_ACPI_WMI_UNDEFINED;  
+        return;
+    }
+
+    cmd_info.invocation_data.guid[cmd_info.current_index] = val;
+    cmd_info.current_index++;
+}
+
+/*
+ * xen_acpi_wmi_set_cmd_instance
+ */
+void xen_acpi_wmi_set_cmd_instance(uint32_t val)
+{
+    if ( cmd_info.invocation_type == XEN_ACPI_WMI_UNDEFINED ) 
+    {
+        fprintf(logfile, 
+            "XEN WMI: Unable to set cmd instance with invalid invocation type!\n");
+        return;
+    }
+
+    switch( cmd_info.invocation_type )
+    {
+        case XEN_ACPI_WMI_EXEC_METHOD:
+            cmd_info.invocation_data.xen_wmi_arg.xen_wmi_method_arg.instance = val;
+            break;
+        case XEN_ACPI_WMI_QUERY_OBJECT:
+            cmd_info.invocation_data.xen_wmi_arg.xen_wmi_query_obj_arg.instance = val;
+            break;
+        case XEN_ACPI_WMI_SET_OBJECT:
+            cmd_info.invocation_data.xen_wmi_arg.xen_wmi_set_obj_arg.instance = val;
+            break;
+        default:
+            fprintf(logfile, 
+                "Invalid attempt to set instance for current invocation type!\n");
+            break;
+    }
+}
+
+/*
+ * xen_acpi_wmi_set_method_id
+ */
+void xen_acpi_wmi_set_method_id(uint32_t val)
+{
+    if ( cmd_info.invocation_type != XEN_ACPI_WMI_EXEC_METHOD )
+    {
+        fprintf(logfile,
+            "Unable to set method id for the current invocation type!\n");
+        return;
+    }
+
+    cmd_info.invocation_data.xen_wmi_arg.xen_wmi_method_arg.method_id = val;
+}
+
+/*
+ * xen_acpi_wmi_get_input_buffer
+ */
+xen_wmi_buffer_t *xen_acpi_wmi_get_input_buffer(void)
+{
+    if ( cmd_info.invocation_type != XEN_ACPI_WMI_EXEC_METHOD  &&
+         cmd_info.invocation_type != XEN_ACPI_WMI_SET_OBJECT )
+        return 0;
+
+    if ( cmd_info.invocation_type == XEN_ACPI_WMI_EXEC_METHOD )
+        return &cmd_info.invocation_data.xen_wmi_arg.xen_wmi_method_arg.in_buf;
+    else if ( cmd_info.invocation_type == XEN_ACPI_WMI_SET_OBJECT )
+        return &cmd_info.invocation_data.xen_wmi_arg.xen_wmi_set_obj_arg.in_buf;
+
+    return 0;
+}
+
+/*
+ * xen_acpi_wmi_set_buffer_size
+ * Guest vACPI layer passes to us the size of the input buffer it is 
+ * about to transfer to ioemu  and this method stores the passed in size  
+ * apart from allocating a buffer with the provided size. 
+ */
+void xen_acpi_wmi_set_in_buffer_size(uint32_t val)
+{
+    xen_wmi_buffer_t *buffer;
+
+    buffer = xen_acpi_wmi_get_input_buffer();
+    if ( buffer == NULL )
+        return;
+
+    cmd_info.current_index = 0;
+    buffer->length = val;
+    buffer->pointer = malloc(val); 
+}
+
+/*
+ * xen_acpi_wmi_set_in_buffer
+ */
+void xen_acpi_wmi_set_in_buffer(uint8_t val)
+{
+    xen_wmi_buffer_t *buffer;
+
+    buffer = xen_acpi_wmi_get_input_buffer();
+    if ( buffer == NULL )
+        return;
+
+    if ( cmd_info.current_index >= buffer->length )
+    {
+        fprintf(logfile, 
+            "XEN WMI: Cannot write beyond allocated input buffer size!!!\n");
+        return;
+    }
+
+    ((byte *)buffer->pointer)[cmd_info.current_index] = val;
+    cmd_info.current_index++;
+}
+
+/*
+ * xen_wmi_get_output_buffer
+ */
+xen_wmi_buffer_t *xen_acpi_wmi_get_output_buffer(void)
+{
+    if ( cmd_info.invocation_type != XEN_ACPI_WMI_EXEC_METHOD &&
+         cmd_info.invocation_type != XEN_ACPI_WMI_QUERY_OBJECT &&
+         cmd_info.invocation_type != XEN_ACPI_WMI_GET_EVENT_DATA )
+    {
+        fprintf(logfile,
+            "XEN WMI: Output buffer not available for current invocation type!\n"); 
+        return 0;
+    }
+
+    if ( cmd_info.invocation_type == XEN_ACPI_WMI_EXEC_METHOD )
+        return  &cmd_info.invocation_data.xen_wmi_arg.xen_wmi_method_arg.out_buf;
+    else if ( cmd_info.invocation_type == XEN_ACPI_WMI_QUERY_OBJECT )
+        return &cmd_info.invocation_data.xen_wmi_arg.xen_wmi_query_obj_arg.out_buf;
+    else if ( cmd_info.invocation_type == XEN_ACPI_WMI_GET_EVENT_DATA )
+        return  &cmd_info.invocation_data.xen_wmi_arg.xen_wmi_event_data_arg.out_buf;
+
+    return 0;
+}
+
+/*
+ * xen_acpi_wmi_allocate_output_buffer
+ */
+void xen_acpi_wmi_allocate_output_buffer(size_t length)
+{
+    xen_wmi_buffer_t *buffer;
+
+    buffer = xen_acpi_wmi_get_output_buffer();
+    if ( buffer == NULL )
+        return;
+
+    buffer->length = (length > 0) ? length : XEN_WMI_DEFAULT_OUTPUT_BUFFER_SIZE;
+    buffer->pointer = malloc(buffer->length); 
+    memset(buffer->pointer, 0, buffer->length);
+
+    buffer->copied_length = malloc(sizeof(size_t));
+    memset(buffer->copied_length, 0, sizeof(size_t));
+}
+
+/*
+ * xen_acpi_wmi_reallocate_output_buffer
+ */
+int xen_acpi_wmi_reallocate_output_buffer()
+{
+    xen_wmi_buffer_t *buffer;
+
+    buffer = xen_acpi_wmi_get_output_buffer();
+    if ( buffer == NULL || buffer->copied_length == NULL || buffer->pointer == NULL )
+        return XEN_WMI_NOT_ENOUGH_MEMORY; 
+
+    /* If required length is less than allocated length,
+     * we shouldn't have failed; no point in rellocating.
+     * @TODO: Rename copied_length to something more appropriate.
+     */
+    if ( *buffer->copied_length <= buffer->length )
+        return XEN_WMI_NOT_ENOUGH_MEMORY;
+
+    free(buffer->pointer);
+    buffer->pointer = malloc(*buffer->copied_length);
+    memset(buffer->pointer, 0, *buffer->copied_length);
+    buffer->length = *buffer->copied_length;
+    return XEN_WMI_SUCCESS;
+}
+
+/*
+ * xen_acpi_wmi_free_input_buffer 
+ */
+void xen_acpi_wmi_free_input_buffer(void)
+{
+    xen_wmi_buffer_t *buffer;
+
+    buffer = xen_acpi_wmi_get_input_buffer();
+    if ( buffer == NULL )
+        return;
+
+    if ( buffer->length > 0 )
+        free(buffer->pointer);
+    buffer->length = 0;
+}
+
+#ifdef XEN_ACPI_WMI_DEBUG
+
+/*
+ * xen_acpi_wmi_print_input_buffer
+ */
+void xen_acpi_wmi_print_input_buffer(xen_wmi_buffer_t *in_buf)
+{
+    int count;
+
+    fprintf(logfile, "In buffer length - %d\n", in_buf->length);
+    fprintf(logfile, "In buffer:  ");
+    for( count = 0; count < in_buf->length; count++ )
+        fprintf(logfile, " %d,  ", ((byte *)in_buf->pointer)[count]);
+    fprintf(logfile, "\n");
+}
+
+/*
+ * xen_acpi_wmi_print_input_info
+ */
+void xen_acpi_wmi_print_input_info(void)
+{
+    int count;
+
+    fprintf(logfile, "Command invocation type - %d\n", cmd_info.invocation_type);
+    fprintf(logfile, "Invocation Data:  \n");
+    fprintf(logfile, "Guid: ");
+
+    for (count=0; count < XEN_WMI_GUID_SIZE; count++)
+        fprintf(logfile,"%d  ", cmd_info.invocation_data.guid[count]);
+
+    fprintf(logfile, "\n");
+
+    if ( cmd_info.invocation_type == XEN_ACPI_WMI_EXEC_METHOD )
+    {
+        fprintf(logfile, 
+            "Instance id - %d\n", 
+            cmd_info.invocation_data.xen_wmi_arg.xen_wmi_method_arg.instance);
+        fprintf(logfile,
+            "Method id - %d\n", 
+            cmd_info.invocation_data.xen_wmi_arg.xen_wmi_method_arg.method_id);
+        xen_acpi_wmi_print_input_buffer(
+            &cmd_info.invocation_data.xen_wmi_arg.xen_wmi_method_arg.in_buf);
+    }
+    else if ( cmd_info.invocation_type == XEN_ACPI_WMI_QUERY_OBJECT )
+    {
+        fprintf(logfile,
+            "Instance id - %d\n", 
+            cmd_info.invocation_data.xen_wmi_arg.xen_wmi_query_obj_arg.instance);
+    }
+    else if ( cmd_info.invocation_type == XEN_ACPI_WMI_SET_OBJECT )
+    {
+        fprintf(logfile,
+            "Instance id - %d\n", 
+            cmd_info.invocation_data.xen_wmi_arg.xen_wmi_set_obj_arg.instance);
+        xen_acpi_wmi_print_input_buffer(
+            &cmd_info.invocation_data.xen_wmi_arg.xen_wmi_set_obj_arg.in_buf);
+    }
+    else if ( cmd_info.invocation_type == XEN_ACPI_WMI_GET_EVENT_DATA )
+    {
+        fprintf(logfile,
+            "Event id - %d\n",
+            cmd_info.invocation_data.xen_wmi_arg.xen_wmi_event_data_arg.event_id);
+    } 
+}
+
+/*
+ * xen_acpi_wmi_print_output_buffer
+ */
+void xen_acpi_wmi_print_output_buffer(void)
+{
+    int count;
+    xen_wmi_buffer_t *buffer = xen_acpi_wmi_get_output_buffer();
+
+    if ( buffer == NULL || buffer->copied_length == NULL || *buffer->copied_length == 0 )
+        return;
+
+    fprintf(logfile, "XEN WMI: Output buffer size is - %d\n",
+            *buffer->copied_length);
+    fprintf(logfile, "XEN WMI output buffer is - ");
+    for (count=0; count < *buffer->copied_length; count++)
+        fprintf(logfile," %d, ", ((byte *)buffer->pointer)[count]);
+
+    fprintf(logfile, "\n");
+}
+
+#endif /* XEN_ACPI_WMI_DEBUG */
+
+/*
+ * xen_acpi_wmi_execute
+ */
+void xen_acpi_wmi_execute(void)
+{
+    int request, ret;
+
+    if ( cmd_info.invocation_type == XEN_ACPI_WMI_UNDEFINED )
+    {
+        fprintf(logfile,
+            "Unable to execute command for the given invocation type!\n");
+        return;
+    }
+
+    switch ( cmd_info.invocation_type )
+    {
+        case XEN_ACPI_WMI_EXEC_METHOD:
+            request = XEN_WMI_IOCTL_CALL_METHOD;
+            break;
+        case XEN_ACPI_WMI_QUERY_OBJECT:
+            request = XEN_WMI_IOCTL_QUERY_OBJECT; 
+            break;
+        case XEN_ACPI_WMI_SET_OBJECT:
+            request = XEN_WMI_IOCTL_SET_OBJECT;
+            break;
+        case XEN_ACPI_WMI_GET_EVENT_DATA:
+            request = XEN_WMI_IOCTL_GET_EVENT_DATA;
+            break;
+        default:
+            fprintf(logfile,
+                "Unable to execute command for the given invocation type!\n");
+            return;
+    } 
+
+    xen_acpi_wmi_allocate_output_buffer(0);
+#ifdef XEN_ACPI_WMI_DEBUG
+    fprintf(logfile, "XEN WMI Invoking ioctl - %d\n", cmd_info.invocation_type);
+    xen_acpi_wmi_print_input_info();
+#endif
+    ret = ioctl(xen_wmi_device, request, &cmd_info.invocation_data);
+    if ( ret == XEN_WMI_BUFFER_TOO_SMALL )
+    {
+        if ( xen_acpi_wmi_reallocate_output_buffer() == XEN_WMI_SUCCESS )
+            ret = ioctl(xen_wmi_device, request, &cmd_info.invocation_data);
+    }
+
+    if ( ret != XEN_WMI_SUCCESS )
+        fprintf(logfile, "Xen WMI ioctl failed with error - %d\n", ret);
+
+#ifdef XEN_ACPI_WMI_DEBUG
+    xen_acpi_wmi_print_output_buffer();
+#endif
+
+    xen_acpi_wmi_free_input_buffer();
+}
+
+/*
+ * xen_acpi_wmi_set_event_id
+ */
+void xen_acpi_wmi_set_event_id(uint8_t event_id)
+{
+    if ( cmd_info.invocation_type != XEN_ACPI_WMI_GET_EVENT_DATA )
+    {
+        fprintf(logfile, 
+            "XEN WMI: Request to set event ID with incorrect invocation type!!!\n");        
+        return;
+    }
+
+    cmd_info.invocation_data.xen_wmi_arg.xen_wmi_event_data_arg.event_id = event_id;
+}
+
+/*
+ * xen_acpi_wmi_cmd_port_read
+ */
+static uint32_t xen_acpi_wmi_cmd_port_read(void *opaque, uint32_t addr)
+{
+#ifdef XEN_ACPI_WMI_DEBUG_EXT
+    fprintf(logfile, "XEN WMI: In cmd port read - %d\n",
+        cmd_info.cmd_type);
+#endif
+    return cmd_info.cmd_type;
+}   
+
+/*
+ * xen_acpi_wmi_cmd_port_write
+ */
+static void xen_acpi_wmi_cmd_port_write(void *opaque, uint32_t addr, uint32_t val)
+{
+#ifdef XEN_ACPI_WMI_DEBUG_EXT
+    fprintf(logfile, "XEN WMI: In cmd port write - %d\n", val);
+#endif
+    cmd_info.cmd_type = val;
+    if ( val < XEN_ACPI_WMI_CMD_INIT || val >= XEN_ACPI_WMI_CMD_UNDEFINED )
+    {
+        fprintf(logfile,"XEN WMI: Unknown xen acpi wmi command - %d\n", val);
+        cmd_info.invocation_type = XEN_ACPI_WMI_UNDEFINED;
+        cmd_info.current_index = 0;
+        return; 
+    } 
+
+    if ( val == XEN_ACPI_WMI_CMD_EXECUTE )
+        xen_acpi_wmi_execute();
+}
+
+/*
+ * xen_acpi_wmi_data_port_readb
+ */
+static uint32_t xen_acpi_wmi_data_port_readb(void *opaque, uint32_t addr)
+{
+    xen_wmi_buffer_t *buffer;
+    byte ret;
+
+    if ( cmd_info.cmd_type == XEN_ACPI_WMI_CMD_OUT_BUFFER )
+    {
+        buffer = xen_acpi_wmi_get_output_buffer();
+        if ( buffer == NULL || buffer->copied_length == NULL )
+            return 0x0;
+
+        if ( *buffer->copied_length == 0 )
+            return 0x0;
+
+        if ( cmd_info.current_index >= *buffer->copied_length )
+        {
+            fprintf(logfile, 
+                "XEN WMI: Output buffer index overflow. Current - %d Max - %d\n",
+                 cmd_info.current_index, *buffer->copied_length);
+            cmd_info.cmd_type = XEN_ACPI_WMI_CMD_UNDEFINED; 
+            return 0x0;
+        }
+
+        ret = ((byte*)buffer->pointer)[cmd_info.current_index];
+        if ( cmd_info.current_index == buffer->length-1 )
+        {
+            /* @TODO: We expect that the firmware would read all of
+             * the output buffer before releasing it.  This
+             * could result in a leak if the firmware chooses
+             * to ignore the return buffer. It might make sense to
+             * introduce a cleanup command. */ 
+            cmd_info.cmd_type = XEN_ACPI_WMI_CMD_UNDEFINED; 
+            buffer->length = 0;
+            free(buffer->pointer);
+            buffer->pointer = NULL;
+            free(buffer->copied_length);
+            buffer->copied_length = NULL;
+        }
+
+#ifdef XEN_ACPI_WMI_DEBUG_EXT 
+        fprintf(logfile, "XEN WMI: Data port read returned - %d\n", ret);
+#endif
+        cmd_info.current_index++;
+        return ret;
+    } 
+
+    fprintf(logfile, "XEN WMI: Data port read byte.  Shouldn't be here!!!\n");
+    return 0x0;
+}  
+
+/*
+ * xen_acpi_wmi_data_port_writeb
+ */
+static void xen_acpi_wmi_data_port_writeb(void *opaque, uint32_t addr, uint32_t val)
+{
+#ifdef XEN_ACPI_WMI_DEBUG_EXT
+    fprintf(logfile, "XEN WMI: In data port write byte - %d\n", val);
+#endif
+
+    switch( cmd_info.cmd_type )
+    {
+        case XEN_ACPI_WMI_CMD_INIT:
+            cmd_info.invocation_type = val;
+            cmd_info.current_index = 0;
+            memset(&cmd_info.invocation_data, 0, sizeof(cmd_info.invocation_data));
+            break;
+        case XEN_ACPI_WMI_CMD_GUID:
+            xen_acpi_wmi_set_guid(val);
+            break;
+        case XEN_ACPI_WMI_CMD_IN_BUFFER:
+            xen_acpi_wmi_set_in_buffer(val);
+            break;
+        case XEN_ACPI_WMI_CMD_EVENT_ID:
+            xen_acpi_wmi_set_event_id(val);
+            break;
+        default:
+            fprintf(logfile, 
+                "XEN WMI: Attempting to write to data(byte) port with incompatible cmd type %d\n",    
+                    cmd_info.cmd_type);
+             break;
+    }    
+}
+
+/*
+ * xen_acpi_wmi_data_port_readl
+ */
+static uint32_t xen_acpi_wmi_data_port_readl(void *opaque, uint32_t addr)
+{
+    xen_wmi_buffer_t *buffer;
+
+    if ( cmd_info.cmd_type == XEN_ACPI_WMI_CMD_OUT_BUFFER_SIZE )
+    {
+        buffer = xen_acpi_wmi_get_output_buffer();
+        if ( buffer == NULL || buffer->copied_length == NULL )
+            return 0x0;
+
+        if (*buffer->copied_length == 0 )
+            return 0x0;
+
+        cmd_info.current_index = 0;
+#ifdef XEN_ACPI_WMI_DEBUG_EXT
+       fprintf(logfile, "XEN WMI: Output buffer length is - %d\n", *buffer->copied_length);
+#endif
+        return *buffer->copied_length;
+    }
+
+    fprintf(logfile, "XEN WMI: Data port read long.  Shouldn't be here!!!\n");
+    return 0x0;
+} 
+
+/*
+ * xen_acpi_wmi_data_port_writel
+ */
+static void xen_acpi_wmi_data_port_writel(void *opaque, uint32_t addr, uint32_t val)
+{
+#ifdef XEN_ACPI_WMI_DEBUG_EXT
+    fprintf(logfile, "XEN WMI: In data port write long - %d\n", val);
+#endif
+
+    switch( cmd_info.cmd_type )
+    {
+        case XEN_ACPI_WMI_CMD_OBJ_INSTANCE:
+            xen_acpi_wmi_set_cmd_instance(val);
+            break;
+        case XEN_ACPI_WMI_CMD_METHOD_ID:
+            xen_acpi_wmi_set_method_id(val);
+            break;
+        case XEN_ACPI_WMI_CMD_IN_BUFFER_SIZE:
+            xen_acpi_wmi_set_in_buffer_size(val);
+            break;
+        default:
+            fprintf(logfile,
+                "XEN WMI: Attempting to write to data(long) port with incompatible cmd type %d\n",
+                    cmd_info.cmd_type);
+             break;
+    }
+}
+
+/*
+ * xen_acpi_wmi_init
+ */
+void xen_acpi_wmi_init(PCIDevice *device)
+{
+    char dev_name[64];
+    char *oem_buffer;
+
+    cmd_info.invocation_type = XEN_ACPI_WMI_UNDEFINED;
+    cmd_info.current_index = 0;
+
+    oem_buffer = xenstore_device_model_read(domid, "oem_value_add", NULL);
+    if ( oem_buffer == NULL )
+    {
+#ifdef XEN_ACPI_WMI_DEBUG 
+        fprintf(logfile,"OEM value add disabled!\n");
+#endif
+        return;
+    }
+
+    sprintf(dev_name, "/dev/%s", XEN_WMI_DEVICE_NAME);
+    xen_wmi_device = open(dev_name, 0);
+    if ( xen_wmi_device < 0 )
+    {
+        fprintf(logfile, 
+            "XEN WMI: Unable to open device - %s\n", XEN_WMI_DEVICE_NAME);
+        return;
+    }
+
+    register_ioport_read(XEN_ACPI_WMI_CMD_PORT, 1, 1, xen_acpi_wmi_cmd_port_read, device);   
+    register_ioport_write(XEN_ACPI_WMI_CMD_PORT, 1, 1, xen_acpi_wmi_cmd_port_write, device); 
+    register_ioport_read(XEN_ACPI_WMI_DATA_PORTB, 1, 1, xen_acpi_wmi_data_port_readb, device);
+    register_ioport_write(XEN_ACPI_WMI_DATA_PORTB, 1, 1, xen_acpi_wmi_data_port_writeb, device);
+    register_ioport_read(XEN_ACPI_WMI_DATA_PORTL, 4, 4, xen_acpi_wmi_data_port_readl, device);
+    register_ioport_write(XEN_ACPI_WMI_DATA_PORTL, 4, 4, xen_acpi_wmi_data_port_writel, device);
+
+    xenstore_register_for_oem_events();
+#ifdef XEN_ACPI_WMI_DEBUG
+    fprintf(logfile, "XEN WMI:  XEN ACPI WMI registration succeeded!!!\n");
+#endif
+}
+
+/*
+ * xen_acpi_wmi_cleanup(void)
+ */
+void xen_acpi_wmi_cleanup(void)
+{
+    if ( xen_wmi_device > 0 )
+        close(xen_wmi_device);
+}
+
+#else
+
+void xen_acpi_wmi_init(PCIDevice *device) { }
+void xen_acpi_wmi_cleanup(void) { }
+
+#endif /* CONFIG_NO_XEN_ACPI_WMI */
diff --git a/hw/xen_acpi_wmi.h b/hw/xen_acpi_wmi.h
new file mode 100644 (file)
index 0000000..91e4c00
--- /dev/null
@@ -0,0 +1,66 @@
+/*
+ * xen_acpi_wmi.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_WMI_H
+#define _XEN_ACPI_WMI_H
+
+#ifdef CONFIG_STUBDOM
+#define CONFIG_NO_XEN_ACPI_WMI
+#endif
+
+#include "acpi-wmi.h"
+
+#define XEN_ACPI_WMI_CMD_PORT   0x96
+#define XEN_ACPI_WMI_DATA_PORTB 0x98
+#define XEN_ACPI_WMI_DATA_PORTL 0x9A
+
+/* Values written to WMI command port */
+enum XEN_ACPI_WMI_COMMAND { XEN_ACPI_WMI_CMD_INIT = 100,
+                            XEN_ACPI_WMI_CMD_GUID,
+                            XEN_ACPI_WMI_CMD_OBJ_INSTANCE,
+                            XEN_ACPI_WMI_CMD_METHOD_ID,
+                            XEN_ACPI_WMI_CMD_IN_BUFFER,
+                            XEN_ACPI_WMI_CMD_IN_BUFFER_SIZE, 
+                            XEN_ACPI_WMI_CMD_EXECUTE,
+                            XEN_ACPI_WMI_CMD_OUT_BUFFER,
+                            XEN_ACPI_WMI_CMD_OUT_BUFFER_SIZE, 
+                            XEN_ACPI_WMI_CMD_EVENT_ID,
+                            XEN_ACPI_WMI_CMD_UNDEFINED }; 
+
+enum XEN_ACPI_WMI_OBJ_INVOCATION_TYPE { XEN_ACPI_WMI_EXEC_METHOD = 1,
+                                        XEN_ACPI_WMI_QUERY_OBJECT,
+                                        XEN_ACPI_WMI_SET_OBJECT,
+                                        XEN_ACPI_WMI_GET_EVENT_DATA,
+                                        XEN_ACPI_WMI_UNDEFINED };
+
+typedef struct xen_acpi_wmi_cmd_info {
+    enum XEN_ACPI_WMI_COMMAND cmd_type;
+    enum XEN_ACPI_WMI_OBJ_INVOCATION_TYPE invocation_type;
+    xen_wmi_obj_invocation_data_t invocation_data;
+    uint32_t current_index;
+} xen_acpi_wmi_cmd_info_t; 
+
+void xen_acpi_wmi_init(PCIDevice *device);
+void xen_acpi_wmi_cleanup(void);
+
+#endif /* _XEN_ACPI_WMI_H */
+
+
index 93d9e645f2d3bee7883dc796e643a42223326610..7dd89769c99f95654022b7f13ec33a4ec16b3935 100644 (file)
@@ -114,6 +114,8 @@ void xenstore_register_for_pm_events(void);
 int xenstore_read_ac_adapter_state(void);
 int xenstore_read_lid_state(void);
 
+void xenstore_register_for_oem_events(void);
+
 /* xenfbfront.c */
 int xenfb_pv_display_init(DisplayState *ds);
 int xenfb_pv_display_start(void *vram_start);
index ac3c925c5b3f23481512b67e8ac18d78ccb62332..a9d5a0403167282599d2cecc3fbea177897ebec6 100644 (file)
@@ -34,6 +34,7 @@ OBJS += exec-dm.o
 OBJS += pci_emulation.o
 OBJS += battery_mgmt.o
 OBJS += pt_pckbd.o
+OBJS += xen_acpi_wmi.o
 
 ifdef CONFIG_STUBDOM
 CPPFLAGS += $(TARGET_CPPFLAGS)
index ac5a73da0a7bd9f6d5c2c0bc7acd130bef828976..6b577b2b9699f378abbc032025b66a221f5d7d32 100644 (file)
@@ -866,6 +866,11 @@ void xenstore_process_event(void *opaque)
         goto out;
     }
 
+    if (!strcmp(vec[XS_WATCH_TOKEN], "oemevt")) {
+        acpi_oem_event();
+        goto out;
+    }
+
     if (strncmp(vec[XS_WATCH_TOKEN], "hd", 2) ||
         strlen(vec[XS_WATCH_TOKEN]) != 3)
         goto out;
@@ -1287,6 +1292,11 @@ void xenstore_register_for_pm_events(void)
    xs_watch(xsh, "/pm/events/powerbuttonpressed", "pwrbuttonpressedevt");
 }
 
+void xenstore_register_for_oem_events(void)
+{
+   xs_watch(xsh, "/oem/event", "oemevt");
+}
+
 int xenstore_read_ac_adapter_state(void)
 {
     int ac_state = 1;