2 * acer_acpi.c - Acer Laptop ACPI Extras
5 * Copyright (C) 2005 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.6"
43 #define PROC_INTERFACE_VERSION 1
44 #define PROC_ACER "acer"
46 #include <linux/kernel.h>
47 #include <linux/module.h>
48 #include <linux/init.h>
49 #include <linux/types.h>
50 #include <linux/proc_fs.h>
51 #include <linux/delay.h>
52 #include <linux/suspend.h>
53 #include <asm/uaccess.h>
55 #include <acpi/acpi_drivers.h>
57 MODULE_AUTHOR("Mark Smith");
58 MODULE_DESCRIPTION("Acer Laptop ACPI Extras Driver");
59 MODULE_LICENSE("GPL");
61 #define MY_LOGPREFIX "acer_acpi: "
62 #define MY_ERR KERN_ERR MY_LOGPREFIX
63 #define MY_NOTICE KERN_NOTICE MY_LOGPREFIX
64 #define MY_INFO KERN_INFO MY_LOGPREFIX
66 #define DEBUG(level, message...) { \
68 printk(KERN_DEBUG MY_LOGPREFIX message);\
72 * On the 5580, brightness values range from 0x0 to 0xf, inclusive.
73 * This may vary on other machines.
75 #define ACER_MAX_BRIGHTNESS 0xf
79 * Meaning is unknown - this number is required for writing to ACPI
80 * (it's also used in acerhk when directly accessing the EC)
82 #define ACER_WRITE 0x9610
85 * Bit masks for the old AMW0 interface
86 * These could vary between the particular interface
88 #define ACER_AMW0_WIRELESS_MASK 0x35
89 #define ACER_AMW0_BLUETOOTH_MASK 0x34
90 #define ACER_AMW0_MAILLED_MASK 0x31
93 * Method IDs for new WMID interface
94 * These could be different for other untested machines
96 #define ACER_WMID_GET_WIRELESS_METHODID 1
97 #define ACER_WMID_GET_BLUETOOTH_METHODID 2
98 #define ACER_WMID_GET_BRIGHTNESS_METHODID 3
99 #define ACER_WMID_SET_WIRELESS_METHODID 4
100 #define ACER_WMID_SET_BLUETOOTH_METHODID 5
101 #define ACER_WMID_SET_BRIGHTNESS_METHODID 6
102 #define ACER_WMID_GET_THREEG_METHODID 9
103 #define ACER_WMID_SET_THREEG_METHODID 10
106 * Acer ACPI method paths
108 * TODO: It may be possbile to autodetect these, since these are all at HID PNP0C14
110 #define AMW0_METHOD "\\_SB_.AMW0.WMAB"
111 #define AMW0_GETDATA "\\_SB_.AMW0._WED"
113 #define WMID_METHOD "\\_SB.WMID.WMBA"
114 #define WMID_GETDATA "\\_SB.WMID._WED"
117 * Interface capability flags
119 #define ACER_CAP_MAILLED (1<<0)
120 #define ACER_CAP_WIRELESS (1<<1)
121 #define ACER_CAP_BLUETOOTH (1<<2)
122 #define ACER_CAP_BRIGHTNESS (1<<3)
123 #define ACER_CAP_THREEG (1<<4)
124 #define ACER_CAP_ANY (0xffffffff)
127 * Presumed start states -
128 * For the old-style interfaces, there is no way to know for certain what the start state
129 * is for any of the parameters (ACPI does not provide any methods or store this
130 * anywhere). We therefore start with an unknown state (this is also how acerhk
131 * does it); we then change the status so that we are in a known state (I
132 * suspect LaunchManager on Windows does something similar, since the wireless
133 * appears to turn off as soon as it launches).
135 * Plus, we can't tell which features are enabled or disabled on a specific
136 * model, just ranges - e.g. The 5020 series can _support_ bluetooth; but the
137 * 5021 has no bluetooth, whilst the 5024 does. However, the BIOS identifies
138 * both laptops as 5020 - we can't tell them apart!
140 * Basically the code works like this:
141 * - On init, any values specified on the commandline are set.
142 * - For interfaces where the current values cannot be detected and which
143 * have not been set on the commandline, we set them to some sane default
146 * See AMW0_init and acer_commandline_init
149 #define ACER_DEFAULT_WIRELESS 0
150 #define ACER_DEFAULT_BLUETOOTH 0
151 #define ACER_DEFAULT_MAILLED 0
152 #define ACER_DEFAULT_THREEG 0
153 #define ACER_DEFAULT_BRIGHTNESS ACER_MAX_BRIGHTNESS
155 static int wireless
= -1;
156 static int bluetooth
= -1;
157 static int mailled
= -1;
158 static int brightness
= -1;
159 static int threeg
= -1;
160 static int debug
= 0;
162 module_param(mailled
, int, 0444);
163 module_param(wireless
, int, 0444);
164 module_param(bluetooth
, int, 0444);
165 module_param(brightness
, int, 0444);
166 module_param(threeg
, int, 0444);
167 module_param(debug
, int, 0664);
168 MODULE_PARM_DESC(wireless
, "Set initial state of Wireless hardware");
169 MODULE_PARM_DESC(bluetooth
, "Set initial state of Bluetooth hardware");
170 MODULE_PARM_DESC(mailled
, "Set initial state of Mail LED");
171 MODULE_PARM_DESC(brightness
, "Set initial LCD backlight brightness");
172 MODULE_PARM_DESC(threeg
, "Set initial state of 3G hardware");
173 MODULE_PARM_DESC(debug
, "Debugging verbosity level (0=least 2=most)");
175 typedef struct _ProcItem
{
177 char *(*read_func
) (char *, uint32_t);
178 unsigned long (*write_func
) (const char *, unsigned long, uint32_t);
179 unsigned int capability
;
183 struct acpi_device
*device
;
187 static struct proc_dir_entry
*acer_proc_dir
;
189 static int is_valid_acpi_path(const char *methodName
)
194 status
= acpi_get_handle(NULL
, (char *)methodName
, &handle
);
195 return ACPI_SUCCESS(status
);
198 /* Each low-level interface must define at least some of the following */
199 typedef struct _Interface
{
201 * The capabilities this interface provides
202 * In the future, these can be removed/added at runtime when we have a
203 * way of detecting what capabilities are /actually/ present on an
209 * Initializes an interface, should allocate the interface-specific
212 acpi_status (*init
) (struct _Interface
*);
215 * Frees an interface, should free the interface-specific data
217 void (*free
) (struct _Interface
*);
220 * Gets and sets various data types.
221 * First paramater: Value to set, or pointer to place got value into
222 * Second parameter: Specific capability being requested
223 * Third paramater: Pointer to this interface
225 acpi_status (*get_bool
) (bool*, uint32_t, struct _Interface
*);
226 acpi_status (*set_bool
) (bool, uint32_t, struct _Interface
*);
227 acpi_status (*get_u8
) (uint8_t*, uint32_t, struct _Interface
*);
228 acpi_status (*set_u8
) (uint8_t, uint32_t, struct _Interface
*);
231 * Interface-specific private data member. Must *not* be touched by
232 * anyone outside of this struct
237 /* The static interface pointer, points to the currently detected interface */
238 static Interface
*interface
;
241 * General interface convenience methods
244 /* These *_via_u8 use the interface's *_u8 methods to emulate other gets/sets */
245 static acpi_status
get_bool_via_u8(bool *value
, uint32_t cap
, Interface
*iface
) {
249 status
= iface
->get_u8(&result
, cap
, iface
);
251 if (ACPI_SUCCESS(status
))
252 *value
= (result
!= 0);
257 static acpi_status
set_bool_via_u8(bool value
, uint32_t cap
, Interface
*iface
) {
258 uint8_t v
= value
? 1 : 0;
260 return iface
->set_u8(v
, cap
, iface
);
264 * Old interface (now known as the AMW0 interface)
266 typedef struct _WMAB_args
{
273 typedef struct _AMW0_Data
{
279 static acpi_status
WMAB_execute(WMAB_args
* regbuf
, struct acpi_buffer
*result
)
281 struct acpi_object_list input
;
282 union acpi_object params
[3];
284 acpi_status status
= AE_OK
;
286 input
.pointer
= params
;
288 params
[0].type
= ACPI_TYPE_INTEGER
;
289 params
[0].integer
.value
= 0x01; /* Only one instance of this object */
290 params
[1].type
= ACPI_TYPE_INTEGER
;
291 params
[1].integer
.value
= 0x01; /* Technically this should be method ID */
292 params
[2].type
= ACPI_TYPE_BUFFER
;
293 params
[2].buffer
.length
= sizeof(WMAB_args
);
294 params
[2].buffer
.pointer
= (u8
*) regbuf
;
296 DEBUG(2, "Doing %s( 1, 1, [%u-byte buffer] )\n", AMW0_METHOD
, params
[2].buffer
.length
);
298 status
= acpi_evaluate_object(NULL
, AMW0_METHOD
, &input
, result
);
300 DEBUG(2, " Execution status: %d\n", status
);
301 DEBUG(2, " Args: 0x%08x 0x%08x 0x%08x 0x%08x\n", regbuf
->eax
, regbuf
->ebx
, regbuf
->ecx
, regbuf
->edx
);
302 DEBUG(2, " Result: %llu bytes\n", result
? result
->length
: 0 );
307 static acpi_status
AMW0_init(Interface
*iface
) {
310 /*AMW0_Data *data = iface->data; */
312 /* Allocate our private data structure */
313 iface
->data
= kmalloc(sizeof(AMW0_Data
), GFP_KERNEL
);
315 AMW0_Data
*data
= iface
->data
;
318 * Call the interface once so the BIOS knows it's to notify us of
321 memset(&args
, 0, sizeof(WMAB_args
));
322 args
.eax
= ACER_WRITE
;
324 status
= WMAB_execute(&args
, NULL
);
327 * If the commandline doesn't specify these, we need to force them to
331 mailled
= ACER_DEFAULT_MAILLED
;
333 wireless
= ACER_DEFAULT_WIRELESS
;
335 bluetooth
= ACER_DEFAULT_BLUETOOTH
;
338 * Set the cached "current" values to impossible ones so that
339 * acer_commandline_init will definitely set them.
341 data
->wireless
= data
->mailled
= data
->bluetooth
= -1;
346 static void AMW0_free(Interface
*iface
) {
347 /* Free our private data structure */
351 static acpi_status
AMW0_get_bool(bool *value
, uint32_t cap
, Interface
*iface
)
353 AMW0_Data
*data
= iface
->data
;
355 /* Currently no way to query the state, so just return the cached value */
357 case ACER_CAP_MAILLED
:
358 *value
= data
->mailled
;
360 case ACER_CAP_WIRELESS
:
361 *value
= data
->wireless
;
363 case ACER_CAP_BLUETOOTH
:
364 *value
= data
->bluetooth
;
367 return AE_BAD_ADDRESS
;
372 static acpi_status
AMW0_set_bool(bool value
, uint32_t cap
, Interface
*iface
)
377 args
.eax
= ACER_WRITE
;
378 args
.ebx
= value
? (1<<8) : 0;
381 case ACER_CAP_MAILLED
:
382 args
.ebx
|= ACER_AMW0_MAILLED_MASK
;
384 case ACER_CAP_WIRELESS
:
385 args
.ebx
|= ACER_AMW0_WIRELESS_MASK
;
387 case ACER_CAP_BLUETOOTH
:
388 args
.ebx
|= ACER_AMW0_BLUETOOTH_MASK
;
391 return AE_BAD_ADDRESS
;
394 /* Actually do the set */
395 status
= WMAB_execute(&args
, NULL
);
398 * Currently no way to query the state, so cache the new value on
401 if (ACPI_SUCCESS(status
)) {
402 AMW0_Data
*data
= iface
->data
;
404 case ACER_CAP_MAILLED
:
405 data
->mailled
= value
;
407 case ACER_CAP_WIRELESS
:
408 data
->wireless
= value
;
410 case ACER_CAP_BLUETOOTH
:
411 data
->bluetooth
= value
;
419 static Interface AMW0_interface
= {
427 .get_bool
= AMW0_get_bool
,
428 .set_bool
= AMW0_set_bool
,
432 * New interface (The WMID interface)
436 WMI_execute(uint32_t methodId
, const struct acpi_buffer
*in
, struct acpi_buffer
*out
) {
437 struct acpi_object_list input
;
438 union acpi_object params
[3];
439 acpi_status status
= AE_OK
;
441 /* WMI calling convention:
442 * _SB.WMID.WMxx( instance, methodId, input_buffer )
443 * - instance is always 1, since there's only this module
444 * - methodId is the method number within the current method group.
445 * - Input buffer is ignored for read-only commands
446 * - Returns a buffer of results
449 input
.pointer
= params
;
450 params
[0].type
= ACPI_TYPE_INTEGER
;
451 params
[0].integer
.value
= 0x01;
452 params
[1].type
= ACPI_TYPE_INTEGER
;
453 params
[1].integer
.value
= methodId
;
454 params
[2].type
= ACPI_TYPE_BUFFER
;
455 params
[2].buffer
.length
= in
->length
;
456 params
[2].buffer
.pointer
= in
->pointer
;
458 DEBUG(2, "Doing %s( 1, %u, [%llu-byte buffer] )\n", WMID_METHOD
, methodId
, in
->length
);
460 status
= acpi_evaluate_object(NULL
, WMID_METHOD
, &input
, out
);
466 WMI_execute_uint32(uint32_t methodId
, uint32_t in
, uint32_t *out
)
468 struct acpi_buffer input
= { (acpi_size
)sizeof(uint32_t), (void*)(&in
) };
469 struct acpi_buffer result
= { ACPI_ALLOCATE_BUFFER
, NULL
};
470 union acpi_object
*obj
;
474 status
= WMI_execute(methodId
, &input
, &result
);
475 DEBUG(2, " Execution status: %d\n", status
);
476 DEBUG(2, " In: 0x%08x\n", in
);
478 if (ACPI_FAILURE(status
))
481 obj
= (union acpi_object
*)result
.pointer
;
482 if (obj
&& obj
->type
== ACPI_TYPE_BUFFER
&& obj
->buffer
.length
== sizeof(uint32_t)) {
483 tmp
= *((uint32_t*)obj
->buffer
.pointer
);
484 DEBUG(2, " Out: 0x%08x\n", tmp
);
488 DEBUG(2, " Got unexpected result of type %d\n", obj
->type
);
490 DEBUG(2, " Got unexpected null result\n");
497 if (result
.length
> 0 && result
.pointer
)
498 kfree(result
.pointer
);
503 static acpi_status
WMID_get_u8(uint8_t *value
, uint32_t cap
, Interface
*iface
) {
506 uint32_t methodId
= 0;
509 case ACER_CAP_WIRELESS
:
510 methodId
= ACER_WMID_GET_WIRELESS_METHODID
;
512 case ACER_CAP_BLUETOOTH
:
513 methodId
= ACER_WMID_GET_BLUETOOTH_METHODID
;
515 case ACER_CAP_BRIGHTNESS
:
516 methodId
= ACER_WMID_GET_BRIGHTNESS_METHODID
;
518 case ACER_CAP_THREEG
:
519 methodId
= ACER_WMID_GET_THREEG_METHODID
;
522 return AE_BAD_ADDRESS
;
524 status
= WMI_execute_uint32(methodId
, 0, &result
);
526 if (ACPI_SUCCESS(status
))
527 *value
= (uint8_t)result
;
532 static acpi_status
WMID_set_u8(uint8_t value
, uint32_t cap
, Interface
*iface
) {
533 uint32_t methodId
= 0;
536 case ACER_CAP_BRIGHTNESS
:
537 methodId
= ACER_WMID_SET_BRIGHTNESS_METHODID
;
539 case ACER_CAP_WIRELESS
:
540 methodId
= ACER_WMID_SET_WIRELESS_METHODID
;
542 case ACER_CAP_BLUETOOTH
:
543 methodId
= ACER_WMID_SET_BLUETOOTH_METHODID
;
544 case ACER_CAP_THREEG
:
545 methodId
= ACER_WMID_SET_THREEG_METHODID
;
548 return AE_BAD_ADDRESS
;
550 return WMI_execute_uint32(methodId
, (uint32_t)value
, NULL
);
554 static Interface WMID_interface
= {
558 ACER_CAP_BRIGHTNESS
|
561 .get_bool
= get_bool_via_u8
,
562 .set_bool
= set_bool_via_u8
,
563 .get_u8
= WMID_get_u8
,
564 .set_u8
= WMID_set_u8
,
569 * High-level Procfs file handlers
573 dispatch_read(char *page
, char **start
, off_t off
, int count
, int *eof
,
580 p
= item
->read_func(p
, item
->capability
);
583 * ISSUE: I don't understand this code
586 if (len
<= off
+ count
)
598 dispatch_write(struct file
*file
, const char __user
* buffer
,
599 unsigned long count
, ProcItem
* item
)
605 * Arg buffer points to userspace memory, which can't be accessed
606 * directly. Since we're making a copy, zero-terminate the
607 * destination so that sscanf can be used on it safely.
609 tmp_buffer
= kmalloc(count
+ 1, GFP_KERNEL
);
610 if (copy_from_user(tmp_buffer
, buffer
, count
)) {
613 tmp_buffer
[count
] = 0;
614 result
= item
->write_func(tmp_buffer
, count
, item
->capability
);
621 * Generic Device (interface-independent)
624 static acpi_status
get_bool(bool *value
, uint32_t cap
) {
625 acpi_status status
= AE_BAD_ADDRESS
;
626 if (interface
->get_bool
)
627 status
= interface
->get_bool(value
, cap
, interface
);
631 static acpi_status
set_bool(int value
, uint32_t cap
) {
632 acpi_status status
= AE_BAD_PARAMETER
;
633 if ((value
== 0 || value
== 1) &&
634 (interface
->capability
& cap
)) {
635 if (interface
->get_bool
) {
636 /* If possible, only set if the value has changed */
638 status
= interface
->get_bool(&actual
, cap
, interface
);
639 if (ACPI_SUCCESS(status
) && actual
== (bool)value
)
642 if (interface
->set_bool
)
643 status
= interface
->set_bool(value
== 1, cap
, interface
);
649 static acpi_status
get_u8(uint8_t *value
, uint32_t cap
) {
650 acpi_status status
= AE_BAD_ADDRESS
;
651 if (interface
->get_u8
)
652 status
= interface
->get_u8(value
, cap
, interface
);
656 static acpi_status
set_u8(uint8_t value
, uint8_t min
, uint8_t max
, uint32_t cap
) {
657 acpi_status status
= AE_BAD_PARAMETER
;
658 if ((value
>= min
&& value
<= max
) &&
659 (interface
->capability
& cap
) ) {
660 if (interface
->get_u8
) {
661 /* If possible, only set if the value has changed */
663 status
= interface
->get_u8(&actual
, cap
, interface
);
664 if (ACPI_SUCCESS(status
) && actual
== value
)
667 if (interface
->set_u8
)
668 status
= interface
->set_u8(value
, cap
, interface
);
673 /* Each _u8 needs a small wrapper that sets the boundary values */
674 static acpi_status
set_brightness(uint8_t value
)
676 return set_u8(value
, 0, ACER_MAX_BRIGHTNESS
, ACER_CAP_BRIGHTNESS
);
679 static void acpi_commandline_init(void)
681 DEBUG(1, "Commandline args: mailled(%d) wireless(%d) bluetooth(%d) brightness(%d)\n",
682 mailled
, wireless
, bluetooth
, brightness
);
685 * These will all fail silently if the value given is invalid, or the
686 * capability isn't available on the given interface
688 set_bool(mailled
, ACER_CAP_MAILLED
);
689 set_bool(wireless
, ACER_CAP_WIRELESS
);
690 set_bool(bluetooth
, ACER_CAP_BLUETOOTH
);
691 set_bool(threeg
, ACER_CAP_THREEG
);
692 set_brightness((uint8_t)brightness
);
698 static char *read_bool(char *p
, uint32_t cap
)
701 acpi_status status
= get_bool(&result
, cap
);
702 if (ACPI_SUCCESS(status
))
703 p
+= sprintf(p
, "%d\n", result
);
705 p
+= sprintf(p
, "Read error" );
709 static unsigned long write_bool(const char *buffer
, unsigned long count
, uint32_t cap
)
714 * For now, we are still supporting the "enabled: %i" - this _will_ be deprecated in 0.7
716 if ((sscanf(buffer
, " enabled : %i", &value
) == 1
717 || sscanf(buffer
, "%i", &value
) == 1)) {
718 acpi_status status
= set_bool(value
, cap
);
719 if (ACPI_FAILURE(status
))
727 static char *read_u8(char *p
, uint32_t cap
)
730 acpi_status status
= get_u8(&result
, cap
);
731 if (ACPI_SUCCESS(status
))
732 p
+= sprintf(p
, "%u\n", result
);
734 p
+= sprintf(p
, "Read error" );
738 static unsigned long write_u8(const char *buffer
, unsigned long count
, uint32_t cap
)
741 acpi_status (*set_method
)(uint8_t);
743 /* Choose the appropriate set_u8 wrapper here, based on the capability */
745 case ACER_CAP_BRIGHTNESS
:
746 set_method
= set_brightness
;
752 if (sscanf(buffer
, "%i", &value
) == 1) {
753 acpi_status status
= (*set_method
)(value
);
754 if (ACPI_FAILURE(status
))
762 static char *read_version(char *p
, uint32_t cap
)
764 p
+= sprintf(p
, "driver: %s\n", ACER_ACPI_VERSION
);
765 p
+= sprintf(p
, "proc_interface: %d\n",
766 PROC_INTERFACE_VERSION
);
770 ProcItem proc_items
[] = {
771 {"mailled", read_bool
, write_bool
, ACER_CAP_MAILLED
},
772 {"bluetooth", read_bool
, write_bool
, ACER_CAP_BLUETOOTH
},
773 {"wireless", read_bool
, write_bool
, ACER_CAP_WIRELESS
},
774 {"brightness", read_u8
, write_u8
, ACER_CAP_BRIGHTNESS
},
775 {"threeg", read_u8
, write_u8
, ACER_CAP_THREEG
},
776 {"version", read_version
, NULL
, ACER_CAP_ANY
},
780 static acpi_status __init
add_proc_entries(void)
782 struct proc_dir_entry
*proc
;
785 for (item
= proc_items
; item
->name
; ++item
) {
787 * Only add the proc file if the current interface actually
790 if (interface
->capability
& item
->capability
) {
791 proc
= create_proc_read_entry(item
->name
,
792 S_IFREG
| S_IRUGO
| S_IWUSR
,
794 (read_proc_t
*) dispatch_read
,
797 proc
->owner
= THIS_MODULE
;
798 if (proc
&& item
->write_func
)
799 proc
->write_proc
= (write_proc_t
*) dispatch_write
;
806 static acpi_status __exit
remove_proc_entries(void)
810 for (item
= proc_items
; item
->name
; ++item
)
811 remove_proc_entry(item
->name
, acer_proc_dir
);
816 * TODO: make this actually do useful stuff, if we ever see events
818 static void acer_acerkeys_notify(acpi_handle handle
, u32 event
, void *data
)
820 struct acer_hotk
*hotk
= (struct acer_hotk
*)data
;
824 printk(MY_ERR
"Got an event!! %X", event
);
829 static int acpi_acerkeys_add(struct acpi_device
*device
)
831 struct acer_hotk
*hotk
= NULL
;
832 acpi_status status
= AE_OK
;
838 (struct acer_hotk
*)kmalloc(sizeof(struct acer_hotk
), GFP_KERNEL
);
841 memset(hotk
, 0, sizeof(struct acer_hotk
));
842 hotk
->handle
= device
->handle
;
843 strcpy(acpi_device_name(device
), "Acer Laptop ACPI Extras");
844 strcpy(acpi_device_class(device
), "hkey");
845 acpi_driver_data(device
) = hotk
;
846 hotk
->device
= device
;
848 status
= acpi_install_notify_handler(hotk
->handle
, ACPI_SYSTEM_NOTIFY
,
849 acer_acerkeys_notify
, hotk
);
850 if (ACPI_FAILURE(status
))
851 printk(MY_ERR
"Error installing notify handler.\n");
855 static int acpi_acerkeys_remove(struct acpi_device
*device
, int type
)
857 acpi_status status
= 0;
858 struct acer_hotk
*hotk
= NULL
;
860 if (!device
|| !acpi_driver_data(device
))
862 hotk
= (struct acer_hotk
*)acpi_driver_data(device
);
864 status
= acpi_remove_notify_handler(hotk
->handle
, ACPI_SYSTEM_NOTIFY
,
865 acer_acerkeys_notify
);
866 if (ACPI_FAILURE(status
))
867 printk(MY_ERR
"Error removing notify handler.\n");
873 static struct acpi_driver acpi_acerkeys
= {
878 .add
= acpi_acerkeys_add
,
879 .remove
= acpi_acerkeys_remove
,
883 static int __init
acer_acpi_init(void)
885 acpi_status status
= AE_OK
;
887 printk(MY_INFO
"Acer Laptop ACPI Extras version %s\n",
890 printk(MY_ERR
"ACPI Disabled, unable to load.\n");
895 * Detect which WMI interface we're using.
897 * TODO: This could be more dynamic, and perhaps done in part by the
900 if (is_valid_acpi_path(AMW0_METHOD
)) {
901 DEBUG(0, "Detected ACER AMW0 interface\n");
902 interface
= &AMW0_interface
;
903 } else if (is_valid_acpi_path(WMID_METHOD
)) {
904 DEBUG(0, "Detected ACER WMID interface\n");
905 interface
= &WMID_interface
;
907 printk(MY_ERR
"No or unsupported WMI interface, unable to load.\n");
908 goto error_no_interface
;
911 /* Now that we have a known interface, initialize it */
912 if (interface
->init
) {
913 status
= interface
->init(interface
);
914 if (ACPI_FAILURE(status
)) {
915 printk(MY_ERR
"Interface initialization failed.\n");
916 goto error_interface_init
;
920 /* Create the proc entries */
921 acer_proc_dir
= proc_mkdir(PROC_ACER
, acpi_root_dir
);
922 if (!acer_proc_dir
) {
923 printk(MY_ERR
"Unable to create /proc entries, aborting.\n");
924 goto error_proc_mkdir
;
927 acer_proc_dir
->owner
= THIS_MODULE
;
928 status
= add_proc_entries();
929 if (ACPI_FAILURE(status
)) {
930 printk(MY_ERR
"Unable to create /proc entries, aborting.\n");
935 * Register the hotkeys driver
937 * TODO: Does this do anything? Can we use the bus detection code to
938 * check for the interface or all or part of the method ID path?
940 status
= acpi_bus_register_driver(&acpi_acerkeys
);
941 if (ACPI_FAILURE(status
)) {
942 printk(MY_ERR
"Unable to register driver, aborting.\n");
943 goto error_acpi_bus_register
;
946 /* Finally, override any initial settings with values from the commandline */
947 acpi_commandline_init();
951 error_acpi_bus_register
:
952 remove_proc_entries();
955 remove_proc_entry(PROC_ACER
, acpi_root_dir
);
958 interface
->free(interface
);
959 error_interface_init
:
964 static void __exit
acer_acpi_exit(void)
966 acpi_bus_unregister_driver(&acpi_acerkeys
);
968 remove_proc_entries();
971 remove_proc_entry(PROC_ACER
, acpi_root_dir
);
974 interface
->free(interface
);
976 printk(MY_INFO
"Acer Laptop ACPI Extras unloaded\n");
980 module_init(acer_acpi_init
);
981 module_exit(acer_acpi_exit
);