File Index
Files and directories
Sign in
FILE

asus-laptop.c

File preview with syntax highlighting.

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