ACPI: move wmi, asus_acpi, toshiba_acpi to drivers/platform/x86
authorLen Brown <len.brown@intel.com>
Thu, 11 Dec 2008 19:37:26 +0000 (14:37 -0500)
committerLen Brown <len.brown@intel.com>
Fri, 19 Dec 2008 09:42:33 +0000 (04:42 -0500)
These are platform specific drivers that happen to use ACPI,
while drivers/acpi/ is for code that implements ACPI itself.

Signed-off-by: Len Brown <len.brown@intel.com>
drivers/acpi/Kconfig
drivers/acpi/Makefile
drivers/acpi/asus_acpi.c [deleted file]
drivers/acpi/toshiba_acpi.c [deleted file]
drivers/acpi/wmi.c [deleted file]
drivers/platform/x86/Kconfig
drivers/platform/x86/Makefile
drivers/platform/x86/asus_acpi.c [new file with mode: 0644]
drivers/platform/x86/toshiba_acpi.c [new file with mode: 0644]
drivers/platform/x86/wmi.c [new file with mode: 0644]

index b0243fd55ac00716d57037cd01c3a67cddb517c1..d7f9839ba264d34fd0159ba1b70289530129ba4c 100644 (file)
@@ -196,90 +196,6 @@ config ACPI_NUMA
        depends on (X86 || IA64)
        default y if IA64_GENERIC || IA64_SGI_SN2
 
-config ACPI_WMI
-       tristate "WMI (EXPERIMENTAL)"
-       depends on X86
-       depends on EXPERIMENTAL
-       help
-         This driver adds support for the ACPI-WMI (Windows Management
-         Instrumentation) mapper device (PNP0C14) found on some systems.
-
-         ACPI-WMI is a proprietary extension to ACPI to expose parts of the
-         ACPI firmware to userspace - this is done through various vendor
-         defined methods and data blocks in a PNP0C14 device, which are then
-         made available for userspace to call.
-
-         The implementation of this in Linux currently only exposes this to
-         other kernel space drivers.
-
-         This driver is a required dependency to build the firmware specific
-         drivers needed on many machines, including Acer and HP laptops.
-
-         It is safe to enable this driver even if your DSDT doesn't define
-         any ACPI-WMI devices.
-
-config ACPI_ASUS
-        tristate "ASUS/Medion Laptop Extras"
-       depends on X86
-       select BACKLIGHT_CLASS_DEVICE
-        ---help---
-          This driver provides support for extra features of ACPI-compatible
-          ASUS laptops. As some of Medion laptops are made by ASUS, it may also
-          support some Medion laptops (such as 9675 for example).  It makes all
-          the extra buttons generate standard ACPI events that go through
-          /proc/acpi/events, and (on some models) adds support for changing the
-          display brightness and output, switching the LCD backlight on and off,
-          and most importantly, allows you to blink those fancy LEDs intended
-          for reporting mail and wireless status.
-
-         Note: display switching code is currently considered EXPERIMENTAL,
-         toying with these values may even lock your machine.
-
-          All settings are changed via /proc/acpi/asus directory entries. Owner
-          and group for these entries can be set with asus_uid and asus_gid
-          parameters.
-
-          More information and a userspace daemon for handling the extra buttons
-          at <http://sourceforge.net/projects/acpi4asus/>.
-
-          If you have an ACPI-compatible ASUS laptop, say Y or M here. This
-          driver is still under development, so if your laptop is unsupported or
-          something works not quite as expected, please use the mailing list
-          available on the above page (acpi4asus-user@lists.sourceforge.net).
-
-         NOTE: This driver is deprecated and will probably be removed soon,
-         use asus-laptop instead.
-
-config ACPI_TOSHIBA
-       tristate "Toshiba Laptop Extras"
-       depends on X86 && INPUT
-       select INPUT_POLLDEV
-       select NET
-       select RFKILL
-       select BACKLIGHT_CLASS_DEVICE
-       ---help---
-         This driver adds support for access to certain system settings
-         on "legacy free" Toshiba laptops.  These laptops can be recognized by
-         their lack of a BIOS setup menu and APM support.
-
-         On these machines, all system configuration is handled through the
-         ACPI.  This driver is required for access to controls not covered
-         by the general ACPI drivers, such as LCD brightness, video output,
-         etc.
-
-         This driver differs from the non-ACPI Toshiba laptop driver (located
-         under "Processor type and features") in several aspects.
-         Configuration is accessed by reading and writing text files in the
-         /proc tree instead of by program interface to /dev.  Furthermore, no
-         power management functions are exposed, as those are handled by the
-         general ACPI drivers.
-
-         More information about this driver is available at
-         <http://memebeam.org/toys/ToshibaAcpiDriver>.
-
-         If you have a legacy free Toshiba laptop (such as the Libretto L1
-         series), say Y.
-
 config ACPI_CUSTOM_DSDT_FILE
        string "Custom DSDT Table file to include"
        default ""
index 3c0c93300f127ffe91343f8514e27b174742bdb0..f64af36b780eb19b7e38fca1f80d429b4200e127 100644 (file)
@@ -59,9 +59,6 @@ obj-y                         += power.o
 obj-$(CONFIG_ACPI_SYSTEM)      += system.o event.o
 obj-$(CONFIG_ACPI_DEBUG)       += debug.o
 obj-$(CONFIG_ACPI_NUMA)                += numa.o
-obj-$(CONFIG_ACPI_WMI)         += wmi.o
-obj-$(CONFIG_ACPI_ASUS)                += asus_acpi.o
-obj-$(CONFIG_ACPI_TOSHIBA)     += toshiba_acpi.o
 obj-$(CONFIG_ACPI_HOTPLUG_MEMORY)      += acpi_memhotplug.o
 obj-$(CONFIG_ACPI_PROCFS_POWER)        += cm_sbs.o
 obj-$(CONFIG_ACPI_SBS)         += sbshc.o
diff --git a/drivers/acpi/asus_acpi.c b/drivers/acpi/asus_acpi.c
deleted file mode 100644 (file)
index 1e74988..0000000
+++ /dev/null
@@ -1,1460 +0,0 @@
-/*
- *  asus_acpi.c - Asus Laptop ACPI Extras
- *
- *
- *  Copyright (C) 2002-2005 Julien Lerouge, 2003-2006 Karol Kozimor
- *
- *  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
- *
- *
- *  The development page for this driver is located at
- *  http://sourceforge.net/projects/acpi4asus/
- *
- *  Credits:
- *  Pontus Fuchs   - Helper functions, cleanup
- *  Johann Wiesner - Small compile fixes
- *  John Belmonte  - ACPI code for Toshiba laptop was a good starting point.
- *  �ic Burghard  - LED display support for W1N
- *
- */
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/types.h>
-#include <linux/proc_fs.h>
-#include <linux/backlight.h>
-#include <acpi/acpi_drivers.h>
-#include <acpi/acpi_bus.h>
-#include <asm/uaccess.h>
-
-#define ASUS_ACPI_VERSION "0.30"
-
-#define PROC_ASUS       "asus" /* The directory */
-#define PROC_MLED       "mled"
-#define PROC_WLED       "wled"
-#define PROC_TLED       "tled"
-#define PROC_BT         "bluetooth"
-#define PROC_LEDD       "ledd"
-#define PROC_INFO       "info"
-#define PROC_LCD        "lcd"
-#define PROC_BRN        "brn"
-#define PROC_DISP       "disp"
-
-#define ACPI_HOTK_NAME          "Asus Laptop ACPI Extras Driver"
-#define ACPI_HOTK_CLASS         "hotkey"
-#define ACPI_HOTK_DEVICE_NAME   "Hotkey"
-
-/*
- * Some events we use, same for all Asus
- */
-#define BR_UP       0x10
-#define BR_DOWN     0x20
-
-/*
- * Flags for hotk status
- */
-#define MLED_ON     0x01       /* Mail LED */
-#define WLED_ON     0x02       /* Wireless LED */
-#define TLED_ON     0x04       /* Touchpad LED */
-#define BT_ON       0x08       /* Internal Bluetooth */
-
-MODULE_AUTHOR("Julien Lerouge, Karol Kozimor");
-MODULE_DESCRIPTION(ACPI_HOTK_NAME);
-MODULE_LICENSE("GPL");
-
-static uid_t asus_uid;
-static gid_t asus_gid;
-module_param(asus_uid, uint, 0);
-MODULE_PARM_DESC(asus_uid, "UID for entries in /proc/acpi/asus");
-module_param(asus_gid, uint, 0);
-MODULE_PARM_DESC(asus_gid, "GID for entries in /proc/acpi/asus");
-
-/* For each model, all features implemented,
- * those marked with R are relative to HOTK, A for absolute */
-struct model_data {
-       char *name;             /* name of the laptop________________A */
-       char *mt_mled;          /* method to handle mled_____________R */
-       char *mled_status;      /* node to handle mled reading_______A */
-       char *mt_wled;          /* method to handle wled_____________R */
-       char *wled_status;      /* node to handle wled reading_______A */
-       char *mt_tled;          /* method to handle tled_____________R */
-       char *tled_status;      /* node to handle tled reading_______A */
-       char *mt_ledd;          /* method to handle LED display______R */
-       char *mt_bt_switch;     /* method to switch Bluetooth on/off_R */
-       char *bt_status;        /* no model currently supports this__? */
-       char *mt_lcd_switch;    /* method to turn LCD on/off_________A */
-       char *lcd_status;       /* node to read LCD panel state______A */
-       char *brightness_up;    /* method to set brightness up_______A */
-       char *brightness_down;  /* method to set brightness down ____A */
-       char *brightness_set;   /* method to set absolute brightness_R */
-       char *brightness_get;   /* method to get absolute brightness_R */
-       char *brightness_status;/* node to get brightness____________A */
-       char *display_set;      /* method to set video output________R */
-       char *display_get;      /* method to get video output________R */
-};
-
-/*
- * This is the main structure, we can use it to store anything interesting
- * about the hotk device
- */
-struct asus_hotk {
-       struct acpi_device *device;     /* the device we are in */
-       acpi_handle handle;             /* the handle of the hotk device */
-       char status;                    /* status of the hotk, for LEDs */
-       u32 ledd_status;                /* status of the LED display */
-       struct model_data *methods;     /* methods available on the laptop */
-       u8 brightness;                  /* brightness level */
-       enum {
-               A1x = 0,        /* A1340D, A1300F */
-               A2x,            /* A2500H */
-               A4G,            /* A4700G */
-               D1x,            /* D1 */
-               L2D,            /* L2000D */
-               L3C,            /* L3800C */
-               L3D,            /* L3400D */
-               L3H,            /* L3H, L2000E, L5D */
-               L4R,            /* L4500R */
-               L5x,            /* L5800C */
-               L8L,            /* L8400L */
-               M1A,            /* M1300A */
-               M2E,            /* M2400E, L4400L */
-               M6N,            /* M6800N, W3400N */
-               M6R,            /* M6700R, A3000G */
-               P30,            /* Samsung P30 */
-               S1x,            /* S1300A, but also L1400B and M2400A (L84F) */
-               S2x,            /* S200 (J1 reported), Victor MP-XP7210 */
-               W1N,            /* W1000N */
-               W5A,            /* W5A */
-               W3V,            /* W3030V */
-               xxN,            /* M2400N, M3700N, M5200N, M6800N,
-                                                        S1300N, S5200N*/
-               A4S,            /* Z81sp */
-               F3Sa,           /* (Centrino) */
-               END_MODEL
-       } model;                /* Models currently supported */
-       u16 event_count[128];   /* Count for each event TODO make this better */
-};
-
-/* Here we go */
-#define A1x_PREFIX "\\_SB.PCI0.ISA.EC0."
-#define L3C_PREFIX "\\_SB.PCI0.PX40.ECD0."
-#define M1A_PREFIX "\\_SB.PCI0.PX40.EC0."
-#define P30_PREFIX "\\_SB.PCI0.LPCB.EC0."
-#define S1x_PREFIX "\\_SB.PCI0.PX40."
-#define S2x_PREFIX A1x_PREFIX
-#define xxN_PREFIX "\\_SB.PCI0.SBRG.EC0."
-
-static struct model_data model_conf[END_MODEL] = {
-       /*
-        * TODO I have seen a SWBX and AIBX method on some models, like L1400B,
-        * it seems to be a kind of switch, but what for ?
-        */
-
-       {
-        .name = "A1x",
-        .mt_mled = "MLED",
-        .mled_status = "\\MAIL",
-        .mt_lcd_switch = A1x_PREFIX "_Q10",
-        .lcd_status = "\\BKLI",
-        .brightness_up = A1x_PREFIX "_Q0E",
-        .brightness_down = A1x_PREFIX "_Q0F"},
-
-       {
-        .name = "A2x",
-        .mt_mled = "MLED",
-        .mt_wled = "WLED",
-        .wled_status = "\\SG66",
-        .mt_lcd_switch = "\\Q10",
-        .lcd_status = "\\BAOF",
-        .brightness_set = "SPLV",
-        .brightness_get = "GPLV",
-        .display_set = "SDSP",
-        .display_get = "\\INFB"},
-
-       {
-        .name = "A4G",
-        .mt_mled = "MLED",
-/* WLED present, but not controlled by ACPI */
-        .mt_lcd_switch = xxN_PREFIX "_Q10",
-        .brightness_set = "SPLV",
-        .brightness_get = "GPLV",
-        .display_set = "SDSP",
-        .display_get = "\\ADVG"},
-
-       {
-        .name = "D1x",
-        .mt_mled = "MLED",
-        .mt_lcd_switch = "\\Q0D",
-        .lcd_status = "\\GP11",
-        .brightness_up = "\\Q0C",
-        .brightness_down = "\\Q0B",
-        .brightness_status = "\\BLVL",
-        .display_set = "SDSP",
-        .display_get = "\\INFB"},
-
-       {
-        .name = "L2D",
-        .mt_mled = "MLED",
-        .mled_status = "\\SGP6",
-        .mt_wled = "WLED",
-        .wled_status = "\\RCP3",
-        .mt_lcd_switch = "\\Q10",
-        .lcd_status = "\\SGP0",
-        .brightness_up = "\\Q0E",
-        .brightness_down = "\\Q0F",
-        .display_set = "SDSP",
-        .display_get = "\\INFB"},
-
-       {
-        .name = "L3C",
-        .mt_mled = "MLED",
-        .mt_wled = "WLED",
-        .mt_lcd_switch = L3C_PREFIX "_Q10",
-        .lcd_status = "\\GL32",
-        .brightness_set = "SPLV",
-        .brightness_get = "GPLV",
-        .display_set = "SDSP",
-        .display_get = "\\_SB.PCI0.PCI1.VGAC.NMAP"},
-
-       {
-        .name = "L3D",
-        .mt_mled = "MLED",
-        .mled_status = "\\MALD",
-        .mt_wled = "WLED",
-        .mt_lcd_switch = "\\Q10",
-        .lcd_status = "\\BKLG",
-        .brightness_set = "SPLV",
-        .brightness_get = "GPLV",
-        .display_set = "SDSP",
-        .display_get = "\\INFB"},
-
-       {
-        .name = "L3H",
-        .mt_mled = "MLED",
-        .mt_wled = "WLED",
-        .mt_lcd_switch = "EHK",
-        .lcd_status = "\\_SB.PCI0.PM.PBC",
-        .brightness_set = "SPLV",
-        .brightness_get = "GPLV",
-        .display_set = "SDSP",
-        .display_get = "\\INFB"},
-
-       {
-        .name = "L4R",
-        .mt_mled = "MLED",
-        .mt_wled = "WLED",
-        .wled_status = "\\_SB.PCI0.SBRG.SG13",
-        .mt_lcd_switch = xxN_PREFIX "_Q10",
-        .lcd_status = "\\_SB.PCI0.SBSM.SEO4",
-        .brightness_set = "SPLV",
-        .brightness_get = "GPLV",
-        .display_set = "SDSP",
-        .display_get = "\\_SB.PCI0.P0P1.VGA.GETD"},
-
-       {
-        .name = "L5x",
-        .mt_mled = "MLED",
-/* WLED present, but not controlled by ACPI */
-        .mt_tled = "TLED",
-        .mt_lcd_switch = "\\Q0D",
-        .lcd_status = "\\BAOF",
-        .brightness_set = "SPLV",
-        .brightness_get = "GPLV",
-        .display_set = "SDSP",
-        .display_get = "\\INFB"},
-
-       {
-        .name = "L8L"
-/* No features, but at least support the hotkeys */
-        },
-
-       {
-        .name = "M1A",
-        .mt_mled = "MLED",
-        .mt_lcd_switch = M1A_PREFIX "Q10",
-        .lcd_status = "\\PNOF",
-        .brightness_up = M1A_PREFIX "Q0E",
-        .brightness_down = M1A_PREFIX "Q0F",
-        .brightness_status = "\\BRIT",
-        .display_set = "SDSP",
-        .display_get = "\\INFB"},
-
-       {
-        .name = "M2E",
-        .mt_mled = "MLED",
-        .mt_wled = "WLED",
-        .mt_lcd_switch = "\\Q10",
-        .lcd_status = "\\GP06",
-        .brightness_set = "SPLV",
-        .brightness_get = "GPLV",
-        .display_set = "SDSP",
-        .display_get = "\\INFB"},
-
-       {
-        .name = "M6N",
-        .mt_mled = "MLED",
-        .mt_wled = "WLED",
-        .wled_status = "\\_SB.PCI0.SBRG.SG13",
-        .mt_lcd_switch = xxN_PREFIX "_Q10",
-        .lcd_status = "\\_SB.BKLT",
-        .brightness_set = "SPLV",
-        .brightness_get = "GPLV",
-        .display_set = "SDSP",
-        .display_get = "\\SSTE"},
-
-       {
-        .name = "M6R",
-        .mt_mled = "MLED",
-        .mt_wled = "WLED",
-        .mt_lcd_switch = xxN_PREFIX "_Q10",
-        .lcd_status = "\\_SB.PCI0.SBSM.SEO4",
-        .brightness_set = "SPLV",
-        .brightness_get = "GPLV",
-        .display_set = "SDSP",
-        .display_get = "\\_SB.PCI0.P0P1.VGA.GETD"},
-
-       {
-        .name = "P30",
-        .mt_wled = "WLED",
-        .mt_lcd_switch = P30_PREFIX "_Q0E",
-        .lcd_status = "\\BKLT",
-        .brightness_up = P30_PREFIX "_Q68",
-        .brightness_down = P30_PREFIX "_Q69",
-        .brightness_get = "GPLV",
-        .display_set = "SDSP",
-        .display_get = "\\DNXT"},
-
-       {
-        .name = "S1x",
-        .mt_mled = "MLED",
-        .mled_status = "\\EMLE",
-        .mt_wled = "WLED",
-        .mt_lcd_switch = S1x_PREFIX "Q10",
-        .lcd_status = "\\PNOF",
-        .brightness_set = "SPLV",
-        .brightness_get = "GPLV"},
-
-       {
-        .name = "S2x",
-        .mt_mled = "MLED",
-        .mled_status = "\\MAIL",
-        .mt_lcd_switch = S2x_PREFIX "_Q10",
-        .lcd_status = "\\BKLI",
-        .brightness_up = S2x_PREFIX "_Q0B",
-        .brightness_down = S2x_PREFIX "_Q0A"},
-
-       {
-        .name = "W1N",
-        .mt_mled = "MLED",
-        .mt_wled = "WLED",
-        .mt_ledd = "SLCM",
-        .mt_lcd_switch = xxN_PREFIX "_Q10",
-        .lcd_status = "\\BKLT",
-        .brightness_set = "SPLV",
-        .brightness_get = "GPLV",
-        .display_set = "SDSP",
-        .display_get = "\\ADVG"},
-
-       {
-        .name = "W5A",
-        .mt_bt_switch = "BLED",
-        .mt_wled = "WLED",
-        .mt_lcd_switch = xxN_PREFIX "_Q10",
-        .brightness_set = "SPLV",
-        .brightness_get = "GPLV",
-        .display_set = "SDSP",
-        .display_get = "\\ADVG"},
-
-       {
-        .name = "W3V",
-        .mt_mled = "MLED",
-        .mt_wled = "WLED",
-        .mt_lcd_switch = xxN_PREFIX "_Q10",
-        .lcd_status = "\\BKLT",
-        .brightness_set = "SPLV",
-        .brightness_get = "GPLV",
-        .display_set = "SDSP",
-        .display_get = "\\INFB"},
-
-       {
-        .name = "xxN",
-        .mt_mled = "MLED",
-/* WLED present, but not controlled by ACPI */
-        .mt_lcd_switch = xxN_PREFIX "_Q10",
-        .lcd_status = "\\BKLT",
-        .brightness_set = "SPLV",
-        .brightness_get = "GPLV",
-        .display_set = "SDSP",
-       .display_get = "\\ADVG"},
-
-       {
-               .name              = "A4S",
-               .brightness_set    = "SPLV",
-               .brightness_get    = "GPLV",
-               .mt_bt_switch      = "BLED",
-               .mt_wled           = "WLED"
-       },
-
-       {
-               .name           = "F3Sa",
-               .mt_bt_switch   = "BLED",
-               .mt_wled        = "WLED",
-               .mt_mled        = "MLED",
-               .brightness_get = "GPLV",
-               .brightness_set = "SPLV",
-               .mt_lcd_switch  = "\\_SB.PCI0.SBRG.EC0._Q10",
-               .lcd_status     = "\\_SB.PCI0.SBRG.EC0.RPIN",
-               .display_get    = "\\ADVG",
-               .display_set    = "SDSP",
-       },
-
-};
-
-/* procdir we use */
-static struct proc_dir_entry *asus_proc_dir;
-
-static struct backlight_device *asus_backlight_device;
-
-/*
- * This header is made available to allow proper configuration given model,
- * revision number , ... this info cannot go in struct asus_hotk because it is
- * available before the hotk
- */
-static struct acpi_table_header *asus_info;
-
-/* The actual device the driver binds to */
-static struct asus_hotk *hotk;
-
-/*
- * The hotkey driver and autoloading declaration
- */
-static int asus_hotk_add(struct acpi_device *device);
-static int asus_hotk_remove(struct acpi_device *device, int type);
-static const struct acpi_device_id asus_device_ids[] = {
-       {"ATK0100", 0},
-       {"", 0},
-};
-MODULE_DEVICE_TABLE(acpi, asus_device_ids);
-
-static struct acpi_driver asus_hotk_driver = {
-       .name = "asus_acpi",
-       .class = ACPI_HOTK_CLASS,
-       .ids = asus_device_ids,
-       .ops = {
-               .add = asus_hotk_add,
-               .remove = asus_hotk_remove,
-               },
-};
-
-/*
- * This function evaluates an ACPI method, given an int as parameter, the
- * method is searched within the scope of the handle, can be NULL. The output
- * of the method is written is output, which can also be NULL
- *
- * returns 1 if write is successful, 0 else.
- */
-static int write_acpi_int(acpi_handle handle, const char *method, int val,
-                         struct acpi_buffer *output)
-{
-       struct acpi_object_list params; /* list of input parameters (int) */
-       union acpi_object in_obj;       /* the only param we use */
-       acpi_status status;
-
-       params.count = 1;
-       params.pointer = &in_obj;
-       in_obj.type = ACPI_TYPE_INTEGER;
-       in_obj.integer.value = val;
-
-       status = acpi_evaluate_object(handle, (char *)method, &params, output);
-       return (status == AE_OK);
-}
-
-static int read_acpi_int(acpi_handle handle, const char *method, int *val)
-{
-       struct acpi_buffer output;
-       union acpi_object out_obj;
-       acpi_status status;
-
-       output.length = sizeof(out_obj);
-       output.pointer = &out_obj;
-
-       status = acpi_evaluate_object(handle, (char *)method, NULL, &output);
-       *val = out_obj.integer.value;
-       return (status == AE_OK) && (out_obj.type == ACPI_TYPE_INTEGER);
-}
-
-/*
- * We write our info in page, we begin at offset off and cannot write more
- * than count bytes. We set eof to 1 if we handle those 2 values. We return the
- * number of bytes written in page
- */
-static int
-proc_read_info(char *page, char **start, off_t off, int count, int *eof,
-              void *data)
-{
-       int len = 0;
-       int temp;
-       char buf[16];           /* enough for all info */
-       /*
-        * We use the easy way, we don't care of off and count,
-        * so we don't set eof to 1
-        */
-
-       len += sprintf(page, ACPI_HOTK_NAME " " ASUS_ACPI_VERSION "\n");
-       len += sprintf(page + len, "Model reference    : %s\n",
-                      hotk->methods->name);
-       /*
-        * The SFUN method probably allows the original driver to get the list
-        * of features supported by a given model. For now, 0x0100 or 0x0800
-        * bit signifies that the laptop is equipped with a Wi-Fi MiniPCI card.
-        * The significance of others is yet to be found.
-        */
-       if (read_acpi_int(hotk->handle, "SFUN", &temp))
-               len +=
-                   sprintf(page + len, "SFUN value         : 0x%04x\n", temp);
-       /*
-        * Another value for userspace: the ASYM method returns 0x02 for
-        * battery low and 0x04 for battery critical, its readings tend to be
-        * more accurate than those provided by _BST.
-        * Note: since not all the laptops provide this method, errors are
-        * silently ignored.
-        */
-       if (read_acpi_int(hotk->handle, "ASYM", &temp))
-               len +=
-                   sprintf(page + len, "ASYM value         : 0x%04x\n", temp);
-       if (asus_info) {
-               snprintf(buf, 16, "%d", asus_info->length);
-               len += sprintf(page + len, "DSDT length        : %s\n", buf);
-               snprintf(buf, 16, "%d", asus_info->checksum);
-               len += sprintf(page + len, "DSDT checksum      : %s\n", buf);
-               snprintf(buf, 16, "%d", asus_info->revision);
-               len += sprintf(page + len, "DSDT revision      : %s\n", buf);
-               snprintf(buf, 7, "%s", asus_info->oem_id);
-               len += sprintf(page + len, "OEM id             : %s\n", buf);
-               snprintf(buf, 9, "%s", asus_info->oem_table_id);
-               len += sprintf(page + len, "OEM table id       : %s\n", buf);
-               snprintf(buf, 16, "%x", asus_info->oem_revision);
-               len += sprintf(page + len, "OEM revision       : 0x%s\n", buf);
-               snprintf(buf, 5, "%s", asus_info->asl_compiler_id);
-               len += sprintf(page + len, "ASL comp vendor id : %s\n", buf);
-               snprintf(buf, 16, "%x", asus_info->asl_compiler_revision);
-               len += sprintf(page + len, "ASL comp revision  : 0x%s\n", buf);
-       }
-
-       return len;
-}
-
-/*
- * /proc handlers
- * We write our info in page, we begin at offset off and cannot write more
- * than count bytes. We set eof to 1 if we handle those 2 values. We return the
- * number of bytes written in page
- */
-
-/* Generic LED functions */
-static int read_led(const char *ledname, int ledmask)
-{
-       if (ledname) {
-               int led_status;
-
-               if (read_acpi_int(NULL, ledname, &led_status))
-                       return led_status;
-               else
-                       printk(KERN_WARNING "Asus ACPI: Error reading LED "
-                              "status\n");
-       }
-       return (hotk->status & ledmask) ? 1 : 0;
-}
-
-static int parse_arg(const char __user *buf, unsigned long count, int *val)
-{
-       char s[32];
-       if (!count)
-               return 0;
-       if (count > 31)
-               return -EINVAL;
-       if (copy_from_user(s, buf, count))
-               return -EFAULT;
-       s[count] = 0;
-       if (sscanf(s, "%i", val) != 1)
-               return -EINVAL;
-       return count;
-}
-
-/* FIXME: kill extraneous args so it can be called independently */
-static int
-write_led(const char __user *buffer, unsigned long count,
-         char *ledname, int ledmask, int invert)
-{
-       int rv, value;
-       int led_out = 0;
-
-       rv = parse_arg(buffer, count, &value);
-       if (rv > 0)
-               led_out = value ? 1 : 0;
-
-       hotk->status =
-           (led_out) ? (hotk->status | ledmask) : (hotk->status & ~ledmask);
-
-       if (invert)             /* invert target value */
-               led_out = !led_out;
-
-       if (!write_acpi_int(hotk->handle, ledname, led_out, NULL))
-               printk(KERN_WARNING "Asus ACPI: LED (%s) write failed\n",
-                      ledname);
-
-       return rv;
-}
-
-/*
- * Proc handlers for MLED
- */
-static int
-proc_read_mled(char *page, char **start, off_t off, int count, int *eof,
-              void *data)
-{
-       return sprintf(page, "%d\n",
-                      read_led(hotk->methods->mled_status, MLED_ON));
-}
-
-static int
-proc_write_mled(struct file *file, const char __user *buffer,
-               unsigned long count, void *data)
-{
-       return write_led(buffer, count, hotk->methods->mt_mled, MLED_ON, 1);
-}
-
-/*
- * Proc handlers for LED display
- */
-static int
-proc_read_ledd(char *page, char **start, off_t off, int count, int *eof,
-              void *data)
-{
-       return sprintf(page, "0x%08x\n", hotk->ledd_status);
-}
-
-static int
-proc_write_ledd(struct file *file, const char __user *buffer,
-               unsigned long count, void *data)
-{
-       int rv, value;
-
-       rv = parse_arg(buffer, count, &value);
-       if (rv > 0) {
-               if (!write_acpi_int
-                   (hotk->handle, hotk->methods->mt_ledd, value, NULL))
-                       printk(KERN_WARNING
-                              "Asus ACPI: LED display write failed\n");
-               else
-                       hotk->ledd_status = (u32) value;
-       }
-       return rv;
-}
-
-/*
- * Proc handlers for WLED
- */
-static int
-proc_read_wled(char *page, char **start, off_t off, int count, int *eof,
-              void *data)
-{
-       return sprintf(page, "%d\n",
-                      read_led(hotk->methods->wled_status, WLED_ON));
-}
-
-static int
-proc_write_wled(struct file *file, const char __user *buffer,
-               unsigned long count, void *data)
-{
-       return write_led(buffer, count, hotk->methods->mt_wled, WLED_ON, 0);
-}
-
-/*
- * Proc handlers for Bluetooth
- */
-static int
-proc_read_bluetooth(char *page, char **start, off_t off, int count, int *eof,
-                   void *data)
-{
-       return sprintf(page, "%d\n", read_led(hotk->methods->bt_status, BT_ON));
-}
-
-static int
-proc_write_bluetooth(struct file *file, const char __user *buffer,
-                    unsigned long count, void *data)
-{
-       /* Note: mt_bt_switch controls both internal Bluetooth adapter's
-          presence and its LED */
-       return write_led(buffer, count, hotk->methods->mt_bt_switch, BT_ON, 0);
-}
-
-/*
- * Proc handlers for TLED
- */
-static int
-proc_read_tled(char *page, char **start, off_t off, int count, int *eof,
-              void *data)
-{
-       return sprintf(page, "%d\n",
-                      read_led(hotk->methods->tled_status, TLED_ON));
-}
-
-static int
-proc_write_tled(struct file *file, const char __user *buffer,
-               unsigned long count, void *data)
-{
-       return write_led(buffer, count, hotk->methods->mt_tled, TLED_ON, 0);
-}
-
-static int get_lcd_state(void)
-{
-       int lcd = 0;
-
-       if (hotk->model == L3H) {
-               /* L3H and the like have to be handled differently */
-               acpi_status status = 0;
-               struct acpi_object_list input;
-               union acpi_object mt_params[2];
-               struct acpi_buffer output;
-               union acpi_object out_obj;
-
-               input.count = 2;
-               input.pointer = mt_params;
-               /* Note: the following values are partly guessed up, but
-                  otherwise they seem to work */
-               mt_params[0].type = ACPI_TYPE_INTEGER;
-               mt_params[0].integer.value = 0x02;
-               mt_params[1].type = ACPI_TYPE_INTEGER;
-               mt_params[1].integer.value = 0x02;
-
-               output.length = sizeof(out_obj);
-               output.pointer = &out_obj;
-
-               status =
-                   acpi_evaluate_object(NULL, hotk->methods->lcd_status,
-                                        &input, &output);
-               if (status != AE_OK)
-                       return -1;
-               if (out_obj.type == ACPI_TYPE_INTEGER)
-                       /* That's what the AML code does */
-                       lcd = out_obj.integer.value >> 8;
-       } else if (hotk->model == F3Sa) {
-               unsigned long long tmp;
-               union acpi_object param;
-               struct acpi_object_list input;
-               acpi_status status;
-
-               /* Read pin 11 */
-               param.type = ACPI_TYPE_INTEGER;
-               param.integer.value = 0x11;
-               input.count = 1;
-               input.pointer = &param;
-
-               status = acpi_evaluate_integer(NULL, hotk->methods->lcd_status,
-                                               &input, &tmp);
-               if (status != AE_OK)
-                       return -1;
-
-               lcd = tmp;
-       } else {
-               /* We don't have to check anything if we are here */
-               if (!read_acpi_int(NULL, hotk->methods->lcd_status, &lcd))
-                       printk(KERN_WARNING
-                              "Asus ACPI: Error reading LCD status\n");
-
-               if (hotk->model == L2D)
-                       lcd = ~lcd;
-       }
-
-       return (lcd & 1);
-}
-
-static int set_lcd_state(int value)
-{
-       int lcd = 0;
-       acpi_status status = 0;
-
-       lcd = value ? 1 : 0;
-       if (lcd != get_lcd_state()) {
-               /* switch */
-               if (hotk->model != L3H) {
-                       status =
-                           acpi_evaluate_object(NULL,
-                                                hotk->methods->mt_lcd_switch,
-                                                NULL, NULL);
-               } else {
-                       /* L3H and the like must be handled differently */
-                       if (!write_acpi_int
-                           (hotk->handle, hotk->methods->mt_lcd_switch, 0x07,
-                            NULL))
-                               status = AE_ERROR;
-                       /* L3H's AML executes EHK (0x07) upon Fn+F7 keypress,
-                          the exact behaviour is simulated here */
-               }
-               if (ACPI_FAILURE(status))
-                       printk(KERN_WARNING "Asus ACPI: Error switching LCD\n");
-       }
-       return 0;
-
-}
-
-static int
-proc_read_lcd(char *page, char **start, off_t off, int count, int *eof,
-             void *data)
-{
-       return sprintf(page, "%d\n", get_lcd_state());
-}
-
-static int
-proc_write_lcd(struct file *file, const char __user *buffer,
-              unsigned long count, void *data)
-{
-       int rv, value;
-
-       rv = parse_arg(buffer, count, &value);
-       if (rv > 0)
-               set_lcd_state(value);
-       return rv;
-}
-
-static int read_brightness(struct backlight_device *bd)
-{
-       int value;
-
-       if (hotk->methods->brightness_get) {    /* SPLV/GPLV laptop */
-               if (!read_acpi_int(hotk->handle, hotk->methods->brightness_get,
-                                  &value))
-                       printk(KERN_WARNING
-                              "Asus ACPI: Error reading brightness\n");
-       } else if (hotk->methods->brightness_status) {  /* For D1 for example */
-               if (!read_acpi_int(NULL, hotk->methods->brightness_status,
-                                  &value))
-                       printk(KERN_WARNING
-                              "Asus ACPI: Error reading brightness\n");
-       } else                  /* No GPLV method */
-               value = hotk->brightness;
-       return value;
-}
-
-/*
- * Change the brightness level
- */
-static int set_brightness(int value)
-{
-       acpi_status status = 0;
-       int ret = 0;
-
-       /* SPLV laptop */
-       if (hotk->methods->brightness_set) {
-               if (!write_acpi_int(hotk->handle, hotk->methods->brightness_set,
-                                   value, NULL))
-                       printk(KERN_WARNING
-                              "Asus ACPI: Error changing brightness\n");
-                       ret = -EIO;
-               goto out;
-       }
-
-       /* No SPLV method if we are here, act as appropriate */
-       value -= read_brightness(NULL);
-       while (value != 0) {
-               status = acpi_evaluate_object(NULL, (value > 0) ?
-                                             hotk->methods->brightness_up :
-                                             hotk->methods->brightness_down,
-                                             NULL, NULL);
-               (value > 0) ? value-- : value++;
-               if (ACPI_FAILURE(status))
-                       printk(KERN_WARNING
-                              "Asus ACPI: Error changing brightness\n");
-                       ret = -EIO;
-       }
-out:
-       return ret;
-}
-
-static int set_brightness_status(struct backlight_device *bd)
-{
-       return set_brightness(bd->props.brightness);
-}
-
-static int
-proc_read_brn(char *page, char **start, off_t off, int count, int *eof,
-             void *data)
-{
-       return sprintf(page, "%d\n", read_brightness(NULL));
-}
-
-static int
-proc_write_brn(struct file *file, const char __user *buffer,
-              unsigned long count, void *data)
-{
-       int rv, value;
-
-       rv = parse_arg(buffer, count, &value);
-       if (rv > 0) {
-               value = (0 < value) ? ((15 < value) ? 15 : value) : 0;
-               /* 0 <= value <= 15 */
-               set_brightness(value);
-       }
-       return rv;
-}
-
-static void set_display(int value)
-{
-       /* no sanity check needed for now */
-       if (!write_acpi_int(hotk->handle, hotk->methods->display_set,
-                           value, NULL))
-               printk(KERN_WARNING "Asus ACPI: Error setting display\n");
-       return;
-}
-
-/*
- * Now, *this* one could be more user-friendly, but so far, no-one has
- * complained. The significance of bits is the same as in proc_write_disp()
- */
-static int
-proc_read_disp(char *page, char **start, off_t off, int count, int *eof,
-              void *data)
-{
-       int value = 0;
-
-       if (!read_acpi_int(hotk->handle, hotk->methods->display_get, &value))
-               printk(KERN_WARNING
-                      "Asus ACPI: Error reading display status\n");
-       value &= 0x07;  /* needed for some models, shouldn't hurt others */
-       return sprintf(page, "%d\n", value);
-}
-
-/*
- * Experimental support for display switching. As of now: 1 should activate
- * the LCD output, 2 should do for CRT, and 4 for TV-Out. Any combination
- * (bitwise) of these will suffice. I never actually tested 3 displays hooked
- * up simultaneously, so be warned. See the acpi4asus README for more info.
- */
-static int
-proc_write_disp(struct file *file, const char __user *buffer,
-               unsigned long count, void *data)
-{
-       int rv, value;
-
-       rv = parse_arg(buffer, count, &value);
-       if (rv > 0)
-               set_display(value);
-       return rv;
-}
-
-typedef int (proc_readfunc) (char *page, char **start, off_t off, int count,
-                            int *eof, void *data);
-typedef int (proc_writefunc) (struct file *file, const char __user *buffer,
-                             unsigned long count, void *data);
-
-static int
-asus_proc_add(char *name, proc_writefunc *writefunc,
-                    proc_readfunc *readfunc, mode_t mode,
-                    struct acpi_device *device)
-{
-       struct proc_dir_entry *proc =
-           create_proc_entry(name, mode, acpi_device_dir(device));
-       if (!proc) {
-               printk(KERN_WARNING "  Unable to create %s fs entry\n", name);
-               return -1;
-       }
-       proc->write_proc = writefunc;
-       proc->read_proc = readfunc;
-       proc->data = acpi_driver_data(device);
-       proc->owner = THIS_MODULE;
-       proc->uid = asus_uid;
-       proc->gid = asus_gid;
-       return 0;
-}
-
-static int asus_hotk_add_fs(struct acpi_device *device)
-{
-       struct proc_dir_entry *proc;
-       mode_t mode;
-
-       /*
-        * If parameter uid or gid is not changed, keep the default setting for
-        * our proc entries (-rw-rw-rw-) else, it means we care about security,
-        * and then set to -rw-rw----
-        */
-
-       if ((asus_uid == 0) && (asus_gid == 0)) {
-               mode = S_IFREG | S_IRUGO | S_IWUGO;
-       } else {
-               mode = S_IFREG | S_IRUSR | S_IRGRP | S_IWUSR | S_IWGRP;
-               printk(KERN_WARNING "  asus_uid and asus_gid parameters are "
-                      "deprecated, use chown and chmod instead!\n");
-       }
-
-       acpi_device_dir(device) = asus_proc_dir;
-       if (!acpi_device_dir(device))
-               return -ENODEV;
-
-       proc = create_proc_entry(PROC_INFO, mode, acpi_device_dir(device));
-       if (proc) {
-               proc->read_proc = proc_read_info;
-               proc->data = acpi_driver_data(device);
-               proc->owner = THIS_MODULE;
-               proc->uid = asus_uid;
-               proc->gid = asus_gid;
-       } else {
-               printk(KERN_WARNING "  Unable to create " PROC_INFO
-                      " fs entry\n");
-       }
-
-       if (hotk->methods->mt_wled) {
-               asus_proc_add(PROC_WLED, &proc_write_wled, &proc_read_wled,
-                             mode, device);
-       }
-
-       if (hotk->methods->mt_ledd) {
-               asus_proc_add(PROC_LEDD, &proc_write_ledd, &proc_read_ledd,
-                             mode, device);
-       }
-
-       if (hotk->methods->mt_mled) {
-               asus_proc_add(PROC_MLED, &proc_write_mled, &proc_read_mled,
-                             mode, device);
-       }
-
-       if (hotk->methods->mt_tled) {
-               asus_proc_add(PROC_TLED, &proc_write_tled, &proc_read_tled,
-                             mode, device);
-       }
-
-       if (hotk->methods->mt_bt_switch) {
-               asus_proc_add(PROC_BT, &proc_write_bluetooth,
-                             &proc_read_bluetooth, mode, device);
-       }
-
-       /*
-        * We need both read node and write method as LCD switch is also
-        * accessible from the keyboard
-        */
-       if (hotk->methods->mt_lcd_switch && hotk->methods->lcd_status) {
-               asus_proc_add(PROC_LCD, &proc_write_lcd, &proc_read_lcd, mode,
-                             device);
-       }
-
-       if ((hotk->methods->brightness_up && hotk->methods->brightness_down) ||
-           (hotk->methods->brightness_get && hotk->methods->brightness_set)) {
-               asus_proc_add(PROC_BRN, &proc_write_brn, &proc_read_brn, mode,
-                             device);
-       }
-
-       if (hotk->methods->display_set) {
-               asus_proc_add(PROC_DISP, &proc_write_disp, &proc_read_disp,
-                             mode, device);
-       }
-
-       return 0;
-}
-
-static int asus_hotk_remove_fs(struct acpi_device *device)
-{
-       if (acpi_device_dir(device)) {
-               remove_proc_entry(PROC_INFO, acpi_device_dir(device));
-               if (hotk->methods->mt_wled)
-                       remove_proc_entry(PROC_WLED, acpi_device_dir(device));
-               if (hotk->methods->mt_mled)
-                       remove_proc_entry(PROC_MLED, acpi_device_dir(device));
-               if (hotk->methods->mt_tled)
-                       remove_proc_entry(PROC_TLED, acpi_device_dir(device));
-               if (hotk->methods->mt_ledd)
-                       remove_proc_entry(PROC_LEDD, acpi_device_dir(device));
-               if (hotk->methods->mt_bt_switch)
-                       remove_proc_entry(PROC_BT, acpi_device_dir(device));
-               if (hotk->methods->mt_lcd_switch && hotk->methods->lcd_status)
-                       remove_proc_entry(PROC_LCD, acpi_device_dir(device));
-               if ((hotk->methods->brightness_up
-                    && hotk->methods->brightness_down)
-                   || (hotk->methods->brightness_get
-                       && hotk->methods->brightness_set))
-                       remove_proc_entry(PROC_BRN, acpi_device_dir(device));
-               if (hotk->methods->display_set)
-                       remove_proc_entry(PROC_DISP, acpi_device_dir(device));
-       }
-       return 0;
-}
-
-static void asus_hotk_notify(acpi_handle handle, u32 event, void *data)
-{
-       /* TODO Find a better way to handle events count. */
-       if (!hotk)
-               return;
-
-       if ((event & ~((u32) BR_UP)) < 16)
-               hotk->brightness = (event & ~((u32) BR_UP));
-       else if ((event & ~((u32) BR_DOWN)) < 16)
-               hotk->brightness = (event & ~((u32) BR_DOWN));
-
-       acpi_bus_generate_proc_event(hotk->device, event,
-                               hotk->event_count[event % 128]++);
-
-       return;
-}
-
-/*
- * Match the model string to the list of supported models. Return END_MODEL if
- * no match or model is NULL.
- */
-static int asus_model_match(char *model)
-{
-       if (model == NULL)
-               return END_MODEL;
-
-       if (strncmp(model, "L3D", 3) == 0)
-               return L3D;
-       else if (strncmp(model, "L2E", 3) == 0 ||
-                strncmp(model, "L3H", 3) == 0 || strncmp(model, "L5D", 3) == 0)
-               return L3H;
-       else if (strncmp(model, "L3", 2) == 0 || strncmp(model, "L2B", 3) == 0)
-               return L3C;
-       else if (strncmp(model, "L8L", 3) == 0)
-               return L8L;
-       else if (strncmp(model, "L4R", 3) == 0)
-               return L4R;
-       else if (strncmp(model, "M6N", 3) == 0 || strncmp(model, "W3N", 3) == 0)
-               return M6N;
-       else if (strncmp(model, "M6R", 3) == 0 || strncmp(model, "A3G", 3) == 0)
-               return M6R;
-       else if (strncmp(model, "M2N", 3) == 0 ||
-                strncmp(model, "M3N", 3) == 0 ||
-                strncmp(model, "M5N", 3) == 0 ||
-                strncmp(model, "M6N", 3) == 0 ||
-                strncmp(model, "S1N", 3) == 0 ||
-                strncmp(model, "S5N", 3) == 0 || strncmp(model, "W1N", 3) == 0)
-               return xxN;
-       else if (strncmp(model, "M1", 2) == 0)
-               return M1A;
-       else if (strncmp(model, "M2", 2) == 0 || strncmp(model, "L4E", 3) == 0)
-               return M2E;
-       else if (strncmp(model, "L2", 2) == 0)
-               return L2D;
-       else if (strncmp(model, "L8", 2) == 0)
-               return S1x;
-       else if (strncmp(model, "D1", 2) == 0)
-               return D1x;
-       else if (strncmp(model, "A1", 2) == 0)
-               return A1x;
-       else if (strncmp(model, "A2", 2) == 0)
-               return A2x;
-       else if (strncmp(model, "J1", 2) == 0)
-               return S2x;
-       else if (strncmp(model, "L5", 2) == 0)
-               return L5x;
-       else if (strncmp(model, "A4G", 3) == 0)
-               return A4G;
-       else if (strncmp(model, "W1N", 3) == 0)
-               return W1N;
-       else if (strncmp(model, "W3V", 3) == 0)
-               return W3V;
-       else if (strncmp(model, "W5A", 3) == 0)
-               return W5A;
-       else if (strncmp(model, "A4S", 3) == 0)
-               return A4S;
-       else if (strncmp(model, "F3Sa", 4) == 0)
-               return F3Sa;
-       else
-               return END_MODEL;
-}
-
-/*
- * This function is used to initialize the hotk with right values. In this
- * method, we can make all the detection we want, and modify the hotk struct
- */
-static int asus_hotk_get_info(void)
-{
-       struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
-       union acpi_object *model = NULL;
-       int bsts_result;
-       char *string = NULL;
-       acpi_status status;
-
-       /*
-        * Get DSDT headers early enough to allow for differentiating between
-        * models, but late enough to allow acpi_bus_register_driver() to fail
-        * before doing anything ACPI-specific. Should we encounter a machine,
-        * which needs special handling (i.e. its hotkey device has a different
-        * HID), this bit will be moved. A global variable asus_info contains
-        * the DSDT header.
-        */
-       status = acpi_get_table(ACPI_SIG_DSDT, 1, &asus_info);
-       if (ACPI_FAILURE(status))
-               printk(KERN_WARNING "  Couldn't get the DSDT table header\n");
-
-       /* We have to write 0 on init this far for all ASUS models */
-       if (!write_acpi_int(hotk->handle, "INIT", 0, &buffer)) {
-               printk(KERN_ERR "  Hotkey initialization failed\n");
-               return -ENODEV;
-       }
-
-       /* This needs to be called for some laptops to init properly */
-       if (!read_acpi_int(hotk->handle, "BSTS", &bsts_result))
-               printk(KERN_WARNING "  Error calling BSTS\n");
-       else if (bsts_result)
-               printk(KERN_NOTICE "  BSTS called, 0x%02x returned\n",
-                      bsts_result);
-
-       /*
-        * Try to match the object returned by INIT to the specific model.
-        * Handle every possible object (or the lack of thereof) the DSDT
-        * writers might throw at us. When in trouble, we pass NULL to
-        * asus_model_match() and try something completely different.
-        */
-       if (buffer.pointer) {
-               model = buffer.pointer;
-               switch (model->type) {
-               case ACPI_TYPE_STRING:
-                       string = model->string.pointer;
-                       break;
-               case ACPI_TYPE_BUFFER:
-                       string = model->buffer.pointer;
-                       break;
-               default:
-                       kfree(model);
-                       model = NULL;
-                       break;
-               }
-       }
-       hotk->model = asus_model_match(string);
-       if (hotk->model == END_MODEL) { /* match failed */
-               if (asus_info &&
-                   strncmp(asus_info->oem_table_id, "ODEM", 4) == 0) {
-                       hotk->model = P30;
-                       printk(KERN_NOTICE
-                              "  Samsung P30 detected, supported\n");
-               } else {
-                       hotk->model = M2E;
-                       printk(KERN_NOTICE "  unsupported model %s, trying "
-                              "default values\n", string);
-                       printk(KERN_NOTICE
-                              "  send /proc/acpi/dsdt to the developers\n");
-                       kfree(model);
-                       return -ENODEV;
-               }
-               hotk->methods = &model_conf[hotk->model];
-               return AE_OK;
-       }
-       hotk->methods = &model_conf[hotk->model];
-       printk(KERN_NOTICE "  %s model detected, supported\n", string);
-
-       /* Sort of per-model blacklist */
-       if (strncmp(string, "L2B", 3) == 0)
-               hotk->methods->lcd_status = NULL;
-       /* L2B is similar enough to L3C to use its settings, with this only
-          exception */
-       else if (strncmp(string, "A3G", 3) == 0)
-               hotk->methods->lcd_status = "\\BLFG";
-       /* A3G is like M6R */
-       else if (strncmp(string, "S5N", 3) == 0 ||
-                strncmp(string, "M5N", 3) == 0 ||
-                strncmp(string, "W3N", 3) == 0)
-               hotk->methods->mt_mled = NULL;
-       /* S5N, M5N and W3N have no MLED */
-       else if (strncmp(string, "L5D", 3) == 0)
-               hotk->methods->mt_wled = NULL;
-       /* L5D's WLED is not controlled by ACPI */
-       else if (strncmp(string, "M2N", 3) == 0 ||
-                strncmp(string, "W3V", 3) == 0 ||
-                strncmp(string, "S1N", 3) == 0)
-               hotk->methods->mt_wled = "WLED";
-       /* M2N, S1N and W3V have a usable WLED */
-       else if (asus_info) {
-               if (strncmp(asus_info->oem_table_id, "L1", 2) == 0)
-                       hotk->methods->mled_status = NULL;
-               /* S1300A reports L84F, but L1400B too, account for that */
-       }
-
-       kfree(model);
-
-       return AE_OK;
-}
-
-static int asus_hotk_check(void)
-{
-       int result = 0;
-
-       result = acpi_bus_get_status(hotk->device);
-       if (result)
-               return result;
-
-       if (hotk->device->status.present) {
-               result = asus_hotk_get_info();
-       } else {
-               printk(KERN_ERR "  Hotkey device not present, aborting\n");
-               return -EINVAL;
-       }
-
-       return result;
-}
-
-static int asus_hotk_found;
-
-static int asus_hotk_add(struct acpi_device *device)
-{
-       acpi_status status = AE_OK;
-       int result;
-
-       if (!device)
-               return -EINVAL;
-
-       printk(KERN_NOTICE "Asus Laptop ACPI Extras version %s\n",
-              ASUS_ACPI_VERSION);
-
-       hotk = kzalloc(sizeof(struct asus_hotk), GFP_KERNEL);
-       if (!hotk)
-               return -ENOMEM;
-
-       hotk->handle = device->handle;
-       strcpy(acpi_device_name(device), ACPI_HOTK_DEVICE_NAME);
-       strcpy(acpi_device_class(device), ACPI_HOTK_CLASS);
-       device->driver_data = hotk;
-       hotk->device = device;
-
-       result = asus_hotk_check();
-       if (result)
-               goto end;
-
-       result = asus_hotk_add_fs(device);
-       if (result)
-               goto end;
-
-       /*
-        * We install the handler, it will receive the hotk in parameter, so, we
-        * could add other data to the hotk struct
-        */
-       status = acpi_install_notify_handler(hotk->handle, ACPI_SYSTEM_NOTIFY,
-                                            asus_hotk_notify, hotk);
-       if (ACPI_FAILURE(status))
-               printk(KERN_ERR "  Error installing notify handler\n");
-
-       /* For laptops without GPLV: init the hotk->brightness value */
-       if ((!hotk->methods->brightness_get)
-           && (!hotk->methods->brightness_status)
-           && (hotk->methods->brightness_up && hotk->methods->brightness_down)) {
-               status =
-                   acpi_evaluate_object(NULL, hotk->methods->brightness_down,
-                                        NULL, NULL);
-               if (ACPI_FAILURE(status))
-                       printk(KERN_WARNING "  Error changing brightness\n");
-               else {
-                       status =
-                           acpi_evaluate_object(NULL,
-                                                hotk->methods->brightness_up,
-                                                NULL, NULL);
-                       if (ACPI_FAILURE(status))
-                               printk(KERN_WARNING "  Strange, error changing"
-                                      " brightness\n");
-               }
-       }
-
-       asus_hotk_found = 1;
-
-       /* LED display is off by default */
-       hotk->ledd_status = 0xFFF;
-
-end:
-       if (result)
-               kfree(hotk);
-
-       return result;
-}
-
-static int asus_hotk_remove(struct acpi_device *device, int type)
-{
-       acpi_status status = 0;
-
-       if (!device || !acpi_driver_data(device))
-               return -EINVAL;
-
-       status = acpi_remove_notify_handler(hotk->handle, ACPI_SYSTEM_NOTIFY,
-                                           asus_hotk_notify);
-       if (ACPI_FAILURE(status))
-               printk(KERN_ERR "Asus ACPI: Error removing notify handler\n");
-
-       asus_hotk_remove_fs(device);
-
-       kfree(hotk);
-
-       return 0;
-}
-
-static struct backlight_ops asus_backlight_data = {
-       .get_brightness = read_brightness,
-       .update_status  = set_brightness_status,
-};
-
-static void asus_acpi_exit(void)
-{
-       if (asus_backlight_device)
-               backlight_device_unregister(asus_backlight_device);
-
-       acpi_bus_unregister_driver(&asus_hotk_driver);
-       remove_proc_entry(PROC_ASUS, acpi_root_dir);
-
-       return;
-}
-
-static int __init asus_acpi_init(void)
-{
-       int result;
-
-       if (acpi_disabled)
-               return -ENODEV;
-
-       asus_proc_dir = proc_mkdir(PROC_ASUS, acpi_root_dir);
-       if (!asus_proc_dir) {
-               printk(KERN_ERR "Asus ACPI: Unable to create /proc entry\n");
-               return -ENODEV;
-       }
-       asus_proc_dir->owner = THIS_MODULE;
-
-       result = acpi_bus_register_driver(&asus_hotk_driver);
-       if (result < 0) {
-               remove_proc_entry(PROC_ASUS, acpi_root_dir);
-               return result;
-       }
-
-       /*
-        * This is a bit of a kludge.  We only want this module loaded
-        * for ASUS systems, but there's currently no way to probe the
-        * ACPI namespace for ASUS HIDs.  So we just return failure if
-        * we didn't find one, which will cause the module to be
-        * unloaded.
-        */
-       if (!asus_hotk_found) {
-               acpi_bus_unregister_driver(&asus_hotk_driver);
-               remove_proc_entry(PROC_ASUS, acpi_root_dir);
-               return -ENODEV;
-       }
-
-       asus_backlight_device = backlight_device_register("asus", NULL, NULL,
-                                                         &asus_backlight_data);
-       if (IS_ERR(asus_backlight_device)) {
-               printk(KERN_ERR "Could not register asus backlight device\n");
-               asus_backlight_device = NULL;
-               asus_acpi_exit();
-               return -ENODEV;
-       }
-       asus_backlight_device->props.max_brightness = 15;
-
-       return 0;
-}
-
-module_init(asus_acpi_init);
-module_exit(asus_acpi_exit);
diff --git a/drivers/acpi/toshiba_acpi.c b/drivers/acpi/toshiba_acpi.c
deleted file mode 100644 (file)
index 40e60fc..0000000
+++ /dev/null
@@ -1,863 +0,0 @@
-/*
- *  toshiba_acpi.c - Toshiba Laptop ACPI Extras
- *
- *
- *  Copyright (C) 2002-2004 John Belmonte
- *  Copyright (C) 2008 Philip Langdale
- *
- *  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
- *
- *
- *  The devolpment page for this driver is located at
- *  http://memebeam.org/toys/ToshibaAcpiDriver.
- *
- *  Credits:
- *     Jonathan A. Buzzard - Toshiba HCI info, and critical tips on reverse
- *             engineering the Windows drivers
- *     Yasushi Nagato - changes for linux kernel 2.4 -> 2.5
- *     Rob Miller - TV out and hotkeys help
- *
- *
- *  TODO
- *
- */
-
-#define TOSHIBA_ACPI_VERSION   "0.19"
-#define PROC_INTERFACE_VERSION 1
-
-#include <linux/kernel.h>
-#include <linux/module.h>
-#include <linux/init.h>
-#include <linux/types.h>
-#include <linux/proc_fs.h>
-#include <linux/backlight.h>
-#include <linux/platform_device.h>
-#include <linux/rfkill.h>
-#include <linux/input-polldev.h>
-
-#include <asm/uaccess.h>
-
-#include <acpi/acpi_drivers.h>
-
-MODULE_AUTHOR("John Belmonte");
-MODULE_DESCRIPTION("Toshiba Laptop ACPI Extras Driver");
-MODULE_LICENSE("GPL");
-
-#define MY_LOGPREFIX "toshiba_acpi: "
-#define MY_ERR KERN_ERR MY_LOGPREFIX
-#define MY_NOTICE KERN_NOTICE MY_LOGPREFIX
-#define MY_INFO KERN_INFO MY_LOGPREFIX
-
-/* Toshiba ACPI method paths */
-#define METHOD_LCD_BRIGHTNESS  "\\_SB_.PCI0.VGA_.LCD_._BCM"
-#define METHOD_HCI_1           "\\_SB_.VALD.GHCI"
-#define METHOD_HCI_2           "\\_SB_.VALZ.GHCI"
-#define METHOD_VIDEO_OUT       "\\_SB_.VALX.DSSX"
-
-/* Toshiba HCI interface definitions
- *
- * HCI is Toshiba's "Hardware Control Interface" which is supposed to
- * be uniform across all their models.  Ideally we would just call
- * dedicated ACPI methods instead of using this primitive interface.
- * However the ACPI methods seem to be incomplete in some areas (for
- * example they allow setting, but not reading, the LCD brightness value),
- * so this is still useful.
- */
-
-#define HCI_WORDS                      6
-
-/* operations */
-#define HCI_SET                                0xff00
-#define HCI_GET                                0xfe00
-
-/* return codes */
-#define HCI_SUCCESS                    0x0000
-#define HCI_FAILURE                    0x1000
-#define HCI_NOT_SUPPORTED              0x8000
-#define HCI_EMPTY                      0x8c00
-
-/* registers */
-#define HCI_FAN                                0x0004
-#define HCI_SYSTEM_EVENT               0x0016
-#define HCI_VIDEO_OUT                  0x001c
-#define HCI_HOTKEY_EVENT               0x001e
-#define HCI_LCD_BRIGHTNESS             0x002a
-#define HCI_WIRELESS                   0x0056
-
-/* field definitions */
-#define HCI_LCD_BRIGHTNESS_BITS                3
-#define HCI_LCD_BRIGHTNESS_SHIFT       (16-HCI_LCD_BRIGHTNESS_BITS)
-#define HCI_LCD_BRIGHTNESS_LEVELS      (1 << HCI_LCD_BRIGHTNESS_BITS)
-#define HCI_VIDEO_OUT_LCD              0x1
-#define HCI_VIDEO_OUT_CRT              0x2
-#define HCI_VIDEO_OUT_TV               0x4
-#define HCI_WIRELESS_KILL_SWITCH       0x01
-#define HCI_WIRELESS_BT_PRESENT                0x0f
-#define HCI_WIRELESS_BT_ATTACH         0x40
-#define HCI_WIRELESS_BT_POWER          0x80
-
-static const struct acpi_device_id toshiba_device_ids[] = {
-       {"TOS6200", 0},
-       {"TOS6208", 0},
-       {"TOS1900", 0},
-       {"", 0},
-};
-MODULE_DEVICE_TABLE(acpi, toshiba_device_ids);
-
-/* utility
- */
-
-static __inline__ void _set_bit(u32 * word, u32 mask, int value)
-{
-       *word = (*word & ~mask) | (mask * value);
-}
-
-/* acpi interface wrappers
- */
-
-static int is_valid_acpi_path(const char *methodName)
-{
-       acpi_handle handle;
-       acpi_status status;
-
-       status = acpi_get_handle(NULL, (char *)methodName, &handle);
-       return !ACPI_FAILURE(status);
-}
-
-static int write_acpi_int(const char *methodName, int val)
-{
-       struct acpi_object_list params;
-       union acpi_object in_objs[1];
-       acpi_status status;
-
-       params.count = ARRAY_SIZE(in_objs);
-       params.pointer = in_objs;
-       in_objs[0].type = ACPI_TYPE_INTEGER;
-       in_objs[0].integer.value = val;
-
-       status = acpi_evaluate_object(NULL, (char *)methodName, &params, NULL);
-       return (status == AE_OK);
-}
-
-#if 0
-static int read_acpi_int(const char *methodName, int *pVal)
-{
-       struct acpi_buffer results;
-       union acpi_object out_objs[1];
-       acpi_status status;
-
-       results.length = sizeof(out_objs);
-       results.pointer = out_objs;
-
-       status = acpi_evaluate_object(0, (char *)methodName, 0, &results);
-       *pVal = out_objs[0].integer.value;
-
-       return (status == AE_OK) && (out_objs[0].type == ACPI_TYPE_INTEGER);
-}
-#endif
-
-static const char *method_hci /*= 0*/ ;
-
-/* Perform a raw HCI call.  Here we don't care about input or output buffer
- * format.
- */
-static acpi_status hci_raw(const u32 in[HCI_WORDS], u32 out[HCI_WORDS])
-{
-       struct acpi_object_list params;
-       union acpi_object in_objs[HCI_WORDS];
-       struct acpi_buffer results;
-       union acpi_object out_objs[HCI_WORDS + 1];
-       acpi_status status;
-       int i;
-
-       params.count = HCI_WORDS;
-       params.pointer = in_objs;
-       for (i = 0; i < HCI_WORDS; ++i) {
-               in_objs[i].type = ACPI_TYPE_INTEGER;
-               in_objs[i].integer.value = in[i];
-       }
-
-       results.length = sizeof(out_objs);
-       results.pointer = out_objs;
-
-       status = acpi_evaluate_object(NULL, (char *)method_hci, &params,
-                                     &results);
-       if ((status == AE_OK) && (out_objs->package.count <= HCI_WORDS)) {
-               for (i = 0; i < out_objs->package.count; ++i) {
-                       out[i] = out_objs->package.elements[i].integer.value;
-               }
-       }
-
-       return status;
-}
-
-/* common hci tasks (get or set one or two value)
- *
- * In addition to the ACPI status, the HCI system returns a result which
- * may be useful (such as "not supported").
- */
-
-static acpi_status hci_write1(u32 reg, u32 in1, u32 * result)
-{
-       u32 in[HCI_WORDS] = { HCI_SET, reg, in1, 0, 0, 0 };
-       u32 out[HCI_WORDS];
-       acpi_status status = hci_raw(in, out);
-       *result = (status == AE_OK) ? out[0] : HCI_FAILURE;
-       return status;
-}
-
-static acpi_status hci_read1(u32 reg, u32 * out1, u32 * result)
-{
-       u32 in[HCI_WORDS] = { HCI_GET, reg, 0, 0, 0, 0 };
-       u32 out[HCI_WORDS];
-       acpi_status status = hci_raw(in, out);
-       *out1 = out[2];
-       *result = (status == AE_OK) ? out[0] : HCI_FAILURE;
-       return status;
-}
-
-static acpi_status hci_write2(u32 reg, u32 in1, u32 in2, u32 *result)
-{
-       u32 in[HCI_WORDS] = { HCI_SET, reg, in1, in2, 0, 0 };
-       u32 out[HCI_WORDS];
-       acpi_status status = hci_raw(in, out);
-       *result = (status == AE_OK) ? out[0] : HCI_FAILURE;
-       return status;
-}
-
-static acpi_status hci_read2(u32 reg, u32 *out1, u32 *out2, u32 *result)
-{
-       u32 in[HCI_WORDS] = { HCI_GET, reg, *out1, *out2, 0, 0 };
-       u32 out[HCI_WORDS];
-       acpi_status status = hci_raw(in, out);
-       *out1 = out[2];
-       *out2 = out[3];
-       *result = (status == AE_OK) ? out[0] : HCI_FAILURE;
-       return status;
-}
-
-struct toshiba_acpi_dev {
-       struct platform_device *p_dev;
-       struct rfkill *rfk_dev;
-       struct input_polled_dev *poll_dev;
-
-       const char *bt_name;
-       const char *rfk_name;
-
-       bool last_rfk_state;
-
-       struct mutex mutex;
-};
-
-static struct toshiba_acpi_dev toshiba_acpi = {
-       .bt_name = "Toshiba Bluetooth",
-       .rfk_name = "Toshiba RFKill Switch",
-       .last_rfk_state = false,
-};
-
-/* Bluetooth rfkill handlers */
-
-static u32 hci_get_bt_present(bool *present)
-{
-       u32 hci_result;
-       u32 value, value2;
-
-       value = 0;
-       value2 = 0;
-       hci_read2(HCI_WIRELESS, &value, &value2, &hci_result);
-       if (hci_result == HCI_SUCCESS)
-               *present = (value & HCI_WIRELESS_BT_PRESENT) ? true : false;
-
-       return hci_result;
-}
-
-static u32 hci_get_bt_on(bool *on)
-{
-       u32 hci_result;
-       u32 value, value2;
-
-       value = 0;
-       value2 = 0x0001;
-       hci_read2(HCI_WIRELESS, &value, &value2, &hci_result);
-       if (hci_result == HCI_SUCCESS)
-               *on = (value & HCI_WIRELESS_BT_POWER) &&
-                     (value & HCI_WIRELESS_BT_ATTACH);
-
-       return hci_result;
-}
-
-static u32 hci_get_radio_state(bool *radio_state)
-{
-       u32 hci_result;
-       u32 value, value2;
-
-       value = 0;
-       value2 = 0x0001;
-       hci_read2(HCI_WIRELESS, &value, &value2, &hci_result);
-
-       *radio_state = value & HCI_WIRELESS_KILL_SWITCH;
-       return hci_result;
-}
-
-static int bt_rfkill_toggle_radio(void *data, enum rfkill_state state)
-{
-       u32 result1, result2;
-       u32 value;
-       bool radio_state;
-       struct toshiba_acpi_dev *dev = data;
-
-       value = (state == RFKILL_STATE_UNBLOCKED);
-
-       if (hci_get_radio_state(&radio_state) != HCI_SUCCESS)
-               return -EFAULT;
-
-       switch (state) {
-       case RFKILL_STATE_UNBLOCKED:
-               if (!radio_state)
-                       return -EPERM;
-               break;
-       case RFKILL_STATE_SOFT_BLOCKED:
-               break;
-       default:
-               return -EINVAL;
-       }
-
-       mutex_lock(&dev->mutex);
-       hci_write2(HCI_WIRELESS, value, HCI_WIRELESS_BT_POWER, &result1);
-       hci_write2(HCI_WIRELESS, value, HCI_WIRELESS_BT_ATTACH, &result2);
-       mutex_unlock(&dev->mutex);
-
-       if (result1 != HCI_SUCCESS || result2 != HCI_SUCCESS)
-               return -EFAULT;
-
-       return 0;
-}
-
-static void bt_poll_rfkill(struct input_polled_dev *poll_dev)
-{
-       bool state_changed;
-       bool new_rfk_state;
-       bool value;
-       u32 hci_result;
-       struct toshiba_acpi_dev *dev = poll_dev->private;
-
-       hci_result = hci_get_radio_state(&value);
-       if (hci_result != HCI_SUCCESS)
-               return; /* Can't do anything useful */
-
-       new_rfk_state = value;
-
-       mutex_lock(&dev->mutex);
-       state_changed = new_rfk_state != dev->last_rfk_state;
-       dev->last_rfk_state = new_rfk_state;
-       mutex_unlock(&dev->mutex);
-
-       if (unlikely(state_changed)) {
-               rfkill_force_state(dev->rfk_dev,
-                                  new_rfk_state ?
-                                  RFKILL_STATE_SOFT_BLOCKED :
-                                  RFKILL_STATE_HARD_BLOCKED);
-               input_report_switch(poll_dev->input, SW_RFKILL_ALL,
-                                   new_rfk_state);
-               input_sync(poll_dev->input);
-       }
-}
-
-static struct proc_dir_entry *toshiba_proc_dir /*= 0*/ ;
-static struct backlight_device *toshiba_backlight_device;
-static int force_fan;
-static int last_key_event;
-static int key_event_valid;
-
-typedef struct _ProcItem {
-       const char *name;
-       char *(*read_func) (char *);
-       unsigned long (*write_func) (const char *, unsigned long);
-} ProcItem;
-
-/* proc file handlers
- */
-
-static int
-dispatch_read(char *page, char **start, off_t off, int count, int *eof,
-             ProcItem * item)
-{
-       char *p = page;
-       int len;
-
-       if (off == 0)
-               p = item->read_func(p);
-
-       /* ISSUE: I don't understand this code */
-       len = (p - page);
-       if (len <= off + count)
-               *eof = 1;
-       *start = page + off;
-       len -= off;
-       if (len > count)
-               len = count;
-       if (len < 0)
-               len = 0;
-       return len;
-}
-
-static int
-dispatch_write(struct file *file, const char __user * buffer,
-              unsigned long count, ProcItem * item)
-{
-       int result;
-       char *tmp_buffer;
-
-       /* Arg buffer points to userspace memory, which can't be accessed
-        * directly.  Since we're making a copy, zero-terminate the
-        * destination so that sscanf can be used on it safely.
-        */
-       tmp_buffer = kmalloc(count + 1, GFP_KERNEL);
-       if (!tmp_buffer)
-               return -ENOMEM;
-
-       if (copy_from_user(tmp_buffer, buffer, count)) {
-               result = -EFAULT;
-       } else {
-               tmp_buffer[count] = 0;
-               result = item->write_func(tmp_buffer, count);
-       }
-       kfree(tmp_buffer);
-       return result;
-}
-
-static int get_lcd(struct backlight_device *bd)
-{
-       u32 hci_result;
-       u32 value;
-
-       hci_read1(HCI_LCD_BRIGHTNESS, &value, &hci_result);
-       if (hci_result == HCI_SUCCESS) {
-               return (value >> HCI_LCD_BRIGHTNESS_SHIFT);
-       } else
-               return -EFAULT;
-}
-
-static char *read_lcd(char *p)
-{
-       int value = get_lcd(NULL);
-
-       if (value >= 0) {
-               p += sprintf(p, "brightness:              %d\n", value);
-               p += sprintf(p, "brightness_levels:       %d\n",
-                            HCI_LCD_BRIGHTNESS_LEVELS);
-       } else {
-               printk(MY_ERR "Error reading LCD brightness\n");
-       }
-
-       return p;
-}
-
-static int set_lcd(int value)
-{
-       u32 hci_result;
-
-       value = value << HCI_LCD_BRIGHTNESS_SHIFT;
-       hci_write1(HCI_LCD_BRIGHTNESS, value, &hci_result);
-       if (hci_result != HCI_SUCCESS)
-               return -EFAULT;
-
-       return 0;
-}
-
-static int set_lcd_status(struct backlight_device *bd)
-{
-       return set_lcd(bd->props.brightness);
-}
-
-static unsigned long write_lcd(const char *buffer, unsigned long count)
-{
-       int value;
-       int ret;
-
-       if (sscanf(buffer, " brightness : %i", &value) == 1 &&
-           value >= 0 && value < HCI_LCD_BRIGHTNESS_LEVELS) {
-               ret = set_lcd(value);
-               if (ret == 0)
-                       ret = count;
-       } else {
-               ret = -EINVAL;
-       }
-       return ret;
-}
-
-static char *read_video(char *p)
-{
-       u32 hci_result;
-       u32 value;
-
-       hci_read1(HCI_VIDEO_OUT, &value, &hci_result);
-       if (hci_result == HCI_SUCCESS) {
-               int is_lcd = (value & HCI_VIDEO_OUT_LCD) ? 1 : 0;
-               int is_crt = (value & HCI_VIDEO_OUT_CRT) ? 1 : 0;
-               int is_tv = (value & HCI_VIDEO_OUT_TV) ? 1 : 0;
-               p += sprintf(p, "lcd_out:                 %d\n", is_lcd);
-               p += sprintf(p, "crt_out:                 %d\n", is_crt);
-               p += sprintf(p, "tv_out:                  %d\n", is_tv);
-       } else {
-               printk(MY_ERR "Error reading video out status\n");
-       }
-
-       return p;
-}
-
-static unsigned long write_video(const char *buffer, unsigned long count)
-{
-       int value;
-       int remain = count;
-       int lcd_out = -1;
-       int crt_out = -1;
-       int tv_out = -1;
-       u32 hci_result;
-       u32 video_out;
-
-       /* scan expression.  Multiple expressions may be delimited with ;
-        *
-        *  NOTE: to keep scanning simple, invalid fields are ignored
-        */
-       while (remain) {
-               if (sscanf(buffer, " lcd_out : %i", &value) == 1)
-                       lcd_out = value & 1;
-               else if (sscanf(buffer, " crt_out : %i", &value) == 1)
-                       crt_out = value & 1;
-               else if (sscanf(buffer, " tv_out : %i", &value) == 1)
-                       tv_out = value & 1;
-               /* advance to one character past the next ; */
-               do {
-                       ++buffer;
-                       --remain;
-               }
-               while (remain && *(buffer - 1) != ';');
-       }
-
-       hci_read1(HCI_VIDEO_OUT, &video_out, &hci_result);
-       if (hci_result == HCI_SUCCESS) {
-               unsigned int new_video_out = video_out;
-               if (lcd_out != -1)
-                       _set_bit(&new_video_out, HCI_VIDEO_OUT_LCD, lcd_out);
-               if (crt_out != -1)
-                       _set_bit(&new_video_out, HCI_VIDEO_OUT_CRT, crt_out);
-               if (tv_out != -1)
-                       _set_bit(&new_video_out, HCI_VIDEO_OUT_TV, tv_out);
-               /* To avoid unnecessary video disruption, only write the new
-                * video setting if something changed. */
-               if (new_video_out != video_out)
-                       write_acpi_int(METHOD_VIDEO_OUT, new_video_out);
-       } else {
-               return -EFAULT;
-       }
-
-       return count;
-}
-
-static char *read_fan(char *p)
-{
-       u32 hci_result;
-       u32 value;
-
-       hci_read1(HCI_FAN, &value, &hci_result);
-       if (hci_result == HCI_SUCCESS) {
-               p += sprintf(p, "running:                 %d\n", (value > 0));
-               p += sprintf(p, "force_on:                %d\n", force_fan);
-       } else {
-               printk(MY_ERR "Error reading fan status\n");
-       }
-
-       return p;
-}
-
-static unsigned long write_fan(const char *buffer, unsigned long count)
-{
-       int value;
-       u32 hci_result;
-
-       if (sscanf(buffer, " force_on : %i", &value) == 1 &&
-           value >= 0 && value <= 1) {
-               hci_write1(HCI_FAN, value, &hci_result);
-               if (hci_result != HCI_SUCCESS)
-                       return -EFAULT;
-               else
-                       force_fan = value;
-       } else {
-               return -EINVAL;
-       }
-
-       return count;
-}
-
-static char *read_keys(char *p)
-{
-       u32 hci_result;
-       u32 value;
-
-       if (!key_event_valid) {
-               hci_read1(HCI_SYSTEM_EVENT, &value, &hci_result);
-               if (hci_result == HCI_SUCCESS) {
-                       key_event_valid = 1;
-                       last_key_event = value;
-               } else if (hci_result == HCI_EMPTY) {
-                       /* better luck next time */
-               } else if (hci_result == HCI_NOT_SUPPORTED) {
-                       /* This is a workaround for an unresolved issue on
-                        * some machines where system events sporadically
-                        * become disabled. */
-                       hci_write1(HCI_SYSTEM_EVENT, 1, &hci_result);
-                       printk(MY_NOTICE "Re-enabled hotkeys\n");
-               } else {
-                       printk(MY_ERR "Error reading hotkey status\n");
-                       goto end;
-               }
-       }
-
-       p += sprintf(p, "hotkey_ready:            %d\n", key_event_valid);
-       p += sprintf(p, "hotkey:                  0x%04x\n", last_key_event);
-
-      end:
-       return p;
-}
-
-static unsigned long write_keys(const char *buffer, unsigned long count)
-{
-       int value;
-
-       if (sscanf(buffer, " hotkey_ready : %i", &value) == 1 && value == 0) {
-               key_event_valid = 0;
-       } else {
-               return -EINVAL;
-       }
-
-       return count;
-}
-
-static char *read_version(char *p)
-{
-       p += sprintf(p, "driver:                  %s\n", TOSHIBA_ACPI_VERSION);
-       p += sprintf(p, "proc_interface:          %d\n",
-                    PROC_INTERFACE_VERSION);
-       return p;
-}
-
-/* proc and module init
- */
-
-#define PROC_TOSHIBA           "toshiba"
-
-static ProcItem proc_items[] = {
-       {"lcd", read_lcd, write_lcd},
-       {"video", read_video, write_video},
-       {"fan", read_fan, write_fan},
-       {"keys", read_keys, write_keys},
-       {"version", read_version, NULL},
-       {NULL}
-};
-
-static acpi_status __init add_device(void)
-{
-       struct proc_dir_entry *proc;
-       ProcItem *item;
-
-       for (item = proc_items; item->name; ++item) {
-               proc = create_proc_read_entry(item->name,
-                                             S_IFREG | S_IRUGO | S_IWUSR,
-                                             toshiba_proc_dir,
-                                             (read_proc_t *) dispatch_read,
-                                             item);
-               if (proc)
-                       proc->owner = THIS_MODULE;
-               if (proc && item->write_func)
-                       proc->write_proc = (write_proc_t *) dispatch_write;
-       }
-
-       return AE_OK;
-}
-
-static acpi_status remove_device(void)
-{
-       ProcItem *item;
-
-       for (item = proc_items; item->name; ++item)
-               remove_proc_entry(item->name, toshiba_proc_dir);
-       return AE_OK;
-}
-
-static struct backlight_ops toshiba_backlight_data = {
-        .get_brightness = get_lcd,
-        .update_status  = set_lcd_status,
-};
-
-static void toshiba_acpi_exit(void)
-{
-       if (toshiba_acpi.poll_dev) {
-               input_unregister_polled_device(toshiba_acpi.poll_dev);
-               input_free_polled_device(toshiba_acpi.poll_dev);
-       }
-
-       if (toshiba_acpi.rfk_dev)
-               rfkill_unregister(toshiba_acpi.rfk_dev);
-
-       if (toshiba_backlight_device)
-               backlight_device_unregister(toshiba_backlight_device);
-
-       remove_device();
-
-       if (toshiba_proc_dir)
-               remove_proc_entry(PROC_TOSHIBA, acpi_root_dir);
-
-       platform_device_unregister(toshiba_acpi.p_dev);
-
-       return;
-}
-
-static int __init toshiba_acpi_init(void)
-{
-       acpi_status status = AE_OK;
-       u32 hci_result;
-       bool bt_present;
-       bool bt_on;
-       bool radio_on;
-       int ret = 0;
-
-       if (acpi_disabled)
-               return -ENODEV;
-
-       /* simple device detection: look for HCI method */
-       if (is_valid_acpi_path(METHOD_HCI_1))
-               method_hci = METHOD_HCI_1;
-       else if (is_valid_acpi_path(METHOD_HCI_2))
-               method_hci = METHOD_HCI_2;
-       else
-               return -ENODEV;
-
-       printk(MY_INFO "Toshiba Laptop ACPI Extras version %s\n",
-              TOSHIBA_ACPI_VERSION);
-       printk(MY_INFO "    HCI method: %s\n", method_hci);
-
-       mutex_init(&toshiba_acpi.mutex);
-
-       toshiba_acpi.p_dev = platform_device_register_simple("toshiba_acpi",
-                                                             -1, NULL, 0);
-       if (IS_ERR(toshiba_acpi.p_dev)) {
-               ret = PTR_ERR(toshiba_acpi.p_dev);
-               printk(MY_ERR "unable to register platform device\n");
-               toshiba_acpi.p_dev = NULL;
-               toshiba_acpi_exit();
-               return ret;
-       }
-
-       force_fan = 0;
-       key_event_valid = 0;
-
-       /* enable event fifo */
-       hci_write1(HCI_SYSTEM_EVENT, 1, &hci_result);
-
-       toshiba_proc_dir = proc_mkdir(PROC_TOSHIBA, acpi_root_dir);
-       if (!toshiba_proc_dir) {
-               toshiba_acpi_exit();
-               return -ENODEV;
-       } else {
-               toshiba_proc_dir->owner = THIS_MODULE;
-               status = add_device();
-               if (ACPI_FAILURE(status)) {
-                       toshiba_acpi_exit();
-                       return -ENODEV;
-               }
-       }
-
-       toshiba_backlight_device = backlight_device_register("toshiba",
-                                               &toshiba_acpi.p_dev->dev,
-                                               NULL,
-                                               &toshiba_backlight_data);
-        if (IS_ERR(toshiba_backlight_device)) {
-               ret = PTR_ERR(toshiba_backlight_device);
-
-               printk(KERN_ERR "Could not register toshiba backlight device\n");
-               toshiba_backlight_device = NULL;
-               toshiba_acpi_exit();
-               return ret;
-       }
-        toshiba_backlight_device->props.max_brightness = HCI_LCD_BRIGHTNESS_LEVELS - 1;
-
-       /* Register rfkill switch for Bluetooth */
-       if (hci_get_bt_present(&bt_present) == HCI_SUCCESS && bt_present) {
-               toshiba_acpi.rfk_dev = rfkill_allocate(&toshiba_acpi.p_dev->dev,
-                                                       RFKILL_TYPE_BLUETOOTH);
-               if (!toshiba_acpi.rfk_dev) {
-                       printk(MY_ERR "unable to allocate rfkill device\n");
-                       toshiba_acpi_exit();
-                       return -ENOMEM;
-               }
-
-               toshiba_acpi.rfk_dev->name = toshiba_acpi.bt_name;
-               toshiba_acpi.rfk_dev->toggle_radio = bt_rfkill_toggle_radio;
-               toshiba_acpi.rfk_dev->user_claim_unsupported = 1;
-               toshiba_acpi.rfk_dev->data = &toshiba_acpi;
-
-               if (hci_get_bt_on(&bt_on) == HCI_SUCCESS && bt_on) {
-                       toshiba_acpi.rfk_dev->state = RFKILL_STATE_UNBLOCKED;
-               } else if (hci_get_radio_state(&radio_on) == HCI_SUCCESS &&
-                          radio_on) {
-                       toshiba_acpi.rfk_dev->state = RFKILL_STATE_SOFT_BLOCKED;
-               } else {
-                       toshiba_acpi.rfk_dev->state = RFKILL_STATE_HARD_BLOCKED;
-               }
-
-               ret = rfkill_register(toshiba_acpi.rfk_dev);
-               if (ret) {
-                       printk(MY_ERR "unable to register rfkill device\n");
-                       toshiba_acpi_exit();
-                       return -ENOMEM;
-               }
-
-               /* Register input device for kill switch */
-               toshiba_acpi.poll_dev = input_allocate_polled_device();
-               if (!toshiba_acpi.poll_dev) {
-                       printk(MY_ERR
-                              "unable to allocate kill-switch input device\n");
-                       toshiba_acpi_exit();
-                       return -ENOMEM;
-               }
-               toshiba_acpi.poll_dev->private = &toshiba_acpi;
-               toshiba_acpi.poll_dev->poll = bt_poll_rfkill;
-               toshiba_acpi.poll_dev->poll_interval = 1000; /* msecs */
-
-               toshiba_acpi.poll_dev->input->name = toshiba_acpi.rfk_name;
-               toshiba_acpi.poll_dev->input->id.bustype = BUS_HOST;
-               /* Toshiba USB ID */
-               toshiba_acpi.poll_dev->input->id.vendor = 0x0930;
-               set_bit(EV_SW, toshiba_acpi.poll_dev->input->evbit);
-               set_bit(SW_RFKILL_ALL, toshiba_acpi.poll_dev->input->swbit);
-               input_report_switch(toshiba_acpi.poll_dev->input,
-                                   SW_RFKILL_ALL, TRUE);
-               input_sync(toshiba_acpi.poll_dev->input);
-
-               ret = input_register_polled_device(toshiba_acpi.poll_dev);
-               if (ret) {
-                       printk(MY_ERR
-                              "unable to register kill-switch input device\n");
-                       toshiba_acpi_exit();
-                       return ret;
-               }
-       }
-
-       return 0;
-}
-
-module_init(toshiba_acpi_init);
-module_exit(toshiba_acpi_exit);
diff --git a/drivers/acpi/wmi.c b/drivers/acpi/wmi.c
deleted file mode 100644 (file)
index 8a8b377..0000000
+++ /dev/null
@@ -1,747 +0,0 @@
-/*
- *  ACPI-WMI mapping driver
- *
- *  Copyright (C) 2007-2008 Carlos Corbacho <carlos@strangeworlds.co.uk>
- *
- *  GUID parsing code from ldm.c is:
- *   Copyright (C) 2001,2002 Richard Russon <ldm@flatcap.org>
- *   Copyright (c) 2001-2007 Anton Altaparmakov
- *   Copyright (C) 2001,2002 Jakob Kemi <jakob.kemi@telia.com>
- *
- * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- *
- *  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.
- *
- * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
- */
-
-#include <linux/kernel.h>
-#include <linux/init.h>
-#include <linux/types.h>
-#include <linux/list.h>
-#include <linux/acpi.h>
-#include <acpi/acpi_bus.h>
-#include <acpi/acpi_drivers.h>
-
-ACPI_MODULE_NAME("wmi");
-MODULE_AUTHOR("Carlos Corbacho");
-MODULE_DESCRIPTION("ACPI-WMI Mapping Driver");
-MODULE_LICENSE("GPL");
-
-#define ACPI_WMI_CLASS "wmi"
-
-#undef PREFIX
-#define PREFIX "ACPI: WMI: "
-
-static DEFINE_MUTEX(wmi_data_lock);
-
-struct guid_block {
-       char guid[16];
-       union {
-               char object_id[2];
-               struct {
-                       unsigned char notify_id;
-                       unsigned char reserved;
-               };
-       };
-       u8 instance_count;
-       u8 flags;
-};
-
-struct wmi_block {
-       struct list_head list;
-       struct guid_block gblock;
-       acpi_handle handle;
-       wmi_notify_handler handler;
-       void *handler_data;
-};
-
-static struct wmi_block wmi_blocks;
-
-/*
- * If the GUID data block is marked as expensive, we must enable and
- * explicitily disable data collection.
- */
-#define ACPI_WMI_EXPENSIVE   0x1
-#define ACPI_WMI_METHOD      0x2       /* GUID is a method */
-#define ACPI_WMI_STRING      0x4       /* GUID takes & returns a string */
-#define ACPI_WMI_EVENT       0x8       /* GUID is an event */
-
-static int acpi_wmi_remove(struct acpi_device *device, int type);
-static int acpi_wmi_add(struct acpi_device *device);
-
-static const struct acpi_device_id wmi_device_ids[] = {
-       {"PNP0C14", 0},
-       {"pnp0c14", 0},
-       {"", 0},
-};
-MODULE_DEVICE_TABLE(acpi, wmi_device_ids);
-
-static struct acpi_driver acpi_wmi_driver = {
-       .name = "wmi",
-       .class = ACPI_WMI_CLASS,
-       .ids = wmi_device_ids,
-       .ops = {
-               .add = acpi_wmi_add,
-               .remove = acpi_wmi_remove,
-               },
-};
-
-/*
- * GUID parsing functions
- */
-
-/**
- * wmi_parse_hexbyte - Convert a ASCII hex number to a byte
- * @src:  Pointer to at least 2 characters to convert.
- *
- * Convert a two character ASCII hex string to a number.
- *
- * Return:  0-255  Success, the byte was parsed correctly
- *          -1     Error, an invalid character was supplied
- */
-static int wmi_parse_hexbyte(const u8 *src)
-{
-       unsigned int x; /* For correct wrapping */
-       int h;
-
-       /* high part */
-       x = src[0];
-       if (x - '0' <= '9' - '0') {
-               h = x - '0';
-       } else if (x - 'a' <= 'f' - 'a') {
-               h = x - 'a' + 10;
-       } else if (x - 'A' <= 'F' - 'A') {
-               h = x - 'A' + 10;
-       } else {
-               return -1;
-       }
-       h <<= 4;
-
-       /* low part */
-       x = src[1];
-       if (x - '0' <= '9' - '0')
-               return h | (x - '0');
-       if (x - 'a' <= 'f' - 'a')
-               return h | (x - 'a' + 10);
-       if (x - 'A' <= 'F' - 'A')
-               return h | (x - 'A' + 10);
-       return -1;
-}
-
-/**
- * wmi_swap_bytes - Rearrange GUID bytes to match GUID binary
- * @src:   Memory block holding binary GUID (16 bytes)
- * @dest:  Memory block to hold byte swapped binary GUID (16 bytes)
- *
- * Byte swap a binary GUID to match it's real GUID value
- */
-static void wmi_swap_bytes(u8 *src, u8 *dest)
-{
-       int i;
-
-       for (i = 0; i <= 3; i++)
-               memcpy(dest + i, src + (3 - i), 1);
-
-       for (i = 0; i <= 1; i++)
-               memcpy(dest + 4 + i, src + (5 - i), 1);
-
-       for (i = 0; i <= 1; i++)
-               memcpy(dest + 6 + i, src + (7 - i), 1);
-
-       memcpy(dest + 8, src + 8, 8);
-}
-
-/**
- * wmi_parse_guid - Convert GUID from ASCII to binary
- * @src:   36 char string of the form fa50ff2b-f2e8-45de-83fa-65417f2f49ba
- * @dest:  Memory block to hold binary GUID (16 bytes)
- *
- * N.B. The GUID need not be NULL terminated.
- *
- * Return:  'true'   @dest contains binary GUID
- *          'false'  @dest contents are undefined
- */
-static bool wmi_parse_guid(const u8 *src, u8 *dest)
-{
-       static const int size[] = { 4, 2, 2, 2, 6 };
-       int i, j, v;
-
-       if (src[8]  != '-' || src[13] != '-' ||
-               src[18] != '-' || src[23] != '-')
-               return false;
-
-       for (j = 0; j < 5; j++, src++) {
-               for (i = 0; i < size[j]; i++, src += 2, *dest++ = v) {
-                       v = wmi_parse_hexbyte(src);
-                       if (v < 0)
-                               return false;
-               }
-       }
-
-       return true;
-}
-
-static bool find_guid(const char *guid_string, struct wmi_block **out)
-{
-       char tmp[16], guid_input[16];
-       struct wmi_block *wblock;
-       struct guid_block *block;
-       struct list_head *p;
-
-       wmi_parse_guid(guid_string, tmp);
-       wmi_swap_bytes(tmp, guid_input);
-
-       list_for_each(p, &wmi_blocks.list) {
-               wblock = list_entry(p, struct wmi_block, list);
-               block = &wblock->gblock;
-
-               if (memcmp(block->guid, guid_input, 16) == 0) {
-                       if (out)
-                               *out = wblock;
-                       return 1;
-               }
-       }
-       return 0;
-}
-
-static acpi_status wmi_method_enable(struct wmi_block *wblock, int enable)
-{
-       struct guid_block *block = NULL;
-       char method[5];
-       struct acpi_object_list input;
-       union acpi_object params[1];
-       acpi_status status;
-       acpi_handle handle;
-
-       block = &wblock->gblock;
-       handle = wblock->handle;
-
-       if (!block)
-               return AE_NOT_EXIST;
-
-       input.count = 1;
-       input.pointer = params;
-       params[0].type = ACPI_TYPE_INTEGER;
-       params[0].integer.value = enable;
-
-       snprintf(method, 5, "WE%02X", block->notify_id);
-       status = acpi_evaluate_object(handle, method, &input, NULL);
-
-       if (status != AE_OK && status != AE_NOT_FOUND)
-               return status;
-       else
-               return AE_OK;
-}
-
-/*
- * Exported WMI functions
- */
-/**
- * wmi_evaluate_method - Evaluate a WMI method
- * @guid_string: 36 char string of the form fa50ff2b-f2e8-45de-83fa-65417f2f49ba
- * @instance: Instance index
- * @method_id: Method ID to call
- * &in: Buffer containing input for the method call
- * &out: Empty buffer to return the method results
- *
- * Call an ACPI-WMI method
- */
-acpi_status wmi_evaluate_method(const char *guid_string, u8 instance,
-u32 method_id, const struct acpi_buffer *in, struct acpi_buffer *out)
-{
-       struct guid_block *block = NULL;
-       struct wmi_block *wblock = NULL;
-       acpi_handle handle;
-       acpi_status status;
-       struct acpi_object_list input;
-       union acpi_object params[3];
-       char method[4] = "WM";
-
-       if (!find_guid(guid_string, &wblock))
-               return AE_ERROR;
-
-       block = &wblock->gblock;
-       handle = wblock->handle;
-
-       if (!(block->flags & ACPI_WMI_METHOD))
-               return AE_BAD_DATA;
-
-       if (block->instance_count < instance)
-               return AE_BAD_PARAMETER;
-
-       input.count = 2;
-       input.pointer = params;
-       params[0].type = ACPI_TYPE_INTEGER;
-       params[0].integer.value = instance;
-       params[1].type = ACPI_TYPE_INTEGER;
-       params[1].integer.value = method_id;
-
-       if (in) {
-               input.count = 3;
-
-               if (block->flags & ACPI_WMI_STRING) {
-                       params[2].type = ACPI_TYPE_STRING;
-               } else {
-                       params[2].type = ACPI_TYPE_BUFFER;
-               }
-               params[2].buffer.length = in->length;
-               params[2].buffer.pointer = in->pointer;
-       }
-
-       strncat(method, block->object_id, 2);
-
-       status = acpi_evaluate_object(handle, method, &input, out);
-
-       return status;
-}
-EXPORT_SYMBOL_GPL(wmi_evaluate_method);
-
-/**
- * wmi_query_block - Return contents of a WMI block
- * @guid_string: 36 char string of the form fa50ff2b-f2e8-45de-83fa-65417f2f49ba
- * @instance: Instance index
- * &out: Empty buffer to return the contents of the data block to
- *
- * Return the contents of an ACPI-WMI data block to a buffer
- */
-acpi_status wmi_query_block(const char *guid_string, u8 instance,
-struct acpi_buffer *out)
-{
-       struct guid_block *block = NULL;
-       struct wmi_block *wblock = NULL;
-       acpi_handle handle, wc_handle;
-       acpi_status status, wc_status = AE_ERROR;
-       struct acpi_object_list input, wc_input;
-       union acpi_object wc_params[1], wq_params[1];
-       char method[4];
-       char wc_method[4] = "WC";
-
-       if (!guid_string || !out)
-               return AE_BAD_PARAMETER;
-
-       if (!find_guid(guid_string, &wblock))
-               return AE_ERROR;
-
-       block = &wblock->gblock;
-       handle = wblock->handle;
-
-       if (block->instance_count < instance)
-               return AE_BAD_PARAMETER;
-
-       /* Check GUID is a data block */
-       if (block->flags & (ACPI_WMI_EVENT | ACPI_WMI_METHOD))
-               return AE_ERROR;
-
-       input.count = 1;
-       input.pointer = wq_params;
-       wq_params[0].type = ACPI_TYPE_INTEGER;
-       wq_params[0].integer.value = instance;
-
-       /*
-        * If ACPI_WMI_EXPENSIVE, call the relevant WCxx method first to
-        * enable collection.
-        */
-       if (block->flags & ACPI_WMI_EXPENSIVE) {
-               wc_input.count = 1;
-               wc_input.pointer = wc_params;
-               wc_params[0].type = ACPI_TYPE_INTEGER;
-               wc_params[0].integer.value = 1;
-
-               strncat(wc_method, block->object_id, 2);
-
-               /*
-                * Some GUIDs break the specification by declaring themselves
-                * expensive, but have no corresponding WCxx method. So we
-                * should not fail if this happens.
-                */
-               wc_status = acpi_get_handle(handle, wc_method, &wc_handle);
-               if (ACPI_SUCCESS(wc_status))
-                       wc_status = acpi_evaluate_object(handle, wc_method,
-                               &wc_input, NULL);
-       }
-
-       strcpy(method, "WQ");
-       strncat(method, block->object_id, 2);
-
-       status = acpi_evaluate_object(handle, method, &input, out);
-
-       /*
-        * If ACPI_WMI_EXPENSIVE, call the relevant WCxx method, even if
-        * the WQxx method failed - we should disable collection anyway.
-        */
-       if ((block->flags & ACPI_WMI_EXPENSIVE) && ACPI_SUCCESS(wc_status)) {
-               wc_params[0].integer.value = 0;
-               status = acpi_evaluate_object(handle,
-               wc_method, &wc_input, NULL);
-       }
-
-       return status;
-}
-EXPORT_SYMBOL_GPL(wmi_query_block);
-
-/**
- * wmi_set_block - Write to a WMI block
- * @guid_string: 36 char string of the form fa50ff2b-f2e8-45de-83fa-65417f2f49ba
- * @instance: Instance index
- * &in: Buffer containing new values for the data block
- *
- * Write the contents of the input buffer to an ACPI-WMI data block
- */
-acpi_status wmi_set_block(const char *guid_string, u8 instance,
-const struct acpi_buffer *in)
-{
-       struct guid_block *block = NULL;
-       struct wmi_block *wblock = NULL;
-       acpi_handle handle;
-       struct acpi_object_list input;
-       union acpi_object params[2];
-       char method[4] = "WS";
-
-       if (!guid_string || !in)
-               return AE_BAD_DATA;
-
-       if (!find_guid(guid_string, &wblock))
-               return AE_ERROR;
-
-       block = &wblock->gblock;
-       handle = wblock->handle;
-
-       if (block->instance_count < instance)
-               return AE_BAD_PARAMETER;
-
-       /* Check GUID is a data block */
-       if (block->flags & (ACPI_WMI_EVENT | ACPI_WMI_METHOD))
-               return AE_ERROR;
-
-       input.count = 2;
-       input.pointer = params;
-       params[0].type = ACPI_TYPE_INTEGER;
-       params[0].integer.value = instance;
-
-       if (block->flags & ACPI_WMI_STRING) {
-               params[1].type = ACPI_TYPE_STRING;
-       } else {
-               params[1].type = ACPI_TYPE_BUFFER;
-       }
-       params[1].buffer.length = in->length;
-       params[1].buffer.pointer = in->pointer;
-
-       strncat(method, block->object_id, 2);
-
-       return acpi_evaluate_object(handle, method, &input, NULL);
-}
-EXPORT_SYMBOL_GPL(wmi_set_block);
-
-/**
- * wmi_install_notify_handler - Register handler for WMI events
- * @handler: Function to handle notifications
- * @data: Data to be returned to handler when event is fired
- *
- * Register a handler for events sent to the ACPI-WMI mapper device.
- */
-acpi_status wmi_install_notify_handler(const char *guid,
-wmi_notify_handler handler, void *data)
-{
-       struct wmi_block *block;
-       acpi_status status;
-
-       if (!guid || !handler)
-               return AE_BAD_PARAMETER;
-
-       find_guid(guid, &block);
-       if (!block)
-               return AE_NOT_EXIST;
-
-       if (block->handler)
-               return AE_ALREADY_ACQUIRED;
-
-       block->handler = handler;
-       block->handler_data = data;
-
-       status = wmi_method_enable(block, 1);
-
-       return status;
-}
-EXPORT_SYMBOL_GPL(wmi_install_notify_handler);
-
-/**
- * wmi_uninstall_notify_handler - Unregister handler for WMI events
- *
- * Unregister handler for events sent to the ACPI-WMI mapper device.
- */
-acpi_status wmi_remove_notify_handler(const char *guid)
-{
-       struct wmi_block *block;
-       acpi_status status;
-
-       if (!guid)
-               return AE_BAD_PARAMETER;
-
-       find_guid(guid, &block);
-       if (!block)
-               return AE_NOT_EXIST;
-
-       if (!block->handler)
-               return AE_NULL_ENTRY;
-
-       status = wmi_method_enable(block, 0);
-
-       block->handler = NULL;
-       block->handler_data = NULL;
-
-       return status;
-}
-EXPORT_SYMBOL_GPL(wmi_remove_notify_handler);
-
-/**
- * wmi_get_event_data - Get WMI data associated with an event
- *
- * @event - Event to find
- * &out - Buffer to hold event data
- *
- * Returns extra data associated with an event in WMI.
- */
-acpi_status wmi_get_event_data(u32 event, struct acpi_buffer *out)
-{
-       struct acpi_object_list input;
-       union acpi_object params[1];
-       struct guid_block *gblock;
-       struct wmi_block *wblock;
-       struct list_head *p;
-
-       input.count = 1;
-       input.pointer = params;
-       params[0].type = ACPI_TYPE_INTEGER;
-       params[0].integer.value = event;
-
-       list_for_each(p, &wmi_blocks.list) {
-               wblock = list_entry(p, struct wmi_block, list);
-               gblock = &wblock->gblock;
-
-               if ((gblock->flags & ACPI_WMI_EVENT) &&
-                       (gblock->notify_id == event))
-                       return acpi_evaluate_object(wblock->handle, "_WED",
-                               &input, out);
-       }
-
-       return AE_NOT_FOUND;
-}
-EXPORT_SYMBOL_GPL(wmi_get_event_data);
-
-/**
- * wmi_has_guid - Check if a GUID is available
- * @guid_string: 36 char string of the form fa50ff2b-f2e8-45de-83fa-65417f2f49ba
- *
- * Check if a given GUID is defined by _WDG
- */
-bool wmi_has_guid(const char *guid_string)
-{
-       return find_guid(guid_string, NULL);
-}
-EXPORT_SYMBOL_GPL(wmi_has_guid);
-
-/*
- * Parse the _WDG method for the GUID data blocks
- */
-static __init acpi_status parse_wdg(acpi_handle handle)
-{
-       struct acpi_buffer out = {ACPI_ALLOCATE_BUFFER, NULL};
-       union acpi_object *obj;
-       struct guid_block *gblock;
-       struct wmi_block *wblock;
-       acpi_status status;
-       u32 i, total;
-
-       status = acpi_evaluate_object(handle, "_WDG", NULL, &out);
-
-       if (ACPI_FAILURE(status))
-               return status;
-
-       obj = (union acpi_object *) out.pointer;
-
-       if (obj->type != ACPI_TYPE_BUFFER)
-               return AE_ERROR;
-
-       total = obj->buffer.length / sizeof(struct guid_block);
-
-       gblock = kzalloc(obj->buffer.length, GFP_KERNEL);
-       if (!gblock)
-               return AE_NO_MEMORY;
-
-       memcpy(gblock, obj->buffer.pointer, obj->buffer.length);
-
-       for (i = 0; i < total; i++) {
-               wblock = kzalloc(sizeof(struct wmi_block), GFP_KERNEL);
-               if (!wblock)
-                       return AE_NO_MEMORY;
-
-               wblock->gblock = gblock[i];
-               wblock->handle = handle;
-               list_add_tail(&wblock->list, &wmi_blocks.list);
-       }
-
-       kfree(out.pointer);
-       kfree(gblock);
-
-       return status;
-}
-
-/*
- * WMI can have EmbeddedControl access regions. In which case, we just want to
- * hand these off to the EC driver.
- */
-static acpi_status
-acpi_wmi_ec_space_handler(u32 function, acpi_physical_address address,
-                     u32 bits, acpi_integer * value,
-                     void *handler_context, void *region_context)
-{
-       int result = 0, i = 0;
-       u8 temp = 0;
-
-       if ((address > 0xFF) || !value)
-               return AE_BAD_PARAMETER;
-
-       if (function != ACPI_READ && function != ACPI_WRITE)
-               return AE_BAD_PARAMETER;
-
-       if (bits != 8)
-               return AE_BAD_PARAMETER;
-
-       if (function == ACPI_READ) {
-               result = ec_read(address, &temp);
-               (*value) |= ((acpi_integer)temp) << i;
-       } else {
-               temp = 0xff & ((*value) >> i);
-               result = ec_write(address, temp);
-       }
-
-       switch (result) {
-       case -EINVAL:
-               return AE_BAD_PARAMETER;
-               break;
-       case -ENODEV:
-               return AE_NOT_FOUND;
-               break;
-       case -ETIME:
-               return AE_TIME;
-               break;
-       default:
-               return AE_OK;
-       }
-}
-
-static void acpi_wmi_notify(acpi_handle handle, u32 event, void *data)
-{
-       struct guid_block *block;
-       struct wmi_block *wblock;
-       struct list_head *p;
-       struct acpi_device *device = data;
-
-       list_for_each(p, &wmi_blocks.list) {
-               wblock = list_entry(p, struct wmi_block, list);
-               block = &wblock->gblock;
-
-               if ((block->flags & ACPI_WMI_EVENT) &&
-                       (block->notify_id == event)) {
-                       if (wblock->handler)
-                               wblock->handler(event, wblock->handler_data);
-
-                       acpi_bus_generate_netlink_event(
-                               device->pnp.device_class, dev_name(&device->dev),
-                               event, 0);
-                       break;
-               }
-       }
-}
-
-static int acpi_wmi_remove(struct acpi_device *device, int type)
-{
-       acpi_remove_notify_handler(device->handle, ACPI_DEVICE_NOTIFY,
-               acpi_wmi_notify);
-
-       acpi_remove_address_space_handler(device->handle,
-                               ACPI_ADR_SPACE_EC, &acpi_wmi_ec_space_handler);
-
-       return 0;
-}
-
-static int __init acpi_wmi_add(struct acpi_device *device)
-{
-       acpi_status status;
-       int result = 0;
-
-       status = acpi_install_notify_handler(device->handle, ACPI_DEVICE_NOTIFY,
-               acpi_wmi_notify, device);
-       if (ACPI_FAILURE(status)) {
-               printk(KERN_ERR PREFIX "Error installing notify handler\n");
-               return -ENODEV;
-       }
-
-       status = acpi_install_address_space_handler(device->handle,
-                                                   ACPI_ADR_SPACE_EC,
-                                                   &acpi_wmi_ec_space_handler,
-                                                   NULL, NULL);
-       if (ACPI_FAILURE(status))
-               return -ENODEV;
-
-       status = parse_wdg(device->handle);
-       if (ACPI_FAILURE(status)) {
-               printk(KERN_ERR PREFIX "Error installing EC region handler\n");
-               return -ENODEV;
-       }
-
-       return result;
-}
-
-static int __init acpi_wmi_init(void)
-{
-       acpi_status result;
-
-       INIT_LIST_HEAD(&wmi_blocks.list);
-
-       if (acpi_disabled)
-               return -ENODEV;
-
-       result = acpi_bus_register_driver(&acpi_wmi_driver);
-
-       if (result < 0) {
-               printk(KERN_INFO PREFIX "Error loading mapper\n");
-       } else {
-               printk(KERN_INFO PREFIX "Mapper loaded\n");
-       }
-
-       return result;
-}
-
-static void __exit acpi_wmi_exit(void)
-{
-       struct list_head *p, *tmp;
-       struct wmi_block *wblock;
-
-       acpi_bus_unregister_driver(&acpi_wmi_driver);
-
-       list_for_each_safe(p, tmp, &wmi_blocks.list) {
-               wblock = list_entry(p, struct wmi_block, list);
-
-               list_del(p);
-               kfree(wblock);
-       }
-
-       printk(KERN_INFO PREFIX "Mapper unloaded\n");
-}
-
-subsys_initcall(acpi_wmi_init);
-module_exit(acpi_wmi_exit);
index 0a9a5b9440af6320b5af35522467b006282a7363..31f3ce2ac01cfc5e8261e8a8b9aa812e30e13066 100644 (file)
@@ -287,4 +287,89 @@ config EEEPC_LAPTOP
 
          If you have an Eee PC laptop, say Y or M here.
 
+
+config ACPI_WMI
+       tristate "WMI (EXPERIMENTAL)"
+       depends on ACPI
+       depends on EXPERIMENTAL
+       help
+         This driver adds support for the ACPI-WMI (Windows Management
+         Instrumentation) mapper device (PNP0C14) found on some systems.
+
+         ACPI-WMI is a proprietary extension to ACPI to expose parts of the
+         ACPI firmware to userspace - this is done through various vendor
+         defined methods and data blocks in a PNP0C14 device, which are then
+         made available for userspace to call.
+
+         The implementation of this in Linux currently only exposes this to
+         other kernel space drivers.
+
+         This driver is a required dependency to build the firmware specific
+         drivers needed on many machines, including Acer and HP laptops.
+
+         It is safe to enable this driver even if your DSDT doesn't define
+         any ACPI-WMI devices.
+
+config ACPI_ASUS
+       tristate "ASUS/Medion Laptop Extras"
+       depends on ACPI
+       select BACKLIGHT_CLASS_DEVICE
+       ---help---
+         This driver provides support for extra features of ACPI-compatible
+         ASUS laptops. As some of Medion laptops are made by ASUS, it may also
+         support some Medion laptops (such as 9675 for example).  It makes all
+         the extra buttons generate standard ACPI events that go through
+         /proc/acpi/events, and (on some models) adds support for changing the
+         display brightness and output, switching the LCD backlight on and off,
+         and most importantly, allows you to blink those fancy LEDs intended
+         for reporting mail and wireless status.
+
+         Note: display switching code is currently considered EXPERIMENTAL,
+         toying with these values may even lock your machine.
+
+         All settings are changed via /proc/acpi/asus directory entries. Owner
+         and group for these entries can be set with asus_uid and asus_gid
+         parameters.
+
+         More information and a userspace daemon for handling the extra buttons
+         at <http://sourceforge.net/projects/acpi4asus/>.
+
+         If you have an ACPI-compatible ASUS laptop, say Y or M here. This
+         driver is still under development, so if your laptop is unsupported or
+         something works not quite as expected, please use the mailing list
+         available on the above page (acpi4asus-user@lists.sourceforge.net).
+
+         NOTE: This driver is deprecated and will probably be removed soon,
+         use asus-laptop instead.
+
+config ACPI_TOSHIBA
+       tristate "Toshiba Laptop Extras"
+       depends on ACPI
+       depends on INPUT
+       select INPUT_POLLDEV
+       select NET
+       select RFKILL
+       select BACKLIGHT_CLASS_DEVICE
+       ---help---
+         This driver adds support for access to certain system settings
+         on "legacy free" Toshiba laptops.  These laptops can be recognized by
+         their lack of a BIOS setup menu and APM support.
+
+         On these machines, all system configuration is handled through the
+         ACPI.  This driver is required for access to controls not covered
+         by the general ACPI drivers, such as LCD brightness, video output,
+         etc.
+
+         This driver differs from the non-ACPI Toshiba laptop driver (located
+         under "Processor type and features") in several aspects.
+         Configuration is accessed by reading and writing text files in the
+         /proc tree instead of by program interface to /dev.  Furthermore, no
+         power management functions are exposed, as those are handled by the
+         general ACPI drivers.
+
+         More information about this driver is available at
+         <http://memebeam.org/toys/ToshibaAcpiDriver>.
+
+         If you have a legacy free Toshiba laptop (such as the Libretto L1
+         series), say Y.
 endif # X86_PLATFORM_DEVICES
index 4d26b1bf22aea5b7605e43c22e3a017fb313a5d4..1e9de2ae0de56db8babfe46cc8724b0d22aa4505 100644 (file)
@@ -14,3 +14,6 @@ obj-$(CONFIG_THINKPAD_ACPI)   += thinkpad_acpi.o
 obj-$(CONFIG_FUJITSU_LAPTOP)   += fujitsu-laptop.o
 obj-$(CONFIG_PANASONIC_LAPTOP) += panasonic-laptop.o
 obj-$(CONFIG_INTEL_MENLOW)     += intel_menlow.o
+obj-$(CONFIG_ACPI_WMI)         += wmi.o
+obj-$(CONFIG_ACPI_ASUS)                += asus_acpi.o
+obj-$(CONFIG_ACPI_TOSHIBA)     += toshiba_acpi.o
diff --git a/drivers/platform/x86/asus_acpi.c b/drivers/platform/x86/asus_acpi.c
new file mode 100644 (file)
index 0000000..1e74988
--- /dev/null
@@ -0,0 +1,1460 @@
+/*
+ *  asus_acpi.c - Asus Laptop ACPI Extras
+ *
+ *
+ *  Copyright (C) 2002-2005 Julien Lerouge, 2003-2006 Karol Kozimor
+ *
+ *  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
+ *
+ *
+ *  The development page for this driver is located at
+ *  http://sourceforge.net/projects/acpi4asus/
+ *
+ *  Credits:
+ *  Pontus Fuchs   - Helper functions, cleanup
+ *  Johann Wiesner - Small compile fixes
+ *  John Belmonte  - ACPI code for Toshiba laptop was a good starting point.
+ *  �ic Burghard  - LED display support for W1N
+ *
+ */
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/proc_fs.h>
+#include <linux/backlight.h>
+#include <acpi/acpi_drivers.h>
+#include <acpi/acpi_bus.h>
+#include <asm/uaccess.h>
+
+#define ASUS_ACPI_VERSION "0.30"
+
+#define PROC_ASUS       "asus" /* The directory */
+#define PROC_MLED       "mled"
+#define PROC_WLED       "wled"
+#define PROC_TLED       "tled"
+#define PROC_BT         "bluetooth"
+#define PROC_LEDD       "ledd"
+#define PROC_INFO       "info"
+#define PROC_LCD        "lcd"
+#define PROC_BRN        "brn"
+#define PROC_DISP       "disp"
+
+#define ACPI_HOTK_NAME          "Asus Laptop ACPI Extras Driver"
+#define ACPI_HOTK_CLASS         "hotkey"
+#define ACPI_HOTK_DEVICE_NAME   "Hotkey"
+
+/*
+ * Some events we use, same for all Asus
+ */
+#define BR_UP       0x10
+#define BR_DOWN     0x20
+
+/*
+ * Flags for hotk status
+ */
+#define MLED_ON     0x01       /* Mail LED */
+#define WLED_ON     0x02       /* Wireless LED */
+#define TLED_ON     0x04       /* Touchpad LED */
+#define BT_ON       0x08       /* Internal Bluetooth */
+
+MODULE_AUTHOR("Julien Lerouge, Karol Kozimor");
+MODULE_DESCRIPTION(ACPI_HOTK_NAME);
+MODULE_LICENSE("GPL");
+
+static uid_t asus_uid;
+static gid_t asus_gid;
+module_param(asus_uid, uint, 0);
+MODULE_PARM_DESC(asus_uid, "UID for entries in /proc/acpi/asus");
+module_param(asus_gid, uint, 0);
+MODULE_PARM_DESC(asus_gid, "GID for entries in /proc/acpi/asus");
+
+/* For each model, all features implemented,
+ * those marked with R are relative to HOTK, A for absolute */
+struct model_data {
+       char *name;             /* name of the laptop________________A */
+       char *mt_mled;          /* method to handle mled_____________R */
+       char *mled_status;      /* node to handle mled reading_______A */
+       char *mt_wled;          /* method to handle wled_____________R */
+       char *wled_status;      /* node to handle wled reading_______A */
+       char *mt_tled;          /* method to handle tled_____________R */
+       char *tled_status;      /* node to handle tled reading_______A */
+       char *mt_ledd;          /* method to handle LED display______R */
+       char *mt_bt_switch;     /* method to switch Bluetooth on/off_R */
+       char *bt_status;        /* no model currently supports this__? */
+       char *mt_lcd_switch;    /* method to turn LCD on/off_________A */
+       char *lcd_status;       /* node to read LCD panel state______A */
+       char *brightness_up;    /* method to set brightness up_______A */
+       char *brightness_down;  /* method to set brightness down ____A */
+       char *brightness_set;   /* method to set absolute brightness_R */
+       char *brightness_get;   /* method to get absolute brightness_R */
+       char *brightness_status;/* node to get brightness____________A */
+       char *display_set;      /* method to set video output________R */
+       char *display_get;      /* method to get video output________R */
+};
+
+/*
+ * This is the main structure, we can use it to store anything interesting
+ * about the hotk device
+ */
+struct asus_hotk {
+       struct acpi_device *device;     /* the device we are in */
+       acpi_handle handle;             /* the handle of the hotk device */
+       char status;                    /* status of the hotk, for LEDs */
+       u32 ledd_status;                /* status of the LED display */
+       struct model_data *methods;     /* methods available on the laptop */
+       u8 brightness;                  /* brightness level */
+       enum {
+               A1x = 0,        /* A1340D, A1300F */
+               A2x,            /* A2500H */
+               A4G,            /* A4700G */
+               D1x,            /* D1 */
+               L2D,            /* L2000D */
+               L3C,            /* L3800C */
+               L3D,            /* L3400D */
+               L3H,            /* L3H, L2000E, L5D */
+               L4R,            /* L4500R */
+               L5x,            /* L5800C */
+               L8L,            /* L8400L */
+               M1A,            /* M1300A */
+               M2E,            /* M2400E, L4400L */
+               M6N,            /* M6800N, W3400N */
+               M6R,            /* M6700R, A3000G */
+               P30,            /* Samsung P30 */
+               S1x,            /* S1300A, but also L1400B and M2400A (L84F) */
+               S2x,            /* S200 (J1 reported), Victor MP-XP7210 */
+               W1N,            /* W1000N */
+               W5A,            /* W5A */
+               W3V,            /* W3030V */
+               xxN,            /* M2400N, M3700N, M5200N, M6800N,
+                                                        S1300N, S5200N*/
+               A4S,            /* Z81sp */
+               F3Sa,           /* (Centrino) */
+               END_MODEL
+       } model;                /* Models currently supported */
+       u16 event_count[128];   /* Count for each event TODO make this better */
+};
+
+/* Here we go */
+#define A1x_PREFIX "\\_SB.PCI0.ISA.EC0."
+#define L3C_PREFIX "\\_SB.PCI0.PX40.ECD0."
+#define M1A_PREFIX "\\_SB.PCI0.PX40.EC0."
+#define P30_PREFIX "\\_SB.PCI0.LPCB.EC0."
+#define S1x_PREFIX "\\_SB.PCI0.PX40."
+#define S2x_PREFIX A1x_PREFIX
+#define xxN_PREFIX "\\_SB.PCI0.SBRG.EC0."
+
+static struct model_data model_conf[END_MODEL] = {
+       /*
+        * TODO I have seen a SWBX and AIBX method on some models, like L1400B,
+        * it seems to be a kind of switch, but what for ?
+        */
+
+       {
+        .name = "A1x",
+        .mt_mled = "MLED",
+        .mled_status = "\\MAIL",
+        .mt_lcd_switch = A1x_PREFIX "_Q10",
+        .lcd_status = "\\BKLI",
+        .brightness_up = A1x_PREFIX "_Q0E",
+        .brightness_down = A1x_PREFIX "_Q0F"},
+
+       {
+        .name = "A2x",
+        .mt_mled = "MLED",
+        .mt_wled = "WLED",
+        .wled_status = "\\SG66",
+        .mt_lcd_switch = "\\Q10",
+        .lcd_status = "\\BAOF",
+        .brightness_set = "SPLV",
+        .brightness_get = "GPLV",
+        .display_set = "SDSP",
+        .display_get = "\\INFB"},
+
+       {
+        .name = "A4G",
+        .mt_mled = "MLED",
+/* WLED present, but not controlled by ACPI */
+        .mt_lcd_switch = xxN_PREFIX "_Q10",
+        .brightness_set = "SPLV",
+        .brightness_get = "GPLV",
+        .display_set = "SDSP",
+        .display_get = "\\ADVG"},
+
+       {
+        .name = "D1x",
+        .mt_mled = "MLED",
+        .mt_lcd_switch = "\\Q0D",
+        .lcd_status = "\\GP11",
+        .brightness_up = "\\Q0C",
+        .brightness_down = "\\Q0B",
+        .brightness_status = "\\BLVL",
+        .display_set = "SDSP",
+        .display_get = "\\INFB"},
+
+       {
+        .name = "L2D",
+        .mt_mled = "MLED",
+        .mled_status = "\\SGP6",
+        .mt_wled = "WLED",
+        .wled_status = "\\RCP3",
+        .mt_lcd_switch = "\\Q10",
+        .lcd_status = "\\SGP0",
+        .brightness_up = "\\Q0E",
+        .brightness_down = "\\Q0F",
+        .display_set = "SDSP",
+        .display_get = "\\INFB"},
+
+       {
+        .name = "L3C",
+        .mt_mled = "MLED",
+        .mt_wled = "WLED",
+        .mt_lcd_switch = L3C_PREFIX "_Q10",
+        .lcd_status = "\\GL32",
+        .brightness_set = "SPLV",
+        .brightness_get = "GPLV",
+        .display_set = "SDSP",
+        .display_get = "\\_SB.PCI0.PCI1.VGAC.NMAP"},
+
+       {
+        .name = "L3D",
+        .mt_mled = "MLED",
+        .mled_status = "\\MALD",
+        .mt_wled = "WLED",
+        .mt_lcd_switch = "\\Q10",
+        .lcd_status = "\\BKLG",
+        .brightness_set = "SPLV",
+        .brightness_get = "GPLV",
+        .display_set = "SDSP",
+        .display_get = "\\INFB"},
+
+       {
+        .name = "L3H",
+        .mt_mled = "MLED",
+        .mt_wled = "WLED",
+        .mt_lcd_switch = "EHK",
+        .lcd_status = "\\_SB.PCI0.PM.PBC",
+        .brightness_set = "SPLV",
+        .brightness_get = "GPLV",
+        .display_set = "SDSP",
+        .display_get = "\\INFB"},
+
+       {
+        .name = "L4R",
+        .mt_mled = "MLED",
+        .mt_wled = "WLED",
+        .wled_status = "\\_SB.PCI0.SBRG.SG13",
+        .mt_lcd_switch = xxN_PREFIX "_Q10",
+        .lcd_status = "\\_SB.PCI0.SBSM.SEO4",
+        .brightness_set = "SPLV",
+        .brightness_get = "GPLV",
+        .display_set = "SDSP",
+        .display_get = "\\_SB.PCI0.P0P1.VGA.GETD"},
+
+       {
+        .name = "L5x",
+        .mt_mled = "MLED",
+/* WLED present, but not controlled by ACPI */
+        .mt_tled = "TLED",
+        .mt_lcd_switch = "\\Q0D",
+        .lcd_status = "\\BAOF",
+        .brightness_set = "SPLV",
+        .brightness_get = "GPLV",
+        .display_set = "SDSP",
+        .display_get = "\\INFB"},
+
+       {
+        .name = "L8L"
+/* No features, but at least support the hotkeys */
+        },
+
+       {
+        .name = "M1A",
+        .mt_mled = "MLED",
+        .mt_lcd_switch = M1A_PREFIX "Q10",
+        .lcd_status = "\\PNOF",
+        .brightness_up = M1A_PREFIX "Q0E",
+        .brightness_down = M1A_PREFIX "Q0F",
+        .brightness_status = "\\BRIT",
+        .display_set = "SDSP",
+        .display_get = "\\INFB"},
+
+       {
+        .name = "M2E",
+        .mt_mled = "MLED",
+        .mt_wled = "WLED",
+        .mt_lcd_switch = "\\Q10",
+        .lcd_status = "\\GP06",
+        .brightness_set = "SPLV",
+        .brightness_get = "GPLV",
+        .display_set = "SDSP",
+        .display_get = "\\INFB"},
+
+       {
+        .name = "M6N",
+        .mt_mled = "MLED",
+        .mt_wled = "WLED",
+        .wled_status = "\\_SB.PCI0.SBRG.SG13",
+        .mt_lcd_switch = xxN_PREFIX "_Q10",
+        .lcd_status = "\\_SB.BKLT",
+        .brightness_set = "SPLV",
+        .brightness_get = "GPLV",
+        .display_set = "SDSP",
+        .display_get = "\\SSTE"},
+
+       {
+        .name = "M6R",
+        .mt_mled = "MLED",
+        .mt_wled = "WLED",
+        .mt_lcd_switch = xxN_PREFIX "_Q10",
+        .lcd_status = "\\_SB.PCI0.SBSM.SEO4",
+        .brightness_set = "SPLV",
+        .brightness_get = "GPLV",
+        .display_set = "SDSP",
+        .display_get = "\\_SB.PCI0.P0P1.VGA.GETD"},
+
+       {
+        .name = "P30",
+        .mt_wled = "WLED",
+        .mt_lcd_switch = P30_PREFIX "_Q0E",
+        .lcd_status = "\\BKLT",
+        .brightness_up = P30_PREFIX "_Q68",
+        .brightness_down = P30_PREFIX "_Q69",
+        .brightness_get = "GPLV",
+        .display_set = "SDSP",
+        .display_get = "\\DNXT"},
+
+       {
+        .name = "S1x",
+        .mt_mled = "MLED",
+        .mled_status = "\\EMLE",
+        .mt_wled = "WLED",
+        .mt_lcd_switch = S1x_PREFIX "Q10",
+        .lcd_status = "\\PNOF",
+        .brightness_set = "SPLV",
+        .brightness_get = "GPLV"},
+
+       {
+        .name = "S2x",
+        .mt_mled = "MLED",
+        .mled_status = "\\MAIL",
+        .mt_lcd_switch = S2x_PREFIX "_Q10",
+        .lcd_status = "\\BKLI",
+        .brightness_up = S2x_PREFIX "_Q0B",
+        .brightness_down = S2x_PREFIX "_Q0A"},
+
+       {
+        .name = "W1N",
+        .mt_mled = "MLED",
+        .mt_wled = "WLED",
+        .mt_ledd = "SLCM",
+        .mt_lcd_switch = xxN_PREFIX "_Q10",
+        .lcd_status = "\\BKLT",
+        .brightness_set = "SPLV",
+        .brightness_get = "GPLV",
+        .display_set = "SDSP",
+        .display_get = "\\ADVG"},
+
+       {
+        .name = "W5A",
+        .mt_bt_switch = "BLED",
+        .mt_wled = "WLED",
+        .mt_lcd_switch = xxN_PREFIX "_Q10",
+        .brightness_set = "SPLV",
+        .brightness_get = "GPLV",
+        .display_set = "SDSP",
+        .display_get = "\\ADVG"},
+
+       {
+        .name = "W3V",
+        .mt_mled = "MLED",
+        .mt_wled = "WLED",
+        .mt_lcd_switch = xxN_PREFIX "_Q10",
+        .lcd_status = "\\BKLT",
+        .brightness_set = "SPLV",
+        .brightness_get = "GPLV",
+        .display_set = "SDSP",
+        .display_get = "\\INFB"},
+
+       {
+        .name = "xxN",
+        .mt_mled = "MLED",
+/* WLED present, but not controlled by ACPI */
+        .mt_lcd_switch = xxN_PREFIX "_Q10",
+        .lcd_status = "\\BKLT",
+        .brightness_set = "SPLV",
+        .brightness_get = "GPLV",
+        .display_set = "SDSP",
+       .display_get = "\\ADVG"},
+
+       {
+               .name              = "A4S",
+               .brightness_set    = "SPLV",
+               .brightness_get    = "GPLV",
+               .mt_bt_switch      = "BLED",
+               .mt_wled           = "WLED"
+       },
+
+       {
+               .name           = "F3Sa",
+               .mt_bt_switch   = "BLED",
+               .mt_wled        = "WLED",
+               .mt_mled        = "MLED",
+               .brightness_get = "GPLV",
+               .brightness_set = "SPLV",
+               .mt_lcd_switch  = "\\_SB.PCI0.SBRG.EC0._Q10",
+               .lcd_status     = "\\_SB.PCI0.SBRG.EC0.RPIN",
+               .display_get    = "\\ADVG",
+               .display_set    = "SDSP",
+       },
+
+};
+
+/* procdir we use */
+static struct proc_dir_entry *asus_proc_dir;
+
+static struct backlight_device *asus_backlight_device;
+
+/*
+ * This header is made available to allow proper configuration given model,
+ * revision number , ... this info cannot go in struct asus_hotk because it is
+ * available before the hotk
+ */
+static struct acpi_table_header *asus_info;
+
+/* The actual device the driver binds to */
+static struct asus_hotk *hotk;
+
+/*
+ * The hotkey driver and autoloading declaration
+ */
+static int asus_hotk_add(struct acpi_device *device);
+static int asus_hotk_remove(struct acpi_device *device, int type);
+static const struct acpi_device_id asus_device_ids[] = {
+       {"ATK0100", 0},
+       {"", 0},
+};
+MODULE_DEVICE_TABLE(acpi, asus_device_ids);
+
+static struct acpi_driver asus_hotk_driver = {
+       .name = "asus_acpi",
+       .class = ACPI_HOTK_CLASS,
+       .ids = asus_device_ids,
+       .ops = {
+               .add = asus_hotk_add,
+               .remove = asus_hotk_remove,
+               },
+};
+
+/*
+ * This function evaluates an ACPI method, given an int as parameter, the
+ * method is searched within the scope of the handle, can be NULL. The output
+ * of the method is written is output, which can also be NULL
+ *
+ * returns 1 if write is successful, 0 else.
+ */
+static int write_acpi_int(acpi_handle handle, const char *method, int val,
+                         struct acpi_buffer *output)
+{
+       struct acpi_object_list params; /* list of input parameters (int) */
+       union acpi_object in_obj;       /* the only param we use */
+       acpi_status status;
+
+       params.count = 1;
+       params.pointer = &in_obj;
+       in_obj.type = ACPI_TYPE_INTEGER;
+       in_obj.integer.value = val;
+
+       status = acpi_evaluate_object(handle, (char *)method, &params, output);
+       return (status == AE_OK);
+}
+
+static int read_acpi_int(acpi_handle handle, const char *method, int *val)
+{
+       struct acpi_buffer output;
+       union acpi_object out_obj;
+       acpi_status status;
+
+       output.length = sizeof(out_obj);
+       output.pointer = &out_obj;
+
+       status = acpi_evaluate_object(handle, (char *)method, NULL, &output);
+       *val = out_obj.integer.value;
+       return (status == AE_OK) && (out_obj.type == ACPI_TYPE_INTEGER);
+}
+
+/*
+ * We write our info in page, we begin at offset off and cannot write more
+ * than count bytes. We set eof to 1 if we handle those 2 values. We return the
+ * number of bytes written in page
+ */
+static int
+proc_read_info(char *page, char **start, off_t off, int count, int *eof,
+              void *data)
+{
+       int len = 0;
+       int temp;
+       char buf[16];           /* enough for all info */
+       /*
+        * We use the easy way, we don't care of off and count,
+        * so we don't set eof to 1
+        */
+
+       len += sprintf(page, ACPI_HOTK_NAME " " ASUS_ACPI_VERSION "\n");
+       len += sprintf(page + len, "Model reference    : %s\n",
+                      hotk->methods->name);
+       /*
+        * The SFUN method probably allows the original driver to get the list
+        * of features supported by a given model. For now, 0x0100 or 0x0800
+        * bit signifies that the laptop is equipped with a Wi-Fi MiniPCI card.
+        * The significance of others is yet to be found.
+        */
+       if (read_acpi_int(hotk->handle, "SFUN", &temp))
+               len +=
+                   sprintf(page + len, "SFUN value         : 0x%04x\n", temp);
+       /*
+        * Another value for userspace: the ASYM method returns 0x02 for
+        * battery low and 0x04 for battery critical, its readings tend to be
+        * more accurate than those provided by _BST.
+        * Note: since not all the laptops provide this method, errors are
+        * silently ignored.
+        */
+       if (read_acpi_int(hotk->handle, "ASYM", &temp))
+               len +=
+                   sprintf(page + len, "ASYM value         : 0x%04x\n", temp);
+       if (asus_info) {
+               snprintf(buf, 16, "%d", asus_info->length);
+               len += sprintf(page + len, "DSDT length        : %s\n", buf);
+               snprintf(buf, 16, "%d", asus_info->checksum);
+               len += sprintf(page + len, "DSDT checksum      : %s\n", buf);
+               snprintf(buf, 16, "%d", asus_info->revision);
+               len += sprintf(page + len, "DSDT revision      : %s\n", buf);
+               snprintf(buf, 7, "%s", asus_info->oem_id);
+               len += sprintf(page + len, "OEM id             : %s\n", buf);
+               snprintf(buf, 9, "%s", asus_info->oem_table_id);
+               len += sprintf(page + len, "OEM table id       : %s\n", buf);
+               snprintf(buf, 16, "%x", asus_info->oem_revision);
+               len += sprintf(page + len, "OEM revision       : 0x%s\n", buf);
+               snprintf(buf, 5, "%s", asus_info->asl_compiler_id);
+               len += sprintf(page + len, "ASL comp vendor id : %s\n", buf);
+               snprintf(buf, 16, "%x", asus_info->asl_compiler_revision);
+               len += sprintf(page + len, "ASL comp revision  : 0x%s\n", buf);
+       }
+
+       return len;
+}
+
+/*
+ * /proc handlers
+ * We write our info in page, we begin at offset off and cannot write more
+ * than count bytes. We set eof to 1 if we handle those 2 values. We return the
+ * number of bytes written in page
+ */
+
+/* Generic LED functions */
+static int read_led(const char *ledname, int ledmask)
+{
+       if (ledname) {
+               int led_status;
+
+               if (read_acpi_int(NULL, ledname, &led_status))
+                       return led_status;
+               else
+                       printk(KERN_WARNING "Asus ACPI: Error reading LED "
+                              "status\n");
+       }
+       return (hotk->status & ledmask) ? 1 : 0;
+}
+
+static int parse_arg(const char __user *buf, unsigned long count, int *val)
+{
+       char s[32];
+       if (!count)
+               return 0;
+       if (count > 31)
+               return -EINVAL;
+       if (copy_from_user(s, buf, count))
+               return -EFAULT;
+       s[count] = 0;
+       if (sscanf(s, "%i", val) != 1)
+               return -EINVAL;
+       return count;
+}
+
+/* FIXME: kill extraneous args so it can be called independently */
+static int
+write_led(const char __user *buffer, unsigned long count,
+         char *ledname, int ledmask, int invert)
+{
+       int rv, value;
+       int led_out = 0;
+
+       rv = parse_arg(buffer, count, &value);
+       if (rv > 0)
+               led_out = value ? 1 : 0;
+
+       hotk->status =
+           (led_out) ? (hotk->status | ledmask) : (hotk->status & ~ledmask);
+
+       if (invert)             /* invert target value */
+               led_out = !led_out;
+
+       if (!write_acpi_int(hotk->handle, ledname, led_out, NULL))
+               printk(KERN_WARNING "Asus ACPI: LED (%s) write failed\n",
+                      ledname);
+
+       return rv;
+}
+
+/*
+ * Proc handlers for MLED
+ */
+static int
+proc_read_mled(char *page, char **start, off_t off, int count, int *eof,
+              void *data)
+{
+       return sprintf(page, "%d\n",
+                      read_led(hotk->methods->mled_status, MLED_ON));
+}
+
+static int
+proc_write_mled(struct file *file, const char __user *buffer,
+               unsigned long count, void *data)
+{
+       return write_led(buffer, count, hotk->methods->mt_mled, MLED_ON, 1);
+}
+
+/*
+ * Proc handlers for LED display
+ */
+static int
+proc_read_ledd(char *page, char **start, off_t off, int count, int *eof,
+              void *data)
+{
+       return sprintf(page, "0x%08x\n", hotk->ledd_status);
+}
+
+static int
+proc_write_ledd(struct file *file, const char __user *buffer,
+               unsigned long count, void *data)
+{
+       int rv, value;
+
+       rv = parse_arg(buffer, count, &value);
+       if (rv > 0) {
+               if (!write_acpi_int
+                   (hotk->handle, hotk->methods->mt_ledd, value, NULL))
+                       printk(KERN_WARNING
+                              "Asus ACPI: LED display write failed\n");
+               else
+                       hotk->ledd_status = (u32) value;
+       }
+       return rv;
+}
+
+/*
+ * Proc handlers for WLED
+ */
+static int
+proc_read_wled(char *page, char **start, off_t off, int count, int *eof,
+              void *data)
+{
+       return sprintf(page, "%d\n",
+                      read_led(hotk->methods->wled_status, WLED_ON));
+}
+
+static int
+proc_write_wled(struct file *file, const char __user *buffer,
+               unsigned long count, void *data)
+{
+       return write_led(buffer, count, hotk->methods->mt_wled, WLED_ON, 0);
+}
+
+/*
+ * Proc handlers for Bluetooth
+ */
+static int
+proc_read_bluetooth(char *page, char **start, off_t off, int count, int *eof,
+                   void *data)
+{
+       return sprintf(page, "%d\n", read_led(hotk->methods->bt_status, BT_ON));
+}
+
+static int
+proc_write_bluetooth(struct file *file, const char __user *buffer,
+                    unsigned long count, void *data)
+{
+       /* Note: mt_bt_switch controls both internal Bluetooth adapter's
+          presence and its LED */
+       return write_led(buffer, count, hotk->methods->mt_bt_switch, BT_ON, 0);
+}
+
+/*
+ * Proc handlers for TLED
+ */
+static int
+proc_read_tled(char *page, char **start, off_t off, int count, int *eof,
+              void *data)
+{
+       return sprintf(page, "%d\n",
+                      read_led(hotk->methods->tled_status, TLED_ON));
+}
+
+static int
+proc_write_tled(struct file *file, const char __user *buffer,
+               unsigned long count, void *data)
+{
+       return write_led(buffer, count, hotk->methods->mt_tled, TLED_ON, 0);
+}
+
+static int get_lcd_state(void)
+{
+       int lcd = 0;
+
+       if (hotk->model == L3H) {
+               /* L3H and the like have to be handled differently */
+               acpi_status status = 0;
+               struct acpi_object_list input;
+               union acpi_object mt_params[2];
+               struct acpi_buffer output;
+               union acpi_object out_obj;
+
+               input.count = 2;
+               input.pointer = mt_params;
+               /* Note: the following values are partly guessed up, but
+                  otherwise they seem to work */
+               mt_params[0].type = ACPI_TYPE_INTEGER;
+               mt_params[0].integer.value = 0x02;
+               mt_params[1].type = ACPI_TYPE_INTEGER;
+               mt_params[1].integer.value = 0x02;
+
+               output.length = sizeof(out_obj);
+               output.pointer = &out_obj;
+
+               status =
+                   acpi_evaluate_object(NULL, hotk->methods->lcd_status,
+                                        &input, &output);
+               if (status != AE_OK)
+                       return -1;
+               if (out_obj.type == ACPI_TYPE_INTEGER)
+                       /* That's what the AML code does */
+                       lcd = out_obj.integer.value >> 8;
+       } else if (hotk->model == F3Sa) {
+               unsigned long long tmp;
+               union acpi_object param;
+               struct acpi_object_list input;
+               acpi_status status;
+
+               /* Read pin 11 */
+               param.type = ACPI_TYPE_INTEGER;
+               param.integer.value = 0x11;
+               input.count = 1;
+               input.pointer = &param;
+
+               status = acpi_evaluate_integer(NULL, hotk->methods->lcd_status,
+                                               &input, &tmp);
+               if (status != AE_OK)
+                       return -1;
+
+               lcd = tmp;
+       } else {
+               /* We don't have to check anything if we are here */
+               if (!read_acpi_int(NULL, hotk->methods->lcd_status, &lcd))
+                       printk(KERN_WARNING
+                              "Asus ACPI: Error reading LCD status\n");
+
+               if (hotk->model == L2D)
+                       lcd = ~lcd;
+       }
+
+       return (lcd & 1);
+}
+
+static int set_lcd_state(int value)
+{
+       int lcd = 0;
+       acpi_status status = 0;
+
+       lcd = value ? 1 : 0;
+       if (lcd != get_lcd_state()) {
+               /* switch */
+               if (hotk->model != L3H) {
+                       status =
+                           acpi_evaluate_object(NULL,
+                                                hotk->methods->mt_lcd_switch,
+                                                NULL, NULL);
+               } else {
+                       /* L3H and the like must be handled differently */
+                       if (!write_acpi_int
+                           (hotk->handle, hotk->methods->mt_lcd_switch, 0x07,
+                            NULL))
+                               status = AE_ERROR;
+                       /* L3H's AML executes EHK (0x07) upon Fn+F7 keypress,
+                          the exact behaviour is simulated here */
+               }
+               if (ACPI_FAILURE(status))
+                       printk(KERN_WARNING "Asus ACPI: Error switching LCD\n");
+       }
+       return 0;
+
+}
+
+static int
+proc_read_lcd(char *page, char **start, off_t off, int count, int *eof,
+             void *data)
+{
+       return sprintf(page, "%d\n", get_lcd_state());
+}
+
+static int
+proc_write_lcd(struct file *file, const char __user *buffer,
+              unsigned long count, void *data)
+{
+       int rv, value;
+
+       rv = parse_arg(buffer, count, &value);
+       if (rv > 0)
+               set_lcd_state(value);
+       return rv;
+}
+
+static int read_brightness(struct backlight_device *bd)
+{
+       int value;
+
+       if (hotk->methods->brightness_get) {    /* SPLV/GPLV laptop */
+               if (!read_acpi_int(hotk->handle, hotk->methods->brightness_get,
+                                  &value))
+                       printk(KERN_WARNING
+                              "Asus ACPI: Error reading brightness\n");
+       } else if (hotk->methods->brightness_status) {  /* For D1 for example */
+               if (!read_acpi_int(NULL, hotk->methods->brightness_status,
+                                  &value))
+                       printk(KERN_WARNING
+                              "Asus ACPI: Error reading brightness\n");
+       } else                  /* No GPLV method */
+               value = hotk->brightness;
+       return value;
+}
+
+/*
+ * Change the brightness level
+ */
+static int set_brightness(int value)
+{
+       acpi_status status = 0;
+       int ret = 0;
+
+       /* SPLV laptop */
+       if (hotk->methods->brightness_set) {
+               if (!write_acpi_int(hotk->handle, hotk->methods->brightness_set,
+                                   value, NULL))
+                       printk(KERN_WARNING
+                              "Asus ACPI: Error changing brightness\n");
+                       ret = -EIO;
+               goto out;
+       }
+
+       /* No SPLV method if we are here, act as appropriate */
+       value -= read_brightness(NULL);
+       while (value != 0) {
+               status = acpi_evaluate_object(NULL, (value > 0) ?
+                                             hotk->methods->brightness_up :
+                                             hotk->methods->brightness_down,
+                                             NULL, NULL);
+               (value > 0) ? value-- : value++;
+               if (ACPI_FAILURE(status))
+                       printk(KERN_WARNING
+                              "Asus ACPI: Error changing brightness\n");
+                       ret = -EIO;
+       }
+out:
+       return ret;
+}
+
+static int set_brightness_status(struct backlight_device *bd)
+{
+       return set_brightness(bd->props.brightness);
+}
+
+static int
+proc_read_brn(char *page, char **start, off_t off, int count, int *eof,
+             void *data)
+{
+       return sprintf(page, "%d\n", read_brightness(NULL));
+}
+
+static int
+proc_write_brn(struct file *file, const char __user *buffer,
+              unsigned long count, void *data)
+{
+       int rv, value;
+
+       rv = parse_arg(buffer, count, &value);
+       if (rv > 0) {
+               value = (0 < value) ? ((15 < value) ? 15 : value) : 0;
+               /* 0 <= value <= 15 */
+               set_brightness(value);
+       }
+       return rv;
+}
+
+static void set_display(int value)
+{
+       /* no sanity check needed for now */
+       if (!write_acpi_int(hotk->handle, hotk->methods->display_set,
+                           value, NULL))
+               printk(KERN_WARNING "Asus ACPI: Error setting display\n");
+       return;
+}
+
+/*
+ * Now, *this* one could be more user-friendly, but so far, no-one has
+ * complained. The significance of bits is the same as in proc_write_disp()
+ */
+static int
+proc_read_disp(char *page, char **start, off_t off, int count, int *eof,
+              void *data)
+{
+       int value = 0;
+
+       if (!read_acpi_int(hotk->handle, hotk->methods->display_get, &value))
+               printk(KERN_WARNING
+                      "Asus ACPI: Error reading display status\n");
+       value &= 0x07;  /* needed for some models, shouldn't hurt others */
+       return sprintf(page, "%d\n", value);
+}
+
+/*
+ * Experimental support for display switching. As of now: 1 should activate
+ * the LCD output, 2 should do for CRT, and 4 for TV-Out. Any combination
+ * (bitwise) of these will suffice. I never actually tested 3 displays hooked
+ * up simultaneously, so be warned. See the acpi4asus README for more info.
+ */
+static int
+proc_write_disp(struct file *file, const char __user *buffer,
+               unsigned long count, void *data)
+{
+       int rv, value;
+
+       rv = parse_arg(buffer, count, &value);
+       if (rv > 0)
+               set_display(value);
+       return rv;
+}
+
+typedef int (proc_readfunc) (char *page, char **start, off_t off, int count,
+                            int *eof, void *data);
+typedef int (proc_writefunc) (struct file *file, const char __user *buffer,
+                             unsigned long count, void *data);
+
+static int
+asus_proc_add(char *name, proc_writefunc *writefunc,
+                    proc_readfunc *readfunc, mode_t mode,
+                    struct acpi_device *device)
+{
+       struct proc_dir_entry *proc =
+           create_proc_entry(name, mode, acpi_device_dir(device));
+       if (!proc) {
+               printk(KERN_WARNING "  Unable to create %s fs entry\n", name);
+               return -1;
+       }
+       proc->write_proc = writefunc;
+       proc->read_proc = readfunc;
+       proc->data = acpi_driver_data(device);
+       proc->owner = THIS_MODULE;
+       proc->uid = asus_uid;
+       proc->gid = asus_gid;
+       return 0;
+}
+
+static int asus_hotk_add_fs(struct acpi_device *device)
+{
+       struct proc_dir_entry *proc;
+       mode_t mode;
+
+       /*
+        * If parameter uid or gid is not changed, keep the default setting for
+        * our proc entries (-rw-rw-rw-) else, it means we care about security,
+        * and then set to -rw-rw----
+        */
+
+       if ((asus_uid == 0) && (asus_gid == 0)) {
+               mode = S_IFREG | S_IRUGO | S_IWUGO;
+       } else {
+               mode = S_IFREG | S_IRUSR | S_IRGRP | S_IWUSR | S_IWGRP;
+               printk(KERN_WARNING "  asus_uid and asus_gid parameters are "
+                      "deprecated, use chown and chmod instead!\n");
+       }
+
+       acpi_device_dir(device) = asus_proc_dir;
+       if (!acpi_device_dir(device))
+               return -ENODEV;
+
+       proc = create_proc_entry(PROC_INFO, mode, acpi_device_dir(device));
+       if (proc) {
+               proc->read_proc = proc_read_info;
+               proc->data = acpi_driver_data(device);
+               proc->owner = THIS_MODULE;
+               proc->uid = asus_uid;
+               proc->gid = asus_gid;
+       } else {
+               printk(KERN_WARNING "  Unable to create " PROC_INFO
+                      " fs entry\n");
+       }
+
+       if (hotk->methods->mt_wled) {
+               asus_proc_add(PROC_WLED, &proc_write_wled, &proc_read_wled,
+                             mode, device);
+       }
+
+       if (hotk->methods->mt_ledd) {
+               asus_proc_add(PROC_LEDD, &proc_write_ledd, &proc_read_ledd,
+                             mode, device);
+       }
+
+       if (hotk->methods->mt_mled) {
+               asus_proc_add(PROC_MLED, &proc_write_mled, &proc_read_mled,
+                             mode, device);
+       }
+
+       if (hotk->methods->mt_tled) {
+               asus_proc_add(PROC_TLED, &proc_write_tled, &proc_read_tled,
+                             mode, device);
+       }
+
+       if (hotk->methods->mt_bt_switch) {
+               asus_proc_add(PROC_BT, &proc_write_bluetooth,
+                             &proc_read_bluetooth, mode, device);
+       }
+
+       /*
+        * We need both read node and write method as LCD switch is also
+        * accessible from the keyboard
+        */
+       if (hotk->methods->mt_lcd_switch && hotk->methods->lcd_status) {
+               asus_proc_add(PROC_LCD, &proc_write_lcd, &proc_read_lcd, mode,
+                             device);
+       }
+
+       if ((hotk->methods->brightness_up && hotk->methods->brightness_down) ||
+           (hotk->methods->brightness_get && hotk->methods->brightness_set)) {
+               asus_proc_add(PROC_BRN, &proc_write_brn, &proc_read_brn, mode,
+                             device);
+       }
+
+       if (hotk->methods->display_set) {
+               asus_proc_add(PROC_DISP, &proc_write_disp, &proc_read_disp,
+                             mode, device);
+       }
+
+       return 0;
+}
+
+static int asus_hotk_remove_fs(struct acpi_device *device)
+{
+       if (acpi_device_dir(device)) {
+               remove_proc_entry(PROC_INFO, acpi_device_dir(device));
+               if (hotk->methods->mt_wled)
+                       remove_proc_entry(PROC_WLED, acpi_device_dir(device));
+               if (hotk->methods->mt_mled)
+                       remove_proc_entry(PROC_MLED, acpi_device_dir(device));
+               if (hotk->methods->mt_tled)
+                       remove_proc_entry(PROC_TLED, acpi_device_dir(device));
+               if (hotk->methods->mt_ledd)
+                       remove_proc_entry(PROC_LEDD, acpi_device_dir(device));
+               if (hotk->methods->mt_bt_switch)
+                       remove_proc_entry(PROC_BT, acpi_device_dir(device));
+               if (hotk->methods->mt_lcd_switch && hotk->methods->lcd_status)
+                       remove_proc_entry(PROC_LCD, acpi_device_dir(device));
+               if ((hotk->methods->brightness_up
+                    && hotk->methods->brightness_down)
+                   || (hotk->methods->brightness_get
+                       && hotk->methods->brightness_set))
+                       remove_proc_entry(PROC_BRN, acpi_device_dir(device));
+               if (hotk->methods->display_set)
+                       remove_proc_entry(PROC_DISP, acpi_device_dir(device));
+       }
+       return 0;
+}
+
+static void asus_hotk_notify(acpi_handle handle, u32 event, void *data)
+{
+       /* TODO Find a better way to handle events count. */
+       if (!hotk)
+               return;
+
+       if ((event & ~((u32) BR_UP)) < 16)
+               hotk->brightness = (event & ~((u32) BR_UP));
+       else if ((event & ~((u32) BR_DOWN)) < 16)
+               hotk->brightness = (event & ~((u32) BR_DOWN));
+
+       acpi_bus_generate_proc_event(hotk->device, event,
+                               hotk->event_count[event % 128]++);
+
+       return;
+}
+
+/*
+ * Match the model string to the list of supported models. Return END_MODEL if
+ * no match or model is NULL.
+ */
+static int asus_model_match(char *model)
+{
+       if (model == NULL)
+               return END_MODEL;
+
+       if (strncmp(model, "L3D", 3) == 0)
+               return L3D;
+       else if (strncmp(model, "L2E", 3) == 0 ||
+                strncmp(model, "L3H", 3) == 0 || strncmp(model, "L5D", 3) == 0)
+               return L3H;
+       else if (strncmp(model, "L3", 2) == 0 || strncmp(model, "L2B", 3) == 0)
+               return L3C;
+       else if (strncmp(model, "L8L", 3) == 0)
+               return L8L;
+       else if (strncmp(model, "L4R", 3) == 0)
+               return L4R;
+       else if (strncmp(model, "M6N", 3) == 0 || strncmp(model, "W3N", 3) == 0)
+               return M6N;
+       else if (strncmp(model, "M6R", 3) == 0 || strncmp(model, "A3G", 3) == 0)
+               return M6R;
+       else if (strncmp(model, "M2N", 3) == 0 ||
+                strncmp(model, "M3N", 3) == 0 ||
+                strncmp(model, "M5N", 3) == 0 ||
+                strncmp(model, "M6N", 3) == 0 ||
+                strncmp(model, "S1N", 3) == 0 ||
+                strncmp(model, "S5N", 3) == 0 || strncmp(model, "W1N", 3) == 0)
+               return xxN;
+       else if (strncmp(model, "M1", 2) == 0)
+               return M1A;
+       else if (strncmp(model, "M2", 2) == 0 || strncmp(model, "L4E", 3) == 0)
+               return M2E;
+       else if (strncmp(model, "L2", 2) == 0)
+               return L2D;
+       else if (strncmp(model, "L8", 2) == 0)
+               return S1x;
+       else if (strncmp(model, "D1", 2) == 0)
+               return D1x;
+       else if (strncmp(model, "A1", 2) == 0)
+               return A1x;
+       else if (strncmp(model, "A2", 2) == 0)
+               return A2x;
+       else if (strncmp(model, "J1", 2) == 0)
+               return S2x;
+       else if (strncmp(model, "L5", 2) == 0)
+               return L5x;
+       else if (strncmp(model, "A4G", 3) == 0)
+               return A4G;
+       else if (strncmp(model, "W1N", 3) == 0)
+               return W1N;
+       else if (strncmp(model, "W3V", 3) == 0)
+               return W3V;
+       else if (strncmp(model, "W5A", 3) == 0)
+               return W5A;
+       else if (strncmp(model, "A4S", 3) == 0)
+               return A4S;
+       else if (strncmp(model, "F3Sa", 4) == 0)
+               return F3Sa;
+       else
+               return END_MODEL;
+}
+
+/*
+ * This function is used to initialize the hotk with right values. In this
+ * method, we can make all the detection we want, and modify the hotk struct
+ */
+static int asus_hotk_get_info(void)
+{
+       struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
+       union acpi_object *model = NULL;
+       int bsts_result;
+       char *string = NULL;
+       acpi_status status;
+
+       /*
+        * Get DSDT headers early enough to allow for differentiating between
+        * models, but late enough to allow acpi_bus_register_driver() to fail
+        * before doing anything ACPI-specific. Should we encounter a machine,
+        * which needs special handling (i.e. its hotkey device has a different
+        * HID), this bit will be moved. A global variable asus_info contains
+        * the DSDT header.
+        */
+       status = acpi_get_table(ACPI_SIG_DSDT, 1, &asus_info);
+       if (ACPI_FAILURE(status))
+               printk(KERN_WARNING "  Couldn't get the DSDT table header\n");
+
+       /* We have to write 0 on init this far for all ASUS models */
+       if (!write_acpi_int(hotk->handle, "INIT", 0, &buffer)) {
+               printk(KERN_ERR "  Hotkey initialization failed\n");
+               return -ENODEV;
+       }
+
+       /* This needs to be called for some laptops to init properly */
+       if (!read_acpi_int(hotk->handle, "BSTS", &bsts_result))
+               printk(KERN_WARNING "  Error calling BSTS\n");
+       else if (bsts_result)
+               printk(KERN_NOTICE "  BSTS called, 0x%02x returned\n",
+                      bsts_result);
+
+       /*
+        * Try to match the object returned by INIT to the specific model.
+        * Handle every possible object (or the lack of thereof) the DSDT
+        * writers might throw at us. When in trouble, we pass NULL to
+        * asus_model_match() and try something completely different.
+        */
+       if (buffer.pointer) {
+               model = buffer.pointer;
+               switch (model->type) {
+               case ACPI_TYPE_STRING:
+                       string = model->string.pointer;
+                       break;
+               case ACPI_TYPE_BUFFER:
+                       string = model->buffer.pointer;
+                       break;
+               default:
+                       kfree(model);
+                       model = NULL;
+                       break;
+               }
+       }
+       hotk->model = asus_model_match(string);
+       if (hotk->model == END_MODEL) { /* match failed */
+               if (asus_info &&
+                   strncmp(asus_info->oem_table_id, "ODEM", 4) == 0) {
+                       hotk->model = P30;
+                       printk(KERN_NOTICE
+                              "  Samsung P30 detected, supported\n");
+               } else {
+                       hotk->model = M2E;
+                       printk(KERN_NOTICE "  unsupported model %s, trying "
+                              "default values\n", string);
+                       printk(KERN_NOTICE
+                              "  send /proc/acpi/dsdt to the developers\n");
+                       kfree(model);
+                       return -ENODEV;
+               }
+               hotk->methods = &model_conf[hotk->model];
+               return AE_OK;
+       }
+       hotk->methods = &model_conf[hotk->model];
+       printk(KERN_NOTICE "  %s model detected, supported\n", string);
+
+       /* Sort of per-model blacklist */
+       if (strncmp(string, "L2B", 3) == 0)
+               hotk->methods->lcd_status = NULL;
+       /* L2B is similar enough to L3C to use its settings, with this only
+          exception */
+       else if (strncmp(string, "A3G", 3) == 0)
+               hotk->methods->lcd_status = "\\BLFG";
+       /* A3G is like M6R */
+       else if (strncmp(string, "S5N", 3) == 0 ||
+                strncmp(string, "M5N", 3) == 0 ||
+                strncmp(string, "W3N", 3) == 0)
+               hotk->methods->mt_mled = NULL;
+       /* S5N, M5N and W3N have no MLED */
+       else if (strncmp(string, "L5D", 3) == 0)
+               hotk->methods->mt_wled = NULL;
+       /* L5D's WLED is not controlled by ACPI */
+       else if (strncmp(string, "M2N", 3) == 0 ||
+                strncmp(string, "W3V", 3) == 0 ||
+                strncmp(string, "S1N", 3) == 0)
+               hotk->methods->mt_wled = "WLED";
+       /* M2N, S1N and W3V have a usable WLED */
+       else if (asus_info) {
+               if (strncmp(asus_info->oem_table_id, "L1", 2) == 0)
+                       hotk->methods->mled_status = NULL;
+               /* S1300A reports L84F, but L1400B too, account for that */
+       }
+
+       kfree(model);
+
+       return AE_OK;
+}
+
+static int asus_hotk_check(void)
+{
+       int result = 0;
+
+       result = acpi_bus_get_status(hotk->device);
+       if (result)
+               return result;
+
+       if (hotk->device->status.present) {
+               result = asus_hotk_get_info();
+       } else {
+               printk(KERN_ERR "  Hotkey device not present, aborting\n");
+               return -EINVAL;
+       }
+
+       return result;
+}
+
+static int asus_hotk_found;
+
+static int asus_hotk_add(struct acpi_device *device)
+{
+       acpi_status status = AE_OK;
+       int result;
+
+       if (!device)
+               return -EINVAL;
+
+       printk(KERN_NOTICE "Asus Laptop ACPI Extras version %s\n",
+              ASUS_ACPI_VERSION);
+
+       hotk = kzalloc(sizeof(struct asus_hotk), GFP_KERNEL);
+       if (!hotk)
+               return -ENOMEM;
+
+       hotk->handle = device->handle;
+       strcpy(acpi_device_name(device), ACPI_HOTK_DEVICE_NAME);
+       strcpy(acpi_device_class(device), ACPI_HOTK_CLASS);
+       device->driver_data = hotk;
+       hotk->device = device;
+
+       result = asus_hotk_check();
+       if (result)
+               goto end;
+
+       result = asus_hotk_add_fs(device);
+       if (result)
+               goto end;
+
+       /*
+        * We install the handler, it will receive the hotk in parameter, so, we
+        * could add other data to the hotk struct
+        */
+       status = acpi_install_notify_handler(hotk->handle, ACPI_SYSTEM_NOTIFY,
+                                            asus_hotk_notify, hotk);
+       if (ACPI_FAILURE(status))
+               printk(KERN_ERR "  Error installing notify handler\n");
+
+       /* For laptops without GPLV: init the hotk->brightness value */
+       if ((!hotk->methods->brightness_get)
+           && (!hotk->methods->brightness_status)
+           && (hotk->methods->brightness_up && hotk->methods->brightness_down)) {
+               status =
+                   acpi_evaluate_object(NULL, hotk->methods->brightness_down,
+                                        NULL, NULL);
+               if (ACPI_FAILURE(status))
+                       printk(KERN_WARNING "  Error changing brightness\n");
+               else {
+                       status =
+                           acpi_evaluate_object(NULL,
+                                                hotk->methods->brightness_up,
+                                                NULL, NULL);
+                       if (ACPI_FAILURE(status))
+                               printk(KERN_WARNING "  Strange, error changing"
+                                      " brightness\n");
+               }
+       }
+
+       asus_hotk_found = 1;
+
+       /* LED display is off by default */
+       hotk->ledd_status = 0xFFF;
+
+end:
+       if (result)
+               kfree(hotk);
+
+       return result;
+}
+
+static int asus_hotk_remove(struct acpi_device *device, int type)
+{
+       acpi_status status = 0;
+
+       if (!device || !acpi_driver_data(device))
+               return -EINVAL;
+
+       status = acpi_remove_notify_handler(hotk->handle, ACPI_SYSTEM_NOTIFY,
+                                           asus_hotk_notify);
+       if (ACPI_FAILURE(status))
+               printk(KERN_ERR "Asus ACPI: Error removing notify handler\n");
+
+       asus_hotk_remove_fs(device);
+
+       kfree(hotk);
+
+       return 0;
+}
+
+static struct backlight_ops asus_backlight_data = {
+       .get_brightness = read_brightness,
+       .update_status  = set_brightness_status,
+};
+
+static void asus_acpi_exit(void)
+{
+       if (asus_backlight_device)
+               backlight_device_unregister(asus_backlight_device);
+
+       acpi_bus_unregister_driver(&asus_hotk_driver);
+       remove_proc_entry(PROC_ASUS, acpi_root_dir);
+
+       return;
+}
+
+static int __init asus_acpi_init(void)
+{
+       int result;
+
+       if (acpi_disabled)
+               return -ENODEV;
+
+       asus_proc_dir = proc_mkdir(PROC_ASUS, acpi_root_dir);
+       if (!asus_proc_dir) {
+               printk(KERN_ERR "Asus ACPI: Unable to create /proc entry\n");
+               return -ENODEV;
+       }
+       asus_proc_dir->owner = THIS_MODULE;
+
+       result = acpi_bus_register_driver(&asus_hotk_driver);
+       if (result < 0) {
+               remove_proc_entry(PROC_ASUS, acpi_root_dir);
+               return result;
+       }
+
+       /*
+        * This is a bit of a kludge.  We only want this module loaded
+        * for ASUS systems, but there's currently no way to probe the
+        * ACPI namespace for ASUS HIDs.  So we just return failure if
+        * we didn't find one, which will cause the module to be
+        * unloaded.
+        */
+       if (!asus_hotk_found) {
+               acpi_bus_unregister_driver(&asus_hotk_driver);
+               remove_proc_entry(PROC_ASUS, acpi_root_dir);
+               return -ENODEV;
+       }
+
+       asus_backlight_device = backlight_device_register("asus", NULL, NULL,
+                                                         &asus_backlight_data);
+       if (IS_ERR(asus_backlight_device)) {
+               printk(KERN_ERR "Could not register asus backlight device\n");
+               asus_backlight_device = NULL;
+               asus_acpi_exit();
+               return -ENODEV;
+       }
+       asus_backlight_device->props.max_brightness = 15;
+
+       return 0;
+}
+
+module_init(asus_acpi_init);
+module_exit(asus_acpi_exit);
diff --git a/drivers/platform/x86/toshiba_acpi.c b/drivers/platform/x86/toshiba_acpi.c
new file mode 100644 (file)
index 0000000..40e60fc
--- /dev/null
@@ -0,0 +1,863 @@
+/*
+ *  toshiba_acpi.c - Toshiba Laptop ACPI Extras
+ *
+ *
+ *  Copyright (C) 2002-2004 John Belmonte
+ *  Copyright (C) 2008 Philip Langdale
+ *
+ *  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
+ *
+ *
+ *  The devolpment page for this driver is located at
+ *  http://memebeam.org/toys/ToshibaAcpiDriver.
+ *
+ *  Credits:
+ *     Jonathan A. Buzzard - Toshiba HCI info, and critical tips on reverse
+ *             engineering the Windows drivers
+ *     Yasushi Nagato - changes for linux kernel 2.4 -> 2.5
+ *     Rob Miller - TV out and hotkeys help
+ *
+ *
+ *  TODO
+ *
+ */
+
+#define TOSHIBA_ACPI_VERSION   "0.19"
+#define PROC_INTERFACE_VERSION 1
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/proc_fs.h>
+#include <linux/backlight.h>
+#include <linux/platform_device.h>
+#include <linux/rfkill.h>
+#include <linux/input-polldev.h>
+
+#include <asm/uaccess.h>
+
+#include <acpi/acpi_drivers.h>
+
+MODULE_AUTHOR("John Belmonte");
+MODULE_DESCRIPTION("Toshiba Laptop ACPI Extras Driver");
+MODULE_LICENSE("GPL");
+
+#define MY_LOGPREFIX "toshiba_acpi: "
+#define MY_ERR KERN_ERR MY_LOGPREFIX
+#define MY_NOTICE KERN_NOTICE MY_LOGPREFIX
+#define MY_INFO KERN_INFO MY_LOGPREFIX
+
+/* Toshiba ACPI method paths */
+#define METHOD_LCD_BRIGHTNESS  "\\_SB_.PCI0.VGA_.LCD_._BCM"
+#define METHOD_HCI_1           "\\_SB_.VALD.GHCI"
+#define METHOD_HCI_2           "\\_SB_.VALZ.GHCI"
+#define METHOD_VIDEO_OUT       "\\_SB_.VALX.DSSX"
+
+/* Toshiba HCI interface definitions
+ *
+ * HCI is Toshiba's "Hardware Control Interface" which is supposed to
+ * be uniform across all their models.  Ideally we would just call
+ * dedicated ACPI methods instead of using this primitive interface.
+ * However the ACPI methods seem to be incomplete in some areas (for
+ * example they allow setting, but not reading, the LCD brightness value),
+ * so this is still useful.
+ */
+
+#define HCI_WORDS                      6
+
+/* operations */
+#define HCI_SET                                0xff00
+#define HCI_GET                                0xfe00
+
+/* return codes */
+#define HCI_SUCCESS                    0x0000
+#define HCI_FAILURE                    0x1000
+#define HCI_NOT_SUPPORTED              0x8000
+#define HCI_EMPTY                      0x8c00
+
+/* registers */
+#define HCI_FAN                                0x0004
+#define HCI_SYSTEM_EVENT               0x0016
+#define HCI_VIDEO_OUT                  0x001c
+#define HCI_HOTKEY_EVENT               0x001e
+#define HCI_LCD_BRIGHTNESS             0x002a
+#define HCI_WIRELESS                   0x0056
+
+/* field definitions */
+#define HCI_LCD_BRIGHTNESS_BITS                3
+#define HCI_LCD_BRIGHTNESS_SHIFT       (16-HCI_LCD_BRIGHTNESS_BITS)
+#define HCI_LCD_BRIGHTNESS_LEVELS      (1 << HCI_LCD_BRIGHTNESS_BITS)
+#define HCI_VIDEO_OUT_LCD              0x1
+#define HCI_VIDEO_OUT_CRT              0x2
+#define HCI_VIDEO_OUT_TV               0x4
+#define HCI_WIRELESS_KILL_SWITCH       0x01
+#define HCI_WIRELESS_BT_PRESENT                0x0f
+#define HCI_WIRELESS_BT_ATTACH         0x40
+#define HCI_WIRELESS_BT_POWER          0x80
+
+static const struct acpi_device_id toshiba_device_ids[] = {
+       {"TOS6200", 0},
+       {"TOS6208", 0},
+       {"TOS1900", 0},
+       {"", 0},
+};
+MODULE_DEVICE_TABLE(acpi, toshiba_device_ids);
+
+/* utility
+ */
+
+static __inline__ void _set_bit(u32 * word, u32 mask, int value)
+{
+       *word = (*word & ~mask) | (mask * value);
+}
+
+/* acpi interface wrappers
+ */
+
+static int is_valid_acpi_path(const char *methodName)
+{
+       acpi_handle handle;
+       acpi_status status;
+
+       status = acpi_get_handle(NULL, (char *)methodName, &handle);
+       return !ACPI_FAILURE(status);
+}
+
+static int write_acpi_int(const char *methodName, int val)
+{
+       struct acpi_object_list params;
+       union acpi_object in_objs[1];
+       acpi_status status;
+
+       params.count = ARRAY_SIZE(in_objs);
+       params.pointer = in_objs;
+       in_objs[0].type = ACPI_TYPE_INTEGER;
+       in_objs[0].integer.value = val;
+
+       status = acpi_evaluate_object(NULL, (char *)methodName, &params, NULL);
+       return (status == AE_OK);
+}
+
+#if 0
+static int read_acpi_int(const char *methodName, int *pVal)
+{
+       struct acpi_buffer results;
+       union acpi_object out_objs[1];
+       acpi_status status;
+
+       results.length = sizeof(out_objs);
+       results.pointer = out_objs;
+
+       status = acpi_evaluate_object(0, (char *)methodName, 0, &results);
+       *pVal = out_objs[0].integer.value;
+
+       return (status == AE_OK) && (out_objs[0].type == ACPI_TYPE_INTEGER);
+}
+#endif
+
+static const char *method_hci /*= 0*/ ;
+
+/* Perform a raw HCI call.  Here we don't care about input or output buffer
+ * format.
+ */
+static acpi_status hci_raw(const u32 in[HCI_WORDS], u32 out[HCI_WORDS])
+{
+       struct acpi_object_list params;
+       union acpi_object in_objs[HCI_WORDS];
+       struct acpi_buffer results;
+       union acpi_object out_objs[HCI_WORDS + 1];
+       acpi_status status;
+       int i;
+
+       params.count = HCI_WORDS;
+       params.pointer = in_objs;
+       for (i = 0; i < HCI_WORDS; ++i) {
+               in_objs[i].type = ACPI_TYPE_INTEGER;
+               in_objs[i].integer.value = in[i];
+       }
+
+       results.length = sizeof(out_objs);
+       results.pointer = out_objs;
+
+       status = acpi_evaluate_object(NULL, (char *)method_hci, &params,
+                                     &results);
+       if ((status == AE_OK) && (out_objs->package.count <= HCI_WORDS)) {
+               for (i = 0; i < out_objs->package.count; ++i) {
+                       out[i] = out_objs->package.elements[i].integer.value;
+               }
+       }
+
+       return status;
+}
+
+/* common hci tasks (get or set one or two value)
+ *
+ * In addition to the ACPI status, the HCI system returns a result which
+ * may be useful (such as "not supported").
+ */
+
+static acpi_status hci_write1(u32 reg, u32 in1, u32 * result)
+{
+       u32 in[HCI_WORDS] = { HCI_SET, reg, in1, 0, 0, 0 };
+       u32 out[HCI_WORDS];
+       acpi_status status = hci_raw(in, out);
+       *result = (status == AE_OK) ? out[0] : HCI_FAILURE;
+       return status;
+}
+
+static acpi_status hci_read1(u32 reg, u32 * out1, u32 * result)
+{
+       u32 in[HCI_WORDS] = { HCI_GET, reg, 0, 0, 0, 0 };
+       u32 out[HCI_WORDS];
+       acpi_status status = hci_raw(in, out);
+       *out1 = out[2];
+       *result = (status == AE_OK) ? out[0] : HCI_FAILURE;
+       return status;
+}
+
+static acpi_status hci_write2(u32 reg, u32 in1, u32 in2, u32 *result)
+{
+       u32 in[HCI_WORDS] = { HCI_SET, reg, in1, in2, 0, 0 };
+       u32 out[HCI_WORDS];
+       acpi_status status = hci_raw(in, out);
+       *result = (status == AE_OK) ? out[0] : HCI_FAILURE;
+       return status;
+}
+
+static acpi_status hci_read2(u32 reg, u32 *out1, u32 *out2, u32 *result)
+{
+       u32 in[HCI_WORDS] = { HCI_GET, reg, *out1, *out2, 0, 0 };
+       u32 out[HCI_WORDS];
+       acpi_status status = hci_raw(in, out);
+       *out1 = out[2];
+       *out2 = out[3];
+       *result = (status == AE_OK) ? out[0] : HCI_FAILURE;
+       return status;
+}
+
+struct toshiba_acpi_dev {
+       struct platform_device *p_dev;
+       struct rfkill *rfk_dev;
+       struct input_polled_dev *poll_dev;
+
+       const char *bt_name;
+       const char *rfk_name;
+
+       bool last_rfk_state;
+
+       struct mutex mutex;
+};
+
+static struct toshiba_acpi_dev toshiba_acpi = {
+       .bt_name = "Toshiba Bluetooth",
+       .rfk_name = "Toshiba RFKill Switch",
+       .last_rfk_state = false,
+};
+
+/* Bluetooth rfkill handlers */
+
+static u32 hci_get_bt_present(bool *present)
+{
+       u32 hci_result;
+       u32 value, value2;
+
+       value = 0;
+       value2 = 0;
+       hci_read2(HCI_WIRELESS, &value, &value2, &hci_result);
+       if (hci_result == HCI_SUCCESS)
+               *present = (value & HCI_WIRELESS_BT_PRESENT) ? true : false;
+
+       return hci_result;
+}
+
+static u32 hci_get_bt_on(bool *on)
+{
+       u32 hci_result;
+       u32 value, value2;
+
+       value = 0;
+       value2 = 0x0001;
+       hci_read2(HCI_WIRELESS, &value, &value2, &hci_result);
+       if (hci_result == HCI_SUCCESS)
+               *on = (value & HCI_WIRELESS_BT_POWER) &&
+                     (value & HCI_WIRELESS_BT_ATTACH);
+
+       return hci_result;
+}
+
+static u32 hci_get_radio_state(bool *radio_state)
+{
+       u32 hci_result;
+       u32 value, value2;
+
+       value = 0;
+       value2 = 0x0001;
+       hci_read2(HCI_WIRELESS, &value, &value2, &hci_result);
+
+       *radio_state = value & HCI_WIRELESS_KILL_SWITCH;
+       return hci_result;
+}
+
+static int bt_rfkill_toggle_radio(void *data, enum rfkill_state state)
+{
+       u32 result1, result2;
+       u32 value;
+       bool radio_state;
+       struct toshiba_acpi_dev *dev = data;
+
+       value = (state == RFKILL_STATE_UNBLOCKED);
+
+       if (hci_get_radio_state(&radio_state) != HCI_SUCCESS)
+               return -EFAULT;
+
+       switch (state) {
+       case RFKILL_STATE_UNBLOCKED:
+               if (!radio_state)
+                       return -EPERM;
+               break;
+       case RFKILL_STATE_SOFT_BLOCKED:
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       mutex_lock(&dev->mutex);
+       hci_write2(HCI_WIRELESS, value, HCI_WIRELESS_BT_POWER, &result1);
+       hci_write2(HCI_WIRELESS, value, HCI_WIRELESS_BT_ATTACH, &result2);
+       mutex_unlock(&dev->mutex);
+
+       if (result1 != HCI_SUCCESS || result2 != HCI_SUCCESS)
+               return -EFAULT;
+
+       return 0;
+}
+
+static void bt_poll_rfkill(struct input_polled_dev *poll_dev)
+{
+       bool state_changed;
+       bool new_rfk_state;
+       bool value;
+       u32 hci_result;
+       struct toshiba_acpi_dev *dev = poll_dev->private;
+
+       hci_result = hci_get_radio_state(&value);
+       if (hci_result != HCI_SUCCESS)
+               return; /* Can't do anything useful */
+
+       new_rfk_state = value;
+
+       mutex_lock(&dev->mutex);
+       state_changed = new_rfk_state != dev->last_rfk_state;
+       dev->last_rfk_state = new_rfk_state;
+       mutex_unlock(&dev->mutex);
+
+       if (unlikely(state_changed)) {
+               rfkill_force_state(dev->rfk_dev,
+                                  new_rfk_state ?
+                                  RFKILL_STATE_SOFT_BLOCKED :
+                                  RFKILL_STATE_HARD_BLOCKED);
+               input_report_switch(poll_dev->input, SW_RFKILL_ALL,
+                                   new_rfk_state);
+               input_sync(poll_dev->input);
+       }
+}
+
+static struct proc_dir_entry *toshiba_proc_dir /*= 0*/ ;
+static struct backlight_device *toshiba_backlight_device;
+static int force_fan;
+static int last_key_event;
+static int key_event_valid;
+
+typedef struct _ProcItem {
+       const char *name;
+       char *(*read_func) (char *);
+       unsigned long (*write_func) (const char *, unsigned long);
+} ProcItem;
+
+/* proc file handlers
+ */
+
+static int
+dispatch_read(char *page, char **start, off_t off, int count, int *eof,
+             ProcItem * item)
+{
+       char *p = page;
+       int len;
+
+       if (off == 0)
+               p = item->read_func(p);
+
+       /* ISSUE: I don't understand this code */
+       len = (p - page);
+       if (len <= off + count)
+               *eof = 1;
+       *start = page + off;
+       len -= off;
+       if (len > count)
+               len = count;
+       if (len < 0)
+               len = 0;
+       return len;
+}
+
+static int
+dispatch_write(struct file *file, const char __user * buffer,
+              unsigned long count, ProcItem * item)
+{
+       int result;
+       char *tmp_buffer;
+
+       /* Arg buffer points to userspace memory, which can't be accessed
+        * directly.  Since we're making a copy, zero-terminate the
+        * destination so that sscanf can be used on it safely.
+        */
+       tmp_buffer = kmalloc(count + 1, GFP_KERNEL);
+       if (!tmp_buffer)
+               return -ENOMEM;
+
+       if (copy_from_user(tmp_buffer, buffer, count)) {
+               result = -EFAULT;
+       } else {
+               tmp_buffer[count] = 0;
+               result = item->write_func(tmp_buffer, count);
+       }
+       kfree(tmp_buffer);
+       return result;
+}
+
+static int get_lcd(struct backlight_device *bd)
+{
+       u32 hci_result;
+       u32 value;
+
+       hci_read1(HCI_LCD_BRIGHTNESS, &value, &hci_result);
+       if (hci_result == HCI_SUCCESS) {
+               return (value >> HCI_LCD_BRIGHTNESS_SHIFT);
+       } else
+               return -EFAULT;
+}
+
+static char *read_lcd(char *p)
+{
+       int value = get_lcd(NULL);
+
+       if (value >= 0) {
+               p += sprintf(p, "brightness:              %d\n", value);
+               p += sprintf(p, "brightness_levels:       %d\n",
+                            HCI_LCD_BRIGHTNESS_LEVELS);
+       } else {
+               printk(MY_ERR "Error reading LCD brightness\n");
+       }
+
+       return p;
+}
+
+static int set_lcd(int value)
+{
+       u32 hci_result;
+
+       value = value << HCI_LCD_BRIGHTNESS_SHIFT;
+       hci_write1(HCI_LCD_BRIGHTNESS, value, &hci_result);
+       if (hci_result != HCI_SUCCESS)
+               return -EFAULT;
+
+       return 0;
+}
+
+static int set_lcd_status(struct backlight_device *bd)
+{
+       return set_lcd(bd->props.brightness);
+}
+
+static unsigned long write_lcd(const char *buffer, unsigned long count)
+{
+       int value;
+       int ret;
+
+       if (sscanf(buffer, " brightness : %i", &value) == 1 &&
+           value >= 0 && value < HCI_LCD_BRIGHTNESS_LEVELS) {
+               ret = set_lcd(value);
+               if (ret == 0)
+                       ret = count;
+       } else {
+               ret = -EINVAL;
+       }
+       return ret;
+}
+
+static char *read_video(char *p)
+{
+       u32 hci_result;
+       u32 value;
+
+       hci_read1(HCI_VIDEO_OUT, &value, &hci_result);
+       if (hci_result == HCI_SUCCESS) {
+               int is_lcd = (value & HCI_VIDEO_OUT_LCD) ? 1 : 0;
+               int is_crt = (value & HCI_VIDEO_OUT_CRT) ? 1 : 0;
+               int is_tv = (value & HCI_VIDEO_OUT_TV) ? 1 : 0;
+               p += sprintf(p, "lcd_out:                 %d\n", is_lcd);
+               p += sprintf(p, "crt_out:                 %d\n", is_crt);
+               p += sprintf(p, "tv_out:                  %d\n", is_tv);
+       } else {
+               printk(MY_ERR "Error reading video out status\n");
+       }
+
+       return p;
+}
+
+static unsigned long write_video(const char *buffer, unsigned long count)
+{
+       int value;
+       int remain = count;
+       int lcd_out = -1;
+       int crt_out = -1;
+       int tv_out = -1;
+       u32 hci_result;
+       u32 video_out;
+
+       /* scan expression.  Multiple expressions may be delimited with ;
+        *
+        *  NOTE: to keep scanning simple, invalid fields are ignored
+        */
+       while (remain) {
+               if (sscanf(buffer, " lcd_out : %i", &value) == 1)
+                       lcd_out = value & 1;
+               else if (sscanf(buffer, " crt_out : %i", &value) == 1)
+                       crt_out = value & 1;
+               else if (sscanf(buffer, " tv_out : %i", &value) == 1)
+                       tv_out = value & 1;
+               /* advance to one character past the next ; */
+               do {
+                       ++buffer;
+                       --remain;
+               }
+               while (remain && *(buffer - 1) != ';');
+       }
+
+       hci_read1(HCI_VIDEO_OUT, &video_out, &hci_result);
+       if (hci_result == HCI_SUCCESS) {
+               unsigned int new_video_out = video_out;
+               if (lcd_out != -1)
+                       _set_bit(&new_video_out, HCI_VIDEO_OUT_LCD, lcd_out);
+               if (crt_out != -1)
+                       _set_bit(&new_video_out, HCI_VIDEO_OUT_CRT, crt_out);
+               if (tv_out != -1)
+                       _set_bit(&new_video_out, HCI_VIDEO_OUT_TV, tv_out);
+               /* To avoid unnecessary video disruption, only write the new
+                * video setting if something changed. */
+               if (new_video_out != video_out)
+                       write_acpi_int(METHOD_VIDEO_OUT, new_video_out);
+       } else {
+               return -EFAULT;
+       }
+
+       return count;
+}
+
+static char *read_fan(char *p)
+{
+       u32 hci_result;
+       u32 value;
+
+       hci_read1(HCI_FAN, &value, &hci_result);
+       if (hci_result == HCI_SUCCESS) {
+               p += sprintf(p, "running:                 %d\n", (value > 0));
+               p += sprintf(p, "force_on:                %d\n", force_fan);
+       } else {
+               printk(MY_ERR "Error reading fan status\n");
+       }
+
+       return p;
+}
+
+static unsigned long write_fan(const char *buffer, unsigned long count)
+{
+       int value;
+       u32 hci_result;
+
+       if (sscanf(buffer, " force_on : %i", &value) == 1 &&
+           value >= 0 && value <= 1) {
+               hci_write1(HCI_FAN, value, &hci_result);
+               if (hci_result != HCI_SUCCESS)
+                       return -EFAULT;
+               else
+                       force_fan = value;
+       } else {
+               return -EINVAL;
+       }
+
+       return count;
+}
+
+static char *read_keys(char *p)
+{
+       u32 hci_result;
+       u32 value;
+
+       if (!key_event_valid) {
+               hci_read1(HCI_SYSTEM_EVENT, &value, &hci_result);
+               if (hci_result == HCI_SUCCESS) {
+                       key_event_valid = 1;
+                       last_key_event = value;
+               } else if (hci_result == HCI_EMPTY) {
+                       /* better luck next time */
+               } else if (hci_result == HCI_NOT_SUPPORTED) {
+                       /* This is a workaround for an unresolved issue on
+                        * some machines where system events sporadically
+                        * become disabled. */
+                       hci_write1(HCI_SYSTEM_EVENT, 1, &hci_result);
+                       printk(MY_NOTICE "Re-enabled hotkeys\n");
+               } else {
+                       printk(MY_ERR "Error reading hotkey status\n");
+                       goto end;
+               }
+       }
+
+       p += sprintf(p, "hotkey_ready:            %d\n", key_event_valid);
+       p += sprintf(p, "hotkey:                  0x%04x\n", last_key_event);
+
+      end:
+       return p;
+}
+
+static unsigned long write_keys(const char *buffer, unsigned long count)
+{
+       int value;
+
+       if (sscanf(buffer, " hotkey_ready : %i", &value) == 1 && value == 0) {
+               key_event_valid = 0;
+       } else {
+               return -EINVAL;
+       }
+
+       return count;
+}
+
+static char *read_version(char *p)
+{
+       p += sprintf(p, "driver:                  %s\n", TOSHIBA_ACPI_VERSION);
+       p += sprintf(p, "proc_interface:          %d\n",
+                    PROC_INTERFACE_VERSION);
+       return p;
+}
+
+/* proc and module init
+ */
+
+#define PROC_TOSHIBA           "toshiba"
+
+static ProcItem proc_items[] = {
+       {"lcd", read_lcd, write_lcd},
+       {"video", read_video, write_video},
+       {"fan", read_fan, write_fan},
+       {"keys", read_keys, write_keys},
+       {"version", read_version, NULL},
+       {NULL}
+};
+
+static acpi_status __init add_device(void)
+{
+       struct proc_dir_entry *proc;
+       ProcItem *item;
+
+       for (item = proc_items; item->name; ++item) {
+               proc = create_proc_read_entry(item->name,
+                                             S_IFREG | S_IRUGO | S_IWUSR,
+                                             toshiba_proc_dir,
+                                             (read_proc_t *) dispatch_read,
+                                             item);
+               if (proc)
+                       proc->owner = THIS_MODULE;
+               if (proc && item->write_func)
+                       proc->write_proc = (write_proc_t *) dispatch_write;
+       }
+
+       return AE_OK;
+}
+
+static acpi_status remove_device(void)
+{
+       ProcItem *item;
+
+       for (item = proc_items; item->name; ++item)
+               remove_proc_entry(item->name, toshiba_proc_dir);
+       return AE_OK;
+}
+
+static struct backlight_ops toshiba_backlight_data = {
+        .get_brightness = get_lcd,
+        .update_status  = set_lcd_status,
+};
+
+static void toshiba_acpi_exit(void)
+{
+       if (toshiba_acpi.poll_dev) {
+               input_unregister_polled_device(toshiba_acpi.poll_dev);
+               input_free_polled_device(toshiba_acpi.poll_dev);
+       }
+
+       if (toshiba_acpi.rfk_dev)
+               rfkill_unregister(toshiba_acpi.rfk_dev);
+
+       if (toshiba_backlight_device)
+               backlight_device_unregister(toshiba_backlight_device);
+
+       remove_device();
+
+       if (toshiba_proc_dir)
+               remove_proc_entry(PROC_TOSHIBA, acpi_root_dir);
+
+       platform_device_unregister(toshiba_acpi.p_dev);
+
+       return;
+}
+
+static int __init toshiba_acpi_init(void)
+{
+       acpi_status status = AE_OK;
+       u32 hci_result;
+       bool bt_present;
+       bool bt_on;
+       bool radio_on;
+       int ret = 0;
+
+       if (acpi_disabled)
+               return -ENODEV;
+
+       /* simple device detection: look for HCI method */
+       if (is_valid_acpi_path(METHOD_HCI_1))
+               method_hci = METHOD_HCI_1;
+       else if (is_valid_acpi_path(METHOD_HCI_2))
+               method_hci = METHOD_HCI_2;
+       else
+               return -ENODEV;
+
+       printk(MY_INFO "Toshiba Laptop ACPI Extras version %s\n",
+              TOSHIBA_ACPI_VERSION);
+       printk(MY_INFO "    HCI method: %s\n", method_hci);
+
+       mutex_init(&toshiba_acpi.mutex);
+
+       toshiba_acpi.p_dev = platform_device_register_simple("toshiba_acpi",
+                                                             -1, NULL, 0);
+       if (IS_ERR(toshiba_acpi.p_dev)) {
+               ret = PTR_ERR(toshiba_acpi.p_dev);
+               printk(MY_ERR "unable to register platform device\n");
+               toshiba_acpi.p_dev = NULL;
+               toshiba_acpi_exit();
+               return ret;
+       }
+
+       force_fan = 0;
+       key_event_valid = 0;
+
+       /* enable event fifo */
+       hci_write1(HCI_SYSTEM_EVENT, 1, &hci_result);
+
+       toshiba_proc_dir = proc_mkdir(PROC_TOSHIBA, acpi_root_dir);
+       if (!toshiba_proc_dir) {
+               toshiba_acpi_exit();
+               return -ENODEV;
+       } else {
+               toshiba_proc_dir->owner = THIS_MODULE;
+               status = add_device();
+               if (ACPI_FAILURE(status)) {
+                       toshiba_acpi_exit();
+                       return -ENODEV;
+               }
+       }
+
+       toshiba_backlight_device = backlight_device_register("toshiba",
+                                               &toshiba_acpi.p_dev->dev,
+                                               NULL,
+                                               &toshiba_backlight_data);
+        if (IS_ERR(toshiba_backlight_device)) {
+               ret = PTR_ERR(toshiba_backlight_device);
+
+               printk(KERN_ERR "Could not register toshiba backlight device\n");
+               toshiba_backlight_device = NULL;
+               toshiba_acpi_exit();
+               return ret;
+       }
+        toshiba_backlight_device->props.max_brightness = HCI_LCD_BRIGHTNESS_LEVELS - 1;
+
+       /* Register rfkill switch for Bluetooth */
+       if (hci_get_bt_present(&bt_present) == HCI_SUCCESS && bt_present) {
+               toshiba_acpi.rfk_dev = rfkill_allocate(&toshiba_acpi.p_dev->dev,
+                                                       RFKILL_TYPE_BLUETOOTH);
+               if (!toshiba_acpi.rfk_dev) {
+                       printk(MY_ERR "unable to allocate rfkill device\n");
+                       toshiba_acpi_exit();
+                       return -ENOMEM;
+               }
+
+               toshiba_acpi.rfk_dev->name = toshiba_acpi.bt_name;
+               toshiba_acpi.rfk_dev->toggle_radio = bt_rfkill_toggle_radio;
+               toshiba_acpi.rfk_dev->user_claim_unsupported = 1;
+               toshiba_acpi.rfk_dev->data = &toshiba_acpi;
+
+               if (hci_get_bt_on(&bt_on) == HCI_SUCCESS && bt_on) {
+                       toshiba_acpi.rfk_dev->state = RFKILL_STATE_UNBLOCKED;
+               } else if (hci_get_radio_state(&radio_on) == HCI_SUCCESS &&
+                          radio_on) {
+                       toshiba_acpi.rfk_dev->state = RFKILL_STATE_SOFT_BLOCKED;
+               } else {
+                       toshiba_acpi.rfk_dev->state = RFKILL_STATE_HARD_BLOCKED;
+               }
+
+               ret = rfkill_register(toshiba_acpi.rfk_dev);
+               if (ret) {
+                       printk(MY_ERR "unable to register rfkill device\n");
+                       toshiba_acpi_exit();
+                       return -ENOMEM;
+               }
+
+               /* Register input device for kill switch */
+               toshiba_acpi.poll_dev = input_allocate_polled_device();
+               if (!toshiba_acpi.poll_dev) {
+                       printk(MY_ERR
+                              "unable to allocate kill-switch input device\n");
+                       toshiba_acpi_exit();
+                       return -ENOMEM;
+               }
+               toshiba_acpi.poll_dev->private = &toshiba_acpi;
+               toshiba_acpi.poll_dev->poll = bt_poll_rfkill;
+               toshiba_acpi.poll_dev->poll_interval = 1000; /* msecs */
+
+               toshiba_acpi.poll_dev->input->name = toshiba_acpi.rfk_name;
+               toshiba_acpi.poll_dev->input->id.bustype = BUS_HOST;
+               /* Toshiba USB ID */
+               toshiba_acpi.poll_dev->input->id.vendor = 0x0930;
+               set_bit(EV_SW, toshiba_acpi.poll_dev->input->evbit);
+               set_bit(SW_RFKILL_ALL, toshiba_acpi.poll_dev->input->swbit);
+               input_report_switch(toshiba_acpi.poll_dev->input,
+                                   SW_RFKILL_ALL, TRUE);
+               input_sync(toshiba_acpi.poll_dev->input);
+
+               ret = input_register_polled_device(toshiba_acpi.poll_dev);
+               if (ret) {
+                       printk(MY_ERR
+                              "unable to register kill-switch input device\n");
+                       toshiba_acpi_exit();
+                       return ret;
+               }
+       }
+
+       return 0;
+}
+
+module_init(toshiba_acpi_init);
+module_exit(toshiba_acpi_exit);
diff --git a/drivers/platform/x86/wmi.c b/drivers/platform/x86/wmi.c
new file mode 100644 (file)
index 0000000..8a8b377
--- /dev/null
@@ -0,0 +1,747 @@
+/*
+ *  ACPI-WMI mapping driver
+ *
+ *  Copyright (C) 2007-2008 Carlos Corbacho <carlos@strangeworlds.co.uk>
+ *
+ *  GUID parsing code from ldm.c is:
+ *   Copyright (C) 2001,2002 Richard Russon <ldm@flatcap.org>
+ *   Copyright (c) 2001-2007 Anton Altaparmakov
+ *   Copyright (C) 2001,2002 Jakob Kemi <jakob.kemi@telia.com>
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ *
+ *  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.
+ *
+ * ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
+ */
+
+#include <linux/kernel.h>
+#include <linux/init.h>
+#include <linux/types.h>
+#include <linux/list.h>
+#include <linux/acpi.h>
+#include <acpi/acpi_bus.h>
+#include <acpi/acpi_drivers.h>
+
+ACPI_MODULE_NAME("wmi");
+MODULE_AUTHOR("Carlos Corbacho");
+MODULE_DESCRIPTION("ACPI-WMI Mapping Driver");
+MODULE_LICENSE("GPL");
+
+#define ACPI_WMI_CLASS "wmi"
+
+#undef PREFIX
+#define PREFIX "ACPI: WMI: "
+
+static DEFINE_MUTEX(wmi_data_lock);
+
+struct guid_block {
+       char guid[16];
+       union {
+               char object_id[2];
+               struct {
+                       unsigned char notify_id;
+                       unsigned char reserved;
+               };
+       };
+       u8 instance_count;
+       u8 flags;
+};
+
+struct wmi_block {
+       struct list_head list;
+       struct guid_block gblock;
+       acpi_handle handle;
+       wmi_notify_handler handler;
+       void *handler_data;
+};
+
+static struct wmi_block wmi_blocks;
+
+/*
+ * If the GUID data block is marked as expensive, we must enable and
+ * explicitily disable data collection.
+ */
+#define ACPI_WMI_EXPENSIVE   0x1
+#define ACPI_WMI_METHOD      0x2       /* GUID is a method */
+#define ACPI_WMI_STRING      0x4       /* GUID takes & returns a string */
+#define ACPI_WMI_EVENT       0x8       /* GUID is an event */
+
+static int acpi_wmi_remove(struct acpi_device *device, int type);
+static int acpi_wmi_add(struct acpi_device *device);
+
+static const struct acpi_device_id wmi_device_ids[] = {
+       {"PNP0C14", 0},
+       {"pnp0c14", 0},
+       {"", 0},
+};
+MODULE_DEVICE_TABLE(acpi, wmi_device_ids);
+
+static struct acpi_driver acpi_wmi_driver = {
+       .name = "wmi",
+       .class = ACPI_WMI_CLASS,
+       .ids = wmi_device_ids,
+       .ops = {
+               .add = acpi_wmi_add,
+               .remove = acpi_wmi_remove,
+               },
+};
+
+/*
+ * GUID parsing functions
+ */
+
+/**
+ * wmi_parse_hexbyte - Convert a ASCII hex number to a byte
+ * @src:  Pointer to at least 2 characters to convert.
+ *
+ * Convert a two character ASCII hex string to a number.
+ *
+ * Return:  0-255  Success, the byte was parsed correctly
+ *          -1     Error, an invalid character was supplied
+ */
+static int wmi_parse_hexbyte(const u8 *src)
+{
+       unsigned int x; /* For correct wrapping */
+       int h;
+
+       /* high part */
+       x = src[0];
+       if (x - '0' <= '9' - '0') {
+               h = x - '0';
+       } else if (x - 'a' <= 'f' - 'a') {
+               h = x - 'a' + 10;
+       } else if (x - 'A' <= 'F' - 'A') {
+               h = x - 'A' + 10;
+       } else {
+               return -1;
+       }
+       h <<= 4;
+
+       /* low part */
+       x = src[1];
+       if (x - '0' <= '9' - '0')
+               return h | (x - '0');
+       if (x - 'a' <= 'f' - 'a')
+               return h | (x - 'a' + 10);
+       if (x - 'A' <= 'F' - 'A')
+               return h | (x - 'A' + 10);
+       return -1;
+}
+
+/**
+ * wmi_swap_bytes - Rearrange GUID bytes to match GUID binary
+ * @src:   Memory block holding binary GUID (16 bytes)
+ * @dest:  Memory block to hold byte swapped binary GUID (16 bytes)
+ *
+ * Byte swap a binary GUID to match it's real GUID value
+ */
+static void wmi_swap_bytes(u8 *src, u8 *dest)
+{
+       int i;
+
+       for (i = 0; i <= 3; i++)
+               memcpy(dest + i, src + (3 - i), 1);
+
+       for (i = 0; i <= 1; i++)
+               memcpy(dest + 4 + i, src + (5 - i), 1);
+
+       for (i = 0; i <= 1; i++)
+               memcpy(dest + 6 + i, src + (7 - i), 1);
+
+       memcpy(dest + 8, src + 8, 8);
+}
+
+/**
+ * wmi_parse_guid - Convert GUID from ASCII to binary
+ * @src:   36 char string of the form fa50ff2b-f2e8-45de-83fa-65417f2f49ba
+ * @dest:  Memory block to hold binary GUID (16 bytes)
+ *
+ * N.B. The GUID need not be NULL terminated.
+ *
+ * Return:  'true'   @dest contains binary GUID
+ *          'false'  @dest contents are undefined
+ */
+static bool wmi_parse_guid(const u8 *src, u8 *dest)
+{
+       static const int size[] = { 4, 2, 2, 2, 6 };
+       int i, j, v;
+
+       if (src[8]  != '-' || src[13] != '-' ||
+               src[18] != '-' || src[23] != '-')
+               return false;
+
+       for (j = 0; j < 5; j++, src++) {
+               for (i = 0; i < size[j]; i++, src += 2, *dest++ = v) {
+                       v = wmi_parse_hexbyte(src);
+                       if (v < 0)
+                               return false;
+               }
+       }
+
+       return true;
+}
+
+static bool find_guid(const char *guid_string, struct wmi_block **out)
+{
+       char tmp[16], guid_input[16];
+       struct wmi_block *wblock;
+       struct guid_block *block;
+       struct list_head *p;
+
+       wmi_parse_guid(guid_string, tmp);
+       wmi_swap_bytes(tmp, guid_input);
+
+       list_for_each(p, &wmi_blocks.list) {
+               wblock = list_entry(p, struct wmi_block, list);
+               block = &wblock->gblock;
+
+               if (memcmp(block->guid, guid_input, 16) == 0) {
+                       if (out)
+                               *out = wblock;
+                       return 1;
+               }
+       }
+       return 0;
+}
+
+static acpi_status wmi_method_enable(struct wmi_block *wblock, int enable)
+{
+       struct guid_block *block = NULL;
+       char method[5];
+       struct acpi_object_list input;
+       union acpi_object params[1];
+       acpi_status status;
+       acpi_handle handle;
+
+       block = &wblock->gblock;
+       handle = wblock->handle;
+
+       if (!block)
+               return AE_NOT_EXIST;
+
+       input.count = 1;
+       input.pointer = params;
+       params[0].type = ACPI_TYPE_INTEGER;
+       params[0].integer.value = enable;
+
+       snprintf(method, 5, "WE%02X", block->notify_id);
+       status = acpi_evaluate_object(handle, method, &input, NULL);
+
+       if (status != AE_OK && status != AE_NOT_FOUND)
+               return status;
+       else
+               return AE_OK;
+}
+
+/*
+ * Exported WMI functions
+ */
+/**
+ * wmi_evaluate_method - Evaluate a WMI method
+ * @guid_string: 36 char string of the form fa50ff2b-f2e8-45de-83fa-65417f2f49ba
+ * @instance: Instance index
+ * @method_id: Method ID to call
+ * &in: Buffer containing input for the method call
+ * &out: Empty buffer to return the method results
+ *
+ * Call an ACPI-WMI method
+ */
+acpi_status wmi_evaluate_method(const char *guid_string, u8 instance,
+u32 method_id, const struct acpi_buffer *in, struct acpi_buffer *out)
+{
+       struct guid_block *block = NULL;
+       struct wmi_block *wblock = NULL;
+       acpi_handle handle;
+       acpi_status status;
+       struct acpi_object_list input;
+       union acpi_object params[3];
+       char method[4] = "WM";
+
+       if (!find_guid(guid_string, &wblock))
+               return AE_ERROR;
+
+       block = &wblock->gblock;
+       handle = wblock->handle;
+
+       if (!(block->flags & ACPI_WMI_METHOD))
+               return AE_BAD_DATA;
+
+       if (block->instance_count < instance)
+               return AE_BAD_PARAMETER;
+
+       input.count = 2;
+       input.pointer = params;
+       params[0].type = ACPI_TYPE_INTEGER;
+       params[0].integer.value = instance;
+       params[1].type = ACPI_TYPE_INTEGER;
+       params[1].integer.value = method_id;
+
+       if (in) {
+               input.count = 3;
+
+               if (block->flags & ACPI_WMI_STRING) {
+                       params[2].type = ACPI_TYPE_STRING;
+               } else {
+                       params[2].type = ACPI_TYPE_BUFFER;
+               }
+               params[2].buffer.length = in->length;
+               params[2].buffer.pointer = in->pointer;
+       }
+
+       strncat(method, block->object_id, 2);
+
+       status = acpi_evaluate_object(handle, method, &input, out);
+
+       return status;
+}
+EXPORT_SYMBOL_GPL(wmi_evaluate_method);
+
+/**
+ * wmi_query_block - Return contents of a WMI block
+ * @guid_string: 36 char string of the form fa50ff2b-f2e8-45de-83fa-65417f2f49ba
+ * @instance: Instance index
+ * &out: Empty buffer to return the contents of the data block to
+ *
+ * Return the contents of an ACPI-WMI data block to a buffer
+ */
+acpi_status wmi_query_block(const char *guid_string, u8 instance,
+struct acpi_buffer *out)
+{
+       struct guid_block *block = NULL;
+       struct wmi_block *wblock = NULL;
+       acpi_handle handle, wc_handle;
+       acpi_status status, wc_status = AE_ERROR;
+       struct acpi_object_list input, wc_input;
+       union acpi_object wc_params[1], wq_params[1];
+       char method[4];
+       char wc_method[4] = "WC";
+
+       if (!guid_string || !out)
+               return AE_BAD_PARAMETER;
+
+       if (!find_guid(guid_string, &wblock))
+               return AE_ERROR;
+
+       block = &wblock->gblock;
+       handle = wblock->handle;
+
+       if (block->instance_count < instance)
+               return AE_BAD_PARAMETER;
+
+       /* Check GUID is a data block */
+       if (block->flags & (ACPI_WMI_EVENT | ACPI_WMI_METHOD))
+               return AE_ERROR;
+
+       input.count = 1;
+       input.pointer = wq_params;
+       wq_params[0].type = ACPI_TYPE_INTEGER;
+       wq_params[0].integer.value = instance;
+
+       /*
+        * If ACPI_WMI_EXPENSIVE, call the relevant WCxx method first to
+        * enable collection.
+        */
+       if (block->flags & ACPI_WMI_EXPENSIVE) {
+               wc_input.count = 1;
+               wc_input.pointer = wc_params;
+               wc_params[0].type = ACPI_TYPE_INTEGER;
+               wc_params[0].integer.value = 1;
+
+               strncat(wc_method, block->object_id, 2);
+
+               /*
+                * Some GUIDs break the specification by declaring themselves
+                * expensive, but have no corresponding WCxx method. So we
+                * should not fail if this happens.
+                */
+               wc_status = acpi_get_handle(handle, wc_method, &wc_handle);
+               if (ACPI_SUCCESS(wc_status))
+                       wc_status = acpi_evaluate_object(handle, wc_method,
+                               &wc_input, NULL);
+       }
+
+       strcpy(method, "WQ");
+       strncat(method, block->object_id, 2);
+
+       status = acpi_evaluate_object(handle, method, &input, out);
+
+       /*
+        * If ACPI_WMI_EXPENSIVE, call the relevant WCxx method, even if
+        * the WQxx method failed - we should disable collection anyway.
+        */
+       if ((block->flags & ACPI_WMI_EXPENSIVE) && ACPI_SUCCESS(wc_status)) {
+               wc_params[0].integer.value = 0;
+               status = acpi_evaluate_object(handle,
+               wc_method, &wc_input, NULL);
+       }
+
+       return status;
+}
+EXPORT_SYMBOL_GPL(wmi_query_block);
+
+/**
+ * wmi_set_block - Write to a WMI block
+ * @guid_string: 36 char string of the form fa50ff2b-f2e8-45de-83fa-65417f2f49ba
+ * @instance: Instance index
+ * &in: Buffer containing new values for the data block
+ *
+ * Write the contents of the input buffer to an ACPI-WMI data block
+ */
+acpi_status wmi_set_block(const char *guid_string, u8 instance,
+const struct acpi_buffer *in)
+{
+       struct guid_block *block = NULL;
+       struct wmi_block *wblock = NULL;
+       acpi_handle handle;
+       struct acpi_object_list input;
+       union acpi_object params[2];
+       char method[4] = "WS";
+
+       if (!guid_string || !in)
+               return AE_BAD_DATA;
+
+       if (!find_guid(guid_string, &wblock))
+               return AE_ERROR;
+
+       block = &wblock->gblock;
+       handle = wblock->handle;
+
+       if (block->instance_count < instance)
+               return AE_BAD_PARAMETER;
+
+       /* Check GUID is a data block */
+       if (block->flags & (ACPI_WMI_EVENT | ACPI_WMI_METHOD))
+               return AE_ERROR;
+
+       input.count = 2;
+       input.pointer = params;
+       params[0].type = ACPI_TYPE_INTEGER;
+       params[0].integer.value = instance;
+
+       if (block->flags & ACPI_WMI_STRING) {
+               params[1].type = ACPI_TYPE_STRING;
+       } else {
+               params[1].type = ACPI_TYPE_BUFFER;
+       }
+       params[1].buffer.length = in->length;
+       params[1].buffer.pointer = in->pointer;
+
+       strncat(method, block->object_id, 2);
+
+       return acpi_evaluate_object(handle, method, &input, NULL);
+}
+EXPORT_SYMBOL_GPL(wmi_set_block);
+
+/**
+ * wmi_install_notify_handler - Register handler for WMI events
+ * @handler: Function to handle notifications
+ * @data: Data to be returned to handler when event is fired
+ *
+ * Register a handler for events sent to the ACPI-WMI mapper device.
+ */
+acpi_status wmi_install_notify_handler(const char *guid,
+wmi_notify_handler handler, void *data)
+{
+       struct wmi_block *block;
+       acpi_status status;
+
+       if (!guid || !handler)
+               return AE_BAD_PARAMETER;
+
+       find_guid(guid, &block);
+       if (!block)
+               return AE_NOT_EXIST;
+
+       if (block->handler)
+               return AE_ALREADY_ACQUIRED;
+
+       block->handler = handler;
+       block->handler_data = data;
+
+       status = wmi_method_enable(block, 1);
+
+       return status;
+}
+EXPORT_SYMBOL_GPL(wmi_install_notify_handler);
+
+/**
+ * wmi_uninstall_notify_handler - Unregister handler for WMI events
+ *
+ * Unregister handler for events sent to the ACPI-WMI mapper device.
+ */
+acpi_status wmi_remove_notify_handler(const char *guid)
+{
+       struct wmi_block *block;
+       acpi_status status;
+
+       if (!guid)
+               return AE_BAD_PARAMETER;
+
+       find_guid(guid, &block);
+       if (!block)
+               return AE_NOT_EXIST;
+
+       if (!block->handler)
+               return AE_NULL_ENTRY;
+
+       status = wmi_method_enable(block, 0);
+
+       block->handler = NULL;
+       block->handler_data = NULL;
+
+       return status;
+}
+EXPORT_SYMBOL_GPL(wmi_remove_notify_handler);
+
+/**
+ * wmi_get_event_data - Get WMI data associated with an event
+ *
+ * @event - Event to find
+ * &out - Buffer to hold event data
+ *
+ * Returns extra data associated with an event in WMI.
+ */
+acpi_status wmi_get_event_data(u32 event, struct acpi_buffer *out)
+{
+       struct acpi_object_list input;
+       union acpi_object params[1];
+       struct guid_block *gblock;
+       struct wmi_block *wblock;
+       struct list_head *p;
+
+       input.count = 1;
+       input.pointer = params;
+       params[0].type = ACPI_TYPE_INTEGER;
+       params[0].integer.value = event;
+
+       list_for_each(p, &wmi_blocks.list) {
+               wblock = list_entry(p, struct wmi_block, list);
+               gblock = &wblock->gblock;
+
+               if ((gblock->flags & ACPI_WMI_EVENT) &&
+                       (gblock->notify_id == event))
+                       return acpi_evaluate_object(wblock->handle, "_WED",
+                               &input, out);
+       }
+
+       return AE_NOT_FOUND;
+}
+EXPORT_SYMBOL_GPL(wmi_get_event_data);
+
+/**
+ * wmi_has_guid - Check if a GUID is available
+ * @guid_string: 36 char string of the form fa50ff2b-f2e8-45de-83fa-65417f2f49ba
+ *
+ * Check if a given GUID is defined by _WDG
+ */
+bool wmi_has_guid(const char *guid_string)
+{
+       return find_guid(guid_string, NULL);
+}
+EXPORT_SYMBOL_GPL(wmi_has_guid);
+
+/*
+ * Parse the _WDG method for the GUID data blocks
+ */
+static __init acpi_status parse_wdg(acpi_handle handle)
+{
+       struct acpi_buffer out = {ACPI_ALLOCATE_BUFFER, NULL};
+       union acpi_object *obj;
+       struct guid_block *gblock;
+       struct wmi_block *wblock;
+       acpi_status status;
+       u32 i, total;
+
+       status = acpi_evaluate_object(handle, "_WDG", NULL, &out);
+
+       if (ACPI_FAILURE(status))
+               return status;
+
+       obj = (union acpi_object *) out.pointer;
+
+       if (obj->type != ACPI_TYPE_BUFFER)
+               return AE_ERROR;
+
+       total = obj->buffer.length / sizeof(struct guid_block);
+
+       gblock = kzalloc(obj->buffer.length, GFP_KERNEL);
+       if (!gblock)
+               return AE_NO_MEMORY;
+
+       memcpy(gblock, obj->buffer.pointer, obj->buffer.length);
+
+       for (i = 0; i < total; i++) {
+               wblock = kzalloc(sizeof(struct wmi_block), GFP_KERNEL);
+               if (!wblock)
+                       return AE_NO_MEMORY;
+
+               wblock->gblock = gblock[i];
+               wblock->handle = handle;
+               list_add_tail(&wblock->list, &wmi_blocks.list);
+       }
+
+       kfree(out.pointer);
+       kfree(gblock);
+
+       return status;
+}
+
+/*
+ * WMI can have EmbeddedControl access regions. In which case, we just want to
+ * hand these off to the EC driver.
+ */
+static acpi_status
+acpi_wmi_ec_space_handler(u32 function, acpi_physical_address address,
+                     u32 bits, acpi_integer * value,
+                     void *handler_context, void *region_context)
+{
+       int result = 0, i = 0;
+       u8 temp = 0;
+
+       if ((address > 0xFF) || !value)
+               return AE_BAD_PARAMETER;
+
+       if (function != ACPI_READ && function != ACPI_WRITE)
+               return AE_BAD_PARAMETER;
+
+       if (bits != 8)
+               return AE_BAD_PARAMETER;
+
+       if (function == ACPI_READ) {
+               result = ec_read(address, &temp);
+               (*value) |= ((acpi_integer)temp) << i;
+       } else {
+               temp = 0xff & ((*value) >> i);
+               result = ec_write(address, temp);
+       }
+
+       switch (result) {
+       case -EINVAL:
+               return AE_BAD_PARAMETER;
+               break;
+       case -ENODEV:
+               return AE_NOT_FOUND;
+               break;
+       case -ETIME:
+               return AE_TIME;
+               break;
+       default:
+               return AE_OK;
+       }
+}
+
+static void acpi_wmi_notify(acpi_handle handle, u32 event, void *data)
+{
+       struct guid_block *block;
+       struct wmi_block *wblock;
+       struct list_head *p;
+       struct acpi_device *device = data;
+
+       list_for_each(p, &wmi_blocks.list) {
+               wblock = list_entry(p, struct wmi_block, list);
+               block = &wblock->gblock;
+
+               if ((block->flags & ACPI_WMI_EVENT) &&
+                       (block->notify_id == event)) {
+                       if (wblock->handler)
+                               wblock->handler(event, wblock->handler_data);
+
+                       acpi_bus_generate_netlink_event(
+                               device->pnp.device_class, dev_name(&device->dev),
+                               event, 0);
+                       break;
+               }
+       }
+}
+
+static int acpi_wmi_remove(struct acpi_device *device, int type)
+{
+       acpi_remove_notify_handler(device->handle, ACPI_DEVICE_NOTIFY,
+               acpi_wmi_notify);
+
+       acpi_remove_address_space_handler(device->handle,
+                               ACPI_ADR_SPACE_EC, &acpi_wmi_ec_space_handler);
+
+       return 0;
+}
+
+static int __init acpi_wmi_add(struct acpi_device *device)
+{
+       acpi_status status;
+       int result = 0;
+
+       status = acpi_install_notify_handler(device->handle, ACPI_DEVICE_NOTIFY,
+               acpi_wmi_notify, device);
+       if (ACPI_FAILURE(status)) {
+               printk(KERN_ERR PREFIX "Error installing notify handler\n");
+               return -ENODEV;
+       }
+
+       status = acpi_install_address_space_handler(device->handle,
+                                                   ACPI_ADR_SPACE_EC,
+                                                   &acpi_wmi_ec_space_handler,
+                                                   NULL, NULL);
+       if (ACPI_FAILURE(status))
+               return -ENODEV;
+
+       status = parse_wdg(device->handle);
+       if (ACPI_FAILURE(status)) {
+               printk(KERN_ERR PREFIX "Error installing EC region handler\n");
+               return -ENODEV;
+       }
+
+       return result;
+}
+
+static int __init acpi_wmi_init(void)
+{
+       acpi_status result;
+
+       INIT_LIST_HEAD(&wmi_blocks.list);
+
+       if (acpi_disabled)
+               return -ENODEV;
+
+       result = acpi_bus_register_driver(&acpi_wmi_driver);
+
+       if (result < 0) {
+               printk(KERN_INFO PREFIX "Error loading mapper\n");
+       } else {
+               printk(KERN_INFO PREFIX "Mapper loaded\n");
+       }
+
+       return result;
+}
+
+static void __exit acpi_wmi_exit(void)
+{
+       struct list_head *p, *tmp;
+       struct wmi_block *wblock;
+
+       acpi_bus_unregister_driver(&acpi_wmi_driver);
+
+       list_for_each_safe(p, tmp, &wmi_blocks.list) {
+               wblock = list_entry(p, struct wmi_block, list);
+
+               list_del(p);
+               kfree(wblock);
+       }
+
+       printk(KERN_INFO PREFIX "Mapper unloaded\n");
+}
+
+subsys_initcall(acpi_wmi_init);
+module_exit(acpi_wmi_exit);