wmi-acer: Add EC region handling
[acer_acpi.git] / acer_acpi.c
blob273424fb8e424e7d82f0f66d1da377f891a00ed9
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"
147 #define WMID_GUID2 "95764E09-FB56-4e83-B31A-37761F60994A"
150 * Interface capability flags
152 #define ACER_CAP_MAILLED (1<<0)
153 #define ACER_CAP_WIRELESS (1<<1)
154 #define ACER_CAP_BLUETOOTH (1<<2)
155 #define ACER_CAP_BRIGHTNESS (1<<3)
156 #define ACER_CAP_THREEG (1<<4)
157 #define ACER_CAP_TOUCHPAD_READ (1<<5)
158 #define ACER_CAP_TEMPERATURE_OVERRIDE (1<<6)
159 #define ACER_CAP_ANY (0xFFFFFFFF)
162 * Interface type flags
164 enum interface_flags {
165 ACER_AMW0,
166 ACER_WMID,
170 * Presumed start states -
171 * On some AMW0 laptops, we do not yet know how to get the device status from
172 * the EC, so we must store this ourselves.
174 * Plus, we can't tell which features are enabled or disabled on a specific
175 * model - e.g. The 5020 series can _support_ bluetooth; but the 5021 has no
176 * bluetooth, whilst the 5024 does. However, the BIOS identifies both laptops
177 * as 5020, and you can add bluetooth later.
179 * Basically the code works like this:
180 * - On init, any values specified on the commandline are set.
181 * - For interfaces where the current values cannot be detected and which
182 * have not been set on the commandline, we set them to some sane default
183 * (disabled)
185 * See AMW0_init and acer_commandline_init
188 #define ACER_DEFAULT_WIRELESS 0
189 #define ACER_DEFAULT_BLUETOOTH 0
190 #define ACER_DEFAULT_MAILLED 0
191 #define ACER_DEFAULT_THREEG 0
193 static int max_brightness = 0xF;
195 static int wireless = -1;
196 static int bluetooth = -1;
197 static int mailled = -1;
198 static int brightness = -1;
199 static int threeg = -1;
200 static int fan_temperature_override = -1;
201 static int debug = 0;
202 static int force_series;
204 module_param(mailled, int, 0444);
205 module_param(wireless, int, 0444);
206 module_param(bluetooth, int, 0444);
207 module_param(brightness, int, 0444);
208 module_param(threeg, int, 0444);
209 module_param(force_series, int, 0444);
210 module_param(fan_temperature_override, int, 0444);
211 module_param(debug, int, 0664);
212 MODULE_PARM_DESC(wireless, "Set initial state of Wireless hardware");
213 MODULE_PARM_DESC(bluetooth, "Set initial state of Bluetooth hardware");
214 MODULE_PARM_DESC(mailled, "Set initial state of Mail LED");
215 MODULE_PARM_DESC(brightness, "Set initial LCD backlight brightness");
216 MODULE_PARM_DESC(threeg, "Set initial state of 3G hardware");
217 MODULE_PARM_DESC(fan_temperature_override, "Set initial state of the 'FAN temperature-override'");
218 MODULE_PARM_DESC(debug, "Debugging verbosity level (0=least 2=most)");
219 MODULE_PARM_DESC(force_series, "Force a different laptop series for extra features (5020, 5720 or 2490)");
221 #ifdef CONFIG_PROC
222 struct ProcItem {
223 const char *name;
224 char *(*read_func) (char *, u32);
225 unsigned long (*write_func) (const char *, unsigned long, u32);
226 unsigned int capability;
229 static struct proc_dir_entry *acer_proc_dir;
230 #endif
233 * Wait for the keyboard controller to become ready
235 static int wait_kbd_write(void)
237 int i = 0;
238 while ((inb(ACER_KBD_STATUS_REG) & 0x02) && (i < 10000)) {
239 udelay(50);
240 i++;
242 return -(i == 10000);
245 static void send_kbd_cmd(u8 cmd, u8 val)
247 preempt_disable();
248 if (!wait_kbd_write())
249 outb(cmd, ACER_KBD_CNTL_REG);
250 if (!wait_kbd_write())
251 outb(val, ACER_KBD_DATA_REG);
252 preempt_enable_no_resched();
255 static void set_keyboard_quirk(void)
257 send_kbd_cmd(0x59, 0x90);
260 struct acer_data {
261 int mailled;
262 int wireless;
263 int bluetooth;
264 int threeg;
265 int brightness;
268 /* Each low-level interface must define at least some of the following */
269 struct Interface {
271 * The ACPI device type
273 u32 type;
276 * The capabilities this interface provides
277 * In the future, these can be removed/added at runtime when we have a
278 * way of detecting what capabilities are /actually/ present on an
279 * interface
281 u32 capability;
284 * Initializes an interface, should allocate the interface-specific
285 * data
287 void (*init) (struct Interface *);
290 * Private data for the current interface
292 struct acer_data data;
295 /* The static interface pointer, points to the currently detected interface */
296 static struct Interface *interface;
299 * Embedded Controller quirks
300 * Some laptops require us to directly access the EC to either enable or query
301 * features that are not available through ACPI.
304 struct quirk_entry {
305 u8 wireless;
306 u8 mailled;
307 u8 brightness;
308 u8 touchpad;
309 u8 temperature_override;
310 u8 mmkeys;
311 u8 bluetooth;
312 u8 max_brightness;
315 static struct quirk_entry *quirks;
317 static void set_quirks(void)
319 if (quirks->mailled != 0) {
320 interface->capability |= ACER_CAP_MAILLED;
321 DEBUG(1, "Using EC direct-access quirk for mail LED\n");
324 if (quirks->touchpad != 0) {
325 interface->capability |= ACER_CAP_TOUCHPAD_READ;
326 DEBUG(1, "Using EC direct-access quirk for reading touchpad status\n");
329 if (quirks->temperature_override != 0) {
330 interface->capability |= ACER_CAP_TEMPERATURE_OVERRIDE;
331 DEBUG(1, "Using EC direct-access quirk for temperature override setting (fan)\n");
334 if (quirks->brightness != 0) {
335 interface->capability |= ACER_CAP_BRIGHTNESS;
336 DEBUG(1, "Using EC direct-access quirk for backlight brightness\n");
339 if (quirks->mmkeys != 0) {
340 set_keyboard_quirk();
341 printk(ACER_INFO "Setting keyboard quirk to enable multimedia keys\n");
344 if (quirks->bluetooth != 0) {
345 interface->capability |= ACER_CAP_BLUETOOTH;
346 DEBUG(1, "Using EC direct-access quirk for bluetooth\n");
349 if (quirks->wireless != 0) {
350 interface->capability |= ACER_CAP_WIRELESS;
351 DEBUG(1, "Using EC direct-access quirk for wireless\n");
354 if (quirks->max_brightness != 0) {
355 max_brightness = quirks->max_brightness;
356 DEBUG(1, "Changing maximum brightness level\n");
360 static int dmi_matched(struct dmi_system_id *dmi)
362 quirks = dmi->driver_data;
363 return 0;
366 static struct quirk_entry quirk_unknown = {
369 static struct quirk_entry quirk_acer_aspire_5020 = {
370 .wireless = 1,
371 .mailled = 2,
372 .brightness = 1,
373 .bluetooth = 1,
376 /* Same Mail LED quirk as TM2490, but does not require keyboard quirk */
377 static struct quirk_entry quirk_acer_aspire_5100 = {
378 .mailled = 1,
381 static struct quirk_entry quirk_acer_aspire_5680 = {
382 .mmkeys = 1,
385 static struct quirk_entry quirk_acer_aspire_9300 = {
386 .wireless = 2,
387 .mailled = 2,
388 .brightness = 1,
389 .bluetooth = 2,
392 static struct quirk_entry quirk_acer_travelmate_2490 = {
393 .mmkeys = 1,
394 .mailled = 1,
395 .temperature_override = 1,
396 .touchpad = 1,
400 * This is similar to the Aspire 5020, but with a different wireless quirk
402 static struct quirk_entry quirk_acer_travelmate_5620 = {
403 .wireless = 2,
404 .mailled = 2,
405 .brightness = 1,
406 .bluetooth = 1,
409 static struct quirk_entry quirk_acer_travelmate_5720 = {
410 .max_brightness = 0x9,
411 .touchpad = 2,
412 .wireless = 2,
413 .bluetooth = 2,
414 .brightness = 1,
417 static struct dmi_system_id acer_quirks[] = {
419 .callback = dmi_matched,
420 .ident = "Acer Aspire 3010",
421 .matches = {
422 DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
423 DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 3010"),
425 .driver_data = &quirk_acer_aspire_5020,
428 .callback = dmi_matched,
429 .ident = "Acer Aspire 3020",
430 .matches = {
431 DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
432 DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 3020"),
434 .driver_data = &quirk_acer_aspire_5020,
437 .callback = dmi_matched,
438 .ident = "Acer Aspire 3040",
439 .matches = {
440 DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
441 DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 3040"),
443 .driver_data = &quirk_acer_aspire_5020,
446 .callback = dmi_matched,
447 .ident = "Acer Aspire 3100",
448 .matches = {
449 DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
450 DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 3100"),
452 .driver_data = &quirk_acer_aspire_5100,
455 .callback = dmi_matched,
456 .ident = "Acer Aspire 5010",
457 .matches = {
458 DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
459 DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5010"),
461 .driver_data = &quirk_acer_aspire_5020,
464 .callback = dmi_matched,
465 .ident = "Acer Aspire 5020",
466 .matches = {
467 DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
468 DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5020"),
470 .driver_data = &quirk_acer_aspire_5020,
473 .callback = dmi_matched,
474 .ident = "Acer Aspire 5040",
475 .matches = {
476 DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
477 DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5040"),
479 .driver_data = &quirk_acer_aspire_5020,
482 .callback = dmi_matched,
483 .ident = "Acer Aspire 5100",
484 .matches = {
485 DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
486 DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5100"),
488 .driver_data = &quirk_acer_aspire_5100,
491 .callback = dmi_matched,
492 .ident = "Acer Aspire 5560",
493 .matches = {
494 DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
495 DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5560"),
497 .driver_data = &quirk_acer_travelmate_5620,
500 .callback = dmi_matched,
501 .ident = "Acer Aspire 5630",
502 .matches = {
503 DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
504 DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5630"),
506 .driver_data = &quirk_acer_travelmate_2490,
509 .callback = dmi_matched,
510 .ident = "Acer Aspire 5650",
511 .matches = {
512 DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
513 DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5650"),
515 .driver_data = &quirk_acer_travelmate_2490,
518 .callback = dmi_matched,
519 .ident = "Acer Aspire 5680",
520 .matches = {
521 DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
522 DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5680"),
524 .driver_data = &quirk_acer_aspire_5680,
527 .callback = dmi_matched,
528 .ident = "Acer Aspire 9300",
529 .matches = {
530 DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
531 DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 9300"),
533 .driver_data = &quirk_acer_aspire_9300,
536 .callback = dmi_matched,
537 .ident = "Acer Aspire 9420",
538 .matches = {
539 DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
540 DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 9420"),
542 .driver_data = &quirk_acer_travelmate_5620,
545 .callback = dmi_matched,
546 .ident = "Acer Extensa 5220",
547 .matches = {
548 DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
549 DMI_MATCH(DMI_PRODUCT_NAME, "Extensa 5220"),
551 .driver_data = &quirk_acer_travelmate_5720,
554 .callback = dmi_matched,
555 .ident = "Acer TravelMate 2420",
556 .matches = {
557 DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
558 DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 2420"),
560 .driver_data = &quirk_acer_aspire_5020,
563 .callback = dmi_matched,
564 .ident = "Acer TravelMate 2490",
565 .matches = {
566 DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
567 DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 2490"),
569 .driver_data = &quirk_acer_travelmate_2490,
572 .callback = dmi_matched,
573 .ident = "Acer TravelMate 5620",
574 .matches = {
575 DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
576 DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 5620"),
578 .driver_data = &quirk_acer_travelmate_5620,
581 .callback = dmi_matched,
582 .ident = "Acer TravelMate 5720",
583 .matches = {
584 DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
585 DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 5720"),
587 .driver_data = &quirk_acer_travelmate_5720,
592 /* Find which quirks are needed for a particular vendor/ model pair */
593 static void find_quirks(void)
595 DEBUG (1, "Looking for quirks\n");
596 if (!force_series) {
597 dmi_check_system(acer_quirks);
598 } else if (force_series == 5020) {
599 DEBUG(0, "Forcing Acer Aspire 5020\n");
600 quirks = &quirk_acer_aspire_5020;
601 } else if (force_series == 2490) {
602 DEBUG(0, "Forcing Acer TravelMate 2490\n");
603 quirks = &quirk_acer_travelmate_2490;
604 } else if (force_series == 5620) {
605 DEBUG(0, "Forcing Acer TravelMate 5620\n");
606 quirks = &quirk_acer_travelmate_5620;
607 } else if (force_series == 5720) {
608 DEBUG(0, "Forcing Acer TravelMate 5720\n");
609 quirks = &quirk_acer_travelmate_5720;
612 if (quirks == NULL) {
613 DEBUG(1, "No quirks known for this laptop\n");
614 quirks = &quirk_unknown;
616 set_quirks();
620 * General interface convenience methods
623 static bool has_cap(u32 cap)
625 if ((interface->capability & cap) != 0) {
626 return 1;
628 return 0;
632 * Old interface (now known as the AMW0 interface)
634 struct WMAB_args {
635 u32 eax;
636 u32 ebx;
637 u32 ecx;
638 u32 edx;
641 static acpi_status WMAB_execute(struct WMAB_args *regbuf, struct acpi_buffer *result)
643 struct acpi_buffer input;
644 acpi_status status;
645 input.length = sizeof(struct WMAB_args);
646 input.pointer = (u8*)regbuf;
648 status = wmi_acer_evaluate_method(AMW0_GUID1, 1, 1, &input, result);
649 DEBUG(2, " Args: 0x%08x 0x%08x 0x%08x 0x%08x\n", regbuf->eax, regbuf->ebx, regbuf->ecx, regbuf->edx );
651 return status;
654 static void AMW0_init(struct Interface *iface) {
655 bool help = 0;
658 * If the commandline doesn't specify these, we need to force them to
659 * the default values
661 if (mailled == -1 && !quirks->mailled)
662 mailled = ACER_DEFAULT_MAILLED;
663 if (wireless == -1 && !quirks->wireless)
664 wireless = ACER_DEFAULT_WIRELESS;
665 if (bluetooth == -1 && !quirks->bluetooth)
666 bluetooth = ACER_DEFAULT_BLUETOOTH;
669 * Set the cached "current" values to impossible ones so that
670 * acer_commandline_init will definitely set them.
672 if (quirks->bluetooth == 0) {
673 help = 1;
674 iface->data.bluetooth = -1;
675 DEBUG(1, "No EC data for reading bluetooth - bluetooth value when read will be a 'best guess'\n");
678 if (quirks->wireless == 0) {
679 help = 1;
680 DEBUG(1, "No EC data for reading wireless - wireless value when read will be a 'best guess'\n");
681 iface->data.wireless = -1;
683 if (quirks->mailled == 0) {
684 help = 1;
685 DEBUG(1, "No EC data for reading mail LED - mail LED value when read will be a 'best guess'\n");
686 iface->data.mailled = -1;
689 if (help) {
690 DEBUG(1, "We need more data from your laptop's Embedded Controller (EC) to better support it\n");
691 DEBUG(1, "Please see http://code.google.com/p/aceracpi/wiki/EmbeddedController on how to help\n");
695 static acpi_status AMW0_get_bool(bool *value, u32 cap, struct Interface *iface)
697 struct acer_data *data = &iface->data;
698 u8 result;
700 DEBUG(2, " AMW0_get_bool: cap=%d\n", cap);
702 * On some models, we can read these values from the EC. On others,
703 * we use a stored value
705 switch (cap) {
706 case ACER_CAP_MAILLED:
707 switch (quirks->mailled) {
708 case 2:
709 ec_read(0x0A, &result);
710 *value = (result >> 7) & 0x01;
711 return 0;
712 default:
713 *value = data->mailled;
715 break;
716 case ACER_CAP_WIRELESS:
717 switch (quirks->wireless) {
718 case 1:
719 ec_read(0x0A, &result);
720 *value = (result >> 2) & 0x01;
721 return 0;
722 case 2:
723 ec_read(0x71, &result);
724 *value = result & 0x01;
725 return 0;
726 default:
727 *value = data->wireless;
729 break;
730 case ACER_CAP_BLUETOOTH:
731 switch (quirks->bluetooth) {
732 case 1:
733 ec_read(0x0A, &result);
734 *value = (result >> 4) & 0x01;
735 return 0;
736 case 2:
737 ec_read(0x71, &result);
738 *value = (result >> 1) & 0x01;
739 return 0;
740 default:
741 *value = data->bluetooth;
743 break;
744 case ACER_CAP_TOUCHPAD_READ:
745 switch (quirks->touchpad) {
746 case 2:
747 ec_read(0x74, &result);
748 *value = (result >> 3) & 0x01;
749 return 0;
750 default:
751 break;
753 default:
754 return AE_BAD_ADDRESS;
756 return AE_OK;
759 static acpi_status AMW0_set_bool(bool value, u32 cap, struct Interface *iface)
761 struct WMAB_args args;
762 struct acer_data *data = &iface->data;
763 acpi_status status;
765 args.eax = ACER_AMW0_WRITE;
766 args.ebx = value ? (1<<8) : 0;
767 args.ecx = args.edx = 0;
769 switch (cap) {
770 case ACER_CAP_MAILLED:
771 args.ebx |= ACER_AMW0_MAILLED_MASK;
772 break;
773 case ACER_CAP_WIRELESS:
774 args.ebx |= ACER_AMW0_WIRELESS_MASK;
775 break;
776 case ACER_CAP_BLUETOOTH:
777 args.ebx |= ACER_AMW0_BLUETOOTH_MASK;
778 break;
779 default:
780 return AE_BAD_ADDRESS;
783 /* Actually do the set */
784 status = WMAB_execute(&args, NULL);
787 * Currently no way to query the state, so cache the new value on
788 * success
790 if (ACPI_SUCCESS(status)) {
791 switch (cap) {
792 case ACER_CAP_MAILLED:
793 data->mailled = value;
794 break;
795 case ACER_CAP_WIRELESS:
796 data->wireless = value;
797 break;
798 case ACER_CAP_BLUETOOTH:
799 data->bluetooth = value;
800 break;
804 return status;
807 static acpi_status AMW0_get_u8(u8 *value, u32 cap, struct Interface *iface) {
808 switch (cap) {
809 case ACER_CAP_BRIGHTNESS:
810 switch (quirks->brightness) {
811 case 1:
812 return ec_read(0x83, value);
813 default:
814 return AE_BAD_ADDRESS;
816 break;
817 default:
818 return AE_BAD_ADDRESS;
820 return AE_OK;
823 static acpi_status AMW0_set_u8(u8 value, u32 cap, struct Interface *iface) {
824 switch (cap) {
825 case ACER_CAP_BRIGHTNESS:
826 switch (quirks->brightness) {
827 case 1:
828 return ec_write(0x83, value);
829 default:
830 return AE_BAD_ADDRESS;
831 break;
833 default:
834 return AE_BAD_ADDRESS;
836 return AE_OK;
839 static struct Interface AMW0_interface = {
840 .type = ACER_AMW0,
841 .capability = (
842 ACER_CAP_MAILLED |
843 ACER_CAP_WIRELESS |
844 ACER_CAP_BLUETOOTH
846 .init = AMW0_init,
850 * New interface (The WMID interface)
852 static acpi_status
853 WMI_execute_u32(u32 method_id, u32 in, u32 *out)
855 struct acpi_buffer input = { (acpi_size) sizeof(u32), (void *)(&in) };
856 struct acpi_buffer result = { ACPI_ALLOCATE_BUFFER, NULL };
857 union acpi_object *obj;
858 u32 tmp;
859 acpi_status status;
861 DEBUG(2, " WMI_execute_u32:\n");
862 status = wmi_acer_evaluate_method(WMID_GUID1, 1, method_id, &input, &result);
863 DEBUG(2, " In: 0x%08x\n", in);
865 if (ACPI_FAILURE(status))
866 return status;
868 obj = (union acpi_object *) result.pointer;
869 if (obj && obj->type == ACPI_TYPE_BUFFER && obj->buffer.length == sizeof(u32)) {
870 tmp = *((u32 *) obj->buffer.pointer);
871 DEBUG(2, " Out: 0x%08x\n", tmp);
872 } else {
873 tmp = 0;
874 if (obj) {
875 DEBUG(2, " Got unexpected result of type %d\n", obj->type);
876 } else {
877 DEBUG(2, " Got unexpected null result\n");
881 if (out)
882 *out = tmp;
884 if (result.length > 0 && result.pointer)
885 kfree(result.pointer);
887 DEBUG(2, " Returning from WMI_execute_u32:\n");
888 return status;
891 static acpi_status WMID_get_u8(u8 *value, u32 cap, struct Interface *iface) {
892 acpi_status status;
893 u32 result;
894 u32 method_id = 0;
896 DEBUG(2, " WMID_get_u8: cap=%d\n", cap);
897 switch (cap) {
898 case ACER_CAP_WIRELESS:
899 method_id = ACER_WMID_GET_WIRELESS_METHODID;
900 break;
901 case ACER_CAP_BLUETOOTH:
902 method_id = ACER_WMID_GET_BLUETOOTH_METHODID;
903 break;
904 case ACER_CAP_BRIGHTNESS:
905 method_id = ACER_WMID_GET_BRIGHTNESS_METHODID;
906 break;
907 case ACER_CAP_THREEG:
908 method_id = ACER_WMID_GET_THREEG_METHODID;
909 break;
910 case ACER_CAP_MAILLED:
911 if (quirks->mailled == 1) {
912 ec_read(0x9f, value);
913 *value &= 0x01;
914 return 0;
916 case ACER_CAP_TOUCHPAD_READ:
917 switch (quirks->touchpad) {
918 case 1:
919 ec_read(0x9e, value);
920 *value = 1 - ((*value >> 3) & 0x01);
921 return 0;
922 default:
923 break;
925 case ACER_CAP_TEMPERATURE_OVERRIDE:
926 if (quirks->temperature_override == 1) {
927 ec_read(0xa9, value);
928 return 0;
930 default:
931 return AE_BAD_ADDRESS;
933 status = WMI_execute_u32(method_id, 0, &result);
934 DEBUG(2, " WMI_execute_u32 status=%d:\n", status);
936 if (ACPI_SUCCESS(status))
937 *value = (u8)result;
939 DEBUG(2, " Returning from WMID_get_u8:\n");
940 return status;
943 static acpi_status WMID_set_u8(u8 value, u32 cap, struct Interface *iface) {
944 u32 method_id = 0;
946 switch (cap) {
947 case ACER_CAP_BRIGHTNESS:
948 method_id = ACER_WMID_SET_BRIGHTNESS_METHODID;
949 break;
950 case ACER_CAP_WIRELESS:
951 method_id = ACER_WMID_SET_WIRELESS_METHODID;
952 break;
953 case ACER_CAP_BLUETOOTH:
954 method_id = ACER_WMID_SET_BLUETOOTH_METHODID;
955 break;
956 case ACER_CAP_THREEG:
957 method_id = ACER_WMID_SET_THREEG_METHODID;
958 break;
959 case ACER_CAP_MAILLED:
960 if (quirks->mailled == 1) {
961 send_kbd_cmd(0x59, value ? 0x92 : 0x93);
962 return 0;
964 case ACER_CAP_TEMPERATURE_OVERRIDE:
965 if (quirks->temperature_override == 1) {
966 ec_write(0xa9, value);
967 return 0;
969 default:
970 return AE_BAD_ADDRESS;
972 return WMI_execute_u32(method_id, (u32)value, NULL);
976 static struct Interface WMID_interface = {
977 .type = ACER_WMID,
978 .capability = (
979 ACER_CAP_WIRELESS
980 | ACER_CAP_BRIGHTNESS
981 | ACER_CAP_BLUETOOTH
982 | ACER_CAP_THREEG
986 #ifdef CONFIG_PROC
988 * High-level Procfs file handlers
991 static int
992 dispatch_read(char *page, char **start, off_t off, int count, int *eof,
993 struct ProcItem *item)
995 char *p = page;
996 int len;
998 DEBUG(2, " dispatch_read: \n");
999 if (off == 0)
1000 p = item->read_func(p, item->capability);
1001 len = (p - page);
1002 if (len <= off + count)
1003 *eof = 1;
1004 *start = page + off;
1005 len -= off;
1006 if (len > count)
1007 len = count;
1008 if (len < 0)
1009 len = 0;
1010 return len;
1013 static int
1014 dispatch_write(struct file *file, const char __user *buffer,
1015 unsigned long count, struct ProcItem *item)
1017 int result;
1018 char *tmp_buffer;
1021 * Arg buffer points to userspace memory, which can't be accessed
1022 * directly. Since we're making a copy, zero-terminate the
1023 * destination so that sscanf can be used on it safely.
1025 tmp_buffer = kmalloc(count + 1, GFP_KERNEL);
1026 if (copy_from_user(tmp_buffer, buffer, count)) {
1027 result = -EFAULT;
1028 } else {
1029 tmp_buffer[count] = 0;
1030 result = item->write_func(tmp_buffer, count, item->capability);
1032 kfree(tmp_buffer);
1033 return result;
1035 #endif
1038 * Generic Device (interface-independent)
1041 static acpi_status get_bool(bool *value, u32 cap) {
1042 acpi_status status = AE_BAD_ADDRESS;
1043 u8 tmp = 0;
1045 DEBUG(2, " get_bool: cap=%d, interface type=%d\n",
1046 cap, interface->type);
1047 switch (interface->type) {
1048 case ACER_AMW0:
1049 status = AMW0_get_bool(value, cap, interface);
1050 break;
1051 case ACER_WMID:
1052 status = WMID_get_u8(&tmp, cap, interface);
1053 *value = (tmp == 1) ? 1 : 0;
1054 break;
1056 DEBUG(2, " Returning from get_bool:\n");
1057 return status;
1060 static acpi_status set_bool(int value, u32 cap) {
1061 acpi_status status = AE_BAD_PARAMETER;
1063 DEBUG(2, " set_bool: cap=%d, interface type=%d, value=%d\n",
1064 cap, interface->type, value);
1065 if ((value == 0 || value == 1) && (interface->capability & cap)) {
1066 switch (interface->type) {
1067 case ACER_AMW0:
1068 status = AMW0_set_bool(value == 1, cap, interface);
1069 break;
1070 case ACER_WMID:
1071 status = WMID_set_u8(value == 1, cap, interface);
1072 break;
1075 return status;
1078 static acpi_status get_u8(u8 *value, u32 cap) {
1079 DEBUG(2, " get_u8: cap=%d\n", cap);
1080 switch (interface->type) {
1081 case ACER_AMW0:
1082 return AMW0_get_u8(value, cap, interface);
1083 break;
1084 case ACER_WMID:
1085 return WMID_get_u8(value, cap, interface);
1086 break;
1087 default:
1088 return AE_BAD_ADDRESS;
1092 static acpi_status set_u8(u8 value, u8 min, u8 max, u32 cap) {
1094 DEBUG(2, " set_u8: cap=%d, interface type=%d, value=%d\n",
1095 cap, interface->type, value);
1097 if ((value >= min && value <= max) && (interface->capability & cap) ) {
1098 switch (interface->type) {
1099 case ACER_AMW0:
1100 return AMW0_set_u8(value, cap, interface);
1101 case ACER_WMID:
1102 return WMID_set_u8(value, cap, interface);
1103 default:
1104 return AE_BAD_PARAMETER;
1107 return AE_BAD_PARAMETER;
1110 /* Each _u8 needs a small wrapper that sets the boundary values */
1111 static acpi_status set_brightness(u8 value)
1113 return set_u8(value, 0, max_brightness, ACER_CAP_BRIGHTNESS);
1116 static acpi_status set_temperature_override(u8 value)
1118 return set_u8(value, 0, ACER_MAX_TEMPERATURE_OVERRIDE, ACER_CAP_TEMPERATURE_OVERRIDE);
1121 static void __init acer_commandline_init(void)
1123 DEBUG(1, "Commandline args: mailled(%d) wireless(%d) bluetooth(%d) brightness(%d)\n",
1124 mailled, wireless, bluetooth, brightness);
1127 * These will all fail silently if the value given is invalid, or the
1128 * capability isn't available on the given interface
1130 set_bool(mailled, ACER_CAP_MAILLED);
1131 set_bool(wireless, ACER_CAP_WIRELESS);
1132 set_bool(bluetooth, ACER_CAP_BLUETOOTH);
1133 set_bool(threeg, ACER_CAP_THREEG);
1134 set_temperature_override(fan_temperature_override);
1135 set_brightness((u8)brightness);
1138 #ifdef CONFIG_PROC
1140 * Procfs interface (deprecated)
1142 static char *read_bool(char *p, u32 cap)
1144 bool result;
1145 acpi_status status;
1147 DEBUG(2, " read_bool: cap=%d\n", cap);
1148 status = get_bool(&result, cap);
1149 if (ACPI_SUCCESS(status))
1150 p += sprintf(p, "%d\n", result);
1151 else
1152 p += sprintf(p, "Read error" );
1153 return p;
1156 static unsigned long write_bool(const char *buffer, unsigned long count, u32 cap)
1158 int value;
1160 DEBUG(2, " write_bool: cap=%d, interface type=%d\n buffer=%s\n",
1161 cap, interface->type, buffer);
1163 if (sscanf(buffer, "%i", &value) == 1) {
1164 acpi_status status = set_bool(value, cap);
1165 if (ACPI_FAILURE(status))
1166 return -EINVAL;
1167 } else {
1168 return -EINVAL;
1170 return count;
1173 static char *read_u8(char *p, u32 cap)
1175 u8 result;
1176 acpi_status status;
1178 DEBUG(2, " read_u8: cap=%d\n", cap);
1179 status = get_u8(&result, cap);
1180 if (ACPI_SUCCESS(status))
1181 p += sprintf(p, "%u\n", result);
1182 else
1183 p += sprintf(p, "Read error" );
1184 return p;
1187 static unsigned long write_u8(const char *buffer, unsigned long count, u32 cap)
1189 int value;
1190 acpi_status (*set_method)(u8);
1192 /* Choose the appropriate set_u8 wrapper here, based on the capability */
1193 switch (cap) {
1194 case ACER_CAP_BRIGHTNESS:
1195 set_method = set_brightness;
1196 break;
1197 case ACER_CAP_TEMPERATURE_OVERRIDE:
1198 set_method = set_temperature_override;
1199 break;
1200 default:
1201 return -EINVAL;
1204 if (sscanf(buffer, "%i", &value) == 1) {
1205 acpi_status status = (*set_method)(value);
1206 if (ACPI_FAILURE(status))
1207 return -EINVAL;
1208 } else {
1209 return -EINVAL;
1211 return count;
1214 static char *read_version(char *p, u32 cap)
1216 p += sprintf(p, "%s\n", ACER_ACPI_VERSION);
1217 return p;
1220 static char *read_interface(char *p, u32 cap)
1222 p += sprintf(p, "%s\n", (interface->type == ACER_AMW0 ) ? "AMW0": "WMID");
1223 return p;
1226 static struct ProcItem proc_items[] = {
1227 {"mailled", read_bool, write_bool, ACER_CAP_MAILLED},
1228 {"bluetooth", read_bool, write_bool, ACER_CAP_BLUETOOTH},
1229 {"wireless", read_bool, write_bool, ACER_CAP_WIRELESS},
1230 {"brightness", read_u8, write_u8, ACER_CAP_BRIGHTNESS},
1231 {"threeg", read_bool, write_bool, ACER_CAP_THREEG},
1232 {"touchpad", read_bool, NULL, ACER_CAP_TOUCHPAD_READ},
1233 {"fan_temperature_override", read_u8, write_u8, ACER_CAP_TEMPERATURE_OVERRIDE},
1234 {"version", read_version, NULL, ACER_CAP_ANY},
1235 {"interface", read_interface, NULL, ACER_CAP_ANY},
1236 {NULL}
1239 static int __init add_proc_entries(void)
1241 struct proc_dir_entry *proc;
1242 struct ProcItem *item;
1244 for (item = proc_items; item->name; ++item) {
1246 * Only add the proc file if the current interface actually
1247 * supports it
1249 if (interface->capability & item->capability) {
1250 proc = create_proc_read_entry(item->name,
1251 S_IFREG | S_IRUGO | S_IWUSR,
1252 acer_proc_dir,
1253 (read_proc_t *) dispatch_read,
1254 item);
1255 if (proc)
1256 proc->owner = THIS_MODULE;
1257 if (proc && item->write_func)
1258 proc->write_proc = (write_proc_t *) dispatch_write;
1262 return 0;
1265 static int __exit remove_proc_entries(void)
1267 struct ProcItem *item;
1269 for (item = proc_items; item->name; ++item)
1270 remove_proc_entry(item->name, acer_proc_dir);
1271 return 0;
1273 #endif
1276 * LED device (Mail LED only, no other LEDs known yet)
1278 static void mail_led_set(struct led_classdev *led_cdev, enum led_brightness value)
1280 bool tmp = value;
1281 set_bool(tmp, ACER_CAP_MAILLED);
1284 static struct led_classdev mail_led = {
1285 .name = "acer_acpi:mail",
1286 .brightness_set = mail_led_set,
1289 static void acer_led_init(struct device *dev)
1291 led_classdev_register(dev, &mail_led);
1294 static void acer_led_exit(void)
1296 led_classdev_unregister(&mail_led);
1299 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,18)
1301 * Backlight device
1303 static struct backlight_device *acer_backlight_device;
1305 static int read_brightness(struct backlight_device *bd)
1307 u8 value;
1308 get_u8(&value, ACER_CAP_BRIGHTNESS);
1309 return value;
1312 #if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,20)
1313 static int update_bl_status(struct backlight_device *bd)
1315 set_brightness(bd->props->brightness);
1316 return 0;
1319 static struct backlight_properties acer_backlight_properties = {
1320 .get_brightness = read_brightness,
1321 .update_status = update_bl_status,
1324 static int __init acer_backlight_init(struct device *dev)
1326 struct backlight_device *bd;
1328 DEBUG(1, "Loading backlight driver\n");
1329 bd = backlight_device_register("acer_acpi", dev, NULL, &acer_backlight_properties);
1330 if (IS_ERR(bd)) {
1331 printk(ACER_ERR "Could not register Acer backlight device\n");
1332 acer_backlight_device = NULL;
1333 return PTR_ERR(bd);
1336 acer_backlight_device = bd;
1338 bd->props->max_brightness = max_brightness;
1339 return 0;
1341 #else
1342 static int update_bl_status(struct backlight_device *bd)
1344 set_brightness(bd->props.brightness);
1345 return 0;
1348 static struct backlight_ops acer_backlight_ops = {
1349 .get_brightness = read_brightness,
1350 .update_status = update_bl_status,
1353 static int __init acer_backlight_init(struct device *dev)
1355 struct backlight_device *bd;
1357 DEBUG(1, "Loading backlight driver\n");
1358 bd = backlight_device_register("acer_acpi", dev, NULL, &acer_backlight_ops);
1359 if (IS_ERR(bd)) {
1360 printk(ACER_ERR "Could not register Acer backlight device\n");
1361 acer_backlight_device = NULL;
1362 return PTR_ERR(bd);
1365 acer_backlight_device = bd;
1367 bd->props.max_brightness = max_brightness;
1368 bd->props.brightness = read_brightness(NULL);
1369 backlight_update_status(bd);
1370 return 0;
1372 #endif
1374 static void __exit acer_backlight_exit(void)
1376 backlight_device_unregister(acer_backlight_device);
1378 #endif
1381 * Read/ write bool sysfs macro
1383 #define show_set_bool(value, cap) \
1384 static ssize_t \
1385 show_bool_##value(struct device *dev, struct device_attribute *attr, \
1386 char *buf) \
1388 bool result; \
1389 acpi_status status = get_bool(&result, cap); \
1390 if (ACPI_SUCCESS(status)) \
1391 return sprintf(buf, "%d\n", result); \
1392 return sprintf(buf, "Read error" ); \
1395 static ssize_t \
1396 set_bool_##value(struct device *dev, struct device_attribute *attr, \
1397 const char *buf, size_t count) \
1399 bool tmp = simple_strtoul(buf, NULL, 10); \
1400 acpi_status status = set_bool(tmp, cap); \
1401 if (ACPI_FAILURE(status)) \
1402 return -EINVAL; \
1403 return count; \
1405 static DEVICE_ATTR(value, S_IWUGO | S_IRUGO | S_IWUSR, \
1406 show_bool_##value, set_bool_##value);
1408 show_set_bool(wireless, ACER_CAP_WIRELESS);
1409 show_set_bool(bluetooth, ACER_CAP_BLUETOOTH);
1410 show_set_bool(threeg, ACER_CAP_THREEG);
1411 show_set_bool(fan_temperature_override, ACER_CAP_TEMPERATURE_OVERRIDE);
1414 * Read-only bool sysfs macro
1416 #define show_bool(value, cap) \
1417 static ssize_t \
1418 show_bool_##value(struct device *dev, struct device_attribute *attr, \
1419 char *buf) \
1421 bool result; \
1422 acpi_status status = get_bool(&result, cap); \
1423 if (ACPI_SUCCESS(status)) \
1424 return sprintf(buf, "%d\n", result); \
1425 return sprintf(buf, "Read error" ); \
1427 static DEVICE_ATTR(value, S_IWUGO | S_IRUGO | S_IWUSR, \
1428 show_bool_##value, NULL);
1430 show_bool(touchpad, ACER_CAP_TOUCHPAD_READ);
1433 * Read interface sysfs macro
1435 static ssize_t show_interface(struct device *dev, struct device_attribute *attr,
1436 char *buf)
1438 return sprintf(buf, "%s\n", (interface->type == ACER_AMW0 ) ? "AMW0" : "WMID");
1441 static DEVICE_ATTR(interface, S_IWUGO | S_IRUGO | S_IWUSR, show_interface, NULL);
1443 static ssize_t show_devices(struct device *dev, struct device_attribute *attr,
1444 char *buf)
1446 struct acpi_buffer out = {ACPI_ALLOCATE_BUFFER, NULL};
1447 union acpi_object *obj;
1448 acpi_status status;
1449 u32 tmp;
1451 status = wmi_acer_query_block(WMID_GUID2, 1, &out);
1452 if (ACPI_FAILURE(status))
1453 return sprintf(buf, "Error\n");
1455 obj = (union acpi_object *) out.pointer;
1456 if (obj && obj->type == ACPI_TYPE_BUFFER && obj->buffer.length == sizeof(u32)) {
1457 tmp = *((u32 *) obj->buffer.pointer);
1458 } else {
1459 return sprintf(buf, "Error\n");
1462 return sprintf(buf, "%u\n", tmp);
1465 static DEVICE_ATTR(devices, S_IWUGO | S_IRUGO | S_IWUSR, show_devices, NULL);
1468 * Platform device
1470 static int __devinit acer_platform_probe(struct platform_device *device)
1472 if (has_cap(ACER_CAP_MAILLED))
1473 acer_led_init(&device->dev);
1474 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,18)
1475 if (has_cap(ACER_CAP_BRIGHTNESS))
1476 acer_backlight_init(&device->dev);
1477 #endif
1478 return 0;
1481 static int acer_platform_remove(struct platform_device *device)
1483 if (has_cap(ACER_CAP_MAILLED))
1484 acer_led_exit();
1485 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,18)
1486 if (has_cap(ACER_CAP_BRIGHTNESS))
1487 acer_backlight_exit();
1488 #endif
1489 return 0;
1492 static int acer_platform_suspend(struct platform_device *device, pm_message_t state)
1495 * WMID fix for suspend-to-disk - save all current states now so we can
1496 * restore them on resume
1498 bool value;
1499 u8 u8value;
1500 struct acer_data *data = &interface->data;
1502 #define save_bool_device(device, cap) \
1503 if (has_cap(cap)) {\
1504 get_bool(&value, cap);\
1505 data->device = value;\
1508 #define save_u8_device(device, cap) \
1509 if (has_cap(cap)) {\
1510 get_u8(&u8value, cap);\
1511 data->device = u8value;\
1514 if (interface->type == ACER_WMID) {
1515 save_bool_device(wireless, ACER_CAP_WIRELESS);
1516 save_bool_device(bluetooth, ACER_CAP_BLUETOOTH);
1517 save_bool_device(threeg, ACER_CAP_THREEG);
1518 save_u8_device(brightness, ACER_CAP_BRIGHTNESS);
1521 return 0;
1524 static int acer_platform_resume(struct platform_device *device)
1526 struct acer_data *data = &interface->data;
1528 #define restore_bool_device(device, cap) \
1529 if (has_cap(cap))\
1530 set_bool(data->device, cap);\
1532 restore_bool_device(wireless, ACER_CAP_WIRELESS);
1533 restore_bool_device(bluetooth, ACER_CAP_BLUETOOTH);
1534 restore_bool_device(threeg, ACER_CAP_THREEG);
1535 restore_bool_device(mailled, ACER_CAP_MAILLED);
1537 if (has_cap(ACER_CAP_BRIGHTNESS))
1538 set_brightness((u8)data->brightness);
1540 /* Check if this laptop requires the keyboard quirk */
1541 if (quirks->mmkeys != 0) {
1542 set_keyboard_quirk();
1543 printk(ACER_INFO "Setting keyboard quirk to enable multimedia keys\n");
1546 return 0;
1549 static struct platform_driver acer_platform_driver = {
1550 .driver = {
1551 .name = "acer_acpi",
1552 .owner = THIS_MODULE,
1554 .probe = acer_platform_probe,
1555 .remove = acer_platform_remove,
1556 .suspend = acer_platform_suspend,
1557 .resume = acer_platform_resume,
1560 static struct platform_device *acer_platform_device;
1562 static int remove_sysfs(struct platform_device *device)
1564 #define remove_device_file(value, cap) \
1565 if (has_cap(cap)) \
1566 device_remove_file(&device->dev, &dev_attr_##value);
1568 if (wmi_acer_has_guid(WMID_GUID2)) {
1569 device_remove_file(&device->dev, &dev_attr_devices);
1572 remove_device_file(wireless, ACER_CAP_WIRELESS);
1573 remove_device_file(bluetooth, ACER_CAP_BLUETOOTH);
1574 remove_device_file(threeg, ACER_CAP_THREEG);
1575 remove_device_file(interface, ACER_CAP_ANY);
1576 remove_device_file(fan_temperature_override, ACER_CAP_TEMPERATURE_OVERRIDE);
1577 remove_device_file(touchpad, ACER_CAP_TOUCHPAD_READ);
1578 return 0;
1581 static int create_sysfs(void)
1583 int retval = -ENOMEM;
1585 #define add_device_file(value, cap) \
1586 if (has_cap(cap)) {\
1587 retval = device_create_file(&acer_platform_device->dev, &dev_attr_##value);\
1588 if (retval)\
1589 goto error;\
1592 if (wmi_acer_has_guid(WMID_GUID2)) {
1593 retval = device_create_file(&acer_platform_device->dev, &dev_attr_devices);
1594 if (retval)
1595 goto error;
1598 add_device_file(wireless, ACER_CAP_WIRELESS);
1599 add_device_file(bluetooth, ACER_CAP_BLUETOOTH);
1600 add_device_file(threeg, ACER_CAP_THREEG);
1601 add_device_file(interface, ACER_CAP_ANY);
1602 add_device_file(fan_temperature_override, ACER_CAP_TEMPERATURE_OVERRIDE);
1603 add_device_file(touchpad, ACER_CAP_TOUCHPAD_READ);
1605 return 0;
1607 error:
1608 remove_sysfs(acer_platform_device);
1609 return retval;
1612 static int __init acer_acpi_init(void)
1614 printk(ACER_INFO "Acer Laptop ACPI Extras version %s\n",
1615 ACER_ACPI_VERSION);
1618 * Detect which WMI interface we're using.
1619 * Check for AMW0 first, as later AMW0 laptops also have the WMID GUID.
1621 if (wmi_acer_has_guid(AMW0_GUID1)) {
1622 DEBUG(0, "Detected Acer AMW0 interface\n");
1623 interface = &AMW0_interface;
1624 } else if (wmi_acer_has_guid(WMID_GUID1)) {
1625 DEBUG(0, "Detected Acer WMID interface\n");
1626 interface = &WMID_interface;
1627 } else {
1628 printk(ACER_ERR "No or unsupported WMI interface, unable to load.\n");
1629 return -ENODEV;
1632 /* Find if this laptop requires any quirks */
1633 DEBUG(1, "Finding quirks\n");
1634 find_quirks();
1636 /* Now that we have a known interface, initialize it */
1637 DEBUG(1, "Initialising interface\n");
1638 if (interface->init)
1639 interface->init(interface);
1641 #ifdef CONFIG_PROC
1642 /* Create the proc entries */
1643 acer_proc_dir = proc_mkdir(PROC_ACER, acpi_root_dir);
1644 if (!acer_proc_dir) {
1645 printk(ACER_ERR "Unable to create /proc entries, aborting.\n");
1646 goto error_proc_mkdir;
1649 acer_proc_dir->owner = THIS_MODULE;
1650 if (add_proc_entries()) {
1651 printk(ACER_ERR "Unable to create /proc entries, aborting.\n");
1652 goto error_proc_add;
1654 #endif
1657 * Register the driver
1659 if (platform_driver_register(&acer_platform_driver)) {
1660 printk(ACER_ERR "Unable to register platform driver, aborting.\n");
1661 goto error_platform_register;
1663 acer_platform_device = platform_device_alloc("acer_acpi", -1);
1664 platform_device_add(acer_platform_device);
1666 create_sysfs();
1668 DEBUG(1, "Driver registered\n");
1670 /* Override any initial settings with values from the commandline */
1671 acer_commandline_init();
1673 return 0;
1675 error_platform_register:
1676 #ifdef CONFIG_PROC
1677 remove_proc_entries();
1678 error_proc_add:
1679 if (acer_proc_dir)
1680 remove_proc_entry(PROC_ACER, acpi_root_dir);
1681 error_proc_mkdir:
1682 #endif
1683 return -ENODEV;
1686 static void __exit acer_acpi_exit(void)
1688 remove_sysfs(acer_platform_device);
1689 platform_device_del(acer_platform_device);
1690 platform_driver_unregister(&acer_platform_driver);
1692 #ifdef CONFIG_PROC
1693 remove_proc_entries();
1695 if (acer_proc_dir)
1696 remove_proc_entry(PROC_ACER, acpi_root_dir);
1697 #endif
1698 printk(ACER_INFO "Acer Laptop ACPI Extras unloaded\n");
1699 return;
1702 module_init(acer_acpi_init);
1703 module_exit(acer_acpi_exit);