eeepc-laptop: fix wlan rfkill state change during init
[GitHub/mt8127/android_kernel_alcatel_ttab.git] / drivers / platform / x86 / eeepc-laptop.c
CommitLineData
e59f8796
EC
1/*
2 * eepc-laptop.c - Asus Eee PC extras
3 *
4 * Based on asus_acpi.c as patched for the Eee PC by Asus:
5 * ftp://ftp.asus.com/pub/ASUS/EeePC/701/ASUS_ACPI_071126.rar
6 * Based on eee.c from eeepc-linux
7 *
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
12 *
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
17 */
18
19#include <linux/kernel.h>
20#include <linux/module.h>
21#include <linux/init.h>
22#include <linux/types.h>
23#include <linux/platform_device.h>
a5fa429b
CC
24#include <linux/backlight.h>
25#include <linux/fb.h>
e1faa9da
CC
26#include <linux/hwmon.h>
27#include <linux/hwmon-sysfs.h>
e59f8796
EC
28#include <acpi/acpi_drivers.h>
29#include <acpi/acpi_bus.h>
30#include <linux/uaccess.h>
a195dcdc
MG
31#include <linux/input.h>
32#include <linux/rfkill.h>
5740294c 33#include <linux/pci.h>
e59f8796
EC
34
35#define EEEPC_LAPTOP_VERSION "0.1"
36
37#define EEEPC_HOTK_NAME "Eee PC Hotkey Driver"
38#define EEEPC_HOTK_FILE "eeepc"
39#define EEEPC_HOTK_CLASS "hotkey"
40#define EEEPC_HOTK_DEVICE_NAME "Hotkey"
41#define EEEPC_HOTK_HID "ASUS010"
42
43#define EEEPC_LOG EEEPC_HOTK_FILE ": "
44#define EEEPC_ERR KERN_ERR EEEPC_LOG
45#define EEEPC_WARNING KERN_WARNING EEEPC_LOG
46#define EEEPC_NOTICE KERN_NOTICE EEEPC_LOG
47#define EEEPC_INFO KERN_INFO EEEPC_LOG
48
49/*
50 * Definitions for Asus EeePC
51 */
52#define NOTIFY_WLAN_ON 0x10
a5fa429b
CC
53#define NOTIFY_BRN_MIN 0x20
54#define NOTIFY_BRN_MAX 0x2f
e59f8796
EC
55
56enum {
57 DISABLE_ASL_WLAN = 0x0001,
58 DISABLE_ASL_BLUETOOTH = 0x0002,
59 DISABLE_ASL_IRDA = 0x0004,
60 DISABLE_ASL_CAMERA = 0x0008,
61 DISABLE_ASL_TV = 0x0010,
62 DISABLE_ASL_GPS = 0x0020,
63 DISABLE_ASL_DISPLAYSWITCH = 0x0040,
64 DISABLE_ASL_MODEM = 0x0080,
65 DISABLE_ASL_CARDREADER = 0x0100
66};
67
68enum {
69 CM_ASL_WLAN = 0,
70 CM_ASL_BLUETOOTH,
71 CM_ASL_IRDA,
72 CM_ASL_1394,
73 CM_ASL_CAMERA,
74 CM_ASL_TV,
75 CM_ASL_GPS,
76 CM_ASL_DVDROM,
77 CM_ASL_DISPLAYSWITCH,
78 CM_ASL_PANELBRIGHT,
79 CM_ASL_BIOSFLASH,
80 CM_ASL_ACPIFLASH,
81 CM_ASL_CPUFV,
82 CM_ASL_CPUTEMPERATURE,
83 CM_ASL_FANCPU,
84 CM_ASL_FANCHASSIS,
85 CM_ASL_USBPORT1,
86 CM_ASL_USBPORT2,
87 CM_ASL_USBPORT3,
88 CM_ASL_MODEM,
89 CM_ASL_CARDREADER,
90 CM_ASL_LID
91};
92
14109461 93static const char *cm_getv[] = {
3af9bfcb 94 "WLDG", "BTHG", NULL, NULL,
e59f8796
EC
95 "CAMG", NULL, NULL, NULL,
96 NULL, "PBLG", NULL, NULL,
97 "CFVG", NULL, NULL, NULL,
98 "USBG", NULL, NULL, "MODG",
99 "CRDG", "LIDG"
100};
101
14109461 102static const char *cm_setv[] = {
3af9bfcb 103 "WLDS", "BTHS", NULL, NULL,
e59f8796
EC
104 "CAMS", NULL, NULL, NULL,
105 "SDSP", "PBLS", "HDPS", NULL,
106 "CFVS", NULL, NULL, NULL,
107 "USBG", NULL, NULL, "MODS",
108 "CRDS", NULL
109};
110
e1faa9da
CC
111#define EEEPC_EC "\\_SB.PCI0.SBRG.EC0."
112
113#define EEEPC_EC_FAN_PWM EEEPC_EC "SC02" /* Fan PWM duty cycle (%) */
114#define EEEPC_EC_SC02 0x63
115#define EEEPC_EC_FAN_HRPM EEEPC_EC "SC05" /* High byte, fan speed (RPM) */
116#define EEEPC_EC_FAN_LRPM EEEPC_EC "SC06" /* Low byte, fan speed (RPM) */
117#define EEEPC_EC_FAN_CTRL EEEPC_EC "SFB3" /* Byte containing SF25 */
118#define EEEPC_EC_SFB3 0xD3
119
e59f8796
EC
120/*
121 * This is the main structure, we can use it to store useful information
122 * about the hotk device
123 */
124struct eeepc_hotk {
125 struct acpi_device *device; /* the device we are in */
126 acpi_handle handle; /* the handle of the hotk device */
127 u32 cm_supported; /* the control methods supported
128 by this BIOS */
129 uint init_flag; /* Init flags */
130 u16 event_count[128]; /* count for each event */
a195dcdc
MG
131 struct input_dev *inputdev;
132 u16 *keycode_map;
133 struct rfkill *eeepc_wlan_rfkill;
134 struct rfkill *eeepc_bluetooth_rfkill;
e59f8796
EC
135};
136
137/* The actual device the driver binds to */
138static struct eeepc_hotk *ehotk;
139
140/* Platform device/driver */
141static struct platform_driver platform_driver = {
142 .driver = {
143 .name = EEEPC_HOTK_FILE,
144 .owner = THIS_MODULE,
145 }
146};
147
148static struct platform_device *platform_device;
149
a195dcdc
MG
150struct key_entry {
151 char type;
152 u8 code;
153 u16 keycode;
154};
155
156enum { KE_KEY, KE_END };
157
158static struct key_entry eeepc_keymap[] = {
159 /* Sleep already handled via generic ACPI code */
160 {KE_KEY, 0x10, KEY_WLAN },
161 {KE_KEY, 0x12, KEY_PROG1 },
162 {KE_KEY, 0x13, KEY_MUTE },
163 {KE_KEY, 0x14, KEY_VOLUMEDOWN },
164 {KE_KEY, 0x15, KEY_VOLUMEUP },
b5f6f265
MG
165 {KE_KEY, 0x1a, KEY_COFFEE },
166 {KE_KEY, 0x1b, KEY_ZOOM },
167 {KE_KEY, 0x1c, KEY_PROG2 },
168 {KE_KEY, 0x1d, KEY_PROG3 },
a195dcdc
MG
169 {KE_KEY, 0x30, KEY_SWITCHVIDEOMODE },
170 {KE_KEY, 0x31, KEY_SWITCHVIDEOMODE },
171 {KE_KEY, 0x32, KEY_SWITCHVIDEOMODE },
172 {KE_END, 0},
173};
174
e59f8796
EC
175/*
176 * The hotkey driver declaration
177 */
178static int eeepc_hotk_add(struct acpi_device *device);
179static int eeepc_hotk_remove(struct acpi_device *device, int type);
180
181static const struct acpi_device_id eeepc_device_ids[] = {
182 {EEEPC_HOTK_HID, 0},
183 {"", 0},
184};
185MODULE_DEVICE_TABLE(acpi, eeepc_device_ids);
186
187static struct acpi_driver eeepc_hotk_driver = {
188 .name = EEEPC_HOTK_NAME,
189 .class = EEEPC_HOTK_CLASS,
190 .ids = eeepc_device_ids,
191 .ops = {
192 .add = eeepc_hotk_add,
193 .remove = eeepc_hotk_remove,
194 },
195};
196
a5fa429b
CC
197/* The backlight device /sys/class/backlight */
198static struct backlight_device *eeepc_backlight_device;
199
e1faa9da
CC
200/* The hwmon device */
201static struct device *eeepc_hwmon_device;
202
a5fa429b
CC
203/*
204 * The backlight class declaration
205 */
206static int read_brightness(struct backlight_device *bd);
207static int update_bl_status(struct backlight_device *bd);
208static struct backlight_ops eeepcbl_ops = {
209 .get_brightness = read_brightness,
210 .update_status = update_bl_status,
211};
212
e59f8796
EC
213MODULE_AUTHOR("Corentin Chary, Eric Cooper");
214MODULE_DESCRIPTION(EEEPC_HOTK_NAME);
215MODULE_LICENSE("GPL");
216
217/*
218 * ACPI Helpers
219 */
220static int write_acpi_int(acpi_handle handle, const char *method, int val,
221 struct acpi_buffer *output)
222{
223 struct acpi_object_list params;
224 union acpi_object in_obj;
225 acpi_status status;
226
227 params.count = 1;
228 params.pointer = &in_obj;
229 in_obj.type = ACPI_TYPE_INTEGER;
230 in_obj.integer.value = val;
231
232 status = acpi_evaluate_object(handle, (char *)method, &params, output);
233 return (status == AE_OK ? 0 : -1);
234}
235
236static int read_acpi_int(acpi_handle handle, const char *method, int *val)
237{
238 acpi_status status;
27663c58 239 unsigned long long result;
e59f8796
EC
240
241 status = acpi_evaluate_integer(handle, (char *)method, NULL, &result);
242 if (ACPI_FAILURE(status)) {
243 *val = -1;
244 return -1;
245 } else {
246 *val = result;
247 return 0;
248 }
249}
250
251static int set_acpi(int cm, int value)
252{
253 if (ehotk->cm_supported & (0x1 << cm)) {
254 const char *method = cm_setv[cm];
255 if (method == NULL)
256 return -ENODEV;
257 if (write_acpi_int(ehotk->handle, method, value, NULL))
258 printk(EEEPC_WARNING "Error writing %s\n", method);
259 }
260 return 0;
261}
262
263static int get_acpi(int cm)
264{
265 int value = -1;
266 if ((ehotk->cm_supported & (0x1 << cm))) {
267 const char *method = cm_getv[cm];
268 if (method == NULL)
269 return -ENODEV;
270 if (read_acpi_int(ehotk->handle, method, &value))
271 printk(EEEPC_WARNING "Error reading %s\n", method);
272 }
273 return value;
274}
275
a5fa429b
CC
276/*
277 * Backlight
278 */
279static int read_brightness(struct backlight_device *bd)
280{
281 return get_acpi(CM_ASL_PANELBRIGHT);
282}
283
284static int set_brightness(struct backlight_device *bd, int value)
285{
286 value = max(0, min(15, value));
287 return set_acpi(CM_ASL_PANELBRIGHT, value);
288}
289
290static int update_bl_status(struct backlight_device *bd)
291{
292 return set_brightness(bd, bd->props.brightness);
293}
294
a195dcdc
MG
295/*
296 * Rfkill helpers
297 */
298
299static int eeepc_wlan_rfkill_set(void *data, enum rfkill_state state)
300{
301 if (state == RFKILL_STATE_SOFT_BLOCKED)
302 return set_acpi(CM_ASL_WLAN, 0);
303 else
304 return set_acpi(CM_ASL_WLAN, 1);
305}
306
307static int eeepc_wlan_rfkill_state(void *data, enum rfkill_state *state)
308{
309 if (get_acpi(CM_ASL_WLAN) == 1)
310 *state = RFKILL_STATE_UNBLOCKED;
311 else
312 *state = RFKILL_STATE_SOFT_BLOCKED;
313 return 0;
314}
315
316static int eeepc_bluetooth_rfkill_set(void *data, enum rfkill_state state)
317{
318 if (state == RFKILL_STATE_SOFT_BLOCKED)
319 return set_acpi(CM_ASL_BLUETOOTH, 0);
320 else
321 return set_acpi(CM_ASL_BLUETOOTH, 1);
322}
323
324static int eeepc_bluetooth_rfkill_state(void *data, enum rfkill_state *state)
325{
326 if (get_acpi(CM_ASL_BLUETOOTH) == 1)
327 *state = RFKILL_STATE_UNBLOCKED;
328 else
329 *state = RFKILL_STATE_SOFT_BLOCKED;
330 return 0;
331}
332
e59f8796
EC
333/*
334 * Sys helpers
335 */
336static int parse_arg(const char *buf, unsigned long count, int *val)
337{
338 if (!count)
339 return 0;
340 if (sscanf(buf, "%i", val) != 1)
341 return -EINVAL;
342 return count;
343}
344
345static ssize_t store_sys_acpi(int cm, const char *buf, size_t count)
346{
347 int rv, value;
348
349 rv = parse_arg(buf, count, &value);
350 if (rv > 0)
351 set_acpi(cm, value);
352 return rv;
353}
354
355static ssize_t show_sys_acpi(int cm, char *buf)
356{
357 return sprintf(buf, "%d\n", get_acpi(cm));
358}
359
360#define EEEPC_CREATE_DEVICE_ATTR(_name, _cm) \
361 static ssize_t show_##_name(struct device *dev, \
362 struct device_attribute *attr, \
363 char *buf) \
364 { \
365 return show_sys_acpi(_cm, buf); \
366 } \
367 static ssize_t store_##_name(struct device *dev, \
368 struct device_attribute *attr, \
369 const char *buf, size_t count) \
370 { \
371 return store_sys_acpi(_cm, buf, count); \
372 } \
373 static struct device_attribute dev_attr_##_name = { \
374 .attr = { \
375 .name = __stringify(_name), \
376 .mode = 0644 }, \
377 .show = show_##_name, \
378 .store = store_##_name, \
379 }
380
381EEEPC_CREATE_DEVICE_ATTR(camera, CM_ASL_CAMERA);
382EEEPC_CREATE_DEVICE_ATTR(cardr, CM_ASL_CARDREADER);
383EEEPC_CREATE_DEVICE_ATTR(disp, CM_ASL_DISPLAYSWITCH);
e59f8796
EC
384
385static struct attribute *platform_attributes[] = {
386 &dev_attr_camera.attr,
387 &dev_attr_cardr.attr,
388 &dev_attr_disp.attr,
e59f8796
EC
389 NULL
390};
391
392static struct attribute_group platform_attribute_group = {
393 .attrs = platform_attributes
394};
395
396/*
397 * Hotkey functions
398 */
a195dcdc
MG
399static struct key_entry *eepc_get_entry_by_scancode(int code)
400{
401 struct key_entry *key;
402
403 for (key = eeepc_keymap; key->type != KE_END; key++)
404 if (code == key->code)
405 return key;
406
407 return NULL;
408}
409
410static struct key_entry *eepc_get_entry_by_keycode(int code)
411{
412 struct key_entry *key;
413
414 for (key = eeepc_keymap; key->type != KE_END; key++)
415 if (code == key->keycode && key->type == KE_KEY)
416 return key;
417
418 return NULL;
419}
420
421static int eeepc_getkeycode(struct input_dev *dev, int scancode, int *keycode)
422{
423 struct key_entry *key = eepc_get_entry_by_scancode(scancode);
424
425 if (key && key->type == KE_KEY) {
426 *keycode = key->keycode;
427 return 0;
428 }
429
430 return -EINVAL;
431}
432
433static int eeepc_setkeycode(struct input_dev *dev, int scancode, int keycode)
434{
435 struct key_entry *key;
436 int old_keycode;
437
438 if (keycode < 0 || keycode > KEY_MAX)
439 return -EINVAL;
440
441 key = eepc_get_entry_by_scancode(scancode);
442 if (key && key->type == KE_KEY) {
443 old_keycode = key->keycode;
444 key->keycode = keycode;
445 set_bit(keycode, dev->keybit);
446 if (!eepc_get_entry_by_keycode(old_keycode))
447 clear_bit(old_keycode, dev->keybit);
448 return 0;
449 }
450
451 return -EINVAL;
452}
453
e59f8796
EC
454static int eeepc_hotk_check(void)
455{
a195dcdc 456 const struct key_entry *key;
e59f8796
EC
457 struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
458 int result;
459
460 result = acpi_bus_get_status(ehotk->device);
461 if (result)
462 return result;
463 if (ehotk->device->status.present) {
464 if (write_acpi_int(ehotk->handle, "INIT", ehotk->init_flag,
465 &buffer)) {
466 printk(EEEPC_ERR "Hotkey initialization failed\n");
467 return -ENODEV;
468 } else {
469 printk(EEEPC_NOTICE "Hotkey init flags 0x%x\n",
470 ehotk->init_flag);
471 }
472 /* get control methods supported */
473 if (read_acpi_int(ehotk->handle, "CMSG"
474 , &ehotk->cm_supported)) {
475 printk(EEEPC_ERR
476 "Get control methods supported failed\n");
477 return -ENODEV;
478 } else {
479 printk(EEEPC_INFO
480 "Get control methods supported: 0x%x\n",
481 ehotk->cm_supported);
482 }
a195dcdc
MG
483 ehotk->inputdev = input_allocate_device();
484 if (!ehotk->inputdev) {
485 printk(EEEPC_INFO "Unable to allocate input device\n");
486 return 0;
487 }
488 ehotk->inputdev->name = "Asus EeePC extra buttons";
489 ehotk->inputdev->phys = EEEPC_HOTK_FILE "/input0";
490 ehotk->inputdev->id.bustype = BUS_HOST;
491 ehotk->inputdev->getkeycode = eeepc_getkeycode;
492 ehotk->inputdev->setkeycode = eeepc_setkeycode;
493
494 for (key = eeepc_keymap; key->type != KE_END; key++) {
495 switch (key->type) {
496 case KE_KEY:
497 set_bit(EV_KEY, ehotk->inputdev->evbit);
498 set_bit(key->keycode, ehotk->inputdev->keybit);
499 break;
500 }
501 }
502 result = input_register_device(ehotk->inputdev);
503 if (result) {
504 printk(EEEPC_INFO "Unable to register input device\n");
505 input_free_device(ehotk->inputdev);
506 return 0;
507 }
e59f8796
EC
508 } else {
509 printk(EEEPC_ERR "Hotkey device not present, aborting\n");
510 return -EINVAL;
511 }
512 return 0;
513}
514
a5fa429b
CC
515static void notify_brn(void)
516{
517 struct backlight_device *bd = eeepc_backlight_device;
7695fb04
DS
518 if (bd)
519 bd->props.brightness = read_brightness(bd);
a5fa429b
CC
520}
521
5740294c
MG
522static void eeepc_rfkill_notify(acpi_handle handle, u32 event, void *data)
523{
524 struct pci_dev *dev;
525 struct pci_bus *bus = pci_find_bus(0, 1);
526
527 if (event != ACPI_NOTIFY_BUS_CHECK)
528 return;
529
530 if (!bus) {
531 printk(EEEPC_WARNING "Unable to find PCI bus 1?\n");
532 return;
533 }
534
535 if (get_acpi(CM_ASL_WLAN) == 1) {
536 dev = pci_get_slot(bus, 0);
537 if (dev) {
538 /* Device already present */
539 pci_dev_put(dev);
540 return;
541 }
542 dev = pci_scan_single_device(bus, 0);
543 if (dev) {
544 pci_bus_assign_resources(bus);
545 if (pci_bus_add_device(dev))
546 printk(EEEPC_ERR "Unable to hotplug wifi\n");
547 }
548 } else {
549 dev = pci_get_slot(bus, 0);
550 if (dev) {
551 pci_remove_bus_device(dev);
552 pci_dev_put(dev);
553 }
554 }
555}
556
e59f8796
EC
557static void eeepc_hotk_notify(acpi_handle handle, u32 event, void *data)
558{
a195dcdc 559 static struct key_entry *key;
7950b71c
CC
560 u16 count;
561
e59f8796
EC
562 if (!ehotk)
563 return;
a5fa429b
CC
564 if (event >= NOTIFY_BRN_MIN && event <= NOTIFY_BRN_MAX)
565 notify_brn();
7950b71c
CC
566 count = ehotk->event_count[event % 128]++;
567 acpi_bus_generate_proc_event(ehotk->device, event, count);
2b25c9f0
CC
568 acpi_bus_generate_netlink_event(ehotk->device->pnp.device_class,
569 dev_name(&ehotk->device->dev), event,
7950b71c 570 count);
a195dcdc
MG
571 if (ehotk->inputdev) {
572 key = eepc_get_entry_by_scancode(event);
573 if (key) {
574 switch (key->type) {
575 case KE_KEY:
576 input_report_key(ehotk->inputdev, key->keycode,
577 1);
578 input_sync(ehotk->inputdev);
579 input_report_key(ehotk->inputdev, key->keycode,
580 0);
581 input_sync(ehotk->inputdev);
582 break;
583 }
584 }
585 }
e59f8796
EC
586}
587
5740294c
MG
588static int eeepc_register_rfkill_notifier(char *node)
589{
590 acpi_status status = AE_OK;
591 acpi_handle handle;
592
593 status = acpi_get_handle(NULL, node, &handle);
594
595 if (ACPI_SUCCESS(status)) {
596 status = acpi_install_notify_handler(handle,
597 ACPI_SYSTEM_NOTIFY,
598 eeepc_rfkill_notify,
599 NULL);
600 if (ACPI_FAILURE(status))
601 printk(EEEPC_WARNING
602 "Failed to register notify on %s\n", node);
603 } else
604 return -ENODEV;
605
606 return 0;
607}
608
609static void eeepc_unregister_rfkill_notifier(char *node)
610{
611 acpi_status status = AE_OK;
612 acpi_handle handle;
613
614 status = acpi_get_handle(NULL, node, &handle);
615
616 if (ACPI_SUCCESS(status)) {
617 status = acpi_remove_notify_handler(handle,
618 ACPI_SYSTEM_NOTIFY,
619 eeepc_rfkill_notify);
620 if (ACPI_FAILURE(status))
621 printk(EEEPC_ERR
622 "Error removing rfkill notify handler %s\n",
623 node);
624 }
625}
626
e59f8796
EC
627static int eeepc_hotk_add(struct acpi_device *device)
628{
629 acpi_status status = AE_OK;
630 int result;
631
632 if (!device)
633 return -EINVAL;
634 printk(EEEPC_NOTICE EEEPC_HOTK_NAME "\n");
635 ehotk = kzalloc(sizeof(struct eeepc_hotk), GFP_KERNEL);
636 if (!ehotk)
637 return -ENOMEM;
638 ehotk->init_flag = DISABLE_ASL_WLAN | DISABLE_ASL_DISPLAYSWITCH;
639 ehotk->handle = device->handle;
640 strcpy(acpi_device_name(device), EEEPC_HOTK_DEVICE_NAME);
641 strcpy(acpi_device_class(device), EEEPC_HOTK_CLASS);
db89b4f0 642 device->driver_data = ehotk;
e59f8796
EC
643 ehotk->device = device;
644 result = eeepc_hotk_check();
645 if (result)
c9ddf8fe 646 goto ehotk_fail;
e59f8796
EC
647 status = acpi_install_notify_handler(ehotk->handle, ACPI_SYSTEM_NOTIFY,
648 eeepc_hotk_notify, ehotk);
649 if (ACPI_FAILURE(status))
650 printk(EEEPC_ERR "Error installing notify handler\n");
a195dcdc 651
fbc97e4c
AJ
652 eeepc_register_rfkill_notifier("\\_SB.PCI0.P0P6");
653 eeepc_register_rfkill_notifier("\\_SB.PCI0.P0P7");
654
a195dcdc
MG
655 if (get_acpi(CM_ASL_WLAN) != -1) {
656 ehotk->eeepc_wlan_rfkill = rfkill_allocate(&device->dev,
657 RFKILL_TYPE_WLAN);
658
659 if (!ehotk->eeepc_wlan_rfkill)
c9ddf8fe 660 goto wlan_fail;
a195dcdc
MG
661
662 ehotk->eeepc_wlan_rfkill->name = "eeepc-wlan";
663 ehotk->eeepc_wlan_rfkill->toggle_radio = eeepc_wlan_rfkill_set;
664 ehotk->eeepc_wlan_rfkill->get_state = eeepc_wlan_rfkill_state;
c9ddf8fe 665 if (get_acpi(CM_ASL_WLAN) == 1) {
a195dcdc
MG
666 ehotk->eeepc_wlan_rfkill->state =
667 RFKILL_STATE_UNBLOCKED;
c9ddf8fe
MG
668 rfkill_set_default(RFKILL_TYPE_WLAN,
669 RFKILL_STATE_UNBLOCKED);
670 } else {
a195dcdc
MG
671 ehotk->eeepc_wlan_rfkill->state =
672 RFKILL_STATE_SOFT_BLOCKED;
c9ddf8fe
MG
673 rfkill_set_default(RFKILL_TYPE_WLAN,
674 RFKILL_STATE_SOFT_BLOCKED);
675 }
676 result = rfkill_register(ehotk->eeepc_wlan_rfkill);
677 if (result)
678 goto wlan_fail;
a195dcdc
MG
679 }
680
681 if (get_acpi(CM_ASL_BLUETOOTH) != -1) {
682 ehotk->eeepc_bluetooth_rfkill =
683 rfkill_allocate(&device->dev, RFKILL_TYPE_BLUETOOTH);
684
685 if (!ehotk->eeepc_bluetooth_rfkill)
c9ddf8fe 686 goto bluetooth_fail;
a195dcdc
MG
687
688 ehotk->eeepc_bluetooth_rfkill->name = "eeepc-bluetooth";
689 ehotk->eeepc_bluetooth_rfkill->toggle_radio =
690 eeepc_bluetooth_rfkill_set;
691 ehotk->eeepc_bluetooth_rfkill->get_state =
692 eeepc_bluetooth_rfkill_state;
c9ddf8fe 693 if (get_acpi(CM_ASL_BLUETOOTH) == 1) {
a195dcdc
MG
694 ehotk->eeepc_bluetooth_rfkill->state =
695 RFKILL_STATE_UNBLOCKED;
c9ddf8fe
MG
696 rfkill_set_default(RFKILL_TYPE_BLUETOOTH,
697 RFKILL_STATE_UNBLOCKED);
698 } else {
a195dcdc
MG
699 ehotk->eeepc_bluetooth_rfkill->state =
700 RFKILL_STATE_SOFT_BLOCKED;
c9ddf8fe
MG
701 rfkill_set_default(RFKILL_TYPE_BLUETOOTH,
702 RFKILL_STATE_SOFT_BLOCKED);
703 }
a195dcdc 704
c9ddf8fe
MG
705 result = rfkill_register(ehotk->eeepc_bluetooth_rfkill);
706 if (result)
707 goto bluetooth_fail;
e59f8796 708 }
5740294c 709
c9ddf8fe
MG
710 return 0;
711
712 bluetooth_fail:
713 if (ehotk->eeepc_bluetooth_rfkill)
714 rfkill_free(ehotk->eeepc_bluetooth_rfkill);
715 rfkill_unregister(ehotk->eeepc_wlan_rfkill);
716 ehotk->eeepc_wlan_rfkill = NULL;
717 wlan_fail:
718 if (ehotk->eeepc_wlan_rfkill)
719 rfkill_free(ehotk->eeepc_wlan_rfkill);
720 ehotk_fail:
721 kfree(ehotk);
722 ehotk = NULL;
723
e59f8796
EC
724 return result;
725}
726
727static int eeepc_hotk_remove(struct acpi_device *device, int type)
728{
729 acpi_status status = 0;
730
731 if (!device || !acpi_driver_data(device))
732 return -EINVAL;
733 status = acpi_remove_notify_handler(ehotk->handle, ACPI_SYSTEM_NOTIFY,
734 eeepc_hotk_notify);
735 if (ACPI_FAILURE(status))
736 printk(EEEPC_ERR "Error removing notify handler\n");
5740294c
MG
737
738 eeepc_unregister_rfkill_notifier("\\_SB.PCI0.P0P6");
739 eeepc_unregister_rfkill_notifier("\\_SB.PCI0.P0P7");
740
e59f8796
EC
741 kfree(ehotk);
742 return 0;
743}
744
e1faa9da
CC
745/*
746 * Hwmon
747 */
748static int eeepc_get_fan_pwm(void)
749{
750 int value = 0;
751
752 read_acpi_int(NULL, EEEPC_EC_FAN_PWM, &value);
04dcd84b 753 value = value * 255 / 100;
e1faa9da
CC
754 return (value);
755}
756
757static void eeepc_set_fan_pwm(int value)
758{
04dcd84b
CC
759 value = SENSORS_LIMIT(value, 0, 255);
760 value = value * 100 / 255;
e1faa9da
CC
761 ec_write(EEEPC_EC_SC02, value);
762}
763
764static int eeepc_get_fan_rpm(void)
765{
766 int high = 0;
767 int low = 0;
768
769 read_acpi_int(NULL, EEEPC_EC_FAN_HRPM, &high);
770 read_acpi_int(NULL, EEEPC_EC_FAN_LRPM, &low);
771 return (high << 8 | low);
772}
773
774static int eeepc_get_fan_ctrl(void)
775{
776 int value = 0;
777
778 read_acpi_int(NULL, EEEPC_EC_FAN_CTRL, &value);
779 return ((value & 0x02 ? 1 : 0));
780}
781
782static void eeepc_set_fan_ctrl(int manual)
783{
784 int value = 0;
785
786 read_acpi_int(NULL, EEEPC_EC_FAN_CTRL, &value);
787 if (manual)
788 value |= 0x02;
789 else
790 value &= ~0x02;
791 ec_write(EEEPC_EC_SFB3, value);
792}
793
794static ssize_t store_sys_hwmon(void (*set)(int), const char *buf, size_t count)
795{
796 int rv, value;
797
798 rv = parse_arg(buf, count, &value);
799 if (rv > 0)
800 set(value);
801 return rv;
802}
803
804static ssize_t show_sys_hwmon(int (*get)(void), char *buf)
805{
806 return sprintf(buf, "%d\n", get());
807}
808
809#define EEEPC_CREATE_SENSOR_ATTR(_name, _mode, _set, _get) \
810 static ssize_t show_##_name(struct device *dev, \
811 struct device_attribute *attr, \
812 char *buf) \
813 { \
814 return show_sys_hwmon(_set, buf); \
815 } \
816 static ssize_t store_##_name(struct device *dev, \
817 struct device_attribute *attr, \
818 const char *buf, size_t count) \
819 { \
820 return store_sys_hwmon(_get, buf, count); \
821 } \
822 static SENSOR_DEVICE_ATTR(_name, _mode, show_##_name, store_##_name, 0);
823
824EEEPC_CREATE_SENSOR_ATTR(fan1_input, S_IRUGO, eeepc_get_fan_rpm, NULL);
04dcd84b 825EEEPC_CREATE_SENSOR_ATTR(pwm1, S_IRUGO | S_IWUSR,
e1faa9da
CC
826 eeepc_get_fan_pwm, eeepc_set_fan_pwm);
827EEEPC_CREATE_SENSOR_ATTR(pwm1_enable, S_IRUGO | S_IWUSR,
828 eeepc_get_fan_ctrl, eeepc_set_fan_ctrl);
829
04dcd84b
CC
830static ssize_t
831show_name(struct device *dev, struct device_attribute *attr, char *buf)
832{
833 return sprintf(buf, "eeepc\n");
834}
835static SENSOR_DEVICE_ATTR(name, S_IRUGO, show_name, NULL, 0);
836
e1faa9da 837static struct attribute *hwmon_attributes[] = {
04dcd84b 838 &sensor_dev_attr_pwm1.dev_attr.attr,
e1faa9da
CC
839 &sensor_dev_attr_fan1_input.dev_attr.attr,
840 &sensor_dev_attr_pwm1_enable.dev_attr.attr,
04dcd84b 841 &sensor_dev_attr_name.dev_attr.attr,
e1faa9da
CC
842 NULL
843};
844
845static struct attribute_group hwmon_attribute_group = {
846 .attrs = hwmon_attributes
847};
848
e59f8796
EC
849/*
850 * exit/init
851 */
a5fa429b
CC
852static void eeepc_backlight_exit(void)
853{
854 if (eeepc_backlight_device)
855 backlight_device_unregister(eeepc_backlight_device);
a9df80c5
CC
856 eeepc_backlight_device = NULL;
857}
858
859static void eeepc_rfkill_exit(void)
860{
a195dcdc
MG
861 if (ehotk->eeepc_wlan_rfkill)
862 rfkill_unregister(ehotk->eeepc_wlan_rfkill);
863 if (ehotk->eeepc_bluetooth_rfkill)
864 rfkill_unregister(ehotk->eeepc_bluetooth_rfkill);
a9df80c5
CC
865}
866
867static void eeepc_input_exit(void)
868{
869 if (ehotk->inputdev)
870 input_unregister_device(ehotk->inputdev);
a5fa429b
CC
871}
872
e1faa9da
CC
873static void eeepc_hwmon_exit(void)
874{
875 struct device *hwmon;
876
877 hwmon = eeepc_hwmon_device;
878 if (!hwmon)
879 return ;
e1faa9da
CC
880 sysfs_remove_group(&hwmon->kobj,
881 &hwmon_attribute_group);
f1441318 882 hwmon_device_unregister(hwmon);
e1faa9da
CC
883 eeepc_hwmon_device = NULL;
884}
885
e59f8796
EC
886static void __exit eeepc_laptop_exit(void)
887{
a5fa429b 888 eeepc_backlight_exit();
a9df80c5
CC
889 eeepc_rfkill_exit();
890 eeepc_input_exit();
e1faa9da 891 eeepc_hwmon_exit();
e59f8796
EC
892 acpi_bus_unregister_driver(&eeepc_hotk_driver);
893 sysfs_remove_group(&platform_device->dev.kobj,
894 &platform_attribute_group);
895 platform_device_unregister(platform_device);
896 platform_driver_unregister(&platform_driver);
897}
898
a5fa429b
CC
899static int eeepc_backlight_init(struct device *dev)
900{
901 struct backlight_device *bd;
902
903 bd = backlight_device_register(EEEPC_HOTK_FILE, dev,
904 NULL, &eeepcbl_ops);
905 if (IS_ERR(bd)) {
906 printk(EEEPC_ERR
907 "Could not register eeepc backlight device\n");
908 eeepc_backlight_device = NULL;
909 return PTR_ERR(bd);
910 }
911 eeepc_backlight_device = bd;
912 bd->props.max_brightness = 15;
913 bd->props.brightness = read_brightness(NULL);
914 bd->props.power = FB_BLANK_UNBLANK;
915 backlight_update_status(bd);
916 return 0;
917}
918
e1faa9da
CC
919static int eeepc_hwmon_init(struct device *dev)
920{
921 struct device *hwmon;
922 int result;
923
924 hwmon = hwmon_device_register(dev);
925 if (IS_ERR(hwmon)) {
926 printk(EEEPC_ERR
927 "Could not register eeepc hwmon device\n");
928 eeepc_hwmon_device = NULL;
929 return PTR_ERR(hwmon);
930 }
931 eeepc_hwmon_device = hwmon;
932 result = sysfs_create_group(&hwmon->kobj,
933 &hwmon_attribute_group);
934 if (result)
935 eeepc_hwmon_exit();
936 return result;
937}
938
e59f8796
EC
939static int __init eeepc_laptop_init(void)
940{
941 struct device *dev;
942 int result;
943
944 if (acpi_disabled)
945 return -ENODEV;
946 result = acpi_bus_register_driver(&eeepc_hotk_driver);
947 if (result < 0)
948 return result;
949 if (!ehotk) {
950 acpi_bus_unregister_driver(&eeepc_hotk_driver);
951 return -ENODEV;
952 }
953 dev = acpi_get_physical_device(ehotk->device->handle);
a2bf8c01
TR
954
955 if (!acpi_video_backlight_support()) {
956 result = eeepc_backlight_init(dev);
957 if (result)
958 goto fail_backlight;
959 } else
960 printk(EEEPC_INFO "Backlight controlled by ACPI video "
961 "driver\n");
962
e1faa9da
CC
963 result = eeepc_hwmon_init(dev);
964 if (result)
965 goto fail_hwmon;
e59f8796
EC
966 /* Register platform stuff */
967 result = platform_driver_register(&platform_driver);
968 if (result)
969 goto fail_platform_driver;
970 platform_device = platform_device_alloc(EEEPC_HOTK_FILE, -1);
971 if (!platform_device) {
972 result = -ENOMEM;
973 goto fail_platform_device1;
974 }
975 result = platform_device_add(platform_device);
976 if (result)
977 goto fail_platform_device2;
978 result = sysfs_create_group(&platform_device->dev.kobj,
979 &platform_attribute_group);
980 if (result)
981 goto fail_sysfs;
982 return 0;
983fail_sysfs:
984 platform_device_del(platform_device);
985fail_platform_device2:
986 platform_device_put(platform_device);
987fail_platform_device1:
988 platform_driver_unregister(&platform_driver);
989fail_platform_driver:
e1faa9da
CC
990 eeepc_hwmon_exit();
991fail_hwmon:
a5fa429b
CC
992 eeepc_backlight_exit();
993fail_backlight:
a9df80c5
CC
994 eeepc_input_exit();
995 eeepc_rfkill_exit();
e59f8796
EC
996 return result;
997}
998
999module_init(eeepc_laptop_init);
1000module_exit(eeepc_laptop_exit);