cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

asus-laptop.c (52182B)


      1// SPDX-License-Identifier: GPL-2.0-or-later
      2/*
      3 *  asus-laptop.c - Asus Laptop Support
      4 *
      5 *  Copyright (C) 2002-2005 Julien Lerouge, 2003-2006 Karol Kozimor
      6 *  Copyright (C) 2006-2007 Corentin Chary
      7 *  Copyright (C) 2011 Wind River Systems
      8 *
      9 *  The development page for this driver is located at
     10 *  http://sourceforge.net/projects/acpi4asus/
     11 *
     12 *  Credits:
     13 *  Pontus Fuchs   - Helper functions, cleanup
     14 *  Johann Wiesner - Small compile fixes
     15 *  John Belmonte  - ACPI code for Toshiba laptop was a good starting point.
     16 *  Eric Burghard  - LED display support for W1N
     17 *  Josh Green     - Light Sens support
     18 *  Thomas Tuttle  - His first patch for led support was very helpful
     19 *  Sam Lin        - GPS support
     20 */
     21
     22#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
     23
     24#include <linux/kernel.h>
     25#include <linux/module.h>
     26#include <linux/init.h>
     27#include <linux/types.h>
     28#include <linux/err.h>
     29#include <linux/proc_fs.h>
     30#include <linux/backlight.h>
     31#include <linux/fb.h>
     32#include <linux/leds.h>
     33#include <linux/platform_device.h>
     34#include <linux/uaccess.h>
     35#include <linux/input.h>
     36#include <linux/input/sparse-keymap.h>
     37#include <linux/rfkill.h>
     38#include <linux/slab.h>
     39#include <linux/dmi.h>
     40#include <linux/acpi.h>
     41#include <acpi/video.h>
     42
     43#define ASUS_LAPTOP_VERSION	"0.42"
     44
     45#define ASUS_LAPTOP_NAME	"Asus Laptop Support"
     46#define ASUS_LAPTOP_CLASS	"hotkey"
     47#define ASUS_LAPTOP_DEVICE_NAME	"Hotkey"
     48#define ASUS_LAPTOP_FILE	KBUILD_MODNAME
     49#define ASUS_LAPTOP_PREFIX	"\\_SB.ATKD."
     50
     51MODULE_AUTHOR("Julien Lerouge, Karol Kozimor, Corentin Chary");
     52MODULE_DESCRIPTION(ASUS_LAPTOP_NAME);
     53MODULE_LICENSE("GPL");
     54
     55/*
     56 * WAPF defines the behavior of the Fn+Fx wlan key
     57 * The significance of values is yet to be found, but
     58 * most of the time:
     59 * Bit | Bluetooth | WLAN
     60 *  0  | Hardware  | Hardware
     61 *  1  | Hardware  | Software
     62 *  4  | Software  | Software
     63 */
     64static uint wapf = 1;
     65module_param(wapf, uint, 0444);
     66MODULE_PARM_DESC(wapf, "WAPF value");
     67
     68static char *wled_type = "unknown";
     69static char *bled_type = "unknown";
     70
     71module_param(wled_type, charp, 0444);
     72MODULE_PARM_DESC(wled_type, "Set the wled type on boot "
     73		 "(unknown, led or rfkill). "
     74		 "default is unknown");
     75
     76module_param(bled_type, charp, 0444);
     77MODULE_PARM_DESC(bled_type, "Set the bled type on boot "
     78		 "(unknown, led or rfkill). "
     79		 "default is unknown");
     80
     81static int wlan_status = 1;
     82static int bluetooth_status = 1;
     83static int wimax_status = -1;
     84static int wwan_status = -1;
     85static int als_status;
     86
     87module_param(wlan_status, int, 0444);
     88MODULE_PARM_DESC(wlan_status, "Set the wireless status on boot "
     89		 "(0 = disabled, 1 = enabled, -1 = don't do anything). "
     90		 "default is -1");
     91
     92module_param(bluetooth_status, int, 0444);
     93MODULE_PARM_DESC(bluetooth_status, "Set the wireless status on boot "
     94		 "(0 = disabled, 1 = enabled, -1 = don't do anything). "
     95		 "default is -1");
     96
     97module_param(wimax_status, int, 0444);
     98MODULE_PARM_DESC(wimax_status, "Set the wireless status on boot "
     99		 "(0 = disabled, 1 = enabled, -1 = don't do anything). "
    100		 "default is -1");
    101
    102module_param(wwan_status, int, 0444);
    103MODULE_PARM_DESC(wwan_status, "Set the wireless status on boot "
    104		 "(0 = disabled, 1 = enabled, -1 = don't do anything). "
    105		 "default is -1");
    106
    107module_param(als_status, int, 0444);
    108MODULE_PARM_DESC(als_status, "Set the ALS status on boot "
    109		 "(0 = disabled, 1 = enabled). "
    110		 "default is 0");
    111
    112/*
    113 * Some events we use, same for all Asus
    114 */
    115#define ATKD_BRNUP_MIN		0x10
    116#define ATKD_BRNUP_MAX		0x1f
    117#define ATKD_BRNDOWN_MIN	0x20
    118#define ATKD_BRNDOWN_MAX	0x2f
    119#define ATKD_BRNDOWN		0x20
    120#define ATKD_BRNUP		0x2f
    121#define ATKD_LCD_ON	0x33
    122#define ATKD_LCD_OFF	0x34
    123
    124/*
    125 * Known bits returned by \_SB.ATKD.HWRS
    126 */
    127#define WL_HWRS		0x80
    128#define BT_HWRS		0x100
    129
    130/*
    131 * Flags for hotk status
    132 * WL_ON and BT_ON are also used for wireless_status()
    133 */
    134#define WL_RSTS		0x01	/* internal Wifi */
    135#define BT_RSTS		0x02	/* internal Bluetooth */
    136#define WM_RSTS		0x08    /* internal wimax */
    137#define WW_RSTS		0x20    /* internal wwan */
    138
    139/* WLED and BLED type */
    140#define TYPE_UNKNOWN	0
    141#define TYPE_LED	1
    142#define TYPE_RFKILL	2
    143
    144/* LED */
    145#define METHOD_MLED		"MLED"
    146#define METHOD_TLED		"TLED"
    147#define METHOD_RLED		"RLED"	/* W1JC */
    148#define METHOD_PLED		"PLED"	/* A7J */
    149#define METHOD_GLED		"GLED"	/* G1, G2 (probably) */
    150
    151/* LEDD */
    152#define METHOD_LEDD		"SLCM"
    153
    154/*
    155 * Bluetooth and WLAN
    156 * WLED and BLED are not handled like other XLED, because in some dsdt
    157 * they also control the WLAN/Bluetooth device.
    158 */
    159#define METHOD_WLAN		"WLED"
    160#define METHOD_BLUETOOTH	"BLED"
    161
    162/* WWAN and WIMAX */
    163#define METHOD_WWAN		"GSMC"
    164#define METHOD_WIMAX		"WMXC"
    165
    166#define METHOD_WL_STATUS	"RSTS"
    167
    168/* Brightness */
    169#define METHOD_BRIGHTNESS_SET	"SPLV"
    170#define METHOD_BRIGHTNESS_GET	"GPLV"
    171
    172/* Display */
    173#define METHOD_SWITCH_DISPLAY	"SDSP"
    174
    175#define METHOD_ALS_CONTROL	"ALSC" /* Z71A Z71V */
    176#define METHOD_ALS_LEVEL	"ALSL" /* Z71A Z71V */
    177
    178/* GPS */
    179/* R2H use different handle for GPS on/off */
    180#define METHOD_GPS_ON		"SDON"
    181#define METHOD_GPS_OFF		"SDOF"
    182#define METHOD_GPS_STATUS	"GPST"
    183
    184/* Keyboard light */
    185#define METHOD_KBD_LIGHT_SET	"SLKB"
    186#define METHOD_KBD_LIGHT_GET	"GLKB"
    187
    188/* For Pegatron Lucid tablet */
    189#define DEVICE_NAME_PEGA	"Lucid"
    190
    191#define METHOD_PEGA_ENABLE	"ENPR"
    192#define METHOD_PEGA_DISABLE	"DAPR"
    193#define PEGA_WLAN	0x00
    194#define PEGA_BLUETOOTH	0x01
    195#define PEGA_WWAN	0x02
    196#define PEGA_ALS	0x04
    197#define PEGA_ALS_POWER	0x05
    198
    199#define METHOD_PEGA_READ	"RDLN"
    200#define PEGA_READ_ALS_H	0x02
    201#define PEGA_READ_ALS_L	0x03
    202
    203#define PEGA_ACCEL_NAME "pega_accel"
    204#define PEGA_ACCEL_DESC "Pegatron Lucid Tablet Accelerometer"
    205#define METHOD_XLRX "XLRX"
    206#define METHOD_XLRY "XLRY"
    207#define METHOD_XLRZ "XLRZ"
    208#define PEGA_ACC_CLAMP 512 /* 1G accel is reported as ~256, so clamp to 2G */
    209#define PEGA_ACC_RETRIES 3
    210
    211/*
    212 * Define a specific led structure to keep the main structure clean
    213 */
    214struct asus_led {
    215	int wk;
    216	struct work_struct work;
    217	struct led_classdev led;
    218	struct asus_laptop *asus;
    219	const char *method;
    220};
    221
    222/*
    223 * Same thing for rfkill
    224 */
    225struct asus_rfkill {
    226	/* type of control. Maps to PEGA_* values or *_RSTS  */
    227	int control_id;
    228	struct rfkill *rfkill;
    229	struct asus_laptop *asus;
    230};
    231
    232/*
    233 * This is the main structure, we can use it to store anything interesting
    234 * about the hotk device
    235 */
    236struct asus_laptop {
    237	char *name;		/* laptop name */
    238
    239	struct acpi_table_header *dsdt_info;
    240	struct platform_device *platform_device;
    241	struct acpi_device *device;		/* the device we are in */
    242	struct backlight_device *backlight_device;
    243
    244	struct input_dev *inputdev;
    245	struct key_entry *keymap;
    246	struct input_dev *pega_accel_poll;
    247
    248	struct asus_led wled;
    249	struct asus_led bled;
    250	struct asus_led mled;
    251	struct asus_led tled;
    252	struct asus_led rled;
    253	struct asus_led pled;
    254	struct asus_led gled;
    255	struct asus_led kled;
    256	struct workqueue_struct *led_workqueue;
    257
    258	int wled_type;
    259	int bled_type;
    260	int wireless_status;
    261	bool have_rsts;
    262	bool is_pega_lucid;
    263	bool pega_acc_live;
    264	int pega_acc_x;
    265	int pega_acc_y;
    266	int pega_acc_z;
    267
    268	struct asus_rfkill wlan;
    269	struct asus_rfkill bluetooth;
    270	struct asus_rfkill wwan;
    271	struct asus_rfkill wimax;
    272	struct asus_rfkill gps;
    273
    274	acpi_handle handle;	/* the handle of the hotk device */
    275	u32 ledd_status;	/* status of the LED display */
    276	u8 light_level;		/* light sensor level */
    277	u8 light_switch;	/* light sensor switch value */
    278	u16 event_count[128];	/* count for each event TODO make this better */
    279};
    280
    281static const struct key_entry asus_keymap[] = {
    282	/* Lenovo SL Specific keycodes */
    283	{KE_KEY, 0x02, { KEY_SCREENLOCK } },
    284	{KE_KEY, 0x05, { KEY_WLAN } },
    285	{KE_KEY, 0x08, { KEY_F13 } },
    286	{KE_KEY, 0x09, { KEY_PROG2 } }, /* Dock */
    287	{KE_KEY, 0x17, { KEY_ZOOM } },
    288	{KE_KEY, 0x1f, { KEY_BATTERY } },
    289	/* End of Lenovo SL Specific keycodes */
    290	{KE_KEY, ATKD_BRNDOWN, { KEY_BRIGHTNESSDOWN } },
    291	{KE_KEY, ATKD_BRNUP, { KEY_BRIGHTNESSUP } },
    292	{KE_KEY, 0x30, { KEY_VOLUMEUP } },
    293	{KE_KEY, 0x31, { KEY_VOLUMEDOWN } },
    294	{KE_KEY, 0x32, { KEY_MUTE } },
    295	{KE_KEY, 0x33, { KEY_DISPLAYTOGGLE } }, /* LCD on */
    296	{KE_KEY, 0x34, { KEY_DISPLAY_OFF } }, /* LCD off */
    297	{KE_KEY, 0x40, { KEY_PREVIOUSSONG } },
    298	{KE_KEY, 0x41, { KEY_NEXTSONG } },
    299	{KE_KEY, 0x43, { KEY_STOPCD } }, /* Stop/Eject */
    300	{KE_KEY, 0x45, { KEY_PLAYPAUSE } },
    301	{KE_KEY, 0x4c, { KEY_MEDIA } }, /* WMP Key */
    302	{KE_KEY, 0x50, { KEY_EMAIL } },
    303	{KE_KEY, 0x51, { KEY_WWW } },
    304	{KE_KEY, 0x55, { KEY_CALC } },
    305	{KE_IGNORE, 0x57, },  /* Battery mode */
    306	{KE_IGNORE, 0x58, },  /* AC mode */
    307	{KE_KEY, 0x5C, { KEY_SCREENLOCK } },  /* Screenlock */
    308	{KE_KEY, 0x5D, { KEY_WLAN } }, /* WLAN Toggle */
    309	{KE_KEY, 0x5E, { KEY_WLAN } }, /* WLAN Enable */
    310	{KE_KEY, 0x5F, { KEY_WLAN } }, /* WLAN Disable */
    311	{KE_KEY, 0x60, { KEY_TOUCHPAD_ON } },
    312	{KE_KEY, 0x61, { KEY_SWITCHVIDEOMODE } }, /* SDSP LCD only */
    313	{KE_KEY, 0x62, { KEY_SWITCHVIDEOMODE } }, /* SDSP CRT only */
    314	{KE_KEY, 0x63, { KEY_SWITCHVIDEOMODE } }, /* SDSP LCD + CRT */
    315	{KE_KEY, 0x64, { KEY_SWITCHVIDEOMODE } }, /* SDSP TV */
    316	{KE_KEY, 0x65, { KEY_SWITCHVIDEOMODE } }, /* SDSP LCD + TV */
    317	{KE_KEY, 0x66, { KEY_SWITCHVIDEOMODE } }, /* SDSP CRT + TV */
    318	{KE_KEY, 0x67, { KEY_SWITCHVIDEOMODE } }, /* SDSP LCD + CRT + TV */
    319	{KE_KEY, 0x6A, { KEY_TOUCHPAD_TOGGLE } }, /* Lock Touchpad Fn + F9 */
    320	{KE_KEY, 0x6B, { KEY_TOUCHPAD_TOGGLE } }, /* Lock Touchpad */
    321	{KE_KEY, 0x6C, { KEY_SLEEP } }, /* Suspend */
    322	{KE_KEY, 0x6D, { KEY_SLEEP } }, /* Hibernate */
    323	{KE_IGNORE, 0x6E, },  /* Low Battery notification */
    324	{KE_KEY, 0x7D, { KEY_BLUETOOTH } }, /* Bluetooth Enable */
    325	{KE_KEY, 0x7E, { KEY_BLUETOOTH } }, /* Bluetooth Disable */
    326	{KE_KEY, 0x82, { KEY_CAMERA } },
    327	{KE_KEY, 0x88, { KEY_RFKILL  } }, /* Radio Toggle Key */
    328	{KE_KEY, 0x8A, { KEY_PROG1 } }, /* Color enhancement mode */
    329	{KE_KEY, 0x8C, { KEY_SWITCHVIDEOMODE } }, /* SDSP DVI only */
    330	{KE_KEY, 0x8D, { KEY_SWITCHVIDEOMODE } }, /* SDSP LCD + DVI */
    331	{KE_KEY, 0x8E, { KEY_SWITCHVIDEOMODE } }, /* SDSP CRT + DVI */
    332	{KE_KEY, 0x8F, { KEY_SWITCHVIDEOMODE } }, /* SDSP TV + DVI */
    333	{KE_KEY, 0x90, { KEY_SWITCHVIDEOMODE } }, /* SDSP LCD + CRT + DVI */
    334	{KE_KEY, 0x91, { KEY_SWITCHVIDEOMODE } }, /* SDSP LCD + TV + DVI */
    335	{KE_KEY, 0x92, { KEY_SWITCHVIDEOMODE } }, /* SDSP CRT + TV + DVI */
    336	{KE_KEY, 0x93, { KEY_SWITCHVIDEOMODE } }, /* SDSP LCD + CRT + TV + DVI */
    337	{KE_KEY, 0x95, { KEY_MEDIA } },
    338	{KE_KEY, 0x99, { KEY_PHONE } },
    339	{KE_KEY, 0xA0, { KEY_SWITCHVIDEOMODE } }, /* SDSP HDMI only */
    340	{KE_KEY, 0xA1, { KEY_SWITCHVIDEOMODE } }, /* SDSP LCD + HDMI */
    341	{KE_KEY, 0xA2, { KEY_SWITCHVIDEOMODE } }, /* SDSP CRT + HDMI */
    342	{KE_KEY, 0xA3, { KEY_SWITCHVIDEOMODE } }, /* SDSP TV + HDMI */
    343	{KE_KEY, 0xA4, { KEY_SWITCHVIDEOMODE } }, /* SDSP LCD + CRT + HDMI */
    344	{KE_KEY, 0xA5, { KEY_SWITCHVIDEOMODE } }, /* SDSP LCD + TV + HDMI */
    345	{KE_KEY, 0xA6, { KEY_SWITCHVIDEOMODE } }, /* SDSP CRT + TV + HDMI */
    346	{KE_KEY, 0xA7, { KEY_SWITCHVIDEOMODE } }, /* SDSP LCD + CRT + TV + HDMI */
    347	{KE_KEY, 0xB5, { KEY_CALC } },
    348	{KE_KEY, 0xC4, { KEY_KBDILLUMUP } },
    349	{KE_KEY, 0xC5, { KEY_KBDILLUMDOWN } },
    350	{KE_END, 0},
    351};
    352
    353
    354/*
    355 * This function evaluates an ACPI method, given an int as parameter, the
    356 * method is searched within the scope of the handle, can be NULL. The output
    357 * of the method is written is output, which can also be NULL
    358 *
    359 * returns 0 if write is successful, -1 else.
    360 */
    361static int write_acpi_int_ret(acpi_handle handle, const char *method, int val,
    362			      struct acpi_buffer *output)
    363{
    364	struct acpi_object_list params;	/* list of input parameters (an int) */
    365	union acpi_object in_obj;	/* the only param we use */
    366	acpi_status status;
    367
    368	if (!handle)
    369		return -1;
    370
    371	params.count = 1;
    372	params.pointer = &in_obj;
    373	in_obj.type = ACPI_TYPE_INTEGER;
    374	in_obj.integer.value = val;
    375
    376	status = acpi_evaluate_object(handle, (char *)method, &params, output);
    377	if (status == AE_OK)
    378		return 0;
    379	else
    380		return -1;
    381}
    382
    383static int write_acpi_int(acpi_handle handle, const char *method, int val)
    384{
    385	return write_acpi_int_ret(handle, method, val, NULL);
    386}
    387
    388static int acpi_check_handle(acpi_handle handle, const char *method,
    389			     acpi_handle *ret)
    390{
    391	acpi_status status;
    392
    393	if (method == NULL)
    394		return -ENODEV;
    395
    396	if (ret)
    397		status = acpi_get_handle(handle, (char *)method,
    398					 ret);
    399	else {
    400		acpi_handle dummy;
    401
    402		status = acpi_get_handle(handle, (char *)method,
    403					 &dummy);
    404	}
    405
    406	if (status != AE_OK) {
    407		if (ret)
    408			pr_warn("Error finding %s\n", method);
    409		return -ENODEV;
    410	}
    411	return 0;
    412}
    413
    414static bool asus_check_pega_lucid(struct asus_laptop *asus)
    415{
    416	return !strcmp(asus->name, DEVICE_NAME_PEGA) &&
    417	   !acpi_check_handle(asus->handle, METHOD_PEGA_ENABLE, NULL) &&
    418	   !acpi_check_handle(asus->handle, METHOD_PEGA_DISABLE, NULL) &&
    419	   !acpi_check_handle(asus->handle, METHOD_PEGA_READ, NULL);
    420}
    421
    422static int asus_pega_lucid_set(struct asus_laptop *asus, int unit, bool enable)
    423{
    424	char *method = enable ? METHOD_PEGA_ENABLE : METHOD_PEGA_DISABLE;
    425	return write_acpi_int(asus->handle, method, unit);
    426}
    427
    428static int pega_acc_axis(struct asus_laptop *asus, int curr, char *method)
    429{
    430	int i, delta;
    431	unsigned long long val;
    432	for (i = 0; i < PEGA_ACC_RETRIES; i++) {
    433		acpi_evaluate_integer(asus->handle, method, NULL, &val);
    434
    435		/* The output is noisy.  From reading the ASL
    436		 * dissassembly, timeout errors are returned with 1's
    437		 * in the high word, and the lack of locking around
    438		 * thei hi/lo byte reads means that a transition
    439		 * between (for example) -1 and 0 could be read as
    440		 * 0xff00 or 0x00ff. */
    441		delta = abs(curr - (short)val);
    442		if (delta < 128 && !(val & ~0xffff))
    443			break;
    444	}
    445	return clamp_val((short)val, -PEGA_ACC_CLAMP, PEGA_ACC_CLAMP);
    446}
    447
    448static void pega_accel_poll(struct input_dev *input)
    449{
    450	struct device *parent = input->dev.parent;
    451	struct asus_laptop *asus = dev_get_drvdata(parent);
    452
    453	/* In some cases, the very first call to poll causes a
    454	 * recursive fault under the polldev worker.  This is
    455	 * apparently related to very early userspace access to the
    456	 * device, and perhaps a firmware bug. Fake the first report. */
    457	if (!asus->pega_acc_live) {
    458		asus->pega_acc_live = true;
    459		input_report_abs(input, ABS_X, 0);
    460		input_report_abs(input, ABS_Y, 0);
    461		input_report_abs(input, ABS_Z, 0);
    462		input_sync(input);
    463		return;
    464	}
    465
    466	asus->pega_acc_x = pega_acc_axis(asus, asus->pega_acc_x, METHOD_XLRX);
    467	asus->pega_acc_y = pega_acc_axis(asus, asus->pega_acc_y, METHOD_XLRY);
    468	asus->pega_acc_z = pega_acc_axis(asus, asus->pega_acc_z, METHOD_XLRZ);
    469
    470	/* Note transform, convert to "right/up/out" in the native
    471	 * landscape orientation (i.e. the vector is the direction of
    472	 * "real up" in the device's cartiesian coordinates). */
    473	input_report_abs(input, ABS_X, -asus->pega_acc_x);
    474	input_report_abs(input, ABS_Y, -asus->pega_acc_y);
    475	input_report_abs(input, ABS_Z,  asus->pega_acc_z);
    476	input_sync(input);
    477}
    478
    479static void pega_accel_exit(struct asus_laptop *asus)
    480{
    481	if (asus->pega_accel_poll) {
    482		input_unregister_device(asus->pega_accel_poll);
    483		asus->pega_accel_poll = NULL;
    484	}
    485}
    486
    487static int pega_accel_init(struct asus_laptop *asus)
    488{
    489	int err;
    490	struct input_dev *input;
    491
    492	if (!asus->is_pega_lucid)
    493		return -ENODEV;
    494
    495	if (acpi_check_handle(asus->handle, METHOD_XLRX, NULL) ||
    496	    acpi_check_handle(asus->handle, METHOD_XLRY, NULL) ||
    497	    acpi_check_handle(asus->handle, METHOD_XLRZ, NULL))
    498		return -ENODEV;
    499
    500	input = input_allocate_device();
    501	if (!input)
    502		return -ENOMEM;
    503
    504	input->name = PEGA_ACCEL_DESC;
    505	input->phys = PEGA_ACCEL_NAME "/input0";
    506	input->dev.parent = &asus->platform_device->dev;
    507	input->id.bustype = BUS_HOST;
    508
    509	input_set_abs_params(input, ABS_X,
    510			     -PEGA_ACC_CLAMP, PEGA_ACC_CLAMP, 0, 0);
    511	input_set_abs_params(input, ABS_Y,
    512			     -PEGA_ACC_CLAMP, PEGA_ACC_CLAMP, 0, 0);
    513	input_set_abs_params(input, ABS_Z,
    514			     -PEGA_ACC_CLAMP, PEGA_ACC_CLAMP, 0, 0);
    515
    516	err = input_setup_polling(input, pega_accel_poll);
    517	if (err)
    518		goto exit;
    519
    520	input_set_poll_interval(input, 125);
    521	input_set_min_poll_interval(input, 50);
    522	input_set_max_poll_interval(input, 2000);
    523
    524	err = input_register_device(input);
    525	if (err)
    526		goto exit;
    527
    528	asus->pega_accel_poll = input;
    529	return 0;
    530
    531exit:
    532	input_free_device(input);
    533	return err;
    534}
    535
    536/* Generic LED function */
    537static int asus_led_set(struct asus_laptop *asus, const char *method,
    538			 int value)
    539{
    540	if (!strcmp(method, METHOD_MLED))
    541		value = !value;
    542	else if (!strcmp(method, METHOD_GLED))
    543		value = !value + 1;
    544	else
    545		value = !!value;
    546
    547	return write_acpi_int(asus->handle, method, value);
    548}
    549
    550/*
    551 * LEDs
    552 */
    553/* /sys/class/led handlers */
    554static void asus_led_cdev_set(struct led_classdev *led_cdev,
    555			 enum led_brightness value)
    556{
    557	struct asus_led *led = container_of(led_cdev, struct asus_led, led);
    558	struct asus_laptop *asus = led->asus;
    559
    560	led->wk = !!value;
    561	queue_work(asus->led_workqueue, &led->work);
    562}
    563
    564static void asus_led_cdev_update(struct work_struct *work)
    565{
    566	struct asus_led *led = container_of(work, struct asus_led, work);
    567	struct asus_laptop *asus = led->asus;
    568
    569	asus_led_set(asus, led->method, led->wk);
    570}
    571
    572static enum led_brightness asus_led_cdev_get(struct led_classdev *led_cdev)
    573{
    574	return led_cdev->brightness;
    575}
    576
    577/*
    578 * Keyboard backlight (also a LED)
    579 */
    580static int asus_kled_lvl(struct asus_laptop *asus)
    581{
    582	unsigned long long kblv;
    583	struct acpi_object_list params;
    584	union acpi_object in_obj;
    585	acpi_status rv;
    586
    587	params.count = 1;
    588	params.pointer = &in_obj;
    589	in_obj.type = ACPI_TYPE_INTEGER;
    590	in_obj.integer.value = 2;
    591
    592	rv = acpi_evaluate_integer(asus->handle, METHOD_KBD_LIGHT_GET,
    593				   &params, &kblv);
    594	if (ACPI_FAILURE(rv)) {
    595		pr_warn("Error reading kled level\n");
    596		return -ENODEV;
    597	}
    598	return kblv;
    599}
    600
    601static int asus_kled_set(struct asus_laptop *asus, int kblv)
    602{
    603	if (kblv > 0)
    604		kblv = (1 << 7) | (kblv & 0x7F);
    605	else
    606		kblv = 0;
    607
    608	if (write_acpi_int(asus->handle, METHOD_KBD_LIGHT_SET, kblv)) {
    609		pr_warn("Keyboard LED display write failed\n");
    610		return -EINVAL;
    611	}
    612	return 0;
    613}
    614
    615static void asus_kled_cdev_set(struct led_classdev *led_cdev,
    616			      enum led_brightness value)
    617{
    618	struct asus_led *led = container_of(led_cdev, struct asus_led, led);
    619	struct asus_laptop *asus = led->asus;
    620
    621	led->wk = value;
    622	queue_work(asus->led_workqueue, &led->work);
    623}
    624
    625static void asus_kled_cdev_update(struct work_struct *work)
    626{
    627	struct asus_led *led = container_of(work, struct asus_led, work);
    628	struct asus_laptop *asus = led->asus;
    629
    630	asus_kled_set(asus, led->wk);
    631}
    632
    633static enum led_brightness asus_kled_cdev_get(struct led_classdev *led_cdev)
    634{
    635	struct asus_led *led = container_of(led_cdev, struct asus_led, led);
    636	struct asus_laptop *asus = led->asus;
    637
    638	return asus_kled_lvl(asus);
    639}
    640
    641static void asus_led_exit(struct asus_laptop *asus)
    642{
    643	led_classdev_unregister(&asus->wled.led);
    644	led_classdev_unregister(&asus->bled.led);
    645	led_classdev_unregister(&asus->mled.led);
    646	led_classdev_unregister(&asus->tled.led);
    647	led_classdev_unregister(&asus->pled.led);
    648	led_classdev_unregister(&asus->rled.led);
    649	led_classdev_unregister(&asus->gled.led);
    650	led_classdev_unregister(&asus->kled.led);
    651
    652	if (asus->led_workqueue) {
    653		destroy_workqueue(asus->led_workqueue);
    654		asus->led_workqueue = NULL;
    655	}
    656}
    657
    658/*  Ugly macro, need to fix that later */
    659static int asus_led_register(struct asus_laptop *asus,
    660			     struct asus_led *led,
    661			     const char *name, const char *method)
    662{
    663	struct led_classdev *led_cdev = &led->led;
    664
    665	if (!method || acpi_check_handle(asus->handle, method, NULL))
    666		return 0; /* Led not present */
    667
    668	led->asus = asus;
    669	led->method = method;
    670
    671	INIT_WORK(&led->work, asus_led_cdev_update);
    672	led_cdev->name = name;
    673	led_cdev->brightness_set = asus_led_cdev_set;
    674	led_cdev->brightness_get = asus_led_cdev_get;
    675	led_cdev->max_brightness = 1;
    676	return led_classdev_register(&asus->platform_device->dev, led_cdev);
    677}
    678
    679static int asus_led_init(struct asus_laptop *asus)
    680{
    681	int r = 0;
    682
    683	/*
    684	 * The Pegatron Lucid has no physical leds, but all methods are
    685	 * available in the DSDT...
    686	 */
    687	if (asus->is_pega_lucid)
    688		return 0;
    689
    690	/*
    691	 * Functions that actually update the LED's are called from a
    692	 * workqueue. By doing this as separate work rather than when the LED
    693	 * subsystem asks, we avoid messing with the Asus ACPI stuff during a
    694	 * potentially bad time, such as a timer interrupt.
    695	 */
    696	asus->led_workqueue = create_singlethread_workqueue("led_workqueue");
    697	if (!asus->led_workqueue)
    698		return -ENOMEM;
    699
    700	if (asus->wled_type == TYPE_LED)
    701		r = asus_led_register(asus, &asus->wled, "asus::wlan",
    702				      METHOD_WLAN);
    703	if (r)
    704		goto error;
    705	if (asus->bled_type == TYPE_LED)
    706		r = asus_led_register(asus, &asus->bled, "asus::bluetooth",
    707				      METHOD_BLUETOOTH);
    708	if (r)
    709		goto error;
    710	r = asus_led_register(asus, &asus->mled, "asus::mail", METHOD_MLED);
    711	if (r)
    712		goto error;
    713	r = asus_led_register(asus, &asus->tled, "asus::touchpad", METHOD_TLED);
    714	if (r)
    715		goto error;
    716	r = asus_led_register(asus, &asus->rled, "asus::record", METHOD_RLED);
    717	if (r)
    718		goto error;
    719	r = asus_led_register(asus, &asus->pled, "asus::phone", METHOD_PLED);
    720	if (r)
    721		goto error;
    722	r = asus_led_register(asus, &asus->gled, "asus::gaming", METHOD_GLED);
    723	if (r)
    724		goto error;
    725	if (!acpi_check_handle(asus->handle, METHOD_KBD_LIGHT_SET, NULL) &&
    726	    !acpi_check_handle(asus->handle, METHOD_KBD_LIGHT_GET, NULL)) {
    727		struct asus_led *led = &asus->kled;
    728		struct led_classdev *cdev = &led->led;
    729
    730		led->asus = asus;
    731
    732		INIT_WORK(&led->work, asus_kled_cdev_update);
    733		cdev->name = "asus::kbd_backlight";
    734		cdev->brightness_set = asus_kled_cdev_set;
    735		cdev->brightness_get = asus_kled_cdev_get;
    736		cdev->max_brightness = 3;
    737		r = led_classdev_register(&asus->platform_device->dev, cdev);
    738	}
    739error:
    740	if (r)
    741		asus_led_exit(asus);
    742	return r;
    743}
    744
    745/*
    746 * Backlight device
    747 */
    748static int asus_read_brightness(struct backlight_device *bd)
    749{
    750	struct asus_laptop *asus = bl_get_data(bd);
    751	unsigned long long value;
    752	acpi_status rv;
    753
    754	rv = acpi_evaluate_integer(asus->handle, METHOD_BRIGHTNESS_GET,
    755				   NULL, &value);
    756	if (ACPI_FAILURE(rv)) {
    757		pr_warn("Error reading brightness\n");
    758		return 0;
    759	}
    760
    761	return value;
    762}
    763
    764static int asus_set_brightness(struct backlight_device *bd, int value)
    765{
    766	struct asus_laptop *asus = bl_get_data(bd);
    767
    768	if (write_acpi_int(asus->handle, METHOD_BRIGHTNESS_SET, value)) {
    769		pr_warn("Error changing brightness\n");
    770		return -EIO;
    771	}
    772	return 0;
    773}
    774
    775static int update_bl_status(struct backlight_device *bd)
    776{
    777	int value = bd->props.brightness;
    778
    779	return asus_set_brightness(bd, value);
    780}
    781
    782static const struct backlight_ops asusbl_ops = {
    783	.get_brightness = asus_read_brightness,
    784	.update_status = update_bl_status,
    785};
    786
    787static int asus_backlight_notify(struct asus_laptop *asus)
    788{
    789	struct backlight_device *bd = asus->backlight_device;
    790	int old = bd->props.brightness;
    791
    792	backlight_force_update(bd, BACKLIGHT_UPDATE_HOTKEY);
    793
    794	return old;
    795}
    796
    797static int asus_backlight_init(struct asus_laptop *asus)
    798{
    799	struct backlight_device *bd;
    800	struct backlight_properties props;
    801
    802	if (acpi_check_handle(asus->handle, METHOD_BRIGHTNESS_GET, NULL) ||
    803	    acpi_check_handle(asus->handle, METHOD_BRIGHTNESS_SET, NULL))
    804		return 0;
    805
    806	memset(&props, 0, sizeof(struct backlight_properties));
    807	props.max_brightness = 15;
    808	props.type = BACKLIGHT_PLATFORM;
    809
    810	bd = backlight_device_register(ASUS_LAPTOP_FILE,
    811				       &asus->platform_device->dev, asus,
    812				       &asusbl_ops, &props);
    813	if (IS_ERR(bd)) {
    814		pr_err("Could not register asus backlight device\n");
    815		asus->backlight_device = NULL;
    816		return PTR_ERR(bd);
    817	}
    818
    819	asus->backlight_device = bd;
    820	bd->props.brightness = asus_read_brightness(bd);
    821	bd->props.power = FB_BLANK_UNBLANK;
    822	backlight_update_status(bd);
    823	return 0;
    824}
    825
    826static void asus_backlight_exit(struct asus_laptop *asus)
    827{
    828	backlight_device_unregister(asus->backlight_device);
    829	asus->backlight_device = NULL;
    830}
    831
    832/*
    833 * Platform device handlers
    834 */
    835
    836/*
    837 * We write our info in page, we begin at offset off and cannot write more
    838 * than count bytes. We set eof to 1 if we handle those 2 values. We return the
    839 * number of bytes written in page
    840 */
    841static ssize_t infos_show(struct device *dev, struct device_attribute *attr,
    842			  char *page)
    843{
    844	struct asus_laptop *asus = dev_get_drvdata(dev);
    845	int len = 0;
    846	unsigned long long temp;
    847	char buf[16];		/* enough for all info */
    848	acpi_status rv;
    849
    850	/*
    851	 * We use the easy way, we don't care of off and count,
    852	 * so we don't set eof to 1
    853	 */
    854
    855	len += sprintf(page, ASUS_LAPTOP_NAME " " ASUS_LAPTOP_VERSION "\n");
    856	len += sprintf(page + len, "Model reference    : %s\n", asus->name);
    857	/*
    858	 * The SFUN method probably allows the original driver to get the list
    859	 * of features supported by a given model. For now, 0x0100 or 0x0800
    860	 * bit signifies that the laptop is equipped with a Wi-Fi MiniPCI card.
    861	 * The significance of others is yet to be found.
    862	 */
    863	rv = acpi_evaluate_integer(asus->handle, "SFUN", NULL, &temp);
    864	if (ACPI_SUCCESS(rv))
    865		len += sprintf(page + len, "SFUN value         : %#x\n",
    866			       (uint) temp);
    867	/*
    868	 * The HWRS method return informations about the hardware.
    869	 * 0x80 bit is for WLAN, 0x100 for Bluetooth.
    870	 * 0x40 for WWAN, 0x10 for WIMAX.
    871	 * The significance of others is yet to be found.
    872	 * We don't currently use this for device detection, and it
    873	 * takes several seconds to run on some systems.
    874	 */
    875	rv = acpi_evaluate_integer(asus->handle, "HWRS", NULL, &temp);
    876	if (ACPI_SUCCESS(rv))
    877		len += sprintf(page + len, "HWRS value         : %#x\n",
    878			       (uint) temp);
    879	/*
    880	 * Another value for userspace: the ASYM method returns 0x02 for
    881	 * battery low and 0x04 for battery critical, its readings tend to be
    882	 * more accurate than those provided by _BST.
    883	 * Note: since not all the laptops provide this method, errors are
    884	 * silently ignored.
    885	 */
    886	rv = acpi_evaluate_integer(asus->handle, "ASYM", NULL, &temp);
    887	if (ACPI_SUCCESS(rv))
    888		len += sprintf(page + len, "ASYM value         : %#x\n",
    889			       (uint) temp);
    890	if (asus->dsdt_info) {
    891		snprintf(buf, 16, "%d", asus->dsdt_info->length);
    892		len += sprintf(page + len, "DSDT length        : %s\n", buf);
    893		snprintf(buf, 16, "%d", asus->dsdt_info->checksum);
    894		len += sprintf(page + len, "DSDT checksum      : %s\n", buf);
    895		snprintf(buf, 16, "%d", asus->dsdt_info->revision);
    896		len += sprintf(page + len, "DSDT revision      : %s\n", buf);
    897		snprintf(buf, 7, "%s", asus->dsdt_info->oem_id);
    898		len += sprintf(page + len, "OEM id             : %s\n", buf);
    899		snprintf(buf, 9, "%s", asus->dsdt_info->oem_table_id);
    900		len += sprintf(page + len, "OEM table id       : %s\n", buf);
    901		snprintf(buf, 16, "%x", asus->dsdt_info->oem_revision);
    902		len += sprintf(page + len, "OEM revision       : 0x%s\n", buf);
    903		snprintf(buf, 5, "%s", asus->dsdt_info->asl_compiler_id);
    904		len += sprintf(page + len, "ASL comp vendor id : %s\n", buf);
    905		snprintf(buf, 16, "%x", asus->dsdt_info->asl_compiler_revision);
    906		len += sprintf(page + len, "ASL comp revision  : 0x%s\n", buf);
    907	}
    908
    909	return len;
    910}
    911static DEVICE_ATTR_RO(infos);
    912
    913static ssize_t sysfs_acpi_set(struct asus_laptop *asus,
    914			      const char *buf, size_t count,
    915			      const char *method)
    916{
    917	int rv, value;
    918
    919	rv = kstrtoint(buf, 0, &value);
    920	if (rv < 0)
    921		return rv;
    922
    923	if (write_acpi_int(asus->handle, method, value))
    924		return -ENODEV;
    925	return count;
    926}
    927
    928/*
    929 * LEDD display
    930 */
    931static ssize_t ledd_show(struct device *dev, struct device_attribute *attr,
    932			 char *buf)
    933{
    934	struct asus_laptop *asus = dev_get_drvdata(dev);
    935
    936	return sprintf(buf, "0x%08x\n", asus->ledd_status);
    937}
    938
    939static ssize_t ledd_store(struct device *dev, struct device_attribute *attr,
    940			  const char *buf, size_t count)
    941{
    942	struct asus_laptop *asus = dev_get_drvdata(dev);
    943	int rv, value;
    944
    945	rv = kstrtoint(buf, 0, &value);
    946	if (rv < 0)
    947		return rv;
    948
    949	if (write_acpi_int(asus->handle, METHOD_LEDD, value)) {
    950		pr_warn("LED display write failed\n");
    951		return -ENODEV;
    952	}
    953
    954	asus->ledd_status = (u32) value;
    955	return count;
    956}
    957static DEVICE_ATTR_RW(ledd);
    958
    959/*
    960 * Wireless
    961 */
    962static int asus_wireless_status(struct asus_laptop *asus, int mask)
    963{
    964	unsigned long long status;
    965	acpi_status rv = AE_OK;
    966
    967	if (!asus->have_rsts)
    968		return (asus->wireless_status & mask) ? 1 : 0;
    969
    970	rv = acpi_evaluate_integer(asus->handle, METHOD_WL_STATUS,
    971				   NULL, &status);
    972	if (ACPI_FAILURE(rv)) {
    973		pr_warn("Error reading Wireless status\n");
    974		return -EINVAL;
    975	}
    976	return !!(status & mask);
    977}
    978
    979/*
    980 * WLAN
    981 */
    982static int asus_wlan_set(struct asus_laptop *asus, int status)
    983{
    984	if (write_acpi_int(asus->handle, METHOD_WLAN, !!status)) {
    985		pr_warn("Error setting wlan status to %d\n", status);
    986		return -EIO;
    987	}
    988	return 0;
    989}
    990
    991static ssize_t wlan_show(struct device *dev, struct device_attribute *attr,
    992			 char *buf)
    993{
    994	struct asus_laptop *asus = dev_get_drvdata(dev);
    995
    996	return sprintf(buf, "%d\n", asus_wireless_status(asus, WL_RSTS));
    997}
    998
    999static ssize_t wlan_store(struct device *dev, struct device_attribute *attr,
   1000			  const char *buf, size_t count)
   1001{
   1002	struct asus_laptop *asus = dev_get_drvdata(dev);
   1003
   1004	return sysfs_acpi_set(asus, buf, count, METHOD_WLAN);
   1005}
   1006static DEVICE_ATTR_RW(wlan);
   1007
   1008/*e
   1009 * Bluetooth
   1010 */
   1011static int asus_bluetooth_set(struct asus_laptop *asus, int status)
   1012{
   1013	if (write_acpi_int(asus->handle, METHOD_BLUETOOTH, !!status)) {
   1014		pr_warn("Error setting bluetooth status to %d\n", status);
   1015		return -EIO;
   1016	}
   1017	return 0;
   1018}
   1019
   1020static ssize_t bluetooth_show(struct device *dev, struct device_attribute *attr,
   1021			      char *buf)
   1022{
   1023	struct asus_laptop *asus = dev_get_drvdata(dev);
   1024
   1025	return sprintf(buf, "%d\n", asus_wireless_status(asus, BT_RSTS));
   1026}
   1027
   1028static ssize_t bluetooth_store(struct device *dev,
   1029			       struct device_attribute *attr, const char *buf,
   1030			       size_t count)
   1031{
   1032	struct asus_laptop *asus = dev_get_drvdata(dev);
   1033
   1034	return sysfs_acpi_set(asus, buf, count, METHOD_BLUETOOTH);
   1035}
   1036static DEVICE_ATTR_RW(bluetooth);
   1037
   1038/*
   1039 * Wimax
   1040 */
   1041static int asus_wimax_set(struct asus_laptop *asus, int status)
   1042{
   1043	if (write_acpi_int(asus->handle, METHOD_WIMAX, !!status)) {
   1044		pr_warn("Error setting wimax status to %d\n", status);
   1045		return -EIO;
   1046	}
   1047	return 0;
   1048}
   1049
   1050static ssize_t wimax_show(struct device *dev, struct device_attribute *attr,
   1051			  char *buf)
   1052{
   1053	struct asus_laptop *asus = dev_get_drvdata(dev);
   1054
   1055	return sprintf(buf, "%d\n", asus_wireless_status(asus, WM_RSTS));
   1056}
   1057
   1058static ssize_t wimax_store(struct device *dev, struct device_attribute *attr,
   1059			   const char *buf, size_t count)
   1060{
   1061	struct asus_laptop *asus = dev_get_drvdata(dev);
   1062
   1063	return sysfs_acpi_set(asus, buf, count, METHOD_WIMAX);
   1064}
   1065static DEVICE_ATTR_RW(wimax);
   1066
   1067/*
   1068 * Wwan
   1069 */
   1070static int asus_wwan_set(struct asus_laptop *asus, int status)
   1071{
   1072	if (write_acpi_int(asus->handle, METHOD_WWAN, !!status)) {
   1073		pr_warn("Error setting wwan status to %d\n", status);
   1074		return -EIO;
   1075	}
   1076	return 0;
   1077}
   1078
   1079static ssize_t wwan_show(struct device *dev, struct device_attribute *attr,
   1080			 char *buf)
   1081{
   1082	struct asus_laptop *asus = dev_get_drvdata(dev);
   1083
   1084	return sprintf(buf, "%d\n", asus_wireless_status(asus, WW_RSTS));
   1085}
   1086
   1087static ssize_t wwan_store(struct device *dev, struct device_attribute *attr,
   1088			  const char *buf, size_t count)
   1089{
   1090	struct asus_laptop *asus = dev_get_drvdata(dev);
   1091
   1092	return sysfs_acpi_set(asus, buf, count, METHOD_WWAN);
   1093}
   1094static DEVICE_ATTR_RW(wwan);
   1095
   1096/*
   1097 * Display
   1098 */
   1099static void asus_set_display(struct asus_laptop *asus, int value)
   1100{
   1101	/* no sanity check needed for now */
   1102	if (write_acpi_int(asus->handle, METHOD_SWITCH_DISPLAY, value))
   1103		pr_warn("Error setting display\n");
   1104	return;
   1105}
   1106
   1107/*
   1108 * Experimental support for display switching. As of now: 1 should activate
   1109 * the LCD output, 2 should do for CRT, 4 for TV-Out and 8 for DVI.
   1110 * Any combination (bitwise) of these will suffice. I never actually tested 4
   1111 * displays hooked up simultaneously, so be warned. See the acpi4asus README
   1112 * for more info.
   1113 */
   1114static ssize_t display_store(struct device *dev, struct device_attribute *attr,
   1115			     const char *buf, size_t count)
   1116{
   1117	struct asus_laptop *asus = dev_get_drvdata(dev);
   1118	int rv, value;
   1119
   1120	rv = kstrtoint(buf, 0, &value);
   1121	if (rv < 0)
   1122		return rv;
   1123
   1124	asus_set_display(asus, value);
   1125	return count;
   1126}
   1127static DEVICE_ATTR_WO(display);
   1128
   1129/*
   1130 * Light Sens
   1131 */
   1132static void asus_als_switch(struct asus_laptop *asus, int value)
   1133{
   1134	int ret;
   1135
   1136	if (asus->is_pega_lucid) {
   1137		ret = asus_pega_lucid_set(asus, PEGA_ALS, value);
   1138		if (!ret)
   1139			ret = asus_pega_lucid_set(asus, PEGA_ALS_POWER, value);
   1140	} else {
   1141		ret = write_acpi_int(asus->handle, METHOD_ALS_CONTROL, value);
   1142	}
   1143	if (ret)
   1144		pr_warn("Error setting light sensor switch\n");
   1145
   1146	asus->light_switch = value;
   1147}
   1148
   1149static ssize_t ls_switch_show(struct device *dev, struct device_attribute *attr,
   1150			      char *buf)
   1151{
   1152	struct asus_laptop *asus = dev_get_drvdata(dev);
   1153
   1154	return sprintf(buf, "%d\n", asus->light_switch);
   1155}
   1156
   1157static ssize_t ls_switch_store(struct device *dev,
   1158			       struct device_attribute *attr, const char *buf,
   1159			       size_t count)
   1160{
   1161	struct asus_laptop *asus = dev_get_drvdata(dev);
   1162	int rv, value;
   1163
   1164	rv = kstrtoint(buf, 0, &value);
   1165	if (rv < 0)
   1166		return rv;
   1167
   1168	asus_als_switch(asus, value ? 1 : 0);
   1169	return count;
   1170}
   1171static DEVICE_ATTR_RW(ls_switch);
   1172
   1173static void asus_als_level(struct asus_laptop *asus, int value)
   1174{
   1175	if (write_acpi_int(asus->handle, METHOD_ALS_LEVEL, value))
   1176		pr_warn("Error setting light sensor level\n");
   1177	asus->light_level = value;
   1178}
   1179
   1180static ssize_t ls_level_show(struct device *dev, struct device_attribute *attr,
   1181			     char *buf)
   1182{
   1183	struct asus_laptop *asus = dev_get_drvdata(dev);
   1184
   1185	return sprintf(buf, "%d\n", asus->light_level);
   1186}
   1187
   1188static ssize_t ls_level_store(struct device *dev, struct device_attribute *attr,
   1189			      const char *buf, size_t count)
   1190{
   1191	struct asus_laptop *asus = dev_get_drvdata(dev);
   1192	int rv, value;
   1193
   1194	rv = kstrtoint(buf, 0, &value);
   1195	if (rv < 0)
   1196		return rv;
   1197
   1198	value = (0 < value) ? ((15 < value) ? 15 : value) : 0;
   1199	/* 0 <= value <= 15 */
   1200	asus_als_level(asus, value);
   1201
   1202	return count;
   1203}
   1204static DEVICE_ATTR_RW(ls_level);
   1205
   1206static int pega_int_read(struct asus_laptop *asus, int arg, int *result)
   1207{
   1208	struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
   1209	int err = write_acpi_int_ret(asus->handle, METHOD_PEGA_READ, arg,
   1210				     &buffer);
   1211	if (!err) {
   1212		union acpi_object *obj = buffer.pointer;
   1213		if (obj && obj->type == ACPI_TYPE_INTEGER)
   1214			*result = obj->integer.value;
   1215		else
   1216			err = -EIO;
   1217	}
   1218	return err;
   1219}
   1220
   1221static ssize_t ls_value_show(struct device *dev, struct device_attribute *attr,
   1222			     char *buf)
   1223{
   1224	struct asus_laptop *asus = dev_get_drvdata(dev);
   1225	int err, hi, lo;
   1226
   1227	err = pega_int_read(asus, PEGA_READ_ALS_H, &hi);
   1228	if (!err)
   1229		err = pega_int_read(asus, PEGA_READ_ALS_L, &lo);
   1230	if (!err)
   1231		return sprintf(buf, "%d\n", 10 * hi + lo);
   1232	return err;
   1233}
   1234static DEVICE_ATTR_RO(ls_value);
   1235
   1236/*
   1237 * GPS
   1238 */
   1239static int asus_gps_status(struct asus_laptop *asus)
   1240{
   1241	unsigned long long status;
   1242	acpi_status rv;
   1243
   1244	rv = acpi_evaluate_integer(asus->handle, METHOD_GPS_STATUS,
   1245				   NULL, &status);
   1246	if (ACPI_FAILURE(rv)) {
   1247		pr_warn("Error reading GPS status\n");
   1248		return -ENODEV;
   1249	}
   1250	return !!status;
   1251}
   1252
   1253static int asus_gps_switch(struct asus_laptop *asus, int status)
   1254{
   1255	const char *meth = status ? METHOD_GPS_ON : METHOD_GPS_OFF;
   1256
   1257	if (write_acpi_int(asus->handle, meth, 0x02))
   1258		return -ENODEV;
   1259	return 0;
   1260}
   1261
   1262static ssize_t gps_show(struct device *dev, struct device_attribute *attr,
   1263			char *buf)
   1264{
   1265	struct asus_laptop *asus = dev_get_drvdata(dev);
   1266
   1267	return sprintf(buf, "%d\n", asus_gps_status(asus));
   1268}
   1269
   1270static ssize_t gps_store(struct device *dev, struct device_attribute *attr,
   1271			 const char *buf, size_t count)
   1272{
   1273	struct asus_laptop *asus = dev_get_drvdata(dev);
   1274	int rv, value;
   1275	int ret;
   1276
   1277	rv = kstrtoint(buf, 0, &value);
   1278	if (rv < 0)
   1279		return rv;
   1280	ret = asus_gps_switch(asus, !!value);
   1281	if (ret)
   1282		return ret;
   1283	rfkill_set_sw_state(asus->gps.rfkill, !value);
   1284	return count;
   1285}
   1286static DEVICE_ATTR_RW(gps);
   1287
   1288/*
   1289 * rfkill
   1290 */
   1291static int asus_gps_rfkill_set(void *data, bool blocked)
   1292{
   1293	struct asus_laptop *asus = data;
   1294
   1295	return asus_gps_switch(asus, !blocked);
   1296}
   1297
   1298static const struct rfkill_ops asus_gps_rfkill_ops = {
   1299	.set_block = asus_gps_rfkill_set,
   1300};
   1301
   1302static int asus_rfkill_set(void *data, bool blocked)
   1303{
   1304	struct asus_rfkill *rfk = data;
   1305	struct asus_laptop *asus = rfk->asus;
   1306
   1307	if (rfk->control_id == WL_RSTS)
   1308		return asus_wlan_set(asus, !blocked);
   1309	else if (rfk->control_id == BT_RSTS)
   1310		return asus_bluetooth_set(asus, !blocked);
   1311	else if (rfk->control_id == WM_RSTS)
   1312		return asus_wimax_set(asus, !blocked);
   1313	else if (rfk->control_id == WW_RSTS)
   1314		return asus_wwan_set(asus, !blocked);
   1315
   1316	return -EINVAL;
   1317}
   1318
   1319static const struct rfkill_ops asus_rfkill_ops = {
   1320	.set_block = asus_rfkill_set,
   1321};
   1322
   1323static void asus_rfkill_terminate(struct asus_rfkill *rfk)
   1324{
   1325	if (!rfk->rfkill)
   1326		return ;
   1327
   1328	rfkill_unregister(rfk->rfkill);
   1329	rfkill_destroy(rfk->rfkill);
   1330	rfk->rfkill = NULL;
   1331}
   1332
   1333static void asus_rfkill_exit(struct asus_laptop *asus)
   1334{
   1335	asus_rfkill_terminate(&asus->wwan);
   1336	asus_rfkill_terminate(&asus->bluetooth);
   1337	asus_rfkill_terminate(&asus->wlan);
   1338	asus_rfkill_terminate(&asus->gps);
   1339}
   1340
   1341static int asus_rfkill_setup(struct asus_laptop *asus, struct asus_rfkill *rfk,
   1342			     const char *name, int control_id, int type,
   1343			     const struct rfkill_ops *ops)
   1344{
   1345	int result;
   1346
   1347	rfk->control_id = control_id;
   1348	rfk->asus = asus;
   1349	rfk->rfkill = rfkill_alloc(name, &asus->platform_device->dev,
   1350				   type, ops, rfk);
   1351	if (!rfk->rfkill)
   1352		return -EINVAL;
   1353
   1354	result = rfkill_register(rfk->rfkill);
   1355	if (result) {
   1356		rfkill_destroy(rfk->rfkill);
   1357		rfk->rfkill = NULL;
   1358	}
   1359
   1360	return result;
   1361}
   1362
   1363static int asus_rfkill_init(struct asus_laptop *asus)
   1364{
   1365	int result = 0;
   1366
   1367	if (asus->is_pega_lucid)
   1368		return -ENODEV;
   1369
   1370	if (!acpi_check_handle(asus->handle, METHOD_GPS_ON, NULL) &&
   1371	    !acpi_check_handle(asus->handle, METHOD_GPS_OFF, NULL) &&
   1372	    !acpi_check_handle(asus->handle, METHOD_GPS_STATUS, NULL))
   1373		result = asus_rfkill_setup(asus, &asus->gps, "asus-gps",
   1374					   -1, RFKILL_TYPE_GPS,
   1375					   &asus_gps_rfkill_ops);
   1376	if (result)
   1377		goto exit;
   1378
   1379
   1380	if (!acpi_check_handle(asus->handle, METHOD_WLAN, NULL) &&
   1381	    asus->wled_type == TYPE_RFKILL)
   1382		result = asus_rfkill_setup(asus, &asus->wlan, "asus-wlan",
   1383					   WL_RSTS, RFKILL_TYPE_WLAN,
   1384					   &asus_rfkill_ops);
   1385	if (result)
   1386		goto exit;
   1387
   1388	if (!acpi_check_handle(asus->handle, METHOD_BLUETOOTH, NULL) &&
   1389	    asus->bled_type == TYPE_RFKILL)
   1390		result = asus_rfkill_setup(asus, &asus->bluetooth,
   1391					   "asus-bluetooth", BT_RSTS,
   1392					   RFKILL_TYPE_BLUETOOTH,
   1393					   &asus_rfkill_ops);
   1394	if (result)
   1395		goto exit;
   1396
   1397	if (!acpi_check_handle(asus->handle, METHOD_WWAN, NULL))
   1398		result = asus_rfkill_setup(asus, &asus->wwan, "asus-wwan",
   1399					   WW_RSTS, RFKILL_TYPE_WWAN,
   1400					   &asus_rfkill_ops);
   1401	if (result)
   1402		goto exit;
   1403
   1404	if (!acpi_check_handle(asus->handle, METHOD_WIMAX, NULL))
   1405		result = asus_rfkill_setup(asus, &asus->wimax, "asus-wimax",
   1406					   WM_RSTS, RFKILL_TYPE_WIMAX,
   1407					   &asus_rfkill_ops);
   1408	if (result)
   1409		goto exit;
   1410
   1411exit:
   1412	if (result)
   1413		asus_rfkill_exit(asus);
   1414
   1415	return result;
   1416}
   1417
   1418static int pega_rfkill_set(void *data, bool blocked)
   1419{
   1420	struct asus_rfkill *rfk = data;
   1421
   1422	int ret = asus_pega_lucid_set(rfk->asus, rfk->control_id, !blocked);
   1423	return ret;
   1424}
   1425
   1426static const struct rfkill_ops pega_rfkill_ops = {
   1427	.set_block = pega_rfkill_set,
   1428};
   1429
   1430static int pega_rfkill_setup(struct asus_laptop *asus, struct asus_rfkill *rfk,
   1431			     const char *name, int controlid, int rfkill_type)
   1432{
   1433	return asus_rfkill_setup(asus, rfk, name, controlid, rfkill_type,
   1434				 &pega_rfkill_ops);
   1435}
   1436
   1437static int pega_rfkill_init(struct asus_laptop *asus)
   1438{
   1439	int ret = 0;
   1440
   1441	if(!asus->is_pega_lucid)
   1442		return -ENODEV;
   1443
   1444	ret = pega_rfkill_setup(asus, &asus->wlan, "pega-wlan",
   1445				PEGA_WLAN, RFKILL_TYPE_WLAN);
   1446	if(ret)
   1447		goto exit;
   1448
   1449	ret = pega_rfkill_setup(asus, &asus->bluetooth, "pega-bt",
   1450				PEGA_BLUETOOTH, RFKILL_TYPE_BLUETOOTH);
   1451	if(ret)
   1452		goto exit;
   1453
   1454	ret = pega_rfkill_setup(asus, &asus->wwan, "pega-wwan",
   1455				PEGA_WWAN, RFKILL_TYPE_WWAN);
   1456
   1457exit:
   1458	if (ret)
   1459		asus_rfkill_exit(asus);
   1460
   1461	return ret;
   1462}
   1463
   1464/*
   1465 * Input device (i.e. hotkeys)
   1466 */
   1467static void asus_input_notify(struct asus_laptop *asus, int event)
   1468{
   1469	if (!asus->inputdev)
   1470		return ;
   1471	if (!sparse_keymap_report_event(asus->inputdev, event, 1, true))
   1472		pr_info("Unknown key %x pressed\n", event);
   1473}
   1474
   1475static int asus_input_init(struct asus_laptop *asus)
   1476{
   1477	struct input_dev *input;
   1478	int error;
   1479
   1480	input = input_allocate_device();
   1481	if (!input)
   1482		return -ENOMEM;
   1483
   1484	input->name = "Asus Laptop extra buttons";
   1485	input->phys = ASUS_LAPTOP_FILE "/input0";
   1486	input->id.bustype = BUS_HOST;
   1487	input->dev.parent = &asus->platform_device->dev;
   1488
   1489	error = sparse_keymap_setup(input, asus_keymap, NULL);
   1490	if (error) {
   1491		pr_err("Unable to setup input device keymap\n");
   1492		goto err_free_dev;
   1493	}
   1494	error = input_register_device(input);
   1495	if (error) {
   1496		pr_warn("Unable to register input device\n");
   1497		goto err_free_dev;
   1498	}
   1499
   1500	asus->inputdev = input;
   1501	return 0;
   1502
   1503err_free_dev:
   1504	input_free_device(input);
   1505	return error;
   1506}
   1507
   1508static void asus_input_exit(struct asus_laptop *asus)
   1509{
   1510	if (asus->inputdev)
   1511		input_unregister_device(asus->inputdev);
   1512	asus->inputdev = NULL;
   1513}
   1514
   1515/*
   1516 * ACPI driver
   1517 */
   1518static void asus_acpi_notify(struct acpi_device *device, u32 event)
   1519{
   1520	struct asus_laptop *asus = acpi_driver_data(device);
   1521	u16 count;
   1522
   1523	/* TODO Find a better way to handle events count. */
   1524	count = asus->event_count[event % 128]++;
   1525	acpi_bus_generate_netlink_event(asus->device->pnp.device_class,
   1526					dev_name(&asus->device->dev), event,
   1527					count);
   1528
   1529	if (event >= ATKD_BRNUP_MIN && event <= ATKD_BRNUP_MAX)
   1530		event = ATKD_BRNUP;
   1531	else if (event >= ATKD_BRNDOWN_MIN &&
   1532		 event <= ATKD_BRNDOWN_MAX)
   1533		event = ATKD_BRNDOWN;
   1534
   1535	/* Brightness events are special */
   1536	if (event == ATKD_BRNDOWN || event == ATKD_BRNUP) {
   1537		if (asus->backlight_device != NULL) {
   1538			/* Update the backlight device. */
   1539			asus_backlight_notify(asus);
   1540			return ;
   1541		}
   1542	}
   1543
   1544	/* Accelerometer "coarse orientation change" event */
   1545	if (asus->pega_accel_poll && event == 0xEA) {
   1546		kobject_uevent(&asus->pega_accel_poll->dev.kobj, KOBJ_CHANGE);
   1547		return ;
   1548	}
   1549
   1550	asus_input_notify(asus, event);
   1551}
   1552
   1553static struct attribute *asus_attributes[] = {
   1554	&dev_attr_infos.attr,
   1555	&dev_attr_wlan.attr,
   1556	&dev_attr_bluetooth.attr,
   1557	&dev_attr_wimax.attr,
   1558	&dev_attr_wwan.attr,
   1559	&dev_attr_display.attr,
   1560	&dev_attr_ledd.attr,
   1561	&dev_attr_ls_value.attr,
   1562	&dev_attr_ls_level.attr,
   1563	&dev_attr_ls_switch.attr,
   1564	&dev_attr_gps.attr,
   1565	NULL
   1566};
   1567
   1568static umode_t asus_sysfs_is_visible(struct kobject *kobj,
   1569				    struct attribute *attr,
   1570				    int idx)
   1571{
   1572	struct device *dev = kobj_to_dev(kobj);
   1573	struct asus_laptop *asus = dev_get_drvdata(dev);
   1574	acpi_handle handle = asus->handle;
   1575	bool supported;
   1576
   1577	if (asus->is_pega_lucid) {
   1578		/* no ls_level interface on the Lucid */
   1579		if (attr == &dev_attr_ls_switch.attr)
   1580			supported = true;
   1581		else if (attr == &dev_attr_ls_level.attr)
   1582			supported = false;
   1583		else
   1584			goto normal;
   1585
   1586		return supported ? attr->mode : 0;
   1587	}
   1588
   1589normal:
   1590	if (attr == &dev_attr_wlan.attr) {
   1591		supported = !acpi_check_handle(handle, METHOD_WLAN, NULL);
   1592
   1593	} else if (attr == &dev_attr_bluetooth.attr) {
   1594		supported = !acpi_check_handle(handle, METHOD_BLUETOOTH, NULL);
   1595
   1596	} else if (attr == &dev_attr_display.attr) {
   1597		supported = !acpi_check_handle(handle, METHOD_SWITCH_DISPLAY, NULL);
   1598
   1599	} else if (attr == &dev_attr_wimax.attr) {
   1600		supported =
   1601			!acpi_check_handle(asus->handle, METHOD_WIMAX, NULL);
   1602
   1603	} else if (attr == &dev_attr_wwan.attr) {
   1604		supported = !acpi_check_handle(asus->handle, METHOD_WWAN, NULL);
   1605
   1606	} else if (attr == &dev_attr_ledd.attr) {
   1607		supported = !acpi_check_handle(handle, METHOD_LEDD, NULL);
   1608
   1609	} else if (attr == &dev_attr_ls_switch.attr ||
   1610		   attr == &dev_attr_ls_level.attr) {
   1611		supported = !acpi_check_handle(handle, METHOD_ALS_CONTROL, NULL) &&
   1612			!acpi_check_handle(handle, METHOD_ALS_LEVEL, NULL);
   1613	} else if (attr == &dev_attr_ls_value.attr) {
   1614		supported = asus->is_pega_lucid;
   1615	} else if (attr == &dev_attr_gps.attr) {
   1616		supported = !acpi_check_handle(handle, METHOD_GPS_ON, NULL) &&
   1617			    !acpi_check_handle(handle, METHOD_GPS_OFF, NULL) &&
   1618			    !acpi_check_handle(handle, METHOD_GPS_STATUS, NULL);
   1619	} else {
   1620		supported = true;
   1621	}
   1622
   1623	return supported ? attr->mode : 0;
   1624}
   1625
   1626
   1627static const struct attribute_group asus_attr_group = {
   1628	.is_visible	= asus_sysfs_is_visible,
   1629	.attrs		= asus_attributes,
   1630};
   1631
   1632static int asus_platform_init(struct asus_laptop *asus)
   1633{
   1634	int result;
   1635
   1636	asus->platform_device = platform_device_alloc(ASUS_LAPTOP_FILE, -1);
   1637	if (!asus->platform_device)
   1638		return -ENOMEM;
   1639	platform_set_drvdata(asus->platform_device, asus);
   1640
   1641	result = platform_device_add(asus->platform_device);
   1642	if (result)
   1643		goto fail_platform_device;
   1644
   1645	result = sysfs_create_group(&asus->platform_device->dev.kobj,
   1646				    &asus_attr_group);
   1647	if (result)
   1648		goto fail_sysfs;
   1649
   1650	return 0;
   1651
   1652fail_sysfs:
   1653	platform_device_del(asus->platform_device);
   1654fail_platform_device:
   1655	platform_device_put(asus->platform_device);
   1656	return result;
   1657}
   1658
   1659static void asus_platform_exit(struct asus_laptop *asus)
   1660{
   1661	sysfs_remove_group(&asus->platform_device->dev.kobj, &asus_attr_group);
   1662	platform_device_unregister(asus->platform_device);
   1663}
   1664
   1665static struct platform_driver platform_driver = {
   1666	.driver = {
   1667		.name = ASUS_LAPTOP_FILE,
   1668	},
   1669};
   1670
   1671/*
   1672 * This function is used to initialize the context with right values. In this
   1673 * method, we can make all the detection we want, and modify the asus_laptop
   1674 * struct
   1675 */
   1676static int asus_laptop_get_info(struct asus_laptop *asus)
   1677{
   1678	struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
   1679	union acpi_object *model = NULL;
   1680	unsigned long long bsts_result;
   1681	char *string = NULL;
   1682	acpi_status status;
   1683
   1684	/*
   1685	 * Get DSDT headers early enough to allow for differentiating between
   1686	 * models, but late enough to allow acpi_bus_register_driver() to fail
   1687	 * before doing anything ACPI-specific. Should we encounter a machine,
   1688	 * which needs special handling (i.e. its hotkey device has a different
   1689	 * HID), this bit will be moved.
   1690	 */
   1691	status = acpi_get_table(ACPI_SIG_DSDT, 1, &asus->dsdt_info);
   1692	if (ACPI_FAILURE(status))
   1693		pr_warn("Couldn't get the DSDT table header\n");
   1694
   1695	/* We have to write 0 on init this far for all ASUS models */
   1696	if (write_acpi_int_ret(asus->handle, "INIT", 0, &buffer)) {
   1697		pr_err("Hotkey initialization failed\n");
   1698		return -ENODEV;
   1699	}
   1700
   1701	/* This needs to be called for some laptops to init properly */
   1702	status =
   1703	    acpi_evaluate_integer(asus->handle, "BSTS", NULL, &bsts_result);
   1704	if (ACPI_FAILURE(status))
   1705		pr_warn("Error calling BSTS\n");
   1706	else if (bsts_result)
   1707		pr_notice("BSTS called, 0x%02x returned\n",
   1708		       (uint) bsts_result);
   1709
   1710	/* This too ... */
   1711	if (write_acpi_int(asus->handle, "CWAP", wapf))
   1712		pr_err("Error calling CWAP(%d)\n", wapf);
   1713	/*
   1714	 * Try to match the object returned by INIT to the specific model.
   1715	 * Handle every possible object (or the lack of thereof) the DSDT
   1716	 * writers might throw at us. When in trouble, we pass NULL to
   1717	 * asus_model_match() and try something completely different.
   1718	 */
   1719	if (buffer.pointer) {
   1720		model = buffer.pointer;
   1721		switch (model->type) {
   1722		case ACPI_TYPE_STRING:
   1723			string = model->string.pointer;
   1724			break;
   1725		case ACPI_TYPE_BUFFER:
   1726			string = model->buffer.pointer;
   1727			break;
   1728		default:
   1729			string = "";
   1730			break;
   1731		}
   1732	}
   1733	asus->name = kstrdup(string, GFP_KERNEL);
   1734	if (!asus->name) {
   1735		kfree(buffer.pointer);
   1736		return -ENOMEM;
   1737	}
   1738
   1739	if (string)
   1740		pr_notice("  %s model detected\n", string);
   1741
   1742	if (!acpi_check_handle(asus->handle, METHOD_WL_STATUS, NULL))
   1743		asus->have_rsts = true;
   1744
   1745	kfree(model);
   1746
   1747	return AE_OK;
   1748}
   1749
   1750static int asus_acpi_init(struct asus_laptop *asus)
   1751{
   1752	int result = 0;
   1753
   1754	result = acpi_bus_get_status(asus->device);
   1755	if (result)
   1756		return result;
   1757	if (!asus->device->status.present) {
   1758		pr_err("Hotkey device not present, aborting\n");
   1759		return -ENODEV;
   1760	}
   1761
   1762	result = asus_laptop_get_info(asus);
   1763	if (result)
   1764		return result;
   1765
   1766	if (!strcmp(bled_type, "led"))
   1767		asus->bled_type = TYPE_LED;
   1768	else if (!strcmp(bled_type, "rfkill"))
   1769		asus->bled_type = TYPE_RFKILL;
   1770
   1771	if (!strcmp(wled_type, "led"))
   1772		asus->wled_type = TYPE_LED;
   1773	else if (!strcmp(wled_type, "rfkill"))
   1774		asus->wled_type = TYPE_RFKILL;
   1775
   1776	if (bluetooth_status >= 0)
   1777		asus_bluetooth_set(asus, !!bluetooth_status);
   1778
   1779	if (wlan_status >= 0)
   1780		asus_wlan_set(asus, !!wlan_status);
   1781
   1782	if (wimax_status >= 0)
   1783		asus_wimax_set(asus, !!wimax_status);
   1784
   1785	if (wwan_status >= 0)
   1786		asus_wwan_set(asus, !!wwan_status);
   1787
   1788	/* Keyboard Backlight is on by default */
   1789	if (!acpi_check_handle(asus->handle, METHOD_KBD_LIGHT_SET, NULL))
   1790		asus_kled_set(asus, 1);
   1791
   1792	/* LED display is off by default */
   1793	asus->ledd_status = 0xFFF;
   1794
   1795	/* Set initial values of light sensor and level */
   1796	asus->light_switch = !!als_status;
   1797	asus->light_level = 5;	/* level 5 for sensor sensitivity */
   1798
   1799	if (asus->is_pega_lucid) {
   1800		asus_als_switch(asus, asus->light_switch);
   1801	} else if (!acpi_check_handle(asus->handle, METHOD_ALS_CONTROL, NULL) &&
   1802		   !acpi_check_handle(asus->handle, METHOD_ALS_LEVEL, NULL)) {
   1803		asus_als_switch(asus, asus->light_switch);
   1804		asus_als_level(asus, asus->light_level);
   1805	}
   1806
   1807	return result;
   1808}
   1809
   1810static void asus_dmi_check(void)
   1811{
   1812	const char *model;
   1813
   1814	model = dmi_get_system_info(DMI_PRODUCT_NAME);
   1815	if (!model)
   1816		return;
   1817
   1818	/* On L1400B WLED control the sound card, don't mess with it ... */
   1819	if (strncmp(model, "L1400B", 6) == 0) {
   1820		wlan_status = -1;
   1821	}
   1822}
   1823
   1824static bool asus_device_present;
   1825
   1826static int asus_acpi_add(struct acpi_device *device)
   1827{
   1828	struct asus_laptop *asus;
   1829	int result;
   1830
   1831	pr_notice("Asus Laptop Support version %s\n",
   1832		  ASUS_LAPTOP_VERSION);
   1833	asus = kzalloc(sizeof(struct asus_laptop), GFP_KERNEL);
   1834	if (!asus)
   1835		return -ENOMEM;
   1836	asus->handle = device->handle;
   1837	strcpy(acpi_device_name(device), ASUS_LAPTOP_DEVICE_NAME);
   1838	strcpy(acpi_device_class(device), ASUS_LAPTOP_CLASS);
   1839	device->driver_data = asus;
   1840	asus->device = device;
   1841
   1842	asus_dmi_check();
   1843
   1844	result = asus_acpi_init(asus);
   1845	if (result)
   1846		goto fail_platform;
   1847
   1848	/*
   1849	 * Need platform type detection first, then the platform
   1850	 * device.  It is used as a parent for the sub-devices below.
   1851	 */
   1852	asus->is_pega_lucid = asus_check_pega_lucid(asus);
   1853	result = asus_platform_init(asus);
   1854	if (result)
   1855		goto fail_platform;
   1856
   1857	if (acpi_video_get_backlight_type() == acpi_backlight_vendor) {
   1858		result = asus_backlight_init(asus);
   1859		if (result)
   1860			goto fail_backlight;
   1861	}
   1862
   1863	result = asus_input_init(asus);
   1864	if (result)
   1865		goto fail_input;
   1866
   1867	result = asus_led_init(asus);
   1868	if (result)
   1869		goto fail_led;
   1870
   1871	result = asus_rfkill_init(asus);
   1872	if (result && result != -ENODEV)
   1873		goto fail_rfkill;
   1874
   1875	result = pega_accel_init(asus);
   1876	if (result && result != -ENODEV)
   1877		goto fail_pega_accel;
   1878
   1879	result = pega_rfkill_init(asus);
   1880	if (result && result != -ENODEV)
   1881		goto fail_pega_rfkill;
   1882
   1883	asus_device_present = true;
   1884	return 0;
   1885
   1886fail_pega_rfkill:
   1887	pega_accel_exit(asus);
   1888fail_pega_accel:
   1889	asus_rfkill_exit(asus);
   1890fail_rfkill:
   1891	asus_led_exit(asus);
   1892fail_led:
   1893	asus_input_exit(asus);
   1894fail_input:
   1895	asus_backlight_exit(asus);
   1896fail_backlight:
   1897	asus_platform_exit(asus);
   1898fail_platform:
   1899	kfree(asus);
   1900
   1901	return result;
   1902}
   1903
   1904static int asus_acpi_remove(struct acpi_device *device)
   1905{
   1906	struct asus_laptop *asus = acpi_driver_data(device);
   1907
   1908	asus_backlight_exit(asus);
   1909	asus_rfkill_exit(asus);
   1910	asus_led_exit(asus);
   1911	asus_input_exit(asus);
   1912	pega_accel_exit(asus);
   1913	asus_platform_exit(asus);
   1914
   1915	kfree(asus->name);
   1916	kfree(asus);
   1917	return 0;
   1918}
   1919
   1920static const struct acpi_device_id asus_device_ids[] = {
   1921	{"ATK0100", 0},
   1922	{"ATK0101", 0},
   1923	{"", 0},
   1924};
   1925MODULE_DEVICE_TABLE(acpi, asus_device_ids);
   1926
   1927static struct acpi_driver asus_acpi_driver = {
   1928	.name = ASUS_LAPTOP_NAME,
   1929	.class = ASUS_LAPTOP_CLASS,
   1930	.owner = THIS_MODULE,
   1931	.ids = asus_device_ids,
   1932	.flags = ACPI_DRIVER_ALL_NOTIFY_EVENTS,
   1933	.ops = {
   1934		.add = asus_acpi_add,
   1935		.remove = asus_acpi_remove,
   1936		.notify = asus_acpi_notify,
   1937		},
   1938};
   1939
   1940static int __init asus_laptop_init(void)
   1941{
   1942	int result;
   1943
   1944	result = platform_driver_register(&platform_driver);
   1945	if (result < 0)
   1946		return result;
   1947
   1948	result = acpi_bus_register_driver(&asus_acpi_driver);
   1949	if (result < 0)
   1950		goto fail_acpi_driver;
   1951	if (!asus_device_present) {
   1952		result = -ENODEV;
   1953		goto fail_no_device;
   1954	}
   1955	return 0;
   1956
   1957fail_no_device:
   1958	acpi_bus_unregister_driver(&asus_acpi_driver);
   1959fail_acpi_driver:
   1960	platform_driver_unregister(&platform_driver);
   1961	return result;
   1962}
   1963
   1964static void __exit asus_laptop_exit(void)
   1965{
   1966	acpi_bus_unregister_driver(&asus_acpi_driver);
   1967	platform_driver_unregister(&platform_driver);
   1968}
   1969
   1970module_init(asus_laptop_init);
   1971module_exit(asus_laptop_exit);