Merge branch 'master' of git+ssh://repo.or.cz/srv/git/acer_acpi
[acer_acpi.git] / acer_acpi.c
blob9c54d98591be47cc9f9c3a5924c83e72ecb0835a
1 /*
2 * Acer Laptop ACPI Extras
4 * Copyright (C) 2005-2007 E.M. Smith
5 * Copyright (C) 2007 Carlos Corbacho <cathectic@gmail.com>
7 * This program is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 2 of the License, or
10 * (at your option) any later version.
12 * This program is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
17 * You should have received a copy of the GNU General Public License
18 * along with this program; if not, write to the Free Software
19 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 * The devolpment page for this driver is located at
23 * http://code.google.com/p/aceracpi
25 * Credits:
27 * John Belmonte - the Toshiba ACPI driver originally adapted for this module.
28 * Julien Lerouge & Karol Kozimor - ASUS Acpi driver authors.
29 * Olaf Tauber - developer of acerhk, the inspiration to solve the 64-bit
30 * driver problem for my Aspire 5024.
31 * Mathieu Segaud - solved the ACPI problem that needed a double-modprobe
32 * in version 0.2 and below.
33 * Jim Ramsay - Figured out and added support for WMID interface
36 #define ACER_ACPI_VERSION "0.10.0"
39 * Comment the following line out to remove /proc support
41 #define CONFIG_PROC
43 #ifdef CONFIG_PROC
44 #define PROC_ACER "acer"
45 #include <linux/proc_fs.h>
46 #endif
48 #include <linux/kernel.h>
49 #include <linux/module.h>
50 #include <linux/init.h>
51 #include <linux/types.h>
52 #include <linux/delay.h>
53 #include <linux/version.h>
55 #if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,17)
56 #include <asm/uaccess.h>
57 #else
58 #include <linux/uaccess.h>
59 #endif
61 #include <linux/io.h>
62 #include <linux/dmi.h>
63 #include <linux/backlight.h>
64 #include <linux/leds.h>
65 #include <linux/platform_device.h>
67 #include <acpi/acpi_drivers.h>
69 #include "wmi-acer.h"
71 /* Workaround needed for older kernels */
72 #ifndef bool
73 #define bool int
74 #endif
76 MODULE_AUTHOR("Mark Smith, Carlos Corbacho");
77 MODULE_DESCRIPTION("Acer Laptop ACPI Extras Driver");
78 MODULE_LICENSE("GPL");
80 #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...) { \
86 if (debug >= level) \
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)
101 struct acer_quirks {
102 const char *vendor;
103 const char *model;
104 u16 quirks;
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) */
115 * Magic Number
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 {
162 ACER_AMW0,
163 ACER_WMID,
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
180 * (disabled)
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)");
218 #ifdef CONFIG_PROC
219 struct ProcItem {
220 const char *name;
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;
227 #endif
230 * Wait for the keyboard controller to become ready
232 static int wait_kbd_write(void)
234 int i = 0;
235 while ((inb(ACER_KBD_STATUS_REG) & 0x02) && (i < 10000)) {
236 udelay(50);
237 i++;
239 return -(i == 10000);
242 static void send_kbd_cmd(u8 cmd, u8 val)
244 preempt_disable();
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);
257 struct acer_data {
258 int mailled;
259 int wireless;
260 int bluetooth;
261 int threeg;
262 int brightness;
265 /* Each low-level interface must define at least some of the following */
266 struct Interface {
268 * The ACPI device type
270 u32 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
276 * interface
278 u32 capability;
281 * Initializes an interface, should allocate the interface-specific
282 * data
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.
301 struct quirk_entry {
302 u8 wireless;
303 u8 mailled;
304 u8 brightness;
305 u8 touchpad;
306 u8 temperature_override;
307 u8 mmkeys;
308 u8 bluetooth;
309 u8 max_brightness;
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;
360 return 0;
363 static struct quirk_entry quirk_unknown = {
366 static struct quirk_entry quirk_acer_aspire_5020 = {
367 .wireless = 1,
368 .mailled = 2,
369 .brightness = 1,
370 .bluetooth = 1,
373 /* Same Mail LED quirk as TM2490, but does not require keyboard quirk */
374 static struct quirk_entry quirk_acer_aspire_5100 = {
375 .mailled = 1,
378 static struct quirk_entry quirk_acer_aspire_5680 = {
379 .mmkeys = 1,
382 static struct quirk_entry quirk_acer_aspire_9300 = {
383 .wireless = 2,
384 .mailled = 2,
385 .brightness = 1,
386 .bluetooth = 2,
389 static struct quirk_entry quirk_acer_travelmate_2490 = {
390 .mmkeys = 1,
391 .mailled = 1,
392 .temperature_override = 1,
393 .touchpad = 1,
397 * This is similar to the Aspire 5020, but with a different wireless quirk
399 static struct quirk_entry quirk_acer_travelmate_5620 = {
400 .wireless = 2,
401 .mailled = 2,
402 .brightness = 1,
403 .bluetooth = 1,
406 static struct quirk_entry quirk_acer_travelmate_5720 = {
407 .max_brightness = 0x9,
408 .touchpad = 2,
409 .wireless = 2,
410 .bluetooth = 2,
411 .brightness = 1,
414 static struct dmi_system_id acer_quirks[] = {
416 .callback = dmi_matched,
417 .ident = "Acer Aspire 3010",
418 .matches = {
419 DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
420 DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 3010"),
422 .driver_data = &quirk_acer_aspire_5020,
425 .callback = dmi_matched,
426 .ident = "Acer Aspire 3020",
427 .matches = {
428 DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
429 DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 3020"),
431 .driver_data = &quirk_acer_aspire_5020,
434 .callback = dmi_matched,
435 .ident = "Acer Aspire 3040",
436 .matches = {
437 DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
438 DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 3040"),
440 .driver_data = &quirk_acer_aspire_5020,
443 .callback = dmi_matched,
444 .ident = "Acer Aspire 3100",
445 .matches = {
446 DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
447 DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 3100"),
449 .driver_data = &quirk_acer_aspire_5100,
452 .callback = dmi_matched,
453 .ident = "Acer Aspire 5010",
454 .matches = {
455 DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
456 DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5010"),
458 .driver_data = &quirk_acer_aspire_5020,
461 .callback = dmi_matched,
462 .ident = "Acer Aspire 5020",
463 .matches = {
464 DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
465 DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5020"),
467 .driver_data = &quirk_acer_aspire_5020,
470 .callback = dmi_matched,
471 .ident = "Acer Aspire 5040",
472 .matches = {
473 DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
474 DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5040"),
476 .driver_data = &quirk_acer_aspire_5020,
479 .callback = dmi_matched,
480 .ident = "Acer Aspire 5100",
481 .matches = {
482 DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
483 DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5100"),
485 .driver_data = &quirk_acer_aspire_5100,
488 .callback = dmi_matched,
489 .ident = "Acer Aspire 5560",
490 .matches = {
491 DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
492 DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5560"),
494 .driver_data = &quirk_acer_travelmate_5620,
497 .callback = dmi_matched,
498 .ident = "Acer Aspire 5630",
499 .matches = {
500 DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
501 DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5630"),
503 .driver_data = &quirk_acer_travelmate_2490,
506 .callback = dmi_matched,
507 .ident = "Acer Aspire 5650",
508 .matches = {
509 DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
510 DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5650"),
512 .driver_data = &quirk_acer_travelmate_2490,
515 .callback = dmi_matched,
516 .ident = "Acer Aspire 5680",
517 .matches = {
518 DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
519 DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5680"),
521 .driver_data = &quirk_acer_aspire_5680,
524 .callback = dmi_matched,
525 .ident = "Acer Aspire 9300",
526 .matches = {
527 DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
528 DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 9300"),
530 .driver_data = &quirk_acer_aspire_9300,
533 .callback = dmi_matched,
534 .ident = "Acer Aspire 9420",
535 .matches = {
536 DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
537 DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 9420"),
539 .driver_data = &quirk_acer_travelmate_5620,
542 .callback = dmi_matched,
543 .ident = "Acer TravelMate 2420",
544 .matches = {
545 DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
546 DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 2420"),
548 .driver_data = &quirk_acer_aspire_5020,
551 .callback = dmi_matched,
552 .ident = "Acer TravelMate 2490",
553 .matches = {
554 DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
555 DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 2490"),
557 .driver_data = &quirk_acer_travelmate_2490,
560 .callback = dmi_matched,
561 .ident = "Acer TravelMate 5620",
562 .matches = {
563 DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
564 DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 5620"),
566 .driver_data = &quirk_acer_travelmate_5620,
569 .callback = dmi_matched,
570 .ident = "Acer TravelMate 5720",
571 .matches = {
572 DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
573 DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 5720"),
575 .driver_data = &quirk_acer_travelmate_5720,
580 /* Find which quirks are needed for a particular vendor/ model pair */
581 static void find_quirks(void)
583 DEBUG (1, "Looking for quirks\n");
584 if (!force_series) {
585 dmi_check_system(acer_quirks);
586 } else if (force_series == 5020) {
587 DEBUG(0, "Forcing Acer Aspire 5020\n");
588 quirks = &quirk_acer_aspire_5020;
589 } else if (force_series == 2490) {
590 DEBUG(0, "Forcing Acer TravelMate 2490\n");
591 quirks = &quirk_acer_travelmate_2490;
592 } else if (force_series == 5620) {
593 DEBUG(0, "Forcing Acer TravelMate 5620\n");
594 quirks = &quirk_acer_travelmate_5620;
595 } else if (force_series == 5720) {
596 DEBUG(0, "Forcing Acer TravelMate 5720\n");
597 quirks = &quirk_acer_travelmate_5720;
600 if (quirks == NULL) {
601 DEBUG(1, "No quirks known for this laptop\n");
602 quirks = &quirk_unknown;
604 set_quirks();
608 * General interface convenience methods
611 static bool has_cap(u32 cap)
613 if ((interface->capability & cap) != 0) {
614 return 1;
616 return 0;
620 * Old interface (now known as the AMW0 interface)
622 struct WMAB_args {
623 u32 eax;
624 u32 ebx;
625 u32 ecx;
626 u32 edx;
629 static acpi_status WMAB_execute(struct WMAB_args *regbuf, struct acpi_buffer *result)
631 struct acpi_buffer input;
632 acpi_status status;
633 input.length = sizeof(struct WMAB_args);
634 input.pointer = (u8*)regbuf;
636 status = wmi_acer_evaluate_method(AMW0_GUID1, 1, 1, &input, result);
637 DEBUG(2, " Args: 0x%08x 0x%08x 0x%08x 0x%08x\n", regbuf->eax, regbuf->ebx, regbuf->ecx, regbuf->edx );
639 return status;
642 static void AMW0_init(struct Interface *iface) {
643 bool help = 0;
646 * If the commandline doesn't specify these, we need to force them to
647 * the default values
649 if (mailled == -1 && !quirks->mailled)
650 mailled = ACER_DEFAULT_MAILLED;
651 if (wireless == -1 && !quirks->wireless)
652 wireless = ACER_DEFAULT_WIRELESS;
653 if (bluetooth == -1 && !quirks->bluetooth)
654 bluetooth = ACER_DEFAULT_BLUETOOTH;
657 * Set the cached "current" values to impossible ones so that
658 * acer_commandline_init will definitely set them.
660 if (quirks->bluetooth == 0) {
661 help = 1;
662 iface->data.bluetooth = -1;
663 printk(ACER_INFO "No EC data for reading bluetooth - bluetooth value when read will be a 'best guess'\n");
666 if (quirks->wireless == 0) {
667 help = 1;
668 printk(ACER_INFO "No EC data for reading wireless - wireless value when read will be a 'best guess'\n");
669 iface->data.wireless = -1;
671 if (quirks->mailled == 0) {
672 help = 1;
673 printk(ACER_INFO "No EC data for reading mail LED - mail LED value when read will be a 'best guess'\n");
674 iface->data.mailled = -1;
677 if (help) {
678 printk(ACER_INFO "We need more data from your laptop's Embedded Controller (EC) to better support it\n");
679 printk(ACER_INFO "Please see http://code.google.com/p/aceracpi/wiki/EmbeddedController on how to help\n");
683 static acpi_status AMW0_get_bool(bool *value, u32 cap, struct Interface *iface)
685 struct acer_data *data = &iface->data;
686 u8 result;
688 DEBUG(2, " AMW0_get_bool: cap=%d\n", cap);
690 * On some models, we can read these values from the EC. On others,
691 * we use a stored value
693 switch (cap) {
694 case ACER_CAP_MAILLED:
695 switch (quirks->mailled) {
696 case 2:
697 ec_read(0x0A, &result);
698 *value = (result >> 7) & 0x01;
699 return 0;
700 default:
701 *value = data->mailled;
703 break;
704 case ACER_CAP_WIRELESS:
705 switch (quirks->wireless) {
706 case 1:
707 ec_read(0x0A, &result);
708 *value = (result >> 2) & 0x01;
709 return 0;
710 case 2:
711 ec_read(0x71, &result);
712 *value = result & 0x01;
713 return 0;
714 default:
715 *value = data->wireless;
717 break;
718 case ACER_CAP_BLUETOOTH:
719 switch (quirks->bluetooth) {
720 case 1:
721 ec_read(0x0A, &result);
722 *value = (result >> 4) & 0x01;
723 return 0;
724 case 2:
725 ec_read(0x71, &result);
726 *value = (result >> 1) & 0x01;
727 return 0;
728 default:
729 *value = data->bluetooth;
731 break;
732 case ACER_CAP_TOUCHPAD_READ:
733 switch (quirks->touchpad) {
734 case 2:
735 ec_read(0x74, &result);
736 *value = (result >> 3) & 0x01;
737 return 0;
738 default:
739 break;
741 default:
742 return AE_BAD_ADDRESS;
744 return AE_OK;
747 static acpi_status AMW0_set_bool(bool value, u32 cap, struct Interface *iface)
749 struct WMAB_args args;
750 struct acer_data *data = &iface->data;
751 acpi_status status;
753 args.eax = ACER_AMW0_WRITE;
754 args.ebx = value ? (1<<8) : 0;
755 args.ecx = args.edx = 0;
757 switch (cap) {
758 case ACER_CAP_MAILLED:
759 args.ebx |= ACER_AMW0_MAILLED_MASK;
760 break;
761 case ACER_CAP_WIRELESS:
762 args.ebx |= ACER_AMW0_WIRELESS_MASK;
763 break;
764 case ACER_CAP_BLUETOOTH:
765 args.ebx |= ACER_AMW0_BLUETOOTH_MASK;
766 break;
767 default:
768 return AE_BAD_ADDRESS;
771 /* Actually do the set */
772 status = WMAB_execute(&args, NULL);
775 * Currently no way to query the state, so cache the new value on
776 * success
778 if (ACPI_SUCCESS(status)) {
779 switch (cap) {
780 case ACER_CAP_MAILLED:
781 data->mailled = value;
782 break;
783 case ACER_CAP_WIRELESS:
784 data->wireless = value;
785 break;
786 case ACER_CAP_BLUETOOTH:
787 data->bluetooth = value;
788 break;
792 return status;
795 static acpi_status AMW0_get_u8(u8 *value, u32 cap, struct Interface *iface) {
796 switch (cap) {
797 case ACER_CAP_BRIGHTNESS:
798 switch (quirks->brightness) {
799 case 1:
800 return ec_read(0x83, value);
801 case 2:
802 return ec_read(0x85, value);
803 default:
804 return AE_BAD_ADDRESS;
806 break;
807 default:
808 return AE_BAD_ADDRESS;
810 return AE_OK;
813 static acpi_status AMW0_set_u8(u8 value, u32 cap, struct Interface *iface) {
814 switch (cap) {
815 case ACER_CAP_BRIGHTNESS:
816 switch (quirks->brightness) {
817 case 1:
818 return ec_write(0x83, value);
819 case 2:
820 return ec_write(0x85, value);
821 default:
822 return AE_BAD_ADDRESS;
823 break;
825 default:
826 return AE_BAD_ADDRESS;
828 return AE_OK;
831 static struct Interface AMW0_interface = {
832 .type = ACER_AMW0,
833 .capability = (
834 ACER_CAP_MAILLED |
835 ACER_CAP_WIRELESS |
836 ACER_CAP_BLUETOOTH
838 .init = AMW0_init,
842 * New interface (The WMID interface)
844 static acpi_status
845 WMI_execute_u32(u32 method_id, u32 in, u32 *out)
847 struct acpi_buffer input = { (acpi_size) sizeof(u32), (void *)(&in) };
848 struct acpi_buffer result = { ACPI_ALLOCATE_BUFFER, NULL };
849 union acpi_object *obj;
850 u32 tmp;
851 acpi_status status;
853 DEBUG(2, " WMI_execute_u32:\n");
854 status = wmi_acer_evaluate_method(WMID_GUID1, 1, method_id, &input, &result);
855 DEBUG(2, " In: 0x%08x\n", in);
857 if (ACPI_FAILURE(status))
858 return status;
860 obj = (union acpi_object *) result.pointer;
861 if (obj && obj->type == ACPI_TYPE_BUFFER && obj->buffer.length == sizeof(u32)) {
862 tmp = *((u32 *) obj->buffer.pointer);
863 DEBUG(2, " Out: 0x%08x\n", tmp);
864 } else {
865 tmp = 0;
866 if (obj) {
867 DEBUG(2, " Got unexpected result of type %d\n", obj->type);
868 } else {
869 DEBUG(2, " Got unexpected null result\n");
873 if (out)
874 *out = tmp;
876 if (result.length > 0 && result.pointer)
877 kfree(result.pointer);
879 DEBUG(2, " Returning from WMI_execute_u32:\n");
880 return status;
883 static acpi_status WMID_get_u8(u8 *value, u32 cap, struct Interface *iface) {
884 acpi_status status;
885 u32 result;
886 u32 method_id = 0;
888 DEBUG(2, " WMID_get_u8: cap=%d\n", cap);
889 switch (cap) {
890 case ACER_CAP_WIRELESS:
891 method_id = ACER_WMID_GET_WIRELESS_METHODID;
892 break;
893 case ACER_CAP_BLUETOOTH:
894 method_id = ACER_WMID_GET_BLUETOOTH_METHODID;
895 break;
896 case ACER_CAP_BRIGHTNESS:
897 method_id = ACER_WMID_GET_BRIGHTNESS_METHODID;
898 break;
899 case ACER_CAP_THREEG:
900 method_id = ACER_WMID_GET_THREEG_METHODID;
901 break;
902 case ACER_CAP_MAILLED:
903 if (quirks->mailled == 1) {
904 ec_read(0x9f, value);
905 *value &= 0x01;
906 return 0;
908 case ACER_CAP_TOUCHPAD_READ:
909 switch (quirks->touchpad) {
910 case 1:
911 ec_read(0x9e, value);
912 *value = 1 - ((*value >> 3) & 0x01);
913 return 0;
914 default:
915 break;
917 case ACER_CAP_TEMPERATURE_OVERRIDE:
918 if (quirks->temperature_override == 1) {
919 ec_read(0xa9, value);
920 return 0;
922 default:
923 return AE_BAD_ADDRESS;
925 status = WMI_execute_u32(method_id, 0, &result);
926 DEBUG(2, " WMI_execute_u32 status=%d:\n", status);
928 if (ACPI_SUCCESS(status))
929 *value = (u8)result;
931 DEBUG(2, " Returning from WMID_get_u8:\n");
932 return status;
935 static acpi_status WMID_set_u8(u8 value, u32 cap, struct Interface *iface) {
936 u32 method_id = 0;
938 switch (cap) {
939 case ACER_CAP_BRIGHTNESS:
940 method_id = ACER_WMID_SET_BRIGHTNESS_METHODID;
941 break;
942 case ACER_CAP_WIRELESS:
943 method_id = ACER_WMID_SET_WIRELESS_METHODID;
944 break;
945 case ACER_CAP_BLUETOOTH:
946 method_id = ACER_WMID_SET_BLUETOOTH_METHODID;
947 break;
948 case ACER_CAP_THREEG:
949 method_id = ACER_WMID_SET_THREEG_METHODID;
950 break;
951 case ACER_CAP_MAILLED:
952 if (quirks->mailled == 1) {
953 send_kbd_cmd(0x59, value ? 0x92 : 0x93);
954 return 0;
956 case ACER_CAP_TEMPERATURE_OVERRIDE:
957 if (quirks->temperature_override == 1) {
958 ec_write(0xa9, value);
959 return 0;
961 default:
962 return AE_BAD_ADDRESS;
964 return WMI_execute_u32(method_id, (u32)value, NULL);
968 static struct Interface WMID_interface = {
969 .type = ACER_WMID,
970 .capability = (
971 ACER_CAP_WIRELESS
972 | ACER_CAP_BRIGHTNESS
973 | ACER_CAP_BLUETOOTH
974 | ACER_CAP_THREEG
978 #ifdef CONFIG_PROC
980 * High-level Procfs file handlers
983 static int
984 dispatch_read(char *page, char **start, off_t off, int count, int *eof,
985 struct ProcItem *item)
987 char *p = page;
988 int len;
990 DEBUG(2, " dispatch_read: \n");
991 if (off == 0)
992 p = item->read_func(p, item->capability);
993 len = (p - page);
994 if (len <= off + count)
995 *eof = 1;
996 *start = page + off;
997 len -= off;
998 if (len > count)
999 len = count;
1000 if (len < 0)
1001 len = 0;
1002 return len;
1005 static int
1006 dispatch_write(struct file *file, const char __user *buffer,
1007 unsigned long count, struct ProcItem *item)
1009 int result;
1010 char *tmp_buffer;
1013 * Arg buffer points to userspace memory, which can't be accessed
1014 * directly. Since we're making a copy, zero-terminate the
1015 * destination so that sscanf can be used on it safely.
1017 tmp_buffer = kmalloc(count + 1, GFP_KERNEL);
1018 if (copy_from_user(tmp_buffer, buffer, count)) {
1019 result = -EFAULT;
1020 } else {
1021 tmp_buffer[count] = 0;
1022 result = item->write_func(tmp_buffer, count, item->capability);
1024 kfree(tmp_buffer);
1025 return result;
1027 #endif
1030 * Generic Device (interface-independent)
1033 static acpi_status get_bool(bool *value, u32 cap) {
1034 acpi_status status = AE_BAD_ADDRESS;
1035 u8 tmp = 0;
1037 DEBUG(2, " get_bool: cap=%d, interface type=%d\n",
1038 cap, interface->type);
1039 switch (interface->type) {
1040 case ACER_AMW0:
1041 status = AMW0_get_bool(value, cap, interface);
1042 break;
1043 case ACER_WMID:
1044 status = WMID_get_u8(&tmp, cap, interface);
1045 *value = (tmp == 1) ? 1 : 0;
1046 break;
1048 DEBUG(2, " Returning from get_bool:\n");
1049 return status;
1052 static acpi_status set_bool(int value, u32 cap) {
1053 acpi_status status = AE_BAD_PARAMETER;
1055 DEBUG(2, " set_bool: cap=%d, interface type=%d, value=%d\n",
1056 cap, interface->type, value);
1057 if ((value == 0 || value == 1) && (interface->capability & cap)) {
1058 switch (interface->type) {
1059 case ACER_AMW0:
1060 status = AMW0_set_bool(value == 1, cap, interface);
1061 break;
1062 case ACER_WMID:
1063 status = WMID_set_u8(value == 1, cap, interface);
1064 break;
1067 return status;
1070 static acpi_status get_u8(u8 *value, u32 cap) {
1071 DEBUG(2, " get_u8: cap=%d\n", cap);
1072 switch (interface->type) {
1073 case ACER_AMW0:
1074 return AMW0_get_u8(value, cap, interface);
1075 break;
1076 case ACER_WMID:
1077 return WMID_get_u8(value, cap, interface);
1078 break;
1079 default:
1080 return AE_BAD_ADDRESS;
1084 static acpi_status set_u8(u8 value, u8 min, u8 max, u32 cap) {
1086 DEBUG(2, " set_u8: cap=%d, interface type=%d, value=%d\n",
1087 cap, interface->type, value);
1089 if ((value >= min && value <= max) && (interface->capability & cap) ) {
1090 switch (interface->type) {
1091 case ACER_AMW0:
1092 return AMW0_set_u8(value, cap, interface);
1093 case ACER_WMID:
1094 return WMID_set_u8(value, cap, interface);
1095 default:
1096 return AE_BAD_PARAMETER;
1099 return AE_BAD_PARAMETER;
1102 /* Each _u8 needs a small wrapper that sets the boundary values */
1103 static acpi_status set_brightness(u8 value)
1105 return set_u8(value, 0, max_brightness, ACER_CAP_BRIGHTNESS);
1108 static acpi_status set_temperature_override(u8 value)
1110 return set_u8(value, 0, ACER_MAX_TEMPERATURE_OVERRIDE, ACER_CAP_TEMPERATURE_OVERRIDE);
1113 static void __init acer_commandline_init(void)
1115 DEBUG(1, "Commandline args: mailled(%d) wireless(%d) bluetooth(%d) brightness(%d)\n",
1116 mailled, wireless, bluetooth, brightness);
1119 * These will all fail silently if the value given is invalid, or the
1120 * capability isn't available on the given interface
1122 set_bool(mailled, ACER_CAP_MAILLED);
1123 set_bool(wireless, ACER_CAP_WIRELESS);
1124 set_bool(bluetooth, ACER_CAP_BLUETOOTH);
1125 set_bool(threeg, ACER_CAP_THREEG);
1126 set_temperature_override(fan_temperature_override);
1127 set_brightness((u8)brightness);
1130 #ifdef CONFIG_PROC
1132 * Procfs interface (deprecated)
1134 static char *read_bool(char *p, u32 cap)
1136 bool result;
1137 acpi_status status;
1139 DEBUG(2, " read_bool: cap=%d\n", cap);
1140 status = get_bool(&result, cap);
1141 if (ACPI_SUCCESS(status))
1142 p += sprintf(p, "%d\n", result);
1143 else
1144 p += sprintf(p, "Read error" );
1145 return p;
1148 static unsigned long write_bool(const char *buffer, unsigned long count, u32 cap)
1150 int value;
1152 DEBUG(2, " write_bool: cap=%d, interface type=%d\n buffer=%s\n",
1153 cap, interface->type, buffer);
1155 if (sscanf(buffer, "%i", &value) == 1) {
1156 acpi_status status = set_bool(value, cap);
1157 if (ACPI_FAILURE(status))
1158 return -EINVAL;
1159 } else {
1160 return -EINVAL;
1162 return count;
1165 static char *read_u8(char *p, u32 cap)
1167 u8 result;
1168 acpi_status status;
1170 DEBUG(2, " read_u8: cap=%d\n", cap);
1171 status = get_u8(&result, cap);
1172 if (ACPI_SUCCESS(status))
1173 p += sprintf(p, "%u\n", result);
1174 else
1175 p += sprintf(p, "Read error" );
1176 return p;
1179 static unsigned long write_u8(const char *buffer, unsigned long count, u32 cap)
1181 int value;
1182 acpi_status (*set_method)(u8);
1184 /* Choose the appropriate set_u8 wrapper here, based on the capability */
1185 switch (cap) {
1186 case ACER_CAP_BRIGHTNESS:
1187 set_method = set_brightness;
1188 break;
1189 case ACER_CAP_TEMPERATURE_OVERRIDE:
1190 set_method = set_temperature_override;
1191 break;
1192 default:
1193 return -EINVAL;
1196 if (sscanf(buffer, "%i", &value) == 1) {
1197 acpi_status status = (*set_method)(value);
1198 if (ACPI_FAILURE(status))
1199 return -EINVAL;
1200 } else {
1201 return -EINVAL;
1203 return count;
1206 static char *read_version(char *p, u32 cap)
1208 p += sprintf(p, "%s\n", ACER_ACPI_VERSION);
1209 return p;
1212 static char *read_interface(char *p, u32 cap)
1214 p += sprintf(p, "%s\n", (interface->type == ACER_AMW0 ) ? "AMW0": "WMID");
1215 return p;
1218 static struct ProcItem proc_items[] = {
1219 {"mailled", read_bool, write_bool, ACER_CAP_MAILLED},
1220 {"bluetooth", read_bool, write_bool, ACER_CAP_BLUETOOTH},
1221 {"wireless", read_bool, write_bool, ACER_CAP_WIRELESS},
1222 {"brightness", read_u8, write_u8, ACER_CAP_BRIGHTNESS},
1223 {"threeg", read_bool, write_bool, ACER_CAP_THREEG},
1224 {"touchpad", read_bool, NULL, ACER_CAP_TOUCHPAD_READ},
1225 {"fan_temperature_override", read_u8, write_u8, ACER_CAP_TEMPERATURE_OVERRIDE},
1226 {"version", read_version, NULL, ACER_CAP_ANY},
1227 {"interface", read_interface, NULL, ACER_CAP_ANY},
1228 {NULL}
1231 static int __init add_proc_entries(void)
1233 struct proc_dir_entry *proc;
1234 struct ProcItem *item;
1236 for (item = proc_items; item->name; ++item) {
1238 * Only add the proc file if the current interface actually
1239 * supports it
1241 if (interface->capability & item->capability) {
1242 proc = create_proc_read_entry(item->name,
1243 S_IFREG | S_IRUGO | S_IWUSR,
1244 acer_proc_dir,
1245 (read_proc_t *) dispatch_read,
1246 item);
1247 if (proc)
1248 proc->owner = THIS_MODULE;
1249 if (proc && item->write_func)
1250 proc->write_proc = (write_proc_t *) dispatch_write;
1254 return 0;
1257 static int __exit remove_proc_entries(void)
1259 struct ProcItem *item;
1261 for (item = proc_items; item->name; ++item)
1262 remove_proc_entry(item->name, acer_proc_dir);
1263 return 0;
1265 #endif
1268 * LED device (Mail LED only, no other LEDs known yet)
1270 static void mail_led_set(struct led_classdev *led_cdev, enum led_brightness value)
1272 bool tmp = value;
1273 set_bool(tmp, ACER_CAP_MAILLED);
1276 static struct led_classdev mail_led = {
1277 .name = "acer_acpi:mail",
1278 .brightness_set = mail_led_set,
1281 static void acer_led_init(struct device *dev)
1283 led_classdev_register(dev, &mail_led);
1286 static void acer_led_exit(void)
1288 led_classdev_unregister(&mail_led);
1291 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,18)
1293 * Backlight device
1295 static struct backlight_device *acer_backlight_device;
1297 static int read_brightness(struct backlight_device *bd)
1299 u8 value;
1300 get_u8(&value, ACER_CAP_BRIGHTNESS);
1301 return value;
1304 #if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,20)
1305 static int update_bl_status(struct backlight_device *bd)
1307 set_brightness(bd->props->brightness);
1308 return 0;
1311 static struct backlight_properties acer_backlight_properties = {
1312 .get_brightness = read_brightness,
1313 .update_status = update_bl_status,
1316 static int __init acer_backlight_init(struct device *dev)
1318 struct backlight_device *bd;
1320 DEBUG(1, "Loading backlight driver\n");
1321 bd = backlight_device_register("acer_acpi", dev, NULL, &acer_backlight_properties);
1322 if (IS_ERR(bd)) {
1323 printk(ACER_ERR "Could not register Acer backlight device\n");
1324 acer_backlight_device = NULL;
1325 return PTR_ERR(bd);
1328 acer_backlight_device = bd;
1330 bd->props->max_brightness = max_brightness;
1331 return 0;
1333 #else
1334 static int update_bl_status(struct backlight_device *bd)
1336 set_brightness(bd->props.brightness);
1337 return 0;
1340 static struct backlight_ops acer_backlight_ops = {
1341 .get_brightness = read_brightness,
1342 .update_status = update_bl_status,
1345 static int __init acer_backlight_init(struct device *dev)
1347 struct backlight_device *bd;
1349 DEBUG(1, "Loading backlight driver\n");
1350 bd = backlight_device_register("acer_acpi", dev, NULL, &acer_backlight_ops);
1351 if (IS_ERR(bd)) {
1352 printk(ACER_ERR "Could not register Acer backlight device\n");
1353 acer_backlight_device = NULL;
1354 return PTR_ERR(bd);
1357 acer_backlight_device = bd;
1359 bd->props.max_brightness = max_brightness;
1360 bd->props.brightness = read_brightness(NULL);
1361 backlight_update_status(bd);
1362 return 0;
1364 #endif
1366 static void __exit acer_backlight_exit(void)
1368 backlight_device_unregister(acer_backlight_device);
1370 #endif
1373 * Read/ write bool sysfs macro
1375 #define show_set_bool(value, cap) \
1376 static ssize_t \
1377 show_bool_##value(struct device *dev, struct device_attribute *attr, \
1378 char *buf) \
1380 bool result; \
1381 acpi_status status = get_bool(&result, cap); \
1382 if (ACPI_SUCCESS(status)) \
1383 return sprintf(buf, "%d\n", result); \
1384 return sprintf(buf, "Read error" ); \
1387 static ssize_t \
1388 set_bool_##value(struct device *dev, struct device_attribute *attr, \
1389 const char *buf, size_t count) \
1391 bool tmp = simple_strtoul(buf, NULL, 10); \
1392 acpi_status status = set_bool(tmp, cap); \
1393 if (ACPI_FAILURE(status)) \
1394 return -EINVAL; \
1395 return count; \
1397 static DEVICE_ATTR(value, S_IWUGO | S_IRUGO | S_IWUSR, \
1398 show_bool_##value, set_bool_##value);
1400 show_set_bool(wireless, ACER_CAP_WIRELESS);
1401 show_set_bool(bluetooth, ACER_CAP_BLUETOOTH);
1402 show_set_bool(threeg, ACER_CAP_THREEG);
1403 show_set_bool(fan_temperature_override, ACER_CAP_TEMPERATURE_OVERRIDE);
1406 * Read-only bool sysfs macro
1408 #define show_bool(value, cap) \
1409 static ssize_t \
1410 show_bool_##value(struct device *dev, struct device_attribute *attr, \
1411 char *buf) \
1413 bool result; \
1414 acpi_status status = get_bool(&result, cap); \
1415 if (ACPI_SUCCESS(status)) \
1416 return sprintf(buf, "%d\n", result); \
1417 return sprintf(buf, "Read error" ); \
1419 static DEVICE_ATTR(value, S_IWUGO | S_IRUGO | S_IWUSR, \
1420 show_bool_##value, NULL);
1422 show_bool(touchpad, ACER_CAP_TOUCHPAD_READ);
1425 * Read interface sysfs macro
1427 static ssize_t show_interface(struct device *dev, struct device_attribute *attr,
1428 char *buf)
1430 return sprintf(buf, "%s\n", (interface->type == ACER_AMW0 ) ? "AMW0" : "WMID");
1433 static DEVICE_ATTR(interface, S_IWUGO | S_IRUGO | S_IWUSR, show_interface, NULL);
1436 * Platform device
1438 static int __devinit acer_platform_probe(struct platform_device *device)
1440 if (has_cap(ACER_CAP_MAILLED))
1441 acer_led_init(&device->dev);
1442 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,18)
1443 if (has_cap(ACER_CAP_BRIGHTNESS))
1444 acer_backlight_init(&device->dev);
1445 #endif
1446 return 0;
1449 static int acer_platform_remove(struct platform_device *device)
1451 if (has_cap(ACER_CAP_MAILLED))
1452 acer_led_exit();
1453 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,18)
1454 if (has_cap(ACER_CAP_BRIGHTNESS))
1455 acer_backlight_exit();
1456 #endif
1457 return 0;
1460 static int acer_platform_suspend(struct platform_device *device, pm_message_t state)
1463 * WMID fix for suspend-to-disk - save all current states now so we can
1464 * restore them on resume
1466 bool value;
1467 u8 u8value;
1468 struct acer_data *data = &interface->data;
1470 #define save_bool_device(device, cap) \
1471 if (has_cap(cap)) {\
1472 get_bool(&value, cap);\
1473 data->device = value;\
1476 #define save_u8_device(device, cap) \
1477 if (has_cap(cap)) {\
1478 get_u8(&u8value, cap);\
1479 data->device = u8value;\
1482 if (interface->type == ACER_WMID) {
1483 save_bool_device(wireless, ACER_CAP_WIRELESS);
1484 save_bool_device(bluetooth, ACER_CAP_BLUETOOTH);
1485 save_bool_device(threeg, ACER_CAP_THREEG);
1486 save_u8_device(brightness, ACER_CAP_BRIGHTNESS);
1489 return 0;
1492 static int acer_platform_resume(struct platform_device *device)
1494 struct acer_data *data = &interface->data;
1496 #define restore_bool_device(device, cap) \
1497 if (has_cap(cap))\
1498 set_bool(data->device, cap);\
1500 restore_bool_device(wireless, ACER_CAP_WIRELESS);
1501 restore_bool_device(bluetooth, ACER_CAP_BLUETOOTH);
1502 restore_bool_device(threeg, ACER_CAP_THREEG);
1503 restore_bool_device(mailled, ACER_CAP_MAILLED);
1505 if (has_cap(ACER_CAP_BRIGHTNESS))
1506 set_brightness((u8)data->brightness);
1508 /* Check if this laptop requires the keyboard quirk */
1509 if (quirks->mmkeys != 0) {
1510 set_keyboard_quirk();
1511 printk(ACER_INFO "Setting keyboard quirk to enable multimedia keys\n");
1514 return 0;
1517 static struct platform_driver acer_platform_driver = {
1518 .driver = {
1519 .name = "acer_acpi",
1520 .owner = THIS_MODULE,
1522 .probe = acer_platform_probe,
1523 .remove = acer_platform_remove,
1524 .suspend = acer_platform_suspend,
1525 .resume = acer_platform_resume,
1528 static struct platform_device *acer_platform_device;
1530 static int remove_sysfs(struct platform_device *device)
1532 #define remove_device_file(value, cap) \
1533 if (has_cap(cap)) \
1534 device_remove_file(&device->dev, &dev_attr_##value);
1536 remove_device_file(wireless, ACER_CAP_WIRELESS);
1537 remove_device_file(bluetooth, ACER_CAP_BLUETOOTH);
1538 remove_device_file(threeg, ACER_CAP_THREEG);
1539 remove_device_file(interface, ACER_CAP_ANY);
1540 remove_device_file(fan_temperature_override, ACER_CAP_TEMPERATURE_OVERRIDE);
1541 remove_device_file(touchpad, ACER_CAP_TOUCHPAD_READ);
1542 return 0;
1545 static int create_sysfs(void)
1547 int retval = -ENOMEM;
1549 #define add_device_file(value, cap) \
1550 if (has_cap(cap)) {\
1551 retval = device_create_file(&acer_platform_device->dev, &dev_attr_##value);\
1552 if (retval)\
1553 goto error;\
1556 add_device_file(wireless, ACER_CAP_WIRELESS);
1557 add_device_file(bluetooth, ACER_CAP_BLUETOOTH);
1558 add_device_file(threeg, ACER_CAP_THREEG);
1559 add_device_file(interface, ACER_CAP_ANY);
1560 add_device_file(fan_temperature_override, ACER_CAP_TEMPERATURE_OVERRIDE);
1561 add_device_file(touchpad, ACER_CAP_TOUCHPAD_READ);
1563 return 0;
1565 error:
1566 remove_sysfs(acer_platform_device);
1567 return retval;
1570 static int __init acer_acpi_init(void)
1572 printk(ACER_INFO "Acer Laptop ACPI Extras version %s\n",
1573 ACER_ACPI_VERSION);
1576 * Detect which WMI interface we're using.
1577 * Check for AMW0 first, as later AMW0 laptops also have the WMID GUID.
1579 if (wmi_acer_has_guid(AMW0_GUID1)) {
1580 DEBUG(0, "Detected Acer AMW0 interface\n");
1581 interface = &AMW0_interface;
1582 } else if (wmi_acer_has_guid(WMID_GUID1)) {
1583 DEBUG(0, "Detected Acer WMID interface\n");
1584 interface = &WMID_interface;
1585 } else {
1586 printk(ACER_ERR "No or unsupported WMI interface, unable to load.\n");
1587 return -ENODEV;
1590 /* Find if this laptop requires any quirks */
1591 DEBUG(1, "Finding quirks\n");
1592 find_quirks();
1594 /* Now that we have a known interface, initialize it */
1595 DEBUG(1, "Initialising interface\n");
1596 if (interface->init)
1597 interface->init(interface);
1599 #ifdef CONFIG_PROC
1600 /* Create the proc entries */
1601 acer_proc_dir = proc_mkdir(PROC_ACER, acpi_root_dir);
1602 if (!acer_proc_dir) {
1603 printk(ACER_ERR "Unable to create /proc entries, aborting.\n");
1604 goto error_proc_mkdir;
1607 acer_proc_dir->owner = THIS_MODULE;
1608 if (add_proc_entries()) {
1609 printk(ACER_ERR "Unable to create /proc entries, aborting.\n");
1610 goto error_proc_add;
1612 #endif
1615 * Register the driver
1617 if (platform_driver_register(&acer_platform_driver)) {
1618 printk(ACER_ERR "Unable to register platform driver, aborting.\n");
1619 goto error_platform_register;
1621 acer_platform_device = platform_device_alloc("acer_acpi", -1);
1622 platform_device_add(acer_platform_device);
1624 create_sysfs();
1626 DEBUG(1, "Driver registered\n");
1628 /* Override any initial settings with values from the commandline */
1629 acer_commandline_init();
1631 return 0;
1633 error_platform_register:
1634 #ifdef CONFIG_PROC
1635 remove_proc_entries();
1636 error_proc_add:
1637 if (acer_proc_dir)
1638 remove_proc_entry(PROC_ACER, acpi_root_dir);
1639 error_proc_mkdir:
1640 #endif
1641 return -ENODEV;
1644 static void __exit acer_acpi_exit(void)
1646 remove_sysfs(acer_platform_device);
1647 platform_device_del(acer_platform_device);
1648 platform_driver_unregister(&acer_platform_driver);
1650 #ifdef CONFIG_PROC
1651 remove_proc_entries();
1653 if (acer_proc_dir)
1654 remove_proc_entry(PROC_ACER, acpi_root_dir);
1655 #endif
1656 printk(ACER_INFO "Acer Laptop ACPI Extras unloaded\n");
1657 return;
1660 module_init(acer_acpi_init);
1661 module_exit(acer_acpi_exit);