acer_acpi - Remove non-existant type 2 brightness quirk
[acer_acpi.git] / acer_acpi.c
blob2ea9b311a5b720a9f54721418194e0e81e21ee4e
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 MODULE_ALIAS("dmi:*:*Acer*:*:");
82 #define ACER_LOGPREFIX "acer_acpi: "
83 #define ACER_ERR KERN_ERR ACER_LOGPREFIX
84 #define ACER_NOTICE KERN_NOTICE ACER_LOGPREFIX
85 #define ACER_INFO KERN_INFO ACER_LOGPREFIX
87 #define DEBUG(level, message...) { \
88 if (debug >= level) \
89 printk(KERN_DEBUG ACER_LOGPREFIX message);\
93 * The maximum temperature one can set for fan control override.
94 * Doesn't propably make much sense if over 80 degrees celsius though...
96 #define ACER_MAX_TEMPERATURE_OVERRIDE 150
99 * The following defines quirks to get some specific functions to work
100 * which are known to not be supported over ACPI (such as the mail LED
101 * on WMID based Acer's)
103 struct acer_quirks {
104 const char *vendor;
105 const char *model;
106 u16 quirks;
110 * Keyboard controller ports
112 #define ACER_KBD_STATUS_REG 0x64 /* Status register (R) */
113 #define ACER_KBD_CNTL_REG 0x64 /* Controller command register (W) */
114 #define ACER_KBD_DATA_REG 0x60 /* Keyboard data register (R/W) */
117 * Magic Number
118 * Meaning is unknown - this number is required for writing to ACPI for AMW0
119 * (it's also used in acerhk when directly accessing the EC)
121 #define ACER_AMW0_WRITE 0x9610
124 * Bit masks for the old AMW0 interface
126 #define ACER_AMW0_WIRELESS_MASK 0x35
127 #define ACER_AMW0_BLUETOOTH_MASK 0x34
128 #define ACER_AMW0_MAILLED_MASK 0x31
131 * Method IDs for new WMID interface
133 #define ACER_WMID_GET_WIRELESS_METHODID 1
134 #define ACER_WMID_GET_BLUETOOTH_METHODID 2
135 #define ACER_WMID_GET_BRIGHTNESS_METHODID 3
136 #define ACER_WMID_SET_WIRELESS_METHODID 4
137 #define ACER_WMID_SET_BLUETOOTH_METHODID 5
138 #define ACER_WMID_SET_BRIGHTNESS_METHODID 6
139 #define ACER_WMID_GET_THREEG_METHODID 10
140 #define ACER_WMID_SET_THREEG_METHODID 11
143 * Acer ACPI method GUIDs
145 #define AMW0_GUID1 "67C3371D-95A3-4C37-BB61-DD47B491DAAB"
146 #define WMID_GUID1 "6AF4F258-B401-42fd-BE91-3D4AC2D7C0D3"
149 * Interface capability flags
151 #define ACER_CAP_MAILLED (1<<0)
152 #define ACER_CAP_WIRELESS (1<<1)
153 #define ACER_CAP_BLUETOOTH (1<<2)
154 #define ACER_CAP_BRIGHTNESS (1<<3)
155 #define ACER_CAP_THREEG (1<<4)
156 #define ACER_CAP_TOUCHPAD_READ (1<<5)
157 #define ACER_CAP_TEMPERATURE_OVERRIDE (1<<6)
158 #define ACER_CAP_ANY (0xFFFFFFFF)
161 * Interface type flags
163 enum interface_flags {
164 ACER_AMW0,
165 ACER_WMID,
169 * Presumed start states -
170 * On some AMW0 laptops, we do not yet know how to get the device status from
171 * the EC, so we must store this ourselves.
173 * Plus, we can't tell which features are enabled or disabled on a specific
174 * model - e.g. The 5020 series can _support_ bluetooth; but the 5021 has no
175 * bluetooth, whilst the 5024 does. However, the BIOS identifies both laptops
176 * as 5020, and you can add bluetooth later.
178 * Basically the code works like this:
179 * - On init, any values specified on the commandline are set.
180 * - For interfaces where the current values cannot be detected and which
181 * have not been set on the commandline, we set them to some sane default
182 * (disabled)
184 * See AMW0_init and acer_commandline_init
187 #define ACER_DEFAULT_WIRELESS 0
188 #define ACER_DEFAULT_BLUETOOTH 0
189 #define ACER_DEFAULT_MAILLED 0
190 #define ACER_DEFAULT_THREEG 0
192 static int max_brightness = 0xF;
194 static int wireless = -1;
195 static int bluetooth = -1;
196 static int mailled = -1;
197 static int brightness = -1;
198 static int threeg = -1;
199 static int fan_temperature_override = -1;
200 static int debug = 0;
201 static int force_series;
203 module_param(mailled, int, 0444);
204 module_param(wireless, int, 0444);
205 module_param(bluetooth, int, 0444);
206 module_param(brightness, int, 0444);
207 module_param(threeg, int, 0444);
208 module_param(force_series, int, 0444);
209 module_param(fan_temperature_override, int, 0444);
210 module_param(debug, int, 0664);
211 MODULE_PARM_DESC(wireless, "Set initial state of Wireless hardware");
212 MODULE_PARM_DESC(bluetooth, "Set initial state of Bluetooth hardware");
213 MODULE_PARM_DESC(mailled, "Set initial state of Mail LED");
214 MODULE_PARM_DESC(brightness, "Set initial LCD backlight brightness");
215 MODULE_PARM_DESC(threeg, "Set initial state of 3G hardware");
216 MODULE_PARM_DESC(fan_temperature_override, "Set initial state of the 'FAN temperature-override'");
217 MODULE_PARM_DESC(debug, "Debugging verbosity level (0=least 2=most)");
218 MODULE_PARM_DESC(force_series, "Force a different laptop series for extra features (5020, 5720 or 2490)");
220 #ifdef CONFIG_PROC
221 struct ProcItem {
222 const char *name;
223 char *(*read_func) (char *, u32);
224 unsigned long (*write_func) (const char *, unsigned long, u32);
225 unsigned int capability;
228 static struct proc_dir_entry *acer_proc_dir;
229 #endif
232 * Wait for the keyboard controller to become ready
234 static int wait_kbd_write(void)
236 int i = 0;
237 while ((inb(ACER_KBD_STATUS_REG) & 0x02) && (i < 10000)) {
238 udelay(50);
239 i++;
241 return -(i == 10000);
244 static void send_kbd_cmd(u8 cmd, u8 val)
246 preempt_disable();
247 if (!wait_kbd_write())
248 outb(cmd, ACER_KBD_CNTL_REG);
249 if (!wait_kbd_write())
250 outb(val, ACER_KBD_DATA_REG);
251 preempt_enable_no_resched();
254 static void set_keyboard_quirk(void)
256 send_kbd_cmd(0x59, 0x90);
259 struct acer_data {
260 int mailled;
261 int wireless;
262 int bluetooth;
263 int threeg;
264 int brightness;
267 /* Each low-level interface must define at least some of the following */
268 struct Interface {
270 * The ACPI device type
272 u32 type;
275 * The capabilities this interface provides
276 * In the future, these can be removed/added at runtime when we have a
277 * way of detecting what capabilities are /actually/ present on an
278 * interface
280 u32 capability;
283 * Initializes an interface, should allocate the interface-specific
284 * data
286 void (*init) (struct Interface *);
289 * Private data for the current interface
291 struct acer_data data;
294 /* The static interface pointer, points to the currently detected interface */
295 static struct Interface *interface;
298 * Embedded Controller quirks
299 * Some laptops require us to directly access the EC to either enable or query
300 * features that are not available through ACPI.
303 struct quirk_entry {
304 u8 wireless;
305 u8 mailled;
306 u8 brightness;
307 u8 touchpad;
308 u8 temperature_override;
309 u8 mmkeys;
310 u8 bluetooth;
311 u8 max_brightness;
314 static struct quirk_entry *quirks;
316 static void set_quirks(void)
318 if (quirks->mailled != 0) {
319 interface->capability |= ACER_CAP_MAILLED;
320 DEBUG(1, "Using EC direct-access quirk for mail LED\n");
323 if (quirks->touchpad != 0) {
324 interface->capability |= ACER_CAP_TOUCHPAD_READ;
325 DEBUG(1, "Using EC direct-access quirk for reading touchpad status\n");
328 if (quirks->temperature_override != 0) {
329 interface->capability |= ACER_CAP_TEMPERATURE_OVERRIDE;
330 DEBUG(1, "Using EC direct-access quirk for temperature override setting (fan)\n");
333 if (quirks->brightness != 0) {
334 interface->capability |= ACER_CAP_BRIGHTNESS;
335 DEBUG(1, "Using EC direct-access quirk for backlight brightness\n");
338 if (quirks->mmkeys != 0) {
339 set_keyboard_quirk();
340 printk(ACER_INFO "Setting keyboard quirk to enable multimedia keys\n");
343 if (quirks->bluetooth != 0) {
344 interface->capability |= ACER_CAP_BLUETOOTH;
345 DEBUG(1, "Using EC direct-access quirk for bluetooth\n");
348 if (quirks->wireless != 0) {
349 interface->capability |= ACER_CAP_WIRELESS;
350 DEBUG(1, "Using EC direct-access quirk for wireless\n");
353 if (quirks->max_brightness != 0) {
354 max_brightness = quirks->max_brightness;
355 DEBUG(1, "Changing maximum brightness level\n");
359 static int dmi_matched(struct dmi_system_id *dmi)
361 quirks = dmi->driver_data;
362 return 0;
365 static struct quirk_entry quirk_unknown = {
368 static struct quirk_entry quirk_acer_aspire_5020 = {
369 .wireless = 1,
370 .mailled = 2,
371 .brightness = 1,
372 .bluetooth = 1,
375 /* Same Mail LED quirk as TM2490, but does not require keyboard quirk */
376 static struct quirk_entry quirk_acer_aspire_5100 = {
377 .mailled = 1,
380 static struct quirk_entry quirk_acer_aspire_5680 = {
381 .mmkeys = 1,
384 static struct quirk_entry quirk_acer_aspire_9300 = {
385 .wireless = 2,
386 .mailled = 2,
387 .brightness = 1,
388 .bluetooth = 2,
391 static struct quirk_entry quirk_acer_travelmate_2490 = {
392 .mmkeys = 1,
393 .mailled = 1,
394 .temperature_override = 1,
395 .touchpad = 1,
399 * This is similar to the Aspire 5020, but with a different wireless quirk
401 static struct quirk_entry quirk_acer_travelmate_5620 = {
402 .wireless = 2,
403 .mailled = 2,
404 .brightness = 1,
405 .bluetooth = 1,
408 static struct quirk_entry quirk_acer_travelmate_5720 = {
409 .max_brightness = 0x9,
410 .touchpad = 2,
411 .wireless = 2,
412 .bluetooth = 2,
413 .brightness = 1,
416 static struct dmi_system_id acer_quirks[] = {
418 .callback = dmi_matched,
419 .ident = "Acer Aspire 3010",
420 .matches = {
421 DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
422 DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 3010"),
424 .driver_data = &quirk_acer_aspire_5020,
427 .callback = dmi_matched,
428 .ident = "Acer Aspire 3020",
429 .matches = {
430 DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
431 DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 3020"),
433 .driver_data = &quirk_acer_aspire_5020,
436 .callback = dmi_matched,
437 .ident = "Acer Aspire 3040",
438 .matches = {
439 DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
440 DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 3040"),
442 .driver_data = &quirk_acer_aspire_5020,
445 .callback = dmi_matched,
446 .ident = "Acer Aspire 3100",
447 .matches = {
448 DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
449 DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 3100"),
451 .driver_data = &quirk_acer_aspire_5100,
454 .callback = dmi_matched,
455 .ident = "Acer Aspire 5010",
456 .matches = {
457 DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
458 DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5010"),
460 .driver_data = &quirk_acer_aspire_5020,
463 .callback = dmi_matched,
464 .ident = "Acer Aspire 5020",
465 .matches = {
466 DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
467 DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5020"),
469 .driver_data = &quirk_acer_aspire_5020,
472 .callback = dmi_matched,
473 .ident = "Acer Aspire 5040",
474 .matches = {
475 DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
476 DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5040"),
478 .driver_data = &quirk_acer_aspire_5020,
481 .callback = dmi_matched,
482 .ident = "Acer Aspire 5100",
483 .matches = {
484 DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
485 DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5100"),
487 .driver_data = &quirk_acer_aspire_5100,
490 .callback = dmi_matched,
491 .ident = "Acer Aspire 5560",
492 .matches = {
493 DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
494 DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5560"),
496 .driver_data = &quirk_acer_travelmate_5620,
499 .callback = dmi_matched,
500 .ident = "Acer Aspire 5630",
501 .matches = {
502 DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
503 DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5630"),
505 .driver_data = &quirk_acer_travelmate_2490,
508 .callback = dmi_matched,
509 .ident = "Acer Aspire 5650",
510 .matches = {
511 DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
512 DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5650"),
514 .driver_data = &quirk_acer_travelmate_2490,
517 .callback = dmi_matched,
518 .ident = "Acer Aspire 5680",
519 .matches = {
520 DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
521 DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5680"),
523 .driver_data = &quirk_acer_aspire_5680,
526 .callback = dmi_matched,
527 .ident = "Acer Aspire 9300",
528 .matches = {
529 DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
530 DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 9300"),
532 .driver_data = &quirk_acer_aspire_9300,
535 .callback = dmi_matched,
536 .ident = "Acer Aspire 9420",
537 .matches = {
538 DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
539 DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 9420"),
541 .driver_data = &quirk_acer_travelmate_5620,
544 .callback = dmi_matched,
545 .ident = "Acer TravelMate 2420",
546 .matches = {
547 DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
548 DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 2420"),
550 .driver_data = &quirk_acer_aspire_5020,
553 .callback = dmi_matched,
554 .ident = "Acer TravelMate 2490",
555 .matches = {
556 DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
557 DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 2490"),
559 .driver_data = &quirk_acer_travelmate_2490,
562 .callback = dmi_matched,
563 .ident = "Acer TravelMate 5620",
564 .matches = {
565 DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
566 DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 5620"),
568 .driver_data = &quirk_acer_travelmate_5620,
571 .callback = dmi_matched,
572 .ident = "Acer TravelMate 5720",
573 .matches = {
574 DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
575 DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 5720"),
577 .driver_data = &quirk_acer_travelmate_5720,
582 /* Find which quirks are needed for a particular vendor/ model pair */
583 static void find_quirks(void)
585 DEBUG (1, "Looking for quirks\n");
586 if (!force_series) {
587 dmi_check_system(acer_quirks);
588 } else if (force_series == 5020) {
589 DEBUG(0, "Forcing Acer Aspire 5020\n");
590 quirks = &quirk_acer_aspire_5020;
591 } else if (force_series == 2490) {
592 DEBUG(0, "Forcing Acer TravelMate 2490\n");
593 quirks = &quirk_acer_travelmate_2490;
594 } else if (force_series == 5620) {
595 DEBUG(0, "Forcing Acer TravelMate 5620\n");
596 quirks = &quirk_acer_travelmate_5620;
597 } else if (force_series == 5720) {
598 DEBUG(0, "Forcing Acer TravelMate 5720\n");
599 quirks = &quirk_acer_travelmate_5720;
602 if (quirks == NULL) {
603 DEBUG(1, "No quirks known for this laptop\n");
604 quirks = &quirk_unknown;
606 set_quirks();
610 * General interface convenience methods
613 static bool has_cap(u32 cap)
615 if ((interface->capability & cap) != 0) {
616 return 1;
618 return 0;
622 * Old interface (now known as the AMW0 interface)
624 struct WMAB_args {
625 u32 eax;
626 u32 ebx;
627 u32 ecx;
628 u32 edx;
631 static acpi_status WMAB_execute(struct WMAB_args *regbuf, struct acpi_buffer *result)
633 struct acpi_buffer input;
634 acpi_status status;
635 input.length = sizeof(struct WMAB_args);
636 input.pointer = (u8*)regbuf;
638 status = wmi_acer_evaluate_method(AMW0_GUID1, 1, 1, &input, result);
639 DEBUG(2, " Args: 0x%08x 0x%08x 0x%08x 0x%08x\n", regbuf->eax, regbuf->ebx, regbuf->ecx, regbuf->edx );
641 return status;
644 static void AMW0_init(struct Interface *iface) {
645 bool help = 0;
648 * If the commandline doesn't specify these, we need to force them to
649 * the default values
651 if (mailled == -1 && !quirks->mailled)
652 mailled = ACER_DEFAULT_MAILLED;
653 if (wireless == -1 && !quirks->wireless)
654 wireless = ACER_DEFAULT_WIRELESS;
655 if (bluetooth == -1 && !quirks->bluetooth)
656 bluetooth = ACER_DEFAULT_BLUETOOTH;
659 * Set the cached "current" values to impossible ones so that
660 * acer_commandline_init will definitely set them.
662 if (quirks->bluetooth == 0) {
663 help = 1;
664 iface->data.bluetooth = -1;
665 printk(ACER_INFO "No EC data for reading bluetooth - bluetooth value when read will be a 'best guess'\n");
668 if (quirks->wireless == 0) {
669 help = 1;
670 printk(ACER_INFO "No EC data for reading wireless - wireless value when read will be a 'best guess'\n");
671 iface->data.wireless = -1;
673 if (quirks->mailled == 0) {
674 help = 1;
675 printk(ACER_INFO "No EC data for reading mail LED - mail LED value when read will be a 'best guess'\n");
676 iface->data.mailled = -1;
679 if (help) {
680 printk(ACER_INFO "We need more data from your laptop's Embedded Controller (EC) to better support it\n");
681 printk(ACER_INFO "Please see http://code.google.com/p/aceracpi/wiki/EmbeddedController on how to help\n");
685 static acpi_status AMW0_get_bool(bool *value, u32 cap, struct Interface *iface)
687 struct acer_data *data = &iface->data;
688 u8 result;
690 DEBUG(2, " AMW0_get_bool: cap=%d\n", cap);
692 * On some models, we can read these values from the EC. On others,
693 * we use a stored value
695 switch (cap) {
696 case ACER_CAP_MAILLED:
697 switch (quirks->mailled) {
698 case 2:
699 ec_read(0x0A, &result);
700 *value = (result >> 7) & 0x01;
701 return 0;
702 default:
703 *value = data->mailled;
705 break;
706 case ACER_CAP_WIRELESS:
707 switch (quirks->wireless) {
708 case 1:
709 ec_read(0x0A, &result);
710 *value = (result >> 2) & 0x01;
711 return 0;
712 case 2:
713 ec_read(0x71, &result);
714 *value = result & 0x01;
715 return 0;
716 default:
717 *value = data->wireless;
719 break;
720 case ACER_CAP_BLUETOOTH:
721 switch (quirks->bluetooth) {
722 case 1:
723 ec_read(0x0A, &result);
724 *value = (result >> 4) & 0x01;
725 return 0;
726 case 2:
727 ec_read(0x71, &result);
728 *value = (result >> 1) & 0x01;
729 return 0;
730 default:
731 *value = data->bluetooth;
733 break;
734 case ACER_CAP_TOUCHPAD_READ:
735 switch (quirks->touchpad) {
736 case 2:
737 ec_read(0x74, &result);
738 *value = (result >> 3) & 0x01;
739 return 0;
740 default:
741 break;
743 default:
744 return AE_BAD_ADDRESS;
746 return AE_OK;
749 static acpi_status AMW0_set_bool(bool value, u32 cap, struct Interface *iface)
751 struct WMAB_args args;
752 struct acer_data *data = &iface->data;
753 acpi_status status;
755 args.eax = ACER_AMW0_WRITE;
756 args.ebx = value ? (1<<8) : 0;
757 args.ecx = args.edx = 0;
759 switch (cap) {
760 case ACER_CAP_MAILLED:
761 args.ebx |= ACER_AMW0_MAILLED_MASK;
762 break;
763 case ACER_CAP_WIRELESS:
764 args.ebx |= ACER_AMW0_WIRELESS_MASK;
765 break;
766 case ACER_CAP_BLUETOOTH:
767 args.ebx |= ACER_AMW0_BLUETOOTH_MASK;
768 break;
769 default:
770 return AE_BAD_ADDRESS;
773 /* Actually do the set */
774 status = WMAB_execute(&args, NULL);
777 * Currently no way to query the state, so cache the new value on
778 * success
780 if (ACPI_SUCCESS(status)) {
781 switch (cap) {
782 case ACER_CAP_MAILLED:
783 data->mailled = value;
784 break;
785 case ACER_CAP_WIRELESS:
786 data->wireless = value;
787 break;
788 case ACER_CAP_BLUETOOTH:
789 data->bluetooth = value;
790 break;
794 return status;
797 static acpi_status AMW0_get_u8(u8 *value, u32 cap, struct Interface *iface) {
798 switch (cap) {
799 case ACER_CAP_BRIGHTNESS:
800 switch (quirks->brightness) {
801 case 1:
802 return ec_read(0x83, 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 default:
820 return AE_BAD_ADDRESS;
821 break;
823 default:
824 return AE_BAD_ADDRESS;
826 return AE_OK;
829 static struct Interface AMW0_interface = {
830 .type = ACER_AMW0,
831 .capability = (
832 ACER_CAP_MAILLED |
833 ACER_CAP_WIRELESS |
834 ACER_CAP_BLUETOOTH
836 .init = AMW0_init,
840 * New interface (The WMID interface)
842 static acpi_status
843 WMI_execute_u32(u32 method_id, u32 in, u32 *out)
845 struct acpi_buffer input = { (acpi_size) sizeof(u32), (void *)(&in) };
846 struct acpi_buffer result = { ACPI_ALLOCATE_BUFFER, NULL };
847 union acpi_object *obj;
848 u32 tmp;
849 acpi_status status;
851 DEBUG(2, " WMI_execute_u32:\n");
852 status = wmi_acer_evaluate_method(WMID_GUID1, 1, method_id, &input, &result);
853 DEBUG(2, " In: 0x%08x\n", in);
855 if (ACPI_FAILURE(status))
856 return status;
858 obj = (union acpi_object *) result.pointer;
859 if (obj && obj->type == ACPI_TYPE_BUFFER && obj->buffer.length == sizeof(u32)) {
860 tmp = *((u32 *) obj->buffer.pointer);
861 DEBUG(2, " Out: 0x%08x\n", tmp);
862 } else {
863 tmp = 0;
864 if (obj) {
865 DEBUG(2, " Got unexpected result of type %d\n", obj->type);
866 } else {
867 DEBUG(2, " Got unexpected null result\n");
871 if (out)
872 *out = tmp;
874 if (result.length > 0 && result.pointer)
875 kfree(result.pointer);
877 DEBUG(2, " Returning from WMI_execute_u32:\n");
878 return status;
881 static acpi_status WMID_get_u8(u8 *value, u32 cap, struct Interface *iface) {
882 acpi_status status;
883 u32 result;
884 u32 method_id = 0;
886 DEBUG(2, " WMID_get_u8: cap=%d\n", cap);
887 switch (cap) {
888 case ACER_CAP_WIRELESS:
889 method_id = ACER_WMID_GET_WIRELESS_METHODID;
890 break;
891 case ACER_CAP_BLUETOOTH:
892 method_id = ACER_WMID_GET_BLUETOOTH_METHODID;
893 break;
894 case ACER_CAP_BRIGHTNESS:
895 method_id = ACER_WMID_GET_BRIGHTNESS_METHODID;
896 break;
897 case ACER_CAP_THREEG:
898 method_id = ACER_WMID_GET_THREEG_METHODID;
899 break;
900 case ACER_CAP_MAILLED:
901 if (quirks->mailled == 1) {
902 ec_read(0x9f, value);
903 *value &= 0x01;
904 return 0;
906 case ACER_CAP_TOUCHPAD_READ:
907 switch (quirks->touchpad) {
908 case 1:
909 ec_read(0x9e, value);
910 *value = 1 - ((*value >> 3) & 0x01);
911 return 0;
912 default:
913 break;
915 case ACER_CAP_TEMPERATURE_OVERRIDE:
916 if (quirks->temperature_override == 1) {
917 ec_read(0xa9, value);
918 return 0;
920 default:
921 return AE_BAD_ADDRESS;
923 status = WMI_execute_u32(method_id, 0, &result);
924 DEBUG(2, " WMI_execute_u32 status=%d:\n", status);
926 if (ACPI_SUCCESS(status))
927 *value = (u8)result;
929 DEBUG(2, " Returning from WMID_get_u8:\n");
930 return status;
933 static acpi_status WMID_set_u8(u8 value, u32 cap, struct Interface *iface) {
934 u32 method_id = 0;
936 switch (cap) {
937 case ACER_CAP_BRIGHTNESS:
938 method_id = ACER_WMID_SET_BRIGHTNESS_METHODID;
939 break;
940 case ACER_CAP_WIRELESS:
941 method_id = ACER_WMID_SET_WIRELESS_METHODID;
942 break;
943 case ACER_CAP_BLUETOOTH:
944 method_id = ACER_WMID_SET_BLUETOOTH_METHODID;
945 break;
946 case ACER_CAP_THREEG:
947 method_id = ACER_WMID_SET_THREEG_METHODID;
948 break;
949 case ACER_CAP_MAILLED:
950 if (quirks->mailled == 1) {
951 send_kbd_cmd(0x59, value ? 0x92 : 0x93);
952 return 0;
954 case ACER_CAP_TEMPERATURE_OVERRIDE:
955 if (quirks->temperature_override == 1) {
956 ec_write(0xa9, value);
957 return 0;
959 default:
960 return AE_BAD_ADDRESS;
962 return WMI_execute_u32(method_id, (u32)value, NULL);
966 static struct Interface WMID_interface = {
967 .type = ACER_WMID,
968 .capability = (
969 ACER_CAP_WIRELESS
970 | ACER_CAP_BRIGHTNESS
971 | ACER_CAP_BLUETOOTH
972 | ACER_CAP_THREEG
976 #ifdef CONFIG_PROC
978 * High-level Procfs file handlers
981 static int
982 dispatch_read(char *page, char **start, off_t off, int count, int *eof,
983 struct ProcItem *item)
985 char *p = page;
986 int len;
988 DEBUG(2, " dispatch_read: \n");
989 if (off == 0)
990 p = item->read_func(p, item->capability);
991 len = (p - page);
992 if (len <= off + count)
993 *eof = 1;
994 *start = page + off;
995 len -= off;
996 if (len > count)
997 len = count;
998 if (len < 0)
999 len = 0;
1000 return len;
1003 static int
1004 dispatch_write(struct file *file, const char __user *buffer,
1005 unsigned long count, struct ProcItem *item)
1007 int result;
1008 char *tmp_buffer;
1011 * Arg buffer points to userspace memory, which can't be accessed
1012 * directly. Since we're making a copy, zero-terminate the
1013 * destination so that sscanf can be used on it safely.
1015 tmp_buffer = kmalloc(count + 1, GFP_KERNEL);
1016 if (copy_from_user(tmp_buffer, buffer, count)) {
1017 result = -EFAULT;
1018 } else {
1019 tmp_buffer[count] = 0;
1020 result = item->write_func(tmp_buffer, count, item->capability);
1022 kfree(tmp_buffer);
1023 return result;
1025 #endif
1028 * Generic Device (interface-independent)
1031 static acpi_status get_bool(bool *value, u32 cap) {
1032 acpi_status status = AE_BAD_ADDRESS;
1033 u8 tmp = 0;
1035 DEBUG(2, " get_bool: cap=%d, interface type=%d\n",
1036 cap, interface->type);
1037 switch (interface->type) {
1038 case ACER_AMW0:
1039 status = AMW0_get_bool(value, cap, interface);
1040 break;
1041 case ACER_WMID:
1042 status = WMID_get_u8(&tmp, cap, interface);
1043 *value = (tmp == 1) ? 1 : 0;
1044 break;
1046 DEBUG(2, " Returning from get_bool:\n");
1047 return status;
1050 static acpi_status set_bool(int value, u32 cap) {
1051 acpi_status status = AE_BAD_PARAMETER;
1053 DEBUG(2, " set_bool: cap=%d, interface type=%d, value=%d\n",
1054 cap, interface->type, value);
1055 if ((value == 0 || value == 1) && (interface->capability & cap)) {
1056 switch (interface->type) {
1057 case ACER_AMW0:
1058 status = AMW0_set_bool(value == 1, cap, interface);
1059 break;
1060 case ACER_WMID:
1061 status = WMID_set_u8(value == 1, cap, interface);
1062 break;
1065 return status;
1068 static acpi_status get_u8(u8 *value, u32 cap) {
1069 DEBUG(2, " get_u8: cap=%d\n", cap);
1070 switch (interface->type) {
1071 case ACER_AMW0:
1072 return AMW0_get_u8(value, cap, interface);
1073 break;
1074 case ACER_WMID:
1075 return WMID_get_u8(value, cap, interface);
1076 break;
1077 default:
1078 return AE_BAD_ADDRESS;
1082 static acpi_status set_u8(u8 value, u8 min, u8 max, u32 cap) {
1084 DEBUG(2, " set_u8: cap=%d, interface type=%d, value=%d\n",
1085 cap, interface->type, value);
1087 if ((value >= min && value <= max) && (interface->capability & cap) ) {
1088 switch (interface->type) {
1089 case ACER_AMW0:
1090 return AMW0_set_u8(value, cap, interface);
1091 case ACER_WMID:
1092 return WMID_set_u8(value, cap, interface);
1093 default:
1094 return AE_BAD_PARAMETER;
1097 return AE_BAD_PARAMETER;
1100 /* Each _u8 needs a small wrapper that sets the boundary values */
1101 static acpi_status set_brightness(u8 value)
1103 return set_u8(value, 0, max_brightness, ACER_CAP_BRIGHTNESS);
1106 static acpi_status set_temperature_override(u8 value)
1108 return set_u8(value, 0, ACER_MAX_TEMPERATURE_OVERRIDE, ACER_CAP_TEMPERATURE_OVERRIDE);
1111 static void __init acer_commandline_init(void)
1113 DEBUG(1, "Commandline args: mailled(%d) wireless(%d) bluetooth(%d) brightness(%d)\n",
1114 mailled, wireless, bluetooth, brightness);
1117 * These will all fail silently if the value given is invalid, or the
1118 * capability isn't available on the given interface
1120 set_bool(mailled, ACER_CAP_MAILLED);
1121 set_bool(wireless, ACER_CAP_WIRELESS);
1122 set_bool(bluetooth, ACER_CAP_BLUETOOTH);
1123 set_bool(threeg, ACER_CAP_THREEG);
1124 set_temperature_override(fan_temperature_override);
1125 set_brightness((u8)brightness);
1128 #ifdef CONFIG_PROC
1130 * Procfs interface (deprecated)
1132 static char *read_bool(char *p, u32 cap)
1134 bool result;
1135 acpi_status status;
1137 DEBUG(2, " read_bool: cap=%d\n", cap);
1138 status = get_bool(&result, cap);
1139 if (ACPI_SUCCESS(status))
1140 p += sprintf(p, "%d\n", result);
1141 else
1142 p += sprintf(p, "Read error" );
1143 return p;
1146 static unsigned long write_bool(const char *buffer, unsigned long count, u32 cap)
1148 int value;
1150 DEBUG(2, " write_bool: cap=%d, interface type=%d\n buffer=%s\n",
1151 cap, interface->type, buffer);
1153 if (sscanf(buffer, "%i", &value) == 1) {
1154 acpi_status status = set_bool(value, cap);
1155 if (ACPI_FAILURE(status))
1156 return -EINVAL;
1157 } else {
1158 return -EINVAL;
1160 return count;
1163 static char *read_u8(char *p, u32 cap)
1165 u8 result;
1166 acpi_status status;
1168 DEBUG(2, " read_u8: cap=%d\n", cap);
1169 status = get_u8(&result, cap);
1170 if (ACPI_SUCCESS(status))
1171 p += sprintf(p, "%u\n", result);
1172 else
1173 p += sprintf(p, "Read error" );
1174 return p;
1177 static unsigned long write_u8(const char *buffer, unsigned long count, u32 cap)
1179 int value;
1180 acpi_status (*set_method)(u8);
1182 /* Choose the appropriate set_u8 wrapper here, based on the capability */
1183 switch (cap) {
1184 case ACER_CAP_BRIGHTNESS:
1185 set_method = set_brightness;
1186 break;
1187 case ACER_CAP_TEMPERATURE_OVERRIDE:
1188 set_method = set_temperature_override;
1189 break;
1190 default:
1191 return -EINVAL;
1194 if (sscanf(buffer, "%i", &value) == 1) {
1195 acpi_status status = (*set_method)(value);
1196 if (ACPI_FAILURE(status))
1197 return -EINVAL;
1198 } else {
1199 return -EINVAL;
1201 return count;
1204 static char *read_version(char *p, u32 cap)
1206 p += sprintf(p, "%s\n", ACER_ACPI_VERSION);
1207 return p;
1210 static char *read_interface(char *p, u32 cap)
1212 p += sprintf(p, "%s\n", (interface->type == ACER_AMW0 ) ? "AMW0": "WMID");
1213 return p;
1216 static struct ProcItem proc_items[] = {
1217 {"mailled", read_bool, write_bool, ACER_CAP_MAILLED},
1218 {"bluetooth", read_bool, write_bool, ACER_CAP_BLUETOOTH},
1219 {"wireless", read_bool, write_bool, ACER_CAP_WIRELESS},
1220 {"brightness", read_u8, write_u8, ACER_CAP_BRIGHTNESS},
1221 {"threeg", read_bool, write_bool, ACER_CAP_THREEG},
1222 {"touchpad", read_bool, NULL, ACER_CAP_TOUCHPAD_READ},
1223 {"fan_temperature_override", read_u8, write_u8, ACER_CAP_TEMPERATURE_OVERRIDE},
1224 {"version", read_version, NULL, ACER_CAP_ANY},
1225 {"interface", read_interface, NULL, ACER_CAP_ANY},
1226 {NULL}
1229 static int __init add_proc_entries(void)
1231 struct proc_dir_entry *proc;
1232 struct ProcItem *item;
1234 for (item = proc_items; item->name; ++item) {
1236 * Only add the proc file if the current interface actually
1237 * supports it
1239 if (interface->capability & item->capability) {
1240 proc = create_proc_read_entry(item->name,
1241 S_IFREG | S_IRUGO | S_IWUSR,
1242 acer_proc_dir,
1243 (read_proc_t *) dispatch_read,
1244 item);
1245 if (proc)
1246 proc->owner = THIS_MODULE;
1247 if (proc && item->write_func)
1248 proc->write_proc = (write_proc_t *) dispatch_write;
1252 return 0;
1255 static int __exit remove_proc_entries(void)
1257 struct ProcItem *item;
1259 for (item = proc_items; item->name; ++item)
1260 remove_proc_entry(item->name, acer_proc_dir);
1261 return 0;
1263 #endif
1266 * LED device (Mail LED only, no other LEDs known yet)
1268 static void mail_led_set(struct led_classdev *led_cdev, enum led_brightness value)
1270 bool tmp = value;
1271 set_bool(tmp, ACER_CAP_MAILLED);
1274 static struct led_classdev mail_led = {
1275 .name = "acer_acpi:mail",
1276 .brightness_set = mail_led_set,
1279 static void acer_led_init(struct device *dev)
1281 led_classdev_register(dev, &mail_led);
1284 static void acer_led_exit(void)
1286 led_classdev_unregister(&mail_led);
1289 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,18)
1291 * Backlight device
1293 static struct backlight_device *acer_backlight_device;
1295 static int read_brightness(struct backlight_device *bd)
1297 u8 value;
1298 get_u8(&value, ACER_CAP_BRIGHTNESS);
1299 return value;
1302 #if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,20)
1303 static int update_bl_status(struct backlight_device *bd)
1305 set_brightness(bd->props->brightness);
1306 return 0;
1309 static struct backlight_properties acer_backlight_properties = {
1310 .get_brightness = read_brightness,
1311 .update_status = update_bl_status,
1314 static int __init acer_backlight_init(struct device *dev)
1316 struct backlight_device *bd;
1318 DEBUG(1, "Loading backlight driver\n");
1319 bd = backlight_device_register("acer_acpi", dev, NULL, &acer_backlight_properties);
1320 if (IS_ERR(bd)) {
1321 printk(ACER_ERR "Could not register Acer backlight device\n");
1322 acer_backlight_device = NULL;
1323 return PTR_ERR(bd);
1326 acer_backlight_device = bd;
1328 bd->props->max_brightness = max_brightness;
1329 return 0;
1331 #else
1332 static int update_bl_status(struct backlight_device *bd)
1334 set_brightness(bd->props.brightness);
1335 return 0;
1338 static struct backlight_ops acer_backlight_ops = {
1339 .get_brightness = read_brightness,
1340 .update_status = update_bl_status,
1343 static int __init acer_backlight_init(struct device *dev)
1345 struct backlight_device *bd;
1347 DEBUG(1, "Loading backlight driver\n");
1348 bd = backlight_device_register("acer_acpi", dev, NULL, &acer_backlight_ops);
1349 if (IS_ERR(bd)) {
1350 printk(ACER_ERR "Could not register Acer backlight device\n");
1351 acer_backlight_device = NULL;
1352 return PTR_ERR(bd);
1355 acer_backlight_device = bd;
1357 bd->props.max_brightness = max_brightness;
1358 bd->props.brightness = read_brightness(NULL);
1359 backlight_update_status(bd);
1360 return 0;
1362 #endif
1364 static void __exit acer_backlight_exit(void)
1366 backlight_device_unregister(acer_backlight_device);
1368 #endif
1371 * Read/ write bool sysfs macro
1373 #define show_set_bool(value, cap) \
1374 static ssize_t \
1375 show_bool_##value(struct device *dev, struct device_attribute *attr, \
1376 char *buf) \
1378 bool result; \
1379 acpi_status status = get_bool(&result, cap); \
1380 if (ACPI_SUCCESS(status)) \
1381 return sprintf(buf, "%d\n", result); \
1382 return sprintf(buf, "Read error" ); \
1385 static ssize_t \
1386 set_bool_##value(struct device *dev, struct device_attribute *attr, \
1387 const char *buf, size_t count) \
1389 bool tmp = simple_strtoul(buf, NULL, 10); \
1390 acpi_status status = set_bool(tmp, cap); \
1391 if (ACPI_FAILURE(status)) \
1392 return -EINVAL; \
1393 return count; \
1395 static DEVICE_ATTR(value, S_IWUGO | S_IRUGO | S_IWUSR, \
1396 show_bool_##value, set_bool_##value);
1398 show_set_bool(wireless, ACER_CAP_WIRELESS);
1399 show_set_bool(bluetooth, ACER_CAP_BLUETOOTH);
1400 show_set_bool(threeg, ACER_CAP_THREEG);
1401 show_set_bool(fan_temperature_override, ACER_CAP_TEMPERATURE_OVERRIDE);
1404 * Read-only bool sysfs macro
1406 #define show_bool(value, cap) \
1407 static ssize_t \
1408 show_bool_##value(struct device *dev, struct device_attribute *attr, \
1409 char *buf) \
1411 bool result; \
1412 acpi_status status = get_bool(&result, cap); \
1413 if (ACPI_SUCCESS(status)) \
1414 return sprintf(buf, "%d\n", result); \
1415 return sprintf(buf, "Read error" ); \
1417 static DEVICE_ATTR(value, S_IWUGO | S_IRUGO | S_IWUSR, \
1418 show_bool_##value, NULL);
1420 show_bool(touchpad, ACER_CAP_TOUCHPAD_READ);
1423 * Read interface sysfs macro
1425 static ssize_t show_interface(struct device *dev, struct device_attribute *attr,
1426 char *buf)
1428 return sprintf(buf, "%s\n", (interface->type == ACER_AMW0 ) ? "AMW0" : "WMID");
1431 static DEVICE_ATTR(interface, S_IWUGO | S_IRUGO | S_IWUSR, show_interface, NULL);
1434 * Platform device
1436 static int __devinit acer_platform_probe(struct platform_device *device)
1438 if (has_cap(ACER_CAP_MAILLED))
1439 acer_led_init(&device->dev);
1440 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,18)
1441 if (has_cap(ACER_CAP_BRIGHTNESS))
1442 acer_backlight_init(&device->dev);
1443 #endif
1444 return 0;
1447 static int acer_platform_remove(struct platform_device *device)
1449 if (has_cap(ACER_CAP_MAILLED))
1450 acer_led_exit();
1451 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,18)
1452 if (has_cap(ACER_CAP_BRIGHTNESS))
1453 acer_backlight_exit();
1454 #endif
1455 return 0;
1458 static int acer_platform_suspend(struct platform_device *device, pm_message_t state)
1461 * WMID fix for suspend-to-disk - save all current states now so we can
1462 * restore them on resume
1464 bool value;
1465 u8 u8value;
1466 struct acer_data *data = &interface->data;
1468 #define save_bool_device(device, cap) \
1469 if (has_cap(cap)) {\
1470 get_bool(&value, cap);\
1471 data->device = value;\
1474 #define save_u8_device(device, cap) \
1475 if (has_cap(cap)) {\
1476 get_u8(&u8value, cap);\
1477 data->device = u8value;\
1480 if (interface->type == ACER_WMID) {
1481 save_bool_device(wireless, ACER_CAP_WIRELESS);
1482 save_bool_device(bluetooth, ACER_CAP_BLUETOOTH);
1483 save_bool_device(threeg, ACER_CAP_THREEG);
1484 save_u8_device(brightness, ACER_CAP_BRIGHTNESS);
1487 return 0;
1490 static int acer_platform_resume(struct platform_device *device)
1492 struct acer_data *data = &interface->data;
1494 #define restore_bool_device(device, cap) \
1495 if (has_cap(cap))\
1496 set_bool(data->device, cap);\
1498 restore_bool_device(wireless, ACER_CAP_WIRELESS);
1499 restore_bool_device(bluetooth, ACER_CAP_BLUETOOTH);
1500 restore_bool_device(threeg, ACER_CAP_THREEG);
1501 restore_bool_device(mailled, ACER_CAP_MAILLED);
1503 if (has_cap(ACER_CAP_BRIGHTNESS))
1504 set_brightness((u8)data->brightness);
1506 /* Check if this laptop requires the keyboard quirk */
1507 if (quirks->mmkeys != 0) {
1508 set_keyboard_quirk();
1509 printk(ACER_INFO "Setting keyboard quirk to enable multimedia keys\n");
1512 return 0;
1515 static struct platform_driver acer_platform_driver = {
1516 .driver = {
1517 .name = "acer_acpi",
1518 .owner = THIS_MODULE,
1520 .probe = acer_platform_probe,
1521 .remove = acer_platform_remove,
1522 .suspend = acer_platform_suspend,
1523 .resume = acer_platform_resume,
1526 static struct platform_device *acer_platform_device;
1528 static int remove_sysfs(struct platform_device *device)
1530 #define remove_device_file(value, cap) \
1531 if (has_cap(cap)) \
1532 device_remove_file(&device->dev, &dev_attr_##value);
1534 remove_device_file(wireless, ACER_CAP_WIRELESS);
1535 remove_device_file(bluetooth, ACER_CAP_BLUETOOTH);
1536 remove_device_file(threeg, ACER_CAP_THREEG);
1537 remove_device_file(interface, ACER_CAP_ANY);
1538 remove_device_file(fan_temperature_override, ACER_CAP_TEMPERATURE_OVERRIDE);
1539 remove_device_file(touchpad, ACER_CAP_TOUCHPAD_READ);
1540 return 0;
1543 static int create_sysfs(void)
1545 int retval = -ENOMEM;
1547 #define add_device_file(value, cap) \
1548 if (has_cap(cap)) {\
1549 retval = device_create_file(&acer_platform_device->dev, &dev_attr_##value);\
1550 if (retval)\
1551 goto error;\
1554 add_device_file(wireless, ACER_CAP_WIRELESS);
1555 add_device_file(bluetooth, ACER_CAP_BLUETOOTH);
1556 add_device_file(threeg, ACER_CAP_THREEG);
1557 add_device_file(interface, ACER_CAP_ANY);
1558 add_device_file(fan_temperature_override, ACER_CAP_TEMPERATURE_OVERRIDE);
1559 add_device_file(touchpad, ACER_CAP_TOUCHPAD_READ);
1561 return 0;
1563 error:
1564 remove_sysfs(acer_platform_device);
1565 return retval;
1568 static int __init acer_acpi_init(void)
1570 printk(ACER_INFO "Acer Laptop ACPI Extras version %s\n",
1571 ACER_ACPI_VERSION);
1574 * Detect which WMI interface we're using.
1575 * Check for AMW0 first, as later AMW0 laptops also have the WMID GUID.
1577 if (wmi_acer_has_guid(AMW0_GUID1)) {
1578 DEBUG(0, "Detected Acer AMW0 interface\n");
1579 interface = &AMW0_interface;
1580 } else if (wmi_acer_has_guid(WMID_GUID1)) {
1581 DEBUG(0, "Detected Acer WMID interface\n");
1582 interface = &WMID_interface;
1583 } else {
1584 printk(ACER_ERR "No or unsupported WMI interface, unable to load.\n");
1585 return -ENODEV;
1588 /* Find if this laptop requires any quirks */
1589 DEBUG(1, "Finding quirks\n");
1590 find_quirks();
1592 /* Now that we have a known interface, initialize it */
1593 DEBUG(1, "Initialising interface\n");
1594 if (interface->init)
1595 interface->init(interface);
1597 #ifdef CONFIG_PROC
1598 /* Create the proc entries */
1599 acer_proc_dir = proc_mkdir(PROC_ACER, acpi_root_dir);
1600 if (!acer_proc_dir) {
1601 printk(ACER_ERR "Unable to create /proc entries, aborting.\n");
1602 goto error_proc_mkdir;
1605 acer_proc_dir->owner = THIS_MODULE;
1606 if (add_proc_entries()) {
1607 printk(ACER_ERR "Unable to create /proc entries, aborting.\n");
1608 goto error_proc_add;
1610 #endif
1613 * Register the driver
1615 if (platform_driver_register(&acer_platform_driver)) {
1616 printk(ACER_ERR "Unable to register platform driver, aborting.\n");
1617 goto error_platform_register;
1619 acer_platform_device = platform_device_alloc("acer_acpi", -1);
1620 platform_device_add(acer_platform_device);
1622 create_sysfs();
1624 DEBUG(1, "Driver registered\n");
1626 /* Override any initial settings with values from the commandline */
1627 acer_commandline_init();
1629 return 0;
1631 error_platform_register:
1632 #ifdef CONFIG_PROC
1633 remove_proc_entries();
1634 error_proc_add:
1635 if (acer_proc_dir)
1636 remove_proc_entry(PROC_ACER, acpi_root_dir);
1637 error_proc_mkdir:
1638 #endif
1639 return -ENODEV;
1642 static void __exit acer_acpi_exit(void)
1644 remove_sysfs(acer_platform_device);
1645 platform_device_del(acer_platform_device);
1646 platform_driver_unregister(&acer_platform_driver);
1648 #ifdef CONFIG_PROC
1649 remove_proc_entries();
1651 if (acer_proc_dir)
1652 remove_proc_entry(PROC_ACER, acpi_root_dir);
1653 #endif
1654 printk(ACER_INFO "Acer Laptop ACPI Extras unloaded\n");
1655 return;
1658 module_init(acer_acpi_init);
1659 module_exit(acer_acpi_exit);