hp-wmi.c 24.7 KB
Newer Older
1 2 3 4
/*
 * HP WMI hotkeys
 *
 * Copyright (C) 2008 Red Hat <mjg@redhat.com>
5
 * Copyright (C) 2010, 2011 Anssi Hannula <anssi.hannula@iki.fi>
6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26
 *
 * 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>
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
 */

27 28
#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt

29 30 31
#include <linux/kernel.h>
#include <linux/module.h>
#include <linux/init.h>
32
#include <linux/slab.h>
33 34
#include <linux/types.h>
#include <linux/input.h>
35
#include <linux/input/sparse-keymap.h>
36 37 38 39 40 41 42 43 44 45 46 47 48 49 50
#include <linux/platform_device.h>
#include <linux/acpi.h>
#include <linux/rfkill.h>
#include <linux/string.h>

MODULE_AUTHOR("Matthew Garrett <mjg59@srcf.ucam.org>");
MODULE_DESCRIPTION("HP laptop WMI hotkeys driver");
MODULE_LICENSE("GPL");

MODULE_ALIAS("wmi:95F24279-4D7B-4334-9387-ACCDC67EF61C");
MODULE_ALIAS("wmi:5FB7F034-2C63-45e9-BE91-3D44E2C707E4");

#define HPWMI_EVENT_GUID "95F24279-4D7B-4334-9387-ACCDC67EF61C"
#define HPWMI_BIOS_GUID "5FB7F034-2C63-45e9-BE91-3D44E2C707E4"

A
Alan Jenkins 已提交
51
enum hp_wmi_radio {
52 53 54 55
	HPWMI_WIFI	= 0x0,
	HPWMI_BLUETOOTH	= 0x1,
	HPWMI_WWAN	= 0x2,
	HPWMI_GPS	= 0x3,
A
Alan Jenkins 已提交
56 57
};

58
enum hp_wmi_event_ids {
59 60 61 62 63 64 65 66 67 68 69 70 71 72 73
	HPWMI_DOCK_EVENT		= 0x01,
	HPWMI_PARK_HDD			= 0x02,
	HPWMI_SMART_ADAPTER		= 0x03,
	HPWMI_BEZEL_BUTTON		= 0x04,
	HPWMI_WIRELESS			= 0x05,
	HPWMI_CPU_BATTERY_THROTTLE	= 0x06,
	HPWMI_LOCK_SWITCH		= 0x07,
	HPWMI_LID_SWITCH		= 0x08,
	HPWMI_SCREEN_ROTATION		= 0x09,
	HPWMI_COOLSENSE_SYSTEM_MOBILE	= 0x0A,
	HPWMI_COOLSENSE_SYSTEM_HOT	= 0x0B,
	HPWMI_PROXIMITY_SENSOR		= 0x0C,
	HPWMI_BACKLIT_KB_BRIGHTNESS	= 0x0D,
	HPWMI_PEAKSHIFT_PERIOD		= 0x0F,
	HPWMI_BATTERY_CHARGE_PERIOD	= 0x10,
74 75
};

76 77 78 79 80
struct bios_args {
	u32 signature;
	u32 command;
	u32 commandtype;
	u32 datasize;
M
Matthew Garrett 已提交
81
	u32 data;
82 83
};

84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111
enum hp_wmi_commandtype {
	HPWMI_DISPLAY_QUERY		= 0x01,
	HPWMI_HDDTEMP_QUERY		= 0x02,
	HPWMI_ALS_QUERY			= 0x03,
	HPWMI_HARDWARE_QUERY		= 0x04,
	HPWMI_WIRELESS_QUERY		= 0x05,
	HPWMI_BATTERY_QUERY		= 0x07,
	HPWMI_BIOS_QUERY		= 0x09,
	HPWMI_FEATURE_QUERY		= 0x0b,
	HPWMI_HOTKEY_QUERY		= 0x0c,
	HPWMI_FEATURE2_QUERY		= 0x0d,
	HPWMI_WIRELESS2_QUERY		= 0x1b,
	HPWMI_POSTCODEERROR_QUERY	= 0x2a,
};

enum hp_wmi_command {
	HPWMI_READ	= 0x01,
	HPWMI_WRITE	= 0x02,
	HPWMI_ODM	= 0x03,
};

#define BIOS_ARGS_INIT(write, ctype, size)				\
	(struct bios_args)	{	.signature = 0x55434553,	\
					.command = (write) ? 0x2 : 0x1,	\
					.commandtype = (ctype),		\
					.datasize = (size),		\
					.data = 0 }

112 113 114 115 116
struct bios_return {
	u32 sigpass;
	u32 return_code;
};

117 118 119 120 121 122 123
enum hp_return_value {
	HPWMI_RET_WRONG_SIGNATURE	= 0x02,
	HPWMI_RET_UNKNOWN_COMMAND	= 0x03,
	HPWMI_RET_UNKNOWN_CMDTYPE	= 0x04,
	HPWMI_RET_INVALID_PARAMETERS	= 0x05,
};

124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156
enum hp_wireless2_bits {
	HPWMI_POWER_STATE	= 0x01,
	HPWMI_POWER_SOFT	= 0x02,
	HPWMI_POWER_BIOS	= 0x04,
	HPWMI_POWER_HARD	= 0x08,
};

#define IS_HWBLOCKED(x) ((x & (HPWMI_POWER_BIOS | HPWMI_POWER_HARD)) \
			 != (HPWMI_POWER_BIOS | HPWMI_POWER_HARD))
#define IS_SWBLOCKED(x) !(x & HPWMI_POWER_SOFT)

struct bios_rfkill2_device_state {
	u8 radio_type;
	u8 bus_type;
	u16 vendor_id;
	u16 product_id;
	u16 subsys_vendor_id;
	u16 subsys_product_id;
	u8 rfkill_id;
	u8 power;
	u8 unknown[4];
};

/* 7 devices fit into the 128 byte buffer */
#define HPWMI_MAX_RFKILL2_DEVICES	7

struct bios_rfkill2_state {
	u8 unknown[7];
	u8 count;
	u8 pad[8];
	struct bios_rfkill2_device_state device[HPWMI_MAX_RFKILL2_DEVICES];
};

157 158 159 160 161 162 163
static const struct key_entry hp_wmi_keymap[] = {
	{ KE_KEY, 0x02,   { KEY_BRIGHTNESSUP } },
	{ KE_KEY, 0x03,   { KEY_BRIGHTNESSDOWN } },
	{ KE_KEY, 0x20e6, { KEY_PROG1 } },
	{ KE_KEY, 0x20e8, { KEY_MEDIA } },
	{ KE_KEY, 0x2142, { KEY_MEDIA } },
	{ KE_KEY, 0x213b, { KEY_INFO } },
164
	{ KE_KEY, 0x2169, { KEY_ROTATE_DISPLAY } },
165
	{ KE_KEY, 0x216a, { KEY_SETUP } },
166 167
	{ KE_KEY, 0x231b, { KEY_HELP } },
	{ KE_END, 0 }
168 169 170 171 172 173 174 175 176
};

static struct input_dev *hp_wmi_input_dev;
static struct platform_device *hp_wmi_platform_dev;

static struct rfkill *wifi_rfkill;
static struct rfkill *bluetooth_rfkill;
static struct rfkill *wwan_rfkill;

177 178 179 180 181 182 183 184 185
struct rfkill2_device {
	u8 id;
	int num;
	struct rfkill *rfkill;
};

static int rfkill2_count;
static struct rfkill2_device rfkill2[HPWMI_MAX_RFKILL2_DEVICES];

186 187 188
/*
 * hp_wmi_perform_query
 *
189 190
 * query:	The commandtype (enum hp_wmi_commandtype)
 * write:	The command (enum hp_wmi_command)
191
 * buffer:	Buffer used as input and/or output
192 193
 * insize:	Size of input buffer
 * outsize:	Size of output buffer
194 195 196 197 198 199 200
 *
 * returns zero on success
 *         an HP WMI query specific error code (which is positive)
 *         -EINVAL if the query was not successful at all
 *         -EINVAL if the output buffer size exceeds buffersize
 *
 * Note: The buffersize must at least be the maximum of the input and output
201
 *       size. E.g. Battery info query is defined to have 1 byte input
202 203
 *       and 128 byte output. The caller would do:
 *       buffer = kzalloc(128, GFP_KERNEL);
204
 *       ret = hp_wmi_perform_query(HPWMI_BATTERY_QUERY, HPWMI_READ, buffer, 1, 128)
205
 */
206 207
static int hp_wmi_perform_query(int query, enum hp_wmi_command command,
				void *buffer, int insize, int outsize)
208
{
209 210
	struct bios_return *bios_return;
	int actual_outsize;
211 212 213
	union acpi_object *obj;
	struct bios_args args = {
		.signature = 0x55434553,
214
		.command = command,
215
		.commandtype = query,
216 217
		.datasize = insize,
		.data = 0,
218 219 220
	};
	struct acpi_buffer input = { sizeof(struct bios_args), &args };
	struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL };
E
Eric Dumazet 已提交
221
	u32 rc;
222

223 224 225 226
	if (WARN_ON(insize > sizeof(args.data)))
		return -EINVAL;
	memcpy(&args.data, buffer, insize);

227
	wmi_evaluate_method(HPWMI_BIOS_GUID, 0, 0x3, &input, &output);
228 229 230

	obj = output.pointer;

T
Thomas Renninger 已提交
231
	if (!obj)
232
		return -EINVAL;
T
Thomas Renninger 已提交
233 234 235 236
	else if (obj->type != ACPI_TYPE_BUFFER) {
		kfree(obj);
		return -EINVAL;
	}
237

238
	bios_return = (struct bios_return *)obj->buffer.pointer;
E
Eric Dumazet 已提交
239
	rc = bios_return->return_code;
240

E
Eric Dumazet 已提交
241 242 243
	if (rc) {
		if (rc != HPWMI_RET_UNKNOWN_CMDTYPE)
			pr_warn("query 0x%x returned error 0x%x\n", query, rc);
244
		kfree(obj);
E
Eric Dumazet 已提交
245
		return rc;
246 247
	}

248 249 250 251 252
	if (!outsize) {
		/* ignore output data */
		kfree(obj);
		return 0;
	}
253

254 255 256
	actual_outsize = min(outsize, (int)(obj->buffer.length - sizeof(*bios_return)));
	memcpy(buffer, obj->buffer.pointer + sizeof(*bios_return), actual_outsize);
	memset(buffer + actual_outsize, 0, outsize - actual_outsize);
257
	kfree(obj);
258
	return 0;
259 260
}

261
static int hp_wmi_read_int(int query)
262
{
263
	int val = 0, ret;
264

265 266
	ret = hp_wmi_perform_query(query, HPWMI_READ, &val,
				   sizeof(val), sizeof(val));
267

268
	if (ret)
269
		return ret < 0 ? ret : -EINVAL;
270 271

	return val;
272 273 274 275
}

static int hp_wmi_dock_state(void)
{
276
	int state = hp_wmi_read_int(HPWMI_HARDWARE_QUERY);
277

278 279
	if (state < 0)
		return state;
280

281
	return state & 0x1;
282 283
}

284
static int hp_wmi_tablet_state(void)
285
{
286 287 288 289
	int state = hp_wmi_read_int(HPWMI_HARDWARE_QUERY);

	if (state < 0)
		return state;
290

291
	return (state & 0x4) ? 1 : 0;
292 293
}

K
Kyle Evans 已提交
294
static int __init hp_wmi_bios_2008_later(void)
295 296
{
	int state = 0;
297
	int ret = hp_wmi_perform_query(HPWMI_FEATURE_QUERY, HPWMI_READ, &state,
298
				       sizeof(state), sizeof(state));
K
Kyle Evans 已提交
299 300
	if (!ret)
		return 1;
301

K
Kyle Evans 已提交
302
	return (ret == HPWMI_RET_UNKNOWN_CMDTYPE) ? 0 : -ENXIO;
303 304
}

K
Kyle Evans 已提交
305
static int __init hp_wmi_bios_2009_later(void)
306
{
K
Kyle Evans 已提交
307
	int state = 0;
308
	int ret = hp_wmi_perform_query(HPWMI_FEATURE2_QUERY, HPWMI_READ, &state,
K
Kyle Evans 已提交
309 310 311
				       sizeof(state), sizeof(state));
	if (!ret)
		return 1;
312

K
Kyle Evans 已提交
313 314
	return (ret == HPWMI_RET_UNKNOWN_CMDTYPE) ? 0 : -ENXIO;
}
315

K
Kyle Evans 已提交
316 317 318
static int __init hp_wmi_enable_hotkeys(void)
{
	int value = 0x6e;
319
	int ret = hp_wmi_perform_query(HPWMI_BIOS_QUERY, HPWMI_WRITE, &value,
K
Kyle Evans 已提交
320
				       sizeof(value), 0);
321
	if (ret)
322
		return ret < 0 ? ret : -EINVAL;
323 324 325
	return 0;
}

J
Johannes Berg 已提交
326
static int hp_wmi_set_block(void *data, bool blocked)
327
{
A
Alan Jenkins 已提交
328 329
	enum hp_wmi_radio r = (enum hp_wmi_radio) data;
	int query = BIT(r + 8) | ((!blocked) << r);
330
	int ret;
331

332
	ret = hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, HPWMI_WRITE,
333
				   &query, sizeof(query), 0);
334
	if (ret)
335
		return ret < 0 ? ret : -EINVAL;
336
	return 0;
337 338
}

J
Johannes Berg 已提交
339 340 341
static const struct rfkill_ops hp_wmi_rfkill_ops = {
	.set_block = hp_wmi_set_block,
};
342

A
Alan Jenkins 已提交
343
static bool hp_wmi_get_sw_state(enum hp_wmi_radio r)
344
{
345 346
	int mask = 0x200 << (r * 8);

347 348
	int wireless = hp_wmi_read_int(HPWMI_WIRELESS_QUERY);

349
	/* TBD: Pass error */
350
	WARN_ONCE(wireless < 0, "error executing HPWMI_WIRELESS_QUERY");
351

352
	return !(wireless & mask);
353 354
}

A
Alan Jenkins 已提交
355
static bool hp_wmi_get_hw_state(enum hp_wmi_radio r)
356
{
357 358
	int mask = 0x800 << (r * 8);

359 360
	int wireless = hp_wmi_read_int(HPWMI_WIRELESS_QUERY);

361
	/* TBD: Pass error */
362
	WARN_ONCE(wireless < 0, "error executing HPWMI_WIRELESS_QUERY");
363

364
	return !(wireless & mask);
365 366
}

367 368 369 370 371
static int hp_wmi_rfkill2_set_block(void *data, bool blocked)
{
	int rfkill_id = (int)(long)data;
	char buffer[4] = { 0x01, 0x00, rfkill_id, !blocked };

372
	if (hp_wmi_perform_query(HPWMI_WIRELESS2_QUERY, HPWMI_WRITE,
373 374 375 376 377 378 379 380 381 382 383 384
				   buffer, sizeof(buffer), 0))
		return -EINVAL;
	return 0;
}

static const struct rfkill_ops hp_wmi_rfkill2_ops = {
	.set_block = hp_wmi_rfkill2_set_block,
};

static int hp_wmi_rfkill2_refresh(void)
{
	struct bios_rfkill2_state state;
385
	int err, i;
386

387
	err = hp_wmi_perform_query(HPWMI_WIRELESS2_QUERY, HPWMI_READ, &state,
388 389 390 391 392 393 394 395 396 397 398
				   0, sizeof(state));
	if (err)
		return err;

	for (i = 0; i < rfkill2_count; i++) {
		int num = rfkill2[i].num;
		struct bios_rfkill2_device_state *devstate;
		devstate = &state.device[num];

		if (num >= state.count ||
		    devstate->rfkill_id != rfkill2[i].id) {
399
			pr_warn("power configuration of the wireless devices unexpectedly changed\n");
400 401 402 403 404 405 406 407 408 409 410
			continue;
		}

		rfkill_set_states(rfkill2[i].rfkill,
				  IS_SWBLOCKED(devstate->power),
				  IS_HWBLOCKED(devstate->power));
	}

	return 0;
}

411 412 413
static ssize_t show_display(struct device *dev, struct device_attribute *attr,
			    char *buf)
{
414
	int value = hp_wmi_read_int(HPWMI_DISPLAY_QUERY);
415 416 417 418 419 420 421 422
	if (value < 0)
		return -EINVAL;
	return sprintf(buf, "%d\n", value);
}

static ssize_t show_hddtemp(struct device *dev, struct device_attribute *attr,
			    char *buf)
{
423
	int value = hp_wmi_read_int(HPWMI_HDDTEMP_QUERY);
424 425 426 427 428 429 430 431
	if (value < 0)
		return -EINVAL;
	return sprintf(buf, "%d\n", value);
}

static ssize_t show_als(struct device *dev, struct device_attribute *attr,
			char *buf)
{
432
	int value = hp_wmi_read_int(HPWMI_ALS_QUERY);
433 434 435 436 437 438 439 440 441 442 443 444 445 446
	if (value < 0)
		return -EINVAL;
	return sprintf(buf, "%d\n", value);
}

static ssize_t show_dock(struct device *dev, struct device_attribute *attr,
			 char *buf)
{
	int value = hp_wmi_dock_state();
	if (value < 0)
		return -EINVAL;
	return sprintf(buf, "%d\n", value);
}

447 448 449 450 451 452 453 454 455
static ssize_t show_tablet(struct device *dev, struct device_attribute *attr,
			 char *buf)
{
	int value = hp_wmi_tablet_state();
	if (value < 0)
		return -EINVAL;
	return sprintf(buf, "%d\n", value);
}

456 457 458 459
static ssize_t show_postcode(struct device *dev, struct device_attribute *attr,
			 char *buf)
{
	/* Get the POST error code of previous boot failure. */
460
	int value = hp_wmi_read_int(HPWMI_POSTCODEERROR_QUERY);
461 462 463 464 465
	if (value < 0)
		return -EINVAL;
	return sprintf(buf, "0x%x\n", value);
}

466 467 468 469
static ssize_t set_als(struct device *dev, struct device_attribute *attr,
		       const char *buf, size_t count)
{
	u32 tmp = simple_strtoul(buf, NULL, 10);
470
	int ret = hp_wmi_perform_query(HPWMI_ALS_QUERY, HPWMI_WRITE, &tmp,
471
				       sizeof(tmp), sizeof(tmp));
472
	if (ret)
473
		return ret < 0 ? ret : -EINVAL;
474

475 476 477
	return count;
}

478 479 480
static ssize_t set_postcode(struct device *dev, struct device_attribute *attr,
		       const char *buf, size_t count)
{
481
	long unsigned int tmp2;
482 483 484 485 486 487 488 489 490
	int ret;
	u32 tmp;

	ret = kstrtoul(buf, 10, &tmp2);
	if (ret || tmp2 != 1)
		return -EINVAL;

	/* Clear the POST error code. It is kept until until cleared. */
	tmp = (u32) tmp2;
491
	ret = hp_wmi_perform_query(HPWMI_POSTCODEERROR_QUERY, HPWMI_WRITE, &tmp,
492 493
				       sizeof(tmp), sizeof(tmp));
	if (ret)
494
		return ret < 0 ? ret : -EINVAL;
495 496 497 498

	return count;
}

499 500 501 502
static DEVICE_ATTR(display, S_IRUGO, show_display, NULL);
static DEVICE_ATTR(hddtemp, S_IRUGO, show_hddtemp, NULL);
static DEVICE_ATTR(als, S_IRUGO | S_IWUSR, show_als, set_als);
static DEVICE_ATTR(dock, S_IRUGO, show_dock, NULL);
503
static DEVICE_ATTR(tablet, S_IRUGO, show_tablet, NULL);
504
static DEVICE_ATTR(postcode, S_IRUGO | S_IWUSR, show_postcode, set_postcode);
505

A
Adrian Bunk 已提交
506
static void hp_wmi_notify(u32 value, void *context)
507 508
{
	struct acpi_buffer response = { ACPI_ALLOCATE_BUFFER, NULL };
509
	u32 event_id, event_data;
510
	union acpi_object *obj;
511
	acpi_status status;
512
	u32 *location;
513
	int key_code;
514

515 516
	status = wmi_get_event_data(value, &response);
	if (status != AE_OK) {
517
		pr_info("bad event status 0x%x\n", status);
518 519
		return;
	}
520 521 522

	obj = (union acpi_object *)response.pointer;

523 524 525
	if (!obj)
		return;
	if (obj->type != ACPI_TYPE_BUFFER) {
526
		pr_info("Unknown response received %d\n", obj->type);
T
Thomas Renninger 已提交
527
		kfree(obj);
A
Alan Jenkins 已提交
528 529 530
		return;
	}

531 532 533 534 535 536 537 538 539 540 541 542
	/*
	 * Depending on ACPI version the concatenation of id and event data
	 * inside _WED function will result in a 8 or 16 byte buffer.
	 */
	location = (u32 *)obj->buffer.pointer;
	if (obj->buffer.length == 8) {
		event_id = *location;
		event_data = *(location + 1);
	} else if (obj->buffer.length == 16) {
		event_id = *location;
		event_data = *(location + 2);
	} else {
543
		pr_info("Unknown buffer length %d\n", obj->buffer.length);
544 545 546
		kfree(obj);
		return;
	}
T
Thomas Renninger 已提交
547
	kfree(obj);
548 549

	switch (event_id) {
550
	case HPWMI_DOCK_EVENT:
551 552 553 554 555 556
		if (test_bit(SW_DOCK, hp_wmi_input_dev->swbit))
			input_report_switch(hp_wmi_input_dev, SW_DOCK,
					    hp_wmi_dock_state());
		if (test_bit(SW_TABLET_MODE, hp_wmi_input_dev->swbit))
			input_report_switch(hp_wmi_input_dev, SW_TABLET_MODE,
					    hp_wmi_tablet_state());
A
Alan Jenkins 已提交
557
		input_sync(hp_wmi_input_dev);
558
		break;
559 560 561 562
	case HPWMI_PARK_HDD:
		break;
	case HPWMI_SMART_ADAPTER:
		break;
563
	case HPWMI_BEZEL_BUTTON:
564 565
		key_code = hp_wmi_read_int(HPWMI_HOTKEY_QUERY);
		if (key_code < 0)
566
			break;
567 568 569

		if (!sparse_keymap_report_event(hp_wmi_input_dev,
						key_code, 1, true))
570
			pr_info("Unknown key code - 0x%x\n", key_code);
571 572
		break;
	case HPWMI_WIRELESS:
573 574 575 576 577
		if (rfkill2_count) {
			hp_wmi_rfkill2_refresh();
			break;
		}

A
Alan Jenkins 已提交
578 579 580 581 582 583 584 585 586 587 588 589
		if (wifi_rfkill)
			rfkill_set_states(wifi_rfkill,
					  hp_wmi_get_sw_state(HPWMI_WIFI),
					  hp_wmi_get_hw_state(HPWMI_WIFI));
		if (bluetooth_rfkill)
			rfkill_set_states(bluetooth_rfkill,
					  hp_wmi_get_sw_state(HPWMI_BLUETOOTH),
					  hp_wmi_get_hw_state(HPWMI_BLUETOOTH));
		if (wwan_rfkill)
			rfkill_set_states(wwan_rfkill,
					  hp_wmi_get_sw_state(HPWMI_WWAN),
					  hp_wmi_get_hw_state(HPWMI_WWAN));
590
		break;
591
	case HPWMI_CPU_BATTERY_THROTTLE:
592
		pr_info("Unimplemented CPU throttle because of 3 Cell battery event detected\n");
593 594 595
		break;
	case HPWMI_LOCK_SWITCH:
		break;
596 597 598 599 600 601 602 603 604 605 606 607 608 609 610 611
	case HPWMI_LID_SWITCH:
		break;
	case HPWMI_SCREEN_ROTATION:
		break;
	case HPWMI_COOLSENSE_SYSTEM_MOBILE:
		break;
	case HPWMI_COOLSENSE_SYSTEM_HOT:
		break;
	case HPWMI_PROXIMITY_SENSOR:
		break;
	case HPWMI_BACKLIT_KB_BRIGHTNESS:
		break;
	case HPWMI_PEAKSHIFT_PERIOD:
		break;
	case HPWMI_BATTERY_CHARGE_PERIOD:
		break;
612
	default:
613
		pr_info("Unknown event_id - %d - 0x%x\n", event_id, event_data);
614 615
		break;
	}
616 617 618 619
}

static int __init hp_wmi_input_setup(void)
{
620
	acpi_status status;
621
	int err, val;
622 623

	hp_wmi_input_dev = input_allocate_device();
624 625
	if (!hp_wmi_input_dev)
		return -ENOMEM;
626 627 628 629 630

	hp_wmi_input_dev->name = "HP WMI hotkeys";
	hp_wmi_input_dev->phys = "wmi/input0";
	hp_wmi_input_dev->id.bustype = BUS_HOST;

631
	__set_bit(EV_SW, hp_wmi_input_dev->evbit);
632 633 634 635 636 637 638 639 640 641 642 643 644 645

	/* Dock */
	val = hp_wmi_dock_state();
	if (!(val < 0)) {
		__set_bit(SW_DOCK, hp_wmi_input_dev->swbit);
		input_report_switch(hp_wmi_input_dev, SW_DOCK, val);
	}

	/* Tablet mode */
	val = hp_wmi_tablet_state();
	if (!(val < 0)) {
		__set_bit(SW_TABLET_MODE, hp_wmi_input_dev->swbit);
		input_report_switch(hp_wmi_input_dev, SW_TABLET_MODE, val);
	}
646 647 648 649

	err = sparse_keymap_setup(hp_wmi_input_dev, hp_wmi_keymap, NULL);
	if (err)
		goto err_free_dev;
650 651 652 653

	/* Set initial hardware state */
	input_sync(hp_wmi_input_dev);

K
Kyle Evans 已提交
654
	if (!hp_wmi_bios_2009_later() && hp_wmi_bios_2008_later())
655 656
		hp_wmi_enable_hotkeys();

657 658 659
	status = wmi_install_notify_handler(HPWMI_EVENT_GUID, hp_wmi_notify, NULL);
	if (ACPI_FAILURE(status)) {
		err = -EIO;
660
		goto err_free_dev;
661 662
	}

663 664 665 666
	err = input_register_device(hp_wmi_input_dev);
	if (err)
		goto err_uninstall_notifier;

667
	return 0;
668 669 670 671 672 673 674 675 676 677 678 679

 err_uninstall_notifier:
	wmi_remove_notify_handler(HPWMI_EVENT_GUID);
 err_free_dev:
	input_free_device(hp_wmi_input_dev);
	return err;
}

static void hp_wmi_input_destroy(void)
{
	wmi_remove_notify_handler(HPWMI_EVENT_GUID);
	input_unregister_device(hp_wmi_input_dev);
680 681 682 683 684 685 686 687
}

static void cleanup_sysfs(struct platform_device *device)
{
	device_remove_file(&device->dev, &dev_attr_display);
	device_remove_file(&device->dev, &dev_attr_hddtemp);
	device_remove_file(&device->dev, &dev_attr_als);
	device_remove_file(&device->dev, &dev_attr_dock);
688
	device_remove_file(&device->dev, &dev_attr_tablet);
689
	device_remove_file(&device->dev, &dev_attr_postcode);
690 691
}

692
static int __init hp_wmi_rfkill_setup(struct platform_device *device)
693
{
694
	int err, wireless;
695

696 697 698
	wireless = hp_wmi_read_int(HPWMI_WIRELESS_QUERY);
	if (wireless)
		return wireless;
699

700
	err = hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, HPWMI_WRITE, &wireless,
701 702 703 704
				   sizeof(wireless), 0);
	if (err)
		return err;

705
	if (wireless & 0x1) {
J
Johannes Berg 已提交
706 707 708
		wifi_rfkill = rfkill_alloc("hp-wifi", &device->dev,
					   RFKILL_TYPE_WLAN,
					   &hp_wmi_rfkill_ops,
A
Alan Jenkins 已提交
709
					   (void *) HPWMI_WIFI);
710 711
		if (!wifi_rfkill)
			return -ENOMEM;
A
Alan Jenkins 已提交
712 713 714 715
		rfkill_init_sw_state(wifi_rfkill,
				     hp_wmi_get_sw_state(HPWMI_WIFI));
		rfkill_set_hw_state(wifi_rfkill,
				    hp_wmi_get_hw_state(HPWMI_WIFI));
716 717
		err = rfkill_register(wifi_rfkill);
		if (err)
J
Johannes Berg 已提交
718
			goto register_wifi_error;
719 720 721
	}

	if (wireless & 0x2) {
J
Johannes Berg 已提交
722 723 724
		bluetooth_rfkill = rfkill_alloc("hp-bluetooth", &device->dev,
						RFKILL_TYPE_BLUETOOTH,
						&hp_wmi_rfkill_ops,
A
Alan Jenkins 已提交
725
						(void *) HPWMI_BLUETOOTH);
726 727
		if (!bluetooth_rfkill) {
			err = -ENOMEM;
728
			goto register_bluetooth_error;
729
		}
A
Alan Jenkins 已提交
730 731 732 733
		rfkill_init_sw_state(bluetooth_rfkill,
				     hp_wmi_get_sw_state(HPWMI_BLUETOOTH));
		rfkill_set_hw_state(bluetooth_rfkill,
				    hp_wmi_get_hw_state(HPWMI_BLUETOOTH));
734
		err = rfkill_register(bluetooth_rfkill);
735
		if (err)
736
			goto register_bluetooth_error;
737 738 739
	}

	if (wireless & 0x4) {
J
Johannes Berg 已提交
740 741 742
		wwan_rfkill = rfkill_alloc("hp-wwan", &device->dev,
					   RFKILL_TYPE_WWAN,
					   &hp_wmi_rfkill_ops,
A
Alan Jenkins 已提交
743
					   (void *) HPWMI_WWAN);
744 745
		if (!wwan_rfkill) {
			err = -ENOMEM;
746
			goto register_wwan_error;
747
		}
A
Alan Jenkins 已提交
748 749 750 751
		rfkill_init_sw_state(wwan_rfkill,
				     hp_wmi_get_sw_state(HPWMI_WWAN));
		rfkill_set_hw_state(wwan_rfkill,
				    hp_wmi_get_hw_state(HPWMI_WWAN));
752 753
		err = rfkill_register(wwan_rfkill);
		if (err)
754
			goto register_wwan_error;
755
	}
756 757

	return 0;
758

759 760 761
register_wwan_error:
	rfkill_destroy(wwan_rfkill);
	wwan_rfkill = NULL;
762 763
	if (bluetooth_rfkill)
		rfkill_unregister(bluetooth_rfkill);
764
register_bluetooth_error:
J
Johannes Berg 已提交
765
	rfkill_destroy(bluetooth_rfkill);
766
	bluetooth_rfkill = NULL;
767 768
	if (wifi_rfkill)
		rfkill_unregister(wifi_rfkill);
J
Johannes Berg 已提交
769 770
register_wifi_error:
	rfkill_destroy(wifi_rfkill);
771
	wifi_rfkill = NULL;
772 773 774
	return err;
}

775
static int __init hp_wmi_rfkill2_setup(struct platform_device *device)
776 777
{
	struct bios_rfkill2_state state;
778 779
	int err, i;

780
	err = hp_wmi_perform_query(HPWMI_WIRELESS2_QUERY, HPWMI_READ, &state,
781 782 783 784 785
				   0, sizeof(state));
	if (err)
		return err;

	if (state.count > HPWMI_MAX_RFKILL2_DEVICES) {
786
		pr_warn("unable to parse 0x1b query output\n");
787 788 789 790 791 792 793 794 795 796 797 798 799 800 801 802 803 804 805 806
		return -EINVAL;
	}

	for (i = 0; i < state.count; i++) {
		struct rfkill *rfkill;
		enum rfkill_type type;
		char *name;
		switch (state.device[i].radio_type) {
		case HPWMI_WIFI:
			type = RFKILL_TYPE_WLAN;
			name = "hp-wifi";
			break;
		case HPWMI_BLUETOOTH:
			type = RFKILL_TYPE_BLUETOOTH;
			name = "hp-bluetooth";
			break;
		case HPWMI_WWAN:
			type = RFKILL_TYPE_WWAN;
			name = "hp-wwan";
			break;
807 808 809 810
		case HPWMI_GPS:
			type = RFKILL_TYPE_GPS;
			name = "hp-gps";
			break;
811
		default:
812 813
			pr_warn("unknown device type 0x%x\n",
				state.device[i].radio_type);
814 815 816 817
			continue;
		}

		if (!state.device[i].vendor_id) {
818 819
			pr_warn("zero device %d while %d reported\n",
				i, state.count);
820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836 837 838 839
			continue;
		}

		rfkill = rfkill_alloc(name, &device->dev, type,
				      &hp_wmi_rfkill2_ops, (void *)(long)i);
		if (!rfkill) {
			err = -ENOMEM;
			goto fail;
		}

		rfkill2[rfkill2_count].id = state.device[i].rfkill_id;
		rfkill2[rfkill2_count].num = i;
		rfkill2[rfkill2_count].rfkill = rfkill;

		rfkill_init_sw_state(rfkill,
				     IS_SWBLOCKED(state.device[i].power));
		rfkill_set_hw_state(rfkill,
				    IS_HWBLOCKED(state.device[i].power));

		if (!(state.device[i].power & HPWMI_POWER_BIOS))
840
			pr_info("device %s blocked by BIOS\n", name);
841 842 843 844 845 846 847 848 849 850 851 852 853 854 855 856 857 858 859

		err = rfkill_register(rfkill);
		if (err) {
			rfkill_destroy(rfkill);
			goto fail;
		}

		rfkill2_count++;
	}

	return 0;
fail:
	for (; rfkill2_count > 0; rfkill2_count--) {
		rfkill_unregister(rfkill2[rfkill2_count - 1].rfkill);
		rfkill_destroy(rfkill2[rfkill2_count - 1].rfkill);
	}
	return err;
}

860
static int __init hp_wmi_bios_setup(struct platform_device *device)
861 862 863
{
	int err;

864 865 866 867
	/* clear detected rfkill devices */
	wifi_rfkill = NULL;
	bluetooth_rfkill = NULL;
	wwan_rfkill = NULL;
868
	rfkill2_count = 0;
869

870
	if (hp_wmi_rfkill_setup(device))
871
		hp_wmi_rfkill2_setup(device);
872 873 874 875 876 877 878 879 880 881 882 883 884 885

	err = device_create_file(&device->dev, &dev_attr_display);
	if (err)
		goto add_sysfs_error;
	err = device_create_file(&device->dev, &dev_attr_hddtemp);
	if (err)
		goto add_sysfs_error;
	err = device_create_file(&device->dev, &dev_attr_als);
	if (err)
		goto add_sysfs_error;
	err = device_create_file(&device->dev, &dev_attr_dock);
	if (err)
		goto add_sysfs_error;
	err = device_create_file(&device->dev, &dev_attr_tablet);
886 887 888
	if (err)
		goto add_sysfs_error;
	err = device_create_file(&device->dev, &dev_attr_postcode);
889 890 891 892
	if (err)
		goto add_sysfs_error;
	return 0;

893 894 895 896 897 898 899
add_sysfs_error:
	cleanup_sysfs(device);
	return err;
}

static int __exit hp_wmi_bios_remove(struct platform_device *device)
{
900
	int i;
901 902
	cleanup_sysfs(device);

903 904 905 906 907
	for (i = 0; i < rfkill2_count; i++) {
		rfkill_unregister(rfkill2[i].rfkill);
		rfkill_destroy(rfkill2[i].rfkill);
	}

J
Johannes Berg 已提交
908
	if (wifi_rfkill) {
909
		rfkill_unregister(wifi_rfkill);
J
Johannes Berg 已提交
910 911 912
		rfkill_destroy(wifi_rfkill);
	}
	if (bluetooth_rfkill) {
913
		rfkill_unregister(bluetooth_rfkill);
914
		rfkill_destroy(bluetooth_rfkill);
J
Johannes Berg 已提交
915 916
	}
	if (wwan_rfkill) {
917
		rfkill_unregister(wwan_rfkill);
J
Johannes Berg 已提交
918 919
		rfkill_destroy(wwan_rfkill);
	}
920 921 922 923

	return 0;
}

F
Frans Pop 已提交
924
static int hp_wmi_resume_handler(struct device *device)
925 926
{
	/*
927 928
	 * Hardware state may have changed while suspended, so trigger
	 * input events for the current state. As this is a switch,
929 930 931
	 * the input layer will only actually pass it on if the state
	 * changed.
	 */
932
	if (hp_wmi_input_dev) {
933 934 935 936 937 938
		if (test_bit(SW_DOCK, hp_wmi_input_dev->swbit))
			input_report_switch(hp_wmi_input_dev, SW_DOCK,
					    hp_wmi_dock_state());
		if (test_bit(SW_TABLET_MODE, hp_wmi_input_dev->swbit))
			input_report_switch(hp_wmi_input_dev, SW_TABLET_MODE,
					    hp_wmi_tablet_state());
939 940
		input_sync(hp_wmi_input_dev);
	}
941

942 943 944
	if (rfkill2_count)
		hp_wmi_rfkill2_refresh();

A
Alan Jenkins 已提交
945 946 947 948 949 950 951 952 953 954 955 956 957
	if (wifi_rfkill)
		rfkill_set_states(wifi_rfkill,
				  hp_wmi_get_sw_state(HPWMI_WIFI),
				  hp_wmi_get_hw_state(HPWMI_WIFI));
	if (bluetooth_rfkill)
		rfkill_set_states(bluetooth_rfkill,
				  hp_wmi_get_sw_state(HPWMI_BLUETOOTH),
				  hp_wmi_get_hw_state(HPWMI_BLUETOOTH));
	if (wwan_rfkill)
		rfkill_set_states(wwan_rfkill,
				  hp_wmi_get_sw_state(HPWMI_WWAN),
				  hp_wmi_get_hw_state(HPWMI_WWAN));

958 959 960
	return 0;
}

961 962 963 964 965 966 967 968 969 970 971 972 973
static const struct dev_pm_ops hp_wmi_pm_ops = {
	.resume  = hp_wmi_resume_handler,
	.restore  = hp_wmi_resume_handler,
};

static struct platform_driver hp_wmi_driver = {
	.driver = {
		.name = "hp-wmi",
		.pm = &hp_wmi_pm_ops,
	},
	.remove = __exit_p(hp_wmi_bios_remove),
};

974 975
static int __init hp_wmi_init(void)
{
976 977
	int event_capable = wmi_has_guid(HPWMI_EVENT_GUID);
	int bios_capable = wmi_has_guid(HPWMI_BIOS_GUID);
978
	int err;
979

980 981 982
	if (!bios_capable && !event_capable)
		return -ENODEV;

983
	if (event_capable) {
984
		err = hp_wmi_input_setup();
985
		if (err)
986
			return err;
987 988
	}

989
	if (bios_capable) {
990 991 992 993 994
		hp_wmi_platform_dev =
			platform_device_register_simple("hp-wmi", -1, NULL, 0);
		if (IS_ERR(hp_wmi_platform_dev)) {
			err = PTR_ERR(hp_wmi_platform_dev);
			goto err_destroy_input;
995
		}
996 997

		err = platform_driver_probe(&hp_wmi_driver, hp_wmi_bios_setup);
998
		if (err)
999
			goto err_unregister_device;
1000 1001 1002
	}

	return 0;
1003

1004 1005 1006
err_unregister_device:
	platform_device_unregister(hp_wmi_platform_dev);
err_destroy_input:
1007 1008
	if (event_capable)
		hp_wmi_input_destroy();
1009 1010

	return err;
1011
}
1012
module_init(hp_wmi_init);
1013 1014 1015

static void __exit hp_wmi_exit(void)
{
1016 1017 1018
	if (wmi_has_guid(HPWMI_EVENT_GUID))
		hp_wmi_input_destroy();

1019
	if (hp_wmi_platform_dev) {
1020
		platform_device_unregister(hp_wmi_platform_dev);
1021 1022 1023 1024
		platform_driver_unregister(&hp_wmi_driver);
	}
}
module_exit(hp_wmi_exit);