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
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
44 #define PROC_ACER "acer"
45 #include <linux/proc_fs.h>
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>
58 #include <linux/uaccess.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>
71 /* Workaround needed for older kernels */
76 MODULE_AUTHOR("Mark Smith, Carlos Corbacho");
77 MODULE_DESCRIPTION("Acer Laptop ACPI Extras Driver");
78 MODULE_LICENSE("GPL");
80 #define ACER_LOGPREFIX "acer_acpi: "
81 #define ACER_ERR KERN_ERR ACER_LOGPREFIX
82 #define ACER_NOTICE KERN_NOTICE ACER_LOGPREFIX
83 #define ACER_INFO KERN_INFO ACER_LOGPREFIX
85 #define DEBUG(level, message...) { \
87 printk(KERN_DEBUG ACER_LOGPREFIX message);\
91 * The maximum temperature one can set for fan control override.
92 * Doesn't propably make much sense if over 80 degrees celsius though...
94 #define ACER_MAX_TEMPERATURE_OVERRIDE 150
97 * The following defines quirks to get some specific functions to work
98 * which are known to not be supported over ACPI (such as the mail LED
99 * on WMID based Acer's)
108 * Keyboard controller ports
110 #define ACER_KBD_STATUS_REG 0x64 /* Status register (R) */
111 #define ACER_KBD_CNTL_REG 0x64 /* Controller command register (W) */
112 #define ACER_KBD_DATA_REG 0x60 /* Keyboard data register (R/W) */
116 * Meaning is unknown - this number is required for writing to ACPI for AMW0
117 * (it's also used in acerhk when directly accessing the EC)
119 #define ACER_AMW0_WRITE 0x9610
122 * Bit masks for the old AMW0 interface
124 #define ACER_AMW0_WIRELESS_MASK 0x35
125 #define ACER_AMW0_BLUETOOTH_MASK 0x34
126 #define ACER_AMW0_MAILLED_MASK 0x31
129 * Method IDs for new WMID interface
131 #define ACER_WMID_GET_WIRELESS_METHODID 1
132 #define ACER_WMID_GET_BLUETOOTH_METHODID 2
133 #define ACER_WMID_GET_BRIGHTNESS_METHODID 3
134 #define ACER_WMID_SET_WIRELESS_METHODID 4
135 #define ACER_WMID_SET_BLUETOOTH_METHODID 5
136 #define ACER_WMID_SET_BRIGHTNESS_METHODID 6
137 #define ACER_WMID_GET_THREEG_METHODID 10
138 #define ACER_WMID_SET_THREEG_METHODID 11
141 * Acer ACPI method GUIDs
143 #define AMW0_GUID1 "67C3371D-95A3-4C37-BB61-DD47B491DAAB"
144 #define WMID_GUID1 "6AF4F258-B401-42fd-BE91-3D4AC2D7C0D3"
147 * Interface capability flags
149 #define ACER_CAP_MAILLED (1<<0)
150 #define ACER_CAP_WIRELESS (1<<1)
151 #define ACER_CAP_BLUETOOTH (1<<2)
152 #define ACER_CAP_BRIGHTNESS (1<<3)
153 #define ACER_CAP_THREEG (1<<4)
154 #define ACER_CAP_TOUCHPAD_READ (1<<5)
155 #define ACER_CAP_TEMPERATURE_OVERRIDE (1<<6)
156 #define ACER_CAP_ANY (0xFFFFFFFF)
159 * Interface type flags
161 enum interface_flags
{
167 * Presumed start states -
168 * On some AMW0 laptops, we do not yet know how to get the device status from
169 * the EC, so we must store this ourselves.
171 * Plus, we can't tell which features are enabled or disabled on a specific
172 * model - e.g. The 5020 series can _support_ bluetooth; but the 5021 has no
173 * bluetooth, whilst the 5024 does. However, the BIOS identifies both laptops
174 * as 5020, and you can add bluetooth later.
176 * Basically the code works like this:
177 * - On init, any values specified on the commandline are set.
178 * - For interfaces where the current values cannot be detected and which
179 * have not been set on the commandline, we set them to some sane default
182 * See AMW0_init and acer_commandline_init
185 #define ACER_DEFAULT_WIRELESS 0
186 #define ACER_DEFAULT_BLUETOOTH 0
187 #define ACER_DEFAULT_MAILLED 0
188 #define ACER_DEFAULT_THREEG 0
190 static int max_brightness
= 0xF;
192 static int wireless
= -1;
193 static int bluetooth
= -1;
194 static int mailled
= -1;
195 static int brightness
= -1;
196 static int threeg
= -1;
197 static int fan_temperature_override
= -1;
198 static int debug
= 0;
199 static int force_series
;
201 module_param(mailled
, int, 0444);
202 module_param(wireless
, int, 0444);
203 module_param(bluetooth
, int, 0444);
204 module_param(brightness
, int, 0444);
205 module_param(threeg
, int, 0444);
206 module_param(force_series
, int, 0444);
207 module_param(fan_temperature_override
, int, 0444);
208 module_param(debug
, int, 0664);
209 MODULE_PARM_DESC(wireless
, "Set initial state of Wireless hardware");
210 MODULE_PARM_DESC(bluetooth
, "Set initial state of Bluetooth hardware");
211 MODULE_PARM_DESC(mailled
, "Set initial state of Mail LED");
212 MODULE_PARM_DESC(brightness
, "Set initial LCD backlight brightness");
213 MODULE_PARM_DESC(threeg
, "Set initial state of 3G hardware");
214 MODULE_PARM_DESC(fan_temperature_override
, "Set initial state of the 'FAN temperature-override'");
215 MODULE_PARM_DESC(debug
, "Debugging verbosity level (0=least 2=most)");
216 MODULE_PARM_DESC(force_series
, "Force a different laptop series for extra features (5020, 5720 or 2490)");
221 char *(*read_func
) (char *, u32
);
222 unsigned long (*write_func
) (const char *, unsigned long, u32
);
223 unsigned int capability
;
226 static struct proc_dir_entry
*acer_proc_dir
;
230 * Wait for the keyboard controller to become ready
232 static int wait_kbd_write(void)
235 while ((inb(ACER_KBD_STATUS_REG
) & 0x02) && (i
< 10000)) {
239 return -(i
== 10000);
242 static void send_kbd_cmd(u8 cmd
, u8 val
)
245 if (!wait_kbd_write())
246 outb(cmd
, ACER_KBD_CNTL_REG
);
247 if (!wait_kbd_write())
248 outb(val
, ACER_KBD_DATA_REG
);
249 preempt_enable_no_resched();
252 static void set_keyboard_quirk(void)
254 send_kbd_cmd(0x59, 0x90);
265 /* Each low-level interface must define at least some of the following */
268 * The ACPI device type
273 * The capabilities this interface provides
274 * In the future, these can be removed/added at runtime when we have a
275 * way of detecting what capabilities are /actually/ present on an
281 * Initializes an interface, should allocate the interface-specific
284 void (*init
) (struct Interface
*);
287 * Private data for the current interface
289 struct acer_data data
;
292 /* The static interface pointer, points to the currently detected interface */
293 static struct Interface
*interface
;
296 * Embedded Controller quirks
297 * Some laptops require us to directly access the EC to either enable or query
298 * features that are not available through ACPI.
306 u8 temperature_override
;
312 static struct quirk_entry
*quirks
;
314 static void set_quirks(void)
316 if (quirks
->mailled
!= 0) {
317 interface
->capability
|= ACER_CAP_MAILLED
;
318 DEBUG(1, "Using EC direct-access quirk for mail LED\n");
321 if (quirks
->touchpad
!= 0) {
322 interface
->capability
|= ACER_CAP_TOUCHPAD_READ
;
323 DEBUG(1, "Using EC direct-access quirk for reading touchpad status\n");
326 if (quirks
->temperature_override
!= 0) {
327 interface
->capability
|= ACER_CAP_TEMPERATURE_OVERRIDE
;
328 DEBUG(1, "Using EC direct-access quirk for temperature override setting (fan)\n");
331 if (quirks
->brightness
!= 0) {
332 interface
->capability
|= ACER_CAP_BRIGHTNESS
;
333 DEBUG(1, "Using EC direct-access quirk for backlight brightness\n");
336 if (quirks
->mmkeys
!= 0) {
337 set_keyboard_quirk();
338 printk(ACER_INFO
"Setting keyboard quirk to enable multimedia keys\n");
341 if (quirks
->bluetooth
!= 0) {
342 interface
->capability
|= ACER_CAP_BLUETOOTH
;
343 DEBUG(1, "Using EC direct-access quirk for bluetooth\n");
346 if (quirks
->wireless
!= 0) {
347 interface
->capability
|= ACER_CAP_WIRELESS
;
348 DEBUG(1, "Using EC direct-access quirk for wireless\n");
351 if (quirks
->max_brightness
!= 0) {
352 max_brightness
= quirks
->max_brightness
;
353 DEBUG(1, "Changing maximum brightness level\n");
357 static int dmi_matched(struct dmi_system_id
*dmi
)
359 quirks
= dmi
->driver_data
;
363 static struct quirk_entry quirk_unknown
= {
366 static struct quirk_entry quirk_acer_aspire_5020
= {
373 static struct quirk_entry quirk_acer_aspire_5680
= {
377 static struct quirk_entry quirk_acer_aspire_9300
= {
381 static struct quirk_entry quirk_acer_travelmate_2490
= {
384 .temperature_override
= 1,
389 * This is similar to the Aspire 5020, but with a different wireless quirk
391 static struct quirk_entry quirk_acer_travelmate_5620
= {
398 static struct quirk_entry quirk_acer_travelmate_5720
= {
399 .max_brightness
= 0x9,
406 static struct dmi_system_id acer_quirks
[] = {
408 .callback
= dmi_matched
,
409 .ident
= "Acer Aspire 3020",
411 DMI_MATCH(DMI_SYS_VENDOR
, "Acer"),
412 DMI_MATCH(DMI_PRODUCT_NAME
, "Aspire 3020"),
414 .driver_data
= &quirk_acer_aspire_5020
,
417 .callback
= dmi_matched
,
418 .ident
= "Acer Aspire 3040",
420 DMI_MATCH(DMI_SYS_VENDOR
, "Acer"),
421 DMI_MATCH(DMI_PRODUCT_NAME
, "Aspire 3040"),
423 .driver_data
= &quirk_acer_aspire_5020
,
426 .callback
= dmi_matched
,
427 .ident
= "Acer Aspire 5020",
429 DMI_MATCH(DMI_SYS_VENDOR
, "Acer"),
430 DMI_MATCH(DMI_PRODUCT_NAME
, "Aspire 5020"),
432 .driver_data
= &quirk_acer_aspire_5020
,
435 .callback
= dmi_matched
,
436 .ident
= "Acer Aspire 5040",
438 DMI_MATCH(DMI_SYS_VENDOR
, "Acer"),
439 DMI_MATCH(DMI_PRODUCT_NAME
, "Aspire 5040"),
441 .driver_data
= &quirk_acer_aspire_5020
,
444 .callback
= dmi_matched
,
445 .ident
= "Acer Aspire 5560",
447 DMI_MATCH(DMI_SYS_VENDOR
, "Acer"),
448 DMI_MATCH(DMI_PRODUCT_NAME
, "Aspire 5560"),
450 .driver_data
= &quirk_acer_travelmate_5620
,
453 .callback
= dmi_matched
,
454 .ident
= "Acer Aspire 5650",
456 DMI_MATCH(DMI_SYS_VENDOR
, "Acer"),
457 DMI_MATCH(DMI_PRODUCT_NAME
, "Aspire 5650"),
459 .driver_data
= &quirk_acer_travelmate_2490
,
462 .callback
= dmi_matched
,
463 .ident
= "Acer Aspire 5680",
465 DMI_MATCH(DMI_SYS_VENDOR
, "Acer"),
466 DMI_MATCH(DMI_PRODUCT_NAME
, "Aspire 5680"),
468 .driver_data
= &quirk_acer_aspire_5680
,
471 .callback
= dmi_matched
,
472 .ident
= "Acer Aspire 9300",
474 DMI_MATCH(DMI_SYS_VENDOR
, "Acer"),
475 DMI_MATCH(DMI_PRODUCT_NAME
, "Aspire 9300"),
477 .driver_data
= &quirk_acer_aspire_9300
,
480 .callback
= dmi_matched
,
481 .ident
= "Acer TravelMate 2420",
483 DMI_MATCH(DMI_SYS_VENDOR
, "Acer"),
484 DMI_MATCH(DMI_PRODUCT_NAME
, "TravelMate 2420"),
486 .driver_data
= &quirk_acer_aspire_5020
,
489 .callback
= dmi_matched
,
490 .ident
= "Acer TravelMate 2490",
492 DMI_MATCH(DMI_SYS_VENDOR
, "Acer"),
493 DMI_MATCH(DMI_PRODUCT_NAME
, "TravelMate 2490"),
495 .driver_data
= &quirk_acer_travelmate_2490
,
498 .callback
= dmi_matched
,
499 .ident
= "Acer TravelMate 5620",
501 DMI_MATCH(DMI_SYS_VENDOR
, "Acer"),
502 DMI_MATCH(DMI_PRODUCT_NAME
, "TravelMate 5620"),
504 .driver_data
= &quirk_acer_travelmate_5620
,
507 .callback
= dmi_matched
,
508 .ident
= "Acer TravelMate 5720",
510 DMI_MATCH(DMI_SYS_VENDOR
, "Acer"),
511 DMI_MATCH(DMI_PRODUCT_NAME
, "TravelMate 5720"),
513 .driver_data
= &quirk_acer_travelmate_5720
,
518 /* Find which quirks are needed for a particular vendor/ model pair */
519 static void find_quirks(void)
521 DEBUG (1, "Looking for quirks\n");
523 dmi_check_system(acer_quirks
);
524 } else if (force_series
== 5020) {
525 DEBUG(0, "Forcing Acer Aspire 5020\n");
526 quirks
= &quirk_acer_aspire_5020
;
527 } else if (force_series
== 2490) {
528 DEBUG(0, "Forcing Acer TravelMate 2490\n");
529 quirks
= &quirk_acer_travelmate_2490
;
530 } else if (force_series
== 5620) {
531 DEBUG(0, "Forcing Acer TravelMate 5620\n");
532 quirks
= &quirk_acer_travelmate_5620
;
533 } else if (force_series
== 5720) {
534 DEBUG(0, "Forcing Acer TravelMate 5720\n");
535 quirks
= &quirk_acer_travelmate_5720
;
538 if (quirks
== NULL
) {
539 DEBUG(1, "No quirks known for this laptop\n");
540 quirks
= &quirk_unknown
;
546 * General interface convenience methods
549 static bool has_cap(u32 cap
)
551 if ((interface
->capability
& cap
) != 0) {
558 * Old interface (now known as the AMW0 interface)
567 static acpi_status
WMAB_execute(struct WMAB_args
*regbuf
, struct acpi_buffer
*result
)
569 struct acpi_buffer input
;
571 input
.length
= sizeof(struct WMAB_args
);
572 input
.pointer
= (u8
*)regbuf
;
574 status
= wmi_acer_evaluate_method(AMW0_GUID1
, 1, 1, &input
, result
);
575 DEBUG(2, " Args: 0x%08x 0x%08x 0x%08x 0x%08x\n", regbuf
->eax
, regbuf
->ebx
, regbuf
->ecx
, regbuf
->edx
);
580 static void AMW0_init(struct Interface
*iface
) {
584 * If the commandline doesn't specify these, we need to force them to
587 if (mailled
== -1 && !quirks
->mailled
)
588 mailled
= ACER_DEFAULT_MAILLED
;
589 if (wireless
== -1 && !quirks
->wireless
)
590 wireless
= ACER_DEFAULT_WIRELESS
;
591 if (bluetooth
== -1 && !quirks
->bluetooth
)
592 bluetooth
= ACER_DEFAULT_BLUETOOTH
;
595 * Set the cached "current" values to impossible ones so that
596 * acer_commandline_init will definitely set them.
598 if (quirks
->bluetooth
== 0) {
600 iface
->data
.bluetooth
= -1;
601 printk(ACER_INFO
"No EC data for reading bluetooth - bluetooth value when read will be a 'best guess'\n");
604 if (quirks
->wireless
== 0) {
606 printk(ACER_INFO
"No EC data for reading wireless - wireless value when read will be a 'best guess'\n");
607 iface
->data
.wireless
= -1;
609 if (quirks
->mailled
== 0) {
611 printk(ACER_INFO
"No EC data for reading mail LED - mail LED value when read will be a 'best guess'\n");
612 iface
->data
.mailled
= -1;
616 printk(ACER_INFO
"We need more data from your laptop's Embedded Controller (EC) to better support it\n");
617 printk(ACER_INFO
"Please see http://code.google.com/p/aceracpi/wiki/EmbeddedController on how to help\n");
621 static acpi_status
AMW0_get_bool(bool *value
, u32 cap
, struct Interface
*iface
)
623 struct acer_data
*data
= &iface
->data
;
626 DEBUG(2, " AMW0_get_bool: cap=%d\n", cap
);
628 * On some models, we can read these values from the EC. On others,
629 * we use a stored value
632 case ACER_CAP_MAILLED
:
633 switch (quirks
->mailled
) {
635 ec_read(0x0A, &result
);
636 *value
= (result
>> 7) & 0x01;
639 *value
= data
->mailled
;
642 case ACER_CAP_WIRELESS
:
643 switch (quirks
->wireless
) {
645 ec_read(0x0A, &result
);
646 *value
= (result
>> 2) & 0x01;
649 ec_read(0x71, &result
);
650 *value
= result
& 0x01;
653 *value
= data
->wireless
;
656 case ACER_CAP_BLUETOOTH
:
657 switch (quirks
->bluetooth
) {
659 ec_read(0x0A, &result
);
660 *value
= (result
>> 4) & 0x01;
663 ec_read(0x71, &result
);
664 *value
= (result
>> 1) & 0x01;
667 *value
= data
->bluetooth
;
670 case ACER_CAP_TOUCHPAD_READ
:
671 switch (quirks
->touchpad
) {
673 ec_read(0x74, &result
);
674 *value
= (result
>> 3) & 0x01;
680 return AE_BAD_ADDRESS
;
685 static acpi_status
AMW0_set_bool(bool value
, u32 cap
, struct Interface
*iface
)
687 struct WMAB_args args
;
688 struct acer_data
*data
= &iface
->data
;
691 args
.eax
= ACER_AMW0_WRITE
;
692 args
.ebx
= value
? (1<<8) : 0;
693 args
.ecx
= args
.edx
= 0;
696 case ACER_CAP_MAILLED
:
697 args
.ebx
|= ACER_AMW0_MAILLED_MASK
;
699 case ACER_CAP_WIRELESS
:
700 args
.ebx
|= ACER_AMW0_WIRELESS_MASK
;
702 case ACER_CAP_BLUETOOTH
:
703 args
.ebx
|= ACER_AMW0_BLUETOOTH_MASK
;
706 return AE_BAD_ADDRESS
;
709 /* Actually do the set */
710 status
= WMAB_execute(&args
, NULL
);
713 * Currently no way to query the state, so cache the new value on
716 if (ACPI_SUCCESS(status
)) {
718 case ACER_CAP_MAILLED
:
719 data
->mailled
= value
;
721 case ACER_CAP_WIRELESS
:
722 data
->wireless
= value
;
724 case ACER_CAP_BLUETOOTH
:
725 data
->bluetooth
= value
;
733 static acpi_status
AMW0_get_u8(u8
*value
, u32 cap
, struct Interface
*iface
) {
735 case ACER_CAP_BRIGHTNESS
:
736 switch (quirks
->brightness
) {
738 return ec_read(0x83, value
);
740 return ec_read(0x85, value
);
742 return AE_BAD_ADDRESS
;
746 return AE_BAD_ADDRESS
;
751 static acpi_status
AMW0_set_u8(u8 value
, u32 cap
, struct Interface
*iface
) {
753 case ACER_CAP_BRIGHTNESS
:
754 switch (quirks
->brightness
) {
756 return ec_write(0x83, value
);
758 return ec_write(0x85, value
);
760 return AE_BAD_ADDRESS
;
764 return AE_BAD_ADDRESS
;
769 static struct Interface AMW0_interface
= {
780 * New interface (The WMID interface)
783 WMI_execute_u32(u32 method_id
, u32 in
, u32
*out
)
785 struct acpi_buffer input
= { (acpi_size
) sizeof(u32
), (void *)(&in
) };
786 struct acpi_buffer result
= { ACPI_ALLOCATE_BUFFER
, NULL
};
787 union acpi_object
*obj
;
791 DEBUG(2, " WMI_execute_u32:\n");
792 status
= wmi_acer_evaluate_method(WMID_GUID1
, 1, method_id
, &input
, &result
);
793 DEBUG(2, " In: 0x%08x\n", in
);
795 if (ACPI_FAILURE(status
))
798 obj
= (union acpi_object
*) result
.pointer
;
799 if (obj
&& obj
->type
== ACPI_TYPE_BUFFER
&& obj
->buffer
.length
== sizeof(u32
)) {
800 tmp
= *((u32
*) obj
->buffer
.pointer
);
801 DEBUG(2, " Out: 0x%08x\n", tmp
);
805 DEBUG(2, " Got unexpected result of type %d\n", obj
->type
);
807 DEBUG(2, " Got unexpected null result\n");
814 if (result
.length
> 0 && result
.pointer
)
815 kfree(result
.pointer
);
817 DEBUG(2, " Returning from WMI_execute_u32:\n");
821 static acpi_status
WMID_get_u8(u8
*value
, u32 cap
, struct Interface
*iface
) {
826 DEBUG(2, " WMID_get_u8: cap=%d\n", cap
);
828 case ACER_CAP_WIRELESS
:
829 method_id
= ACER_WMID_GET_WIRELESS_METHODID
;
831 case ACER_CAP_BLUETOOTH
:
832 method_id
= ACER_WMID_GET_BLUETOOTH_METHODID
;
834 case ACER_CAP_BRIGHTNESS
:
835 method_id
= ACER_WMID_GET_BRIGHTNESS_METHODID
;
837 case ACER_CAP_THREEG
:
838 method_id
= ACER_WMID_GET_THREEG_METHODID
;
840 case ACER_CAP_MAILLED
:
841 if (quirks
->mailled
== 1) {
842 ec_read(0x9f, value
);
846 case ACER_CAP_TOUCHPAD_READ
:
847 switch (quirks
->touchpad
) {
849 ec_read(0x9e, value
);
850 *value
= 1 - ((*value
>> 3) & 0x01);
855 case ACER_CAP_TEMPERATURE_OVERRIDE
:
856 if (quirks
->temperature_override
== 1) {
857 ec_read(0xa9, value
);
861 return AE_BAD_ADDRESS
;
863 status
= WMI_execute_u32(method_id
, 0, &result
);
864 DEBUG(2, " WMI_execute_u32 status=%d:\n", status
);
866 if (ACPI_SUCCESS(status
))
869 DEBUG(2, " Returning from WMID_get_u8:\n");
873 static acpi_status
WMID_set_u8(u8 value
, u32 cap
, struct Interface
*iface
) {
877 case ACER_CAP_BRIGHTNESS
:
878 method_id
= ACER_WMID_SET_BRIGHTNESS_METHODID
;
880 case ACER_CAP_WIRELESS
:
881 method_id
= ACER_WMID_SET_WIRELESS_METHODID
;
883 case ACER_CAP_BLUETOOTH
:
884 method_id
= ACER_WMID_SET_BLUETOOTH_METHODID
;
886 case ACER_CAP_THREEG
:
887 method_id
= ACER_WMID_SET_THREEG_METHODID
;
889 case ACER_CAP_MAILLED
:
890 if (quirks
->mailled
== 1) {
891 send_kbd_cmd(0x59, value
? 0x92 : 0x93);
894 case ACER_CAP_TEMPERATURE_OVERRIDE
:
895 if (quirks
->temperature_override
== 1) {
896 ec_write(0xa9, value
);
900 return AE_BAD_ADDRESS
;
902 return WMI_execute_u32(method_id
, (u32
)value
, NULL
);
906 static struct Interface WMID_interface
= {
910 | ACER_CAP_BRIGHTNESS
918 * High-level Procfs file handlers
922 dispatch_read(char *page
, char **start
, off_t off
, int count
, int *eof
,
923 struct ProcItem
*item
)
928 DEBUG(2, " dispatch_read: \n");
930 p
= item
->read_func(p
, item
->capability
);
932 if (len
<= off
+ count
)
944 dispatch_write(struct file
*file
, const char __user
*buffer
,
945 unsigned long count
, struct ProcItem
*item
)
951 * Arg buffer points to userspace memory, which can't be accessed
952 * directly. Since we're making a copy, zero-terminate the
953 * destination so that sscanf can be used on it safely.
955 tmp_buffer
= kmalloc(count
+ 1, GFP_KERNEL
);
956 if (copy_from_user(tmp_buffer
, buffer
, count
)) {
959 tmp_buffer
[count
] = 0;
960 result
= item
->write_func(tmp_buffer
, count
, item
->capability
);
968 * Generic Device (interface-independent)
971 static acpi_status
get_bool(bool *value
, u32 cap
) {
972 acpi_status status
= AE_BAD_ADDRESS
;
975 DEBUG(2, " get_bool: cap=%d, interface type=%d\n",
976 cap
, interface
->type
);
977 switch (interface
->type
) {
979 status
= AMW0_get_bool(value
, cap
, interface
);
982 status
= WMID_get_u8(&tmp
, cap
, interface
);
983 *value
= (tmp
== 1) ? 1 : 0;
986 DEBUG(2, " Returning from get_bool:\n");
990 static acpi_status
set_bool(int value
, u32 cap
) {
991 acpi_status status
= AE_BAD_PARAMETER
;
993 DEBUG(2, " set_bool: cap=%d, interface type=%d, value=%d\n",
994 cap
, interface
->type
, value
);
995 if ((value
== 0 || value
== 1) && (interface
->capability
& cap
)) {
996 switch (interface
->type
) {
998 status
= AMW0_set_bool(value
== 1, cap
, interface
);
1001 status
= WMID_set_u8(value
== 1, cap
, interface
);
1008 static acpi_status
get_u8(u8
*value
, u32 cap
) {
1009 DEBUG(2, " get_u8: cap=%d\n", cap
);
1010 switch (interface
->type
) {
1012 return AMW0_get_u8(value
, cap
, interface
);
1015 return WMID_get_u8(value
, cap
, interface
);
1018 return AE_BAD_ADDRESS
;
1022 static acpi_status
set_u8(u8 value
, u8 min
, u8 max
, u32 cap
) {
1024 DEBUG(2, " set_u8: cap=%d, interface type=%d, value=%d\n",
1025 cap
, interface
->type
, value
);
1027 if ((value
>= min
&& value
<= max
) && (interface
->capability
& cap
) ) {
1028 switch (interface
->type
) {
1030 return AMW0_set_u8(value
, cap
, interface
);
1032 return WMID_set_u8(value
, cap
, interface
);
1034 return AE_BAD_PARAMETER
;
1037 return AE_BAD_PARAMETER
;
1040 /* Each _u8 needs a small wrapper that sets the boundary values */
1041 static acpi_status
set_brightness(u8 value
)
1043 return set_u8(value
, 0, max_brightness
, ACER_CAP_BRIGHTNESS
);
1046 static acpi_status
set_temperature_override(u8 value
)
1048 return set_u8(value
, 0, ACER_MAX_TEMPERATURE_OVERRIDE
, ACER_CAP_TEMPERATURE_OVERRIDE
);
1051 static void __init
acer_commandline_init(void)
1053 DEBUG(1, "Commandline args: mailled(%d) wireless(%d) bluetooth(%d) brightness(%d)\n",
1054 mailled
, wireless
, bluetooth
, brightness
);
1057 * These will all fail silently if the value given is invalid, or the
1058 * capability isn't available on the given interface
1060 set_bool(mailled
, ACER_CAP_MAILLED
);
1061 set_bool(wireless
, ACER_CAP_WIRELESS
);
1062 set_bool(bluetooth
, ACER_CAP_BLUETOOTH
);
1063 set_bool(threeg
, ACER_CAP_THREEG
);
1064 set_temperature_override(fan_temperature_override
);
1065 set_brightness((u8
)brightness
);
1070 * Procfs interface (deprecated)
1072 static char *read_bool(char *p
, u32 cap
)
1077 DEBUG(2, " read_bool: cap=%d\n", cap
);
1078 status
= get_bool(&result
, cap
);
1079 if (ACPI_SUCCESS(status
))
1080 p
+= sprintf(p
, "%d\n", result
);
1082 p
+= sprintf(p
, "Read error" );
1086 static unsigned long write_bool(const char *buffer
, unsigned long count
, u32 cap
)
1090 DEBUG(2, " write_bool: cap=%d, interface type=%d\n buffer=%s\n",
1091 cap
, interface
->type
, buffer
);
1093 if (sscanf(buffer
, "%i", &value
) == 1) {
1094 acpi_status status
= set_bool(value
, cap
);
1095 if (ACPI_FAILURE(status
))
1103 static char *read_u8(char *p
, u32 cap
)
1108 DEBUG(2, " read_u8: cap=%d\n", cap
);
1109 status
= get_u8(&result
, cap
);
1110 if (ACPI_SUCCESS(status
))
1111 p
+= sprintf(p
, "%u\n", result
);
1113 p
+= sprintf(p
, "Read error" );
1117 static unsigned long write_u8(const char *buffer
, unsigned long count
, u32 cap
)
1120 acpi_status (*set_method
)(u8
);
1122 /* Choose the appropriate set_u8 wrapper here, based on the capability */
1124 case ACER_CAP_BRIGHTNESS
:
1125 set_method
= set_brightness
;
1127 case ACER_CAP_TEMPERATURE_OVERRIDE
:
1128 set_method
= set_temperature_override
;
1134 if (sscanf(buffer
, "%i", &value
) == 1) {
1135 acpi_status status
= (*set_method
)(value
);
1136 if (ACPI_FAILURE(status
))
1144 static char *read_version(char *p
, u32 cap
)
1146 p
+= sprintf(p
, "%s\n", ACER_ACPI_VERSION
);
1150 static char *read_interface(char *p
, u32 cap
)
1152 p
+= sprintf(p
, "%s\n", (interface
->type
== ACER_AMW0
) ? "AMW0": "WMID");
1156 static struct ProcItem proc_items
[] = {
1157 {"mailled", read_bool
, write_bool
, ACER_CAP_MAILLED
},
1158 {"bluetooth", read_bool
, write_bool
, ACER_CAP_BLUETOOTH
},
1159 {"wireless", read_bool
, write_bool
, ACER_CAP_WIRELESS
},
1160 {"brightness", read_u8
, write_u8
, ACER_CAP_BRIGHTNESS
},
1161 {"threeg", read_bool
, write_bool
, ACER_CAP_THREEG
},
1162 {"touchpad", read_bool
, NULL
, ACER_CAP_TOUCHPAD_READ
},
1163 {"fan_temperature_override", read_u8
, write_u8
, ACER_CAP_TEMPERATURE_OVERRIDE
},
1164 {"version", read_version
, NULL
, ACER_CAP_ANY
},
1165 {"interface", read_interface
, NULL
, ACER_CAP_ANY
},
1169 static int __init
add_proc_entries(void)
1171 struct proc_dir_entry
*proc
;
1172 struct ProcItem
*item
;
1174 for (item
= proc_items
; item
->name
; ++item
) {
1176 * Only add the proc file if the current interface actually
1179 if (interface
->capability
& item
->capability
) {
1180 proc
= create_proc_read_entry(item
->name
,
1181 S_IFREG
| S_IRUGO
| S_IWUSR
,
1183 (read_proc_t
*) dispatch_read
,
1186 proc
->owner
= THIS_MODULE
;
1187 if (proc
&& item
->write_func
)
1188 proc
->write_proc
= (write_proc_t
*) dispatch_write
;
1195 static int __exit
remove_proc_entries(void)
1197 struct ProcItem
*item
;
1199 for (item
= proc_items
; item
->name
; ++item
)
1200 remove_proc_entry(item
->name
, acer_proc_dir
);
1206 * LED device (Mail LED only, no other LEDs known yet)
1208 static void mail_led_set(struct led_classdev
*led_cdev
, enum led_brightness value
)
1211 set_bool(tmp
, ACER_CAP_MAILLED
);
1214 static struct led_classdev mail_led
= {
1215 .name
= "acer_acpi:mail",
1216 .brightness_set
= mail_led_set
,
1219 static void acer_led_init(struct device
*dev
)
1221 led_classdev_register(dev
, &mail_led
);
1224 static void acer_led_exit(void)
1226 led_classdev_unregister(&mail_led
);
1229 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,18)
1233 static struct backlight_device
*acer_backlight_device
;
1235 static int read_brightness(struct backlight_device
*bd
)
1238 get_u8(&value
, ACER_CAP_BRIGHTNESS
);
1242 #if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,20)
1243 static int update_bl_status(struct backlight_device
*bd
)
1245 set_brightness(bd
->props
->brightness
);
1249 static struct backlight_properties acer_backlight_properties
= {
1250 .get_brightness
= read_brightness
,
1251 .update_status
= update_bl_status
,
1254 static int __init
acer_backlight_init(struct device
*dev
)
1256 struct backlight_device
*bd
;
1258 DEBUG(1, "Loading backlight driver\n");
1259 bd
= backlight_device_register("acer_acpi", dev
, NULL
, &acer_backlight_properties
);
1261 printk(ACER_ERR
"Could not register Acer backlight device\n");
1262 acer_backlight_device
= NULL
;
1266 acer_backlight_device
= bd
;
1268 bd
->props
->max_brightness
= max_brightness
;
1272 static int update_bl_status(struct backlight_device
*bd
)
1274 set_brightness(bd
->props
.brightness
);
1278 static struct backlight_ops acer_backlight_ops
= {
1279 .get_brightness
= read_brightness
,
1280 .update_status
= update_bl_status
,
1283 static int __init
acer_backlight_init(struct device
*dev
)
1285 struct backlight_device
*bd
;
1287 DEBUG(1, "Loading backlight driver\n");
1288 bd
= backlight_device_register("acer_acpi", dev
, NULL
, &acer_backlight_ops
);
1290 printk(ACER_ERR
"Could not register Acer backlight device\n");
1291 acer_backlight_device
= NULL
;
1295 acer_backlight_device
= bd
;
1297 bd
->props
.max_brightness
= max_brightness
;
1298 bd
->props
.brightness
= read_brightness(NULL
);
1299 backlight_update_status(bd
);
1304 static void __exit
acer_backlight_exit(void)
1306 backlight_device_unregister(acer_backlight_device
);
1311 * Read/ write bool sysfs macro
1313 #define show_set_bool(value, cap) \
1315 show_bool_##value(struct device *dev, struct device_attribute *attr, \
1319 acpi_status status = get_bool(&result, cap); \
1320 if (ACPI_SUCCESS(status)) \
1321 return sprintf(buf, "%d\n", result); \
1322 return sprintf(buf, "Read error" ); \
1326 set_bool_##value(struct device *dev, struct device_attribute *attr, \
1327 const char *buf, size_t count) \
1329 bool tmp = simple_strtoul(buf, NULL, 10); \
1330 acpi_status status = set_bool(tmp, cap); \
1331 if (ACPI_FAILURE(status)) \
1335 static DEVICE_ATTR(value, S_IWUGO | S_IRUGO | S_IWUSR, \
1336 show_bool_##value, set_bool_##value);
1338 show_set_bool(wireless
, ACER_CAP_WIRELESS
);
1339 show_set_bool(bluetooth
, ACER_CAP_BLUETOOTH
);
1340 show_set_bool(threeg
, ACER_CAP_THREEG
);
1341 show_set_bool(fan_temperature_override
, ACER_CAP_TEMPERATURE_OVERRIDE
);
1344 * Read-only bool sysfs macro
1346 #define show_bool(value, cap) \
1348 show_bool_##value(struct device *dev, struct device_attribute *attr, \
1352 acpi_status status = get_bool(&result, cap); \
1353 if (ACPI_SUCCESS(status)) \
1354 return sprintf(buf, "%d\n", result); \
1355 return sprintf(buf, "Read error" ); \
1357 static DEVICE_ATTR(value, S_IWUGO | S_IRUGO | S_IWUSR, \
1358 show_bool_##value, NULL);
1360 show_bool(touchpad
, ACER_CAP_TOUCHPAD_READ
);
1363 * Read interface sysfs macro
1365 static ssize_t
show_interface(struct device
*dev
, struct device_attribute
*attr
,
1368 return sprintf(buf
, "%s\n", (interface
->type
== ACER_AMW0
) ? "AMW0" : "WMID");
1371 static DEVICE_ATTR(interface
, S_IWUGO
| S_IRUGO
| S_IWUSR
, show_interface
, NULL
);
1376 static int __devinit
acer_platform_probe(struct platform_device
*device
)
1378 if (has_cap(ACER_CAP_MAILLED
))
1379 acer_led_init(&device
->dev
);
1380 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,18)
1381 if (has_cap(ACER_CAP_BRIGHTNESS
))
1382 acer_backlight_init(&device
->dev
);
1387 static int acer_platform_remove(struct platform_device
*device
)
1389 if (has_cap(ACER_CAP_MAILLED
))
1391 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,18)
1392 if (has_cap(ACER_CAP_BRIGHTNESS
))
1393 acer_backlight_exit();
1398 static int acer_platform_suspend(struct platform_device
*device
, pm_message_t state
)
1401 * WMID fix for suspend-to-disk - save all current states now so we can
1402 * restore them on resume
1406 struct acer_data
*data
= &interface
->data
;
1408 #define save_bool_device(device, cap) \
1409 if (has_cap(cap)) {\
1410 get_bool(&value, cap);\
1411 data->device = value;\
1414 #define save_u8_device(device, cap) \
1415 if (has_cap(cap)) {\
1416 get_u8(&u8value, cap);\
1417 data->device = u8value;\
1420 if (interface
->type
== ACER_WMID
) {
1421 save_bool_device(wireless
, ACER_CAP_WIRELESS
);
1422 save_bool_device(bluetooth
, ACER_CAP_BLUETOOTH
);
1423 save_bool_device(threeg
, ACER_CAP_THREEG
);
1424 save_u8_device(brightness
, ACER_CAP_BRIGHTNESS
);
1430 static int acer_platform_resume(struct platform_device
*device
)
1432 struct acer_data
*data
= &interface
->data
;
1434 #define restore_bool_device(device, cap) \
1436 set_bool(data->device, cap);\
1438 restore_bool_device(wireless, ACER_CAP_WIRELESS);
1439 restore_bool_device(bluetooth
, ACER_CAP_BLUETOOTH
);
1440 restore_bool_device(threeg
, ACER_CAP_THREEG
);
1441 restore_bool_device(mailled
, ACER_CAP_MAILLED
);
1443 if (has_cap(ACER_CAP_BRIGHTNESS
))
1444 set_brightness((u8
)data
->brightness
);
1446 /* Check if this laptop requires the keyboard quirk */
1447 if (quirks
->mmkeys
!= 0) {
1448 set_keyboard_quirk();
1449 printk(ACER_INFO
"Setting keyboard quirk to enable multimedia keys\n");
1455 static struct platform_driver acer_platform_driver
= {
1457 .name
= "acer_acpi",
1458 .owner
= THIS_MODULE
,
1460 .probe
= acer_platform_probe
,
1461 .remove
= acer_platform_remove
,
1462 .suspend
= acer_platform_suspend
,
1463 .resume
= acer_platform_resume
,
1466 static struct platform_device
*acer_platform_device
;
1468 static int remove_sysfs(struct platform_device
*device
)
1470 #define remove_device_file(value, cap) \
1472 device_remove_file(&device->dev, &dev_attr_##value);
1474 remove_device_file(wireless
, ACER_CAP_WIRELESS
);
1475 remove_device_file(bluetooth
, ACER_CAP_BLUETOOTH
);
1476 remove_device_file(threeg
, ACER_CAP_THREEG
);
1477 remove_device_file(interface
, ACER_CAP_ANY
);
1478 remove_device_file(fan_temperature_override
, ACER_CAP_TEMPERATURE_OVERRIDE
);
1479 remove_device_file(touchpad
, ACER_CAP_TOUCHPAD_READ
);
1483 static int create_sysfs(void)
1485 int retval
= -ENOMEM
;
1487 #define add_device_file(value, cap) \
1488 if (has_cap(cap)) {\
1489 retval = device_create_file(&acer_platform_device->dev, &dev_attr_##value);\
1494 add_device_file(wireless
, ACER_CAP_WIRELESS
);
1495 add_device_file(bluetooth
, ACER_CAP_BLUETOOTH
);
1496 add_device_file(threeg
, ACER_CAP_THREEG
);
1497 add_device_file(interface
, ACER_CAP_ANY
);
1498 add_device_file(fan_temperature_override
, ACER_CAP_TEMPERATURE_OVERRIDE
);
1499 add_device_file(touchpad
, ACER_CAP_TOUCHPAD_READ
);
1504 remove_sysfs(acer_platform_device
);
1508 static int __init
acer_acpi_init(void)
1510 printk(ACER_INFO
"Acer Laptop ACPI Extras version %s\n",
1514 * Detect which WMI interface we're using.
1515 * Check for AMW0 first, as later AMW0 laptops also have the WMID GUID.
1517 if (wmi_acer_has_guid(AMW0_GUID1
)) {
1518 DEBUG(0, "Detected Acer AMW0 interface\n");
1519 interface
= &AMW0_interface
;
1520 } else if (wmi_acer_has_guid(WMID_GUID1
)) {
1521 DEBUG(0, "Detected Acer WMID interface\n");
1522 interface
= &WMID_interface
;
1524 printk(ACER_ERR
"No or unsupported WMI interface, unable to load.\n");
1528 /* Find if this laptop requires any quirks */
1529 DEBUG(1, "Finding quirks\n");
1532 /* Now that we have a known interface, initialize it */
1533 DEBUG(1, "Initialising interface\n");
1534 if (interface
->init
)
1535 interface
->init(interface
);
1538 /* Create the proc entries */
1539 acer_proc_dir
= proc_mkdir(PROC_ACER
, acpi_root_dir
);
1540 if (!acer_proc_dir
) {
1541 printk(ACER_ERR
"Unable to create /proc entries, aborting.\n");
1542 goto error_proc_mkdir
;
1545 acer_proc_dir
->owner
= THIS_MODULE
;
1546 if (add_proc_entries()) {
1547 printk(ACER_ERR
"Unable to create /proc entries, aborting.\n");
1548 goto error_proc_add
;
1553 * Register the driver
1555 if (platform_driver_register(&acer_platform_driver
)) {
1556 printk(ACER_ERR
"Unable to register platform driver, aborting.\n");
1557 goto error_platform_register
;
1559 acer_platform_device
= platform_device_alloc("acer_acpi", -1);
1560 platform_device_add(acer_platform_device
);
1564 DEBUG(1, "Driver registered\n");
1566 /* Override any initial settings with values from the commandline */
1567 acer_commandline_init();
1571 error_platform_register
:
1573 remove_proc_entries();
1576 remove_proc_entry(PROC_ACER
, acpi_root_dir
);
1582 static void __exit
acer_acpi_exit(void)
1584 remove_sysfs(acer_platform_device
);
1585 platform_device_del(acer_platform_device
);
1586 platform_driver_unregister(&acer_platform_driver
);
1589 remove_proc_entries();
1592 remove_proc_entry(PROC_ACER
, acpi_root_dir
);
1594 printk(ACER_INFO
"Acer Laptop ACPI Extras unloaded\n");
1598 module_init(acer_acpi_init
);
1599 module_exit(acer_acpi_exit
);