1 /*
2  * HP WMI hotkeys
3  *
4  * Copyright (C) 2008 Red Hat <mjg@redhat.com>
5  * Copyright (C) 2010, 2011 Anssi Hannula <anssi.hannula@iki.fi>
6  *
7  * Portions based on wistron_btns.c:
8  * Copyright (C) 2005 Miloslav Trmac <mitr@volny.cz>
9  * Copyright (C) 2005 Bernhard Rosenkraenzer <bero@arklinux.org>
10  * Copyright (C) 2005 Dmitry Torokhov <dtor@mail.ru>
11  *
12  *  This program is free software; you can redistribute it and/or modify
13  *  it under the terms of the GNU General Public License as published by
14  *  the Free Software Foundation; either version 2 of the License, or
15  *  (at your option) any later version.
16  *
17  *  This program is distributed in the hope that it will be useful,
18  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
19  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
20  *  GNU General Public License for more details.
21  *
22  *  You should have received a copy of the GNU General Public License
23  *  along with this program; if not, write to the Free Software
24  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
25  */
26 
27 #include <linux/kernel.h>
28 #include <linux/module.h>
29 #include <linux/init.h>
30 #include <linux/slab.h>
31 #include <linux/types.h>
32 #include <linux/input.h>
33 #include <linux/input/sparse-keymap.h>
34 #include <linux/platform_device.h>
35 #include <linux/acpi.h>
36 #include <linux/rfkill.h>
37 #include <linux/string.h>
38 
39 MODULE_AUTHOR("Matthew Garrett <mjg59@srcf.ucam.org>");
40 MODULE_DESCRIPTION("HP laptop WMI hotkeys driver");
41 MODULE_LICENSE("GPL");
42 
43 MODULE_ALIAS("wmi:95F24279-4D7B-4334-9387-ACCDC67EF61C");
44 MODULE_ALIAS("wmi:5FB7F034-2C63-45e9-BE91-3D44E2C707E4");
45 
46 #define HPWMI_EVENT_GUID "95F24279-4D7B-4334-9387-ACCDC67EF61C"
47 #define HPWMI_BIOS_GUID "5FB7F034-2C63-45e9-BE91-3D44E2C707E4"
48 
49 #define HPWMI_DISPLAY_QUERY 0x1
50 #define HPWMI_HDDTEMP_QUERY 0x2
51 #define HPWMI_ALS_QUERY 0x3
52 #define HPWMI_HARDWARE_QUERY 0x4
53 #define HPWMI_WIRELESS_QUERY 0x5
54 #define HPWMI_HOTKEY_QUERY 0xc
55 #define HPWMI_WIRELESS2_QUERY 0x1b
56 
57 #define PREFIX "HP WMI: "
58 #define UNIMP "Unimplemented "
59 
60 enum hp_wmi_radio {
61 	HPWMI_WIFI = 0,
62 	HPWMI_BLUETOOTH = 1,
63 	HPWMI_WWAN = 2,
64 };
65 
66 enum hp_wmi_event_ids {
67 	HPWMI_DOCK_EVENT = 1,
68 	HPWMI_PARK_HDD = 2,
69 	HPWMI_SMART_ADAPTER = 3,
70 	HPWMI_BEZEL_BUTTON = 4,
71 	HPWMI_WIRELESS = 5,
72 	HPWMI_CPU_BATTERY_THROTTLE = 6,
73 	HPWMI_LOCK_SWITCH = 7,
74 };
75 
76 static int __devinit hp_wmi_bios_setup(struct platform_device *device);
77 static int __exit hp_wmi_bios_remove(struct platform_device *device);
78 static int hp_wmi_resume_handler(struct device *device);
79 
80 struct bios_args {
81 	u32 signature;
82 	u32 command;
83 	u32 commandtype;
84 	u32 datasize;
85 	u32 data;
86 };
87 
88 struct bios_return {
89 	u32 sigpass;
90 	u32 return_code;
91 };
92 
93 enum hp_return_value {
94 	HPWMI_RET_WRONG_SIGNATURE	= 0x02,
95 	HPWMI_RET_UNKNOWN_COMMAND	= 0x03,
96 	HPWMI_RET_UNKNOWN_CMDTYPE	= 0x04,
97 	HPWMI_RET_INVALID_PARAMETERS	= 0x05,
98 };
99 
100 enum hp_wireless2_bits {
101 	HPWMI_POWER_STATE	= 0x01,
102 	HPWMI_POWER_SOFT	= 0x02,
103 	HPWMI_POWER_BIOS	= 0x04,
104 	HPWMI_POWER_HARD	= 0x08,
105 };
106 
107 #define IS_HWBLOCKED(x) ((x & (HPWMI_POWER_BIOS | HPWMI_POWER_HARD)) \
108 			 != (HPWMI_POWER_BIOS | HPWMI_POWER_HARD))
109 #define IS_SWBLOCKED(x) !(x & HPWMI_POWER_SOFT)
110 
111 struct bios_rfkill2_device_state {
112 	u8 radio_type;
113 	u8 bus_type;
114 	u16 vendor_id;
115 	u16 product_id;
116 	u16 subsys_vendor_id;
117 	u16 subsys_product_id;
118 	u8 rfkill_id;
119 	u8 power;
120 	u8 unknown[4];
121 };
122 
123 /* 7 devices fit into the 128 byte buffer */
124 #define HPWMI_MAX_RFKILL2_DEVICES	7
125 
126 struct bios_rfkill2_state {
127 	u8 unknown[7];
128 	u8 count;
129 	u8 pad[8];
130 	struct bios_rfkill2_device_state device[HPWMI_MAX_RFKILL2_DEVICES];
131 };
132 
133 static const struct key_entry hp_wmi_keymap[] = {
134 	{ KE_KEY, 0x02,   { KEY_BRIGHTNESSUP } },
135 	{ KE_KEY, 0x03,   { KEY_BRIGHTNESSDOWN } },
136 	{ KE_KEY, 0x20e6, { KEY_PROG1 } },
137 	{ KE_KEY, 0x20e8, { KEY_MEDIA } },
138 	{ KE_KEY, 0x2142, { KEY_MEDIA } },
139 	{ KE_KEY, 0x213b, { KEY_INFO } },
140 	{ KE_KEY, 0x2169, { KEY_DIRECTION } },
141 	{ KE_KEY, 0x231b, { KEY_HELP } },
142 	{ KE_END, 0 }
143 };
144 
145 static struct input_dev *hp_wmi_input_dev;
146 static struct platform_device *hp_wmi_platform_dev;
147 
148 static struct rfkill *wifi_rfkill;
149 static struct rfkill *bluetooth_rfkill;
150 static struct rfkill *wwan_rfkill;
151 
152 struct rfkill2_device {
153 	u8 id;
154 	int num;
155 	struct rfkill *rfkill;
156 };
157 
158 static int rfkill2_count;
159 static struct rfkill2_device rfkill2[HPWMI_MAX_RFKILL2_DEVICES];
160 
161 static const struct dev_pm_ops hp_wmi_pm_ops = {
162 	.resume  = hp_wmi_resume_handler,
163 	.restore  = hp_wmi_resume_handler,
164 };
165 
166 static struct platform_driver hp_wmi_driver = {
167 	.driver = {
168 		.name = "hp-wmi",
169 		.owner = THIS_MODULE,
170 		.pm = &hp_wmi_pm_ops,
171 	},
172 	.probe = hp_wmi_bios_setup,
173 	.remove = hp_wmi_bios_remove,
174 };
175 
176 /*
177  * hp_wmi_perform_query
178  *
179  * query:	The commandtype -> What should be queried
180  * write:	The command -> 0 read, 1 write, 3 ODM specific
181  * buffer:	Buffer used as input and/or output
182  * insize:	Size of input buffer
183  * outsize:	Size of output buffer
184  *
185  * returns zero on success
186  *         an HP WMI query specific error code (which is positive)
187  *         -EINVAL if the query was not successful at all
188  *         -EINVAL if the output buffer size exceeds buffersize
189  *
190  * Note: The buffersize must at least be the maximum of the input and output
191  *       size. E.g. Battery info query (0x7) is defined to have 1 byte input
192  *       and 128 byte output. The caller would do:
193  *       buffer = kzalloc(128, GFP_KERNEL);
194  *       ret = hp_wmi_perform_query(0x7, 0, buffer, 1, 128)
195  */
hp_wmi_perform_query(int query,int write,void * buffer,int insize,int outsize)196 static int hp_wmi_perform_query(int query, int write, void *buffer,
197 				int insize, int outsize)
198 {
199 	struct bios_return *bios_return;
200 	int actual_outsize;
201 	union acpi_object *obj;
202 	struct bios_args args = {
203 		.signature = 0x55434553,
204 		.command = write ? 0x2 : 0x1,
205 		.commandtype = query,
206 		.datasize = insize,
207 		.data = 0,
208 	};
209 	struct acpi_buffer input = { sizeof(struct bios_args), &args };
210 	struct acpi_buffer output = { ACPI_ALLOCATE_BUFFER, NULL };
211 
212 	if (WARN_ON(insize > sizeof(args.data)))
213 		return -EINVAL;
214 	memcpy(&args.data, buffer, insize);
215 
216 	wmi_evaluate_method(HPWMI_BIOS_GUID, 0, 0x3, &input, &output);
217 
218 	obj = output.pointer;
219 
220 	if (!obj)
221 		return -EINVAL;
222 	else if (obj->type != ACPI_TYPE_BUFFER) {
223 		kfree(obj);
224 		return -EINVAL;
225 	}
226 
227 	bios_return = (struct bios_return *)obj->buffer.pointer;
228 
229 	if (bios_return->return_code) {
230 		if (bios_return->return_code != HPWMI_RET_UNKNOWN_CMDTYPE)
231 			printk(KERN_WARNING PREFIX "query 0x%x returned "
232 						   "error 0x%x\n",
233 			       query, bios_return->return_code);
234 		kfree(obj);
235 		return bios_return->return_code;
236 	}
237 
238 	if (!outsize) {
239 		/* ignore output data */
240 		kfree(obj);
241 		return 0;
242 	}
243 
244 	actual_outsize = min(outsize, (int)(obj->buffer.length - sizeof(*bios_return)));
245 	memcpy(buffer, obj->buffer.pointer + sizeof(*bios_return), actual_outsize);
246 	memset(buffer + actual_outsize, 0, outsize - actual_outsize);
247 	kfree(obj);
248 	return 0;
249 }
250 
hp_wmi_display_state(void)251 static int hp_wmi_display_state(void)
252 {
253 	int state = 0;
254 	int ret = hp_wmi_perform_query(HPWMI_DISPLAY_QUERY, 0, &state,
255 				       sizeof(state), sizeof(state));
256 	if (ret)
257 		return -EINVAL;
258 	return state;
259 }
260 
hp_wmi_hddtemp_state(void)261 static int hp_wmi_hddtemp_state(void)
262 {
263 	int state = 0;
264 	int ret = hp_wmi_perform_query(HPWMI_HDDTEMP_QUERY, 0, &state,
265 				       sizeof(state), sizeof(state));
266 	if (ret)
267 		return -EINVAL;
268 	return state;
269 }
270 
hp_wmi_als_state(void)271 static int hp_wmi_als_state(void)
272 {
273 	int state = 0;
274 	int ret = hp_wmi_perform_query(HPWMI_ALS_QUERY, 0, &state,
275 				       sizeof(state), sizeof(state));
276 	if (ret)
277 		return -EINVAL;
278 	return state;
279 }
280 
hp_wmi_dock_state(void)281 static int hp_wmi_dock_state(void)
282 {
283 	int state = 0;
284 	int ret = hp_wmi_perform_query(HPWMI_HARDWARE_QUERY, 0, &state,
285 				       sizeof(state), sizeof(state));
286 
287 	if (ret)
288 		return -EINVAL;
289 
290 	return state & 0x1;
291 }
292 
hp_wmi_tablet_state(void)293 static int hp_wmi_tablet_state(void)
294 {
295 	int state = 0;
296 	int ret = hp_wmi_perform_query(HPWMI_HARDWARE_QUERY, 0, &state,
297 				       sizeof(state), sizeof(state));
298 	if (ret)
299 		return ret;
300 
301 	return (state & 0x4) ? 1 : 0;
302 }
303 
hp_wmi_set_block(void * data,bool blocked)304 static int hp_wmi_set_block(void *data, bool blocked)
305 {
306 	enum hp_wmi_radio r = (enum hp_wmi_radio) data;
307 	int query = BIT(r + 8) | ((!blocked) << r);
308 	int ret;
309 
310 	ret = hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 1,
311 				   &query, sizeof(query), 0);
312 	if (ret)
313 		return -EINVAL;
314 	return 0;
315 }
316 
317 static const struct rfkill_ops hp_wmi_rfkill_ops = {
318 	.set_block = hp_wmi_set_block,
319 };
320 
hp_wmi_get_sw_state(enum hp_wmi_radio r)321 static bool hp_wmi_get_sw_state(enum hp_wmi_radio r)
322 {
323 	int wireless = 0;
324 	int mask;
325 	hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 0,
326 			     &wireless, sizeof(wireless),
327 			     sizeof(wireless));
328 	/* TBD: Pass error */
329 
330 	mask = 0x200 << (r * 8);
331 
332 	if (wireless & mask)
333 		return false;
334 	else
335 		return true;
336 }
337 
hp_wmi_get_hw_state(enum hp_wmi_radio r)338 static bool hp_wmi_get_hw_state(enum hp_wmi_radio r)
339 {
340 	int wireless = 0;
341 	int mask;
342 	hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 0,
343 			     &wireless, sizeof(wireless),
344 			     sizeof(wireless));
345 	/* TBD: Pass error */
346 
347 	mask = 0x800 << (r * 8);
348 
349 	if (wireless & mask)
350 		return false;
351 	else
352 		return true;
353 }
354 
hp_wmi_rfkill2_set_block(void * data,bool blocked)355 static int hp_wmi_rfkill2_set_block(void *data, bool blocked)
356 {
357 	int rfkill_id = (int)(long)data;
358 	char buffer[4] = { 0x01, 0x00, rfkill_id, !blocked };
359 
360 	if (hp_wmi_perform_query(HPWMI_WIRELESS2_QUERY, 1,
361 				   buffer, sizeof(buffer), 0))
362 		return -EINVAL;
363 	return 0;
364 }
365 
366 static const struct rfkill_ops hp_wmi_rfkill2_ops = {
367 	.set_block = hp_wmi_rfkill2_set_block,
368 };
369 
hp_wmi_rfkill2_refresh(void)370 static int hp_wmi_rfkill2_refresh(void)
371 {
372 	int err, i;
373 	struct bios_rfkill2_state state;
374 
375 	err = hp_wmi_perform_query(HPWMI_WIRELESS2_QUERY, 0, &state,
376 				   0, sizeof(state));
377 	if (err)
378 		return err;
379 
380 	for (i = 0; i < rfkill2_count; i++) {
381 		int num = rfkill2[i].num;
382 		struct bios_rfkill2_device_state *devstate;
383 		devstate = &state.device[num];
384 
385 		if (num >= state.count ||
386 		    devstate->rfkill_id != rfkill2[i].id) {
387 			printk(KERN_WARNING PREFIX "power configuration of "
388 			       "the wireless devices unexpectedly changed\n");
389 			continue;
390 		}
391 
392 		rfkill_set_states(rfkill2[i].rfkill,
393 				  IS_SWBLOCKED(devstate->power),
394 				  IS_HWBLOCKED(devstate->power));
395 	}
396 
397 	return 0;
398 }
399 
show_display(struct device * dev,struct device_attribute * attr,char * buf)400 static ssize_t show_display(struct device *dev, struct device_attribute *attr,
401 			    char *buf)
402 {
403 	int value = hp_wmi_display_state();
404 	if (value < 0)
405 		return -EINVAL;
406 	return sprintf(buf, "%d\n", value);
407 }
408 
show_hddtemp(struct device * dev,struct device_attribute * attr,char * buf)409 static ssize_t show_hddtemp(struct device *dev, struct device_attribute *attr,
410 			    char *buf)
411 {
412 	int value = hp_wmi_hddtemp_state();
413 	if (value < 0)
414 		return -EINVAL;
415 	return sprintf(buf, "%d\n", value);
416 }
417 
show_als(struct device * dev,struct device_attribute * attr,char * buf)418 static ssize_t show_als(struct device *dev, struct device_attribute *attr,
419 			char *buf)
420 {
421 	int value = hp_wmi_als_state();
422 	if (value < 0)
423 		return -EINVAL;
424 	return sprintf(buf, "%d\n", value);
425 }
426 
show_dock(struct device * dev,struct device_attribute * attr,char * buf)427 static ssize_t show_dock(struct device *dev, struct device_attribute *attr,
428 			 char *buf)
429 {
430 	int value = hp_wmi_dock_state();
431 	if (value < 0)
432 		return -EINVAL;
433 	return sprintf(buf, "%d\n", value);
434 }
435 
show_tablet(struct device * dev,struct device_attribute * attr,char * buf)436 static ssize_t show_tablet(struct device *dev, struct device_attribute *attr,
437 			 char *buf)
438 {
439 	int value = hp_wmi_tablet_state();
440 	if (value < 0)
441 		return -EINVAL;
442 	return sprintf(buf, "%d\n", value);
443 }
444 
set_als(struct device * dev,struct device_attribute * attr,const char * buf,size_t count)445 static ssize_t set_als(struct device *dev, struct device_attribute *attr,
446 		       const char *buf, size_t count)
447 {
448 	u32 tmp = simple_strtoul(buf, NULL, 10);
449 	int ret = hp_wmi_perform_query(HPWMI_ALS_QUERY, 1, &tmp,
450 				       sizeof(tmp), sizeof(tmp));
451 	if (ret)
452 		return -EINVAL;
453 
454 	return count;
455 }
456 
457 static DEVICE_ATTR(display, S_IRUGO, show_display, NULL);
458 static DEVICE_ATTR(hddtemp, S_IRUGO, show_hddtemp, NULL);
459 static DEVICE_ATTR(als, S_IRUGO | S_IWUSR, show_als, set_als);
460 static DEVICE_ATTR(dock, S_IRUGO, show_dock, NULL);
461 static DEVICE_ATTR(tablet, S_IRUGO, show_tablet, NULL);
462 
hp_wmi_notify(u32 value,void * context)463 static void hp_wmi_notify(u32 value, void *context)
464 {
465 	struct acpi_buffer response = { ACPI_ALLOCATE_BUFFER, NULL };
466 	union acpi_object *obj;
467 	u32 event_id, event_data;
468 	int key_code = 0, ret;
469 	u32 *location;
470 	acpi_status status;
471 
472 	status = wmi_get_event_data(value, &response);
473 	if (status != AE_OK) {
474 		printk(KERN_INFO PREFIX "bad event status 0x%x\n", status);
475 		return;
476 	}
477 
478 	obj = (union acpi_object *)response.pointer;
479 
480 	if (!obj)
481 		return;
482 	if (obj->type != ACPI_TYPE_BUFFER) {
483 		printk(KERN_INFO "hp-wmi: Unknown response received %d\n",
484 		       obj->type);
485 		kfree(obj);
486 		return;
487 	}
488 
489 	/*
490 	 * Depending on ACPI version the concatenation of id and event data
491 	 * inside _WED function will result in a 8 or 16 byte buffer.
492 	 */
493 	location = (u32 *)obj->buffer.pointer;
494 	if (obj->buffer.length == 8) {
495 		event_id = *location;
496 		event_data = *(location + 1);
497 	} else if (obj->buffer.length == 16) {
498 		event_id = *location;
499 		event_data = *(location + 2);
500 	} else {
501 		printk(KERN_INFO "hp-wmi: Unknown buffer length %d\n",
502 		       obj->buffer.length);
503 		kfree(obj);
504 		return;
505 	}
506 	kfree(obj);
507 
508 	switch (event_id) {
509 	case HPWMI_DOCK_EVENT:
510 		input_report_switch(hp_wmi_input_dev, SW_DOCK,
511 				    hp_wmi_dock_state());
512 		input_report_switch(hp_wmi_input_dev, SW_TABLET_MODE,
513 				    hp_wmi_tablet_state());
514 		input_sync(hp_wmi_input_dev);
515 		break;
516 	case HPWMI_PARK_HDD:
517 		break;
518 	case HPWMI_SMART_ADAPTER:
519 		break;
520 	case HPWMI_BEZEL_BUTTON:
521 		ret = hp_wmi_perform_query(HPWMI_HOTKEY_QUERY, 0,
522 					   &key_code,
523 					   sizeof(key_code),
524 					   sizeof(key_code));
525 		if (ret)
526 			break;
527 
528 		if (!sparse_keymap_report_event(hp_wmi_input_dev,
529 						key_code, 1, true))
530 			printk(KERN_INFO PREFIX "Unknown key code - 0x%x\n",
531 			       key_code);
532 		break;
533 	case HPWMI_WIRELESS:
534 		if (rfkill2_count) {
535 			hp_wmi_rfkill2_refresh();
536 			break;
537 		}
538 
539 		if (wifi_rfkill)
540 			rfkill_set_states(wifi_rfkill,
541 					  hp_wmi_get_sw_state(HPWMI_WIFI),
542 					  hp_wmi_get_hw_state(HPWMI_WIFI));
543 		if (bluetooth_rfkill)
544 			rfkill_set_states(bluetooth_rfkill,
545 					  hp_wmi_get_sw_state(HPWMI_BLUETOOTH),
546 					  hp_wmi_get_hw_state(HPWMI_BLUETOOTH));
547 		if (wwan_rfkill)
548 			rfkill_set_states(wwan_rfkill,
549 					  hp_wmi_get_sw_state(HPWMI_WWAN),
550 					  hp_wmi_get_hw_state(HPWMI_WWAN));
551 		break;
552 	case HPWMI_CPU_BATTERY_THROTTLE:
553 		printk(KERN_INFO PREFIX UNIMP "CPU throttle because of 3 Cell"
554 		       " battery event detected\n");
555 		break;
556 	case HPWMI_LOCK_SWITCH:
557 		break;
558 	default:
559 		printk(KERN_INFO PREFIX "Unknown event_id - %d - 0x%x\n",
560 		       event_id, event_data);
561 		break;
562 	}
563 }
564 
hp_wmi_input_setup(void)565 static int __init hp_wmi_input_setup(void)
566 {
567 	acpi_status status;
568 	int err;
569 
570 	hp_wmi_input_dev = input_allocate_device();
571 	if (!hp_wmi_input_dev)
572 		return -ENOMEM;
573 
574 	hp_wmi_input_dev->name = "HP WMI hotkeys";
575 	hp_wmi_input_dev->phys = "wmi/input0";
576 	hp_wmi_input_dev->id.bustype = BUS_HOST;
577 
578 	__set_bit(EV_SW, hp_wmi_input_dev->evbit);
579 	__set_bit(SW_DOCK, hp_wmi_input_dev->swbit);
580 	__set_bit(SW_TABLET_MODE, hp_wmi_input_dev->swbit);
581 
582 	err = sparse_keymap_setup(hp_wmi_input_dev, hp_wmi_keymap, NULL);
583 	if (err)
584 		goto err_free_dev;
585 
586 	/* Set initial hardware state */
587 	input_report_switch(hp_wmi_input_dev, SW_DOCK, hp_wmi_dock_state());
588 	input_report_switch(hp_wmi_input_dev, SW_TABLET_MODE,
589 			    hp_wmi_tablet_state());
590 	input_sync(hp_wmi_input_dev);
591 
592 	status = wmi_install_notify_handler(HPWMI_EVENT_GUID, hp_wmi_notify, NULL);
593 	if (ACPI_FAILURE(status)) {
594 		err = -EIO;
595 		goto err_free_keymap;
596 	}
597 
598 	err = input_register_device(hp_wmi_input_dev);
599 	if (err)
600 		goto err_uninstall_notifier;
601 
602 	return 0;
603 
604  err_uninstall_notifier:
605 	wmi_remove_notify_handler(HPWMI_EVENT_GUID);
606  err_free_keymap:
607 	sparse_keymap_free(hp_wmi_input_dev);
608  err_free_dev:
609 	input_free_device(hp_wmi_input_dev);
610 	return err;
611 }
612 
hp_wmi_input_destroy(void)613 static void hp_wmi_input_destroy(void)
614 {
615 	wmi_remove_notify_handler(HPWMI_EVENT_GUID);
616 	sparse_keymap_free(hp_wmi_input_dev);
617 	input_unregister_device(hp_wmi_input_dev);
618 }
619 
cleanup_sysfs(struct platform_device * device)620 static void cleanup_sysfs(struct platform_device *device)
621 {
622 	device_remove_file(&device->dev, &dev_attr_display);
623 	device_remove_file(&device->dev, &dev_attr_hddtemp);
624 	device_remove_file(&device->dev, &dev_attr_als);
625 	device_remove_file(&device->dev, &dev_attr_dock);
626 	device_remove_file(&device->dev, &dev_attr_tablet);
627 }
628 
hp_wmi_rfkill_setup(struct platform_device * device)629 static int __devinit hp_wmi_rfkill_setup(struct platform_device *device)
630 {
631 	int err;
632 	int wireless = 0;
633 
634 	err = hp_wmi_perform_query(HPWMI_WIRELESS_QUERY, 0, &wireless,
635 				   sizeof(wireless), sizeof(wireless));
636 	if (err)
637 		return err;
638 
639 	if (wireless & 0x1) {
640 		wifi_rfkill = rfkill_alloc("hp-wifi", &device->dev,
641 					   RFKILL_TYPE_WLAN,
642 					   &hp_wmi_rfkill_ops,
643 					   (void *) HPWMI_WIFI);
644 		rfkill_init_sw_state(wifi_rfkill,
645 				     hp_wmi_get_sw_state(HPWMI_WIFI));
646 		rfkill_set_hw_state(wifi_rfkill,
647 				    hp_wmi_get_hw_state(HPWMI_WIFI));
648 		err = rfkill_register(wifi_rfkill);
649 		if (err)
650 			goto register_wifi_error;
651 	}
652 
653 	if (wireless & 0x2) {
654 		bluetooth_rfkill = rfkill_alloc("hp-bluetooth", &device->dev,
655 						RFKILL_TYPE_BLUETOOTH,
656 						&hp_wmi_rfkill_ops,
657 						(void *) HPWMI_BLUETOOTH);
658 		rfkill_init_sw_state(bluetooth_rfkill,
659 				     hp_wmi_get_sw_state(HPWMI_BLUETOOTH));
660 		rfkill_set_hw_state(bluetooth_rfkill,
661 				    hp_wmi_get_hw_state(HPWMI_BLUETOOTH));
662 		err = rfkill_register(bluetooth_rfkill);
663 		if (err)
664 			goto register_bluetooth_error;
665 	}
666 
667 	if (wireless & 0x4) {
668 		wwan_rfkill = rfkill_alloc("hp-wwan", &device->dev,
669 					   RFKILL_TYPE_WWAN,
670 					   &hp_wmi_rfkill_ops,
671 					   (void *) HPWMI_WWAN);
672 		rfkill_init_sw_state(wwan_rfkill,
673 				     hp_wmi_get_sw_state(HPWMI_WWAN));
674 		rfkill_set_hw_state(wwan_rfkill,
675 				    hp_wmi_get_hw_state(HPWMI_WWAN));
676 		err = rfkill_register(wwan_rfkill);
677 		if (err)
678 			goto register_wwan_err;
679 	}
680 
681 	return 0;
682 register_wwan_err:
683 	rfkill_destroy(wwan_rfkill);
684 	wwan_rfkill = NULL;
685 	if (bluetooth_rfkill)
686 		rfkill_unregister(bluetooth_rfkill);
687 register_bluetooth_error:
688 	rfkill_destroy(bluetooth_rfkill);
689 	bluetooth_rfkill = NULL;
690 	if (wifi_rfkill)
691 		rfkill_unregister(wifi_rfkill);
692 register_wifi_error:
693 	rfkill_destroy(wifi_rfkill);
694 	wifi_rfkill = NULL;
695 	return err;
696 }
697 
hp_wmi_rfkill2_setup(struct platform_device * device)698 static int __devinit hp_wmi_rfkill2_setup(struct platform_device *device)
699 {
700 	int err, i;
701 	struct bios_rfkill2_state state;
702 	err = hp_wmi_perform_query(HPWMI_WIRELESS2_QUERY, 0, &state,
703 				   0, sizeof(state));
704 	if (err)
705 		return err;
706 
707 	if (state.count > HPWMI_MAX_RFKILL2_DEVICES) {
708 		printk(KERN_WARNING PREFIX "unable to parse 0x1b query output\n");
709 		return -EINVAL;
710 	}
711 
712 	for (i = 0; i < state.count; i++) {
713 		struct rfkill *rfkill;
714 		enum rfkill_type type;
715 		char *name;
716 		switch (state.device[i].radio_type) {
717 		case HPWMI_WIFI:
718 			type = RFKILL_TYPE_WLAN;
719 			name = "hp-wifi";
720 			break;
721 		case HPWMI_BLUETOOTH:
722 			type = RFKILL_TYPE_BLUETOOTH;
723 			name = "hp-bluetooth";
724 			break;
725 		case HPWMI_WWAN:
726 			type = RFKILL_TYPE_WWAN;
727 			name = "hp-wwan";
728 			break;
729 		default:
730 			printk(KERN_WARNING PREFIX "unknown device type 0x%x\n",
731 				 state.device[i].radio_type);
732 			continue;
733 		}
734 
735 		if (!state.device[i].vendor_id) {
736 			printk(KERN_WARNING PREFIX "zero device %d while %d "
737 			       "reported\n", i, state.count);
738 			continue;
739 		}
740 
741 		rfkill = rfkill_alloc(name, &device->dev, type,
742 				      &hp_wmi_rfkill2_ops, (void *)(long)i);
743 		if (!rfkill) {
744 			err = -ENOMEM;
745 			goto fail;
746 		}
747 
748 		rfkill2[rfkill2_count].id = state.device[i].rfkill_id;
749 		rfkill2[rfkill2_count].num = i;
750 		rfkill2[rfkill2_count].rfkill = rfkill;
751 
752 		rfkill_init_sw_state(rfkill,
753 				     IS_SWBLOCKED(state.device[i].power));
754 		rfkill_set_hw_state(rfkill,
755 				    IS_HWBLOCKED(state.device[i].power));
756 
757 		if (!(state.device[i].power & HPWMI_POWER_BIOS))
758 			printk(KERN_INFO PREFIX "device %s blocked by BIOS\n",
759 			       name);
760 
761 		err = rfkill_register(rfkill);
762 		if (err) {
763 			rfkill_destroy(rfkill);
764 			goto fail;
765 		}
766 
767 		rfkill2_count++;
768 	}
769 
770 	return 0;
771 fail:
772 	for (; rfkill2_count > 0; rfkill2_count--) {
773 		rfkill_unregister(rfkill2[rfkill2_count - 1].rfkill);
774 		rfkill_destroy(rfkill2[rfkill2_count - 1].rfkill);
775 	}
776 	return err;
777 }
778 
hp_wmi_bios_setup(struct platform_device * device)779 static int __devinit hp_wmi_bios_setup(struct platform_device *device)
780 {
781 	int err;
782 
783 	/* clear detected rfkill devices */
784 	wifi_rfkill = NULL;
785 	bluetooth_rfkill = NULL;
786 	wwan_rfkill = NULL;
787 	rfkill2_count = 0;
788 
789 	if (hp_wmi_rfkill_setup(device))
790 		hp_wmi_rfkill2_setup(device);
791 
792 	err = device_create_file(&device->dev, &dev_attr_display);
793 	if (err)
794 		goto add_sysfs_error;
795 	err = device_create_file(&device->dev, &dev_attr_hddtemp);
796 	if (err)
797 		goto add_sysfs_error;
798 	err = device_create_file(&device->dev, &dev_attr_als);
799 	if (err)
800 		goto add_sysfs_error;
801 	err = device_create_file(&device->dev, &dev_attr_dock);
802 	if (err)
803 		goto add_sysfs_error;
804 	err = device_create_file(&device->dev, &dev_attr_tablet);
805 	if (err)
806 		goto add_sysfs_error;
807 	return 0;
808 
809 add_sysfs_error:
810 	cleanup_sysfs(device);
811 	return err;
812 }
813 
hp_wmi_bios_remove(struct platform_device * device)814 static int __exit hp_wmi_bios_remove(struct platform_device *device)
815 {
816 	int i;
817 	cleanup_sysfs(device);
818 
819 	for (i = 0; i < rfkill2_count; i++) {
820 		rfkill_unregister(rfkill2[i].rfkill);
821 		rfkill_destroy(rfkill2[i].rfkill);
822 	}
823 
824 	if (wifi_rfkill) {
825 		rfkill_unregister(wifi_rfkill);
826 		rfkill_destroy(wifi_rfkill);
827 	}
828 	if (bluetooth_rfkill) {
829 		rfkill_unregister(bluetooth_rfkill);
830 		rfkill_destroy(bluetooth_rfkill);
831 	}
832 	if (wwan_rfkill) {
833 		rfkill_unregister(wwan_rfkill);
834 		rfkill_destroy(wwan_rfkill);
835 	}
836 
837 	return 0;
838 }
839 
hp_wmi_resume_handler(struct device * device)840 static int hp_wmi_resume_handler(struct device *device)
841 {
842 	/*
843 	 * Hardware state may have changed while suspended, so trigger
844 	 * input events for the current state. As this is a switch,
845 	 * the input layer will only actually pass it on if the state
846 	 * changed.
847 	 */
848 	if (hp_wmi_input_dev) {
849 		input_report_switch(hp_wmi_input_dev, SW_DOCK,
850 				    hp_wmi_dock_state());
851 		input_report_switch(hp_wmi_input_dev, SW_TABLET_MODE,
852 				    hp_wmi_tablet_state());
853 		input_sync(hp_wmi_input_dev);
854 	}
855 
856 	if (rfkill2_count)
857 		hp_wmi_rfkill2_refresh();
858 
859 	if (wifi_rfkill)
860 		rfkill_set_states(wifi_rfkill,
861 				  hp_wmi_get_sw_state(HPWMI_WIFI),
862 				  hp_wmi_get_hw_state(HPWMI_WIFI));
863 	if (bluetooth_rfkill)
864 		rfkill_set_states(bluetooth_rfkill,
865 				  hp_wmi_get_sw_state(HPWMI_BLUETOOTH),
866 				  hp_wmi_get_hw_state(HPWMI_BLUETOOTH));
867 	if (wwan_rfkill)
868 		rfkill_set_states(wwan_rfkill,
869 				  hp_wmi_get_sw_state(HPWMI_WWAN),
870 				  hp_wmi_get_hw_state(HPWMI_WWAN));
871 
872 	return 0;
873 }
874 
hp_wmi_init(void)875 static int __init hp_wmi_init(void)
876 {
877 	int err;
878 	int event_capable = wmi_has_guid(HPWMI_EVENT_GUID);
879 	int bios_capable = wmi_has_guid(HPWMI_BIOS_GUID);
880 
881 	if (event_capable) {
882 		err = hp_wmi_input_setup();
883 		if (err)
884 			return err;
885 	}
886 
887 	if (bios_capable) {
888 		err = platform_driver_register(&hp_wmi_driver);
889 		if (err)
890 			goto err_driver_reg;
891 		hp_wmi_platform_dev = platform_device_alloc("hp-wmi", -1);
892 		if (!hp_wmi_platform_dev) {
893 			err = -ENOMEM;
894 			goto err_device_alloc;
895 		}
896 		err = platform_device_add(hp_wmi_platform_dev);
897 		if (err)
898 			goto err_device_add;
899 	}
900 
901 	if (!bios_capable && !event_capable)
902 		return -ENODEV;
903 
904 	return 0;
905 
906 err_device_add:
907 	platform_device_put(hp_wmi_platform_dev);
908 err_device_alloc:
909 	platform_driver_unregister(&hp_wmi_driver);
910 err_driver_reg:
911 	if (event_capable)
912 		hp_wmi_input_destroy();
913 
914 	return err;
915 }
916 
hp_wmi_exit(void)917 static void __exit hp_wmi_exit(void)
918 {
919 	if (wmi_has_guid(HPWMI_EVENT_GUID))
920 		hp_wmi_input_destroy();
921 
922 	if (hp_wmi_platform_dev) {
923 		platform_device_unregister(hp_wmi_platform_dev);
924 		platform_driver_unregister(&hp_wmi_driver);
925 	}
926 }
927 
928 module_init(hp_wmi_init);
929 module_exit(hp_wmi_exit);
930