wmi-acer - Unregister EC handler on module unload
[acer_acpi.git] / acer_acpi.c
blobcb4d5486f0ffbc6ecefc529d8ff161ea246c43db
1 /*
2 * Acer Laptop ACPI Extras
4 * Copyright (C) 2005-2007 E.M. Smith
5 * Copyright (C) 2007 Carlos Corbacho <cathectic@gmail.com>
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 * The devolpment page for this driver is located at
23 * http://code.google.com/p/aceracpi
25 * Credits:
27 * John Belmonte - the Toshiba ACPI driver originally adapted for this module.
28 * Julien Lerouge & Karol Kozimor - ASUS Acpi driver authors.
29 * Olaf Tauber - developer of acerhk, the inspiration to solve the 64-bit
30 * driver problem for my Aspire 5024.
31 * Mathieu Segaud - solved the ACPI problem that needed a double-modprobe
32 * in version 0.2 and below.
33 * Jim Ramsay - Figured out and added support for WMID interface
36 #define ACER_ACPI_VERSION "0.10.0"
39 * Comment the following line out to remove /proc support
41 #define CONFIG_PROC
43 #ifdef CONFIG_PROC
44 #define PROC_ACER "acer"
45 #include <linux/proc_fs.h>
46 #endif
48 #include <linux/kernel.h>
49 #include <linux/module.h>
50 #include <linux/init.h>
51 #include <linux/types.h>
52 #include <linux/delay.h>
53 #include <linux/version.h>
55 #if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,17)
56 #include <asm/uaccess.h>
57 #else
58 #include <linux/uaccess.h>
59 #endif
61 #include <linux/io.h>
62 #include <linux/dmi.h>
63 #include <linux/backlight.h>
64 #include <linux/leds.h>
65 #include <linux/platform_device.h>
67 #include <acpi/acpi_drivers.h>
69 #include "wmi-acer.h"
71 /* Workaround needed for older kernels */
72 #ifndef bool
73 #define bool int
74 #endif
76 MODULE_AUTHOR("Mark Smith, Carlos Corbacho");
77 MODULE_DESCRIPTION("Acer Laptop ACPI Extras Driver");
78 MODULE_LICENSE("GPL");
80 MODULE_ALIAS("dmi:*:*Acer*:*:");
82 #define ACER_LOGPREFIX "acer_acpi: "
83 #define ACER_ERR KERN_ERR ACER_LOGPREFIX
84 #define ACER_NOTICE KERN_NOTICE ACER_LOGPREFIX
85 #define ACER_INFO KERN_INFO ACER_LOGPREFIX
87 #define DEBUG(level, message...) { \
88 if (debug >= level) \
89 printk(KERN_DEBUG ACER_LOGPREFIX message);\
93 * The maximum temperature one can set for fan control override.
94 * Doesn't propably make much sense if over 80 degrees celsius though...
96 #define ACER_MAX_TEMPERATURE_OVERRIDE 150
99 * The following defines quirks to get some specific functions to work
100 * which are known to not be supported over ACPI (such as the mail LED
101 * on WMID based Acer's)
103 struct acer_quirks {
104 const char *vendor;
105 const char *model;
106 u16 quirks;
110 * Keyboard controller ports
112 #define ACER_KBD_STATUS_REG 0x64 /* Status register (R) */
113 #define ACER_KBD_CNTL_REG 0x64 /* Controller command register (W) */
114 #define ACER_KBD_DATA_REG 0x60 /* Keyboard data register (R/W) */
117 * Magic Number
118 * Meaning is unknown - this number is required for writing to ACPI for AMW0
119 * (it's also used in acerhk when directly accessing the EC)
121 #define ACER_AMW0_WRITE 0x9610
124 * Bit masks for the old AMW0 interface
126 #define ACER_AMW0_WIRELESS_MASK 0x35
127 #define ACER_AMW0_BLUETOOTH_MASK 0x34
128 #define ACER_AMW0_MAILLED_MASK 0x31
131 * Method IDs for new WMID interface
133 #define ACER_WMID_GET_WIRELESS_METHODID 1
134 #define ACER_WMID_GET_BLUETOOTH_METHODID 2
135 #define ACER_WMID_GET_BRIGHTNESS_METHODID 3
136 #define ACER_WMID_SET_WIRELESS_METHODID 4
137 #define ACER_WMID_SET_BLUETOOTH_METHODID 5
138 #define ACER_WMID_SET_BRIGHTNESS_METHODID 6
139 #define ACER_WMID_GET_THREEG_METHODID 10
140 #define ACER_WMID_SET_THREEG_METHODID 11
143 * Acer ACPI method GUIDs
145 #define AMW0_GUID1 "67C3371D-95A3-4C37-BB61-DD47B491DAAB"
146 #define WMID_GUID1 "6AF4F258-B401-42fd-BE91-3D4AC2D7C0D3"
147 #define WMID_GUID2 "95764E09-FB56-4e83-B31A-37761F60994A"
150 * Interface capability flags
152 #define ACER_CAP_MAILLED (1<<0)
153 #define ACER_CAP_WIRELESS (1<<1)
154 #define ACER_CAP_BLUETOOTH (1<<2)
155 #define ACER_CAP_BRIGHTNESS (1<<3)
156 #define ACER_CAP_THREEG (1<<4)
157 #define ACER_CAP_TOUCHPAD_READ (1<<5)
158 #define ACER_CAP_TEMPERATURE_OVERRIDE (1<<6)
159 #define ACER_CAP_ANY (0xFFFFFFFF)
162 * Interface type flags
164 enum interface_flags {
165 ACER_AMW0,
166 ACER_AMW0_V2,
167 ACER_WMID,
171 * Presumed start states -
172 * On some AMW0 laptops, we do not yet know how to get the device status from
173 * the EC, so we must store this ourselves.
175 * Plus, we can't tell which features are enabled or disabled on a specific
176 * model - e.g. The 5020 series can _support_ bluetooth; but the 5021 has no
177 * bluetooth, whilst the 5024 does. However, the BIOS identifies both laptops
178 * as 5020, and you can add bluetooth later.
180 * Basically the code works like this:
181 * - On init, any values specified on the commandline are set.
182 * - For interfaces where the current values cannot be detected and which
183 * have not been set on the commandline, we set them to some sane default
184 * (disabled)
186 * See AMW0_init and acer_commandline_init
189 #define ACER_DEFAULT_WIRELESS 0
190 #define ACER_DEFAULT_BLUETOOTH 0
191 #define ACER_DEFAULT_MAILLED 0
192 #define ACER_DEFAULT_THREEG 0
194 static int max_brightness = 0xF;
196 static int wireless = -1;
197 static int bluetooth = -1;
198 static int mailled = -1;
199 static int brightness = -1;
200 static int threeg = -1;
201 static int fan_temperature_override = -1;
202 static int debug = 0;
203 static int force_series;
205 module_param(mailled, int, 0444);
206 module_param(wireless, int, 0444);
207 module_param(bluetooth, int, 0444);
208 module_param(brightness, int, 0444);
209 module_param(threeg, int, 0444);
210 module_param(force_series, int, 0444);
211 module_param(fan_temperature_override, int, 0444);
212 module_param(debug, int, 0664);
213 MODULE_PARM_DESC(wireless, "Set initial state of Wireless hardware");
214 MODULE_PARM_DESC(bluetooth, "Set initial state of Bluetooth hardware");
215 MODULE_PARM_DESC(mailled, "Set initial state of Mail LED");
216 MODULE_PARM_DESC(brightness, "Set initial LCD backlight brightness");
217 MODULE_PARM_DESC(threeg, "Set initial state of 3G hardware");
218 MODULE_PARM_DESC(fan_temperature_override, "Set initial state of the 'FAN temperature-override'");
219 MODULE_PARM_DESC(debug, "Debugging verbosity level (0=least 2=most)");
220 MODULE_PARM_DESC(force_series, "Force a different laptop series for extra features (5020, 5720 or 2490)");
222 #ifdef CONFIG_PROC
223 struct ProcItem {
224 const char *name;
225 char *(*read_func) (char *, u32);
226 unsigned long (*write_func) (const char *, unsigned long, u32);
227 unsigned int capability;
230 static struct proc_dir_entry *acer_proc_dir;
231 #endif
234 * Wait for the keyboard controller to become ready
236 static int wait_kbd_write(void)
238 int i = 0;
239 while ((inb(ACER_KBD_STATUS_REG) & 0x02) && (i < 10000)) {
240 udelay(50);
241 i++;
243 return -(i == 10000);
246 static void send_kbd_cmd(u8 cmd, u8 val)
248 preempt_disable();
249 if (!wait_kbd_write())
250 outb(cmd, ACER_KBD_CNTL_REG);
251 if (!wait_kbd_write())
252 outb(val, ACER_KBD_DATA_REG);
253 preempt_enable_no_resched();
256 static void set_keyboard_quirk(void)
258 send_kbd_cmd(0x59, 0x90);
261 struct acer_data {
262 int mailled;
263 int wireless;
264 int bluetooth;
265 int threeg;
266 int brightness;
269 /* Each low-level interface must define at least some of the following */
270 struct Interface {
271 u32 type; /* WMI device type */
272 u32 capability; /* The capabilities this interface provides */
273 struct acer_data data; /* Private data for interface */
276 /* The static interface pointer, points to the currently detected interface */
277 static struct Interface *interface;
280 * Embedded Controller quirks
281 * Some laptops require us to directly access the EC to either enable or query
282 * features that are not available through ACPI.
285 struct quirk_entry {
286 u8 wireless;
287 u8 mailled;
288 u8 brightness;
289 u8 touchpad;
290 u8 temperature_override;
291 u8 mmkeys;
292 u8 bluetooth;
293 u8 max_brightness;
296 static struct quirk_entry *quirks;
298 static void set_quirks(void)
300 if (quirks->mailled != 0) {
301 interface->capability |= ACER_CAP_MAILLED;
302 DEBUG(1, "Using EC direct-access quirk for mail LED\n");
305 if (quirks->touchpad != 0) {
306 interface->capability |= ACER_CAP_TOUCHPAD_READ;
307 DEBUG(1, "Using EC direct-access quirk for reading touchpad status\n");
310 if (quirks->temperature_override != 0) {
311 interface->capability |= ACER_CAP_TEMPERATURE_OVERRIDE;
312 DEBUG(1, "Using EC direct-access quirk for temperature override setting (fan)\n");
315 if (quirks->brightness != 0) {
316 interface->capability |= ACER_CAP_BRIGHTNESS;
317 DEBUG(1, "Using EC direct-access quirk for backlight brightness\n");
320 if (quirks->mmkeys != 0) {
321 set_keyboard_quirk();
322 printk(ACER_INFO "Setting keyboard quirk to enable multimedia keys\n");
325 if (quirks->bluetooth != 0) {
326 interface->capability |= ACER_CAP_BLUETOOTH;
327 DEBUG(1, "Using EC direct-access quirk for bluetooth\n");
330 if (quirks->wireless != 0) {
331 interface->capability |= ACER_CAP_WIRELESS;
332 DEBUG(1, "Using EC direct-access quirk for wireless\n");
335 if (quirks->max_brightness != 0) {
336 max_brightness = quirks->max_brightness;
337 DEBUG(1, "Changing maximum brightness level\n");
341 static int dmi_matched(struct dmi_system_id *dmi)
343 quirks = dmi->driver_data;
344 return 0;
347 static struct quirk_entry quirk_unknown = {
350 /* Same Mail LED quirk as TM2490, but does not require keyboard quirk */
351 static struct quirk_entry quirk_acer_aspire_5100 = {
352 .mailled = 1,
355 static struct quirk_entry quirk_acer_travelmate_2490 = {
356 .mmkeys = 1,
357 .mailled = 1,
358 .temperature_override = 1,
359 .touchpad = 1,
362 static struct quirk_entry quirk_acer_travelmate_5720 = {
363 .max_brightness = 0x9,
364 .touchpad = 2,
367 static struct dmi_system_id acer_quirks[] = {
369 .callback = dmi_matched,
370 .ident = "Acer Aspire 3100",
371 .matches = {
372 DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
373 DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 3100"),
375 .driver_data = &quirk_acer_aspire_5100,
378 .callback = dmi_matched,
379 .ident = "Acer Aspire 5100",
380 .matches = {
381 DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
382 DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5100"),
384 .driver_data = &quirk_acer_aspire_5100,
387 .callback = dmi_matched,
388 .ident = "Acer Aspire 5630",
389 .matches = {
390 DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
391 DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5630"),
393 .driver_data = &quirk_acer_travelmate_2490,
396 .callback = dmi_matched,
397 .ident = "Acer Aspire 5650",
398 .matches = {
399 DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
400 DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5650"),
402 .driver_data = &quirk_acer_travelmate_2490,
405 .callback = dmi_matched,
406 .ident = "Acer Aspire 5680",
407 .matches = {
408 DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
409 DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5680"),
411 .driver_data = &quirk_acer_travelmate_2490,
414 .callback = dmi_matched,
415 .ident = "Acer Extensa 5220",
416 .matches = {
417 DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
418 DMI_MATCH(DMI_PRODUCT_NAME, "Extensa 5220"),
420 .driver_data = &quirk_acer_travelmate_5720,
423 .callback = dmi_matched,
424 .ident = "Acer TravelMate 2490",
425 .matches = {
426 DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
427 DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 2490"),
429 .driver_data = &quirk_acer_travelmate_2490,
432 .callback = dmi_matched,
433 .ident = "Acer TravelMate 5720",
434 .matches = {
435 DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
436 DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 5720"),
438 .driver_data = &quirk_acer_travelmate_5720,
443 /* Find which quirks are needed for a particular vendor/ model pair */
444 static void find_quirks(void)
446 DEBUG (1, "Looking for quirks\n");
447 if (!force_series) {
448 dmi_check_system(acer_quirks);
449 } else if (force_series == 2490) {
450 DEBUG(0, "Forcing Acer TravelMate 2490\n");
451 quirks = &quirk_acer_travelmate_2490;
454 if (quirks == NULL) {
455 DEBUG(1, "No quirks known for this laptop\n");
456 quirks = &quirk_unknown;
458 set_quirks();
462 * General interface convenience methods
465 static bool has_cap(u32 cap)
467 if ((interface->capability & cap) != 0) {
468 return 1;
470 return 0;
474 * Old interface (now known as the AMW0 interface)
476 struct WMAB_args {
477 u32 eax;
478 u32 ebx;
479 u32 ecx;
480 u32 edx;
483 static acpi_status WMAB_execute(struct WMAB_args *regbuf, struct acpi_buffer *result)
485 struct acpi_buffer input;
486 acpi_status status;
487 input.length = sizeof(struct WMAB_args);
488 input.pointer = (u8*)regbuf;
490 status = wmi_acer_evaluate_method(AMW0_GUID1, 1, 1, &input, result);
491 DEBUG(2, " Args: 0x%08x 0x%08x 0x%08x 0x%08x\n", regbuf->eax, regbuf->ebx, regbuf->ecx, regbuf->edx );
493 return status;
496 static acpi_status AMW0_get_bool(bool *value, u32 cap, struct Interface *iface)
498 u8 result;
500 DEBUG(2, " AMW0_get_bool: cap=%d\n", cap);
501 switch (cap) {
502 case ACER_CAP_MAILLED:
503 switch (quirks->mailled) {
504 default:
505 ec_read(0x0A, &result);
506 *value = (result >> 7) & 0x01;
507 return 0;
509 break;
510 case ACER_CAP_WIRELESS:
511 switch (quirks->wireless) {
512 default:
513 ec_read(0x0A, &result);
514 *value = (result >> 2) & 0x01;
515 return 0;
517 break;
518 case ACER_CAP_BLUETOOTH:
519 switch (quirks->bluetooth) {
520 default:
521 ec_read(0x0A, &result);
522 *value = (result >> 4) & 0x01;
523 return 0;
525 break;
526 default:
527 return AE_BAD_ADDRESS;
529 return AE_OK;
532 static acpi_status AMW0_set_bool(bool value, u32 cap, struct Interface *iface)
534 struct WMAB_args args;
536 args.eax = ACER_AMW0_WRITE;
537 args.ebx = value ? (1<<8) : 0;
538 args.ecx = args.edx = 0;
540 switch (cap) {
541 case ACER_CAP_MAILLED:
542 args.ebx |= ACER_AMW0_MAILLED_MASK;
543 break;
544 case ACER_CAP_WIRELESS:
545 args.ebx |= ACER_AMW0_WIRELESS_MASK;
546 break;
547 case ACER_CAP_BLUETOOTH:
548 args.ebx |= ACER_AMW0_BLUETOOTH_MASK;
549 break;
550 default:
551 return AE_BAD_ADDRESS;
554 /* Actually do the set */
555 return WMAB_execute(&args, NULL);
558 static acpi_status AMW0_get_u8(u8 *value, u32 cap, struct Interface *iface) {
559 switch (cap) {
560 case ACER_CAP_BRIGHTNESS:
561 switch (quirks->brightness) {
562 default:
563 return ec_read(0x83, value);
565 break;
566 default:
567 return AE_BAD_ADDRESS;
569 return AE_OK;
572 static acpi_status AMW0_set_u8(u8 value, u32 cap, struct Interface *iface) {
573 switch (cap) {
574 case ACER_CAP_BRIGHTNESS:
575 switch (quirks->brightness) {
576 case 1:
577 return ec_write(0x83, value);
578 default:
579 return AE_BAD_ADDRESS;
580 break;
582 default:
583 return AE_BAD_ADDRESS;
585 return AE_OK;
588 static struct Interface AMW0_interface = {
589 .type = ACER_AMW0,
590 .capability = (
591 ACER_CAP_MAILLED |
592 ACER_CAP_WIRELESS |
593 ACER_CAP_BLUETOOTH
597 static struct Interface AMW0_V2_interface = {
598 .type = ACER_AMW0_V2,
599 .capability = (
600 ACER_CAP_MAILLED |
601 ACER_CAP_WIRELESS |
602 ACER_CAP_BLUETOOTH |
603 ACER_CAP_BRIGHTNESS
608 * New interface (The WMID interface)
610 static acpi_status
611 WMI_execute_u32(u32 method_id, u32 in, u32 *out)
613 struct acpi_buffer input = { (acpi_size) sizeof(u32), (void *)(&in) };
614 struct acpi_buffer result = { ACPI_ALLOCATE_BUFFER, NULL };
615 union acpi_object *obj;
616 u32 tmp;
617 acpi_status status;
619 DEBUG(2, " WMI_execute_u32:\n");
620 status = wmi_acer_evaluate_method(WMID_GUID1, 1, method_id, &input, &result);
621 DEBUG(2, " In: 0x%08x\n", in);
623 if (ACPI_FAILURE(status))
624 return status;
626 obj = (union acpi_object *) result.pointer;
627 if (obj && obj->type == ACPI_TYPE_BUFFER && obj->buffer.length == sizeof(u32)) {
628 tmp = *((u32 *) obj->buffer.pointer);
629 DEBUG(2, " Out: 0x%08x\n", tmp);
630 } else {
631 tmp = 0;
632 if (obj) {
633 DEBUG(2, " Got unexpected result of type %d\n", obj->type);
634 } else {
635 DEBUG(2, " Got unexpected null result\n");
639 if (out)
640 *out = tmp;
642 if (result.length > 0 && result.pointer)
643 kfree(result.pointer);
645 DEBUG(2, " Returning from WMI_execute_u32:\n");
646 return status;
649 static acpi_status WMID_get_u8(u8 *value, u32 cap, struct Interface *iface) {
650 acpi_status status;
651 u32 result;
652 u32 method_id = 0;
654 DEBUG(2, " WMID_get_u8: cap=%d\n", cap);
655 switch (cap) {
656 case ACER_CAP_WIRELESS:
657 method_id = ACER_WMID_GET_WIRELESS_METHODID;
658 break;
659 case ACER_CAP_BLUETOOTH:
660 method_id = ACER_WMID_GET_BLUETOOTH_METHODID;
661 break;
662 case ACER_CAP_BRIGHTNESS:
663 method_id = ACER_WMID_GET_BRIGHTNESS_METHODID;
664 break;
665 case ACER_CAP_THREEG:
666 method_id = ACER_WMID_GET_THREEG_METHODID;
667 break;
668 case ACER_CAP_MAILLED:
669 if (quirks->mailled == 1) {
670 ec_read(0x9f, value);
671 *value &= 0x01;
672 return 0;
674 case ACER_CAP_TOUCHPAD_READ:
675 switch (quirks->touchpad) {
676 case 1:
677 ec_read(0x9e, value);
678 *value = 1 - ((*value >> 3) & 0x01);
679 return 0;
680 case 2:
681 ec_read(0x74, value);
682 *value = ((*value >> 3) & 0x01);
683 return 0;
684 default:
685 break;
687 case ACER_CAP_TEMPERATURE_OVERRIDE:
688 if (quirks->temperature_override == 1) {
689 ec_read(0xa9, value);
690 return 0;
692 default:
693 return AE_BAD_ADDRESS;
695 status = WMI_execute_u32(method_id, 0, &result);
696 DEBUG(2, " WMI_execute_u32 status=%d:\n", status);
698 if (ACPI_SUCCESS(status))
699 *value = (u8)result;
701 DEBUG(2, " Returning from WMID_get_u8:\n");
702 return status;
705 static acpi_status WMID_set_u8(u8 value, u32 cap, struct Interface *iface) {
706 u32 method_id = 0;
708 switch (cap) {
709 case ACER_CAP_BRIGHTNESS:
710 method_id = ACER_WMID_SET_BRIGHTNESS_METHODID;
711 break;
712 case ACER_CAP_WIRELESS:
713 method_id = ACER_WMID_SET_WIRELESS_METHODID;
714 break;
715 case ACER_CAP_BLUETOOTH:
716 method_id = ACER_WMID_SET_BLUETOOTH_METHODID;
717 break;
718 case ACER_CAP_THREEG:
719 method_id = ACER_WMID_SET_THREEG_METHODID;
720 break;
721 case ACER_CAP_MAILLED:
722 if (quirks->mailled == 1) {
723 send_kbd_cmd(0x59, value ? 0x92 : 0x93);
724 return 0;
726 case ACER_CAP_TEMPERATURE_OVERRIDE:
727 if (quirks->temperature_override == 1) {
728 ec_write(0xa9, value);
729 return 0;
731 default:
732 return AE_BAD_ADDRESS;
734 return WMI_execute_u32(method_id, (u32)value, NULL);
738 static struct Interface WMID_interface = {
739 .type = ACER_WMID,
740 .capability = (
741 ACER_CAP_WIRELESS
742 | ACER_CAP_BRIGHTNESS
743 | ACER_CAP_BLUETOOTH
744 | ACER_CAP_THREEG
748 #ifdef CONFIG_PROC
750 * High-level Procfs file handlers
753 static int
754 dispatch_read(char *page, char **start, off_t off, int count, int *eof,
755 struct ProcItem *item)
757 char *p = page;
758 int len;
760 DEBUG(2, " dispatch_read: \n");
761 if (off == 0)
762 p = item->read_func(p, item->capability);
763 len = (p - page);
764 if (len <= off + count)
765 *eof = 1;
766 *start = page + off;
767 len -= off;
768 if (len > count)
769 len = count;
770 if (len < 0)
771 len = 0;
772 return len;
775 static int
776 dispatch_write(struct file *file, const char __user *buffer,
777 unsigned long count, struct ProcItem *item)
779 int result;
780 char *tmp_buffer;
783 * Arg buffer points to userspace memory, which can't be accessed
784 * directly. Since we're making a copy, zero-terminate the
785 * destination so that sscanf can be used on it safely.
787 tmp_buffer = kmalloc(count + 1, GFP_KERNEL);
788 if (copy_from_user(tmp_buffer, buffer, count)) {
789 result = -EFAULT;
790 } else {
791 tmp_buffer[count] = 0;
792 result = item->write_func(tmp_buffer, count, item->capability);
794 kfree(tmp_buffer);
795 return result;
797 #endif
800 * Generic Device (interface-independent)
803 static acpi_status get_bool(bool *value, u32 cap) {
804 acpi_status status = AE_BAD_ADDRESS;
805 u8 tmp = 0;
807 DEBUG(2, " get_bool: cap=%d, interface type=%d\n",
808 cap, interface->type);
809 switch (interface->type) {
810 case ACER_AMW0:
811 status = AMW0_get_bool(value, cap, interface);
812 break;
813 case ACER_AMW0_V2:
814 if (cap == ACER_CAP_MAILLED) {
815 status = AMW0_get_bool(value, cap, interface);
816 break;
818 case ACER_WMID:
819 status = WMID_get_u8(&tmp, cap, interface);
820 *value = (tmp == 1) ? 1 : 0;
821 break;
823 DEBUG(2, " Returning from get_bool:\n");
824 return status;
827 static acpi_status set_bool(int value, u32 cap) {
828 acpi_status status = AE_BAD_PARAMETER;
830 DEBUG(2, " set_bool: cap=%d, interface type=%d, value=%d\n",
831 cap, interface->type, value);
832 if ((value == 0 || value == 1) && (interface->capability & cap)) {
833 switch (interface->type) {
834 case ACER_AMW0:
835 status = AMW0_set_bool(value == 1, cap, interface);
836 break;
837 case ACER_AMW0_V2:
838 if (cap == ACER_CAP_MAILLED) {
839 status = AMW0_set_bool(value == 1, cap,
840 interface);
841 break;
843 case ACER_WMID:
844 status = WMID_set_u8(value == 1, cap, interface);
845 break;
848 return status;
851 static acpi_status get_u8(u8 *value, u32 cap) {
852 DEBUG(2, " get_u8: cap=%d\n", cap);
853 switch (interface->type) {
854 case ACER_AMW0:
855 return AMW0_get_u8(value, cap, interface);
856 break;
857 case ACER_AMW0_V2:
858 case ACER_WMID:
859 return WMID_get_u8(value, cap, interface);
860 break;
861 default:
862 return AE_BAD_ADDRESS;
866 static acpi_status set_u8(u8 value, u8 min, u8 max, u32 cap) {
868 DEBUG(2, " set_u8: cap=%d, interface type=%d, value=%d\n",
869 cap, interface->type, value);
871 if ((value >= min && value <= max) && (interface->capability & cap) ) {
872 switch (interface->type) {
873 case ACER_AMW0:
874 return AMW0_set_u8(value, cap, interface);
875 case ACER_AMW0_V2:
876 case ACER_WMID:
877 return WMID_set_u8(value, cap, interface);
878 default:
879 return AE_BAD_PARAMETER;
882 return AE_BAD_PARAMETER;
885 /* Each _u8 needs a small wrapper that sets the boundary values */
886 static acpi_status set_brightness(u8 value)
888 return set_u8(value, 0, max_brightness, ACER_CAP_BRIGHTNESS);
891 static acpi_status set_temperature_override(u8 value)
893 return set_u8(value, 0, ACER_MAX_TEMPERATURE_OVERRIDE, ACER_CAP_TEMPERATURE_OVERRIDE);
896 static void __init acer_commandline_init(void)
898 DEBUG(1, "Commandline args: mailled(%d) wireless(%d) bluetooth(%d) brightness(%d)\n",
899 mailled, wireless, bluetooth, brightness);
902 * These will all fail silently if the value given is invalid, or the
903 * capability isn't available on the given interface
905 set_bool(mailled, ACER_CAP_MAILLED);
906 set_bool(wireless, ACER_CAP_WIRELESS);
907 set_bool(bluetooth, ACER_CAP_BLUETOOTH);
908 set_bool(threeg, ACER_CAP_THREEG);
909 set_temperature_override(fan_temperature_override);
910 set_brightness((u8)brightness);
913 #ifdef CONFIG_PROC
915 * Procfs interface (deprecated)
917 static char *read_bool(char *p, u32 cap)
919 bool result;
920 acpi_status status;
922 DEBUG(2, " read_bool: cap=%d\n", cap);
923 status = get_bool(&result, cap);
924 if (ACPI_SUCCESS(status))
925 p += sprintf(p, "%d\n", result);
926 else
927 p += sprintf(p, "Read error" );
928 return p;
931 static unsigned long write_bool(const char *buffer, unsigned long count, u32 cap)
933 int value;
935 DEBUG(2, " write_bool: cap=%d, interface type=%d\n buffer=%s\n",
936 cap, interface->type, buffer);
938 if (sscanf(buffer, "%i", &value) == 1) {
939 acpi_status status = set_bool(value, cap);
940 if (ACPI_FAILURE(status))
941 return -EINVAL;
942 } else {
943 return -EINVAL;
945 return count;
948 static char *read_u8(char *p, u32 cap)
950 u8 result;
951 acpi_status status;
953 DEBUG(2, " read_u8: cap=%d\n", cap);
954 status = get_u8(&result, cap);
955 if (ACPI_SUCCESS(status))
956 p += sprintf(p, "%u\n", result);
957 else
958 p += sprintf(p, "Read error" );
959 return p;
962 static unsigned long write_u8(const char *buffer, unsigned long count, u32 cap)
964 int value;
965 acpi_status (*set_method)(u8);
967 /* Choose the appropriate set_u8 wrapper here, based on the capability */
968 switch (cap) {
969 case ACER_CAP_BRIGHTNESS:
970 set_method = set_brightness;
971 break;
972 case ACER_CAP_TEMPERATURE_OVERRIDE:
973 set_method = set_temperature_override;
974 break;
975 default:
976 return -EINVAL;
979 if (sscanf(buffer, "%i", &value) == 1) {
980 acpi_status status = (*set_method)(value);
981 if (ACPI_FAILURE(status))
982 return -EINVAL;
983 } else {
984 return -EINVAL;
986 return count;
989 static char *read_version(char *p, u32 cap)
991 p += sprintf(p, "%s\n", ACER_ACPI_VERSION);
992 return p;
995 static char *read_interface(char *p, u32 cap)
997 p += sprintf(p, "%s\n", (interface->type == ACER_AMW0 ) ? "AMW0": "WMID");
998 return p;
1001 static struct ProcItem proc_items[] = {
1002 {"mailled", read_bool, write_bool, ACER_CAP_MAILLED},
1003 {"bluetooth", read_bool, write_bool, ACER_CAP_BLUETOOTH},
1004 {"wireless", read_bool, write_bool, ACER_CAP_WIRELESS},
1005 {"brightness", read_u8, write_u8, ACER_CAP_BRIGHTNESS},
1006 {"threeg", read_bool, write_bool, ACER_CAP_THREEG},
1007 {"touchpad", read_bool, NULL, ACER_CAP_TOUCHPAD_READ},
1008 {"fan_temperature_override", read_u8, write_u8, ACER_CAP_TEMPERATURE_OVERRIDE},
1009 {"version", read_version, NULL, ACER_CAP_ANY},
1010 {"interface", read_interface, NULL, ACER_CAP_ANY},
1011 {NULL}
1014 static int __init add_proc_entries(void)
1016 struct proc_dir_entry *proc;
1017 struct ProcItem *item;
1019 for (item = proc_items; item->name; ++item) {
1021 * Only add the proc file if the current interface actually
1022 * supports it
1024 if (interface->capability & item->capability) {
1025 proc = create_proc_read_entry(item->name,
1026 S_IFREG | S_IRUGO | S_IWUSR,
1027 acer_proc_dir,
1028 (read_proc_t *) dispatch_read,
1029 item);
1030 if (proc)
1031 proc->owner = THIS_MODULE;
1032 if (proc && item->write_func)
1033 proc->write_proc = (write_proc_t *) dispatch_write;
1037 return 0;
1040 static int __exit remove_proc_entries(void)
1042 struct ProcItem *item;
1044 for (item = proc_items; item->name; ++item)
1045 remove_proc_entry(item->name, acer_proc_dir);
1046 return 0;
1048 #endif
1051 * LED device (Mail LED only, no other LEDs known yet)
1053 static void mail_led_set(struct led_classdev *led_cdev, enum led_brightness value)
1055 bool tmp = value;
1056 set_bool(tmp, ACER_CAP_MAILLED);
1059 static struct led_classdev mail_led = {
1060 .name = "acer_acpi:mail",
1061 .brightness_set = mail_led_set,
1064 static void acer_led_init(struct device *dev)
1066 led_classdev_register(dev, &mail_led);
1069 static void acer_led_exit(void)
1071 led_classdev_unregister(&mail_led);
1074 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,18)
1076 * Backlight device
1078 static struct backlight_device *acer_backlight_device;
1080 static int read_brightness(struct backlight_device *bd)
1082 u8 value;
1083 get_u8(&value, ACER_CAP_BRIGHTNESS);
1084 return value;
1087 #if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,20)
1088 static int update_bl_status(struct backlight_device *bd)
1090 set_brightness(bd->props->brightness);
1091 return 0;
1094 static struct backlight_properties acer_backlight_properties = {
1095 .get_brightness = read_brightness,
1096 .update_status = update_bl_status,
1099 static int __init acer_backlight_init(struct device *dev)
1101 struct backlight_device *bd;
1103 DEBUG(1, "Loading backlight driver\n");
1104 bd = backlight_device_register("acer_acpi", dev, NULL, &acer_backlight_properties);
1105 if (IS_ERR(bd)) {
1106 printk(ACER_ERR "Could not register Acer backlight device\n");
1107 acer_backlight_device = NULL;
1108 return PTR_ERR(bd);
1111 acer_backlight_device = bd;
1113 bd->props->max_brightness = max_brightness;
1114 return 0;
1116 #else
1117 static int update_bl_status(struct backlight_device *bd)
1119 set_brightness(bd->props.brightness);
1120 return 0;
1123 static struct backlight_ops acer_backlight_ops = {
1124 .get_brightness = read_brightness,
1125 .update_status = update_bl_status,
1128 static int __init acer_backlight_init(struct device *dev)
1130 struct backlight_device *bd;
1132 DEBUG(1, "Loading backlight driver\n");
1133 bd = backlight_device_register("acer_acpi", dev, NULL, &acer_backlight_ops);
1134 if (IS_ERR(bd)) {
1135 printk(ACER_ERR "Could not register Acer backlight device\n");
1136 acer_backlight_device = NULL;
1137 return PTR_ERR(bd);
1140 acer_backlight_device = bd;
1142 bd->props.max_brightness = max_brightness;
1143 bd->props.brightness = read_brightness(NULL);
1144 backlight_update_status(bd);
1145 return 0;
1147 #endif
1149 static void __exit acer_backlight_exit(void)
1151 backlight_device_unregister(acer_backlight_device);
1153 #endif
1156 * Read/ write bool sysfs macro
1158 #define show_set_bool(value, cap) \
1159 static ssize_t \
1160 show_bool_##value(struct device *dev, struct device_attribute *attr, \
1161 char *buf) \
1163 bool result; \
1164 acpi_status status = get_bool(&result, cap); \
1165 if (ACPI_SUCCESS(status)) \
1166 return sprintf(buf, "%d\n", result); \
1167 return sprintf(buf, "Read error" ); \
1170 static ssize_t \
1171 set_bool_##value(struct device *dev, struct device_attribute *attr, \
1172 const char *buf, size_t count) \
1174 bool tmp = simple_strtoul(buf, NULL, 10); \
1175 acpi_status status = set_bool(tmp, cap); \
1176 if (ACPI_FAILURE(status)) \
1177 return -EINVAL; \
1178 return count; \
1180 static DEVICE_ATTR(value, S_IWUGO | S_IRUGO | S_IWUSR, \
1181 show_bool_##value, set_bool_##value);
1183 show_set_bool(wireless, ACER_CAP_WIRELESS);
1184 show_set_bool(bluetooth, ACER_CAP_BLUETOOTH);
1185 show_set_bool(threeg, ACER_CAP_THREEG);
1186 show_set_bool(fan_temperature_override, ACER_CAP_TEMPERATURE_OVERRIDE);
1189 * Read-only bool sysfs macro
1191 #define show_bool(value, cap) \
1192 static ssize_t \
1193 show_bool_##value(struct device *dev, struct device_attribute *attr, \
1194 char *buf) \
1196 bool result; \
1197 acpi_status status = get_bool(&result, cap); \
1198 if (ACPI_SUCCESS(status)) \
1199 return sprintf(buf, "%d\n", result); \
1200 return sprintf(buf, "Read error" ); \
1202 static DEVICE_ATTR(value, S_IWUGO | S_IRUGO | S_IWUSR, \
1203 show_bool_##value, NULL);
1205 show_bool(touchpad, ACER_CAP_TOUCHPAD_READ);
1208 * Read interface sysfs macro
1210 static ssize_t show_interface(struct device *dev, struct device_attribute *attr,
1211 char *buf)
1213 switch (interface->type) {
1214 case ACER_AMW0:
1215 return sprintf(buf, "AMW0\n");
1216 case ACER_AMW0_V2:
1217 return sprintf(buf, "AMW0 v2\n");
1218 case ACER_WMID:
1219 return sprintf(buf, "WMID\n");
1220 default:
1221 return sprintf(buf, "Error!\n");
1225 static DEVICE_ATTR(interface, S_IWUGO | S_IRUGO | S_IWUSR, show_interface, NULL);
1227 static ssize_t show_devices(struct device *dev, struct device_attribute *attr,
1228 char *buf)
1230 struct acpi_buffer out = {ACPI_ALLOCATE_BUFFER, NULL};
1231 union acpi_object *obj;
1232 acpi_status status;
1233 u32 tmp;
1235 status = wmi_acer_query_block(WMID_GUID2, 1, &out);
1236 if (ACPI_FAILURE(status))
1237 return sprintf(buf, "Error\n");
1239 obj = (union acpi_object *) out.pointer;
1240 if (obj && obj->type == ACPI_TYPE_BUFFER && obj->buffer.length == sizeof(u32)) {
1241 tmp = *((u32 *) obj->buffer.pointer);
1242 } else {
1243 return sprintf(buf, "Error\n");
1246 return sprintf(buf, "%u\n", tmp);
1249 static DEVICE_ATTR(devices, S_IWUGO | S_IRUGO | S_IWUSR, show_devices, NULL);
1252 * Platform device
1254 static int __devinit acer_platform_probe(struct platform_device *device)
1256 if (has_cap(ACER_CAP_MAILLED))
1257 acer_led_init(&device->dev);
1258 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,18)
1259 if (has_cap(ACER_CAP_BRIGHTNESS))
1260 acer_backlight_init(&device->dev);
1261 #endif
1262 return 0;
1265 static int acer_platform_remove(struct platform_device *device)
1267 if (has_cap(ACER_CAP_MAILLED))
1268 acer_led_exit();
1269 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,18)
1270 if (has_cap(ACER_CAP_BRIGHTNESS))
1271 acer_backlight_exit();
1272 #endif
1273 return 0;
1276 static int acer_platform_suspend(struct platform_device *device, pm_message_t state)
1279 * WMID fix for suspend-to-disk - save all current states now so we can
1280 * restore them on resume
1282 bool value;
1283 u8 u8value;
1284 struct acer_data *data = &interface->data;
1286 #define save_bool_device(device, cap) \
1287 if (has_cap(cap)) {\
1288 get_bool(&value, cap);\
1289 data->device = value;\
1292 #define save_u8_device(device, cap) \
1293 if (has_cap(cap)) {\
1294 get_u8(&u8value, cap);\
1295 data->device = u8value;\
1298 save_bool_device(wireless, ACER_CAP_WIRELESS);
1299 save_bool_device(bluetooth, ACER_CAP_BLUETOOTH);
1300 save_bool_device(threeg, ACER_CAP_THREEG);
1301 save_bool_device(mailled, ACER_CAP_MAILLED);
1302 save_u8_device(brightness, ACER_CAP_BRIGHTNESS);
1304 return 0;
1307 static int acer_platform_resume(struct platform_device *device)
1309 struct acer_data *data = &interface->data;
1311 #define restore_bool_device(device, cap) \
1312 if (has_cap(cap))\
1313 set_bool(data->device, cap);\
1315 restore_bool_device(wireless, ACER_CAP_WIRELESS);
1316 restore_bool_device(bluetooth, ACER_CAP_BLUETOOTH);
1317 restore_bool_device(threeg, ACER_CAP_THREEG);
1318 restore_bool_device(mailled, ACER_CAP_MAILLED);
1320 if (has_cap(ACER_CAP_BRIGHTNESS))
1321 set_brightness((u8)data->brightness);
1323 /* Check if this laptop requires the keyboard quirk */
1324 if (quirks->mmkeys != 0) {
1325 set_keyboard_quirk();
1326 printk(ACER_INFO "Setting keyboard quirk to enable multimedia keys\n");
1329 return 0;
1332 static struct platform_driver acer_platform_driver = {
1333 .driver = {
1334 .name = "acer_acpi",
1335 .owner = THIS_MODULE,
1337 .probe = acer_platform_probe,
1338 .remove = acer_platform_remove,
1339 .suspend = acer_platform_suspend,
1340 .resume = acer_platform_resume,
1343 static struct platform_device *acer_platform_device;
1345 static int remove_sysfs(struct platform_device *device)
1347 #define remove_device_file(value, cap) \
1348 if (has_cap(cap)) \
1349 device_remove_file(&device->dev, &dev_attr_##value);
1351 if (wmi_acer_has_guid(WMID_GUID2)) {
1352 device_remove_file(&device->dev, &dev_attr_devices);
1355 remove_device_file(wireless, ACER_CAP_WIRELESS);
1356 remove_device_file(bluetooth, ACER_CAP_BLUETOOTH);
1357 remove_device_file(threeg, ACER_CAP_THREEG);
1358 remove_device_file(interface, ACER_CAP_ANY);
1359 remove_device_file(fan_temperature_override, ACER_CAP_TEMPERATURE_OVERRIDE);
1360 remove_device_file(touchpad, ACER_CAP_TOUCHPAD_READ);
1361 return 0;
1364 static int create_sysfs(void)
1366 int retval = -ENOMEM;
1368 #define add_device_file(value, cap) \
1369 if (has_cap(cap)) {\
1370 retval = device_create_file(&acer_platform_device->dev, &dev_attr_##value);\
1371 if (retval)\
1372 goto error;\
1375 if (wmi_acer_has_guid(WMID_GUID2)) {
1376 retval = device_create_file(&acer_platform_device->dev, &dev_attr_devices);
1377 if (retval)
1378 goto error;
1381 add_device_file(wireless, ACER_CAP_WIRELESS);
1382 add_device_file(bluetooth, ACER_CAP_BLUETOOTH);
1383 add_device_file(threeg, ACER_CAP_THREEG);
1384 add_device_file(interface, ACER_CAP_ANY);
1385 add_device_file(fan_temperature_override, ACER_CAP_TEMPERATURE_OVERRIDE);
1386 add_device_file(touchpad, ACER_CAP_TOUCHPAD_READ);
1388 return 0;
1390 error:
1391 remove_sysfs(acer_platform_device);
1392 return retval;
1395 static int __init acer_acpi_init(void)
1397 printk(ACER_INFO "Acer Laptop ACPI Extras version %s\n",
1398 ACER_ACPI_VERSION);
1400 /* Find if this laptop requires any quirks */
1401 DEBUG(1, "Finding quirks\n");
1402 find_quirks();
1405 * Detect which WMI interface we're using.
1407 if (wmi_acer_has_guid(AMW0_GUID1)) {
1408 interface = &AMW0_interface;
1410 if (wmi_acer_has_guid(WMID_GUID1)) {
1411 DEBUG(0, "Detected Acer AMW0 version 2 interface\n");
1412 interface = &AMW0_V2_interface;
1413 } else {
1414 DEBUG(0, "Detected Acer AMW0 version 1 interface\n");
1415 if (!quirks->brightness) {
1416 quirks->brightness = 1;
1417 interface->capability |= ACER_CAP_BRIGHTNESS;
1420 } else if (wmi_acer_has_guid(WMID_GUID1)) {
1421 DEBUG(0, "Detected Acer WMID interface\n");
1422 interface = &WMID_interface;
1423 } else {
1424 printk(ACER_ERR "No or unsupported WMI interface, unable to load.\n");
1425 return -ENODEV;
1428 #ifdef CONFIG_PROC
1429 /* Create the proc entries */
1430 acer_proc_dir = proc_mkdir(PROC_ACER, acpi_root_dir);
1431 if (!acer_proc_dir) {
1432 printk(ACER_ERR "Unable to create /proc entries, aborting.\n");
1433 goto error_proc_mkdir;
1436 acer_proc_dir->owner = THIS_MODULE;
1437 if (add_proc_entries()) {
1438 printk(ACER_ERR "Unable to create /proc entries, aborting.\n");
1439 goto error_proc_add;
1441 #endif
1444 * Register the driver
1446 if (platform_driver_register(&acer_platform_driver)) {
1447 printk(ACER_ERR "Unable to register platform driver, aborting.\n");
1448 goto error_platform_register;
1450 acer_platform_device = platform_device_alloc("acer_acpi", -1);
1451 platform_device_add(acer_platform_device);
1453 create_sysfs();
1455 DEBUG(1, "Driver registered\n");
1457 /* Override any initial settings with values from the commandline */
1458 acer_commandline_init();
1460 return 0;
1462 error_platform_register:
1463 #ifdef CONFIG_PROC
1464 remove_proc_entries();
1465 error_proc_add:
1466 if (acer_proc_dir)
1467 remove_proc_entry(PROC_ACER, acpi_root_dir);
1468 error_proc_mkdir:
1469 #endif
1470 return -ENODEV;
1473 static void __exit acer_acpi_exit(void)
1475 remove_sysfs(acer_platform_device);
1476 platform_device_del(acer_platform_device);
1477 platform_driver_unregister(&acer_platform_driver);
1479 #ifdef CONFIG_PROC
1480 remove_proc_entries();
1482 if (acer_proc_dir)
1483 remove_proc_entry(PROC_ACER, acpi_root_dir);
1484 #endif
1485 printk(ACER_INFO "Acer Laptop ACPI Extras unloaded\n");
1486 return;
1489 module_init(acer_acpi_init);
1490 module_exit(acer_acpi_exit);