2 * Acer WMI Laptop Extras
4 * Copyright (C) 2007-2009 Carlos Corbacho <carlos@strangeworlds.co.uk>
7 * Copyright (C) 2005-2007 E.M. Smith
8 * Copyright (C) 2007-2008 Carlos Corbacho <cathectic@gmail.com>
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of the GNU General Public License as published by
12 * the Free Software Foundation; either version 2 of the License, or
13 * (at your option) any later version.
15 * This program is distributed in the hope that it will be useful,
16 * but WITHOUT ANY WARRANTY; without even the implied warranty of
17 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
18 * GNU General Public License for more details.
20 * You should have received a copy of the GNU General Public License
21 * along with this program; if not, write to the Free Software
22 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
25 #include <linux/kernel.h>
26 #include <linux/module.h>
27 #include <linux/init.h>
28 #include <linux/types.h>
29 #include <linux/dmi.h>
31 #include <linux/backlight.h>
32 #include <linux/leds.h>
33 #include <linux/platform_device.h>
34 #include <linux/acpi.h>
35 #include <linux/i8042.h>
36 #include <linux/rfkill.h>
37 #include <linux/workqueue.h>
38 #include <linux/debugfs.h>
39 #include <linux/slab.h>
41 #include <acpi/acpi_drivers.h>
43 MODULE_AUTHOR("Carlos Corbacho");
44 MODULE_DESCRIPTION("Acer Laptop WMI Extras Driver");
45 MODULE_LICENSE("GPL");
47 #define ACER_LOGPREFIX "acer-wmi: "
48 #define ACER_ERR KERN_ERR ACER_LOGPREFIX
49 #define ACER_NOTICE KERN_NOTICE ACER_LOGPREFIX
50 #define ACER_INFO KERN_INFO ACER_LOGPREFIX
53 * The following defines quirks to get some specific functions to work
54 * which are known to not be supported over ACPI-WMI (such as the mail LED
55 * on WMID based Acer's)
65 * Meaning is unknown - this number is required for writing to ACPI for AMW0
66 * (it's also used in acerhk when directly accessing the BIOS)
68 #define ACER_AMW0_WRITE 0x9610
71 * Bit masks for the AMW0 interface
73 #define ACER_AMW0_WIRELESS_MASK 0x35
74 #define ACER_AMW0_BLUETOOTH_MASK 0x34
75 #define ACER_AMW0_MAILLED_MASK 0x31
78 * Method IDs for WMID interface
80 #define ACER_WMID_GET_WIRELESS_METHODID 1
81 #define ACER_WMID_GET_BLUETOOTH_METHODID 2
82 #define ACER_WMID_GET_BRIGHTNESS_METHODID 3
83 #define ACER_WMID_SET_WIRELESS_METHODID 4
84 #define ACER_WMID_SET_BLUETOOTH_METHODID 5
85 #define ACER_WMID_SET_BRIGHTNESS_METHODID 6
86 #define ACER_WMID_GET_THREEG_METHODID 10
87 #define ACER_WMID_SET_THREEG_METHODID 11
90 * Acer ACPI method GUIDs
92 #define AMW0_GUID1 "67C3371D-95A3-4C37-BB61-DD47B491DAAB"
93 #define AMW0_GUID2 "431F16ED-0C2B-444C-B267-27DEB140CF9C"
94 #define WMID_GUID1 "6AF4F258-B401-42fd-BE91-3D4AC2D7C0D3"
95 #define WMID_GUID2 "95764E09-FB56-4e83-B31A-37761F60994A"
97 MODULE_ALIAS("wmi:67C3371D-95A3-4C37-BB61-DD47B491DAAB");
98 MODULE_ALIAS("wmi:6AF4F258-B401-42fd-BE91-3D4AC2D7C0D3");
101 * Interface capability flags
103 #define ACER_CAP_MAILLED (1<<0)
104 #define ACER_CAP_WIRELESS (1<<1)
105 #define ACER_CAP_BLUETOOTH (1<<2)
106 #define ACER_CAP_BRIGHTNESS (1<<3)
107 #define ACER_CAP_THREEG (1<<4)
108 #define ACER_CAP_ANY (0xFFFFFFFF)
111 * Interface type flags
113 enum interface_flags
{
119 #define ACER_DEFAULT_WIRELESS 0
120 #define ACER_DEFAULT_BLUETOOTH 0
121 #define ACER_DEFAULT_MAILLED 0
122 #define ACER_DEFAULT_THREEG 0
124 static int max_brightness
= 0xF;
126 static int mailled
= -1;
127 static int brightness
= -1;
128 static int threeg
= -1;
129 static int force_series
;
131 module_param(mailled
, int, 0444);
132 module_param(brightness
, int, 0444);
133 module_param(threeg
, int, 0444);
134 module_param(force_series
, int, 0444);
135 MODULE_PARM_DESC(mailled
, "Set initial state of Mail LED");
136 MODULE_PARM_DESC(brightness
, "Set initial LCD backlight brightness");
137 MODULE_PARM_DESC(threeg
, "Set initial state of 3G hardware");
138 MODULE_PARM_DESC(force_series
, "Force a different laptop series");
148 struct dentry
*devices
;
152 static struct rfkill
*wireless_rfkill
;
153 static struct rfkill
*bluetooth_rfkill
;
155 /* Each low-level interface must define at least some of the following */
156 struct wmi_interface
{
157 /* The WMI device type */
160 /* The capabilities this interface provides */
163 /* Private data for the current interface */
164 struct acer_data data
;
166 /* debugfs entries associated with this interface */
167 struct acer_debug debug
;
170 /* The static interface pointer, points to the currently detected interface */
171 static struct wmi_interface
*interface
;
174 * Embedded Controller quirks
175 * Some laptops require us to directly access the EC to either enable or query
176 * features that are not available through WMI.
186 static struct quirk_entry
*quirks
;
188 static void set_quirks(void)
194 interface
->capability
|= ACER_CAP_MAILLED
;
196 if (quirks
->brightness
)
197 interface
->capability
|= ACER_CAP_BRIGHTNESS
;
200 static int dmi_matched(const struct dmi_system_id
*dmi
)
202 quirks
= dmi
->driver_data
;
206 static struct quirk_entry quirk_unknown
= {
209 static struct quirk_entry quirk_acer_aspire_1520
= {
213 static struct quirk_entry quirk_acer_travelmate_2490
= {
217 /* This AMW0 laptop has no bluetooth */
218 static struct quirk_entry quirk_medion_md_98300
= {
222 static struct quirk_entry quirk_fujitsu_amilo_li_1718
= {
226 /* The Aspire One has a dummy ACPI-WMI interface - disable it */
227 static struct dmi_system_id __devinitdata acer_blacklist
[] = {
229 .ident
= "Acer Aspire One (SSD)",
231 DMI_MATCH(DMI_SYS_VENDOR
, "Acer"),
232 DMI_MATCH(DMI_PRODUCT_NAME
, "AOA110"),
236 .ident
= "Acer Aspire One (HDD)",
238 DMI_MATCH(DMI_SYS_VENDOR
, "Acer"),
239 DMI_MATCH(DMI_PRODUCT_NAME
, "AOA150"),
245 static struct dmi_system_id acer_quirks
[] = {
247 .callback
= dmi_matched
,
248 .ident
= "Acer Aspire 1360",
250 DMI_MATCH(DMI_SYS_VENDOR
, "Acer"),
251 DMI_MATCH(DMI_PRODUCT_NAME
, "Aspire 1360"),
253 .driver_data
= &quirk_acer_aspire_1520
,
256 .callback
= dmi_matched
,
257 .ident
= "Acer Aspire 1520",
259 DMI_MATCH(DMI_SYS_VENDOR
, "Acer"),
260 DMI_MATCH(DMI_PRODUCT_NAME
, "Aspire 1520"),
262 .driver_data
= &quirk_acer_aspire_1520
,
265 .callback
= dmi_matched
,
266 .ident
= "Acer Aspire 3100",
268 DMI_MATCH(DMI_SYS_VENDOR
, "Acer"),
269 DMI_MATCH(DMI_PRODUCT_NAME
, "Aspire 3100"),
271 .driver_data
= &quirk_acer_travelmate_2490
,
274 .callback
= dmi_matched
,
275 .ident
= "Acer Aspire 3610",
277 DMI_MATCH(DMI_SYS_VENDOR
, "Acer"),
278 DMI_MATCH(DMI_PRODUCT_NAME
, "Aspire 3610"),
280 .driver_data
= &quirk_acer_travelmate_2490
,
283 .callback
= dmi_matched
,
284 .ident
= "Acer Aspire 5100",
286 DMI_MATCH(DMI_SYS_VENDOR
, "Acer"),
287 DMI_MATCH(DMI_PRODUCT_NAME
, "Aspire 5100"),
289 .driver_data
= &quirk_acer_travelmate_2490
,
292 .callback
= dmi_matched
,
293 .ident
= "Acer Aspire 5610",
295 DMI_MATCH(DMI_SYS_VENDOR
, "Acer"),
296 DMI_MATCH(DMI_PRODUCT_NAME
, "Aspire 5610"),
298 .driver_data
= &quirk_acer_travelmate_2490
,
301 .callback
= dmi_matched
,
302 .ident
= "Acer Aspire 5630",
304 DMI_MATCH(DMI_SYS_VENDOR
, "Acer"),
305 DMI_MATCH(DMI_PRODUCT_NAME
, "Aspire 5630"),
307 .driver_data
= &quirk_acer_travelmate_2490
,
310 .callback
= dmi_matched
,
311 .ident
= "Acer Aspire 5650",
313 DMI_MATCH(DMI_SYS_VENDOR
, "Acer"),
314 DMI_MATCH(DMI_PRODUCT_NAME
, "Aspire 5650"),
316 .driver_data
= &quirk_acer_travelmate_2490
,
319 .callback
= dmi_matched
,
320 .ident
= "Acer Aspire 5680",
322 DMI_MATCH(DMI_SYS_VENDOR
, "Acer"),
323 DMI_MATCH(DMI_PRODUCT_NAME
, "Aspire 5680"),
325 .driver_data
= &quirk_acer_travelmate_2490
,
328 .callback
= dmi_matched
,
329 .ident
= "Acer Aspire 9110",
331 DMI_MATCH(DMI_SYS_VENDOR
, "Acer"),
332 DMI_MATCH(DMI_PRODUCT_NAME
, "Aspire 9110"),
334 .driver_data
= &quirk_acer_travelmate_2490
,
337 .callback
= dmi_matched
,
338 .ident
= "Acer TravelMate 2490",
340 DMI_MATCH(DMI_SYS_VENDOR
, "Acer"),
341 DMI_MATCH(DMI_PRODUCT_NAME
, "TravelMate 2490"),
343 .driver_data
= &quirk_acer_travelmate_2490
,
346 .callback
= dmi_matched
,
347 .ident
= "Acer TravelMate 4200",
349 DMI_MATCH(DMI_SYS_VENDOR
, "Acer"),
350 DMI_MATCH(DMI_PRODUCT_NAME
, "TravelMate 4200"),
352 .driver_data
= &quirk_acer_travelmate_2490
,
355 .callback
= dmi_matched
,
356 .ident
= "Fujitsu Siemens Amilo Li 1718",
358 DMI_MATCH(DMI_SYS_VENDOR
, "FUJITSU SIEMENS"),
359 DMI_MATCH(DMI_PRODUCT_NAME
, "AMILO Li 1718"),
361 .driver_data
= &quirk_fujitsu_amilo_li_1718
,
364 .callback
= dmi_matched
,
365 .ident
= "Medion MD 98300",
367 DMI_MATCH(DMI_SYS_VENDOR
, "MEDION"),
368 DMI_MATCH(DMI_PRODUCT_NAME
, "WAM2030"),
370 .driver_data
= &quirk_medion_md_98300
,
375 /* Find which quirks are needed for a particular vendor/ model pair */
376 static void find_quirks(void)
379 dmi_check_system(acer_quirks
);
380 } else if (force_series
== 2490) {
381 quirks
= &quirk_acer_travelmate_2490
;
385 quirks
= &quirk_unknown
;
391 * General interface convenience methods
394 static bool has_cap(u32 cap
)
396 if ((interface
->capability
& cap
) != 0)
403 * AMW0 (V1) interface
420 static acpi_status
wmab_execute(struct wmab_args
*regbuf
,
421 struct acpi_buffer
*result
)
423 struct acpi_buffer input
;
425 input
.length
= sizeof(struct wmab_args
);
426 input
.pointer
= (u8
*)regbuf
;
428 status
= wmi_evaluate_method(AMW0_GUID1
, 1, 1, &input
, result
);
433 static acpi_status
AMW0_get_u32(u32
*value
, u32 cap
,
434 struct wmi_interface
*iface
)
440 case ACER_CAP_MAILLED
:
441 switch (quirks
->mailled
) {
443 err
= ec_read(0xA, &result
);
446 *value
= (result
>> 7) & 0x1;
450 case ACER_CAP_WIRELESS
:
451 switch (quirks
->wireless
) {
453 err
= ec_read(0x7B, &result
);
456 *value
= result
& 0x1;
459 err
= ec_read(0x71, &result
);
462 *value
= result
& 0x1;
465 err
= ec_read(0xA, &result
);
468 *value
= (result
>> 2) & 0x1;
472 case ACER_CAP_BLUETOOTH
:
473 switch (quirks
->bluetooth
) {
475 err
= ec_read(0xA, &result
);
478 *value
= (result
>> 4) & 0x1;
482 case ACER_CAP_BRIGHTNESS
:
483 switch (quirks
->brightness
) {
485 err
= ec_read(0x83, &result
);
498 static acpi_status
AMW0_set_u32(u32 value
, u32 cap
, struct wmi_interface
*iface
)
500 struct wmab_args args
;
502 args
.eax
= ACER_AMW0_WRITE
;
503 args
.ebx
= value
? (1<<8) : 0;
504 args
.ecx
= args
.edx
= 0;
507 case ACER_CAP_MAILLED
:
509 return AE_BAD_PARAMETER
;
510 args
.ebx
|= ACER_AMW0_MAILLED_MASK
;
512 case ACER_CAP_WIRELESS
:
514 return AE_BAD_PARAMETER
;
515 args
.ebx
|= ACER_AMW0_WIRELESS_MASK
;
517 case ACER_CAP_BLUETOOTH
:
519 return AE_BAD_PARAMETER
;
520 args
.ebx
|= ACER_AMW0_BLUETOOTH_MASK
;
522 case ACER_CAP_BRIGHTNESS
:
523 if (value
> max_brightness
)
524 return AE_BAD_PARAMETER
;
525 switch (quirks
->brightness
) {
527 return ec_write(0x83, value
);
534 /* Actually do the set */
535 return wmab_execute(&args
, NULL
);
538 static acpi_status
AMW0_find_mailled(void)
540 struct wmab_args args
;
542 acpi_status status
= AE_OK
;
543 struct acpi_buffer out
= { ACPI_ALLOCATE_BUFFER
, NULL
};
544 union acpi_object
*obj
;
547 args
.ebx
= args
.ecx
= args
.edx
= 0;
549 status
= wmab_execute(&args
, &out
);
550 if (ACPI_FAILURE(status
))
553 obj
= (union acpi_object
*) out
.pointer
;
554 if (obj
&& obj
->type
== ACPI_TYPE_BUFFER
&&
555 obj
->buffer
.length
== sizeof(struct wmab_ret
)) {
556 ret
= *((struct wmab_ret
*) obj
->buffer
.pointer
);
562 interface
->capability
|= ACER_CAP_MAILLED
;
569 static acpi_status
AMW0_set_capabilities(void)
571 struct wmab_args args
;
573 acpi_status status
= AE_OK
;
574 struct acpi_buffer out
= { ACPI_ALLOCATE_BUFFER
, NULL
};
575 union acpi_object
*obj
;
578 * On laptops with this strange GUID (non Acer), normal probing doesn't
581 if (wmi_has_guid(AMW0_GUID2
)) {
582 interface
->capability
|= ACER_CAP_WIRELESS
;
586 args
.eax
= ACER_AMW0_WRITE
;
587 args
.ecx
= args
.edx
= 0;
589 args
.ebx
= 0xa2 << 8;
590 args
.ebx
|= ACER_AMW0_WIRELESS_MASK
;
592 status
= wmab_execute(&args
, &out
);
593 if (ACPI_FAILURE(status
))
596 obj
= (union acpi_object
*) out
.pointer
;
597 if (obj
&& obj
->type
== ACPI_TYPE_BUFFER
&&
598 obj
->buffer
.length
== sizeof(struct wmab_ret
)) {
599 ret
= *((struct wmab_ret
*) obj
->buffer
.pointer
);
605 interface
->capability
|= ACER_CAP_WIRELESS
;
608 args
.ebx
|= ACER_AMW0_BLUETOOTH_MASK
;
610 status
= wmab_execute(&args
, &out
);
611 if (ACPI_FAILURE(status
))
614 obj
= (union acpi_object
*) out
.pointer
;
615 if (obj
&& obj
->type
== ACPI_TYPE_BUFFER
616 && obj
->buffer
.length
== sizeof(struct wmab_ret
)) {
617 ret
= *((struct wmab_ret
*) obj
->buffer
.pointer
);
623 interface
->capability
|= ACER_CAP_BLUETOOTH
;
628 * This appears to be safe to enable, since all Wistron based laptops
629 * appear to use the same EC register for brightness, even if they
630 * differ for wireless, etc
632 if (quirks
->brightness
>= 0)
633 interface
->capability
|= ACER_CAP_BRIGHTNESS
;
638 static struct wmi_interface AMW0_interface
= {
642 static struct wmi_interface AMW0_V2_interface
= {
643 .type
= ACER_AMW0_V2
,
647 * New interface (The WMID interface)
650 WMI_execute_u32(u32 method_id
, u32 in
, u32
*out
)
652 struct acpi_buffer input
= { (acpi_size
) sizeof(u32
), (void *)(&in
) };
653 struct acpi_buffer result
= { ACPI_ALLOCATE_BUFFER
, NULL
};
654 union acpi_object
*obj
;
658 status
= wmi_evaluate_method(WMID_GUID1
, 1, method_id
, &input
, &result
);
660 if (ACPI_FAILURE(status
))
663 obj
= (union acpi_object
*) result
.pointer
;
664 if (obj
&& obj
->type
== ACPI_TYPE_BUFFER
&&
665 obj
->buffer
.length
== sizeof(u32
)) {
666 tmp
= *((u32
*) obj
->buffer
.pointer
);
674 kfree(result
.pointer
);
679 static acpi_status
WMID_get_u32(u32
*value
, u32 cap
,
680 struct wmi_interface
*iface
)
684 u32 result
, method_id
= 0;
687 case ACER_CAP_WIRELESS
:
688 method_id
= ACER_WMID_GET_WIRELESS_METHODID
;
690 case ACER_CAP_BLUETOOTH
:
691 method_id
= ACER_WMID_GET_BLUETOOTH_METHODID
;
693 case ACER_CAP_BRIGHTNESS
:
694 method_id
= ACER_WMID_GET_BRIGHTNESS_METHODID
;
696 case ACER_CAP_THREEG
:
697 method_id
= ACER_WMID_GET_THREEG_METHODID
;
699 case ACER_CAP_MAILLED
:
700 if (quirks
->mailled
== 1) {
708 status
= WMI_execute_u32(method_id
, 0, &result
);
710 if (ACPI_SUCCESS(status
))
716 static acpi_status
WMID_set_u32(u32 value
, u32 cap
, struct wmi_interface
*iface
)
722 case ACER_CAP_BRIGHTNESS
:
723 if (value
> max_brightness
)
724 return AE_BAD_PARAMETER
;
725 method_id
= ACER_WMID_SET_BRIGHTNESS_METHODID
;
727 case ACER_CAP_WIRELESS
:
729 return AE_BAD_PARAMETER
;
730 method_id
= ACER_WMID_SET_WIRELESS_METHODID
;
732 case ACER_CAP_BLUETOOTH
:
734 return AE_BAD_PARAMETER
;
735 method_id
= ACER_WMID_SET_BLUETOOTH_METHODID
;
737 case ACER_CAP_THREEG
:
739 return AE_BAD_PARAMETER
;
740 method_id
= ACER_WMID_SET_THREEG_METHODID
;
742 case ACER_CAP_MAILLED
:
744 return AE_BAD_PARAMETER
;
745 if (quirks
->mailled
== 1) {
746 param
= value
? 0x92 : 0x93;
748 i8042_command(¶m
, 0x1059);
756 return WMI_execute_u32(method_id
, (u32
)value
, NULL
);
759 static acpi_status
WMID_set_capabilities(void)
761 struct acpi_buffer out
= {ACPI_ALLOCATE_BUFFER
, NULL
};
762 union acpi_object
*obj
;
766 status
= wmi_query_block(WMID_GUID2
, 1, &out
);
767 if (ACPI_FAILURE(status
))
770 obj
= (union acpi_object
*) out
.pointer
;
771 if (obj
&& obj
->type
== ACPI_TYPE_BUFFER
&&
772 obj
->buffer
.length
== sizeof(u32
)) {
773 devices
= *((u32
*) obj
->buffer
.pointer
);
778 /* Not sure on the meaning of the relevant bits yet to detect these */
779 interface
->capability
|= ACER_CAP_WIRELESS
;
780 interface
->capability
|= ACER_CAP_THREEG
;
782 /* WMID always provides brightness methods */
783 interface
->capability
|= ACER_CAP_BRIGHTNESS
;
786 interface
->capability
|= ACER_CAP_BLUETOOTH
;
788 if (!(devices
& 0x20))
789 max_brightness
= 0x9;
794 static struct wmi_interface wmid_interface
= {
799 * Generic Device (interface-independent)
802 static acpi_status
get_u32(u32
*value
, u32 cap
)
804 acpi_status status
= AE_ERROR
;
806 switch (interface
->type
) {
808 status
= AMW0_get_u32(value
, cap
, interface
);
811 if (cap
== ACER_CAP_MAILLED
) {
812 status
= AMW0_get_u32(value
, cap
, interface
);
816 status
= WMID_get_u32(value
, cap
, interface
);
823 static acpi_status
set_u32(u32 value
, u32 cap
)
827 if (interface
->capability
& cap
) {
828 switch (interface
->type
) {
830 return AMW0_set_u32(value
, cap
, interface
);
832 if (cap
== ACER_CAP_MAILLED
)
833 return AMW0_set_u32(value
, cap
, interface
);
836 * On some models, some WMID methods don't toggle
837 * properly. For those cases, we want to run the AMW0
838 * method afterwards to be certain we've really toggled
841 if (cap
== ACER_CAP_WIRELESS
||
842 cap
== ACER_CAP_BLUETOOTH
) {
843 status
= WMID_set_u32(value
, cap
, interface
);
844 if (ACPI_FAILURE(status
))
847 return AMW0_set_u32(value
, cap
, interface
);
850 return WMID_set_u32(value
, cap
, interface
);
852 return AE_BAD_PARAMETER
;
855 return AE_BAD_PARAMETER
;
858 static void __init
acer_commandline_init(void)
861 * These will all fail silently if the value given is invalid, or the
862 * capability isn't available on the given interface
864 set_u32(mailled
, ACER_CAP_MAILLED
);
865 set_u32(threeg
, ACER_CAP_THREEG
);
866 set_u32(brightness
, ACER_CAP_BRIGHTNESS
);
870 * LED device (Mail LED only, no other LEDs known yet)
872 static void mail_led_set(struct led_classdev
*led_cdev
,
873 enum led_brightness value
)
875 set_u32(value
, ACER_CAP_MAILLED
);
878 static struct led_classdev mail_led
= {
879 .name
= "acer-wmi::mail",
880 .brightness_set
= mail_led_set
,
883 static int __devinit
acer_led_init(struct device
*dev
)
885 return led_classdev_register(dev
, &mail_led
);
888 static void acer_led_exit(void)
890 led_classdev_unregister(&mail_led
);
896 static struct backlight_device
*acer_backlight_device
;
898 static int read_brightness(struct backlight_device
*bd
)
901 get_u32(&value
, ACER_CAP_BRIGHTNESS
);
905 static int update_bl_status(struct backlight_device
*bd
)
907 int intensity
= bd
->props
.brightness
;
909 if (bd
->props
.power
!= FB_BLANK_UNBLANK
)
911 if (bd
->props
.fb_blank
!= FB_BLANK_UNBLANK
)
914 set_u32(intensity
, ACER_CAP_BRIGHTNESS
);
919 static struct backlight_ops acer_bl_ops
= {
920 .get_brightness
= read_brightness
,
921 .update_status
= update_bl_status
,
924 static int __devinit
acer_backlight_init(struct device
*dev
)
926 struct backlight_properties props
;
927 struct backlight_device
*bd
;
929 memset(&props
, 0, sizeof(struct backlight_properties
));
930 props
.max_brightness
= max_brightness
;
931 bd
= backlight_device_register("acer-wmi", dev
, NULL
, &acer_bl_ops
,
934 printk(ACER_ERR
"Could not register Acer backlight device\n");
935 acer_backlight_device
= NULL
;
939 acer_backlight_device
= bd
;
941 bd
->props
.power
= FB_BLANK_UNBLANK
;
942 bd
->props
.brightness
= read_brightness(bd
);
943 backlight_update_status(bd
);
947 static void acer_backlight_exit(void)
949 backlight_device_unregister(acer_backlight_device
);
955 static void acer_rfkill_update(struct work_struct
*ignored
);
956 static DECLARE_DELAYED_WORK(acer_rfkill_work
, acer_rfkill_update
);
957 static void acer_rfkill_update(struct work_struct
*ignored
)
962 status
= get_u32(&state
, ACER_CAP_WIRELESS
);
963 if (ACPI_SUCCESS(status
))
964 rfkill_set_sw_state(wireless_rfkill
, !state
);
966 if (has_cap(ACER_CAP_BLUETOOTH
)) {
967 status
= get_u32(&state
, ACER_CAP_BLUETOOTH
);
968 if (ACPI_SUCCESS(status
))
969 rfkill_set_sw_state(bluetooth_rfkill
, !state
);
972 schedule_delayed_work(&acer_rfkill_work
, round_jiffies_relative(HZ
));
975 static int acer_rfkill_set(void *data
, bool blocked
)
978 u32 cap
= (unsigned long)data
;
979 status
= set_u32(!blocked
, cap
);
980 if (ACPI_FAILURE(status
))
985 static const struct rfkill_ops acer_rfkill_ops
= {
986 .set_block
= acer_rfkill_set
,
989 static struct rfkill
*acer_rfkill_register(struct device
*dev
,
990 enum rfkill_type type
,
994 struct rfkill
*rfkill_dev
;
996 rfkill_dev
= rfkill_alloc(name
, dev
, type
,
998 (void *)(unsigned long)cap
);
1000 return ERR_PTR(-ENOMEM
);
1002 err
= rfkill_register(rfkill_dev
);
1004 rfkill_destroy(rfkill_dev
);
1005 return ERR_PTR(err
);
1010 static int acer_rfkill_init(struct device
*dev
)
1012 wireless_rfkill
= acer_rfkill_register(dev
, RFKILL_TYPE_WLAN
,
1013 "acer-wireless", ACER_CAP_WIRELESS
);
1014 if (IS_ERR(wireless_rfkill
))
1015 return PTR_ERR(wireless_rfkill
);
1017 if (has_cap(ACER_CAP_BLUETOOTH
)) {
1018 bluetooth_rfkill
= acer_rfkill_register(dev
,
1019 RFKILL_TYPE_BLUETOOTH
, "acer-bluetooth",
1020 ACER_CAP_BLUETOOTH
);
1021 if (IS_ERR(bluetooth_rfkill
)) {
1022 rfkill_unregister(wireless_rfkill
);
1023 rfkill_destroy(wireless_rfkill
);
1024 return PTR_ERR(bluetooth_rfkill
);
1028 schedule_delayed_work(&acer_rfkill_work
, round_jiffies_relative(HZ
));
1033 static void acer_rfkill_exit(void)
1035 cancel_delayed_work_sync(&acer_rfkill_work
);
1037 rfkill_unregister(wireless_rfkill
);
1038 rfkill_destroy(wireless_rfkill
);
1040 if (has_cap(ACER_CAP_BLUETOOTH
)) {
1041 rfkill_unregister(bluetooth_rfkill
);
1042 rfkill_destroy(bluetooth_rfkill
);
1050 static ssize_t
show_bool_threeg(struct device
*dev
,
1051 struct device_attribute
*attr
, char *buf
)
1054 acpi_status status
= get_u32(&result
, ACER_CAP_THREEG
);
1055 if (ACPI_SUCCESS(status
))
1056 return sprintf(buf
, "%u\n", result
);
1057 return sprintf(buf
, "Read error\n");
1060 static ssize_t
set_bool_threeg(struct device
*dev
,
1061 struct device_attribute
*attr
, const char *buf
, size_t count
)
1063 u32 tmp
= simple_strtoul(buf
, NULL
, 10);
1064 acpi_status status
= set_u32(tmp
, ACER_CAP_THREEG
);
1065 if (ACPI_FAILURE(status
))
1069 static DEVICE_ATTR(threeg
, S_IWUGO
| S_IRUGO
| S_IWUSR
, show_bool_threeg
,
1072 static ssize_t
show_interface(struct device
*dev
, struct device_attribute
*attr
,
1075 switch (interface
->type
) {
1077 return sprintf(buf
, "AMW0\n");
1079 return sprintf(buf
, "AMW0 v2\n");
1081 return sprintf(buf
, "WMID\n");
1083 return sprintf(buf
, "Error!\n");
1087 static DEVICE_ATTR(interface
, S_IWUGO
| S_IRUGO
| S_IWUSR
,
1088 show_interface
, NULL
);
1093 static u32
get_wmid_devices(void)
1095 struct acpi_buffer out
= {ACPI_ALLOCATE_BUFFER
, NULL
};
1096 union acpi_object
*obj
;
1099 status
= wmi_query_block(WMID_GUID2
, 1, &out
);
1100 if (ACPI_FAILURE(status
))
1103 obj
= (union acpi_object
*) out
.pointer
;
1104 if (obj
&& obj
->type
== ACPI_TYPE_BUFFER
&&
1105 obj
->buffer
.length
== sizeof(u32
)) {
1106 return *((u32
*) obj
->buffer
.pointer
);
1115 static int __devinit
acer_platform_probe(struct platform_device
*device
)
1119 if (has_cap(ACER_CAP_MAILLED
)) {
1120 err
= acer_led_init(&device
->dev
);
1125 if (has_cap(ACER_CAP_BRIGHTNESS
)) {
1126 err
= acer_backlight_init(&device
->dev
);
1128 goto error_brightness
;
1131 err
= acer_rfkill_init(&device
->dev
);
1138 if (has_cap(ACER_CAP_BRIGHTNESS
))
1139 acer_backlight_exit();
1141 if (has_cap(ACER_CAP_MAILLED
))
1147 static int acer_platform_remove(struct platform_device
*device
)
1149 if (has_cap(ACER_CAP_MAILLED
))
1151 if (has_cap(ACER_CAP_BRIGHTNESS
))
1152 acer_backlight_exit();
1158 static int acer_platform_suspend(struct platform_device
*dev
,
1162 struct acer_data
*data
= &interface
->data
;
1167 if (has_cap(ACER_CAP_MAILLED
)) {
1168 get_u32(&value
, ACER_CAP_MAILLED
);
1169 data
->mailled
= value
;
1172 if (has_cap(ACER_CAP_BRIGHTNESS
)) {
1173 get_u32(&value
, ACER_CAP_BRIGHTNESS
);
1174 data
->brightness
= value
;
1180 static int acer_platform_resume(struct platform_device
*device
)
1182 struct acer_data
*data
= &interface
->data
;
1187 if (has_cap(ACER_CAP_MAILLED
))
1188 set_u32(data
->mailled
, ACER_CAP_MAILLED
);
1190 if (has_cap(ACER_CAP_BRIGHTNESS
))
1191 set_u32(data
->brightness
, ACER_CAP_BRIGHTNESS
);
1196 static struct platform_driver acer_platform_driver
= {
1199 .owner
= THIS_MODULE
,
1201 .probe
= acer_platform_probe
,
1202 .remove
= acer_platform_remove
,
1203 .suspend
= acer_platform_suspend
,
1204 .resume
= acer_platform_resume
,
1207 static struct platform_device
*acer_platform_device
;
1209 static int remove_sysfs(struct platform_device
*device
)
1211 if (has_cap(ACER_CAP_THREEG
))
1212 device_remove_file(&device
->dev
, &dev_attr_threeg
);
1214 device_remove_file(&device
->dev
, &dev_attr_interface
);
1219 static int create_sysfs(void)
1221 int retval
= -ENOMEM
;
1223 if (has_cap(ACER_CAP_THREEG
)) {
1224 retval
= device_create_file(&acer_platform_device
->dev
,
1230 retval
= device_create_file(&acer_platform_device
->dev
,
1231 &dev_attr_interface
);
1238 remove_sysfs(acer_platform_device
);
1242 static void remove_debugfs(void)
1244 debugfs_remove(interface
->debug
.devices
);
1245 debugfs_remove(interface
->debug
.root
);
1248 static int create_debugfs(void)
1250 interface
->debug
.root
= debugfs_create_dir("acer-wmi", NULL
);
1251 if (!interface
->debug
.root
) {
1252 printk(ACER_ERR
"Failed to create debugfs directory");
1256 interface
->debug
.devices
= debugfs_create_u32("devices", S_IRUGO
,
1257 interface
->debug
.root
,
1258 &interface
->debug
.wmid_devices
);
1259 if (!interface
->debug
.devices
)
1269 static int __init
acer_wmi_init(void)
1273 printk(ACER_INFO
"Acer Laptop ACPI-WMI Extras\n");
1275 if (dmi_check_system(acer_blacklist
)) {
1276 printk(ACER_INFO
"Blacklisted hardware detected - "
1284 * Detect which ACPI-WMI interface we're using.
1286 if (wmi_has_guid(AMW0_GUID1
) && wmi_has_guid(WMID_GUID1
))
1287 interface
= &AMW0_V2_interface
;
1289 if (!wmi_has_guid(AMW0_GUID1
) && wmi_has_guid(WMID_GUID1
))
1290 interface
= &wmid_interface
;
1292 if (wmi_has_guid(WMID_GUID2
) && interface
) {
1293 if (ACPI_FAILURE(WMID_set_capabilities())) {
1294 printk(ACER_ERR
"Unable to detect available WMID "
1298 } else if (!wmi_has_guid(WMID_GUID2
) && interface
) {
1299 printk(ACER_ERR
"No WMID device detection method found\n");
1303 if (wmi_has_guid(AMW0_GUID1
) && !wmi_has_guid(WMID_GUID1
)) {
1304 interface
= &AMW0_interface
;
1306 if (ACPI_FAILURE(AMW0_set_capabilities())) {
1307 printk(ACER_ERR
"Unable to detect available AMW0 "
1313 if (wmi_has_guid(AMW0_GUID1
))
1314 AMW0_find_mailled();
1317 printk(ACER_ERR
"No or unsupported WMI interface, unable to "
1324 if (acpi_video_backlight_support() && has_cap(ACER_CAP_BRIGHTNESS
)) {
1325 interface
->capability
&= ~ACER_CAP_BRIGHTNESS
;
1326 printk(ACER_INFO
"Brightness must be controlled by "
1327 "generic video driver\n");
1330 if (platform_driver_register(&acer_platform_driver
)) {
1331 printk(ACER_ERR
"Unable to register platform driver.\n");
1332 goto error_platform_register
;
1334 acer_platform_device
= platform_device_alloc("acer-wmi", -1);
1335 platform_device_add(acer_platform_device
);
1337 err
= create_sysfs();
1341 if (wmi_has_guid(WMID_GUID2
)) {
1342 interface
->debug
.wmid_devices
= get_wmid_devices();
1343 err
= create_debugfs();
1348 /* Override any initial settings with values from the commandline */
1349 acer_commandline_init();
1353 error_platform_register
:
1357 static void __exit
acer_wmi_exit(void)
1359 remove_sysfs(acer_platform_device
);
1361 platform_device_del(acer_platform_device
);
1362 platform_driver_unregister(&acer_platform_driver
);
1364 printk(ACER_INFO
"Acer Laptop WMI Extras unloaded\n");
1368 module_init(acer_wmi_init
);
1369 module_exit(acer_wmi_exit
);