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