eeepc-laptop: Work around rfkill firmware bug
[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
302static int eeepc_wlan_rfkill_set(void *data, enum rfkill_state state)
303{
304 if (state == RFKILL_STATE_SOFT_BLOCKED)
305 return set_acpi(CM_ASL_WLAN, 0);
306 else
307 return set_acpi(CM_ASL_WLAN, 1);
308}
309
310static int eeepc_wlan_rfkill_state(void *data, enum rfkill_state *state)
311{
312 if (get_acpi(CM_ASL_WLAN) == 1)
313 *state = RFKILL_STATE_UNBLOCKED;
314 else
315 *state = RFKILL_STATE_SOFT_BLOCKED;
316 return 0;
317}
318
319static int eeepc_bluetooth_rfkill_set(void *data, enum rfkill_state state)
320{
321 if (state == RFKILL_STATE_SOFT_BLOCKED)
322 return set_acpi(CM_ASL_BLUETOOTH, 0);
323 else
324 return set_acpi(CM_ASL_BLUETOOTH, 1);
325}
326
327static int eeepc_bluetooth_rfkill_state(void *data, enum rfkill_state *state)
328{
329 if (get_acpi(CM_ASL_BLUETOOTH) == 1)
330 *state = RFKILL_STATE_UNBLOCKED;
331 else
332 *state = RFKILL_STATE_SOFT_BLOCKED;
333 return 0;
334}
335
e59f8796
EC
336/*
337 * Sys helpers
338 */
339static int parse_arg(const char *buf, unsigned long count, int *val)
340{
341 if (!count)
342 return 0;
343 if (sscanf(buf, "%i", val) != 1)
344 return -EINVAL;
345 return count;
346}
347
348static ssize_t store_sys_acpi(int cm, const char *buf, size_t count)
349{
350 int rv, value;
351
352 rv = parse_arg(buf, count, &value);
353 if (rv > 0)
354 set_acpi(cm, value);
355 return rv;
356}
357
358static ssize_t show_sys_acpi(int cm, char *buf)
359{
360 return sprintf(buf, "%d\n", get_acpi(cm));
361}
362
363#define EEEPC_CREATE_DEVICE_ATTR(_name, _cm) \
364 static ssize_t show_##_name(struct device *dev, \
365 struct device_attribute *attr, \
366 char *buf) \
367 { \
368 return show_sys_acpi(_cm, buf); \
369 } \
370 static ssize_t store_##_name(struct device *dev, \
371 struct device_attribute *attr, \
372 const char *buf, size_t count) \
373 { \
374 return store_sys_acpi(_cm, buf, count); \
375 } \
376 static struct device_attribute dev_attr_##_name = { \
377 .attr = { \
378 .name = __stringify(_name), \
379 .mode = 0644 }, \
380 .show = show_##_name, \
381 .store = store_##_name, \
382 }
383
384EEEPC_CREATE_DEVICE_ATTR(camera, CM_ASL_CAMERA);
385EEEPC_CREATE_DEVICE_ATTR(cardr, CM_ASL_CARDREADER);
386EEEPC_CREATE_DEVICE_ATTR(disp, CM_ASL_DISPLAYSWITCH);
e59f8796
EC
387
388static struct attribute *platform_attributes[] = {
389 &dev_attr_camera.attr,
390 &dev_attr_cardr.attr,
391 &dev_attr_disp.attr,
e59f8796
EC
392 NULL
393};
394
395static struct attribute_group platform_attribute_group = {
396 .attrs = platform_attributes
397};
398
399/*
400 * Hotkey functions
401 */
a195dcdc
MG
402static struct key_entry *eepc_get_entry_by_scancode(int code)
403{
404 struct key_entry *key;
405
406 for (key = eeepc_keymap; key->type != KE_END; key++)
407 if (code == key->code)
408 return key;
409
410 return NULL;
411}
412
413static struct key_entry *eepc_get_entry_by_keycode(int code)
414{
415 struct key_entry *key;
416
417 for (key = eeepc_keymap; key->type != KE_END; key++)
418 if (code == key->keycode && key->type == KE_KEY)
419 return key;
420
421 return NULL;
422}
423
424static int eeepc_getkeycode(struct input_dev *dev, int scancode, int *keycode)
425{
426 struct key_entry *key = eepc_get_entry_by_scancode(scancode);
427
428 if (key && key->type == KE_KEY) {
429 *keycode = key->keycode;
430 return 0;
431 }
432
433 return -EINVAL;
434}
435
436static int eeepc_setkeycode(struct input_dev *dev, int scancode, int keycode)
437{
438 struct key_entry *key;
439 int old_keycode;
440
441 if (keycode < 0 || keycode > KEY_MAX)
442 return -EINVAL;
443
444 key = eepc_get_entry_by_scancode(scancode);
445 if (key && key->type == KE_KEY) {
446 old_keycode = key->keycode;
447 key->keycode = keycode;
448 set_bit(keycode, dev->keybit);
449 if (!eepc_get_entry_by_keycode(old_keycode))
450 clear_bit(old_keycode, dev->keybit);
451 return 0;
452 }
453
454 return -EINVAL;
455}
456
e59f8796
EC
457static int eeepc_hotk_check(void)
458{
a195dcdc 459 const struct key_entry *key;
e59f8796
EC
460 struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
461 int result;
462
463 result = acpi_bus_get_status(ehotk->device);
464 if (result)
465 return result;
466 if (ehotk->device->status.present) {
467 if (write_acpi_int(ehotk->handle, "INIT", ehotk->init_flag,
468 &buffer)) {
469 printk(EEEPC_ERR "Hotkey initialization failed\n");
470 return -ENODEV;
471 } else {
472 printk(EEEPC_NOTICE "Hotkey init flags 0x%x\n",
473 ehotk->init_flag);
474 }
475 /* get control methods supported */
476 if (read_acpi_int(ehotk->handle, "CMSG"
477 , &ehotk->cm_supported)) {
478 printk(EEEPC_ERR
479 "Get control methods supported failed\n");
480 return -ENODEV;
481 } else {
482 printk(EEEPC_INFO
483 "Get control methods supported: 0x%x\n",
484 ehotk->cm_supported);
485 }
a195dcdc
MG
486 ehotk->inputdev = input_allocate_device();
487 if (!ehotk->inputdev) {
488 printk(EEEPC_INFO "Unable to allocate input device\n");
489 return 0;
490 }
491 ehotk->inputdev->name = "Asus EeePC extra buttons";
492 ehotk->inputdev->phys = EEEPC_HOTK_FILE "/input0";
493 ehotk->inputdev->id.bustype = BUS_HOST;
494 ehotk->inputdev->getkeycode = eeepc_getkeycode;
495 ehotk->inputdev->setkeycode = eeepc_setkeycode;
496
497 for (key = eeepc_keymap; key->type != KE_END; key++) {
498 switch (key->type) {
499 case KE_KEY:
500 set_bit(EV_KEY, ehotk->inputdev->evbit);
501 set_bit(key->keycode, ehotk->inputdev->keybit);
502 break;
503 }
504 }
505 result = input_register_device(ehotk->inputdev);
506 if (result) {
507 printk(EEEPC_INFO "Unable to register input device\n");
508 input_free_device(ehotk->inputdev);
509 return 0;
510 }
e59f8796
EC
511 } else {
512 printk(EEEPC_ERR "Hotkey device not present, aborting\n");
513 return -EINVAL;
514 }
515 return 0;
516}
517
64b86b65 518static int notify_brn(void)
a5fa429b 519{
64b86b65 520 /* returns the *previous* brightness, or -1 */
a5fa429b 521 struct backlight_device *bd = eeepc_backlight_device;
64b86b65
DS
522 if (bd) {
523 int old = bd->props.brightness;
7695fb04 524 bd->props.brightness = read_brightness(bd);
64b86b65
DS
525 return old;
526 }
527 return -1;
a5fa429b
CC
528}
529
5740294c
MG
530static void eeepc_rfkill_notify(acpi_handle handle, u32 event, void *data)
531{
978605c4 532 enum rfkill_state state;
5740294c
MG
533 struct pci_dev *dev;
534 struct pci_bus *bus = pci_find_bus(0, 1);
535
536 if (event != ACPI_NOTIFY_BUS_CHECK)
537 return;
538
539 if (!bus) {
540 printk(EEEPC_WARNING "Unable to find PCI bus 1?\n");
541 return;
542 }
543
978605c4
AJ
544 eeepc_wlan_rfkill_state(ehotk->eeepc_wlan_rfkill, &state);
545
546 if (state == RFKILL_STATE_UNBLOCKED) {
5740294c
MG
547 dev = pci_get_slot(bus, 0);
548 if (dev) {
549 /* Device already present */
550 pci_dev_put(dev);
551 return;
552 }
553 dev = pci_scan_single_device(bus, 0);
554 if (dev) {
555 pci_bus_assign_resources(bus);
556 if (pci_bus_add_device(dev))
557 printk(EEEPC_ERR "Unable to hotplug wifi\n");
558 }
559 } else {
560 dev = pci_get_slot(bus, 0);
561 if (dev) {
562 pci_remove_bus_device(dev);
563 pci_dev_put(dev);
564 }
565 }
978605c4
AJ
566
567 rfkill_force_state(ehotk->eeepc_wlan_rfkill, state);
5740294c
MG
568}
569
e59f8796
EC
570static void eeepc_hotk_notify(acpi_handle handle, u32 event, void *data)
571{
a195dcdc 572 static struct key_entry *key;
7950b71c 573 u16 count;
64b86b65 574 int brn = -ENODEV;
7950b71c 575
e59f8796
EC
576 if (!ehotk)
577 return;
a5fa429b 578 if (event >= NOTIFY_BRN_MIN && event <= NOTIFY_BRN_MAX)
64b86b65 579 brn = notify_brn();
7950b71c
CC
580 count = ehotk->event_count[event % 128]++;
581 acpi_bus_generate_proc_event(ehotk->device, event, count);
2b25c9f0
CC
582 acpi_bus_generate_netlink_event(ehotk->device->pnp.device_class,
583 dev_name(&ehotk->device->dev), event,
7950b71c 584 count);
a195dcdc 585 if (ehotk->inputdev) {
64b86b65
DS
586 if (brn != -ENODEV) {
587 /* brightness-change events need special
588 * handling for conversion to key events
589 */
590 if (brn < 0)
591 brn = event;
592 else
593 brn += NOTIFY_BRN_MIN;
594 if (event < brn)
595 event = NOTIFY_BRN_MIN; /* brightness down */
596 else if (event > brn)
597 event = NOTIFY_BRN_MIN + 2; /* ... up */
598 else
599 event = NOTIFY_BRN_MIN + 1; /* ... unchanged */
600 }
a195dcdc
MG
601 key = eepc_get_entry_by_scancode(event);
602 if (key) {
603 switch (key->type) {
604 case KE_KEY:
605 input_report_key(ehotk->inputdev, key->keycode,
606 1);
607 input_sync(ehotk->inputdev);
608 input_report_key(ehotk->inputdev, key->keycode,
609 0);
610 input_sync(ehotk->inputdev);
611 break;
612 }
613 }
614 }
e59f8796
EC
615}
616
5740294c
MG
617static int eeepc_register_rfkill_notifier(char *node)
618{
619 acpi_status status = AE_OK;
620 acpi_handle handle;
621
622 status = acpi_get_handle(NULL, node, &handle);
623
624 if (ACPI_SUCCESS(status)) {
625 status = acpi_install_notify_handler(handle,
626 ACPI_SYSTEM_NOTIFY,
627 eeepc_rfkill_notify,
628 NULL);
629 if (ACPI_FAILURE(status))
630 printk(EEEPC_WARNING
631 "Failed to register notify on %s\n", node);
632 } else
633 return -ENODEV;
634
635 return 0;
636}
637
638static void eeepc_unregister_rfkill_notifier(char *node)
639{
640 acpi_status status = AE_OK;
641 acpi_handle handle;
642
643 status = acpi_get_handle(NULL, node, &handle);
644
645 if (ACPI_SUCCESS(status)) {
646 status = acpi_remove_notify_handler(handle,
647 ACPI_SYSTEM_NOTIFY,
648 eeepc_rfkill_notify);
649 if (ACPI_FAILURE(status))
650 printk(EEEPC_ERR
651 "Error removing rfkill notify handler %s\n",
652 node);
653 }
654}
655
e59f8796
EC
656static int eeepc_hotk_add(struct acpi_device *device)
657{
658 acpi_status status = AE_OK;
659 int result;
660
661 if (!device)
662 return -EINVAL;
663 printk(EEEPC_NOTICE EEEPC_HOTK_NAME "\n");
664 ehotk = kzalloc(sizeof(struct eeepc_hotk), GFP_KERNEL);
665 if (!ehotk)
666 return -ENOMEM;
667 ehotk->init_flag = DISABLE_ASL_WLAN | DISABLE_ASL_DISPLAYSWITCH;
668 ehotk->handle = device->handle;
669 strcpy(acpi_device_name(device), EEEPC_HOTK_DEVICE_NAME);
670 strcpy(acpi_device_class(device), EEEPC_HOTK_CLASS);
db89b4f0 671 device->driver_data = ehotk;
e59f8796
EC
672 ehotk->device = device;
673 result = eeepc_hotk_check();
674 if (result)
c9ddf8fe 675 goto ehotk_fail;
e59f8796
EC
676 status = acpi_install_notify_handler(ehotk->handle, ACPI_SYSTEM_NOTIFY,
677 eeepc_hotk_notify, ehotk);
678 if (ACPI_FAILURE(status))
679 printk(EEEPC_ERR "Error installing notify handler\n");
a195dcdc 680
fbc97e4c
AJ
681 eeepc_register_rfkill_notifier("\\_SB.PCI0.P0P6");
682 eeepc_register_rfkill_notifier("\\_SB.PCI0.P0P7");
683
a195dcdc
MG
684 if (get_acpi(CM_ASL_WLAN) != -1) {
685 ehotk->eeepc_wlan_rfkill = rfkill_allocate(&device->dev,
686 RFKILL_TYPE_WLAN);
687
688 if (!ehotk->eeepc_wlan_rfkill)
c9ddf8fe 689 goto wlan_fail;
a195dcdc
MG
690
691 ehotk->eeepc_wlan_rfkill->name = "eeepc-wlan";
692 ehotk->eeepc_wlan_rfkill->toggle_radio = eeepc_wlan_rfkill_set;
693 ehotk->eeepc_wlan_rfkill->get_state = eeepc_wlan_rfkill_state;
c9ddf8fe 694 if (get_acpi(CM_ASL_WLAN) == 1) {
a195dcdc
MG
695 ehotk->eeepc_wlan_rfkill->state =
696 RFKILL_STATE_UNBLOCKED;
c9ddf8fe
MG
697 rfkill_set_default(RFKILL_TYPE_WLAN,
698 RFKILL_STATE_UNBLOCKED);
699 } else {
a195dcdc
MG
700 ehotk->eeepc_wlan_rfkill->state =
701 RFKILL_STATE_SOFT_BLOCKED;
c9ddf8fe
MG
702 rfkill_set_default(RFKILL_TYPE_WLAN,
703 RFKILL_STATE_SOFT_BLOCKED);
704 }
705 result = rfkill_register(ehotk->eeepc_wlan_rfkill);
706 if (result)
707 goto wlan_fail;
a195dcdc
MG
708 }
709
710 if (get_acpi(CM_ASL_BLUETOOTH) != -1) {
711 ehotk->eeepc_bluetooth_rfkill =
712 rfkill_allocate(&device->dev, RFKILL_TYPE_BLUETOOTH);
713
714 if (!ehotk->eeepc_bluetooth_rfkill)
c9ddf8fe 715 goto bluetooth_fail;
a195dcdc
MG
716
717 ehotk->eeepc_bluetooth_rfkill->name = "eeepc-bluetooth";
718 ehotk->eeepc_bluetooth_rfkill->toggle_radio =
719 eeepc_bluetooth_rfkill_set;
720 ehotk->eeepc_bluetooth_rfkill->get_state =
721 eeepc_bluetooth_rfkill_state;
c9ddf8fe 722 if (get_acpi(CM_ASL_BLUETOOTH) == 1) {
a195dcdc
MG
723 ehotk->eeepc_bluetooth_rfkill->state =
724 RFKILL_STATE_UNBLOCKED;
c9ddf8fe
MG
725 rfkill_set_default(RFKILL_TYPE_BLUETOOTH,
726 RFKILL_STATE_UNBLOCKED);
727 } else {
a195dcdc
MG
728 ehotk->eeepc_bluetooth_rfkill->state =
729 RFKILL_STATE_SOFT_BLOCKED;
c9ddf8fe
MG
730 rfkill_set_default(RFKILL_TYPE_BLUETOOTH,
731 RFKILL_STATE_SOFT_BLOCKED);
732 }
a195dcdc 733
c9ddf8fe
MG
734 result = rfkill_register(ehotk->eeepc_bluetooth_rfkill);
735 if (result)
736 goto bluetooth_fail;
e59f8796 737 }
5740294c 738
c9ddf8fe
MG
739 return 0;
740
741 bluetooth_fail:
742 if (ehotk->eeepc_bluetooth_rfkill)
743 rfkill_free(ehotk->eeepc_bluetooth_rfkill);
744 rfkill_unregister(ehotk->eeepc_wlan_rfkill);
745 ehotk->eeepc_wlan_rfkill = NULL;
746 wlan_fail:
747 if (ehotk->eeepc_wlan_rfkill)
748 rfkill_free(ehotk->eeepc_wlan_rfkill);
749 ehotk_fail:
750 kfree(ehotk);
751 ehotk = NULL;
752
e59f8796
EC
753 return result;
754}
755
756static int eeepc_hotk_remove(struct acpi_device *device, int type)
757{
758 acpi_status status = 0;
759
760 if (!device || !acpi_driver_data(device))
761 return -EINVAL;
762 status = acpi_remove_notify_handler(ehotk->handle, ACPI_SYSTEM_NOTIFY,
763 eeepc_hotk_notify);
764 if (ACPI_FAILURE(status))
765 printk(EEEPC_ERR "Error removing notify handler\n");
5740294c
MG
766
767 eeepc_unregister_rfkill_notifier("\\_SB.PCI0.P0P6");
768 eeepc_unregister_rfkill_notifier("\\_SB.PCI0.P0P7");
769
e59f8796
EC
770 kfree(ehotk);
771 return 0;
772}
773
e1faa9da
CC
774/*
775 * Hwmon
776 */
777static int eeepc_get_fan_pwm(void)
778{
779 int value = 0;
780
781 read_acpi_int(NULL, EEEPC_EC_FAN_PWM, &value);
04dcd84b 782 value = value * 255 / 100;
e1faa9da
CC
783 return (value);
784}
785
786static void eeepc_set_fan_pwm(int value)
787{
04dcd84b
CC
788 value = SENSORS_LIMIT(value, 0, 255);
789 value = value * 100 / 255;
e1faa9da
CC
790 ec_write(EEEPC_EC_SC02, value);
791}
792
793static int eeepc_get_fan_rpm(void)
794{
795 int high = 0;
796 int low = 0;
797
798 read_acpi_int(NULL, EEEPC_EC_FAN_HRPM, &high);
799 read_acpi_int(NULL, EEEPC_EC_FAN_LRPM, &low);
800 return (high << 8 | low);
801}
802
803static int eeepc_get_fan_ctrl(void)
804{
805 int value = 0;
806
807 read_acpi_int(NULL, EEEPC_EC_FAN_CTRL, &value);
808 return ((value & 0x02 ? 1 : 0));
809}
810
811static void eeepc_set_fan_ctrl(int manual)
812{
813 int value = 0;
814
815 read_acpi_int(NULL, EEEPC_EC_FAN_CTRL, &value);
816 if (manual)
817 value |= 0x02;
818 else
819 value &= ~0x02;
820 ec_write(EEEPC_EC_SFB3, value);
821}
822
823static ssize_t store_sys_hwmon(void (*set)(int), const char *buf, size_t count)
824{
825 int rv, value;
826
827 rv = parse_arg(buf, count, &value);
828 if (rv > 0)
829 set(value);
830 return rv;
831}
832
833static ssize_t show_sys_hwmon(int (*get)(void), char *buf)
834{
835 return sprintf(buf, "%d\n", get());
836}
837
838#define EEEPC_CREATE_SENSOR_ATTR(_name, _mode, _set, _get) \
839 static ssize_t show_##_name(struct device *dev, \
840 struct device_attribute *attr, \
841 char *buf) \
842 { \
843 return show_sys_hwmon(_set, buf); \
844 } \
845 static ssize_t store_##_name(struct device *dev, \
846 struct device_attribute *attr, \
847 const char *buf, size_t count) \
848 { \
849 return store_sys_hwmon(_get, buf, count); \
850 } \
851 static SENSOR_DEVICE_ATTR(_name, _mode, show_##_name, store_##_name, 0);
852
853EEEPC_CREATE_SENSOR_ATTR(fan1_input, S_IRUGO, eeepc_get_fan_rpm, NULL);
04dcd84b 854EEEPC_CREATE_SENSOR_ATTR(pwm1, S_IRUGO | S_IWUSR,
e1faa9da
CC
855 eeepc_get_fan_pwm, eeepc_set_fan_pwm);
856EEEPC_CREATE_SENSOR_ATTR(pwm1_enable, S_IRUGO | S_IWUSR,
857 eeepc_get_fan_ctrl, eeepc_set_fan_ctrl);
858
04dcd84b
CC
859static ssize_t
860show_name(struct device *dev, struct device_attribute *attr, char *buf)
861{
862 return sprintf(buf, "eeepc\n");
863}
864static SENSOR_DEVICE_ATTR(name, S_IRUGO, show_name, NULL, 0);
865
e1faa9da 866static struct attribute *hwmon_attributes[] = {
04dcd84b 867 &sensor_dev_attr_pwm1.dev_attr.attr,
e1faa9da
CC
868 &sensor_dev_attr_fan1_input.dev_attr.attr,
869 &sensor_dev_attr_pwm1_enable.dev_attr.attr,
04dcd84b 870 &sensor_dev_attr_name.dev_attr.attr,
e1faa9da
CC
871 NULL
872};
873
874static struct attribute_group hwmon_attribute_group = {
875 .attrs = hwmon_attributes
876};
877
e59f8796
EC
878/*
879 * exit/init
880 */
a5fa429b
CC
881static void eeepc_backlight_exit(void)
882{
883 if (eeepc_backlight_device)
884 backlight_device_unregister(eeepc_backlight_device);
a9df80c5
CC
885 eeepc_backlight_device = NULL;
886}
887
888static void eeepc_rfkill_exit(void)
889{
a195dcdc
MG
890 if (ehotk->eeepc_wlan_rfkill)
891 rfkill_unregister(ehotk->eeepc_wlan_rfkill);
892 if (ehotk->eeepc_bluetooth_rfkill)
893 rfkill_unregister(ehotk->eeepc_bluetooth_rfkill);
a9df80c5
CC
894}
895
896static void eeepc_input_exit(void)
897{
898 if (ehotk->inputdev)
899 input_unregister_device(ehotk->inputdev);
a5fa429b
CC
900}
901
e1faa9da
CC
902static void eeepc_hwmon_exit(void)
903{
904 struct device *hwmon;
905
906 hwmon = eeepc_hwmon_device;
907 if (!hwmon)
908 return ;
e1faa9da
CC
909 sysfs_remove_group(&hwmon->kobj,
910 &hwmon_attribute_group);
f1441318 911 hwmon_device_unregister(hwmon);
e1faa9da
CC
912 eeepc_hwmon_device = NULL;
913}
914
e59f8796
EC
915static void __exit eeepc_laptop_exit(void)
916{
a5fa429b 917 eeepc_backlight_exit();
a9df80c5
CC
918 eeepc_rfkill_exit();
919 eeepc_input_exit();
e1faa9da 920 eeepc_hwmon_exit();
e59f8796
EC
921 acpi_bus_unregister_driver(&eeepc_hotk_driver);
922 sysfs_remove_group(&platform_device->dev.kobj,
923 &platform_attribute_group);
924 platform_device_unregister(platform_device);
925 platform_driver_unregister(&platform_driver);
926}
927
a5fa429b
CC
928static int eeepc_backlight_init(struct device *dev)
929{
930 struct backlight_device *bd;
931
932 bd = backlight_device_register(EEEPC_HOTK_FILE, dev,
933 NULL, &eeepcbl_ops);
934 if (IS_ERR(bd)) {
935 printk(EEEPC_ERR
936 "Could not register eeepc backlight device\n");
937 eeepc_backlight_device = NULL;
938 return PTR_ERR(bd);
939 }
940 eeepc_backlight_device = bd;
941 bd->props.max_brightness = 15;
942 bd->props.brightness = read_brightness(NULL);
943 bd->props.power = FB_BLANK_UNBLANK;
944 backlight_update_status(bd);
945 return 0;
946}
947
e1faa9da
CC
948static int eeepc_hwmon_init(struct device *dev)
949{
950 struct device *hwmon;
951 int result;
952
953 hwmon = hwmon_device_register(dev);
954 if (IS_ERR(hwmon)) {
955 printk(EEEPC_ERR
956 "Could not register eeepc hwmon device\n");
957 eeepc_hwmon_device = NULL;
958 return PTR_ERR(hwmon);
959 }
960 eeepc_hwmon_device = hwmon;
961 result = sysfs_create_group(&hwmon->kobj,
962 &hwmon_attribute_group);
963 if (result)
964 eeepc_hwmon_exit();
965 return result;
966}
967
e59f8796
EC
968static int __init eeepc_laptop_init(void)
969{
970 struct device *dev;
971 int result;
972
973 if (acpi_disabled)
974 return -ENODEV;
975 result = acpi_bus_register_driver(&eeepc_hotk_driver);
976 if (result < 0)
977 return result;
978 if (!ehotk) {
979 acpi_bus_unregister_driver(&eeepc_hotk_driver);
980 return -ENODEV;
981 }
982 dev = acpi_get_physical_device(ehotk->device->handle);
a2bf8c01
TR
983
984 if (!acpi_video_backlight_support()) {
985 result = eeepc_backlight_init(dev);
986 if (result)
987 goto fail_backlight;
988 } else
989 printk(EEEPC_INFO "Backlight controlled by ACPI video "
990 "driver\n");
991
e1faa9da
CC
992 result = eeepc_hwmon_init(dev);
993 if (result)
994 goto fail_hwmon;
e59f8796
EC
995 /* Register platform stuff */
996 result = platform_driver_register(&platform_driver);
997 if (result)
998 goto fail_platform_driver;
999 platform_device = platform_device_alloc(EEEPC_HOTK_FILE, -1);
1000 if (!platform_device) {
1001 result = -ENOMEM;
1002 goto fail_platform_device1;
1003 }
1004 result = platform_device_add(platform_device);
1005 if (result)
1006 goto fail_platform_device2;
1007 result = sysfs_create_group(&platform_device->dev.kobj,
1008 &platform_attribute_group);
1009 if (result)
1010 goto fail_sysfs;
1011 return 0;
1012fail_sysfs:
1013 platform_device_del(platform_device);
1014fail_platform_device2:
1015 platform_device_put(platform_device);
1016fail_platform_device1:
1017 platform_driver_unregister(&platform_driver);
1018fail_platform_driver:
e1faa9da
CC
1019 eeepc_hwmon_exit();
1020fail_hwmon:
a5fa429b
CC
1021 eeepc_backlight_exit();
1022fail_backlight:
a9df80c5
CC
1023 eeepc_input_exit();
1024 eeepc_rfkill_exit();
e59f8796
EC
1025 return result;
1026}
1027
1028module_init(eeepc_laptop_init);
1029module_exit(eeepc_laptop_exit);
This page took 0.242051 seconds and 5 git commands to generate.