rfkill: don't restore software blocked state on persistent devices
[deliverable/linux.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 },
978605c4 161 {KE_KEY, 0x11, KEY_WLAN },
a195dcdc
MG
162 {KE_KEY, 0x12, KEY_PROG1 },
163 {KE_KEY, 0x13, KEY_MUTE },
164 {KE_KEY, 0x14, KEY_VOLUMEDOWN },
165 {KE_KEY, 0x15, KEY_VOLUMEUP },
b5f6f265
MG
166 {KE_KEY, 0x1a, KEY_COFFEE },
167 {KE_KEY, 0x1b, KEY_ZOOM },
168 {KE_KEY, 0x1c, KEY_PROG2 },
169 {KE_KEY, 0x1d, KEY_PROG3 },
64b86b65
DS
170 {KE_KEY, NOTIFY_BRN_MIN, KEY_BRIGHTNESSDOWN },
171 {KE_KEY, NOTIFY_BRN_MIN + 2, KEY_BRIGHTNESSUP },
a195dcdc
MG
172 {KE_KEY, 0x30, KEY_SWITCHVIDEOMODE },
173 {KE_KEY, 0x31, KEY_SWITCHVIDEOMODE },
174 {KE_KEY, 0x32, KEY_SWITCHVIDEOMODE },
175 {KE_END, 0},
176};
177
e59f8796
EC
178/*
179 * The hotkey driver declaration
180 */
181static int eeepc_hotk_add(struct acpi_device *device);
182static int eeepc_hotk_remove(struct acpi_device *device, int type);
183
184static const struct acpi_device_id eeepc_device_ids[] = {
185 {EEEPC_HOTK_HID, 0},
186 {"", 0},
187};
188MODULE_DEVICE_TABLE(acpi, eeepc_device_ids);
189
190static struct acpi_driver eeepc_hotk_driver = {
191 .name = EEEPC_HOTK_NAME,
192 .class = EEEPC_HOTK_CLASS,
193 .ids = eeepc_device_ids,
194 .ops = {
195 .add = eeepc_hotk_add,
196 .remove = eeepc_hotk_remove,
197 },
198};
199
a5fa429b
CC
200/* The backlight device /sys/class/backlight */
201static struct backlight_device *eeepc_backlight_device;
202
e1faa9da
CC
203/* The hwmon device */
204static struct device *eeepc_hwmon_device;
205
a5fa429b
CC
206/*
207 * The backlight class declaration
208 */
209static int read_brightness(struct backlight_device *bd);
210static int update_bl_status(struct backlight_device *bd);
211static struct backlight_ops eeepcbl_ops = {
212 .get_brightness = read_brightness,
213 .update_status = update_bl_status,
214};
215
e59f8796
EC
216MODULE_AUTHOR("Corentin Chary, Eric Cooper");
217MODULE_DESCRIPTION(EEEPC_HOTK_NAME);
218MODULE_LICENSE("GPL");
219
220/*
221 * ACPI Helpers
222 */
223static int write_acpi_int(acpi_handle handle, const char *method, int val,
224 struct acpi_buffer *output)
225{
226 struct acpi_object_list params;
227 union acpi_object in_obj;
228 acpi_status status;
229
230 params.count = 1;
231 params.pointer = &in_obj;
232 in_obj.type = ACPI_TYPE_INTEGER;
233 in_obj.integer.value = val;
234
235 status = acpi_evaluate_object(handle, (char *)method, &params, output);
236 return (status == AE_OK ? 0 : -1);
237}
238
239static int read_acpi_int(acpi_handle handle, const char *method, int *val)
240{
241 acpi_status status;
27663c58 242 unsigned long long result;
e59f8796
EC
243
244 status = acpi_evaluate_integer(handle, (char *)method, NULL, &result);
245 if (ACPI_FAILURE(status)) {
246 *val = -1;
247 return -1;
248 } else {
249 *val = result;
250 return 0;
251 }
252}
253
254static int set_acpi(int cm, int value)
255{
256 if (ehotk->cm_supported & (0x1 << cm)) {
257 const char *method = cm_setv[cm];
258 if (method == NULL)
259 return -ENODEV;
260 if (write_acpi_int(ehotk->handle, method, value, NULL))
261 printk(EEEPC_WARNING "Error writing %s\n", method);
262 }
263 return 0;
264}
265
266static int get_acpi(int cm)
267{
268 int value = -1;
269 if ((ehotk->cm_supported & (0x1 << cm))) {
270 const char *method = cm_getv[cm];
271 if (method == NULL)
272 return -ENODEV;
273 if (read_acpi_int(ehotk->handle, method, &value))
274 printk(EEEPC_WARNING "Error reading %s\n", method);
275 }
276 return value;
277}
278
a5fa429b
CC
279/*
280 * Backlight
281 */
282static int read_brightness(struct backlight_device *bd)
283{
284 return get_acpi(CM_ASL_PANELBRIGHT);
285}
286
287static int set_brightness(struct backlight_device *bd, int value)
288{
289 value = max(0, min(15, value));
290 return set_acpi(CM_ASL_PANELBRIGHT, value);
291}
292
293static int update_bl_status(struct backlight_device *bd)
294{
295 return set_brightness(bd, bd->props.brightness);
296}
297
a195dcdc
MG
298/*
299 * Rfkill helpers
300 */
301
19d337df 302static bool eeepc_wlan_rfkill_blocked(void)
a195dcdc
MG
303{
304 if (get_acpi(CM_ASL_WLAN) == 1)
19d337df
JB
305 return false;
306 return true;
a195dcdc
MG
307}
308
19d337df 309static int eeepc_rfkill_set(void *data, bool blocked)
a195dcdc 310{
19d337df
JB
311 unsigned long asl = (unsigned long)data;
312 return set_acpi(asl, !blocked);
a195dcdc
MG
313}
314
19d337df
JB
315static const struct rfkill_ops eeepc_rfkill_ops = {
316 .set_block = eeepc_rfkill_set,
317};
a195dcdc 318
e59f8796
EC
319/*
320 * Sys helpers
321 */
322static int parse_arg(const char *buf, unsigned long count, int *val)
323{
324 if (!count)
325 return 0;
326 if (sscanf(buf, "%i", val) != 1)
327 return -EINVAL;
328 return count;
329}
330
331static ssize_t store_sys_acpi(int cm, const char *buf, size_t count)
332{
333 int rv, value;
334
335 rv = parse_arg(buf, count, &value);
336 if (rv > 0)
337 set_acpi(cm, value);
338 return rv;
339}
340
341static ssize_t show_sys_acpi(int cm, char *buf)
342{
343 return sprintf(buf, "%d\n", get_acpi(cm));
344}
345
346#define EEEPC_CREATE_DEVICE_ATTR(_name, _cm) \
347 static ssize_t show_##_name(struct device *dev, \
348 struct device_attribute *attr, \
349 char *buf) \
350 { \
351 return show_sys_acpi(_cm, buf); \
352 } \
353 static ssize_t store_##_name(struct device *dev, \
354 struct device_attribute *attr, \
355 const char *buf, size_t count) \
356 { \
357 return store_sys_acpi(_cm, buf, count); \
358 } \
359 static struct device_attribute dev_attr_##_name = { \
360 .attr = { \
361 .name = __stringify(_name), \
362 .mode = 0644 }, \
363 .show = show_##_name, \
364 .store = store_##_name, \
365 }
366
367EEEPC_CREATE_DEVICE_ATTR(camera, CM_ASL_CAMERA);
368EEEPC_CREATE_DEVICE_ATTR(cardr, CM_ASL_CARDREADER);
369EEEPC_CREATE_DEVICE_ATTR(disp, CM_ASL_DISPLAYSWITCH);
158ca1d7 370EEEPC_CREATE_DEVICE_ATTR(cpufv, CM_ASL_CPUFV);
e59f8796
EC
371
372static struct attribute *platform_attributes[] = {
373 &dev_attr_camera.attr,
374 &dev_attr_cardr.attr,
375 &dev_attr_disp.attr,
158ca1d7 376 &dev_attr_cpufv.attr,
e59f8796
EC
377 NULL
378};
379
380static struct attribute_group platform_attribute_group = {
381 .attrs = platform_attributes
382};
383
384/*
385 * Hotkey functions
386 */
a195dcdc
MG
387static struct key_entry *eepc_get_entry_by_scancode(int code)
388{
389 struct key_entry *key;
390
391 for (key = eeepc_keymap; key->type != KE_END; key++)
392 if (code == key->code)
393 return key;
394
395 return NULL;
396}
397
398static struct key_entry *eepc_get_entry_by_keycode(int code)
399{
400 struct key_entry *key;
401
402 for (key = eeepc_keymap; key->type != KE_END; key++)
403 if (code == key->keycode && key->type == KE_KEY)
404 return key;
405
406 return NULL;
407}
408
409static int eeepc_getkeycode(struct input_dev *dev, int scancode, int *keycode)
410{
411 struct key_entry *key = eepc_get_entry_by_scancode(scancode);
412
413 if (key && key->type == KE_KEY) {
414 *keycode = key->keycode;
415 return 0;
416 }
417
418 return -EINVAL;
419}
420
421static int eeepc_setkeycode(struct input_dev *dev, int scancode, int keycode)
422{
423 struct key_entry *key;
424 int old_keycode;
425
426 if (keycode < 0 || keycode > KEY_MAX)
427 return -EINVAL;
428
429 key = eepc_get_entry_by_scancode(scancode);
430 if (key && key->type == KE_KEY) {
431 old_keycode = key->keycode;
432 key->keycode = keycode;
433 set_bit(keycode, dev->keybit);
434 if (!eepc_get_entry_by_keycode(old_keycode))
435 clear_bit(old_keycode, dev->keybit);
436 return 0;
437 }
438
439 return -EINVAL;
440}
441
e59f8796
EC
442static int eeepc_hotk_check(void)
443{
a195dcdc 444 const struct key_entry *key;
e59f8796
EC
445 struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
446 int result;
447
448 result = acpi_bus_get_status(ehotk->device);
449 if (result)
450 return result;
451 if (ehotk->device->status.present) {
452 if (write_acpi_int(ehotk->handle, "INIT", ehotk->init_flag,
453 &buffer)) {
454 printk(EEEPC_ERR "Hotkey initialization failed\n");
455 return -ENODEV;
456 } else {
457 printk(EEEPC_NOTICE "Hotkey init flags 0x%x\n",
458 ehotk->init_flag);
459 }
460 /* get control methods supported */
461 if (read_acpi_int(ehotk->handle, "CMSG"
462 , &ehotk->cm_supported)) {
463 printk(EEEPC_ERR
464 "Get control methods supported failed\n");
465 return -ENODEV;
466 } else {
467 printk(EEEPC_INFO
468 "Get control methods supported: 0x%x\n",
469 ehotk->cm_supported);
470 }
a195dcdc
MG
471 ehotk->inputdev = input_allocate_device();
472 if (!ehotk->inputdev) {
473 printk(EEEPC_INFO "Unable to allocate input device\n");
474 return 0;
475 }
476 ehotk->inputdev->name = "Asus EeePC extra buttons";
477 ehotk->inputdev->phys = EEEPC_HOTK_FILE "/input0";
478 ehotk->inputdev->id.bustype = BUS_HOST;
479 ehotk->inputdev->getkeycode = eeepc_getkeycode;
480 ehotk->inputdev->setkeycode = eeepc_setkeycode;
481
482 for (key = eeepc_keymap; key->type != KE_END; key++) {
483 switch (key->type) {
484 case KE_KEY:
485 set_bit(EV_KEY, ehotk->inputdev->evbit);
486 set_bit(key->keycode, ehotk->inputdev->keybit);
487 break;
488 }
489 }
490 result = input_register_device(ehotk->inputdev);
491 if (result) {
492 printk(EEEPC_INFO "Unable to register input device\n");
493 input_free_device(ehotk->inputdev);
494 return 0;
495 }
e59f8796
EC
496 } else {
497 printk(EEEPC_ERR "Hotkey device not present, aborting\n");
498 return -EINVAL;
499 }
500 return 0;
501}
502
64b86b65 503static int notify_brn(void)
a5fa429b 504{
64b86b65 505 /* returns the *previous* brightness, or -1 */
a5fa429b 506 struct backlight_device *bd = eeepc_backlight_device;
64b86b65
DS
507 if (bd) {
508 int old = bd->props.brightness;
7695fb04 509 bd->props.brightness = read_brightness(bd);
64b86b65
DS
510 return old;
511 }
512 return -1;
a5fa429b
CC
513}
514
5740294c
MG
515static void eeepc_rfkill_notify(acpi_handle handle, u32 event, void *data)
516{
517 struct pci_dev *dev;
518 struct pci_bus *bus = pci_find_bus(0, 1);
19d337df 519 bool blocked;
5740294c
MG
520
521 if (event != ACPI_NOTIFY_BUS_CHECK)
522 return;
523
524 if (!bus) {
525 printk(EEEPC_WARNING "Unable to find PCI bus 1?\n");
526 return;
527 }
528
19d337df
JB
529 blocked = eeepc_wlan_rfkill_blocked();
530 if (!blocked) {
5740294c
MG
531 dev = pci_get_slot(bus, 0);
532 if (dev) {
533 /* Device already present */
534 pci_dev_put(dev);
535 return;
536 }
537 dev = pci_scan_single_device(bus, 0);
538 if (dev) {
539 pci_bus_assign_resources(bus);
540 if (pci_bus_add_device(dev))
541 printk(EEEPC_ERR "Unable to hotplug wifi\n");
542 }
543 } else {
544 dev = pci_get_slot(bus, 0);
545 if (dev) {
546 pci_remove_bus_device(dev);
547 pci_dev_put(dev);
548 }
549 }
978605c4 550
19d337df 551 rfkill_set_sw_state(ehotk->eeepc_wlan_rfkill, blocked);
5740294c
MG
552}
553
e59f8796
EC
554static void eeepc_hotk_notify(acpi_handle handle, u32 event, void *data)
555{
a195dcdc 556 static struct key_entry *key;
7950b71c 557 u16 count;
64b86b65 558 int brn = -ENODEV;
7950b71c 559
e59f8796
EC
560 if (!ehotk)
561 return;
a5fa429b 562 if (event >= NOTIFY_BRN_MIN && event <= NOTIFY_BRN_MAX)
64b86b65 563 brn = notify_brn();
7950b71c
CC
564 count = ehotk->event_count[event % 128]++;
565 acpi_bus_generate_proc_event(ehotk->device, event, count);
2b25c9f0
CC
566 acpi_bus_generate_netlink_event(ehotk->device->pnp.device_class,
567 dev_name(&ehotk->device->dev), event,
7950b71c 568 count);
a195dcdc 569 if (ehotk->inputdev) {
64b86b65
DS
570 if (brn != -ENODEV) {
571 /* brightness-change events need special
572 * handling for conversion to key events
573 */
574 if (brn < 0)
575 brn = event;
576 else
577 brn += NOTIFY_BRN_MIN;
578 if (event < brn)
579 event = NOTIFY_BRN_MIN; /* brightness down */
580 else if (event > brn)
581 event = NOTIFY_BRN_MIN + 2; /* ... up */
582 else
583 event = NOTIFY_BRN_MIN + 1; /* ... unchanged */
584 }
a195dcdc
MG
585 key = eepc_get_entry_by_scancode(event);
586 if (key) {
587 switch (key->type) {
588 case KE_KEY:
589 input_report_key(ehotk->inputdev, key->keycode,
590 1);
591 input_sync(ehotk->inputdev);
592 input_report_key(ehotk->inputdev, key->keycode,
593 0);
594 input_sync(ehotk->inputdev);
595 break;
596 }
597 }
598 }
e59f8796
EC
599}
600
5740294c
MG
601static int eeepc_register_rfkill_notifier(char *node)
602{
603 acpi_status status = AE_OK;
604 acpi_handle handle;
605
606 status = acpi_get_handle(NULL, node, &handle);
607
608 if (ACPI_SUCCESS(status)) {
609 status = acpi_install_notify_handler(handle,
610 ACPI_SYSTEM_NOTIFY,
611 eeepc_rfkill_notify,
612 NULL);
613 if (ACPI_FAILURE(status))
614 printk(EEEPC_WARNING
615 "Failed to register notify on %s\n", node);
616 } else
617 return -ENODEV;
618
619 return 0;
620}
621
622static void eeepc_unregister_rfkill_notifier(char *node)
623{
624 acpi_status status = AE_OK;
625 acpi_handle handle;
626
627 status = acpi_get_handle(NULL, node, &handle);
628
629 if (ACPI_SUCCESS(status)) {
630 status = acpi_remove_notify_handler(handle,
631 ACPI_SYSTEM_NOTIFY,
632 eeepc_rfkill_notify);
633 if (ACPI_FAILURE(status))
634 printk(EEEPC_ERR
635 "Error removing rfkill notify handler %s\n",
636 node);
637 }
638}
639
e59f8796
EC
640static int eeepc_hotk_add(struct acpi_device *device)
641{
642 acpi_status status = AE_OK;
643 int result;
644
645 if (!device)
646 return -EINVAL;
647 printk(EEEPC_NOTICE EEEPC_HOTK_NAME "\n");
648 ehotk = kzalloc(sizeof(struct eeepc_hotk), GFP_KERNEL);
649 if (!ehotk)
650 return -ENOMEM;
651 ehotk->init_flag = DISABLE_ASL_WLAN | DISABLE_ASL_DISPLAYSWITCH;
652 ehotk->handle = device->handle;
653 strcpy(acpi_device_name(device), EEEPC_HOTK_DEVICE_NAME);
654 strcpy(acpi_device_class(device), EEEPC_HOTK_CLASS);
db89b4f0 655 device->driver_data = ehotk;
e59f8796
EC
656 ehotk->device = device;
657 result = eeepc_hotk_check();
658 if (result)
c9ddf8fe 659 goto ehotk_fail;
e59f8796
EC
660 status = acpi_install_notify_handler(ehotk->handle, ACPI_SYSTEM_NOTIFY,
661 eeepc_hotk_notify, ehotk);
662 if (ACPI_FAILURE(status))
663 printk(EEEPC_ERR "Error installing notify handler\n");
a195dcdc 664
fbc97e4c
AJ
665 eeepc_register_rfkill_notifier("\\_SB.PCI0.P0P6");
666 eeepc_register_rfkill_notifier("\\_SB.PCI0.P0P7");
667
a195dcdc 668 if (get_acpi(CM_ASL_WLAN) != -1) {
19d337df
JB
669 ehotk->eeepc_wlan_rfkill = rfkill_alloc("eeepc-wlan",
670 &device->dev,
671 RFKILL_TYPE_WLAN,
672 &eeepc_rfkill_ops,
673 (void *)CM_ASL_WLAN);
a195dcdc
MG
674
675 if (!ehotk->eeepc_wlan_rfkill)
c9ddf8fe 676 goto wlan_fail;
a195dcdc 677
06d5caf4
AJ
678 rfkill_init_sw_state(ehotk->eeepc_wlan_rfkill,
679 get_acpi(CM_ASL_WLAN) != 1);
c9ddf8fe
MG
680 result = rfkill_register(ehotk->eeepc_wlan_rfkill);
681 if (result)
682 goto wlan_fail;
a195dcdc
MG
683 }
684
685 if (get_acpi(CM_ASL_BLUETOOTH) != -1) {
686 ehotk->eeepc_bluetooth_rfkill =
19d337df
JB
687 rfkill_alloc("eeepc-bluetooth",
688 &device->dev,
689 RFKILL_TYPE_BLUETOOTH,
690 &eeepc_rfkill_ops,
691 (void *)CM_ASL_BLUETOOTH);
a195dcdc
MG
692
693 if (!ehotk->eeepc_bluetooth_rfkill)
c9ddf8fe 694 goto bluetooth_fail;
a195dcdc 695
06d5caf4
AJ
696 rfkill_init_sw_state(ehotk->eeepc_bluetooth_rfkill,
697 get_acpi(CM_ASL_BLUETOOTH) != 1);
c9ddf8fe
MG
698 result = rfkill_register(ehotk->eeepc_bluetooth_rfkill);
699 if (result)
700 goto bluetooth_fail;
e59f8796 701 }
5740294c 702
c9ddf8fe
MG
703 return 0;
704
705 bluetooth_fail:
19d337df 706 rfkill_destroy(ehotk->eeepc_bluetooth_rfkill);
c9ddf8fe 707 rfkill_unregister(ehotk->eeepc_wlan_rfkill);
c9ddf8fe 708 wlan_fail:
19d337df 709 rfkill_destroy(ehotk->eeepc_wlan_rfkill);
bd32005e
CC
710 eeepc_unregister_rfkill_notifier("\\_SB.PCI0.P0P6");
711 eeepc_unregister_rfkill_notifier("\\_SB.PCI0.P0P7");
c9ddf8fe
MG
712 ehotk_fail:
713 kfree(ehotk);
714 ehotk = NULL;
715
e59f8796
EC
716 return result;
717}
718
719static int eeepc_hotk_remove(struct acpi_device *device, int type)
720{
721 acpi_status status = 0;
722
723 if (!device || !acpi_driver_data(device))
724 return -EINVAL;
725 status = acpi_remove_notify_handler(ehotk->handle, ACPI_SYSTEM_NOTIFY,
726 eeepc_hotk_notify);
727 if (ACPI_FAILURE(status))
728 printk(EEEPC_ERR "Error removing notify handler\n");
5740294c
MG
729
730 eeepc_unregister_rfkill_notifier("\\_SB.PCI0.P0P6");
731 eeepc_unregister_rfkill_notifier("\\_SB.PCI0.P0P7");
732
e59f8796
EC
733 kfree(ehotk);
734 return 0;
735}
736
e1faa9da
CC
737/*
738 * Hwmon
739 */
740static int eeepc_get_fan_pwm(void)
741{
742 int value = 0;
743
744 read_acpi_int(NULL, EEEPC_EC_FAN_PWM, &value);
04dcd84b 745 value = value * 255 / 100;
e1faa9da
CC
746 return (value);
747}
748
749static void eeepc_set_fan_pwm(int value)
750{
04dcd84b
CC
751 value = SENSORS_LIMIT(value, 0, 255);
752 value = value * 100 / 255;
e1faa9da
CC
753 ec_write(EEEPC_EC_SC02, value);
754}
755
756static int eeepc_get_fan_rpm(void)
757{
758 int high = 0;
759 int low = 0;
760
761 read_acpi_int(NULL, EEEPC_EC_FAN_HRPM, &high);
762 read_acpi_int(NULL, EEEPC_EC_FAN_LRPM, &low);
763 return (high << 8 | low);
764}
765
766static int eeepc_get_fan_ctrl(void)
767{
768 int value = 0;
769
770 read_acpi_int(NULL, EEEPC_EC_FAN_CTRL, &value);
771 return ((value & 0x02 ? 1 : 0));
772}
773
774static void eeepc_set_fan_ctrl(int manual)
775{
776 int value = 0;
777
778 read_acpi_int(NULL, EEEPC_EC_FAN_CTRL, &value);
779 if (manual)
780 value |= 0x02;
781 else
782 value &= ~0x02;
783 ec_write(EEEPC_EC_SFB3, value);
784}
785
786static ssize_t store_sys_hwmon(void (*set)(int), const char *buf, size_t count)
787{
788 int rv, value;
789
790 rv = parse_arg(buf, count, &value);
791 if (rv > 0)
792 set(value);
793 return rv;
794}
795
796static ssize_t show_sys_hwmon(int (*get)(void), char *buf)
797{
798 return sprintf(buf, "%d\n", get());
799}
800
801#define EEEPC_CREATE_SENSOR_ATTR(_name, _mode, _set, _get) \
802 static ssize_t show_##_name(struct device *dev, \
803 struct device_attribute *attr, \
804 char *buf) \
805 { \
806 return show_sys_hwmon(_set, buf); \
807 } \
808 static ssize_t store_##_name(struct device *dev, \
809 struct device_attribute *attr, \
810 const char *buf, size_t count) \
811 { \
812 return store_sys_hwmon(_get, buf, count); \
813 } \
814 static SENSOR_DEVICE_ATTR(_name, _mode, show_##_name, store_##_name, 0);
815
816EEEPC_CREATE_SENSOR_ATTR(fan1_input, S_IRUGO, eeepc_get_fan_rpm, NULL);
04dcd84b 817EEEPC_CREATE_SENSOR_ATTR(pwm1, S_IRUGO | S_IWUSR,
e1faa9da
CC
818 eeepc_get_fan_pwm, eeepc_set_fan_pwm);
819EEEPC_CREATE_SENSOR_ATTR(pwm1_enable, S_IRUGO | S_IWUSR,
820 eeepc_get_fan_ctrl, eeepc_set_fan_ctrl);
821
04dcd84b
CC
822static ssize_t
823show_name(struct device *dev, struct device_attribute *attr, char *buf)
824{
825 return sprintf(buf, "eeepc\n");
826}
827static SENSOR_DEVICE_ATTR(name, S_IRUGO, show_name, NULL, 0);
828
e1faa9da 829static struct attribute *hwmon_attributes[] = {
04dcd84b 830 &sensor_dev_attr_pwm1.dev_attr.attr,
e1faa9da
CC
831 &sensor_dev_attr_fan1_input.dev_attr.attr,
832 &sensor_dev_attr_pwm1_enable.dev_attr.attr,
04dcd84b 833 &sensor_dev_attr_name.dev_attr.attr,
e1faa9da
CC
834 NULL
835};
836
837static struct attribute_group hwmon_attribute_group = {
838 .attrs = hwmon_attributes
839};
840
e59f8796
EC
841/*
842 * exit/init
843 */
a5fa429b
CC
844static void eeepc_backlight_exit(void)
845{
846 if (eeepc_backlight_device)
847 backlight_device_unregister(eeepc_backlight_device);
a9df80c5
CC
848 eeepc_backlight_device = NULL;
849}
850
851static void eeepc_rfkill_exit(void)
852{
a195dcdc
MG
853 if (ehotk->eeepc_wlan_rfkill)
854 rfkill_unregister(ehotk->eeepc_wlan_rfkill);
855 if (ehotk->eeepc_bluetooth_rfkill)
856 rfkill_unregister(ehotk->eeepc_bluetooth_rfkill);
a9df80c5
CC
857}
858
859static void eeepc_input_exit(void)
860{
861 if (ehotk->inputdev)
862 input_unregister_device(ehotk->inputdev);
a5fa429b
CC
863}
864
e1faa9da
CC
865static void eeepc_hwmon_exit(void)
866{
867 struct device *hwmon;
868
869 hwmon = eeepc_hwmon_device;
870 if (!hwmon)
871 return ;
e1faa9da
CC
872 sysfs_remove_group(&hwmon->kobj,
873 &hwmon_attribute_group);
f1441318 874 hwmon_device_unregister(hwmon);
e1faa9da
CC
875 eeepc_hwmon_device = NULL;
876}
877
e59f8796
EC
878static void __exit eeepc_laptop_exit(void)
879{
a5fa429b 880 eeepc_backlight_exit();
a9df80c5
CC
881 eeepc_rfkill_exit();
882 eeepc_input_exit();
e1faa9da 883 eeepc_hwmon_exit();
e59f8796
EC
884 acpi_bus_unregister_driver(&eeepc_hotk_driver);
885 sysfs_remove_group(&platform_device->dev.kobj,
886 &platform_attribute_group);
887 platform_device_unregister(platform_device);
888 platform_driver_unregister(&platform_driver);
889}
890
a5fa429b
CC
891static int eeepc_backlight_init(struct device *dev)
892{
893 struct backlight_device *bd;
894
895 bd = backlight_device_register(EEEPC_HOTK_FILE, dev,
896 NULL, &eeepcbl_ops);
897 if (IS_ERR(bd)) {
898 printk(EEEPC_ERR
899 "Could not register eeepc backlight device\n");
900 eeepc_backlight_device = NULL;
901 return PTR_ERR(bd);
902 }
903 eeepc_backlight_device = bd;
904 bd->props.max_brightness = 15;
905 bd->props.brightness = read_brightness(NULL);
906 bd->props.power = FB_BLANK_UNBLANK;
907 backlight_update_status(bd);
908 return 0;
909}
910
e1faa9da
CC
911static int eeepc_hwmon_init(struct device *dev)
912{
913 struct device *hwmon;
914 int result;
915
916 hwmon = hwmon_device_register(dev);
917 if (IS_ERR(hwmon)) {
918 printk(EEEPC_ERR
919 "Could not register eeepc hwmon device\n");
920 eeepc_hwmon_device = NULL;
921 return PTR_ERR(hwmon);
922 }
923 eeepc_hwmon_device = hwmon;
924 result = sysfs_create_group(&hwmon->kobj,
925 &hwmon_attribute_group);
926 if (result)
927 eeepc_hwmon_exit();
928 return result;
929}
930
e59f8796
EC
931static int __init eeepc_laptop_init(void)
932{
933 struct device *dev;
934 int result;
935
936 if (acpi_disabled)
937 return -ENODEV;
938 result = acpi_bus_register_driver(&eeepc_hotk_driver);
939 if (result < 0)
940 return result;
941 if (!ehotk) {
942 acpi_bus_unregister_driver(&eeepc_hotk_driver);
943 return -ENODEV;
944 }
945 dev = acpi_get_physical_device(ehotk->device->handle);
a2bf8c01
TR
946
947 if (!acpi_video_backlight_support()) {
948 result = eeepc_backlight_init(dev);
949 if (result)
950 goto fail_backlight;
951 } else
952 printk(EEEPC_INFO "Backlight controlled by ACPI video "
953 "driver\n");
954
e1faa9da
CC
955 result = eeepc_hwmon_init(dev);
956 if (result)
957 goto fail_hwmon;
e59f8796
EC
958 /* Register platform stuff */
959 result = platform_driver_register(&platform_driver);
960 if (result)
961 goto fail_platform_driver;
962 platform_device = platform_device_alloc(EEEPC_HOTK_FILE, -1);
963 if (!platform_device) {
964 result = -ENOMEM;
965 goto fail_platform_device1;
966 }
967 result = platform_device_add(platform_device);
968 if (result)
969 goto fail_platform_device2;
970 result = sysfs_create_group(&platform_device->dev.kobj,
971 &platform_attribute_group);
972 if (result)
973 goto fail_sysfs;
974 return 0;
975fail_sysfs:
976 platform_device_del(platform_device);
977fail_platform_device2:
978 platform_device_put(platform_device);
979fail_platform_device1:
980 platform_driver_unregister(&platform_driver);
981fail_platform_driver:
e1faa9da
CC
982 eeepc_hwmon_exit();
983fail_hwmon:
a5fa429b
CC
984 eeepc_backlight_exit();
985fail_backlight:
a9df80c5
CC
986 eeepc_input_exit();
987 eeepc_rfkill_exit();
e59f8796
EC
988 return result;
989}
990
991module_init(eeepc_laptop_init);
992module_exit(eeepc_laptop_exit);
This page took 0.171139 seconds and 5 git commands to generate.