asus-wmi.c 69.3 KB
Newer Older
1
// SPDX-License-Identifier: GPL-2.0-or-later
2
/*
3
 * Asus PC WMI hotkey driver
4 5
 *
 * Copyright(C) 2010 Intel Corporation.
C
Corentin Chary 已提交
6
 * Copyright(C) 2010-2011 Corentin Chary <corentin.chary@gmail.com>
7 8 9 10 11 12 13
 *
 * Portions based on wistron_btns.c:
 * Copyright (C) 2005 Miloslav Trmac <mitr@volny.cz>
 * Copyright (C) 2005 Bernhard Rosenkraenzer <bero@arklinux.org>
 * Copyright (C) 2005 Dmitry Torokhov <dtor@mail.ru>
 */

14 15
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt

16 17 18 19
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
#include <linux/types.h>
T
Tejun Heo 已提交
20
#include <linux/slab.h>
21 22
#include <linux/input.h>
#include <linux/input/sparse-keymap.h>
Y
Yong Wang 已提交
23 24
#include <linux/fb.h>
#include <linux/backlight.h>
25
#include <linux/leds.h>
26
#include <linux/rfkill.h>
27 28
#include <linux/pci.h>
#include <linux/pci_hotplug.h>
29
#include <linux/power_supply.h>
30 31
#include <linux/hwmon.h>
#include <linux/hwmon-sysfs.h>
C
Corentin Chary 已提交
32 33
#include <linux/debugfs.h>
#include <linux/seq_file.h>
34
#include <linux/platform_data/x86/asus-wmi.h>
35
#include <linux/platform_device.h>
36
#include <linux/acpi.h>
37
#include <linux/dmi.h>
38
#include <linux/units.h>
39 40

#include <acpi/battery.h>
41
#include <acpi/video.h>
42

43
#include "asus-wmi.h"
44

C
Corentin Chary 已提交
45
MODULE_AUTHOR("Corentin Chary <corentin.chary@gmail.com>, "
46 47
	      "Yong Wang <yong.y.wang@intel.com>");
MODULE_DESCRIPTION("Asus Generic WMI Driver");
48 49
MODULE_LICENSE("GPL");

50 51
#define to_asus_wmi_driver(pdrv)					\
	(container_of((pdrv), struct asus_wmi_driver, platform_driver))
52

53
#define ASUS_WMI_MGMT_GUID	"97845ED0-4E6D-11DE-8A39-0800200C9A66"
54

C
Corentin Chary 已提交
55 56 57 58
#define NOTIFY_BRNUP_MIN		0x11
#define NOTIFY_BRNUP_MAX		0x1f
#define NOTIFY_BRNDOWN_MIN		0x20
#define NOTIFY_BRNDOWN_MAX		0x2e
59
#define NOTIFY_FNLOCK_TOGGLE		0x4e
60
#define NOTIFY_KBD_DOCK_CHANGE		0x75
61 62
#define NOTIFY_KBD_BRTUP		0xc4
#define NOTIFY_KBD_BRTDWN		0xc5
63
#define NOTIFY_KBD_BRTTOGGLE		0xc7
64
#define NOTIFY_KBD_FBM			0x99
65
#define NOTIFY_KBD_TTP			0xae
66

67 68
#define ASUS_WMI_FNLOCK_BIOS_DISABLED	BIT(0)

K
Kast Bernd 已提交
69 70 71 72
#define ASUS_FAN_DESC			"cpu_fan"
#define ASUS_FAN_MFUN			0x13
#define ASUS_FAN_SFUN_READ		0x06
#define ASUS_FAN_SFUN_WRITE		0x07
73 74

/* Based on standard hwmon pwmX_enable values */
75
#define ASUS_FAN_CTRL_FULLSPEED		0
K
Kast Bernd 已提交
76 77 78
#define ASUS_FAN_CTRL_MANUAL		1
#define ASUS_FAN_CTRL_AUTO		2

79 80 81 82 83 84
#define ASUS_FAN_BOOST_MODE_NORMAL		0
#define ASUS_FAN_BOOST_MODE_OVERBOOST		1
#define ASUS_FAN_BOOST_MODE_OVERBOOST_MASK	0x01
#define ASUS_FAN_BOOST_MODE_SILENT		2
#define ASUS_FAN_BOOST_MODE_SILENT_MASK		0x02
#define ASUS_FAN_BOOST_MODES_MASK		0x03
85

86 87 88 89
#define ASUS_THROTTLE_THERMAL_POLICY_DEFAULT	0
#define ASUS_THROTTLE_THERMAL_POLICY_OVERBOOST	1
#define ASUS_THROTTLE_THERMAL_POLICY_SILENT	2

90 91 92
#define USB_INTEL_XUSB2PR		0xD0
#define PCI_DEVICE_ID_INTEL_LYNXPOINT_LP_XHCI	0x9c31

93
#define ASUS_ACPI_UID_ASUSWMI		"ASUSWMI"
94 95 96 97 98 99 100
#define ASUS_ACPI_UID_ATK		"ATK"

#define WMI_EVENT_QUEUE_SIZE		0x10
#define WMI_EVENT_QUEUE_END		0x1
#define WMI_EVENT_MASK			0xFFFF
/* The WMI hotkey event value is always the same. */
#define WMI_EVENT_VALUE_ATK		0xFF
101

102 103
#define WMI_EVENT_MASK			0xFFFF

104 105
static const char * const ashs_ids[] = { "ATK4001", "ATK4002", NULL };

106 107 108 109 110 111 112 113 114 115
static bool ashs_present(void)
{
	int i = 0;
	while (ashs_ids[i]) {
		if (acpi_dev_found(ashs_ids[i++]))
			return true;
	}
	return false;
}

Y
Yong Wang 已提交
116
struct bios_args {
117 118
	u32 arg0;
	u32 arg1;
119
	u32 arg2; /* At least TUF Gaming series uses 3 dword input buffer. */
120 121
	u32 arg4;
	u32 arg5;
122
} __packed;
Y
Yong Wang 已提交
123

K
Kast Bernd 已提交
124 125 126 127 128 129 130 131 132 133 134 135 136
/*
 * Struct that's used for all methods called via AGFN. Naming is
 * identically to the AML code.
 */
struct agfn_args {
	u16 mfun; /* probably "Multi-function" to be called */
	u16 sfun; /* probably "Sub-function" to be called */
	u16 len;  /* size of the hole struct, including subfunction fields */
	u8 stas;  /* not used by now */
	u8 err;   /* zero on success */
} __packed;

/* struct used for calling fan read and write methods */
137
struct agfn_fan_args {
K
Kast Bernd 已提交
138 139 140 141 142
	struct agfn_args agfn;	/* common fields */
	u8 fan;			/* fan number: 0: set auto mode 1: 1st fan */
	u32 speed;		/* read: RPM/100 - write: 0-255 */
} __packed;

C
Corentin Chary 已提交
143
/*
144
 * <platform>/    - debugfs root directory
C
Corentin Chary 已提交
145 146
 *   dev_id      - current dev_id
 *   ctrl_param  - current ctrl_param
147
 *   method_id   - current method_id
C
Corentin Chary 已提交
148 149
 *   devs        - call DEVS(dev_id, ctrl_param) and print result
 *   dsts        - call DSTS(dev_id)  and print result
150
 *   call        - call method_id(dev_id, ctrl_param) and print result
C
Corentin Chary 已提交
151
 */
152
struct asus_wmi_debug {
C
Corentin Chary 已提交
153
	struct dentry *root;
154
	u32 method_id;
C
Corentin Chary 已提交
155 156 157 158
	u32 dev_id;
	u32 ctrl_param;
};

159 160 161 162 163 164
struct asus_rfkill {
	struct asus_wmi *asus;
	struct rfkill *rfkill;
	u32 dev_id;
};

165 166 167
enum fan_type {
	FAN_TYPE_NONE = 0,
	FAN_TYPE_AGFN,		/* deprecated on newer platforms */
168
	FAN_TYPE_SPEC83,	/* starting in Spec 8.3, use CPU_FAN_CTRL */
169 170
};

171
struct asus_wmi {
172
	int dsts_id;
173 174
	int spec;
	int sfun;
175
	bool wmi_event_queue;
176

177
	struct input_dev *inputdev;
Y
Yong Wang 已提交
178
	struct backlight_device *backlight_device;
179
	struct platform_device *platform_device;
180

181 182
	struct led_classdev wlan_led;
	int wlan_led_wk;
183 184
	struct led_classdev tpd_led;
	int tpd_led_wk;
185 186
	struct led_classdev kbd_led;
	int kbd_led_wk;
187 188
	struct led_classdev lightbar_led;
	int lightbar_led_wk;
189 190
	struct workqueue_struct *led_workqueue;
	struct work_struct tpd_led_work;
191
	struct work_struct wlan_led_work;
192
	struct work_struct lightbar_led_work;
193

194 195 196 197
	struct asus_rfkill wlan;
	struct asus_rfkill bluetooth;
	struct asus_rfkill wimax;
	struct asus_rfkill wwan3g;
198
	struct asus_rfkill gps;
199
	struct asus_rfkill uwb;
C
Corentin Chary 已提交
200

201 202 203
	enum fan_type fan_type;
	int fan_pwm_mode;
	int agfn_pwm;
K
Kast Bernd 已提交
204

205 206 207
	bool fan_boost_mode_available;
	u8 fan_boost_mode_mask;
	u8 fan_boost_mode;
208

209 210 211
	bool throttle_thermal_policy_available;
	u8 throttle_thermal_policy_mode;

212 213
	// The RSOC controls the maximum charging percentage.
	bool battery_rsoc_available;
214

L
Lukas Wunner 已提交
215
	struct hotplug_slot hotplug_slot;
216
	struct mutex hotplug_lock;
217 218 219
	struct mutex wmi_lock;
	struct workqueue_struct *hotplug_workqueue;
	struct work_struct hotplug_work;
220

221 222
	bool fnlock_locked;

223 224 225
	struct asus_wmi_debug debug;

	struct asus_wmi_driver *driver;
226 227
};

228 229
/* WMI ************************************************************************/

230 231
static int asus_wmi_evaluate_method3(u32 method_id,
		u32 arg0, u32 arg1, u32 arg2, u32 *retval)
Y
Yong Wang 已提交
232
{
233 234 235
	struct bios_args args = {
		.arg0 = arg0,
		.arg1 = arg1,
236
		.arg2 = arg2,
237 238
	};
	struct acpi_buffer input = { (acpi_size) sizeof(args), &args };
Y
Yong Wang 已提交
239 240
	struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL };
	acpi_status status;
241
	union acpi_object *obj;
242
	u32 tmp = 0;
Y
Yong Wang 已提交
243

244
	status = wmi_evaluate_method(ASUS_WMI_MGMT_GUID, 0, method_id,
245
				     &input, &output);
Y
Yong Wang 已提交
246 247

	if (ACPI_FAILURE(status))
248
		return -EIO;
Y
Yong Wang 已提交
249 250 251

	obj = (union acpi_object *)output.pointer;
	if (obj && obj->type == ACPI_TYPE_INTEGER)
252
		tmp = (u32) obj->integer.value;
Y
Yong Wang 已提交
253

254 255
	if (retval)
		*retval = tmp;
Y
Yong Wang 已提交
256 257 258

	kfree(obj);

259 260
	if (tmp == ASUS_WMI_UNSUPPORTED_METHOD)
		return -ENODEV;
Y
Yong Wang 已提交
261

262
	return 0;
Y
Yong Wang 已提交
263
}
264 265 266 267 268

int asus_wmi_evaluate_method(u32 method_id, u32 arg0, u32 arg1, u32 *retval)
{
	return asus_wmi_evaluate_method3(method_id, arg0, arg1, 0, retval);
}
269
EXPORT_SYMBOL_GPL(asus_wmi_evaluate_method);
Y
Yong Wang 已提交
270

K
Kast Bernd 已提交
271 272 273 274 275
static int asus_wmi_evaluate_method_agfn(const struct acpi_buffer args)
{
	struct acpi_buffer input;
	u64 phys_addr;
	u32 retval;
276
	u32 status;
K
Kast Bernd 已提交
277 278 279 280 281

	/*
	 * Copy to dma capable address otherwise memory corruption occurs as
	 * bios has to be able to access it.
	 */
282
	input.pointer = kmemdup(args.pointer, args.length, GFP_DMA | GFP_KERNEL);
K
Kast Bernd 已提交
283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299
	input.length = args.length;
	if (!input.pointer)
		return -ENOMEM;
	phys_addr = virt_to_phys(input.pointer);

	status = asus_wmi_evaluate_method(ASUS_WMI_METHODID_AGFN,
					phys_addr, 0, &retval);
	if (!status)
		memcpy(args.pointer, input.pointer, args.length);

	kfree(input.pointer);
	if (status)
		return -ENXIO;

	return retval;
}

300
static int asus_wmi_get_devstate(struct asus_wmi *asus, u32 dev_id, u32 *retval)
Y
Yong Wang 已提交
301
{
302
	return asus_wmi_evaluate_method(asus->dsts_id, dev_id, 0, retval);
303
}
Y
Yong Wang 已提交
304

305
static int asus_wmi_set_devstate(u32 dev_id, u32 ctrl_param,
306
				 u32 *retval)
307 308 309
{
	return asus_wmi_evaluate_method(ASUS_WMI_METHODID_DEVS, dev_id,
					ctrl_param, retval);
Y
Yong Wang 已提交
310 311
}

312
/* Helper for special devices with magic return codes */
313 314
static int asus_wmi_get_devstate_bits(struct asus_wmi *asus,
				      u32 dev_id, u32 mask)
315 316
{
	u32 retval = 0;
317
	int err;
318

319
	err = asus_wmi_get_devstate(asus, dev_id, &retval);
320 321
	if (err < 0)
		return err;
322

323
	if (!(retval & ASUS_WMI_DSTS_PRESENCE_BIT))
324 325
		return -ENODEV;

326 327 328 329 330
	if (mask == ASUS_WMI_DSTS_STATUS_BIT) {
		if (retval & ASUS_WMI_DSTS_UNKNOWN_BIT)
			return -ENODEV;
	}

331 332 333
	return retval & mask;
}

334
static int asus_wmi_get_devstate_simple(struct asus_wmi *asus, u32 dev_id)
335
{
336 337
	return asus_wmi_get_devstate_bits(asus, dev_id,
					  ASUS_WMI_DSTS_STATUS_BIT);
338 339
}

340 341 342 343 344 345 346 347
static bool asus_wmi_dev_is_present(struct asus_wmi *asus, u32 dev_id)
{
	u32 retval;
	int status = asus_wmi_get_devstate(asus, dev_id, &retval);

	return status == 0 && (retval & ASUS_WMI_DSTS_PRESENCE_BIT);
}

348 349 350 351
/* Input **********************************************************************/

static int asus_wmi_input_init(struct asus_wmi *asus)
{
352
	int err, result;
353 354 355 356 357 358 359 360 361 362 363 364 365 366 367

	asus->inputdev = input_allocate_device();
	if (!asus->inputdev)
		return -ENOMEM;

	asus->inputdev->name = asus->driver->input_name;
	asus->inputdev->phys = asus->driver->input_phys;
	asus->inputdev->id.bustype = BUS_HOST;
	asus->inputdev->dev.parent = &asus->platform_device->dev;
	set_bit(EV_REP, asus->inputdev->evbit);

	err = sparse_keymap_setup(asus->inputdev, asus->driver->keymap, NULL);
	if (err)
		goto err_free_dev;

368 369 370 371 372 373 374 375
	result = asus_wmi_get_devstate_simple(asus, ASUS_WMI_DEVID_KBD_DOCK);
	if (result >= 0) {
		input_set_capability(asus->inputdev, EV_SW, SW_TABLET_MODE);
		input_report_switch(asus->inputdev, SW_TABLET_MODE, !result);
	} else if (result != -ENODEV) {
		pr_err("Error checking for keyboard-dock: %d\n", result);
	}

376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394
	err = input_register_device(asus->inputdev);
	if (err)
		goto err_free_dev;

	return 0;

err_free_dev:
	input_free_device(asus->inputdev);
	return err;
}

static void asus_wmi_input_exit(struct asus_wmi *asus)
{
	if (asus->inputdev)
		input_unregister_device(asus->inputdev);

	asus->inputdev = NULL;
}

395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439
/* Battery ********************************************************************/

/* The battery maximum charging percentage */
static int charge_end_threshold;

static ssize_t charge_control_end_threshold_store(struct device *dev,
						  struct device_attribute *attr,
						  const char *buf, size_t count)
{
	int value, ret, rv;

	ret = kstrtouint(buf, 10, &value);
	if (ret)
		return ret;

	if (value < 0 || value > 100)
		return -EINVAL;

	ret = asus_wmi_set_devstate(ASUS_WMI_DEVID_RSOC, value, &rv);
	if (ret)
		return ret;

	if (rv != 1)
		return -EIO;

	/* There isn't any method in the DSDT to read the threshold, so we
	 * save the threshold.
	 */
	charge_end_threshold = value;
	return count;
}

static ssize_t charge_control_end_threshold_show(struct device *device,
						 struct device_attribute *attr,
						 char *buf)
{
	return sprintf(buf, "%d\n", charge_end_threshold);
}

static DEVICE_ATTR_RW(charge_control_end_threshold);

static int asus_wmi_battery_add(struct power_supply *battery)
{
	/* The WMI method does not provide a way to specific a battery, so we
	 * just assume it is the first battery.
440 441
	 * Note: On some newer ASUS laptops (Zenbook UM431DA), the primary/first
	 * battery is named BATT.
442
	 */
443
	if (strcmp(battery->desc->name, "BAT0") != 0 &&
444
	    strcmp(battery->desc->name, "BAT1") != 0 &&
445
	    strcmp(battery->desc->name, "BATT") != 0)
446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 483 484 485 486 487 488 489
		return -ENODEV;

	if (device_create_file(&battery->dev,
	    &dev_attr_charge_control_end_threshold))
		return -ENODEV;

	/* The charge threshold is only reset when the system is power cycled,
	 * and we can't get the current threshold so let set it to 100% when
	 * a battery is added.
	 */
	asus_wmi_set_devstate(ASUS_WMI_DEVID_RSOC, 100, NULL);
	charge_end_threshold = 100;

	return 0;
}

static int asus_wmi_battery_remove(struct power_supply *battery)
{
	device_remove_file(&battery->dev,
			   &dev_attr_charge_control_end_threshold);
	return 0;
}

static struct acpi_battery_hook battery_hook = {
	.add_battery = asus_wmi_battery_add,
	.remove_battery = asus_wmi_battery_remove,
	.name = "ASUS Battery Extension",
};

static void asus_wmi_battery_init(struct asus_wmi *asus)
{
	asus->battery_rsoc_available = false;
	if (asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_RSOC)) {
		asus->battery_rsoc_available = true;
		battery_hook_register(&battery_hook);
	}
}

static void asus_wmi_battery_exit(struct asus_wmi *asus)
{
	if (asus->battery_rsoc_available)
		battery_hook_unregister(&battery_hook);
}

490 491
/* LEDs ***********************************************************************/

492 493 494
/*
 * These functions actually update the LED's, and are called from a
 * workqueue. By doing this as separate work rather than when the LED
495
 * subsystem asks, we avoid messing with the Asus ACPI stuff during a
496 497 498 499 500
 * potentially bad time, such as a timer interrupt.
 */
static void tpd_led_update(struct work_struct *work)
{
	int ctrl_param;
501
	struct asus_wmi *asus;
502

503
	asus = container_of(work, struct asus_wmi, tpd_led_work);
504

505 506
	ctrl_param = asus->tpd_led_wk;
	asus_wmi_set_devstate(ASUS_WMI_DEVID_TOUCHPAD_LED, ctrl_param, NULL);
507 508 509 510 511
}

static void tpd_led_set(struct led_classdev *led_cdev,
			enum led_brightness value)
{
512
	struct asus_wmi *asus;
513

514
	asus = container_of(led_cdev, struct asus_wmi, tpd_led);
515

516 517
	asus->tpd_led_wk = !!value;
	queue_work(asus->led_workqueue, &asus->tpd_led_work);
518 519
}

520
static int read_tpd_led_state(struct asus_wmi *asus)
521
{
522
	return asus_wmi_get_devstate_simple(asus, ASUS_WMI_DEVID_TOUCHPAD_LED);
523 524 525 526
}

static enum led_brightness tpd_led_get(struct led_classdev *led_cdev)
{
527
	struct asus_wmi *asus;
528

529
	asus = container_of(led_cdev, struct asus_wmi, tpd_led);
530

531
	return read_tpd_led_state(asus);
532 533
}

534
static void kbd_led_update(struct asus_wmi *asus)
535
{
536
	int ctrl_param = 0;
537

538
	ctrl_param = 0x80 | (asus->kbd_led_wk & 0x7F);
539 540
	asus_wmi_set_devstate(ASUS_WMI_DEVID_KBD_BACKLIGHT, ctrl_param, NULL);
}
541

542 543 544 545 546 547 548 549 550 551 552 553 554
static int kbd_led_read(struct asus_wmi *asus, int *level, int *env)
{
	int retval;

	/*
	 * bits 0-2: level
	 * bit 7: light on/off
	 * bit 8-10: environment (0: dark, 1: normal, 2: light)
	 * bit 17: status unknown
	 */
	retval = asus_wmi_get_devstate_bits(asus, ASUS_WMI_DEVID_KBD_BACKLIGHT,
					    0xFFFF);

555
	/* Unknown status is considered as off */
556
	if (retval == 0x8000)
557
		retval = 0;
558

559 560
	if (retval < 0)
		return retval;
561

562 563 564 565 566
	if (level)
		*level = retval & 0x7F;
	if (env)
		*env = (retval >> 8) & 0x7F;
	return 0;
567 568
}

569
static void do_kbd_led_set(struct led_classdev *led_cdev, int value)
570 571
{
	struct asus_wmi *asus;
572
	int max_level;
573 574

	asus = container_of(led_cdev, struct asus_wmi, kbd_led);
575
	max_level = asus->kbd_led.max_brightness;
576

577
	asus->kbd_led_wk = clamp_val(value, 0, max_level);
578
	kbd_led_update(asus);
579 580
}

581 582 583
static void kbd_led_set(struct led_classdev *led_cdev,
			enum led_brightness value)
{
584 585 586 587
	/* Prevent disabling keyboard backlight on module unregister */
	if (led_cdev->flags & LED_UNREGISTERING)
		return;

588 589 590
	do_kbd_led_set(led_cdev, value);
}

591 592 593 594 595 596 597 598
static void kbd_led_set_by_kbd(struct asus_wmi *asus, enum led_brightness value)
{
	struct led_classdev *led_cdev = &asus->kbd_led;

	do_kbd_led_set(led_cdev, value);
	led_classdev_notify_brightness_hw_changed(led_cdev, asus->kbd_led_wk);
}

599 600 601 602 603 604 605 606 607 608 609 610
static enum led_brightness kbd_led_get(struct led_classdev *led_cdev)
{
	struct asus_wmi *asus;
	int retval, value;

	asus = container_of(led_cdev, struct asus_wmi, kbd_led);

	retval = kbd_led_read(asus, &value, NULL);
	if (retval < 0)
		return retval;

	return value;
611 612
}

613 614 615 616 617 618 619 620 621 622 623 624 625 626 627 628 629 630 631 632 633 634 635 636 637 638 639 640 641 642 643 644 645 646 647 648 649 650 651 652 653 654
static int wlan_led_unknown_state(struct asus_wmi *asus)
{
	u32 result;

	asus_wmi_get_devstate(asus, ASUS_WMI_DEVID_WIRELESS_LED, &result);

	return result & ASUS_WMI_DSTS_UNKNOWN_BIT;
}

static void wlan_led_update(struct work_struct *work)
{
	int ctrl_param;
	struct asus_wmi *asus;

	asus = container_of(work, struct asus_wmi, wlan_led_work);

	ctrl_param = asus->wlan_led_wk;
	asus_wmi_set_devstate(ASUS_WMI_DEVID_WIRELESS_LED, ctrl_param, NULL);
}

static void wlan_led_set(struct led_classdev *led_cdev,
			 enum led_brightness value)
{
	struct asus_wmi *asus;

	asus = container_of(led_cdev, struct asus_wmi, wlan_led);

	asus->wlan_led_wk = !!value;
	queue_work(asus->led_workqueue, &asus->wlan_led_work);
}

static enum led_brightness wlan_led_get(struct led_classdev *led_cdev)
{
	struct asus_wmi *asus;
	u32 result;

	asus = container_of(led_cdev, struct asus_wmi, wlan_led);
	asus_wmi_get_devstate(asus, ASUS_WMI_DEVID_WIRELESS_LED, &result);

	return result & ASUS_WMI_DSTS_BRIGHTNESS_MASK;
}

655 656 657 658 659 660 661 662 663 664 665 666 667 668 669 670 671 672 673 674 675 676 677 678 679 680 681 682 683 684 685 686 687
static void lightbar_led_update(struct work_struct *work)
{
	struct asus_wmi *asus;
	int ctrl_param;

	asus = container_of(work, struct asus_wmi, lightbar_led_work);

	ctrl_param = asus->lightbar_led_wk;
	asus_wmi_set_devstate(ASUS_WMI_DEVID_LIGHTBAR, ctrl_param, NULL);
}

static void lightbar_led_set(struct led_classdev *led_cdev,
			     enum led_brightness value)
{
	struct asus_wmi *asus;

	asus = container_of(led_cdev, struct asus_wmi, lightbar_led);

	asus->lightbar_led_wk = !!value;
	queue_work(asus->led_workqueue, &asus->lightbar_led_work);
}

static enum led_brightness lightbar_led_get(struct led_classdev *led_cdev)
{
	struct asus_wmi *asus;
	u32 result;

	asus = container_of(led_cdev, struct asus_wmi, lightbar_led);
	asus_wmi_get_devstate(asus, ASUS_WMI_DEVID_LIGHTBAR, &result);

	return result & ASUS_WMI_DSTS_LIGHTBAR_MASK;
}

688
static void asus_wmi_led_exit(struct asus_wmi *asus)
689
{
690 691 692 693 694
	led_classdev_unregister(&asus->kbd_led);
	led_classdev_unregister(&asus->tpd_led);
	led_classdev_unregister(&asus->wlan_led);
	led_classdev_unregister(&asus->lightbar_led);

695 696
	if (asus->led_workqueue)
		destroy_workqueue(asus->led_workqueue);
697 698
}

699 700
static int asus_wmi_led_init(struct asus_wmi *asus)
{
701
	int rv = 0, led_val;
702 703 704 705 706 707 708 709 710 711 712 713 714 715 716 717 718 719 720

	asus->led_workqueue = create_singlethread_workqueue("led_workqueue");
	if (!asus->led_workqueue)
		return -ENOMEM;

	if (read_tpd_led_state(asus) >= 0) {
		INIT_WORK(&asus->tpd_led_work, tpd_led_update);

		asus->tpd_led.name = "asus::touchpad";
		asus->tpd_led.brightness_set = tpd_led_set;
		asus->tpd_led.brightness_get = tpd_led_get;
		asus->tpd_led.max_brightness = 1;

		rv = led_classdev_register(&asus->platform_device->dev,
					   &asus->tpd_led);
		if (rv)
			goto error;
	}

721
	if (!kbd_led_read(asus, &led_val, NULL)) {
722
		asus->kbd_led_wk = led_val;
723
		asus->kbd_led.name = "asus::kbd_backlight";
724
		asus->kbd_led.flags = LED_BRIGHT_HW_CHANGED;
725 726 727 728 729 730
		asus->kbd_led.brightness_set = kbd_led_set;
		asus->kbd_led.brightness_get = kbd_led_get;
		asus->kbd_led.max_brightness = 3;

		rv = led_classdev_register(&asus->platform_device->dev,
					   &asus->kbd_led);
731 732 733 734
		if (rv)
			goto error;
	}

735 736
	if (asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_WIRELESS_LED)
			&& (asus->driver->quirks->wapf > 0)) {
737 738 739 740 741 742 743 744 745 746 747 748
		INIT_WORK(&asus->wlan_led_work, wlan_led_update);

		asus->wlan_led.name = "asus::wlan";
		asus->wlan_led.brightness_set = wlan_led_set;
		if (!wlan_led_unknown_state(asus))
			asus->wlan_led.brightness_get = wlan_led_get;
		asus->wlan_led.flags = LED_CORE_SUSPENDRESUME;
		asus->wlan_led.max_brightness = 1;
		asus->wlan_led.default_trigger = "asus-wlan";

		rv = led_classdev_register(&asus->platform_device->dev,
					   &asus->wlan_led);
749 750 751 752
		if (rv)
			goto error;
	}

753
	if (asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_LIGHTBAR)) {
754 755 756 757 758 759 760 761 762
		INIT_WORK(&asus->lightbar_led_work, lightbar_led_update);

		asus->lightbar_led.name = "asus::lightbar";
		asus->lightbar_led.brightness_set = lightbar_led_set;
		asus->lightbar_led.brightness_get = lightbar_led_get;
		asus->lightbar_led.max_brightness = 1;

		rv = led_classdev_register(&asus->platform_device->dev,
					   &asus->lightbar_led);
763 764 765 766 767 768 769 770 771
	}

error:
	if (rv)
		asus_wmi_led_exit(asus);

	return rv;
}

772
/* RF *************************************************************************/
773

774 775 776
/*
 * PCI hotplug (for wlan rfkill)
 */
777
static bool asus_wlan_rfkill_blocked(struct asus_wmi *asus)
778
{
779
	int result = asus_wmi_get_devstate_simple(asus, ASUS_WMI_DEVID_WLAN);
780

781
	if (result < 0)
782
		return false;
783
	return !result;
784 785
}

786
static void asus_rfkill_hotplug(struct asus_wmi *asus)
787 788 789
{
	struct pci_dev *dev;
	struct pci_bus *bus;
790
	bool blocked;
791 792 793
	bool absent;
	u32 l;

794 795 796
	mutex_lock(&asus->wmi_lock);
	blocked = asus_wlan_rfkill_blocked(asus);
	mutex_unlock(&asus->wmi_lock);
797

798
	mutex_lock(&asus->hotplug_lock);
799
	pci_lock_rescan_remove();
800

801 802
	if (asus->wlan.rfkill)
		rfkill_set_sw_state(asus->wlan.rfkill, blocked);
803

L
Lukas Wunner 已提交
804
	if (asus->hotplug_slot.ops) {
805 806
		bus = pci_find_bus(0, 1);
		if (!bus) {
807
			pr_warn("Unable to find PCI bus 1?\n");
808 809 810 811 812 813 814 815 816 817
			goto out_unlock;
		}

		if (pci_bus_read_config_dword(bus, 0, PCI_VENDOR_ID, &l)) {
			pr_err("Unable to read PCI config space?\n");
			goto out_unlock;
		}
		absent = (l == 0xffffffff);

		if (blocked != absent) {
818 819 820 821 822 823
			pr_warn("BIOS says wireless lan is %s, "
				"but the pci device is %s\n",
				blocked ? "blocked" : "unblocked",
				absent ? "absent" : "present");
			pr_warn("skipped wireless hotplug as probably "
				"inappropriate for this model\n");
824 825 826 827 828 829 830 831 832 833 834 835 836
			goto out_unlock;
		}

		if (!blocked) {
			dev = pci_get_slot(bus, 0);
			if (dev) {
				/* Device already present */
				pci_dev_put(dev);
				goto out_unlock;
			}
			dev = pci_scan_single_device(bus, 0);
			if (dev) {
				pci_bus_assign_resources(bus);
837
				pci_bus_add_device(dev);
838 839 840 841
			}
		} else {
			dev = pci_get_slot(bus, 0);
			if (dev) {
842
				pci_stop_and_remove_bus_device(dev);
843 844 845 846 847 848
				pci_dev_put(dev);
			}
		}
	}

out_unlock:
849
	pci_unlock_rescan_remove();
850
	mutex_unlock(&asus->hotplug_lock);
851 852
}

853
static void asus_rfkill_notify(acpi_handle handle, u32 event, void *data)
854
{
855
	struct asus_wmi *asus = data;
856 857 858 859

	if (event != ACPI_NOTIFY_BUS_CHECK)
		return;

860
	/*
861
	 * We can't call directly asus_rfkill_hotplug because most
862 863
	 * of the time WMBC is still being executed and not reetrant.
	 * There is currently no way to tell ACPICA that  we want this
864
	 * method to be serialized, we schedule a asus_rfkill_hotplug
865 866
	 * call later, in a safer context.
	 */
867
	queue_work(asus->hotplug_workqueue, &asus->hotplug_work);
868 869
}

870
static int asus_register_rfkill_notifier(struct asus_wmi *asus, char *node)
871 872 873 874 875
{
	acpi_status status;
	acpi_handle handle;

	status = acpi_get_handle(NULL, node, &handle);
876
	if (ACPI_FAILURE(status))
877 878
		return -ENODEV;

879 880 881 882 883
	status = acpi_install_notify_handler(handle, ACPI_SYSTEM_NOTIFY,
					     asus_rfkill_notify, asus);
	if (ACPI_FAILURE(status))
		pr_warn("Failed to register notify on %s\n", node);

884 885 886
	return 0;
}

887
static void asus_unregister_rfkill_notifier(struct asus_wmi *asus, char *node)
888 889 890 891 892
{
	acpi_status status = AE_OK;
	acpi_handle handle;

	status = acpi_get_handle(NULL, node, &handle);
893 894
	if (ACPI_FAILURE(status))
		return;
895

896 897 898 899
	status = acpi_remove_notify_handler(handle, ACPI_SYSTEM_NOTIFY,
					    asus_rfkill_notify);
	if (ACPI_FAILURE(status))
		pr_err("Error removing rfkill notify handler %s\n", node);
900 901
}

902 903
static int asus_get_adapter_status(struct hotplug_slot *hotplug_slot,
				   u8 *value)
904
{
L
Lukas Wunner 已提交
905 906
	struct asus_wmi *asus = container_of(hotplug_slot,
					     struct asus_wmi, hotplug_slot);
907
	int result = asus_wmi_get_devstate_simple(asus, ASUS_WMI_DEVID_WLAN);
908

909 910
	if (result < 0)
		return result;
911

912
	*value = !!result;
913 914 915
	return 0;
}

916
static const struct hotplug_slot_ops asus_hotplug_slot_ops = {
917 918
	.get_adapter_status = asus_get_adapter_status,
	.get_power_status = asus_get_adapter_status,
919 920
};

921
static void asus_hotplug_work(struct work_struct *work)
922
{
923
	struct asus_wmi *asus;
924

925 926
	asus = container_of(work, struct asus_wmi, hotplug_work);
	asus_rfkill_hotplug(asus);
927 928
}

929
static int asus_setup_pci_hotplug(struct asus_wmi *asus)
930 931 932 933 934 935 936 937 938
{
	int ret = -ENOMEM;
	struct pci_bus *bus = pci_find_bus(0, 1);

	if (!bus) {
		pr_err("Unable to find wifi PCI bus\n");
		return -ENODEV;
	}

939 940 941
	asus->hotplug_workqueue =
	    create_singlethread_workqueue("hotplug_workqueue");
	if (!asus->hotplug_workqueue)
942 943
		goto error_workqueue;

944
	INIT_WORK(&asus->hotplug_work, asus_hotplug_work);
945

L
Lukas Wunner 已提交
946
	asus->hotplug_slot.ops = &asus_hotplug_slot_ops;
947

L
Lukas Wunner 已提交
948
	ret = pci_hp_register(&asus->hotplug_slot, bus, 0, "asus-wifi");
949 950 951 952 953 954 955 956
	if (ret) {
		pr_err("Unable to register hotplug slot - %d\n", ret);
		goto error_register;
	}

	return 0;

error_register:
L
Lukas Wunner 已提交
957
	asus->hotplug_slot.ops = NULL;
958
	destroy_workqueue(asus->hotplug_workqueue);
959
error_workqueue:
960 961 962
	return ret;
}

963 964 965
/*
 * Rfkill devices
 */
966
static int asus_rfkill_set(void *data, bool blocked)
967
{
968
	struct asus_rfkill *priv = data;
969
	u32 ctrl_param = !blocked;
970
	u32 dev_id = priv->dev_id;
971

972 973 974 975 976 977 978 979 980 981 982 983 984
	/*
	 * If the user bit is set, BIOS can't set and record the wlan status,
	 * it will report the value read from id ASUS_WMI_DEVID_WLAN_LED
	 * while we query the wlan status through WMI(ASUS_WMI_DEVID_WLAN).
	 * So, we have to record wlan status in id ASUS_WMI_DEVID_WLAN_LED
	 * while setting the wlan status through WMI.
	 * This is also the behavior that windows app will do.
	 */
	if ((dev_id == ASUS_WMI_DEVID_WLAN) &&
	     priv->asus->driver->wlan_ctrl_by_user)
		dev_id = ASUS_WMI_DEVID_WLAN_LED;

	return asus_wmi_set_devstate(dev_id, ctrl_param, NULL);
985 986
}

987
static void asus_rfkill_query(struct rfkill *rfkill, void *data)
988
{
989
	struct asus_rfkill *priv = data;
990
	int result;
991

992
	result = asus_wmi_get_devstate_simple(priv->asus, priv->dev_id);
993

994
	if (result < 0)
995
		return;
996

997
	rfkill_set_sw_state(priv->rfkill, !result);
998 999
}

1000
static int asus_rfkill_wlan_set(void *data, bool blocked)
1001
{
1002 1003
	struct asus_rfkill *priv = data;
	struct asus_wmi *asus = priv->asus;
1004 1005 1006 1007
	int ret;

	/*
	 * This handler is enabled only if hotplug is enabled.
1008
	 * In this case, the asus_wmi_set_devstate() will
1009 1010 1011 1012
	 * trigger a wmi notification and we need to wait
	 * this call to finish before being able to call
	 * any wmi method
	 */
1013
	mutex_lock(&asus->wmi_lock);
1014
	ret = asus_rfkill_set(data, blocked);
1015
	mutex_unlock(&asus->wmi_lock);
1016 1017 1018
	return ret;
}

1019 1020
static const struct rfkill_ops asus_rfkill_wlan_ops = {
	.set_block = asus_rfkill_wlan_set,
1021
	.query = asus_rfkill_query,
1022 1023
};

1024 1025 1026
static const struct rfkill_ops asus_rfkill_ops = {
	.set_block = asus_rfkill_set,
	.query = asus_rfkill_query,
1027 1028
};

1029
static int asus_new_rfkill(struct asus_wmi *asus,
1030
			   struct asus_rfkill *arfkill,
1031
			   const char *name, enum rfkill_type type, int dev_id)
1032
{
1033
	int result = asus_wmi_get_devstate_simple(asus, dev_id);
1034
	struct rfkill **rfkill = &arfkill->rfkill;
1035

1036 1037
	if (result < 0)
		return result;
1038

1039 1040 1041
	arfkill->dev_id = dev_id;
	arfkill->asus = asus;

1042 1043
	if (dev_id == ASUS_WMI_DEVID_WLAN &&
	    asus->driver->quirks->hotplug_wireless)
1044
		*rfkill = rfkill_alloc(name, &asus->platform_device->dev, type,
1045
				       &asus_rfkill_wlan_ops, arfkill);
1046
	else
1047
		*rfkill = rfkill_alloc(name, &asus->platform_device->dev, type,
1048
				       &asus_rfkill_ops, arfkill);
1049 1050 1051 1052

	if (!*rfkill)
		return -EINVAL;

1053
	if ((dev_id == ASUS_WMI_DEVID_WLAN) &&
1054
			(asus->driver->quirks->wapf > 0))
1055 1056
		rfkill_set_led_trigger_name(*rfkill, "asus-wlan");

1057
	rfkill_init_sw_state(*rfkill, !result);
1058 1059 1060 1061 1062 1063 1064 1065 1066
	result = rfkill_register(*rfkill);
	if (result) {
		rfkill_destroy(*rfkill);
		*rfkill = NULL;
		return result;
	}
	return 0;
}

1067
static void asus_wmi_rfkill_exit(struct asus_wmi *asus)
1068
{
1069 1070 1071
	if (asus->driver->wlan_ctrl_by_user && ashs_present())
		return;

1072 1073 1074
	asus_unregister_rfkill_notifier(asus, "\\_SB.PCI0.P0P5");
	asus_unregister_rfkill_notifier(asus, "\\_SB.PCI0.P0P6");
	asus_unregister_rfkill_notifier(asus, "\\_SB.PCI0.P0P7");
1075 1076 1077 1078
	if (asus->wlan.rfkill) {
		rfkill_unregister(asus->wlan.rfkill);
		rfkill_destroy(asus->wlan.rfkill);
		asus->wlan.rfkill = NULL;
1079
	}
1080 1081
	/*
	 * Refresh pci hotplug in case the rfkill state was changed after
1082
	 * asus_unregister_rfkill_notifier()
1083
	 */
1084
	asus_rfkill_hotplug(asus);
L
Lukas Wunner 已提交
1085 1086
	if (asus->hotplug_slot.ops)
		pci_hp_deregister(&asus->hotplug_slot);
1087 1088 1089
	if (asus->hotplug_workqueue)
		destroy_workqueue(asus->hotplug_workqueue);

1090 1091 1092 1093
	if (asus->bluetooth.rfkill) {
		rfkill_unregister(asus->bluetooth.rfkill);
		rfkill_destroy(asus->bluetooth.rfkill);
		asus->bluetooth.rfkill = NULL;
1094
	}
1095 1096 1097 1098
	if (asus->wimax.rfkill) {
		rfkill_unregister(asus->wimax.rfkill);
		rfkill_destroy(asus->wimax.rfkill);
		asus->wimax.rfkill = NULL;
C
Corentin Chary 已提交
1099
	}
1100 1101 1102 1103
	if (asus->wwan3g.rfkill) {
		rfkill_unregister(asus->wwan3g.rfkill);
		rfkill_destroy(asus->wwan3g.rfkill);
		asus->wwan3g.rfkill = NULL;
1104
	}
1105 1106 1107 1108 1109
	if (asus->gps.rfkill) {
		rfkill_unregister(asus->gps.rfkill);
		rfkill_destroy(asus->gps.rfkill);
		asus->gps.rfkill = NULL;
	}
1110 1111 1112 1113 1114
	if (asus->uwb.rfkill) {
		rfkill_unregister(asus->uwb.rfkill);
		rfkill_destroy(asus->uwb.rfkill);
		asus->uwb.rfkill = NULL;
	}
1115 1116
}

1117
static int asus_wmi_rfkill_init(struct asus_wmi *asus)
1118 1119 1120
{
	int result = 0;

1121 1122
	mutex_init(&asus->hotplug_lock);
	mutex_init(&asus->wmi_lock);
1123

1124 1125
	result = asus_new_rfkill(asus, &asus->wlan, "asus-wlan",
				 RFKILL_TYPE_WLAN, ASUS_WMI_DEVID_WLAN);
1126 1127 1128 1129

	if (result && result != -ENODEV)
		goto exit;

1130
	result = asus_new_rfkill(asus, &asus->bluetooth,
1131 1132
				 "asus-bluetooth", RFKILL_TYPE_BLUETOOTH,
				 ASUS_WMI_DEVID_BLUETOOTH);
1133 1134 1135 1136

	if (result && result != -ENODEV)
		goto exit;

1137 1138
	result = asus_new_rfkill(asus, &asus->wimax, "asus-wimax",
				 RFKILL_TYPE_WIMAX, ASUS_WMI_DEVID_WIMAX);
C
Corentin Chary 已提交
1139 1140 1141 1142

	if (result && result != -ENODEV)
		goto exit;

1143 1144
	result = asus_new_rfkill(asus, &asus->wwan3g, "asus-wwan3g",
				 RFKILL_TYPE_WWAN, ASUS_WMI_DEVID_WWAN3G);
1145 1146 1147 1148

	if (result && result != -ENODEV)
		goto exit;

1149 1150 1151 1152 1153 1154
	result = asus_new_rfkill(asus, &asus->gps, "asus-gps",
				 RFKILL_TYPE_GPS, ASUS_WMI_DEVID_GPS);

	if (result && result != -ENODEV)
		goto exit;

1155 1156 1157 1158 1159 1160
	result = asus_new_rfkill(asus, &asus->uwb, "asus-uwb",
				 RFKILL_TYPE_UWB, ASUS_WMI_DEVID_UWB);

	if (result && result != -ENODEV)
		goto exit;

1161
	if (!asus->driver->quirks->hotplug_wireless)
1162 1163
		goto exit;

1164
	result = asus_setup_pci_hotplug(asus);
1165 1166 1167 1168 1169 1170 1171
	/*
	 * If we get -EBUSY then something else is handling the PCI hotplug -
	 * don't fail in this case
	 */
	if (result == -EBUSY)
		result = 0;

1172 1173 1174
	asus_register_rfkill_notifier(asus, "\\_SB.PCI0.P0P5");
	asus_register_rfkill_notifier(asus, "\\_SB.PCI0.P0P6");
	asus_register_rfkill_notifier(asus, "\\_SB.PCI0.P0P7");
1175 1176 1177 1178
	/*
	 * Refresh pci hotplug in case the rfkill state was changed during
	 * setup.
	 */
1179
	asus_rfkill_hotplug(asus);
1180

1181 1182
exit:
	if (result && result != -ENODEV)
1183
		asus_wmi_rfkill_exit(asus);
1184 1185 1186 1187 1188 1189 1190

	if (result == -ENODEV)
		result = 0;

	return result;
}

1191 1192
/* Quirks *********************************************************************/

1193 1194 1195 1196 1197 1198 1199 1200 1201 1202 1203 1204 1205 1206 1207 1208 1209 1210 1211 1212 1213 1214 1215
static void asus_wmi_set_xusb2pr(struct asus_wmi *asus)
{
	struct pci_dev *xhci_pdev;
	u32 orig_ports_available;
	u32 ports_available = asus->driver->quirks->xusb2pr;

	xhci_pdev = pci_get_device(PCI_VENDOR_ID_INTEL,
			PCI_DEVICE_ID_INTEL_LYNXPOINT_LP_XHCI,
			NULL);

	if (!xhci_pdev)
		return;

	pci_read_config_dword(xhci_pdev, USB_INTEL_XUSB2PR,
				&orig_ports_available);

	pci_write_config_dword(xhci_pdev, USB_INTEL_XUSB2PR,
				cpu_to_le32(ports_available));

	pr_info("set USB_INTEL_XUSB2PR old: 0x%04x, new: 0x%04x\n",
			orig_ports_available, ports_available);
}

1216 1217 1218 1219 1220 1221 1222 1223 1224
/*
 * Some devices dont support or have borcken get_als method
 * but still support set method.
 */
static void asus_wmi_set_als(void)
{
	asus_wmi_set_devstate(ASUS_WMI_DEVID_ALS_ENABLE, 1, NULL);
}

1225 1226
/* Hwmon device ***************************************************************/

1227
static int asus_agfn_fan_speed_read(struct asus_wmi *asus, int fan,
K
Kast Bernd 已提交
1228 1229
					  int *speed)
{
1230
	struct agfn_fan_args args = {
K
Kast Bernd 已提交
1231 1232 1233 1234 1235 1236 1237 1238 1239 1240 1241 1242 1243 1244 1245 1246 1247 1248 1249 1250 1251 1252 1253
		.agfn.len = sizeof(args),
		.agfn.mfun = ASUS_FAN_MFUN,
		.agfn.sfun = ASUS_FAN_SFUN_READ,
		.fan = fan,
		.speed = 0,
	};
	struct acpi_buffer input = { (acpi_size) sizeof(args), &args };
	int status;

	if (fan != 1)
		return -EINVAL;

	status = asus_wmi_evaluate_method_agfn(input);

	if (status || args.agfn.err)
		return -ENXIO;

	if (speed)
		*speed = args.speed;

	return 0;
}

1254
static int asus_agfn_fan_speed_write(struct asus_wmi *asus, int fan,
K
Kast Bernd 已提交
1255 1256
				     int *speed)
{
1257
	struct agfn_fan_args args = {
K
Kast Bernd 已提交
1258 1259 1260 1261 1262 1263 1264 1265 1266 1267 1268 1269 1270 1271 1272 1273 1274 1275 1276
		.agfn.len = sizeof(args),
		.agfn.mfun = ASUS_FAN_MFUN,
		.agfn.sfun = ASUS_FAN_SFUN_WRITE,
		.fan = fan,
		.speed = speed ?  *speed : 0,
	};
	struct acpi_buffer input = { (acpi_size) sizeof(args), &args };
	int status;

	/* 1: for setting 1st fan's speed 0: setting auto mode */
	if (fan != 1 && fan != 0)
		return -EINVAL;

	status = asus_wmi_evaluate_method_agfn(input);

	if (status || args.agfn.err)
		return -ENXIO;

	if (speed && fan == 1)
1277
		asus->agfn_pwm = *speed;
K
Kast Bernd 已提交
1278 1279 1280 1281 1282 1283 1284 1285

	return 0;
}

/*
 * Check if we can read the speed of one fan. If true we assume we can also
 * control it.
 */
1286
static bool asus_wmi_has_agfn_fan(struct asus_wmi *asus)
K
Kast Bernd 已提交
1287 1288
{
	int status;
1289 1290
	int speed;
	u32 value;
K
Kast Bernd 已提交
1291

1292 1293 1294
	status = asus_agfn_fan_speed_read(asus, 1, &speed);
	if (status != 0)
		return false;
K
Kast Bernd 已提交
1295

1296 1297 1298
	status = asus_wmi_get_devstate(asus, ASUS_WMI_DEVID_FAN_CTRL, &value);
	if (status != 0)
		return false;
K
Kast Bernd 已提交
1299

1300 1301 1302 1303 1304 1305 1306 1307 1308 1309
	/*
	 * We need to find a better way, probably using sfun,
	 * bits or spec ...
	 * Currently we disable it if:
	 * - ASUS_WMI_UNSUPPORTED_METHOD is returned
	 * - reverved bits are non-zero
	 * - sfun and presence bit are not set
	 */
	return !(value == ASUS_WMI_UNSUPPORTED_METHOD || value & 0xFFF80000
		 || (!asus->sfun && !(value & ASUS_WMI_DSTS_PRESENCE_BIT)));
K
Kast Bernd 已提交
1310 1311
}

1312
static int asus_fan_set_auto(struct asus_wmi *asus)
K
Kast Bernd 已提交
1313 1314
{
	int status;
1315
	u32 retval;
K
Kast Bernd 已提交
1316

1317 1318 1319 1320 1321 1322 1323 1324 1325 1326 1327 1328 1329 1330 1331 1332 1333 1334
	switch (asus->fan_type) {
	case FAN_TYPE_SPEC83:
		status = asus_wmi_set_devstate(ASUS_WMI_DEVID_CPU_FAN_CTRL,
					       0, &retval);
		if (status)
			return status;

		if (retval != 1)
			return -EIO;
		break;

	case FAN_TYPE_AGFN:
		status = asus_agfn_fan_speed_write(asus, 0, NULL);
		if (status)
			return -ENXIO;
		break;

	default:
K
Kast Bernd 已提交
1335
		return -ENXIO;
1336 1337
	}

K
Kast Bernd 已提交
1338 1339 1340 1341

	return 0;
}

1342 1343 1344
static ssize_t pwm1_show(struct device *dev,
			       struct device_attribute *attr,
			       char *buf)
1345 1346 1347
{
	struct asus_wmi *asus = dev_get_drvdata(dev);
	int err;
1348
	int value;
1349

1350 1351 1352
	/* If we already set a value then just return it */
	if (asus->agfn_pwm >= 0)
		return sprintf(buf, "%d\n", asus->agfn_pwm);
1353

1354 1355 1356 1357 1358
	/*
	 * If we haven't set already set a value through the AGFN interface,
	 * we read a current value through the (now-deprecated) FAN_CTRL device.
	 */
	err = asus_wmi_get_devstate(asus, ASUS_WMI_DEVID_FAN_CTRL, &value);
1359
	if (err < 0)
1360
		return err;
1361

1362 1363 1364 1365 1366 1367 1368 1369 1370 1371 1372
	value &= 0xFF;

	if (value == 1) /* Low Speed */
		value = 85;
	else if (value == 2)
		value = 170;
	else if (value == 3)
		value = 255;
	else if (value) {
		pr_err("Unknown fan speed %#x\n", value);
		value = -1;
1373 1374 1375 1376 1377
	}

	return sprintf(buf, "%d\n", value);
}

K
Kast Bernd 已提交
1378 1379 1380 1381 1382 1383 1384 1385 1386 1387 1388 1389 1390 1391
static ssize_t pwm1_store(struct device *dev,
				     struct device_attribute *attr,
				     const char *buf, size_t count) {
	struct asus_wmi *asus = dev_get_drvdata(dev);
	int value;
	int state;
	int ret;

	ret = kstrtouint(buf, 10, &value);
	if (ret)
		return ret;

	value = clamp(value, 0, 255);

1392
	state = asus_agfn_fan_speed_write(asus, 1, &value);
K
Kast Bernd 已提交
1393 1394 1395
	if (state)
		pr_warn("Setting fan speed failed: %d\n", state);
	else
1396
		asus->fan_pwm_mode = ASUS_FAN_CTRL_MANUAL;
K
Kast Bernd 已提交
1397 1398 1399 1400 1401 1402 1403 1404

	return count;
}

static ssize_t fan1_input_show(struct device *dev,
					struct device_attribute *attr,
					char *buf)
{
1405 1406 1407
	struct asus_wmi *asus = dev_get_drvdata(dev);
	int value;
	int ret;
K
Kast Bernd 已提交
1408

1409 1410 1411 1412 1413 1414
	switch (asus->fan_type) {
	case FAN_TYPE_SPEC83:
		ret = asus_wmi_get_devstate(asus, ASUS_WMI_DEVID_CPU_FAN_CTRL,
					    &value);
		if (ret < 0)
			return ret;
1415

1416 1417 1418 1419 1420 1421 1422 1423 1424 1425 1426 1427 1428 1429 1430 1431
		value &= 0xffff;
		break;

	case FAN_TYPE_AGFN:
		/* no speed readable on manual mode */
		if (asus->fan_pwm_mode == ASUS_FAN_CTRL_MANUAL)
			return -ENXIO;

		ret = asus_agfn_fan_speed_read(asus, 1, &value);
		if (ret) {
			pr_warn("reading fan speed failed: %d\n", ret);
			return -ENXIO;
		}
		break;

	default:
1432 1433
		return -ENXIO;
	}
K
Kast Bernd 已提交
1434

1435
	return sprintf(buf, "%d\n", value < 0 ? -1 : value*100);
K
Kast Bernd 已提交
1436 1437 1438 1439 1440 1441 1442 1443
}

static ssize_t pwm1_enable_show(struct device *dev,
						 struct device_attribute *attr,
						 char *buf)
{
	struct asus_wmi *asus = dev_get_drvdata(dev);

1444 1445 1446 1447 1448 1449 1450 1451 1452
	/*
	 * Just read back the cached pwm mode.
	 *
	 * For the CPU_FAN device, the spec indicates that we should be
	 * able to read the device status and consult bit 19 to see if we
	 * are in Full On or Automatic mode. However, this does not work
	 * in practice on X532FL at least (the bit is always 0) and there's
	 * also nothing in the DSDT to indicate that this behaviour exists.
	 */
1453
	return sprintf(buf, "%d\n", asus->fan_pwm_mode);
K
Kast Bernd 已提交
1454 1455 1456 1457 1458 1459 1460 1461 1462
}

static ssize_t pwm1_enable_store(struct device *dev,
						  struct device_attribute *attr,
						  const char *buf, size_t count)
{
	struct asus_wmi *asus = dev_get_drvdata(dev);
	int status = 0;
	int state;
1463
	int value;
K
Kast Bernd 已提交
1464
	int ret;
1465
	u32 retval;
K
Kast Bernd 已提交
1466 1467 1468 1469 1470

	ret = kstrtouint(buf, 10, &state);
	if (ret)
		return ret;

1471 1472 1473 1474 1475 1476 1477 1478 1479 1480 1481
	if (asus->fan_type == FAN_TYPE_SPEC83) {
		switch (state) { /* standard documented hwmon values */
		case ASUS_FAN_CTRL_FULLSPEED:
			value = 1;
			break;
		case ASUS_FAN_CTRL_AUTO:
			value = 0;
			break;
		default:
			return -EINVAL;
		}
K
Kast Bernd 已提交
1482

1483 1484 1485 1486 1487 1488 1489 1490 1491 1492 1493 1494 1495 1496 1497 1498 1499 1500 1501 1502 1503
		ret = asus_wmi_set_devstate(ASUS_WMI_DEVID_CPU_FAN_CTRL,
					    value, &retval);
		if (ret)
			return ret;

		if (retval != 1)
			return -EIO;
	} else if (asus->fan_type == FAN_TYPE_AGFN) {
		switch (state) {
		case ASUS_FAN_CTRL_MANUAL:
			break;

		case ASUS_FAN_CTRL_AUTO:
			status = asus_fan_set_auto(asus);
			if (status)
				return status;
			break;

		default:
			return -EINVAL;
		}
1504 1505 1506
	}

	asus->fan_pwm_mode = state;
K
Kast Bernd 已提交
1507 1508 1509 1510 1511 1512 1513 1514 1515 1516
	return count;
}

static ssize_t fan1_label_show(struct device *dev,
					  struct device_attribute *attr,
					  char *buf)
{
	return sprintf(buf, "%s\n", ASUS_FAN_DESC);
}

C
Corentin Chary 已提交
1517 1518 1519 1520 1521 1522 1523 1524 1525 1526 1527 1528
static ssize_t asus_hwmon_temp1(struct device *dev,
				struct device_attribute *attr,
				char *buf)
{
	struct asus_wmi *asus = dev_get_drvdata(dev);
	u32 value;
	int err;

	err = asus_wmi_get_devstate(asus, ASUS_WMI_DEVID_THERMAL_CTRL, &value);
	if (err < 0)
		return err;

1529 1530
	return sprintf(buf, "%ld\n",
		       deci_kelvin_to_millicelsius(value & 0xFFFF));
C
Corentin Chary 已提交
1531 1532
}

K
Kast Bernd 已提交
1533 1534 1535 1536 1537 1538 1539
/* Fan1 */
static DEVICE_ATTR_RW(pwm1);
static DEVICE_ATTR_RW(pwm1_enable);
static DEVICE_ATTR_RO(fan1_input);
static DEVICE_ATTR_RO(fan1_label);

/* Temperature */
1540
static DEVICE_ATTR(temp1_input, S_IRUGO, asus_hwmon_temp1, NULL);
1541 1542

static struct attribute *hwmon_attributes[] = {
1543
	&dev_attr_pwm1.attr,
K
Kast Bernd 已提交
1544 1545 1546 1547
	&dev_attr_pwm1_enable.attr,
	&dev_attr_fan1_input.attr,
	&dev_attr_fan1_label.attr,

1548
	&dev_attr_temp1_input.attr,
1549 1550 1551
	NULL
};

1552
static umode_t asus_hwmon_sysfs_is_visible(struct kobject *kobj,
1553
					  struct attribute *attr, int idx)
1554 1555
{
	struct device *dev = container_of(kobj, struct device, kobj);
1556
	struct asus_wmi *asus = dev_get_drvdata(dev->parent);
1557
	u32 value = ASUS_WMI_UNSUPPORTED_METHOD;
K
Kast Bernd 已提交
1558

1559 1560 1561 1562
	if (attr == &dev_attr_pwm1.attr) {
		if (asus->fan_type != FAN_TYPE_AGFN)
			return 0;
	} else if (attr == &dev_attr_fan1_input.attr
K
Kast Bernd 已提交
1563 1564
	    || attr == &dev_attr_fan1_label.attr
	    || attr == &dev_attr_pwm1_enable.attr) {
1565 1566 1567 1568 1569 1570
		if (asus->fan_type == FAN_TYPE_NONE)
			return 0;
	} else if (attr == &dev_attr_temp1_input.attr) {
		int err = asus_wmi_get_devstate(asus,
						ASUS_WMI_DEVID_THERMAL_CTRL,
						&value);
1571

1572
		if (err < 0)
1573
			return 0; /* can't return negative here */
1574

1575 1576 1577 1578 1579
		/*
		 * If the temperature value in deci-Kelvin is near the absolute
		 * zero temperature, something is clearly wrong
		 */
		if (value == 0 || value == 1)
1580
			return 0;
1581 1582
	}

1583
	return attr->mode;
1584 1585
}

1586
static const struct attribute_group hwmon_attribute_group = {
1587 1588 1589
	.is_visible = asus_hwmon_sysfs_is_visible,
	.attrs = hwmon_attributes
};
1590
__ATTRIBUTE_GROUPS(hwmon_attribute);
1591 1592 1593

static int asus_wmi_hwmon_init(struct asus_wmi *asus)
{
1594
	struct device *dev = &asus->platform_device->dev;
1595 1596
	struct device *hwmon;

1597 1598 1599
	hwmon = devm_hwmon_device_register_with_groups(dev, "asus", asus,
			hwmon_attribute_groups);

1600 1601 1602 1603
	if (IS_ERR(hwmon)) {
		pr_err("Could not register asus hwmon device\n");
		return PTR_ERR(hwmon);
	}
1604
	return 0;
1605 1606
}

1607 1608
static int asus_wmi_fan_init(struct asus_wmi *asus)
{
1609 1610
	asus->fan_type = FAN_TYPE_NONE;
	asus->agfn_pwm = -1;
1611

1612 1613 1614
	if (asus_wmi_dev_is_present(asus, ASUS_WMI_DEVID_CPU_FAN_CTRL))
		asus->fan_type = FAN_TYPE_SPEC83;
	else if (asus_wmi_has_agfn_fan(asus))
1615
		asus->fan_type = FAN_TYPE_AGFN;
1616

1617 1618 1619 1620 1621 1622
	if (asus->fan_type == FAN_TYPE_NONE)
		return -ENODEV;

	asus_fan_set_auto(asus);
	asus->fan_pwm_mode = ASUS_FAN_CTRL_AUTO;
	return 0;
1623 1624
}

1625 1626
/* Fan mode *******************************************************************/

1627
static int fan_boost_mode_check_present(struct asus_wmi *asus)
1628 1629 1630 1631
{
	u32 result;
	int err;

1632
	asus->fan_boost_mode_available = false;
1633

1634 1635
	err = asus_wmi_get_devstate(asus, ASUS_WMI_DEVID_FAN_BOOST_MODE,
				    &result);
1636 1637 1638 1639 1640 1641 1642 1643
	if (err) {
		if (err == -ENODEV)
			return 0;
		else
			return err;
	}

	if ((result & ASUS_WMI_DSTS_PRESENCE_BIT) &&
1644 1645 1646
			(result & ASUS_FAN_BOOST_MODES_MASK)) {
		asus->fan_boost_mode_available = true;
		asus->fan_boost_mode_mask = result & ASUS_FAN_BOOST_MODES_MASK;
1647 1648 1649 1650 1651
	}

	return 0;
}

1652
static int fan_boost_mode_write(struct asus_wmi *asus)
1653 1654 1655 1656 1657
{
	int err;
	u8 value;
	u32 retval;

1658
	value = asus->fan_boost_mode;
1659

1660 1661 1662
	pr_info("Set fan boost mode: %u\n", value);
	err = asus_wmi_set_devstate(ASUS_WMI_DEVID_FAN_BOOST_MODE, value,
				    &retval);
1663
	if (err) {
1664
		pr_warn("Failed to set fan boost mode: %d\n", err);
1665 1666 1667 1668
		return err;
	}

	if (retval != 1) {
1669 1670
		pr_warn("Failed to set fan boost mode (retval): 0x%x\n",
			retval);
1671 1672 1673 1674 1675 1676
		return -EIO;
	}

	return 0;
}

1677
static int fan_boost_mode_switch_next(struct asus_wmi *asus)
1678
{
1679 1680 1681 1682 1683 1684 1685 1686 1687 1688
	u8 mask = asus->fan_boost_mode_mask;

	if (asus->fan_boost_mode == ASUS_FAN_BOOST_MODE_NORMAL) {
		if (mask & ASUS_FAN_BOOST_MODE_OVERBOOST_MASK)
			asus->fan_boost_mode = ASUS_FAN_BOOST_MODE_OVERBOOST;
		else if (mask & ASUS_FAN_BOOST_MODE_SILENT_MASK)
			asus->fan_boost_mode = ASUS_FAN_BOOST_MODE_SILENT;
	} else if (asus->fan_boost_mode == ASUS_FAN_BOOST_MODE_OVERBOOST) {
		if (mask & ASUS_FAN_BOOST_MODE_SILENT_MASK)
			asus->fan_boost_mode = ASUS_FAN_BOOST_MODE_SILENT;
1689
		else
1690
			asus->fan_boost_mode = ASUS_FAN_BOOST_MODE_NORMAL;
1691
	} else {
1692
		asus->fan_boost_mode = ASUS_FAN_BOOST_MODE_NORMAL;
1693 1694
	}

1695
	return fan_boost_mode_write(asus);
1696 1697
}

1698 1699
static ssize_t fan_boost_mode_show(struct device *dev,
				   struct device_attribute *attr, char *buf)
1700 1701 1702
{
	struct asus_wmi *asus = dev_get_drvdata(dev);

1703
	return scnprintf(buf, PAGE_SIZE, "%d\n", asus->fan_boost_mode);
1704 1705
}

1706 1707 1708
static ssize_t fan_boost_mode_store(struct device *dev,
				    struct device_attribute *attr,
				    const char *buf, size_t count)
1709 1710 1711 1712
{
	int result;
	u8 new_mode;
	struct asus_wmi *asus = dev_get_drvdata(dev);
1713
	u8 mask = asus->fan_boost_mode_mask;
1714 1715 1716 1717 1718 1719 1720

	result = kstrtou8(buf, 10, &new_mode);
	if (result < 0) {
		pr_warn("Trying to store invalid value\n");
		return result;
	}

1721 1722
	if (new_mode == ASUS_FAN_BOOST_MODE_OVERBOOST) {
		if (!(mask & ASUS_FAN_BOOST_MODE_OVERBOOST_MASK))
1723
			return -EINVAL;
1724 1725
	} else if (new_mode == ASUS_FAN_BOOST_MODE_SILENT) {
		if (!(mask & ASUS_FAN_BOOST_MODE_SILENT_MASK))
1726
			return -EINVAL;
1727
	} else if (new_mode != ASUS_FAN_BOOST_MODE_NORMAL) {
1728 1729 1730
		return -EINVAL;
	}

1731 1732
	asus->fan_boost_mode = new_mode;
	fan_boost_mode_write(asus);
1733

1734
	return count;
1735 1736
}

1737 1738
// Fan boost mode: 0 - normal, 1 - overboost, 2 - silent
static DEVICE_ATTR_RW(fan_boost_mode);
1739

1740 1741 1742 1743 1744 1745 1746 1747 1748 1749 1750 1751 1752 1753 1754 1755 1756 1757 1758 1759 1760 1761 1762 1763 1764 1765 1766 1767 1768 1769 1770 1771 1772 1773 1774 1775 1776 1777 1778 1779 1780 1781 1782 1783 1784 1785 1786 1787
/* Throttle thermal policy ****************************************************/

static int throttle_thermal_policy_check_present(struct asus_wmi *asus)
{
	u32 result;
	int err;

	asus->throttle_thermal_policy_available = false;

	err = asus_wmi_get_devstate(asus,
				    ASUS_WMI_DEVID_THROTTLE_THERMAL_POLICY,
				    &result);
	if (err) {
		if (err == -ENODEV)
			return 0;
		return err;
	}

	if (result & ASUS_WMI_DSTS_PRESENCE_BIT)
		asus->throttle_thermal_policy_available = true;

	return 0;
}

static int throttle_thermal_policy_write(struct asus_wmi *asus)
{
	int err;
	u8 value;
	u32 retval;

	value = asus->throttle_thermal_policy_mode;

	err = asus_wmi_set_devstate(ASUS_WMI_DEVID_THROTTLE_THERMAL_POLICY,
				    value, &retval);
	if (err) {
		pr_warn("Failed to set throttle thermal policy: %d\n", err);
		return err;
	}

	if (retval != 1) {
		pr_warn("Failed to set throttle thermal policy (retval): 0x%x\n",
			retval);
		return -EIO;
	}

	return 0;
}

1788 1789 1790 1791 1792 1793 1794 1795 1796
static int throttle_thermal_policy_set_default(struct asus_wmi *asus)
{
	if (!asus->throttle_thermal_policy_available)
		return 0;

	asus->throttle_thermal_policy_mode = ASUS_THROTTLE_THERMAL_POLICY_DEFAULT;
	return throttle_thermal_policy_write(asus);
}

1797 1798 1799 1800 1801 1802 1803 1804 1805 1806 1807 1808 1809 1810 1811 1812 1813 1814 1815 1816 1817 1818 1819 1820 1821 1822 1823 1824 1825 1826 1827 1828 1829 1830 1831 1832 1833 1834 1835 1836 1837 1838 1839 1840
static int throttle_thermal_policy_switch_next(struct asus_wmi *asus)
{
	u8 new_mode = asus->throttle_thermal_policy_mode + 1;

	if (new_mode > ASUS_THROTTLE_THERMAL_POLICY_SILENT)
		new_mode = ASUS_THROTTLE_THERMAL_POLICY_DEFAULT;

	asus->throttle_thermal_policy_mode = new_mode;
	return throttle_thermal_policy_write(asus);
}

static ssize_t throttle_thermal_policy_show(struct device *dev,
				   struct device_attribute *attr, char *buf)
{
	struct asus_wmi *asus = dev_get_drvdata(dev);
	u8 mode = asus->throttle_thermal_policy_mode;

	return scnprintf(buf, PAGE_SIZE, "%d\n", mode);
}

static ssize_t throttle_thermal_policy_store(struct device *dev,
				    struct device_attribute *attr,
				    const char *buf, size_t count)
{
	int result;
	u8 new_mode;
	struct asus_wmi *asus = dev_get_drvdata(dev);

	result = kstrtou8(buf, 10, &new_mode);
	if (result < 0)
		return result;

	if (new_mode > ASUS_THROTTLE_THERMAL_POLICY_SILENT)
		return -EINVAL;

	asus->throttle_thermal_policy_mode = new_mode;
	throttle_thermal_policy_write(asus);

	return count;
}

// Throttle thermal policy: 0 - default, 1 - overboost, 2 - silent
static DEVICE_ATTR_RW(throttle_thermal_policy);

1841 1842
/* Backlight ******************************************************************/

1843
static int read_backlight_power(struct asus_wmi *asus)
1844
{
1845
	int ret;
1846

1847 1848 1849 1850 1851
	if (asus->driver->quirks->store_backlight_power)
		ret = !asus->driver->panel_power;
	else
		ret = asus_wmi_get_devstate_simple(asus,
						   ASUS_WMI_DEVID_BACKLIGHT);
1852 1853 1854 1855 1856 1857 1858

	if (ret < 0)
		return ret;

	return ret ? FB_BLANK_UNBLANK : FB_BLANK_POWERDOWN;
}

1859
static int read_brightness_max(struct asus_wmi *asus)
Y
Yong Wang 已提交
1860
{
1861
	u32 retval;
1862
	int err;
Y
Yong Wang 已提交
1863

1864
	err = asus_wmi_get_devstate(asus, ASUS_WMI_DEVID_BRIGHTNESS, &retval);
1865 1866 1867 1868 1869 1870 1871 1872 1873 1874 1875 1876 1877 1878 1879
	if (err < 0)
		return err;

	retval = retval & ASUS_WMI_DSTS_MAX_BRIGTH_MASK;
	retval >>= 8;

	if (!retval)
		return -ENODEV;

	return retval;
}

static int read_brightness(struct backlight_device *bd)
{
	struct asus_wmi *asus = bl_get_data(bd);
1880 1881
	u32 retval;
	int err;
1882 1883

	err = asus_wmi_get_devstate(asus, ASUS_WMI_DEVID_BRIGHTNESS, &retval);
1884 1885 1886 1887
	if (err < 0)
		return err;

	return retval & ASUS_WMI_DSTS_BRIGHTNESS_MASK;
Y
Yong Wang 已提交
1888 1889
}

1890
static u32 get_scalar_command(struct backlight_device *bd)
Y
Yong Wang 已提交
1891
{
1892
	struct asus_wmi *asus = bl_get_data(bd);
1893
	u32 ctrl_param = 0;
Y
Yong Wang 已提交
1894

1895 1896 1897 1898 1899 1900
	if ((asus->driver->brightness < bd->props.brightness) ||
	    bd->props.brightness == bd->props.max_brightness)
		ctrl_param = 0x00008001;
	else if ((asus->driver->brightness > bd->props.brightness) ||
		 bd->props.brightness == 0)
		ctrl_param = 0x00008000;
Y
Yong Wang 已提交
1901

1902
	asus->driver->brightness = bd->props.brightness;
Y
Yong Wang 已提交
1903

1904 1905 1906
	return ctrl_param;
}

Y
Yong Wang 已提交
1907 1908
static int update_bl_status(struct backlight_device *bd)
{
1909
	struct asus_wmi *asus = bl_get_data(bd);
1910
	u32 ctrl_param;
1911
	int power, err = 0;
1912

1913
	power = read_backlight_power(asus);
1914 1915
	if (power != -ENODEV && bd->props.power != power) {
		ctrl_param = !!(bd->props.power == FB_BLANK_UNBLANK);
1916 1917
		err = asus_wmi_set_devstate(ASUS_WMI_DEVID_BACKLIGHT,
					    ctrl_param, NULL);
1918 1919 1920
		if (asus->driver->quirks->store_backlight_power)
			asus->driver->panel_power = bd->props.power;

1921 1922 1923 1924
		/* When using scalar brightness, updating the brightness
		 * will mess with the backlight power */
		if (asus->driver->quirks->scalar_panel_brightness)
			return err;
1925
	}
1926 1927 1928 1929 1930 1931 1932 1933 1934

	if (asus->driver->quirks->scalar_panel_brightness)
		ctrl_param = get_scalar_command(bd);
	else
		ctrl_param = bd->props.brightness;

	err = asus_wmi_set_devstate(ASUS_WMI_DEVID_BRIGHTNESS,
				    ctrl_param, NULL);

1935
	return err;
Y
Yong Wang 已提交
1936 1937
}

1938
static const struct backlight_ops asus_wmi_bl_ops = {
Y
Yong Wang 已提交
1939 1940 1941 1942
	.get_brightness = read_brightness,
	.update_status = update_bl_status,
};

1943
static int asus_wmi_backlight_notify(struct asus_wmi *asus, int code)
Y
Yong Wang 已提交
1944
{
1945
	struct backlight_device *bd = asus->backlight_device;
Y
Yong Wang 已提交
1946
	int old = bd->props.brightness;
1947
	int new = old;
Y
Yong Wang 已提交
1948 1949 1950 1951 1952 1953 1954 1955 1956 1957 1958 1959 1960

	if (code >= NOTIFY_BRNUP_MIN && code <= NOTIFY_BRNUP_MAX)
		new = code - NOTIFY_BRNUP_MIN + 1;
	else if (code >= NOTIFY_BRNDOWN_MIN && code <= NOTIFY_BRNDOWN_MAX)
		new = code - NOTIFY_BRNDOWN_MIN;

	bd->props.brightness = new;
	backlight_update_status(bd);
	backlight_force_update(bd, BACKLIGHT_UPDATE_HOTKEY);

	return old;
}

1961
static int asus_wmi_backlight_init(struct asus_wmi *asus)
Y
Yong Wang 已提交
1962 1963 1964
{
	struct backlight_device *bd;
	struct backlight_properties props;
1965 1966 1967
	int max;
	int power;

1968
	max = read_brightness_max(asus);
1969
	if (max < 0)
1970 1971 1972
		return max;

	power = read_backlight_power(asus);
1973 1974
	if (power == -ENODEV)
		power = FB_BLANK_UNBLANK;
1975 1976
	else if (power < 0)
		return power;
Y
Yong Wang 已提交
1977 1978

	memset(&props, 0, sizeof(struct backlight_properties));
1979
	props.type = BACKLIGHT_PLATFORM;
1980
	props.max_brightness = max;
1981 1982 1983
	bd = backlight_device_register(asus->driver->name,
				       &asus->platform_device->dev, asus,
				       &asus_wmi_bl_ops, &props);
Y
Yong Wang 已提交
1984 1985 1986 1987 1988
	if (IS_ERR(bd)) {
		pr_err("Could not register backlight device\n");
		return PTR_ERR(bd);
	}

1989
	asus->backlight_device = bd;
Y
Yong Wang 已提交
1990

1991 1992 1993
	if (asus->driver->quirks->store_backlight_power)
		asus->driver->panel_power = power;

Y
Yong Wang 已提交
1994
	bd->props.brightness = read_brightness(bd);
1995
	bd->props.power = power;
Y
Yong Wang 已提交
1996 1997
	backlight_update_status(bd);

1998 1999
	asus->driver->brightness = bd->props.brightness;

Y
Yong Wang 已提交
2000 2001 2002
	return 0;
}

2003
static void asus_wmi_backlight_exit(struct asus_wmi *asus)
Y
Yong Wang 已提交
2004
{
2005
	backlight_device_unregister(asus->backlight_device);
Y
Yong Wang 已提交
2006

2007
	asus->backlight_device = NULL;
Y
Yong Wang 已提交
2008 2009
}

A
AceLan Kao 已提交
2010 2011 2012 2013 2014 2015 2016 2017 2018 2019 2020 2021
static int is_display_toggle(int code)
{
	/* display toggle keys */
	if ((code >= 0x61 && code <= 0x67) ||
	    (code >= 0x8c && code <= 0x93) ||
	    (code >= 0xa0 && code <= 0xa7) ||
	    (code >= 0xd0 && code <= 0xd5))
		return 1;

	return 0;
}

2022 2023
/* Fn-lock ********************************************************************/

2024 2025 2026 2027 2028 2029 2030 2031 2032 2033 2034 2035 2036 2037 2038 2039 2040
static bool asus_wmi_has_fnlock_key(struct asus_wmi *asus)
{
	u32 result;

	asus_wmi_get_devstate(asus, ASUS_WMI_DEVID_FNLOCK, &result);

	return (result & ASUS_WMI_DSTS_PRESENCE_BIT) &&
		!(result & ASUS_WMI_FNLOCK_BIOS_DISABLED);
}

static void asus_wmi_fnlock_update(struct asus_wmi *asus)
{
	int mode = asus->fnlock_locked;

	asus_wmi_set_devstate(ASUS_WMI_DEVID_FNLOCK, mode, NULL);
}

2041 2042
/* WMI events *****************************************************************/

2043
static int asus_wmi_get_event_code(u32 value)
Y
Yong Wang 已提交
2044 2045 2046 2047 2048 2049 2050
{
	struct acpi_buffer response = { ACPI_ALLOCATE_BUFFER, NULL };
	union acpi_object *obj;
	acpi_status status;
	int code;

	status = wmi_get_event_data(value, &response);
2051 2052 2053 2054
	if (ACPI_FAILURE(status)) {
		pr_warn("Failed to get WMI notify code: %s\n",
				acpi_format_exception(status));
		return -EIO;
Y
Yong Wang 已提交
2055 2056 2057 2058
	}

	obj = (union acpi_object *)response.pointer;

2059 2060 2061 2062 2063 2064 2065 2066 2067 2068 2069 2070 2071
	if (obj && obj->type == ACPI_TYPE_INTEGER)
		code = (int)(obj->integer.value & WMI_EVENT_MASK);
	else
		code = -EIO;

	kfree(obj);
	return code;
}

static void asus_wmi_handle_event_code(int code, struct asus_wmi *asus)
{
	unsigned int key_value = 1;
	bool autorelease = 1;
2072
	int result, orig_code;
Y
Yong Wang 已提交
2073

C
Corentin Chary 已提交
2074
	orig_code = code;
Y
Yong Wang 已提交
2075

2076 2077 2078 2079
	if (asus->driver->key_filter) {
		asus->driver->key_filter(asus->driver, &code, &key_value,
					 &autorelease);
		if (code == ASUS_WMI_KEY_IGNORE)
2080
			return;
2081 2082
	}

C
Corentin Chary 已提交
2083
	if (code >= NOTIFY_BRNUP_MIN && code <= NOTIFY_BRNUP_MAX)
2084
		code = ASUS_WMI_BRN_UP;
2085
	else if (code >= NOTIFY_BRNDOWN_MIN && code <= NOTIFY_BRNDOWN_MAX)
2086
		code = ASUS_WMI_BRN_DOWN;
Y
Yong Wang 已提交
2087

2088
	if (code == ASUS_WMI_BRN_DOWN || code == ASUS_WMI_BRN_UP) {
2089
		if (acpi_video_get_backlight_type() == acpi_backlight_vendor) {
C
Corentin Chary 已提交
2090
			asus_wmi_backlight_notify(asus, orig_code);
2091
			return;
A
AceLan Kao 已提交
2092 2093 2094
		}
	}

2095
	if (code == NOTIFY_KBD_BRTUP) {
2096
		kbd_led_set_by_kbd(asus, asus->kbd_led_wk + 1);
2097
		return;
2098 2099
	}
	if (code == NOTIFY_KBD_BRTDWN) {
2100
		kbd_led_set_by_kbd(asus, asus->kbd_led_wk - 1);
2101
		return;
2102
	}
2103 2104
	if (code == NOTIFY_KBD_BRTTOGGLE) {
		if (asus->kbd_led_wk == asus->kbd_led.max_brightness)
2105
			kbd_led_set_by_kbd(asus, 0);
2106
		else
2107
			kbd_led_set_by_kbd(asus, asus->kbd_led_wk + 1);
2108
		return;
2109
	}
2110

2111 2112 2113
	if (code == NOTIFY_FNLOCK_TOGGLE) {
		asus->fnlock_locked = !asus->fnlock_locked;
		asus_wmi_fnlock_update(asus);
2114
		return;
2115 2116
	}

2117 2118 2119 2120 2121 2122 2123 2124 2125 2126 2127
	if (code == NOTIFY_KBD_DOCK_CHANGE) {
		result = asus_wmi_get_devstate_simple(asus,
						      ASUS_WMI_DEVID_KBD_DOCK);
		if (result >= 0) {
			input_report_switch(asus->inputdev, SW_TABLET_MODE,
					    !result);
			input_sync(asus->inputdev);
		}
		return;
	}

2128 2129
	if (asus->fan_boost_mode_available && code == NOTIFY_KBD_FBM) {
		fan_boost_mode_switch_next(asus);
2130 2131 2132
		return;
	}

2133 2134 2135 2136 2137
	if (asus->throttle_thermal_policy_available && code == NOTIFY_KBD_TTP) {
		throttle_thermal_policy_switch_next(asus);
		return;
	}

2138 2139
	if (is_display_toggle(code) && asus->driver->quirks->no_display_toggle)
		return;
A
AceLan Kao 已提交
2140 2141 2142

	if (!sparse_keymap_report_event(asus->inputdev, code,
					key_value, autorelease))
C
Corentin Chary 已提交
2143
		pr_info("Unknown key %x pressed\n", code);
2144
}
Y
Yong Wang 已提交
2145

2146 2147 2148
static void asus_wmi_notify(u32 value, void *context)
{
	struct asus_wmi *asus = context;
2149 2150
	int code;
	int i;
2151

2152 2153 2154 2155 2156 2157 2158 2159 2160 2161 2162 2163 2164 2165 2166 2167 2168 2169
	for (i = 0; i < WMI_EVENT_QUEUE_SIZE + 1; i++) {
		code = asus_wmi_get_event_code(value);
		if (code < 0) {
			pr_warn("Failed to get notify code: %d\n", code);
			return;
		}

		if (code == WMI_EVENT_QUEUE_END || code == WMI_EVENT_MASK)
			return;

		asus_wmi_handle_event_code(code, asus);

		/*
		 * Double check that queue is present:
		 * ATK (with queue) uses 0xff, ASUSWMI (without) 0xd2.
		 */
		if (!asus->wmi_event_queue || value != WMI_EVENT_VALUE_ATK)
			return;
2170 2171
	}

2172
	pr_warn("Failed to process event queue, last code: 0x%x\n", code);
Y
Yong Wang 已提交
2173 2174
}

2175 2176 2177 2178 2179 2180 2181 2182 2183 2184 2185 2186 2187 2188 2189 2190 2191 2192
static int asus_wmi_notify_queue_flush(struct asus_wmi *asus)
{
	int code;
	int i;

	for (i = 0; i < WMI_EVENT_QUEUE_SIZE + 1; i++) {
		code = asus_wmi_get_event_code(WMI_EVENT_VALUE_ATK);
		if (code < 0) {
			pr_warn("Failed to get event during flush: %d\n", code);
			return code;
		}

		if (code == WMI_EVENT_QUEUE_END || code == WMI_EVENT_MASK)
			return 0;
	}

	pr_warn("Failed to flush event queue\n");
	return -EIO;
Y
Yong Wang 已提交
2193 2194
}

2195 2196
/* Sysfs **********************************************************************/

2197 2198
static ssize_t store_sys_wmi(struct asus_wmi *asus, int devid,
			     const char *buf, size_t count)
2199 2200
{
	u32 retval;
2201
	int err, value;
2202

2203
	value = asus_wmi_get_devstate_simple(asus, devid);
2204
	if (value < 0)
2205 2206
		return value;

2207 2208 2209
	err = kstrtoint(buf, 0, &value);
	if (err)
		return err;
2210

2211
	err = asus_wmi_set_devstate(devid, value, &retval);
2212 2213
	if (err < 0)
		return err;
2214

2215
	return count;
2216 2217
}

2218
static ssize_t show_sys_wmi(struct asus_wmi *asus, int devid, char *buf)
2219
{
2220
	int value = asus_wmi_get_devstate_simple(asus, devid);
2221 2222 2223 2224 2225 2226 2227

	if (value < 0)
		return value;

	return sprintf(buf, "%d\n", value);
}

2228
#define ASUS_WMI_CREATE_DEVICE_ATTR(_name, _mode, _cm)			\
2229 2230 2231 2232
	static ssize_t show_##_name(struct device *dev,			\
				    struct device_attribute *attr,	\
				    char *buf)				\
	{								\
2233 2234 2235
		struct asus_wmi *asus = dev_get_drvdata(dev);		\
									\
		return show_sys_wmi(asus, _cm, buf);			\
2236 2237 2238 2239 2240
	}								\
	static ssize_t store_##_name(struct device *dev,		\
				     struct device_attribute *attr,	\
				     const char *buf, size_t count)	\
	{								\
2241 2242 2243
		struct asus_wmi *asus = dev_get_drvdata(dev);		\
									\
		return store_sys_wmi(asus, _cm, buf, count);		\
2244 2245 2246 2247 2248 2249 2250 2251 2252
	}								\
	static struct device_attribute dev_attr_##_name = {		\
		.attr = {						\
			.name = __stringify(_name),			\
			.mode = _mode },				\
		.show   = show_##_name,					\
		.store  = store_##_name,				\
	}

2253 2254 2255
ASUS_WMI_CREATE_DEVICE_ATTR(touchpad, 0644, ASUS_WMI_DEVID_TOUCHPAD);
ASUS_WMI_CREATE_DEVICE_ATTR(camera, 0644, ASUS_WMI_DEVID_CAMERA);
ASUS_WMI_CREATE_DEVICE_ATTR(cardr, 0644, ASUS_WMI_DEVID_CARDREADER);
A
AceLan Kao 已提交
2256
ASUS_WMI_CREATE_DEVICE_ATTR(lid_resume, 0644, ASUS_WMI_DEVID_LID_RESUME);
2257
ASUS_WMI_CREATE_DEVICE_ATTR(als_enable, 0644, ASUS_WMI_DEVID_ALS_ENABLE);
2258

2259
static ssize_t cpufv_store(struct device *dev, struct device_attribute *attr,
D
Dmitry Torokhov 已提交
2260
			   const char *buf, size_t count)
2261
{
2262
	int value, rv;
2263

2264 2265 2266 2267
	rv = kstrtoint(buf, 0, &value);
	if (rv)
		return rv;

2268 2269 2270
	if (value < 0 || value > 2)
		return -EINVAL;

2271 2272 2273 2274 2275
	rv = asus_wmi_evaluate_method(ASUS_WMI_METHODID_CFVS, value, 0, NULL);
	if (rv < 0)
		return rv;

	return count;
2276 2277
}

2278
static DEVICE_ATTR_WO(cpufv);
2279

2280 2281
static struct attribute *platform_attributes[] = {
	&dev_attr_cpufv.attr,
2282 2283
	&dev_attr_camera.attr,
	&dev_attr_cardr.attr,
2284
	&dev_attr_touchpad.attr,
A
AceLan Kao 已提交
2285
	&dev_attr_lid_resume.attr,
2286
	&dev_attr_als_enable.attr,
2287
	&dev_attr_fan_boost_mode.attr,
2288
	&dev_attr_throttle_thermal_policy.attr,
2289 2290 2291
	NULL
};

2292
static umode_t asus_sysfs_is_visible(struct kobject *kobj,
2293
				    struct attribute *attr, int idx)
2294
{
2295
	struct device *dev = container_of(kobj, struct device, kobj);
2296
	struct asus_wmi *asus = dev_get_drvdata(dev);
2297
	bool ok = true;
2298 2299 2300
	int devid = -1;

	if (attr == &dev_attr_camera.attr)
2301
		devid = ASUS_WMI_DEVID_CAMERA;
2302
	else if (attr == &dev_attr_cardr.attr)
2303
		devid = ASUS_WMI_DEVID_CARDREADER;
2304
	else if (attr == &dev_attr_touchpad.attr)
2305
		devid = ASUS_WMI_DEVID_TOUCHPAD;
A
AceLan Kao 已提交
2306 2307
	else if (attr == &dev_attr_lid_resume.attr)
		devid = ASUS_WMI_DEVID_LID_RESUME;
2308 2309
	else if (attr == &dev_attr_als_enable.attr)
		devid = ASUS_WMI_DEVID_ALS_ENABLE;
2310 2311
	else if (attr == &dev_attr_fan_boost_mode.attr)
		ok = asus->fan_boost_mode_available;
2312 2313
	else if (attr == &dev_attr_throttle_thermal_policy.attr)
		ok = asus->throttle_thermal_policy_available;
2314 2315

	if (devid != -1)
2316
		ok = !(asus_wmi_get_devstate_simple(asus, devid) < 0);
2317

2318
	return ok ? attr->mode : 0;
2319 2320
}

2321
static const struct attribute_group platform_attribute_group = {
2322 2323
	.is_visible = asus_sysfs_is_visible,
	.attrs = platform_attributes
2324 2325
};

2326
static void asus_wmi_sysfs_exit(struct platform_device *device)
2327
{
2328
	sysfs_remove_group(&device->dev.kobj, &platform_attribute_group);
2329 2330
}

2331
static int asus_wmi_sysfs_init(struct platform_device *device)
2332
{
2333
	return sysfs_create_group(&device->dev.kobj, &platform_attribute_group);
2334 2335
}

2336 2337
/* Platform device ************************************************************/

2338
static int asus_wmi_platform_init(struct asus_wmi *asus)
2339
{
2340 2341
	struct device *dev = &asus->platform_device->dev;
	char *wmi_uid;
2342 2343 2344 2345
	int rv;

	/* INIT enable hotkeys on some models */
	if (!asus_wmi_evaluate_method(ASUS_WMI_METHODID_INIT, 0, 0, &rv))
V
vic 已提交
2346
		pr_info("Initialization: %#x\n", rv);
2347 2348 2349

	/* We don't know yet what to do with this version... */
	if (!asus_wmi_evaluate_method(ASUS_WMI_METHODID_SPEC, 0, 0x9, &rv)) {
V
vic 已提交
2350
		pr_info("BIOS WMI version: %d.%d\n", rv >> 16, rv & 0xFF);
2351 2352 2353 2354 2355 2356 2357 2358 2359 2360
		asus->spec = rv;
	}

	/*
	 * The SFUN method probably allows the original driver to get the list
	 * of features supported by a given model. For now, 0x0100 or 0x0800
	 * bit signifies that the laptop is equipped with a Wi-Fi MiniPCI card.
	 * The significance of others is yet to be found.
	 */
	if (!asus_wmi_evaluate_method(ASUS_WMI_METHODID_SFUN, 0, 0, &rv)) {
V
vic 已提交
2361
		pr_info("SFUN value: %#x\n", rv);
2362 2363 2364
		asus->sfun = rv;
	}

2365 2366 2367 2368 2369 2370
	/*
	 * Eee PC and Notebooks seems to have different method_id for DSTS,
	 * but it may also be related to the BIOS's SPEC.
	 * Note, on most Eeepc, there is no way to check if a method exist
	 * or note, while on notebooks, they returns 0xFFFFFFFE on failure,
	 * but once again, SPEC may probably be used for that kind of things.
2371 2372 2373 2374 2375 2376
	 *
	 * Additionally at least TUF Gaming series laptops return nothing for
	 * unknown methods, so the detection in this way is not possible.
	 *
	 * There is strong indication that only ACPI WMI devices that have _UID
	 * equal to "ASUSWMI" use DCTS whereas those with "ATK" use DSTS.
2377
	 */
2378 2379 2380 2381 2382 2383 2384 2385 2386
	wmi_uid = wmi_get_acpi_device_uid(ASUS_WMI_MGMT_GUID);
	if (!wmi_uid)
		return -ENODEV;

	if (!strcmp(wmi_uid, ASUS_ACPI_UID_ASUSWMI)) {
		dev_info(dev, "Detected ASUSWMI, use DCTS\n");
		asus->dsts_id = ASUS_WMI_METHODID_DCTS;
	} else {
		dev_info(dev, "Detected %s, not ASUSWMI, use DSTS\n", wmi_uid);
2387
		asus->dsts_id = ASUS_WMI_METHODID_DSTS;
2388
	}
2389

2390 2391 2392 2393 2394 2395 2396 2397 2398 2399 2400 2401 2402 2403 2404 2405
	/*
	 * Some devices can have multiple event codes stored in a queue before
	 * the module load if it was unloaded intermittently after calling
	 * the INIT method (enables event handling). The WMI notify handler is
	 * expected to retrieve all event codes until a retrieved code equals
	 * queue end marker (One or Ones). Old codes are flushed from the queue
	 * upon module load. Not enabling this when it should be has minimal
	 * visible impact so fall back if anything goes wrong.
	 */
	wmi_uid = wmi_get_acpi_device_uid(asus->driver->event_guid);
	if (wmi_uid && !strcmp(wmi_uid, ASUS_ACPI_UID_ATK)) {
		dev_info(dev, "Detected ATK, enable event queue\n");

		if (!asus_wmi_notify_queue_flush(asus))
			asus->wmi_event_queue = true;
	}
2406

2407 2408
	/* CWAP allow to define the behavior of the Fn+F2 key,
	 * this method doesn't seems to be present on Eee PCs */
2409
	if (asus->driver->quirks->wapf >= 0)
2410
		asus_wmi_set_devstate(ASUS_WMI_DEVID_CWAP,
2411
				      asus->driver->quirks->wapf, NULL);
2412

2413
	return 0;
2414 2415
}

2416
/* debugfs ********************************************************************/
2417

2418 2419
struct asus_wmi_debugfs_node {
	struct asus_wmi *asus;
C
Corentin Chary 已提交
2420
	char *name;
2421
	int (*show) (struct seq_file *m, void *data);
C
Corentin Chary 已提交
2422 2423 2424 2425
};

static int show_dsts(struct seq_file *m, void *data)
{
2426
	struct asus_wmi *asus = m->private;
2427
	int err;
C
Corentin Chary 已提交
2428 2429
	u32 retval = -1;

2430
	err = asus_wmi_get_devstate(asus, asus->debug.dev_id, &retval);
2431 2432
	if (err < 0)
		return err;
C
Corentin Chary 已提交
2433

2434
	seq_printf(m, "DSTS(%#x) = %#x\n", asus->debug.dev_id, retval);
C
Corentin Chary 已提交
2435 2436 2437 2438 2439 2440

	return 0;
}

static int show_devs(struct seq_file *m, void *data)
{
2441
	struct asus_wmi *asus = m->private;
2442
	int err;
C
Corentin Chary 已提交
2443 2444
	u32 retval = -1;

2445 2446 2447 2448
	err = asus_wmi_set_devstate(asus->debug.dev_id, asus->debug.ctrl_param,
				    &retval);
	if (err < 0)
		return err;
C
Corentin Chary 已提交
2449

2450
	seq_printf(m, "DEVS(%#x, %#x) = %#x\n", asus->debug.dev_id,
2451
		   asus->debug.ctrl_param, retval);
C
Corentin Chary 已提交
2452 2453 2454 2455

	return 0;
}

2456 2457 2458 2459 2460 2461 2462 2463 2464 2465 2466 2467 2468
static int show_call(struct seq_file *m, void *data)
{
	struct asus_wmi *asus = m->private;
	struct bios_args args = {
		.arg0 = asus->debug.dev_id,
		.arg1 = asus->debug.ctrl_param,
	};
	struct acpi_buffer input = { (acpi_size) sizeof(args), &args };
	struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL };
	union acpi_object *obj;
	acpi_status status;

	status = wmi_evaluate_method(ASUS_WMI_MGMT_GUID,
2469
				     0, asus->debug.method_id,
2470 2471 2472 2473 2474 2475 2476 2477 2478 2479 2480 2481 2482
				     &input, &output);

	if (ACPI_FAILURE(status))
		return -EIO;

	obj = (union acpi_object *)output.pointer;
	if (obj && obj->type == ACPI_TYPE_INTEGER)
		seq_printf(m, "%#x(%#x, %#x) = %#x\n", asus->debug.method_id,
			   asus->debug.dev_id, asus->debug.ctrl_param,
			   (u32) obj->integer.value);
	else
		seq_printf(m, "%#x(%#x, %#x) = t:%d\n", asus->debug.method_id,
			   asus->debug.dev_id, asus->debug.ctrl_param,
2483
			   obj ? obj->type : -1);
2484 2485 2486 2487 2488 2489

	kfree(obj);

	return 0;
}

2490 2491 2492
static struct asus_wmi_debugfs_node asus_wmi_debug_files[] = {
	{NULL, "devs", show_devs},
	{NULL, "dsts", show_dsts},
2493
	{NULL, "call", show_call},
C
Corentin Chary 已提交
2494 2495
};

2496
static int asus_wmi_debugfs_open(struct inode *inode, struct file *file)
C
Corentin Chary 已提交
2497
{
2498
	struct asus_wmi_debugfs_node *node = inode->i_private;
C
Corentin Chary 已提交
2499

2500
	return single_open(file, node->show, node->asus);
C
Corentin Chary 已提交
2501 2502
}

2503
static const struct file_operations asus_wmi_debugfs_io_ops = {
C
Corentin Chary 已提交
2504
	.owner = THIS_MODULE,
2505
	.open = asus_wmi_debugfs_open,
C
Corentin Chary 已提交
2506 2507 2508 2509 2510
	.read = seq_read,
	.llseek = seq_lseek,
	.release = single_release,
};

2511
static void asus_wmi_debugfs_exit(struct asus_wmi *asus)
C
Corentin Chary 已提交
2512
{
2513
	debugfs_remove_recursive(asus->debug.root);
C
Corentin Chary 已提交
2514 2515
}

2516
static void asus_wmi_debugfs_init(struct asus_wmi *asus)
C
Corentin Chary 已提交
2517 2518 2519
{
	int i;

2520
	asus->debug.root = debugfs_create_dir(asus->driver->name, NULL);
C
Corentin Chary 已提交
2521

2522 2523
	debugfs_create_x32("method_id", S_IRUGO | S_IWUSR, asus->debug.root,
			   &asus->debug.method_id);
2524

2525 2526
	debugfs_create_x32("dev_id", S_IRUGO | S_IWUSR, asus->debug.root,
			   &asus->debug.dev_id);
C
Corentin Chary 已提交
2527

2528 2529
	debugfs_create_x32("ctrl_param", S_IRUGO | S_IWUSR, asus->debug.root,
			   &asus->debug.ctrl_param);
C
Corentin Chary 已提交
2530

2531 2532
	for (i = 0; i < ARRAY_SIZE(asus_wmi_debug_files); i++) {
		struct asus_wmi_debugfs_node *node = &asus_wmi_debug_files[i];
C
Corentin Chary 已提交
2533

2534
		node->asus = asus;
2535 2536 2537
		debugfs_create_file(node->name, S_IFREG | S_IRUGO,
				    asus->debug.root, node,
				    &asus_wmi_debugfs_io_ops);
C
Corentin Chary 已提交
2538 2539 2540
	}
}

2541
/* Init / exit ****************************************************************/
K
Kast Bernd 已提交
2542

2543
static int asus_wmi_add(struct platform_device *pdev)
2544
{
2545 2546 2547
	struct platform_driver *pdrv = to_platform_driver(pdev->dev.driver);
	struct asus_wmi_driver *wdrv = to_asus_wmi_driver(pdrv);
	struct asus_wmi *asus;
2548
	const char *chassis_type;
2549
	acpi_status status;
2550
	int err;
2551
	u32 result;
2552

2553 2554
	asus = kzalloc(sizeof(struct asus_wmi), GFP_KERNEL);
	if (!asus)
2555 2556
		return -ENOMEM;

2557 2558 2559 2560
	asus->driver = wdrv;
	asus->platform_device = pdev;
	wdrv->platform_device = pdev;
	platform_set_drvdata(asus->platform_device, asus);
2561

2562 2563
	if (wdrv->detect_quirks)
		wdrv->detect_quirks(asus->driver);
2564

2565
	err = asus_wmi_platform_init(asus);
2566 2567
	if (err)
		goto fail_platform;
2568

2569
	err = fan_boost_mode_check_present(asus);
2570
	if (err)
2571
		goto fail_fan_boost_mode;
2572

2573 2574 2575
	err = throttle_thermal_policy_check_present(asus);
	if (err)
		goto fail_throttle_thermal_policy;
2576 2577
	else
		throttle_thermal_policy_set_default(asus);
2578

2579 2580 2581 2582
	err = asus_wmi_sysfs_init(asus->platform_device);
	if (err)
		goto fail_sysfs;

2583
	err = asus_wmi_input_init(asus);
2584
	if (err)
2585
		goto fail_input;
Y
Yong Wang 已提交
2586

K
Kast Bernd 已提交
2587 2588
	err = asus_wmi_fan_init(asus); /* probably no problems on error */

2589 2590 2591 2592
	err = asus_wmi_hwmon_init(asus);
	if (err)
		goto fail_hwmon;

2593
	err = asus_wmi_led_init(asus);
2594 2595 2596
	if (err)
		goto fail_leds;

2597 2598 2599 2600
	asus_wmi_get_devstate(asus, ASUS_WMI_DEVID_WLAN, &result);
	if (result & (ASUS_WMI_DSTS_PRESENCE_BIT | ASUS_WMI_DSTS_USER_BIT))
		asus->driver->wlan_ctrl_by_user = 1;

2601
	if (!(asus->driver->wlan_ctrl_by_user && ashs_present())) {
2602 2603 2604 2605
		err = asus_wmi_rfkill_init(asus);
		if (err)
			goto fail_rfkill;
	}
2606

2607 2608 2609
	if (asus->driver->quirks->wmi_force_als_set)
		asus_wmi_set_als();

2610 2611 2612 2613
	/* Some Asus desktop boards export an acpi-video backlight interface,
	   stop this from showing up */
	chassis_type = dmi_get_system_info(DMI_CHASSIS_TYPE);
	if (chassis_type && !strcmp(chassis_type, "3"))
2614 2615
		acpi_video_set_dmi_backlight_type(acpi_backlight_vendor);

2616
	if (asus->driver->quirks->wmi_backlight_power)
2617 2618
		acpi_video_set_dmi_backlight_type(acpi_backlight_vendor);

2619 2620 2621
	if (asus->driver->quirks->wmi_backlight_native)
		acpi_video_set_dmi_backlight_type(acpi_backlight_native);

2622 2623 2624
	if (asus->driver->quirks->xusb2pr)
		asus_wmi_set_xusb2pr(asus);

2625
	if (acpi_video_get_backlight_type() == acpi_backlight_vendor) {
2626
		err = asus_wmi_backlight_init(asus);
2627
		if (err && err != -ENODEV)
2628
			goto fail_backlight;
2629
	} else if (asus->driver->quirks->wmi_backlight_set_devstate)
2630
		err = asus_wmi_set_devstate(ASUS_WMI_DEVID_BACKLIGHT, 2, NULL);
2631

2632 2633 2634 2635 2636
	if (asus_wmi_has_fnlock_key(asus)) {
		asus->fnlock_locked = true;
		asus_wmi_fnlock_update(asus);
	}

2637 2638
	status = wmi_install_notify_handler(asus->driver->event_guid,
					    asus_wmi_notify, asus);
2639
	if (ACPI_FAILURE(status)) {
2640
		pr_err("Unable to register notify handler - %d\n", status);
2641
		err = -ENODEV;
2642
		goto fail_wmi_handler;
2643 2644
	}

2645 2646
	asus_wmi_battery_init(asus);

2647
	asus_wmi_debugfs_init(asus);
C
Corentin Chary 已提交
2648

2649
	return 0;
2650

2651
fail_wmi_handler:
2652
	asus_wmi_backlight_exit(asus);
2653
fail_backlight:
2654
	asus_wmi_rfkill_exit(asus);
2655
fail_rfkill:
2656
	asus_wmi_led_exit(asus);
2657
fail_leds:
2658
fail_hwmon:
2659
	asus_wmi_input_exit(asus);
2660
fail_input:
2661 2662
	asus_wmi_sysfs_exit(asus->platform_device);
fail_sysfs:
2663
fail_throttle_thermal_policy:
2664
fail_fan_boost_mode:
2665
fail_platform:
2666
	kfree(asus);
2667
	return err;
2668 2669
}

2670
static int asus_wmi_remove(struct platform_device *device)
2671
{
2672 2673 2674 2675 2676 2677 2678 2679 2680
	struct asus_wmi *asus;

	asus = platform_get_drvdata(device);
	wmi_remove_notify_handler(asus->driver->event_guid);
	asus_wmi_backlight_exit(asus);
	asus_wmi_input_exit(asus);
	asus_wmi_led_exit(asus);
	asus_wmi_rfkill_exit(asus);
	asus_wmi_debugfs_exit(asus);
2681
	asus_wmi_sysfs_exit(asus->platform_device);
2682
	asus_fan_set_auto(asus);
2683
	asus_wmi_battery_exit(asus);
2684 2685

	kfree(asus);
2686 2687 2688
	return 0;
}

2689 2690
/* Platform driver - hibernate/resume callbacks *******************************/

2691
static int asus_hotk_thaw(struct device *device)
2692
{
2693
	struct asus_wmi *asus = dev_get_drvdata(device);
2694

2695
	if (asus->wlan.rfkill) {
2696 2697 2698 2699 2700 2701 2702
		bool wlan;

		/*
		 * Work around bios bug - acpi _PTS turns off the wireless led
		 * during suspend.  Normally it restores it on resume, but
		 * we should kick it ourselves in case hibernation is aborted.
		 */
2703
		wlan = asus_wmi_get_devstate_simple(asus, ASUS_WMI_DEVID_WLAN);
2704
		asus_wmi_set_devstate(ASUS_WMI_DEVID_WLAN, wlan, NULL);
2705 2706 2707 2708 2709
	}

	return 0;
}

2710 2711 2712 2713 2714
static int asus_hotk_resume(struct device *device)
{
	struct asus_wmi *asus = dev_get_drvdata(device);

	if (!IS_ERR_OR_NULL(asus->kbd_led.dev))
2715
		kbd_led_update(asus);
2716

2717 2718
	if (asus_wmi_has_fnlock_key(asus))
		asus_wmi_fnlock_update(asus);
2719 2720 2721
	return 0;
}

2722
static int asus_hotk_restore(struct device *device)
2723
{
2724
	struct asus_wmi *asus = dev_get_drvdata(device);
2725 2726 2727
	int bl;

	/* Refresh both wlan rfkill state and pci hotplug */
2728
	if (asus->wlan.rfkill)
2729
		asus_rfkill_hotplug(asus);
2730

2731
	if (asus->bluetooth.rfkill) {
2732 2733
		bl = !asus_wmi_get_devstate_simple(asus,
						   ASUS_WMI_DEVID_BLUETOOTH);
2734
		rfkill_set_sw_state(asus->bluetooth.rfkill, bl);
C
Corentin Chary 已提交
2735
	}
2736
	if (asus->wimax.rfkill) {
2737
		bl = !asus_wmi_get_devstate_simple(asus, ASUS_WMI_DEVID_WIMAX);
2738
		rfkill_set_sw_state(asus->wimax.rfkill, bl);
C
Corentin Chary 已提交
2739
	}
2740
	if (asus->wwan3g.rfkill) {
2741
		bl = !asus_wmi_get_devstate_simple(asus, ASUS_WMI_DEVID_WWAN3G);
2742
		rfkill_set_sw_state(asus->wwan3g.rfkill, bl);
2743
	}
2744 2745 2746 2747
	if (asus->gps.rfkill) {
		bl = !asus_wmi_get_devstate_simple(asus, ASUS_WMI_DEVID_GPS);
		rfkill_set_sw_state(asus->gps.rfkill, bl);
	}
2748 2749 2750 2751
	if (asus->uwb.rfkill) {
		bl = !asus_wmi_get_devstate_simple(asus, ASUS_WMI_DEVID_UWB);
		rfkill_set_sw_state(asus->uwb.rfkill, bl);
	}
2752
	if (!IS_ERR_OR_NULL(asus->kbd_led.dev))
2753
		kbd_led_update(asus);
2754

2755 2756
	if (asus_wmi_has_fnlock_key(asus))
		asus_wmi_fnlock_update(asus);
2757 2758 2759
	return 0;
}

2760 2761 2762
static const struct dev_pm_ops asus_pm_ops = {
	.thaw = asus_hotk_thaw,
	.restore = asus_hotk_restore,
2763
	.resume = asus_hotk_resume,
2764 2765
};

2766 2767
/* Registration ***************************************************************/

2768
static int asus_wmi_probe(struct platform_device *pdev)
2769
{
2770 2771 2772
	struct platform_driver *pdrv = to_platform_driver(pdev->dev.driver);
	struct asus_wmi_driver *wdrv = to_asus_wmi_driver(pdrv);
	int ret;
2773

2774
	if (!wmi_has_guid(ASUS_WMI_MGMT_GUID)) {
2775
		pr_warn("ASUS Management GUID not found\n");
2776 2777 2778
		return -ENODEV;
	}

2779
	if (wdrv->event_guid && !wmi_has_guid(wdrv->event_guid)) {
2780
		pr_warn("ASUS Event GUID not found\n");
2781 2782 2783
		return -ENODEV;
	}

2784 2785 2786 2787 2788 2789 2790
	if (wdrv->probe) {
		ret = wdrv->probe(pdev);
		if (ret)
			return ret;
	}

	return asus_wmi_add(pdev);
2791
}
2792

2793
static bool used;
2794

C
Corentin Chary 已提交
2795
int __init_or_module asus_wmi_register_driver(struct asus_wmi_driver *driver)
2796
{
2797 2798 2799 2800 2801 2802 2803 2804 2805 2806 2807 2808 2809 2810
	struct platform_driver *platform_driver;
	struct platform_device *platform_device;

	if (used)
		return -EBUSY;

	platform_driver = &driver->platform_driver;
	platform_driver->remove = asus_wmi_remove;
	platform_driver->driver.owner = driver->owner;
	platform_driver->driver.name = driver->name;
	platform_driver->driver.pm = &asus_pm_ops;

	platform_device = platform_create_bundle(platform_driver,
						 asus_wmi_probe,
2811 2812 2813
						 NULL, 0, NULL, 0);
	if (IS_ERR(platform_device))
		return PTR_ERR(platform_device);
2814 2815 2816 2817 2818 2819 2820 2821 2822 2823 2824 2825 2826 2827 2828 2829

	used = true;
	return 0;
}
EXPORT_SYMBOL_GPL(asus_wmi_register_driver);

void asus_wmi_unregister_driver(struct asus_wmi_driver *driver)
{
	platform_device_unregister(driver->platform_device);
	platform_driver_unregister(&driver->platform_driver);
	used = false;
}
EXPORT_SYMBOL_GPL(asus_wmi_unregister_driver);

static int __init asus_wmi_init(void)
{
V
vic 已提交
2830
	pr_info("ASUS WMI generic driver loaded\n");
2831 2832 2833
	return 0;
}

2834
static void __exit asus_wmi_exit(void)
2835
{
V
vic 已提交
2836
	pr_info("ASUS WMI generic driver unloaded\n");
2837 2838
}

2839 2840
module_init(asus_wmi_init);
module_exit(asus_wmi_exit);