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