eeepc-laptop: Check return values from rfkill_register
[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>
e59f8796
EC
33
34#define EEEPC_LAPTOP_VERSION "0.1"
35
36#define EEEPC_HOTK_NAME "Eee PC Hotkey Driver"
37#define EEEPC_HOTK_FILE "eeepc"
38#define EEEPC_HOTK_CLASS "hotkey"
39#define EEEPC_HOTK_DEVICE_NAME "Hotkey"
40#define EEEPC_HOTK_HID "ASUS010"
41
42#define EEEPC_LOG EEEPC_HOTK_FILE ": "
43#define EEEPC_ERR KERN_ERR EEEPC_LOG
44#define EEEPC_WARNING KERN_WARNING EEEPC_LOG
45#define EEEPC_NOTICE KERN_NOTICE EEEPC_LOG
46#define EEEPC_INFO KERN_INFO EEEPC_LOG
47
48/*
49 * Definitions for Asus EeePC
50 */
51#define NOTIFY_WLAN_ON 0x10
a5fa429b
CC
52#define NOTIFY_BRN_MIN 0x20
53#define NOTIFY_BRN_MAX 0x2f
e59f8796
EC
54
55enum {
56 DISABLE_ASL_WLAN = 0x0001,
57 DISABLE_ASL_BLUETOOTH = 0x0002,
58 DISABLE_ASL_IRDA = 0x0004,
59 DISABLE_ASL_CAMERA = 0x0008,
60 DISABLE_ASL_TV = 0x0010,
61 DISABLE_ASL_GPS = 0x0020,
62 DISABLE_ASL_DISPLAYSWITCH = 0x0040,
63 DISABLE_ASL_MODEM = 0x0080,
64 DISABLE_ASL_CARDREADER = 0x0100
65};
66
67enum {
68 CM_ASL_WLAN = 0,
69 CM_ASL_BLUETOOTH,
70 CM_ASL_IRDA,
71 CM_ASL_1394,
72 CM_ASL_CAMERA,
73 CM_ASL_TV,
74 CM_ASL_GPS,
75 CM_ASL_DVDROM,
76 CM_ASL_DISPLAYSWITCH,
77 CM_ASL_PANELBRIGHT,
78 CM_ASL_BIOSFLASH,
79 CM_ASL_ACPIFLASH,
80 CM_ASL_CPUFV,
81 CM_ASL_CPUTEMPERATURE,
82 CM_ASL_FANCPU,
83 CM_ASL_FANCHASSIS,
84 CM_ASL_USBPORT1,
85 CM_ASL_USBPORT2,
86 CM_ASL_USBPORT3,
87 CM_ASL_MODEM,
88 CM_ASL_CARDREADER,
89 CM_ASL_LID
90};
91
14109461 92static const char *cm_getv[] = {
3af9bfcb 93 "WLDG", "BTHG", NULL, NULL,
e59f8796
EC
94 "CAMG", NULL, NULL, NULL,
95 NULL, "PBLG", NULL, NULL,
96 "CFVG", NULL, NULL, NULL,
97 "USBG", NULL, NULL, "MODG",
98 "CRDG", "LIDG"
99};
100
14109461 101static const char *cm_setv[] = {
3af9bfcb 102 "WLDS", "BTHS", NULL, NULL,
e59f8796
EC
103 "CAMS", NULL, NULL, NULL,
104 "SDSP", "PBLS", "HDPS", NULL,
105 "CFVS", NULL, NULL, NULL,
106 "USBG", NULL, NULL, "MODS",
107 "CRDS", NULL
108};
109
e1faa9da
CC
110#define EEEPC_EC "\\_SB.PCI0.SBRG.EC0."
111
112#define EEEPC_EC_FAN_PWM EEEPC_EC "SC02" /* Fan PWM duty cycle (%) */
113#define EEEPC_EC_SC02 0x63
114#define EEEPC_EC_FAN_HRPM EEEPC_EC "SC05" /* High byte, fan speed (RPM) */
115#define EEEPC_EC_FAN_LRPM EEEPC_EC "SC06" /* Low byte, fan speed (RPM) */
116#define EEEPC_EC_FAN_CTRL EEEPC_EC "SFB3" /* Byte containing SF25 */
117#define EEEPC_EC_SFB3 0xD3
118
e59f8796
EC
119/*
120 * This is the main structure, we can use it to store useful information
121 * about the hotk device
122 */
123struct eeepc_hotk {
124 struct acpi_device *device; /* the device we are in */
125 acpi_handle handle; /* the handle of the hotk device */
126 u32 cm_supported; /* the control methods supported
127 by this BIOS */
128 uint init_flag; /* Init flags */
129 u16 event_count[128]; /* count for each event */
a195dcdc
MG
130 struct input_dev *inputdev;
131 u16 *keycode_map;
132 struct rfkill *eeepc_wlan_rfkill;
133 struct rfkill *eeepc_bluetooth_rfkill;
e59f8796
EC
134};
135
136/* The actual device the driver binds to */
137static struct eeepc_hotk *ehotk;
138
139/* Platform device/driver */
140static struct platform_driver platform_driver = {
141 .driver = {
142 .name = EEEPC_HOTK_FILE,
143 .owner = THIS_MODULE,
144 }
145};
146
147static struct platform_device *platform_device;
148
a195dcdc
MG
149struct key_entry {
150 char type;
151 u8 code;
152 u16 keycode;
153};
154
155enum { KE_KEY, KE_END };
156
157static struct key_entry eeepc_keymap[] = {
158 /* Sleep already handled via generic ACPI code */
159 {KE_KEY, 0x10, KEY_WLAN },
160 {KE_KEY, 0x12, KEY_PROG1 },
161 {KE_KEY, 0x13, KEY_MUTE },
162 {KE_KEY, 0x14, KEY_VOLUMEDOWN },
163 {KE_KEY, 0x15, KEY_VOLUMEUP },
b5f6f265
MG
164 {KE_KEY, 0x1a, KEY_COFFEE },
165 {KE_KEY, 0x1b, KEY_ZOOM },
166 {KE_KEY, 0x1c, KEY_PROG2 },
167 {KE_KEY, 0x1d, KEY_PROG3 },
a195dcdc
MG
168 {KE_KEY, 0x30, KEY_SWITCHVIDEOMODE },
169 {KE_KEY, 0x31, KEY_SWITCHVIDEOMODE },
170 {KE_KEY, 0x32, KEY_SWITCHVIDEOMODE },
171 {KE_END, 0},
172};
173
e59f8796
EC
174/*
175 * The hotkey driver declaration
176 */
177static int eeepc_hotk_add(struct acpi_device *device);
178static int eeepc_hotk_remove(struct acpi_device *device, int type);
179
180static const struct acpi_device_id eeepc_device_ids[] = {
181 {EEEPC_HOTK_HID, 0},
182 {"", 0},
183};
184MODULE_DEVICE_TABLE(acpi, eeepc_device_ids);
185
186static struct acpi_driver eeepc_hotk_driver = {
187 .name = EEEPC_HOTK_NAME,
188 .class = EEEPC_HOTK_CLASS,
189 .ids = eeepc_device_ids,
190 .ops = {
191 .add = eeepc_hotk_add,
192 .remove = eeepc_hotk_remove,
193 },
194};
195
a5fa429b
CC
196/* The backlight device /sys/class/backlight */
197static struct backlight_device *eeepc_backlight_device;
198
e1faa9da
CC
199/* The hwmon device */
200static struct device *eeepc_hwmon_device;
201
a5fa429b
CC
202/*
203 * The backlight class declaration
204 */
205static int read_brightness(struct backlight_device *bd);
206static int update_bl_status(struct backlight_device *bd);
207static struct backlight_ops eeepcbl_ops = {
208 .get_brightness = read_brightness,
209 .update_status = update_bl_status,
210};
211
e59f8796
EC
212MODULE_AUTHOR("Corentin Chary, Eric Cooper");
213MODULE_DESCRIPTION(EEEPC_HOTK_NAME);
214MODULE_LICENSE("GPL");
215
216/*
217 * ACPI Helpers
218 */
219static int write_acpi_int(acpi_handle handle, const char *method, int val,
220 struct acpi_buffer *output)
221{
222 struct acpi_object_list params;
223 union acpi_object in_obj;
224 acpi_status status;
225
226 params.count = 1;
227 params.pointer = &in_obj;
228 in_obj.type = ACPI_TYPE_INTEGER;
229 in_obj.integer.value = val;
230
231 status = acpi_evaluate_object(handle, (char *)method, &params, output);
232 return (status == AE_OK ? 0 : -1);
233}
234
235static int read_acpi_int(acpi_handle handle, const char *method, int *val)
236{
237 acpi_status status;
27663c58 238 unsigned long long result;
e59f8796
EC
239
240 status = acpi_evaluate_integer(handle, (char *)method, NULL, &result);
241 if (ACPI_FAILURE(status)) {
242 *val = -1;
243 return -1;
244 } else {
245 *val = result;
246 return 0;
247 }
248}
249
250static int set_acpi(int cm, int value)
251{
252 if (ehotk->cm_supported & (0x1 << cm)) {
253 const char *method = cm_setv[cm];
254 if (method == NULL)
255 return -ENODEV;
256 if (write_acpi_int(ehotk->handle, method, value, NULL))
257 printk(EEEPC_WARNING "Error writing %s\n", method);
258 }
259 return 0;
260}
261
262static int get_acpi(int cm)
263{
264 int value = -1;
265 if ((ehotk->cm_supported & (0x1 << cm))) {
266 const char *method = cm_getv[cm];
267 if (method == NULL)
268 return -ENODEV;
269 if (read_acpi_int(ehotk->handle, method, &value))
270 printk(EEEPC_WARNING "Error reading %s\n", method);
271 }
272 return value;
273}
274
a5fa429b
CC
275/*
276 * Backlight
277 */
278static int read_brightness(struct backlight_device *bd)
279{
280 return get_acpi(CM_ASL_PANELBRIGHT);
281}
282
283static int set_brightness(struct backlight_device *bd, int value)
284{
285 value = max(0, min(15, value));
286 return set_acpi(CM_ASL_PANELBRIGHT, value);
287}
288
289static int update_bl_status(struct backlight_device *bd)
290{
291 return set_brightness(bd, bd->props.brightness);
292}
293
a195dcdc
MG
294/*
295 * Rfkill helpers
296 */
297
298static int eeepc_wlan_rfkill_set(void *data, enum rfkill_state state)
299{
300 if (state == RFKILL_STATE_SOFT_BLOCKED)
301 return set_acpi(CM_ASL_WLAN, 0);
302 else
303 return set_acpi(CM_ASL_WLAN, 1);
304}
305
306static int eeepc_wlan_rfkill_state(void *data, enum rfkill_state *state)
307{
308 if (get_acpi(CM_ASL_WLAN) == 1)
309 *state = RFKILL_STATE_UNBLOCKED;
310 else
311 *state = RFKILL_STATE_SOFT_BLOCKED;
312 return 0;
313}
314
315static int eeepc_bluetooth_rfkill_set(void *data, enum rfkill_state state)
316{
317 if (state == RFKILL_STATE_SOFT_BLOCKED)
318 return set_acpi(CM_ASL_BLUETOOTH, 0);
319 else
320 return set_acpi(CM_ASL_BLUETOOTH, 1);
321}
322
323static int eeepc_bluetooth_rfkill_state(void *data, enum rfkill_state *state)
324{
325 if (get_acpi(CM_ASL_BLUETOOTH) == 1)
326 *state = RFKILL_STATE_UNBLOCKED;
327 else
328 *state = RFKILL_STATE_SOFT_BLOCKED;
329 return 0;
330}
331
e59f8796
EC
332/*
333 * Sys helpers
334 */
335static int parse_arg(const char *buf, unsigned long count, int *val)
336{
337 if (!count)
338 return 0;
339 if (sscanf(buf, "%i", val) != 1)
340 return -EINVAL;
341 return count;
342}
343
344static ssize_t store_sys_acpi(int cm, const char *buf, size_t count)
345{
346 int rv, value;
347
348 rv = parse_arg(buf, count, &value);
349 if (rv > 0)
350 set_acpi(cm, value);
351 return rv;
352}
353
354static ssize_t show_sys_acpi(int cm, char *buf)
355{
356 return sprintf(buf, "%d\n", get_acpi(cm));
357}
358
359#define EEEPC_CREATE_DEVICE_ATTR(_name, _cm) \
360 static ssize_t show_##_name(struct device *dev, \
361 struct device_attribute *attr, \
362 char *buf) \
363 { \
364 return show_sys_acpi(_cm, buf); \
365 } \
366 static ssize_t store_##_name(struct device *dev, \
367 struct device_attribute *attr, \
368 const char *buf, size_t count) \
369 { \
370 return store_sys_acpi(_cm, buf, count); \
371 } \
372 static struct device_attribute dev_attr_##_name = { \
373 .attr = { \
374 .name = __stringify(_name), \
375 .mode = 0644 }, \
376 .show = show_##_name, \
377 .store = store_##_name, \
378 }
379
380EEEPC_CREATE_DEVICE_ATTR(camera, CM_ASL_CAMERA);
381EEEPC_CREATE_DEVICE_ATTR(cardr, CM_ASL_CARDREADER);
382EEEPC_CREATE_DEVICE_ATTR(disp, CM_ASL_DISPLAYSWITCH);
e59f8796
EC
383
384static struct attribute *platform_attributes[] = {
385 &dev_attr_camera.attr,
386 &dev_attr_cardr.attr,
387 &dev_attr_disp.attr,
e59f8796
EC
388 NULL
389};
390
391static struct attribute_group platform_attribute_group = {
392 .attrs = platform_attributes
393};
394
395/*
396 * Hotkey functions
397 */
a195dcdc
MG
398static struct key_entry *eepc_get_entry_by_scancode(int code)
399{
400 struct key_entry *key;
401
402 for (key = eeepc_keymap; key->type != KE_END; key++)
403 if (code == key->code)
404 return key;
405
406 return NULL;
407}
408
409static struct key_entry *eepc_get_entry_by_keycode(int code)
410{
411 struct key_entry *key;
412
413 for (key = eeepc_keymap; key->type != KE_END; key++)
414 if (code == key->keycode && key->type == KE_KEY)
415 return key;
416
417 return NULL;
418}
419
420static int eeepc_getkeycode(struct input_dev *dev, int scancode, int *keycode)
421{
422 struct key_entry *key = eepc_get_entry_by_scancode(scancode);
423
424 if (key && key->type == KE_KEY) {
425 *keycode = key->keycode;
426 return 0;
427 }
428
429 return -EINVAL;
430}
431
432static int eeepc_setkeycode(struct input_dev *dev, int scancode, int keycode)
433{
434 struct key_entry *key;
435 int old_keycode;
436
437 if (keycode < 0 || keycode > KEY_MAX)
438 return -EINVAL;
439
440 key = eepc_get_entry_by_scancode(scancode);
441 if (key && key->type == KE_KEY) {
442 old_keycode = key->keycode;
443 key->keycode = keycode;
444 set_bit(keycode, dev->keybit);
445 if (!eepc_get_entry_by_keycode(old_keycode))
446 clear_bit(old_keycode, dev->keybit);
447 return 0;
448 }
449
450 return -EINVAL;
451}
452
e59f8796
EC
453static int eeepc_hotk_check(void)
454{
a195dcdc 455 const struct key_entry *key;
e59f8796
EC
456 struct acpi_buffer buffer = { ACPI_ALLOCATE_BUFFER, NULL };
457 int result;
458
459 result = acpi_bus_get_status(ehotk->device);
460 if (result)
461 return result;
462 if (ehotk->device->status.present) {
463 if (write_acpi_int(ehotk->handle, "INIT", ehotk->init_flag,
464 &buffer)) {
465 printk(EEEPC_ERR "Hotkey initialization failed\n");
466 return -ENODEV;
467 } else {
468 printk(EEEPC_NOTICE "Hotkey init flags 0x%x\n",
469 ehotk->init_flag);
470 }
471 /* get control methods supported */
472 if (read_acpi_int(ehotk->handle, "CMSG"
473 , &ehotk->cm_supported)) {
474 printk(EEEPC_ERR
475 "Get control methods supported failed\n");
476 return -ENODEV;
477 } else {
478 printk(EEEPC_INFO
479 "Get control methods supported: 0x%x\n",
480 ehotk->cm_supported);
481 }
a195dcdc
MG
482 ehotk->inputdev = input_allocate_device();
483 if (!ehotk->inputdev) {
484 printk(EEEPC_INFO "Unable to allocate input device\n");
485 return 0;
486 }
487 ehotk->inputdev->name = "Asus EeePC extra buttons";
488 ehotk->inputdev->phys = EEEPC_HOTK_FILE "/input0";
489 ehotk->inputdev->id.bustype = BUS_HOST;
490 ehotk->inputdev->getkeycode = eeepc_getkeycode;
491 ehotk->inputdev->setkeycode = eeepc_setkeycode;
492
493 for (key = eeepc_keymap; key->type != KE_END; key++) {
494 switch (key->type) {
495 case KE_KEY:
496 set_bit(EV_KEY, ehotk->inputdev->evbit);
497 set_bit(key->keycode, ehotk->inputdev->keybit);
498 break;
499 }
500 }
501 result = input_register_device(ehotk->inputdev);
502 if (result) {
503 printk(EEEPC_INFO "Unable to register input device\n");
504 input_free_device(ehotk->inputdev);
505 return 0;
506 }
e59f8796
EC
507 } else {
508 printk(EEEPC_ERR "Hotkey device not present, aborting\n");
509 return -EINVAL;
510 }
511 return 0;
512}
513
a5fa429b
CC
514static void notify_brn(void)
515{
516 struct backlight_device *bd = eeepc_backlight_device;
517 bd->props.brightness = read_brightness(bd);
518}
519
e59f8796
EC
520static void eeepc_hotk_notify(acpi_handle handle, u32 event, void *data)
521{
a195dcdc 522 static struct key_entry *key;
e59f8796
EC
523 if (!ehotk)
524 return;
a5fa429b
CC
525 if (event >= NOTIFY_BRN_MIN && event <= NOTIFY_BRN_MAX)
526 notify_brn();
e59f8796
EC
527 acpi_bus_generate_proc_event(ehotk->device, event,
528 ehotk->event_count[event % 128]++);
a195dcdc
MG
529 if (ehotk->inputdev) {
530 key = eepc_get_entry_by_scancode(event);
531 if (key) {
532 switch (key->type) {
533 case KE_KEY:
534 input_report_key(ehotk->inputdev, key->keycode,
535 1);
536 input_sync(ehotk->inputdev);
537 input_report_key(ehotk->inputdev, key->keycode,
538 0);
539 input_sync(ehotk->inputdev);
540 break;
541 }
542 }
543 }
e59f8796
EC
544}
545
546static int eeepc_hotk_add(struct acpi_device *device)
547{
548 acpi_status status = AE_OK;
549 int result;
550
551 if (!device)
552 return -EINVAL;
553 printk(EEEPC_NOTICE EEEPC_HOTK_NAME "\n");
554 ehotk = kzalloc(sizeof(struct eeepc_hotk), GFP_KERNEL);
555 if (!ehotk)
556 return -ENOMEM;
557 ehotk->init_flag = DISABLE_ASL_WLAN | DISABLE_ASL_DISPLAYSWITCH;
558 ehotk->handle = device->handle;
559 strcpy(acpi_device_name(device), EEEPC_HOTK_DEVICE_NAME);
560 strcpy(acpi_device_class(device), EEEPC_HOTK_CLASS);
db89b4f0 561 device->driver_data = ehotk;
e59f8796
EC
562 ehotk->device = device;
563 result = eeepc_hotk_check();
564 if (result)
c9ddf8fe 565 goto ehotk_fail;
e59f8796
EC
566 status = acpi_install_notify_handler(ehotk->handle, ACPI_SYSTEM_NOTIFY,
567 eeepc_hotk_notify, ehotk);
568 if (ACPI_FAILURE(status))
569 printk(EEEPC_ERR "Error installing notify handler\n");
a195dcdc
MG
570
571 if (get_acpi(CM_ASL_WLAN) != -1) {
572 ehotk->eeepc_wlan_rfkill = rfkill_allocate(&device->dev,
573 RFKILL_TYPE_WLAN);
574
575 if (!ehotk->eeepc_wlan_rfkill)
c9ddf8fe 576 goto wlan_fail;
a195dcdc
MG
577
578 ehotk->eeepc_wlan_rfkill->name = "eeepc-wlan";
579 ehotk->eeepc_wlan_rfkill->toggle_radio = eeepc_wlan_rfkill_set;
580 ehotk->eeepc_wlan_rfkill->get_state = eeepc_wlan_rfkill_state;
c9ddf8fe 581 if (get_acpi(CM_ASL_WLAN) == 1) {
a195dcdc
MG
582 ehotk->eeepc_wlan_rfkill->state =
583 RFKILL_STATE_UNBLOCKED;
c9ddf8fe
MG
584 rfkill_set_default(RFKILL_TYPE_WLAN,
585 RFKILL_STATE_UNBLOCKED);
586 } else {
a195dcdc
MG
587 ehotk->eeepc_wlan_rfkill->state =
588 RFKILL_STATE_SOFT_BLOCKED;
c9ddf8fe
MG
589 rfkill_set_default(RFKILL_TYPE_WLAN,
590 RFKILL_STATE_SOFT_BLOCKED);
591 }
592 result = rfkill_register(ehotk->eeepc_wlan_rfkill);
593 if (result)
594 goto wlan_fail;
a195dcdc
MG
595 }
596
597 if (get_acpi(CM_ASL_BLUETOOTH) != -1) {
598 ehotk->eeepc_bluetooth_rfkill =
599 rfkill_allocate(&device->dev, RFKILL_TYPE_BLUETOOTH);
600
601 if (!ehotk->eeepc_bluetooth_rfkill)
c9ddf8fe 602 goto bluetooth_fail;
a195dcdc
MG
603
604 ehotk->eeepc_bluetooth_rfkill->name = "eeepc-bluetooth";
605 ehotk->eeepc_bluetooth_rfkill->toggle_radio =
606 eeepc_bluetooth_rfkill_set;
607 ehotk->eeepc_bluetooth_rfkill->get_state =
608 eeepc_bluetooth_rfkill_state;
c9ddf8fe 609 if (get_acpi(CM_ASL_BLUETOOTH) == 1) {
a195dcdc
MG
610 ehotk->eeepc_bluetooth_rfkill->state =
611 RFKILL_STATE_UNBLOCKED;
c9ddf8fe
MG
612 rfkill_set_default(RFKILL_TYPE_BLUETOOTH,
613 RFKILL_STATE_UNBLOCKED);
614 } else {
a195dcdc
MG
615 ehotk->eeepc_bluetooth_rfkill->state =
616 RFKILL_STATE_SOFT_BLOCKED;
c9ddf8fe
MG
617 rfkill_set_default(RFKILL_TYPE_BLUETOOTH,
618 RFKILL_STATE_SOFT_BLOCKED);
619 }
a195dcdc 620
c9ddf8fe
MG
621 result = rfkill_register(ehotk->eeepc_bluetooth_rfkill);
622 if (result)
623 goto bluetooth_fail;
e59f8796 624 }
c9ddf8fe
MG
625 return 0;
626
627 bluetooth_fail:
628 if (ehotk->eeepc_bluetooth_rfkill)
629 rfkill_free(ehotk->eeepc_bluetooth_rfkill);
630 rfkill_unregister(ehotk->eeepc_wlan_rfkill);
631 ehotk->eeepc_wlan_rfkill = NULL;
632 wlan_fail:
633 if (ehotk->eeepc_wlan_rfkill)
634 rfkill_free(ehotk->eeepc_wlan_rfkill);
635 ehotk_fail:
636 kfree(ehotk);
637 ehotk = NULL;
638
e59f8796
EC
639 return result;
640}
641
642static int eeepc_hotk_remove(struct acpi_device *device, int type)
643{
644 acpi_status status = 0;
645
646 if (!device || !acpi_driver_data(device))
647 return -EINVAL;
648 status = acpi_remove_notify_handler(ehotk->handle, ACPI_SYSTEM_NOTIFY,
649 eeepc_hotk_notify);
650 if (ACPI_FAILURE(status))
651 printk(EEEPC_ERR "Error removing notify handler\n");
652 kfree(ehotk);
653 return 0;
654}
655
e1faa9da
CC
656/*
657 * Hwmon
658 */
659static int eeepc_get_fan_pwm(void)
660{
661 int value = 0;
662
663 read_acpi_int(NULL, EEEPC_EC_FAN_PWM, &value);
04dcd84b 664 value = value * 255 / 100;
e1faa9da
CC
665 return (value);
666}
667
668static void eeepc_set_fan_pwm(int value)
669{
04dcd84b
CC
670 value = SENSORS_LIMIT(value, 0, 255);
671 value = value * 100 / 255;
e1faa9da
CC
672 ec_write(EEEPC_EC_SC02, value);
673}
674
675static int eeepc_get_fan_rpm(void)
676{
677 int high = 0;
678 int low = 0;
679
680 read_acpi_int(NULL, EEEPC_EC_FAN_HRPM, &high);
681 read_acpi_int(NULL, EEEPC_EC_FAN_LRPM, &low);
682 return (high << 8 | low);
683}
684
685static int eeepc_get_fan_ctrl(void)
686{
687 int value = 0;
688
689 read_acpi_int(NULL, EEEPC_EC_FAN_CTRL, &value);
690 return ((value & 0x02 ? 1 : 0));
691}
692
693static void eeepc_set_fan_ctrl(int manual)
694{
695 int value = 0;
696
697 read_acpi_int(NULL, EEEPC_EC_FAN_CTRL, &value);
698 if (manual)
699 value |= 0x02;
700 else
701 value &= ~0x02;
702 ec_write(EEEPC_EC_SFB3, value);
703}
704
705static ssize_t store_sys_hwmon(void (*set)(int), const char *buf, size_t count)
706{
707 int rv, value;
708
709 rv = parse_arg(buf, count, &value);
710 if (rv > 0)
711 set(value);
712 return rv;
713}
714
715static ssize_t show_sys_hwmon(int (*get)(void), char *buf)
716{
717 return sprintf(buf, "%d\n", get());
718}
719
720#define EEEPC_CREATE_SENSOR_ATTR(_name, _mode, _set, _get) \
721 static ssize_t show_##_name(struct device *dev, \
722 struct device_attribute *attr, \
723 char *buf) \
724 { \
725 return show_sys_hwmon(_set, buf); \
726 } \
727 static ssize_t store_##_name(struct device *dev, \
728 struct device_attribute *attr, \
729 const char *buf, size_t count) \
730 { \
731 return store_sys_hwmon(_get, buf, count); \
732 } \
733 static SENSOR_DEVICE_ATTR(_name, _mode, show_##_name, store_##_name, 0);
734
735EEEPC_CREATE_SENSOR_ATTR(fan1_input, S_IRUGO, eeepc_get_fan_rpm, NULL);
04dcd84b 736EEEPC_CREATE_SENSOR_ATTR(pwm1, S_IRUGO | S_IWUSR,
e1faa9da
CC
737 eeepc_get_fan_pwm, eeepc_set_fan_pwm);
738EEEPC_CREATE_SENSOR_ATTR(pwm1_enable, S_IRUGO | S_IWUSR,
739 eeepc_get_fan_ctrl, eeepc_set_fan_ctrl);
740
04dcd84b
CC
741static ssize_t
742show_name(struct device *dev, struct device_attribute *attr, char *buf)
743{
744 return sprintf(buf, "eeepc\n");
745}
746static SENSOR_DEVICE_ATTR(name, S_IRUGO, show_name, NULL, 0);
747
e1faa9da 748static struct attribute *hwmon_attributes[] = {
04dcd84b 749 &sensor_dev_attr_pwm1.dev_attr.attr,
e1faa9da
CC
750 &sensor_dev_attr_fan1_input.dev_attr.attr,
751 &sensor_dev_attr_pwm1_enable.dev_attr.attr,
04dcd84b 752 &sensor_dev_attr_name.dev_attr.attr,
e1faa9da
CC
753 NULL
754};
755
756static struct attribute_group hwmon_attribute_group = {
757 .attrs = hwmon_attributes
758};
759
e59f8796
EC
760/*
761 * exit/init
762 */
a5fa429b
CC
763static void eeepc_backlight_exit(void)
764{
765 if (eeepc_backlight_device)
766 backlight_device_unregister(eeepc_backlight_device);
a9df80c5
CC
767 eeepc_backlight_device = NULL;
768}
769
770static void eeepc_rfkill_exit(void)
771{
a195dcdc
MG
772 if (ehotk->eeepc_wlan_rfkill)
773 rfkill_unregister(ehotk->eeepc_wlan_rfkill);
774 if (ehotk->eeepc_bluetooth_rfkill)
775 rfkill_unregister(ehotk->eeepc_bluetooth_rfkill);
a9df80c5
CC
776}
777
778static void eeepc_input_exit(void)
779{
780 if (ehotk->inputdev)
781 input_unregister_device(ehotk->inputdev);
a5fa429b
CC
782}
783
e1faa9da
CC
784static void eeepc_hwmon_exit(void)
785{
786 struct device *hwmon;
787
788 hwmon = eeepc_hwmon_device;
789 if (!hwmon)
790 return ;
e1faa9da
CC
791 sysfs_remove_group(&hwmon->kobj,
792 &hwmon_attribute_group);
f1441318 793 hwmon_device_unregister(hwmon);
e1faa9da
CC
794 eeepc_hwmon_device = NULL;
795}
796
e59f8796
EC
797static void __exit eeepc_laptop_exit(void)
798{
a5fa429b 799 eeepc_backlight_exit();
a9df80c5
CC
800 eeepc_rfkill_exit();
801 eeepc_input_exit();
e1faa9da 802 eeepc_hwmon_exit();
e59f8796
EC
803 acpi_bus_unregister_driver(&eeepc_hotk_driver);
804 sysfs_remove_group(&platform_device->dev.kobj,
805 &platform_attribute_group);
806 platform_device_unregister(platform_device);
807 platform_driver_unregister(&platform_driver);
808}
809
a5fa429b
CC
810static int eeepc_backlight_init(struct device *dev)
811{
812 struct backlight_device *bd;
813
814 bd = backlight_device_register(EEEPC_HOTK_FILE, dev,
815 NULL, &eeepcbl_ops);
816 if (IS_ERR(bd)) {
817 printk(EEEPC_ERR
818 "Could not register eeepc backlight device\n");
819 eeepc_backlight_device = NULL;
820 return PTR_ERR(bd);
821 }
822 eeepc_backlight_device = bd;
823 bd->props.max_brightness = 15;
824 bd->props.brightness = read_brightness(NULL);
825 bd->props.power = FB_BLANK_UNBLANK;
826 backlight_update_status(bd);
827 return 0;
828}
829
e1faa9da
CC
830static int eeepc_hwmon_init(struct device *dev)
831{
832 struct device *hwmon;
833 int result;
834
835 hwmon = hwmon_device_register(dev);
836 if (IS_ERR(hwmon)) {
837 printk(EEEPC_ERR
838 "Could not register eeepc hwmon device\n");
839 eeepc_hwmon_device = NULL;
840 return PTR_ERR(hwmon);
841 }
842 eeepc_hwmon_device = hwmon;
843 result = sysfs_create_group(&hwmon->kobj,
844 &hwmon_attribute_group);
845 if (result)
846 eeepc_hwmon_exit();
847 return result;
848}
849
e59f8796
EC
850static int __init eeepc_laptop_init(void)
851{
852 struct device *dev;
853 int result;
854
855 if (acpi_disabled)
856 return -ENODEV;
857 result = acpi_bus_register_driver(&eeepc_hotk_driver);
858 if (result < 0)
859 return result;
860 if (!ehotk) {
861 acpi_bus_unregister_driver(&eeepc_hotk_driver);
862 return -ENODEV;
863 }
864 dev = acpi_get_physical_device(ehotk->device->handle);
a2bf8c01
TR
865
866 if (!acpi_video_backlight_support()) {
867 result = eeepc_backlight_init(dev);
868 if (result)
869 goto fail_backlight;
870 } else
871 printk(EEEPC_INFO "Backlight controlled by ACPI video "
872 "driver\n");
873
e1faa9da
CC
874 result = eeepc_hwmon_init(dev);
875 if (result)
876 goto fail_hwmon;
e59f8796
EC
877 /* Register platform stuff */
878 result = platform_driver_register(&platform_driver);
879 if (result)
880 goto fail_platform_driver;
881 platform_device = platform_device_alloc(EEEPC_HOTK_FILE, -1);
882 if (!platform_device) {
883 result = -ENOMEM;
884 goto fail_platform_device1;
885 }
886 result = platform_device_add(platform_device);
887 if (result)
888 goto fail_platform_device2;
889 result = sysfs_create_group(&platform_device->dev.kobj,
890 &platform_attribute_group);
891 if (result)
892 goto fail_sysfs;
893 return 0;
894fail_sysfs:
895 platform_device_del(platform_device);
896fail_platform_device2:
897 platform_device_put(platform_device);
898fail_platform_device1:
899 platform_driver_unregister(&platform_driver);
900fail_platform_driver:
e1faa9da
CC
901 eeepc_hwmon_exit();
902fail_hwmon:
a5fa429b
CC
903 eeepc_backlight_exit();
904fail_backlight:
a9df80c5
CC
905 eeepc_input_exit();
906 eeepc_rfkill_exit();
e59f8796
EC
907 return result;
908}
909
910module_init(eeepc_laptop_init);
911module_exit(eeepc_laptop_exit);
This page took 0.116232 seconds and 5 git commands to generate.