asus_acpi: Deprecate in favor of asus-laptop
[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);
96e9cfeb 183static int eeepc_hotk_resume(struct acpi_device *device);
d9b9bd7b 184static void eeepc_hotk_notify(struct acpi_device *device, u32 event);
e59f8796
EC
185
186static const struct acpi_device_id eeepc_device_ids[] = {
187 {EEEPC_HOTK_HID, 0},
188 {"", 0},
189};
190MODULE_DEVICE_TABLE(acpi, eeepc_device_ids);
191
192static struct acpi_driver eeepc_hotk_driver = {
193 .name = EEEPC_HOTK_NAME,
194 .class = EEEPC_HOTK_CLASS,
195 .ids = eeepc_device_ids,
d9b9bd7b 196 .flags = ACPI_DRIVER_ALL_NOTIFY_EVENTS,
e59f8796
EC
197 .ops = {
198 .add = eeepc_hotk_add,
199 .remove = eeepc_hotk_remove,
96e9cfeb 200 .resume = eeepc_hotk_resume,
d9b9bd7b 201 .notify = eeepc_hotk_notify,
e59f8796
EC
202 },
203};
204
a5fa429b
CC
205/* The backlight device /sys/class/backlight */
206static struct backlight_device *eeepc_backlight_device;
207
e1faa9da
CC
208/* The hwmon device */
209static struct device *eeepc_hwmon_device;
210
a5fa429b
CC
211/*
212 * The backlight class declaration
213 */
214static int read_brightness(struct backlight_device *bd);
215static int update_bl_status(struct backlight_device *bd);
216static struct backlight_ops eeepcbl_ops = {
217 .get_brightness = read_brightness,
218 .update_status = update_bl_status,
219};
220
e59f8796
EC
221MODULE_AUTHOR("Corentin Chary, Eric Cooper");
222MODULE_DESCRIPTION(EEEPC_HOTK_NAME);
223MODULE_LICENSE("GPL");
224
225/*
226 * ACPI Helpers
227 */
228static int write_acpi_int(acpi_handle handle, const char *method, int val,
229 struct acpi_buffer *output)
230{
231 struct acpi_object_list params;
232 union acpi_object in_obj;
233 acpi_status status;
234
235 params.count = 1;
236 params.pointer = &in_obj;
237 in_obj.type = ACPI_TYPE_INTEGER;
238 in_obj.integer.value = val;
239
240 status = acpi_evaluate_object(handle, (char *)method, &params, output);
241 return (status == AE_OK ? 0 : -1);
242}
243
244static int read_acpi_int(acpi_handle handle, const char *method, int *val)
245{
246 acpi_status status;
27663c58 247 unsigned long long result;
e59f8796
EC
248
249 status = acpi_evaluate_integer(handle, (char *)method, NULL, &result);
250 if (ACPI_FAILURE(status)) {
251 *val = -1;
252 return -1;
253 } else {
254 *val = result;
255 return 0;
256 }
257}
258
259static int set_acpi(int cm, int value)
260{
261 if (ehotk->cm_supported & (0x1 << cm)) {
262 const char *method = cm_setv[cm];
263 if (method == NULL)
264 return -ENODEV;
265 if (write_acpi_int(ehotk->handle, method, value, NULL))
266 printk(EEEPC_WARNING "Error writing %s\n", method);
267 }
268 return 0;
269}
270
271static int get_acpi(int cm)
272{
273 int value = -1;
274 if ((ehotk->cm_supported & (0x1 << cm))) {
275 const char *method = cm_getv[cm];
276 if (method == NULL)
277 return -ENODEV;
278 if (read_acpi_int(ehotk->handle, method, &value))
279 printk(EEEPC_WARNING "Error reading %s\n", method);
280 }
281 return value;
282}
283
a5fa429b
CC
284/*
285 * Backlight
286 */
287static int read_brightness(struct backlight_device *bd)
288{
289 return get_acpi(CM_ASL_PANELBRIGHT);
290}
291
292static int set_brightness(struct backlight_device *bd, int value)
293{
294 value = max(0, min(15, value));
295 return set_acpi(CM_ASL_PANELBRIGHT, value);
296}
297
298static int update_bl_status(struct backlight_device *bd)
299{
300 return set_brightness(bd, bd->props.brightness);
301}
302
a195dcdc
MG
303/*
304 * Rfkill helpers
305 */
306
19d337df 307static bool eeepc_wlan_rfkill_blocked(void)
a195dcdc
MG
308{
309 if (get_acpi(CM_ASL_WLAN) == 1)
19d337df
JB
310 return false;
311 return true;
a195dcdc
MG
312}
313
19d337df 314static int eeepc_rfkill_set(void *data, bool blocked)
a195dcdc 315{
19d337df
JB
316 unsigned long asl = (unsigned long)data;
317 return set_acpi(asl, !blocked);
a195dcdc
MG
318}
319
19d337df
JB
320static const struct rfkill_ops eeepc_rfkill_ops = {
321 .set_block = eeepc_rfkill_set,
322};
a195dcdc 323
cede2cb6
PE
324static void __init eeepc_enable_camera(void)
325{
326 /*
327 * If the following call to set_acpi() fails, it's because there's no
328 * camera so we can ignore the error.
329 */
330 set_acpi(CM_ASL_CAMERA, 1);
331}
332
e59f8796
EC
333/*
334 * Sys helpers
335 */
336static int parse_arg(const char *buf, unsigned long count, int *val)
337{
338 if (!count)
339 return 0;
340 if (sscanf(buf, "%i", val) != 1)
341 return -EINVAL;
342 return count;
343}
344
345static ssize_t store_sys_acpi(int cm, const char *buf, size_t count)
346{
347 int rv, value;
348
349 rv = parse_arg(buf, count, &value);
350 if (rv > 0)
351 set_acpi(cm, value);
352 return rv;
353}
354
355static ssize_t show_sys_acpi(int cm, char *buf)
356{
357 return sprintf(buf, "%d\n", get_acpi(cm));
358}
359
360#define EEEPC_CREATE_DEVICE_ATTR(_name, _cm) \
361 static ssize_t show_##_name(struct device *dev, \
362 struct device_attribute *attr, \
363 char *buf) \
364 { \
365 return show_sys_acpi(_cm, buf); \
366 } \
367 static ssize_t store_##_name(struct device *dev, \
368 struct device_attribute *attr, \
369 const char *buf, size_t count) \
370 { \
371 return store_sys_acpi(_cm, buf, count); \
372 } \
373 static struct device_attribute dev_attr_##_name = { \
374 .attr = { \
375 .name = __stringify(_name), \
376 .mode = 0644 }, \
377 .show = show_##_name, \
378 .store = store_##_name, \
379 }
380
381EEEPC_CREATE_DEVICE_ATTR(camera, CM_ASL_CAMERA);
382EEEPC_CREATE_DEVICE_ATTR(cardr, CM_ASL_CARDREADER);
383EEEPC_CREATE_DEVICE_ATTR(disp, CM_ASL_DISPLAYSWITCH);
158ca1d7 384EEEPC_CREATE_DEVICE_ATTR(cpufv, CM_ASL_CPUFV);
e59f8796
EC
385
386static struct attribute *platform_attributes[] = {
387 &dev_attr_camera.attr,
388 &dev_attr_cardr.attr,
389 &dev_attr_disp.attr,
158ca1d7 390 &dev_attr_cpufv.attr,
e59f8796
EC
391 NULL
392};
393
394static struct attribute_group platform_attribute_group = {
395 .attrs = platform_attributes
396};
397
398/*
399 * Hotkey functions
400 */
a195dcdc
MG
401static struct key_entry *eepc_get_entry_by_scancode(int code)
402{
403 struct key_entry *key;
404
405 for (key = eeepc_keymap; key->type != KE_END; key++)
406 if (code == key->code)
407 return key;
408
409 return NULL;
410}
411
412static struct key_entry *eepc_get_entry_by_keycode(int code)
413{
414 struct key_entry *key;
415
416 for (key = eeepc_keymap; key->type != KE_END; key++)
417 if (code == key->keycode && key->type == KE_KEY)
418 return key;
419
420 return NULL;
421}
422
423static int eeepc_getkeycode(struct input_dev *dev, int scancode, int *keycode)
424{
425 struct key_entry *key = eepc_get_entry_by_scancode(scancode);
426
427 if (key && key->type == KE_KEY) {
428 *keycode = key->keycode;
429 return 0;
430 }
431
432 return -EINVAL;
433}
434
435static int eeepc_setkeycode(struct input_dev *dev, int scancode, int keycode)
436{
437 struct key_entry *key;
438 int old_keycode;
439
440 if (keycode < 0 || keycode > KEY_MAX)
441 return -EINVAL;
442
443 key = eepc_get_entry_by_scancode(scancode);
444 if (key && key->type == KE_KEY) {
445 old_keycode = key->keycode;
446 key->keycode = keycode;
447 set_bit(keycode, dev->keybit);
448 if (!eepc_get_entry_by_keycode(old_keycode))
449 clear_bit(old_keycode, dev->keybit);
450 return 0;
451 }
452
453 return -EINVAL;
454}
455
e59f8796
EC
456static int eeepc_hotk_check(void)
457{
a195dcdc 458 const struct key_entry *key;
e59f8796
EC
459 struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
460 int result;
461
462 result = acpi_bus_get_status(ehotk->device);
463 if (result)
464 return result;
465 if (ehotk->device->status.present) {
466 if (write_acpi_int(ehotk->handle, "INIT", ehotk->init_flag,
467 &buffer)) {
468 printk(EEEPC_ERR "Hotkey initialization failed\n");
469 return -ENODEV;
470 } else {
471 printk(EEEPC_NOTICE "Hotkey init flags 0x%x\n",
472 ehotk->init_flag);
473 }
474 /* get control methods supported */
475 if (read_acpi_int(ehotk->handle, "CMSG"
476 , &ehotk->cm_supported)) {
477 printk(EEEPC_ERR
478 "Get control methods supported failed\n");
479 return -ENODEV;
480 } else {
481 printk(EEEPC_INFO
482 "Get control methods supported: 0x%x\n",
483 ehotk->cm_supported);
484 }
a195dcdc
MG
485 ehotk->inputdev = input_allocate_device();
486 if (!ehotk->inputdev) {
487 printk(EEEPC_INFO "Unable to allocate input device\n");
488 return 0;
489 }
490 ehotk->inputdev->name = "Asus EeePC extra buttons";
491 ehotk->inputdev->phys = EEEPC_HOTK_FILE "/input0";
492 ehotk->inputdev->id.bustype = BUS_HOST;
493 ehotk->inputdev->getkeycode = eeepc_getkeycode;
494 ehotk->inputdev->setkeycode = eeepc_setkeycode;
495
496 for (key = eeepc_keymap; key->type != KE_END; key++) {
497 switch (key->type) {
498 case KE_KEY:
499 set_bit(EV_KEY, ehotk->inputdev->evbit);
500 set_bit(key->keycode, ehotk->inputdev->keybit);
501 break;
502 }
503 }
504 result = input_register_device(ehotk->inputdev);
505 if (result) {
506 printk(EEEPC_INFO "Unable to register input device\n");
507 input_free_device(ehotk->inputdev);
508 return 0;
509 }
e59f8796
EC
510 } else {
511 printk(EEEPC_ERR "Hotkey device not present, aborting\n");
512 return -EINVAL;
513 }
514 return 0;
515}
516
64b86b65 517static int notify_brn(void)
a5fa429b 518{
64b86b65 519 /* returns the *previous* brightness, or -1 */
a5fa429b 520 struct backlight_device *bd = eeepc_backlight_device;
64b86b65
DS
521 if (bd) {
522 int old = bd->props.brightness;
7695fb04 523 bd->props.brightness = read_brightness(bd);
64b86b65
DS
524 return old;
525 }
526 return -1;
a5fa429b
CC
527}
528
96e9cfeb 529static void eeepc_rfkill_hotplug(void)
5740294c
MG
530{
531 struct pci_dev *dev;
532 struct pci_bus *bus = pci_find_bus(0, 1);
19d337df 533 bool blocked;
5740294c 534
5740294c
MG
535 if (!bus) {
536 printk(EEEPC_WARNING "Unable to find PCI bus 1?\n");
537 return;
538 }
539
19d337df
JB
540 blocked = eeepc_wlan_rfkill_blocked();
541 if (!blocked) {
5740294c
MG
542 dev = pci_get_slot(bus, 0);
543 if (dev) {
544 /* Device already present */
545 pci_dev_put(dev);
546 return;
547 }
548 dev = pci_scan_single_device(bus, 0);
549 if (dev) {
550 pci_bus_assign_resources(bus);
551 if (pci_bus_add_device(dev))
552 printk(EEEPC_ERR "Unable to hotplug wifi\n");
553 }
554 } else {
555 dev = pci_get_slot(bus, 0);
556 if (dev) {
557 pci_remove_bus_device(dev);
558 pci_dev_put(dev);
559 }
560 }
978605c4 561
19d337df 562 rfkill_set_sw_state(ehotk->eeepc_wlan_rfkill, blocked);
5740294c
MG
563}
564
96e9cfeb
AJ
565static void eeepc_rfkill_notify(acpi_handle handle, u32 event, void *data)
566{
567 if (event != ACPI_NOTIFY_BUS_CHECK)
568 return;
569
570 eeepc_rfkill_hotplug();
571}
572
d9b9bd7b 573static void eeepc_hotk_notify(struct acpi_device *device, u32 event)
e59f8796 574{
a195dcdc 575 static struct key_entry *key;
7950b71c 576 u16 count;
64b86b65 577 int brn = -ENODEV;
7950b71c 578
e59f8796
EC
579 if (!ehotk)
580 return;
d9b9bd7b
BH
581 if (event > ACPI_MAX_SYS_NOTIFY)
582 return;
a5fa429b 583 if (event >= NOTIFY_BRN_MIN && event <= NOTIFY_BRN_MAX)
64b86b65 584 brn = notify_brn();
7950b71c
CC
585 count = ehotk->event_count[event % 128]++;
586 acpi_bus_generate_proc_event(ehotk->device, event, count);
2b25c9f0
CC
587 acpi_bus_generate_netlink_event(ehotk->device->pnp.device_class,
588 dev_name(&ehotk->device->dev), event,
7950b71c 589 count);
a195dcdc 590 if (ehotk->inputdev) {
64b86b65
DS
591 if (brn != -ENODEV) {
592 /* brightness-change events need special
593 * handling for conversion to key events
594 */
595 if (brn < 0)
596 brn = event;
597 else
598 brn += NOTIFY_BRN_MIN;
599 if (event < brn)
600 event = NOTIFY_BRN_MIN; /* brightness down */
601 else if (event > brn)
602 event = NOTIFY_BRN_MIN + 2; /* ... up */
603 else
604 event = NOTIFY_BRN_MIN + 1; /* ... unchanged */
605 }
a195dcdc
MG
606 key = eepc_get_entry_by_scancode(event);
607 if (key) {
608 switch (key->type) {
609 case KE_KEY:
610 input_report_key(ehotk->inputdev, key->keycode,
611 1);
612 input_sync(ehotk->inputdev);
613 input_report_key(ehotk->inputdev, key->keycode,
614 0);
615 input_sync(ehotk->inputdev);
616 break;
617 }
618 }
619 }
e59f8796
EC
620}
621
5740294c
MG
622static int eeepc_register_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_install_notify_handler(handle,
631 ACPI_SYSTEM_NOTIFY,
632 eeepc_rfkill_notify,
633 NULL);
634 if (ACPI_FAILURE(status))
635 printk(EEEPC_WARNING
636 "Failed to register notify on %s\n", node);
637 } else
638 return -ENODEV;
639
640 return 0;
641}
642
643static void eeepc_unregister_rfkill_notifier(char *node)
644{
645 acpi_status status = AE_OK;
646 acpi_handle handle;
647
648 status = acpi_get_handle(NULL, node, &handle);
649
650 if (ACPI_SUCCESS(status)) {
651 status = acpi_remove_notify_handler(handle,
652 ACPI_SYSTEM_NOTIFY,
653 eeepc_rfkill_notify);
654 if (ACPI_FAILURE(status))
655 printk(EEEPC_ERR
656 "Error removing rfkill notify handler %s\n",
657 node);
658 }
659}
660
e59f8796
EC
661static int eeepc_hotk_add(struct acpi_device *device)
662{
e59f8796
EC
663 int result;
664
665 if (!device)
666 return -EINVAL;
667 printk(EEEPC_NOTICE EEEPC_HOTK_NAME "\n");
668 ehotk = kzalloc(sizeof(struct eeepc_hotk), GFP_KERNEL);
669 if (!ehotk)
670 return -ENOMEM;
671 ehotk->init_flag = DISABLE_ASL_WLAN | DISABLE_ASL_DISPLAYSWITCH;
672 ehotk->handle = device->handle;
673 strcpy(acpi_device_name(device), EEEPC_HOTK_DEVICE_NAME);
674 strcpy(acpi_device_class(device), EEEPC_HOTK_CLASS);
db89b4f0 675 device->driver_data = ehotk;
e59f8796
EC
676 ehotk->device = device;
677 result = eeepc_hotk_check();
678 if (result)
c9ddf8fe 679 goto ehotk_fail;
a195dcdc 680
fbc97e4c
AJ
681 eeepc_register_rfkill_notifier("\\_SB.PCI0.P0P6");
682 eeepc_register_rfkill_notifier("\\_SB.PCI0.P0P7");
683
a195dcdc 684 if (get_acpi(CM_ASL_WLAN) != -1) {
19d337df
JB
685 ehotk->eeepc_wlan_rfkill = rfkill_alloc("eeepc-wlan",
686 &device->dev,
687 RFKILL_TYPE_WLAN,
688 &eeepc_rfkill_ops,
689 (void *)CM_ASL_WLAN);
a195dcdc
MG
690
691 if (!ehotk->eeepc_wlan_rfkill)
c9ddf8fe 692 goto wlan_fail;
a195dcdc 693
06d5caf4
AJ
694 rfkill_init_sw_state(ehotk->eeepc_wlan_rfkill,
695 get_acpi(CM_ASL_WLAN) != 1);
c9ddf8fe
MG
696 result = rfkill_register(ehotk->eeepc_wlan_rfkill);
697 if (result)
698 goto wlan_fail;
a195dcdc
MG
699 }
700
701 if (get_acpi(CM_ASL_BLUETOOTH) != -1) {
702 ehotk->eeepc_bluetooth_rfkill =
19d337df
JB
703 rfkill_alloc("eeepc-bluetooth",
704 &device->dev,
705 RFKILL_TYPE_BLUETOOTH,
706 &eeepc_rfkill_ops,
707 (void *)CM_ASL_BLUETOOTH);
a195dcdc
MG
708
709 if (!ehotk->eeepc_bluetooth_rfkill)
c9ddf8fe 710 goto bluetooth_fail;
a195dcdc 711
06d5caf4
AJ
712 rfkill_init_sw_state(ehotk->eeepc_bluetooth_rfkill,
713 get_acpi(CM_ASL_BLUETOOTH) != 1);
c9ddf8fe
MG
714 result = rfkill_register(ehotk->eeepc_bluetooth_rfkill);
715 if (result)
716 goto bluetooth_fail;
e59f8796 717 }
5740294c 718
c9ddf8fe
MG
719 return 0;
720
721 bluetooth_fail:
19d337df 722 rfkill_destroy(ehotk->eeepc_bluetooth_rfkill);
c9ddf8fe 723 rfkill_unregister(ehotk->eeepc_wlan_rfkill);
c9ddf8fe 724 wlan_fail:
19d337df 725 rfkill_destroy(ehotk->eeepc_wlan_rfkill);
bd32005e
CC
726 eeepc_unregister_rfkill_notifier("\\_SB.PCI0.P0P6");
727 eeepc_unregister_rfkill_notifier("\\_SB.PCI0.P0P7");
c9ddf8fe
MG
728 ehotk_fail:
729 kfree(ehotk);
730 ehotk = NULL;
731
e59f8796
EC
732 return result;
733}
734
735static int eeepc_hotk_remove(struct acpi_device *device, int type)
736{
e59f8796
EC
737 if (!device || !acpi_driver_data(device))
738 return -EINVAL;
5740294c
MG
739
740 eeepc_unregister_rfkill_notifier("\\_SB.PCI0.P0P6");
741 eeepc_unregister_rfkill_notifier("\\_SB.PCI0.P0P7");
742
e59f8796
EC
743 kfree(ehotk);
744 return 0;
745}
746
96e9cfeb
AJ
747static int eeepc_hotk_resume(struct acpi_device *device)
748{
749 if (ehotk->eeepc_wlan_rfkill) {
750 bool wlan;
751
752 /* Workaround - it seems that _PTS disables the wireless
753 without notification or changing the value read by WLAN.
754 Normally this is fine because the correct value is restored
755 from the non-volatile storage on resume, but we need to do
756 it ourself if case suspend is aborted, or we lose wireless.
757 */
758 wlan = get_acpi(CM_ASL_WLAN);
759 set_acpi(CM_ASL_WLAN, wlan);
760
761 rfkill_set_sw_state(ehotk->eeepc_wlan_rfkill,
762 wlan != 1);
763
764 eeepc_rfkill_hotplug();
765 }
766
767 if (ehotk->eeepc_bluetooth_rfkill)
768 rfkill_set_sw_state(ehotk->eeepc_bluetooth_rfkill,
769 get_acpi(CM_ASL_BLUETOOTH) != 1);
770
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;
cede2cb6
PE
995
996 eeepc_enable_camera();
997
e59f8796
EC
998 /* Register platform stuff */
999 result = platform_driver_register(&platform_driver);
1000 if (result)
1001 goto fail_platform_driver;
1002 platform_device = platform_device_alloc(EEEPC_HOTK_FILE, -1);
1003 if (!platform_device) {
1004 result = -ENOMEM;
1005 goto fail_platform_device1;
1006 }
1007 result = platform_device_add(platform_device);
1008 if (result)
1009 goto fail_platform_device2;
1010 result = sysfs_create_group(&platform_device->dev.kobj,
1011 &platform_attribute_group);
1012 if (result)
1013 goto fail_sysfs;
1014 return 0;
1015fail_sysfs:
1016 platform_device_del(platform_device);
1017fail_platform_device2:
1018 platform_device_put(platform_device);
1019fail_platform_device1:
1020 platform_driver_unregister(&platform_driver);
1021fail_platform_driver:
e1faa9da
CC
1022 eeepc_hwmon_exit();
1023fail_hwmon:
a5fa429b
CC
1024 eeepc_backlight_exit();
1025fail_backlight:
a9df80c5
CC
1026 eeepc_input_exit();
1027 eeepc_rfkill_exit();
e59f8796
EC
1028 return result;
1029}
1030
1031module_init(eeepc_laptop_init);
1032module_exit(eeepc_laptop_exit);
This page took 0.176817 seconds and 5 git commands to generate.