2 * acer_acpi.c - Acer Laptop ACPI Extras
5 * Copyright (C) 2005-2007 E.M. Smith
6 * Copyright (C) 2007 Carlos Corbacho <cathectic@gmail.com>
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.
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.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23 * The devolpment page for this driver is located at
24 * http://code.google.com/p/aceracpi
28 * John Belmonte - the Toshiba ACPI driver I've adapted for this module.
29 * Julien Lerouge & Karol Kozimor - ASUS Acpi driver authors.
30 * Olaf Tauber - developer of acerhk, the inspiration to solve the 64-bit
31 * driver problem for my Aspire 5024.
32 * Mathieu Segaud - solved the ACPI problem that needed a double-modprobe
33 * in version 0.2 and below.
34 * Carlos Corbacho - added initial status support for wireless/ mail/
35 * bluetooth, added module parameter support to turn
36 * hardware/ LEDs on and off at module loading (thanks
37 * again to acerhk for the inspiration)
38 * Jim Ramsay - Figured out and added support for WMID interface
42 #define ACER_ACPI_VERSION "0.9.0"
45 * Comment the following line out to remove /proc support
50 #define PROC_ACER "acer"
53 #include <linux/kernel.h>
54 #include <linux/module.h>
55 #include <linux/init.h>
56 #include <linux/types.h>
57 #include <linux/proc_fs.h>
58 #include <linux/delay.h>
59 #include <linux/version.h>
61 #if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,17)
62 #include <asm/uaccess.h>
64 #include <linux/uaccess.h>
67 #include <linux/preempt.h>
69 #include <linux/dmi.h>
70 #include <linux/backlight.h>
71 #include <linux/leds.h>
72 #include <linux/platform_device.h>
74 #include <acpi/acpi_drivers.h>
76 /* Workaround needed for older kernels */
81 MODULE_AUTHOR("Mark Smith, Carlos Corbacho");
82 MODULE_DESCRIPTION("Acer Laptop ACPI Extras Driver");
83 MODULE_LICENSE("GPL");
85 #define MY_LOGPREFIX "acer_acpi: "
86 #define MY_ERR KERN_ERR MY_LOGPREFIX
87 #define MY_NOTICE KERN_NOTICE MY_LOGPREFIX
88 #define MY_INFO KERN_INFO MY_LOGPREFIX
90 #define DEBUG(level, message...) { \
92 printk(KERN_DEBUG MY_LOGPREFIX message);\
96 * The maximum temperature one can set for fan control override.
97 * Doesn't propably make much sense if over 80 degrees celsius though...
99 #define ACER_MAX_TEMPERATURE_OVERRIDE 150
102 * The following defines quirks to get some specific functions to work
103 * which are known to not be supported over ACPI (such as the mail LED
104 * on WMID based Acer's)
113 * Keyboard controller ports
115 #define ACER_KBD_STATUS_REG 0x64 /* Status register (R) */
116 #define ACER_KBD_CNTL_REG 0x64 /* Controller command register (W) */
117 #define ACER_KBD_DATA_REG 0x60 /* Keyboard data register (R/W) */
121 * Meaning is unknown - this number is required for writing to ACPI for AMW0
122 * (it's also used in acerhk when directly accessing the EC)
124 #define ACER_AMW0_WRITE 0x9610
127 * Bit masks for the old AMW0 interface
128 * These could vary between the particular interface
130 #define ACER_AMW0_WIRELESS_MASK 0x35
131 #define ACER_AMW0_BLUETOOTH_MASK 0x34
132 #define ACER_AMW0_MAILLED_MASK 0x31
135 * Method IDs for new WMID interface
136 * These could be different for other untested machines
138 #define ACER_WMID_GET_WIRELESS_METHODID 1
139 #define ACER_WMID_GET_BLUETOOTH_METHODID 2
140 #define ACER_WMID_GET_BRIGHTNESS_METHODID 3
141 #define ACER_WMID_SET_WIRELESS_METHODID 4
142 #define ACER_WMID_SET_BLUETOOTH_METHODID 5
143 #define ACER_WMID_SET_BRIGHTNESS_METHODID 6
144 #define ACER_WMID_GET_THREEG_METHODID 10
145 #define ACER_WMID_SET_THREEG_METHODID 11
148 * Acer ACPI method paths
150 * TODO: It may be possbile to autodetect these, since these are all at HID PNP0C14
152 #define AMW0_METHOD "\\_SB_.AMW0.WMAB"
153 #define AMW0_GETDATA "\\_SB_.AMW0._WED"
155 #define WMID_METHOD "\\_SB.WMID.WMBA"
156 #define WMID_GETDATA "\\_SB.WMID._WED"
159 * Interface capability flags
161 #define ACER_CAP_MAILLED (1<<0)
162 #define ACER_CAP_WIRELESS (1<<1)
163 #define ACER_CAP_BLUETOOTH (1<<2)
164 #define ACER_CAP_BRIGHTNESS (1<<3)
165 #define ACER_CAP_THREEG (1<<4)
166 #define ACER_CAP_TOUCHPAD_READ (1<<5)
167 #define ACER_CAP_TEMPERATURE_OVERRIDE (1<<6)
168 #define ACER_CAP_ANY (0xffffffff)
171 * Interface type flags
173 #define ACER_AMW0 (1<<0)
174 #define ACER_WMID (1<<1)
177 * Presumed start states -
178 * On some AMW0 laptops, we do not yet know how to get the device status from
179 * the EC, so we must store this ourselves.
181 * Plus, we can't tell which features are enabled or disabled on a specific
182 * model - e.g. The 5020 series can _support_ bluetooth; but the 5021 has no
183 * bluetooth, whilst the 5024 does. However, the BIOS identifies both laptops
184 * as 5020, and you can add bluetooth later.
186 * Basically the code works like this:
187 * - On init, any values specified on the commandline are set.
188 * - For interfaces where the current values cannot be detected and which
189 * have not been set on the commandline, we set them to some sane default
192 * See AMW0_init and acer_commandline_init
195 #define ACER_DEFAULT_WIRELESS 0
196 #define ACER_DEFAULT_BLUETOOTH 0
197 #define ACER_DEFAULT_MAILLED 0
198 #define ACER_DEFAULT_THREEG 0
200 static int max_brightness
= 0xF;
202 static int wireless
= -1;
203 static int bluetooth
= -1;
204 static int mailled
= -1;
205 static int brightness
= -1;
206 static int threeg
= -1;
207 static int fan_temperature_override
= -1;
208 static int debug
= 0;
209 static int force_series
;
211 module_param(mailled
, int, 0444);
212 module_param(wireless
, int, 0444);
213 module_param(bluetooth
, int, 0444);
214 module_param(brightness
, int, 0444);
215 module_param(threeg
, int, 0444);
216 module_param(force_series
, int, 0444);
217 module_param(fan_temperature_override
, int, 0444);
218 module_param(debug
, int, 0664);
219 MODULE_PARM_DESC(wireless
, "Set initial state of Wireless hardware");
220 MODULE_PARM_DESC(bluetooth
, "Set initial state of Bluetooth hardware");
221 MODULE_PARM_DESC(mailled
, "Set initial state of Mail LED");
222 MODULE_PARM_DESC(brightness
, "Set initial LCD backlight brightness");
223 MODULE_PARM_DESC(threeg
, "Set initial state of 3G hardware");
224 MODULE_PARM_DESC(fan_temperature_override
, "Set initial state of the 'FAN temperature-override'");
225 MODULE_PARM_DESC(debug
, "Debugging verbosity level (0=least 2=most)");
226 MODULE_PARM_DESC(force_series
, "Force a different laptop series for extra features (5020 or 2490)");
231 char *(*read_func
) (char *, u32
);
232 unsigned long (*write_func
) (const char *, unsigned long, u32
);
233 unsigned int capability
;
236 static struct proc_dir_entry
*acer_proc_dir
;
239 static int is_valid_acpi_path(const char *methodName
)
244 status
= acpi_get_handle(NULL
, (char *)methodName
, &handle
);
245 return ACPI_SUCCESS(status
);
249 * Wait for the keyboard controller to become ready
251 static int wait_kbd_write(void)
254 while ((inb(ACER_KBD_STATUS_REG
) & 0x02) && (i
< 10000)) {
258 return -(i
== 10000);
261 static void send_kbd_cmd(u8 cmd
, u8 val
)
264 if (!wait_kbd_write())
265 outb(cmd
, ACER_KBD_CNTL_REG
);
266 if (!wait_kbd_write())
267 outb(val
, ACER_KBD_DATA_REG
);
268 preempt_enable_no_resched();
271 static void set_keyboard_quirk(void)
273 send_kbd_cmd(0x59, 0x90);
276 /* Each low-level interface must define at least some of the following */
279 * The ACPI device type
284 * The capabilities this interface provides
285 * In the future, these can be removed/added at runtime when we have a
286 * way of detecting what capabilities are /actually/ present on an
292 * Initializes an interface, should allocate the interface-specific
295 void (*init
) (struct Interface
*);
298 * Frees an interface, should free the interface-specific data
300 void (*free
) (struct Interface
*);
303 * Interface-specific private data member. Must *not* be touched by
304 * anyone outside of this struct
309 /* The static interface pointer, points to the currently detected interface */
310 static struct Interface
*interface
;
313 * Embedded Controller quirks
314 * Some laptops require us to directly access the EC to either enable or query
315 * features that are not available through ACPI.
323 int temperature_override
;
329 static struct quirk_entry
*quirks
;
331 static void set_quirks(void)
333 if (quirks
->mailled
) {
334 interface
->capability
|= ACER_CAP_MAILLED
;
335 DEBUG(1, "Using EC direct-access quirk for mail LED\n");
338 if (quirks
->touchpad
) {
339 interface
->capability
|= ACER_CAP_TOUCHPAD_READ
;
340 DEBUG(1, "Using EC direct-access quirk for reading touchpad status\n");
343 if (quirks
->temperature_override
) {
344 interface
->capability
|= ACER_CAP_TEMPERATURE_OVERRIDE
;
345 DEBUG(1, "Using EC direct-access quirk for temperature override setting (fan)\n");
348 if (quirks
->brightness
) {
349 interface
->capability
|= ACER_CAP_BRIGHTNESS
;
350 DEBUG(1, "Using EC direct-access quirk for backlight brightness\n");
353 if (quirks
->mmkeys
) {
354 set_keyboard_quirk();
355 printk(MY_INFO
"Setting keyboard quirk to enable multimedia keys\n");
358 if (quirks
->bluetooth
) {
359 interface
->capability
|= ACER_CAP_BLUETOOTH
;
360 DEBUG(1, "Using EC direct-access quirk for bluetooth\n");
363 if (quirks
->wireless
) {
364 interface
->capability
|= ACER_CAP_WIRELESS
;
365 DEBUG(1, "Using EC direct-access quirk for wireless\n");
368 if (quirks
->max_brightness
) {
369 max_brightness
= quirks
->max_brightness
;
370 DEBUG(1, "Changing maximum brightness level\n");
374 static int dmi_matched(struct dmi_system_id
*dmi
)
376 quirks
= dmi
->driver_data
;
380 static struct quirk_entry quirk_unknown
= {
383 static struct quirk_entry quirk_acer_aspire_5020
= {
390 static struct quirk_entry quirk_acer_aspire_5680
= {
394 static struct quirk_entry quirk_acer_aspire_9300
= {
398 static struct quirk_entry quirk_acer_travelmate_2490
= {
401 .temperature_override
= 1,
405 static struct quirk_entry quirk_acer_travelmate_5720
= {
406 .max_brightness
= 0x9,
413 static struct dmi_system_id acer_quirks
[] = {
415 .callback
= dmi_matched
,
416 .ident
= "Acer Aspire 3020",
418 DMI_MATCH(DMI_SYS_VENDOR
, "Acer"),
419 DMI_MATCH(DMI_PRODUCT_NAME
, "Aspire 3020"),
421 .driver_data
= &quirk_acer_aspire_5020
,
424 .callback
= dmi_matched
,
425 .ident
= "Acer Aspire 3040",
427 DMI_MATCH(DMI_SYS_VENDOR
, "Acer"),
428 DMI_MATCH(DMI_PRODUCT_NAME
, "Aspire 3040"),
430 .driver_data
= &quirk_acer_aspire_5020
,
433 .callback
= dmi_matched
,
434 .ident
= "Acer Aspire 5020",
436 DMI_MATCH(DMI_SYS_VENDOR
, "Acer"),
437 DMI_MATCH(DMI_PRODUCT_NAME
, "Aspire 5020"),
439 .driver_data
= &quirk_acer_aspire_5020
,
442 .callback
= dmi_matched
,
443 .ident
= "Acer Aspire 5040",
445 DMI_MATCH(DMI_SYS_VENDOR
, "Acer"),
446 DMI_MATCH(DMI_PRODUCT_NAME
, "Aspire 5040"),
448 .driver_data
= &quirk_acer_aspire_5020
,
451 .callback
= dmi_matched
,
452 .ident
= "Acer Aspire 5560",
454 DMI_MATCH(DMI_SYS_VENDOR
, "Acer"),
455 DMI_MATCH(DMI_PRODUCT_NAME
, "Aspire 5560"),
457 .driver_data
= &quirk_acer_aspire_5020
,
460 .callback
= dmi_matched
,
461 .ident
= "Acer Aspire 5650",
463 DMI_MATCH(DMI_SYS_VENDOR
, "Acer"),
464 DMI_MATCH(DMI_PRODUCT_NAME
, "Aspire 5650"),
466 .driver_data
= &quirk_acer_travelmate_2490
,
469 .callback
= dmi_matched
,
470 .ident
= "Acer Aspire 5680",
472 DMI_MATCH(DMI_SYS_VENDOR
, "Acer"),
473 DMI_MATCH(DMI_PRODUCT_NAME
, "Aspire 5680"),
475 .driver_data
= &quirk_acer_aspire_5680
,
478 .callback
= dmi_matched
,
479 .ident
= "Acer Aspire 9300",
481 DMI_MATCH(DMI_SYS_VENDOR
, "Acer"),
482 DMI_MATCH(DMI_PRODUCT_NAME
, "Aspire 9300"),
484 .driver_data
= &quirk_acer_aspire_9300
,
487 .callback
= dmi_matched
,
488 .ident
= "Acer TravelMate 2420",
490 DMI_MATCH(DMI_SYS_VENDOR
, "Acer"),
491 DMI_MATCH(DMI_PRODUCT_NAME
, "TravelMate 2420"),
493 .driver_data
= &quirk_acer_aspire_5020
,
496 .callback
= dmi_matched
,
497 .ident
= "Acer TravelMate 2490",
499 DMI_MATCH(DMI_SYS_VENDOR
, "Acer"),
500 DMI_MATCH(DMI_PRODUCT_NAME
, "TravelMate 2490"),
502 .driver_data
= &quirk_acer_travelmate_2490
,
505 .callback
= dmi_matched
,
506 .ident
= "Acer TravelMate 5720",
508 DMI_MATCH(DMI_SYS_VENDOR
, "Acer"),
509 DMI_MATCH(DMI_PRODUCT_NAME
, "TravelMate 5720"),
511 .driver_data
= &quirk_acer_travelmate_5720
,
516 /* Find which quirks are needed for a particular vendor/ model pair */
517 static void find_quirks(void)
519 DEBUG (1, "Looking for quirks\n");
521 dmi_check_system(acer_quirks
);
522 } else if (force_series
== 5020) {
523 DEBUG(0, "Forcing Acer Aspire 5020\n");
524 quirks
= &quirk_acer_aspire_5020
;
525 } else if (force_series
== 2490) {
526 DEBUG(0, "Forcing Acer TravelMate 2490\n");
527 quirks
= &quirk_acer_travelmate_2490
;
528 } else if (force_series
== 5720) {
529 DEBUG(0, "Forcing Acer TravelMate 5720\n");
530 quirks
= &quirk_acer_travelmate_5720
;
533 if (quirks
== NULL
) {
534 DEBUG(1, "No quirks known for this laptop\n");
535 quirks
= &quirk_unknown
;
541 * General interface convenience methods
544 static bool has_cap(u32 cap
)
546 if ((interface
->capability
& cap
) != 0) {
552 static void interface_free(struct Interface
*iface
)
554 /* Free our private data structure */
558 /* General wrapper around the ACPI call */
560 WMI_execute(char *methodPath
, u32 methodId
, const struct acpi_buffer
*in
, struct acpi_buffer
*out
) {
561 struct acpi_object_list input
;
562 union acpi_object params
[3];
563 acpi_status status
= AE_OK
;
565 /* WMI calling convention:
566 * methodPath( instance, methodId, input_buffer )
567 * - instance is always 1, since there's only this module
568 * - methodId is the method number within the current method group.
569 * - Input buffer is ignored for read-only commands
570 * - May return a buffer of results (optional)
573 input
.pointer
= params
;
574 params
[0].type
= ACPI_TYPE_INTEGER
;
575 params
[0].integer
.value
= 0x01;
576 params
[1].type
= ACPI_TYPE_INTEGER
;
577 params
[1].integer
.value
= methodId
;
578 params
[2].type
= ACPI_TYPE_BUFFER
;
579 params
[2].buffer
.length
= in
->length
;
580 params
[2].buffer
.pointer
= in
->pointer
;
582 DEBUG(2, "Doing %s( 1, %u, [%llu-byte buffer] )\n", methodPath
, methodId
, (u64
)in
->length
);
584 status
= acpi_evaluate_object(NULL
, methodPath
, &input
, out
);
586 DEBUG(2, " Execution status: %d\n", status
);
587 DEBUG(2, " Result: %llu bytes\n", (u64
)(out
? out
->length
: 0) );
593 * Old interface (now known as the AMW0 interface)
608 static acpi_status
WMAB_execute(struct WMAB_args
* regbuf
, struct acpi_buffer
*result
)
610 struct acpi_buffer input
;
612 input
.length
= sizeof(struct WMAB_args
);
613 input
.pointer
= (u8
*)regbuf
;
615 status
= WMI_execute( AMW0_METHOD
, 1, &input
, result
);
616 DEBUG(2, " Args: 0x%08x 0x%08x 0x%08x 0x%08x\n", regbuf
->eax
, regbuf
->ebx
, regbuf
->ecx
, regbuf
->edx
);
621 static void AMW0_init(struct Interface
*iface
) {
623 struct AMW0_Data
*data
;
625 /* Allocate our private data structure */
626 iface
->data
= kmalloc(sizeof(struct AMW0_Data
), GFP_KERNEL
);
627 data
= (struct AMW0_Data
*)iface
->data
;
630 * If the commandline doesn't specify these, we need to force them to
633 if (mailled
== -1 && !quirks
->mailled
)
634 mailled
= ACER_DEFAULT_MAILLED
;
635 if (wireless
== -1 && !quirks
->wireless
)
636 wireless
= ACER_DEFAULT_WIRELESS
;
637 if (bluetooth
== -1 && !quirks
->bluetooth
)
638 bluetooth
= ACER_DEFAULT_BLUETOOTH
;
641 * Set the cached "current" values to impossible ones so that
642 * acer_commandline_init will definitely set them.
644 if (!quirks
->bluetooth
) {
646 data
->bluetooth
= -1;
647 printk(MY_INFO
"No EC data for reading bluetooth - bluetooth value when read will be a 'best guess'\n");
650 if (!quirks
->wireless
) {
652 printk(MY_INFO
"No EC data for reading wireless - wireless value when read will be a 'best guess'\n");
655 if (!quirks
->mailled
) {
657 printk(MY_INFO
"No EC data for reading mail LED - mail LED value when read will be a 'best guess'\n");
662 printk(MY_INFO
"We need more data from your laptop's Embedded Controller (EC) to better support it\n");
663 printk(MY_INFO
"Please see http://code.google.com/p/aceracpi/wiki/EmbeddedController on how to help\n");
667 static acpi_status
AMW0_get_bool(bool *value
, u32 cap
, struct Interface
*iface
)
669 struct AMW0_Data
*data
= iface
->data
;
673 * On some models, we can read these values from the EC. On others,
674 * we use a stored value
677 case ACER_CAP_MAILLED
:
678 if (quirks
->mailled
== 2) {
679 ec_read(0x0A, &result
);
680 *value
= (result
>> 7) & 0x01;
684 *value
= data
->mailled
;
686 case ACER_CAP_WIRELESS
:
687 switch (quirks
->wireless
) {
689 ec_read(0x0A, &result
);
690 *value
= (result
>> 2) & 0x01;
693 ec_read(0x71, &result
);
694 *value
= result
& 0x01;
697 *value
= data
->wireless
;
700 case ACER_CAP_BLUETOOTH
:
701 switch (quirks
->bluetooth
) {
703 ec_read(0x0A, &result
);
704 *value
= (result
>> 4) & 0x01;
707 ec_read(0x71, &result
);
708 *value
= (result
>> 1) & 0x01;
711 *value
= data
->bluetooth
;
714 case ACER_CAP_TOUCHPAD_READ
:
715 switch (quirks
->touchpad
) {
717 ec_read(0x74, &result
);
718 *value
= (result
>> 3) & 0x01;
724 return AE_BAD_ADDRESS
;
729 static acpi_status
AMW0_set_bool(bool value
, u32 cap
, struct Interface
*iface
)
731 struct WMAB_args args
;
734 args
.eax
= ACER_AMW0_WRITE
;
735 args
.ebx
= value
? (1<<8) : 0;
738 case ACER_CAP_MAILLED
:
739 args
.ebx
|= ACER_AMW0_MAILLED_MASK
;
741 case ACER_CAP_WIRELESS
:
742 args
.ebx
|= ACER_AMW0_WIRELESS_MASK
;
744 case ACER_CAP_BLUETOOTH
:
745 args
.ebx
|= ACER_AMW0_BLUETOOTH_MASK
;
748 return AE_BAD_ADDRESS
;
751 /* Actually do the set */
752 status
= WMAB_execute(&args
, NULL
);
755 * Currently no way to query the state, so cache the new value on
758 if (ACPI_SUCCESS(status
)) {
759 struct AMW0_Data
*data
= iface
->data
;
761 case ACER_CAP_MAILLED
:
762 data
->mailled
= value
;
764 case ACER_CAP_WIRELESS
:
765 data
->wireless
= value
;
767 case ACER_CAP_BLUETOOTH
:
768 data
->bluetooth
= value
;
776 static acpi_status
AMW0_get_u8(u8
*value
, u32 cap
, struct Interface
*iface
) {
778 case ACER_CAP_BRIGHTNESS
:
779 switch (quirks
->brightness
) {
781 ec_read(0x83, value
);
784 ec_read(0x85, value
);
787 return AE_BAD_ADDRESS
;
791 return AE_BAD_ADDRESS
;
796 static acpi_status
AMW0_set_u8(u8 value
, u32 cap
, struct Interface
*iface
) {
798 case ACER_CAP_BRIGHTNESS
:
799 switch (quirks
->brightness
) {
801 ec_write(0x83, value
);
804 ec_write(0x85, value
);
807 return AE_BAD_ADDRESS
;
811 return AE_BAD_ADDRESS
;
816 static struct Interface AMW0_interface
= {
824 .free
= interface_free
,
828 * New interface (The WMID interface)
838 static void WMID_init(struct Interface
*iface
)
840 struct WMID_Data
*data
;
842 /* Allocate our private data structure */
843 iface
->data
= kmalloc(sizeof(struct WMID_Data
), GFP_KERNEL
);
844 data
= (struct WMID_Data
*)iface
->data
;
848 WMI_execute_u32(u32 methodId
, u32 in
, u32
*out
)
850 struct acpi_buffer input
= { (acpi_size
)sizeof(u32
), (void*)(&in
) };
851 struct acpi_buffer result
= { ACPI_ALLOCATE_BUFFER
, NULL
};
852 union acpi_object
*obj
;
856 status
= WMI_execute(WMID_METHOD
, methodId
, &input
, &result
);
857 DEBUG(2, " In: 0x%08x\n", in
);
859 if (ACPI_FAILURE(status
))
862 obj
= (union acpi_object
*)result
.pointer
;
863 if (obj
&& obj
->type
== ACPI_TYPE_BUFFER
&& obj
->buffer
.length
== sizeof(u32
)) {
864 tmp
= *((u32
*)obj
->buffer
.pointer
);
865 DEBUG(2, " Out: 0x%08x\n", tmp
);
869 DEBUG(2, " Got unexpected result of type %d\n", obj
->type
);
871 DEBUG(2, " Got unexpected null result\n");
878 if (result
.length
> 0 && result
.pointer
)
879 kfree(result
.pointer
);
884 static acpi_status
WMID_get_u8(u8
*value
, u32 cap
, struct Interface
*iface
) {
890 case ACER_CAP_WIRELESS
:
891 methodId
= ACER_WMID_GET_WIRELESS_METHODID
;
893 case ACER_CAP_BLUETOOTH
:
894 methodId
= ACER_WMID_GET_BLUETOOTH_METHODID
;
896 case ACER_CAP_BRIGHTNESS
:
897 methodId
= ACER_WMID_GET_BRIGHTNESS_METHODID
;
899 case ACER_CAP_THREEG
:
900 methodId
= ACER_WMID_GET_THREEG_METHODID
;
902 case ACER_CAP_MAILLED
:
903 if (quirks
->mailled
== 1) {
904 ec_read(0x9f, value
);
908 case ACER_CAP_TOUCHPAD_READ
:
909 switch (quirks
->touchpad
) {
911 ec_read(0x9e, value
);
912 *value
= 1 - ((*value
>> 3) & 0x01);
917 case ACER_CAP_TEMPERATURE_OVERRIDE
:
918 if (quirks
->temperature_override
== 1) {
919 ec_read(0xa9, value
);
923 return AE_BAD_ADDRESS
;
925 status
= WMI_execute_u32(methodId
, 0, &result
);
927 if (ACPI_SUCCESS(status
))
933 static acpi_status
WMID_set_u8(u8 value
, u32 cap
, struct Interface
*iface
) {
937 case ACER_CAP_BRIGHTNESS
:
938 methodId
= ACER_WMID_SET_BRIGHTNESS_METHODID
;
940 case ACER_CAP_WIRELESS
:
941 methodId
= ACER_WMID_SET_WIRELESS_METHODID
;
943 case ACER_CAP_BLUETOOTH
:
944 methodId
= ACER_WMID_SET_BLUETOOTH_METHODID
;
946 case ACER_CAP_THREEG
:
947 methodId
= ACER_WMID_SET_THREEG_METHODID
;
949 case ACER_CAP_MAILLED
:
950 if (quirks
->mailled
== 1) {
951 send_kbd_cmd(0x59, value
? 0x92 : 0x93);
954 case ACER_CAP_TEMPERATURE_OVERRIDE
:
955 if (quirks
->temperature_override
== 1) {
956 ec_write(0xa9, value
);
960 return AE_BAD_ADDRESS
;
962 return WMI_execute_u32(methodId
, (u32
)value
, NULL
);
966 static struct Interface WMID_interface
= {
969 | ACER_CAP_BRIGHTNESS
974 .free
= interface_free
,
980 * High-level Procfs file handlers
984 dispatch_read(char *page
, char **start
, off_t off
, int count
, int *eof
,
985 struct ProcItem
* item
)
991 p
= item
->read_func(p
, item
->capability
);
993 if (len
<= off
+ count
)
1005 dispatch_write(struct file
*file
, const char __user
* buffer
,
1006 unsigned long count
, struct ProcItem
* item
)
1012 * Arg buffer points to userspace memory, which can't be accessed
1013 * directly. Since we're making a copy, zero-terminate the
1014 * destination so that sscanf can be used on it safely.
1016 tmp_buffer
= kmalloc(count
+ 1, GFP_KERNEL
);
1017 if (copy_from_user(tmp_buffer
, buffer
, count
)) {
1020 tmp_buffer
[count
] = 0;
1021 result
= item
->write_func(tmp_buffer
, count
, item
->capability
);
1029 * Generic Device (interface-independent)
1032 static acpi_status
get_bool(bool *value
, u32 cap
) {
1033 acpi_status status
= AE_BAD_ADDRESS
;
1036 switch (interface
->type
) {
1038 status
= AMW0_get_bool(value
, cap
, interface
);
1041 status
= WMID_get_u8(tmp
, cap
, interface
);
1042 *value
= (*tmp
== 1) ? 1 : 0;
1048 static acpi_status
set_bool(int value
, u32 cap
) {
1049 acpi_status status
= AE_BAD_PARAMETER
;
1051 if ((value
== 0 || value
== 1) && (interface
->capability
& cap
)) {
1052 switch (interface
->type
) {
1054 status
= AMW0_set_bool(value
== 1, cap
, interface
);
1057 status
= AMW0_set_u8(value
== 1, cap
, interface
);
1065 static acpi_status
get_u8(u8
*value
, u32 cap
) {
1066 switch (interface
->type
) {
1068 return AMW0_get_u8(value
, cap
, interface
);
1071 return WMID_get_u8(value
, cap
, interface
);
1074 return AE_BAD_ADDRESS
;
1078 static acpi_status
set_u8(u8 value
, u8 min
, u8 max
, u32 cap
) {
1079 if ((value
>= min
&& value
<= max
) && (interface
->capability
& cap
) ) {
1080 switch (interface
->type
) {
1082 return AMW0_set_u8(value
, cap
, interface
);
1084 return WMID_set_u8(value
, cap
, interface
);
1086 return AE_BAD_PARAMETER
;
1089 return AE_BAD_PARAMETER
;
1092 /* Each _u8 needs a small wrapper that sets the boundary values */
1093 static acpi_status
set_brightness(u8 value
)
1095 return set_u8(value
, 0, max_brightness
, ACER_CAP_BRIGHTNESS
);
1098 static acpi_status
set_temperature_override(u8 value
)
1100 return set_u8(value
, 0, ACER_MAX_TEMPERATURE_OVERRIDE
, ACER_CAP_TEMPERATURE_OVERRIDE
);
1103 static void __init
acer_commandline_init(void)
1105 DEBUG(1, "Commandline args: mailled(%d) wireless(%d) bluetooth(%d) brightness(%d)\n",
1106 mailled
, wireless
, bluetooth
, brightness
);
1109 * These will all fail silently if the value given is invalid, or the
1110 * capability isn't available on the given interface
1112 set_bool(mailled
, ACER_CAP_MAILLED
);
1113 set_bool(wireless
, ACER_CAP_WIRELESS
);
1114 set_bool(bluetooth
, ACER_CAP_BLUETOOTH
);
1115 set_bool(threeg
, ACER_CAP_THREEG
);
1116 set_temperature_override(fan_temperature_override
);
1117 set_brightness((u8
)brightness
);
1122 * Procfs interface (deprecated)
1124 static char *read_bool(char *p
, u32 cap
)
1127 acpi_status status
= get_bool(&result
, cap
);
1128 if (ACPI_SUCCESS(status
))
1129 p
+= sprintf(p
, "%d\n", result
);
1131 p
+= sprintf(p
, "Read error" );
1135 static unsigned long write_bool(const char *buffer
, unsigned long count
, u32 cap
)
1139 if (sscanf(buffer
, "%i", &value
) == 1) {
1140 acpi_status status
= set_bool(value
, cap
);
1141 if (ACPI_FAILURE(status
))
1149 static char *read_u8(char *p
, u32 cap
)
1152 acpi_status status
= get_u8(&result
, cap
);
1153 if (ACPI_SUCCESS(status
))
1154 p
+= sprintf(p
, "%u\n", result
);
1156 p
+= sprintf(p
, "Read error" );
1160 static unsigned long write_u8(const char *buffer
, unsigned long count
, u32 cap
)
1163 acpi_status (*set_method
)(u8
);
1165 /* Choose the appropriate set_u8 wrapper here, based on the capability */
1167 case ACER_CAP_BRIGHTNESS
:
1168 set_method
= set_brightness
;
1170 case ACER_CAP_TEMPERATURE_OVERRIDE
:
1171 set_method
= set_temperature_override
;
1177 if (sscanf(buffer
, "%i", &value
) == 1) {
1178 acpi_status status
= (*set_method
)(value
);
1179 if (ACPI_FAILURE(status
))
1187 static char *read_version(char *p
, u32 cap
)
1189 p
+= sprintf(p
, "%s\n", ACER_ACPI_VERSION
);
1193 static char *read_interface(char *p
, u32 cap
)
1195 p
+= sprintf(p
, "%s\n", (interface
->type
== ACER_AMW0
) ? "AMW0": "WMID");
1199 struct ProcItem proc_items
[] = {
1200 {"mailled", read_bool
, write_bool
, ACER_CAP_MAILLED
},
1201 {"bluetooth", read_bool
, write_bool
, ACER_CAP_BLUETOOTH
},
1202 {"wireless", read_bool
, write_bool
, ACER_CAP_WIRELESS
},
1203 {"brightness", read_u8
, write_u8
, ACER_CAP_BRIGHTNESS
},
1204 {"threeg", read_bool
, write_bool
, ACER_CAP_THREEG
},
1205 {"touchpad", read_bool
, NULL
, ACER_CAP_TOUCHPAD_READ
},
1206 {"fan_temperature_override", read_u8
, write_u8
, ACER_CAP_TEMPERATURE_OVERRIDE
},
1207 {"version", read_version
, NULL
, ACER_CAP_ANY
},
1208 {"interface", read_interface
, NULL
, ACER_CAP_ANY
},
1212 static acpi_status __init
add_proc_entries(void)
1214 struct proc_dir_entry
*proc
;
1215 struct ProcItem
*item
;
1217 for (item
= proc_items
; item
->name
; ++item
) {
1219 * Only add the proc file if the current interface actually
1222 if (interface
->capability
& item
->capability
) {
1223 proc
= create_proc_read_entry(item
->name
,
1224 S_IFREG
| S_IRUGO
| S_IWUSR
,
1226 (read_proc_t
*) dispatch_read
,
1229 proc
->owner
= THIS_MODULE
;
1230 if (proc
&& item
->write_func
)
1231 proc
->write_proc
= (write_proc_t
*) dispatch_write
;
1238 static acpi_status __exit
remove_proc_entries(void)
1240 struct ProcItem
*item
;
1242 for (item
= proc_items
; item
->name
; ++item
)
1243 remove_proc_entry(item
->name
, acer_proc_dir
);
1249 * LED device (Mail LED only, no other LEDs known yet)
1251 static void mail_led_set(struct led_classdev
*led_cdev
, enum led_brightness value
)
1254 set_bool(tmp
, ACER_CAP_MAILLED
);
1257 static struct led_classdev mail_led
= {
1258 .name
= "acer_acpi:mail",
1259 .brightness_set
= mail_led_set
,
1262 static void acer_led_init(struct device
*dev
)
1264 led_classdev_register(dev
, &mail_led
);
1267 static void acer_led_exit(void)
1269 led_classdev_unregister(&mail_led
);
1272 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,18)
1276 static struct backlight_device
*acer_backlight_device
;
1278 static int read_brightness(struct backlight_device
*bd
)
1281 get_u8(&value
, ACER_CAP_BRIGHTNESS
);
1285 #if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,20)
1286 static int update_bl_status(struct backlight_device
*bd
)
1288 set_brightness(bd
->props
->brightness
);
1292 static struct backlight_properties acer_backlight_properties
= {
1293 .get_brightness
= read_brightness
,
1294 .update_status
= update_bl_status
,
1297 static int __init
acer_backlight_init(struct device
*dev
)
1299 struct backlight_device
*bd
;
1301 DEBUG(1, "Loading backlight driver\n");
1302 bd
= backlight_device_register("acer_acpi", dev
, NULL
, &acer_backlight_properties
);
1304 printk(MY_ERR
"Could not register Acer backlight device\n");
1305 acer_backlight_device
= NULL
;
1309 acer_backlight_device
= bd
;
1311 bd
->props
->max_brightness
= max_brightness
;
1315 static int update_bl_status(struct backlight_device
*bd
)
1317 set_brightness(bd
->props
.brightness
);
1321 static struct backlight_ops acer_backlight_ops
= {
1322 .get_brightness
= read_brightness
,
1323 .update_status
= update_bl_status
,
1326 static int __init
acer_backlight_init(struct device
*dev
)
1328 struct backlight_device
*bd
;
1330 DEBUG(1, "Loading backlight driver\n");
1331 bd
= backlight_device_register("acer_acpi", dev
, NULL
, &acer_backlight_ops
);
1333 printk(MY_ERR
"Could not register Acer backlight device\n");
1334 acer_backlight_device
= NULL
;
1338 acer_backlight_device
= bd
;
1340 bd
->props
.max_brightness
= max_brightness
;
1341 bd
->props
.brightness
= read_brightness(NULL
);
1342 backlight_update_status(bd
);
1347 static void __exit
acer_backlight_exit(void)
1349 backlight_device_unregister(acer_backlight_device
);
1358 * Read/ write bool sysfs macro
1360 #define show_set_bool(value, cap) \
1362 show_bool_##value(struct device *dev, struct device_attribute *attr, \
1366 acpi_status status = get_bool(&result, cap); \
1367 if (ACPI_SUCCESS(status)) \
1368 return sprintf(buf, "%d\n", result); \
1369 return sprintf(buf, "Read error" ); \
1373 set_bool_##value(struct device *dev, struct device_attribute *attr, \
1374 const char *buf, size_t count) \
1376 bool tmp = simple_strtoul(buf, NULL, 10); \
1377 acpi_status status = set_bool(tmp, cap); \
1378 if (ACPI_FAILURE(status)) \
1382 static DEVICE_ATTR(value, S_IWUGO | S_IRUGO | S_IWUSR, \
1383 show_bool_##value, set_bool_##value);
1385 show_set_bool(wireless
, ACER_CAP_WIRELESS
);
1386 show_set_bool(bluetooth
, ACER_CAP_BLUETOOTH
);
1387 show_set_bool(threeg
, ACER_CAP_THREEG
);
1388 show_set_bool(fan_temperature_override
, ACER_CAP_TEMPERATURE_OVERRIDE
);
1391 * Read-only bool sysfs macro
1393 #define show_bool(value, cap) \
1395 show_bool_##value(struct device *dev, struct device_attribute *attr, \
1399 acpi_status status = get_bool(&result, cap); \
1400 if (ACPI_SUCCESS(status)) \
1401 return sprintf(buf, "%d\n", result); \
1402 return sprintf(buf, "Read error" ); \
1404 static DEVICE_ATTR(value, S_IWUGO | S_IRUGO | S_IWUSR, \
1405 show_bool_##value, NULL);
1407 show_bool(touchpad
, ACER_CAP_TOUCHPAD_READ
);
1410 * Read interface sysfs macro
1412 static ssize_t
show_interface(struct device
*dev
, struct device_attribute
*attr
,
1415 return sprintf(buf
, "%s\n", (interface
->type
== ACER_AMW0
) ? "AMW0": "WMID");
1418 static DEVICE_ATTR(interface
, S_IWUGO
| S_IRUGO
| S_IWUSR
, show_interface
, NULL
);
1420 static struct platform_driver acer_platform_driver
= {
1422 .name
= "acer_acpi",
1423 .owner
= THIS_MODULE
,
1427 static struct platform_device
*acer_platform_device
;
1429 static int remove_sysfs(struct platform_device
*device
)
1431 #define remove_device_file(value, cap) \
1433 device_remove_file(&device->dev, &dev_attr_##value);
1435 remove_device_file(wireless
, ACER_CAP_WIRELESS
);
1436 remove_device_file(bluetooth
, ACER_CAP_BLUETOOTH
);
1437 remove_device_file(threeg
, ACER_CAP_THREEG
);
1438 remove_device_file(interface
, ACER_CAP_ANY
);
1439 remove_device_file(fan_temperature_override
, ACER_CAP_TEMPERATURE_OVERRIDE
);
1440 remove_device_file(touchpad
, ACER_CAP_TOUCHPAD_READ
);
1444 static int acer_platform_add(void)
1446 int retval
= -ENOMEM
;
1447 platform_driver_register(&acer_platform_driver
);
1449 acer_platform_device
= platform_device_alloc("acer_acpi", -1);
1451 platform_device_add(acer_platform_device
);
1453 #define add_device_file(value, cap) \
1454 if (has_cap(cap)) {\
1455 retval = device_create_file(&acer_platform_device->dev, &dev_attr_##value);\
1460 add_device_file(wireless
, ACER_CAP_WIRELESS
);
1461 add_device_file(bluetooth
, ACER_CAP_BLUETOOTH
);
1462 add_device_file(threeg
, ACER_CAP_THREEG
);
1463 add_device_file(interface
, ACER_CAP_ANY
);
1464 add_device_file(fan_temperature_override
, ACER_CAP_TEMPERATURE_OVERRIDE
);
1465 add_device_file(touchpad
, ACER_CAP_TOUCHPAD_READ
);
1470 remove_sysfs(acer_platform_device
);
1474 static void acer_platform_remove(void)
1476 remove_sysfs(acer_platform_device
);
1477 platform_device_del(acer_platform_device
);
1478 platform_driver_unregister(&acer_platform_driver
);
1484 static int acer_acpi_suspend(struct acpi_device
*device
, pm_message_t state
)
1487 * WMID fix for suspend-to-disk - save all current states now so we can
1488 * restore them on resume
1493 #define save_bool_device(device, cap) \
1494 if (has_cap(cap)) {\
1495 get_bool(&value, cap);\
1496 data->device = value;\
1499 #define save_u8_device(device, cap) \
1500 if (has_cap(cap)) {\
1501 get_u8(&u8value, cap);\
1502 data->device = u8value;\
1505 if (interface
->type
== ACER_WMID
) {
1506 struct WMID_Data
*data
= interface
->data
;
1507 save_bool_device(wireless
, ACER_CAP_WIRELESS
);
1508 save_bool_device(bluetooth
, ACER_CAP_BLUETOOTH
);
1509 save_bool_device(threeg
, ACER_CAP_THREEG
);
1510 save_u8_device(brightness
, ACER_CAP_BRIGHTNESS
);
1516 static int acer_acpi_resume(struct acpi_device
*device
)
1518 #define restore_bool_device(device, cap) \
1520 set_bool(data->device, cap);\
1523 * We must _always_ restore AMW0's values, otherwise the values
1524 * after suspend-to-disk are wrong
1526 if (interface
->type
== ACER_AMW0
) {
1527 struct AMW0_Data
*data
= interface
->data
;
1529 restore_bool_device(wireless
, ACER_CAP_WIRELESS
);
1530 restore_bool_device(bluetooth
, ACER_CAP_BLUETOOTH
);
1531 restore_bool_device(mailled
, ACER_CAP_MAILLED
);
1533 else if (interface
->type
== ACER_WMID
) {
1534 struct WMID_Data
*data
= interface
->data
;
1536 if (has_cap(ACER_CAP_BRIGHTNESS
))
1537 set_brightness((u8
)data
->brightness
);
1538 restore_bool_device(threeg
, ACER_CAP_THREEG
);
1539 restore_bool_device(wireless
, ACER_CAP_WIRELESS
);
1540 restore_bool_device(bluetooth
, ACER_CAP_BLUETOOTH
);
1543 /* Check if this laptop requires the keyboard quirk */
1544 if (quirks
->mmkeys
) {
1545 set_keyboard_quirk();
1546 printk(MY_INFO
"Setting keyboard quirk to enable multimedia keys\n");
1552 static int acer_acpi_add(struct acpi_device
*device
)
1554 struct device
*dev
= acpi_get_physical_device(device
->handle
);
1555 if (has_cap(ACER_CAP_MAILLED
))
1557 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,18)
1558 if (has_cap(ACER_CAP_BRIGHTNESS
))
1559 acer_backlight_init(dev
);
1562 acer_platform_add();
1566 static int acer_acpi_remove(struct acpi_device
*device
, int type
)
1568 if (has_cap(ACER_CAP_MAILLED
))
1570 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,18)
1571 if (has_cap(ACER_CAP_BRIGHTNESS
))
1572 acer_backlight_exit();
1575 acer_platform_remove();
1579 static struct acpi_driver acer
= {
1580 .name
= "acer_acpi",
1584 .add
= acer_acpi_add
,
1585 .remove
= acer_acpi_remove
,
1586 .suspend
= acer_acpi_suspend
,
1587 .resume
= acer_acpi_resume
,
1591 static int __init
acer_acpi_init(void)
1593 acpi_status status
= AE_OK
;
1595 printk(MY_INFO
"Acer Laptop ACPI Extras version %s\n",
1597 if (acpi_disabled
) {
1598 printk(MY_ERR
"ACPI Disabled, unable to load.\n");
1603 * Detect which WMI interface we're using.
1605 * TODO: This could be more dynamic, and perhaps done in part by the
1608 if (is_valid_acpi_path(AMW0_METHOD
)) {
1609 DEBUG(0, "Detected Acer AMW0 interface\n");
1610 /* .ids is case sensitive - and AMW0 uses a strange mixed case */
1611 acer
.ids
= "pnp0c14";
1612 interface
= &AMW0_interface
;
1613 } else if (is_valid_acpi_path(WMID_METHOD
)) {
1614 DEBUG(0, "Detected Acer WMID interface\n");
1615 interface
= &WMID_interface
;
1617 printk(MY_ERR
"No or unsupported WMI interface, unable to load.\n");
1618 goto error_no_interface
;
1621 /* Find if this laptop requires any quirks */
1622 DEBUG(1, "Finding quirks\n");
1625 /* Now that we have a known interface, initialize it */
1626 DEBUG(1, "Initialising interface\n");
1627 if (interface
->init
)
1628 interface
->init(interface
);
1631 /* Create the proc entries */
1632 acer_proc_dir
= proc_mkdir(PROC_ACER
, acpi_root_dir
);
1633 if (!acer_proc_dir
) {
1634 printk(MY_ERR
"Unable to create /proc entries, aborting.\n");
1635 goto error_proc_mkdir
;
1638 acer_proc_dir
->owner
= THIS_MODULE
;
1639 status
= add_proc_entries();
1641 printk(MY_ERR
"Unable to create /proc entries, aborting.\n");
1642 goto error_proc_add
;
1647 * Register the driver
1649 status
= acpi_bus_register_driver(&acer
);
1650 DEBUG(1, "ACPI driver registered\n");
1652 printk(MY_ERR
"Unable to register ACPI driver, aborting.\n");
1653 goto error_acpi_bus_register
;
1656 /* Override any initial settings with values from the commandline */
1657 acer_commandline_init();
1661 error_acpi_bus_register
:
1663 remove_proc_entries();
1666 remove_proc_entry(PROC_ACER
, acpi_root_dir
);
1668 if (interface
->free
)
1669 interface
->free(interface
);
1675 static void __exit
acer_acpi_exit(void)
1677 acpi_bus_unregister_driver(&acer
);
1680 remove_proc_entries();
1683 remove_proc_entry(PROC_ACER
, acpi_root_dir
);
1686 if (interface
->free
)
1687 interface
->free(interface
);
1689 printk(MY_INFO
"Acer Laptop ACPI Extras unloaded\n");
1693 module_init(acer_acpi_init
);
1694 module_exit(acer_acpi_exit
);