acer_acpi - Add quirks for Acer Aspire 3610 & 5610
[acer_acpi.git] / acer_acpi.c
blob27913e76a4c59941a2175e7a765d98d6ffb3e8e4
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.11.1"
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 MODULE_AUTHOR("Mark Smith, Carlos Corbacho");
72 MODULE_DESCRIPTION("Acer Laptop ACPI Extras Driver");
73 MODULE_LICENSE("GPL");
75 MODULE_ALIAS("dmi:*:*Acer*:*:");
77 #define ACER_LOGPREFIX "acer_acpi: "
78 #define ACER_ERR KERN_ERR ACER_LOGPREFIX
79 #define ACER_NOTICE KERN_NOTICE ACER_LOGPREFIX
80 #define ACER_INFO KERN_INFO ACER_LOGPREFIX
82 #define DEBUG(level, message...) { \
83 if (debug >= level) \
84 printk(KERN_DEBUG ACER_LOGPREFIX message);\
88 * The maximum temperature one can set for fan control override.
89 * Doesn't propably make much sense if over 80 degrees celsius though...
91 #define ACER_MAX_TEMPERATURE_OVERRIDE 150
94 * The following defines quirks to get some specific functions to work
95 * which are known to not be supported over ACPI (such as the mail LED
96 * on WMID based Acer's)
98 struct acer_quirks {
99 const char *vendor;
100 const char *model;
101 u16 quirks;
105 * Keyboard controller ports
107 #define ACER_KBD_STATUS_REG 0x64 /* Status register (R) */
108 #define ACER_KBD_CNTL_REG 0x64 /* Controller command register (W) */
109 #define ACER_KBD_DATA_REG 0x60 /* Keyboard data register (R/W) */
112 * Magic Number
113 * Meaning is unknown - this number is required for writing to ACPI for AMW0
114 * (it's also used in acerhk when directly accessing the EC)
116 #define ACER_AMW0_WRITE 0x9610
119 * Bit masks for the old AMW0 interface
121 #define ACER_AMW0_WIRELESS_MASK 0x35
122 #define ACER_AMW0_BLUETOOTH_MASK 0x34
123 #define ACER_AMW0_MAILLED_MASK 0x31
126 * Method IDs for new WMID interface
128 #define ACER_WMID_GET_WIRELESS_METHODID 1
129 #define ACER_WMID_GET_BLUETOOTH_METHODID 2
130 #define ACER_WMID_GET_BRIGHTNESS_METHODID 3
131 #define ACER_WMID_SET_WIRELESS_METHODID 4
132 #define ACER_WMID_SET_BLUETOOTH_METHODID 5
133 #define ACER_WMID_SET_BRIGHTNESS_METHODID 6
134 #define ACER_WMID_GET_THREEG_METHODID 10
135 #define ACER_WMID_SET_THREEG_METHODID 11
138 * Acer ACPI method GUIDs
140 #define AMW0_GUID1 "67C3371D-95A3-4C37-BB61-DD47B491DAAB"
141 #define WMID_GUID1 "6AF4F258-B401-42fd-BE91-3D4AC2D7C0D3"
142 #define WMID_GUID2 "95764E09-FB56-4e83-B31A-37761F60994A"
145 * Interface capability flags
147 #define ACER_CAP_MAILLED (1<<0)
148 #define ACER_CAP_WIRELESS (1<<1)
149 #define ACER_CAP_BLUETOOTH (1<<2)
150 #define ACER_CAP_BRIGHTNESS (1<<3)
151 #define ACER_CAP_THREEG (1<<4)
152 #define ACER_CAP_TOUCHPAD_READ (1<<5)
153 #define ACER_CAP_TEMPERATURE_OVERRIDE (1<<6)
154 #define ACER_CAP_ANY (0xFFFFFFFF)
157 * Interface type flags
159 enum interface_flags {
160 ACER_AMW0,
161 ACER_AMW0_V2,
162 ACER_WMID,
166 * Presumed start states -
167 * On some AMW0 laptops, we do not yet know how to get the device status from
168 * the EC, so we must store this ourselves.
170 * Plus, we can't tell which features are enabled or disabled on a specific
171 * model - e.g. The 5020 series can _support_ bluetooth; but the 5021 has no
172 * bluetooth, whilst the 5024 does. However, the BIOS identifies both laptops
173 * as 5020, and you can add bluetooth later.
175 * Basically the code works like this:
176 * - On init, any values specified on the commandline are set.
177 * - For interfaces where the current values cannot be detected and which
178 * have not been set on the commandline, we set them to some sane default
179 * (disabled)
181 * See AMW0_init and acer_commandline_init
184 #define ACER_DEFAULT_WIRELESS 0
185 #define ACER_DEFAULT_BLUETOOTH 0
186 #define ACER_DEFAULT_MAILLED 0
187 #define ACER_DEFAULT_THREEG 0
189 static int max_brightness = 0xF;
191 static int wireless = -1;
192 static int bluetooth = -1;
193 static int mailled = -1;
194 static int brightness = -1;
195 static int threeg = -1;
196 static int fan_temperature_override = -1;
197 static int debug;
198 static int force_series;
200 module_param(mailled, int, 0444);
201 module_param(wireless, int, 0444);
202 module_param(bluetooth, int, 0444);
203 module_param(brightness, int, 0444);
204 module_param(threeg, int, 0444);
205 module_param(force_series, int, 0444);
206 module_param(fan_temperature_override, int, 0444);
207 module_param(debug, int, 0664);
208 MODULE_PARM_DESC(wireless, "Set initial state of Wireless hardware");
209 MODULE_PARM_DESC(bluetooth, "Set initial state of Bluetooth hardware");
210 MODULE_PARM_DESC(mailled, "Set initial state of Mail LED");
211 MODULE_PARM_DESC(brightness, "Set initial LCD backlight brightness");
212 MODULE_PARM_DESC(threeg, "Set initial state of 3G hardware");
213 MODULE_PARM_DESC(fan_temperature_override, "Set initial state of the 'FAN temperature-override'");
214 MODULE_PARM_DESC(debug, "Debugging verbosity level (0=least 2=most)");
215 MODULE_PARM_DESC(force_series, "Force a different laptop series for extra features (5020, 5720 or 2490)");
217 #ifdef CONFIG_PROC
218 struct ProcItem {
219 const char *name;
220 char *(*read_func) (char *, u32);
221 unsigned long (*write_func) (const char *, unsigned long, u32);
222 unsigned int capability;
225 static struct proc_dir_entry *acer_proc_dir;
226 #endif
229 * Wait for the keyboard controller to become ready
231 static int wait_kbd_write(void)
233 int i = 0;
234 while ((inb(ACER_KBD_STATUS_REG) & 0x02) && (i < 10000)) {
235 udelay(50);
236 i++;
238 return -(i == 10000);
241 static void send_kbd_cmd(u8 cmd, u8 val)
243 preempt_disable();
244 if (!wait_kbd_write())
245 outb(cmd, ACER_KBD_CNTL_REG);
246 if (!wait_kbd_write())
247 outb(val, ACER_KBD_DATA_REG);
248 preempt_enable_no_resched();
251 static void set_keyboard_quirk(void)
253 send_kbd_cmd(0x59, 0x90);
256 struct acer_data {
257 int mailled;
258 int wireless;
259 int bluetooth;
260 int threeg;
261 int brightness;
264 /* Each low-level interface must define at least some of the following */
265 struct Interface {
266 u32 type; /* WMI device type */
267 u32 capability; /* The capabilities this interface provides */
268 struct acer_data data; /* Private data for interface */
271 /* The static interface pointer, points to the currently detected interface */
272 static struct Interface *interface;
275 * Embedded Controller quirks
276 * Some laptops require us to directly access the EC to either enable or query
277 * features that are not available through ACPI.
280 struct quirk_entry {
281 u8 wireless;
282 u8 mailled;
283 u8 brightness;
284 u8 touchpad;
285 u8 temperature_override;
286 u8 mmkeys;
287 u8 bluetooth;
290 static struct quirk_entry *quirks;
292 static void set_quirks(void)
294 if (quirks->mailled != 0) {
295 interface->capability |= ACER_CAP_MAILLED;
296 DEBUG(1, "Using EC direct-access quirk for mail LED\n");
299 if (quirks->touchpad != 0) {
300 interface->capability |= ACER_CAP_TOUCHPAD_READ;
301 DEBUG(1, "Using EC direct-access quirk for reading touchpad status\n");
304 if (quirks->temperature_override != 0) {
305 interface->capability |= ACER_CAP_TEMPERATURE_OVERRIDE;
306 DEBUG(1, "Using EC direct-access quirk for temperature override setting (fan)\n");
309 if (quirks->brightness != 0) {
310 interface->capability |= ACER_CAP_BRIGHTNESS;
311 DEBUG(1, "Using EC direct-access quirk for backlight brightness\n");
314 if (quirks->mmkeys != 0) {
315 set_keyboard_quirk();
316 printk(ACER_INFO "Setting keyboard quirk to enable multimedia keys\n");
319 if (quirks->bluetooth != 0) {
320 interface->capability |= ACER_CAP_BLUETOOTH;
321 DEBUG(1, "Using EC direct-access quirk for bluetooth\n");
324 if (quirks->wireless != 0) {
325 interface->capability |= ACER_CAP_WIRELESS;
326 DEBUG(1, "Using EC direct-access quirk for wireless\n");
330 #if LINUX_VERSION_CODE >= KERNEL_VERSION(2,6,24)
331 static int dmi_matched(const struct dmi_system_id *dmi)
332 #else
333 static int dmi_matched(struct dmi_system_id *dmi)
334 #endif
336 quirks = dmi->driver_data;
337 return 0;
340 static struct quirk_entry quirk_unknown = {
343 /* Same Mail LED quirk as TM2490, but does not require keyboard quirk */
344 static struct quirk_entry quirk_acer_aspire_5100 = {
345 .mailled = 1,
348 static struct quirk_entry quirk_acer_travelmate_2490 = {
349 .mmkeys = 1,
350 .mailled = 1,
351 .temperature_override = 1,
352 .touchpad = 1,
355 static struct quirk_entry quirk_acer_travelmate_5720 = {
356 .touchpad = 2,
359 static struct quirk_entry quirk_medion_md_98300 = {
360 .wireless = 1,
363 static struct dmi_system_id acer_quirks[] = {
365 .callback = dmi_matched,
366 .ident = "Acer Aspire 3100",
367 .matches = {
368 DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
369 DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 3100"),
371 .driver_data = &quirk_acer_aspire_5100,
374 .callback = dmi_matched,
375 .ident = "Acer Aspire 3610",
376 .matches = {
377 DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
378 DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 3610"),
380 .driver_data = &quirk_acer_travelmate_2490,
383 .callback = dmi_matched,
384 .ident = "Acer Aspire 5100",
385 .matches = {
386 DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
387 DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5100"),
389 .driver_data = &quirk_acer_aspire_5100,
392 .callback = dmi_matched,
393 .ident = "Acer Aspire 5610",
394 .matches = {
395 DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
396 DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5610"),
398 .driver_data = &quirk_acer_travelmate_2490,
401 .callback = dmi_matched,
402 .ident = "Acer Aspire 5630",
403 .matches = {
404 DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
405 DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5630"),
407 .driver_data = &quirk_acer_travelmate_2490,
410 .callback = dmi_matched,
411 .ident = "Acer Aspire 5650",
412 .matches = {
413 DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
414 DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5650"),
416 .driver_data = &quirk_acer_travelmate_2490,
419 .callback = dmi_matched,
420 .ident = "Acer Aspire 5680",
421 .matches = {
422 DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
423 DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5680"),
425 .driver_data = &quirk_acer_travelmate_2490,
428 .callback = dmi_matched,
429 .ident = "Acer Aspire 9110",
430 .matches = {
431 DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
432 DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 9110"),
434 .driver_data = &quirk_acer_travelmate_2490,
437 .callback = dmi_matched,
438 .ident = "Acer Extensa 5220",
439 .matches = {
440 DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
441 DMI_MATCH(DMI_PRODUCT_NAME, "Extensa 5220"),
443 .driver_data = &quirk_acer_travelmate_5720,
446 .callback = dmi_matched,
447 .ident = "Acer TravelMate 2490",
448 .matches = {
449 DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
450 DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 2490"),
452 .driver_data = &quirk_acer_travelmate_2490,
455 .callback = dmi_matched,
456 .ident = "Acer TravelMate 4200",
457 .matches = {
458 DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
459 DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 4200"),
461 .driver_data = &quirk_acer_travelmate_2490,
464 .callback = dmi_matched,
465 .ident = "Acer TravelMate 5720",
466 .matches = {
467 DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
468 DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 5720"),
470 .driver_data = &quirk_acer_travelmate_5720,
473 .callback = dmi_matched,
474 .ident = "Medion MD 98300",
475 .matches = {
476 DMI_MATCH(DMI_SYS_VENDOR, "MEDION"),
477 DMI_MATCH(DMI_PRODUCT_NAME, "WAM2030"),
479 .driver_data = &quirk_medion_md_98300,
484 /* Find which quirks are needed for a particular vendor/ model pair */
485 static void find_quirks(void)
487 DEBUG(1, "Looking for quirks\n");
488 if (!force_series) {
489 dmi_check_system(acer_quirks);
490 } else if (force_series == 2490) {
491 DEBUG(0, "Forcing Acer TravelMate 2490\n");
492 quirks = &quirk_acer_travelmate_2490;
495 if (quirks == NULL) {
496 DEBUG(1, "No quirks known for this laptop\n");
497 quirks = &quirk_unknown;
499 set_quirks();
503 * General interface convenience methods
506 static bool has_cap(u32 cap)
508 if ((interface->capability & cap) != 0)
509 return 1;
510 return 0;
514 * Old interface (now known as the AMW0 interface)
516 struct WMAB_args {
517 u32 eax;
518 u32 ebx;
519 u32 ecx;
520 u32 edx;
523 struct WMAB_ret {
524 u32 eax;
525 u32 ebx;
526 u32 ecx;
527 u32 edx;
528 u32 eex;
531 static acpi_status WMAB_execute(struct WMAB_args *regbuf, struct acpi_buffer *result)
533 struct acpi_buffer input;
534 acpi_status status;
535 input.length = sizeof(struct WMAB_args);
536 input.pointer = (u8 *) regbuf;
538 status = wmi_acer_evaluate_method(AMW0_GUID1, 1, 1, &input, result);
539 DEBUG(2, " Args: 0x%08x 0x%08x 0x%08x 0x%08x\n", regbuf->eax, regbuf->ebx, regbuf->ecx, regbuf->edx );
541 return status;
544 static acpi_status AMW0_get_u32(u32 *value, u32 cap, struct Interface *iface)
546 u8 result;
548 DEBUG(2, " AMW0_get_u32: cap=%d\n", cap);
549 switch (cap) {
550 case ACER_CAP_MAILLED:
551 switch (quirks->mailled) {
552 default:
553 ec_read(0x0A, &result);
554 *value = (result >> 7) & 0x01;
555 return 0;
557 break;
558 case ACER_CAP_WIRELESS:
559 switch (quirks->wireless) {
560 case 1:
561 ec_read(0x7B, &result);
562 *value = result & 0x01;
563 return 0;
564 default:
565 ec_read(0x0A, &result);
566 *value = (result >> 2) & 0x01;
567 return 0;
569 break;
570 case ACER_CAP_BLUETOOTH:
571 switch (quirks->bluetooth) {
572 default:
573 ec_read(0x0A, &result);
574 *value = (result >> 4) & 0x01;
575 return 0;
577 break;
578 case ACER_CAP_BRIGHTNESS:
579 switch (quirks->brightness) {
580 default:
581 ec_read(0x83, &result);
582 *value = result;
583 return 0;
585 break;
586 default:
587 return AE_BAD_ADDRESS;
589 return AE_OK;
592 static acpi_status AMW0_set_u32(u32 value, u32 cap, struct Interface *iface)
594 struct WMAB_args args;
596 args.eax = ACER_AMW0_WRITE;
597 args.ebx = value ? (1<<8) : 0;
598 args.ecx = args.edx = 0;
600 switch (cap) {
601 case ACER_CAP_MAILLED:
602 if (value > 1)
603 return AE_BAD_PARAMETER;
604 args.ebx |= ACER_AMW0_MAILLED_MASK;
605 break;
606 case ACER_CAP_WIRELESS:
607 if (value > 1)
608 return AE_BAD_PARAMETER;
609 args.ebx |= ACER_AMW0_WIRELESS_MASK;
610 break;
611 case ACER_CAP_BLUETOOTH:
612 if (value > 1)
613 return AE_BAD_PARAMETER;
614 args.ebx |= ACER_AMW0_BLUETOOTH_MASK;
615 break;
616 case ACER_CAP_BRIGHTNESS:
617 if (value > max_brightness)
618 return AE_BAD_PARAMETER;
619 switch (quirks->brightness) {
620 default:
621 return ec_write(0x83, value);
622 break;
624 default:
625 return AE_BAD_ADDRESS;
628 /* Actually do the set */
629 return WMAB_execute(&args, NULL);
632 static acpi_status AMW0_find_mailled(void)
634 struct WMAB_args args;
635 struct WMAB_ret ret;
636 acpi_status status = AE_OK;
637 struct acpi_buffer out = { ACPI_ALLOCATE_BUFFER, NULL };
638 union acpi_object *obj;
640 args.eax = 0x0086;
641 args.ebx = args.ecx = args.edx = 0;
643 status = WMAB_execute(&args, &out);
644 if (ACPI_FAILURE(status))
645 return status;
647 obj = (union acpi_object *) out.pointer;
648 if (obj && obj->type == ACPI_TYPE_BUFFER &&
649 obj->buffer.length == sizeof(struct WMAB_ret)) {
650 ret = *((struct WMAB_ret *) obj->buffer.pointer);
651 } else {
652 return AE_ERROR;
655 if (ret.eex & 0x1) {
656 interface->capability |= ACER_CAP_MAILLED;
657 DEBUG(1, "Mail LED available - enabling\n");
660 return AE_OK;
663 static acpi_status AMW0_set_capabilities(void) {
664 struct WMAB_args args;
665 struct WMAB_ret ret;
666 acpi_status status = AE_OK;
667 struct acpi_buffer out = { ACPI_ALLOCATE_BUFFER, NULL };
668 union acpi_object *obj;
670 args.eax = ACER_AMW0_WRITE;
671 args.ecx = args.edx = 0;
673 args.ebx = 0xa2 << 8;
674 args.ebx |= ACER_AMW0_WIRELESS_MASK;
676 status = WMAB_execute(&args, &out);
677 if (ACPI_FAILURE(status)) {
678 printk(ACER_INFO "Problem with wireless path\n");
679 return status;
682 obj = (union acpi_object *) out.pointer;
683 if (obj && obj->type == ACPI_TYPE_BUFFER &&
684 obj->buffer.length == sizeof(struct WMAB_ret)) {
685 ret = *((struct WMAB_ret *) obj->buffer.pointer);
686 } else {
687 return AE_ERROR;
690 if (ret.eax & 0x1) {
691 interface->capability |= ACER_CAP_WIRELESS;
692 DEBUG(1, "Wireless hardware available - enabling\n");
695 args.ebx = 2 << 8;
696 args.ebx |= ACER_AMW0_BLUETOOTH_MASK;
698 status = WMAB_execute(&args, &out);
699 if (ACPI_FAILURE(status))
700 return status;
702 obj = (union acpi_object *) out.pointer;
703 if (obj && obj->type == ACPI_TYPE_BUFFER
704 && obj->buffer.length == sizeof(struct WMAB_ret)) {
705 ret = *((struct WMAB_ret *) obj->buffer.pointer);
706 } else {
707 return AE_ERROR;
710 if (ret.eax & 0x1) {
711 interface->capability |= ACER_CAP_BLUETOOTH;
712 DEBUG(1, "Bluetooth hardware available - enabling\n");
716 * This appears to be safe to enable, since all Wistron based laptops
717 * appear to use the same EC register for brightness, even if they
718 * differ for wireless, etc
720 interface->capability |= ACER_CAP_BRIGHTNESS;
722 return AE_OK;
725 static struct Interface AMW0_interface = {
726 .type = ACER_AMW0,
729 static struct Interface AMW0_V2_interface = {
730 .type = ACER_AMW0_V2,
731 .capability = (
732 ACER_CAP_BRIGHTNESS
737 * New interface (The WMID interface)
739 static acpi_status
740 WMI_execute_u32(u32 method_id, u32 in, u32 *out)
742 struct acpi_buffer input = { (acpi_size) sizeof(u32), (void *)(&in) };
743 struct acpi_buffer result = { ACPI_ALLOCATE_BUFFER, NULL };
744 union acpi_object *obj;
745 u32 tmp;
746 acpi_status status;
748 DEBUG(2, " WMI_execute_u32:\n");
749 status = wmi_acer_evaluate_method(WMID_GUID1, 1, method_id, &input, &result);
750 DEBUG(2, " In: 0x%08x\n", in);
752 if (ACPI_FAILURE(status))
753 return status;
755 obj = (union acpi_object *) result.pointer;
756 if (obj && obj->type == ACPI_TYPE_BUFFER && obj->buffer.length == sizeof(u32)) {
757 tmp = *((u32 *) obj->buffer.pointer);
758 DEBUG(2, " Out: 0x%08x\n", tmp);
759 } else {
760 tmp = 0;
761 if (obj) {
762 DEBUG(2, " Got unexpected result of type %d\n", obj->type);
763 } else {
764 DEBUG(2, " Got unexpected null result\n");
768 if (out)
769 *out = tmp;
771 if (result.length > 0 && result.pointer)
772 kfree(result.pointer);
774 DEBUG(2, " Returning from WMI_execute_u32:\n");
775 return status;
778 static acpi_status WMID_get_u32(u32 *value, u32 cap, struct Interface *iface)
780 acpi_status status;
781 u8 tmp;
782 u32 result, method_id = 0;
784 DEBUG(2, " WMID_get_u32: cap=%d\n", cap);
785 switch (cap) {
786 case ACER_CAP_WIRELESS:
787 method_id = ACER_WMID_GET_WIRELESS_METHODID;
788 break;
789 case ACER_CAP_BLUETOOTH:
790 method_id = ACER_WMID_GET_BLUETOOTH_METHODID;
791 break;
792 case ACER_CAP_BRIGHTNESS:
793 method_id = ACER_WMID_GET_BRIGHTNESS_METHODID;
794 break;
795 case ACER_CAP_THREEG:
796 method_id = ACER_WMID_GET_THREEG_METHODID;
797 break;
798 case ACER_CAP_MAILLED:
799 if (quirks->mailled == 1) {
800 ec_read(0x9f, &tmp);
801 *value = tmp & 0x01;
802 return 0;
804 case ACER_CAP_TOUCHPAD_READ:
805 switch (quirks->touchpad) {
806 case 1:
807 ec_read(0x9e, &tmp);
808 *value = 1 - ((tmp >> 3) & 0x01);
809 return 0;
810 case 2:
811 ec_read(0x74, &tmp);
812 *value = ((tmp >> 3) & 0x01);
813 return 0;
814 default:
815 break;
817 case ACER_CAP_TEMPERATURE_OVERRIDE:
818 if (quirks->temperature_override == 1) {
819 ec_read(0xa9, &tmp);
820 *value = tmp;
821 return 0;
823 default:
824 return AE_BAD_ADDRESS;
826 status = WMI_execute_u32(method_id, 0, &result);
827 DEBUG(2, " WMI_execute_u32 status=%d:\n", status);
829 if (ACPI_SUCCESS(status))
830 *value = (u8)result;
832 DEBUG(2, " Returning from WMID_get_u32:\n");
833 return status;
836 static acpi_status WMID_set_u32(u32 value, u32 cap, struct Interface *iface)
838 u32 method_id = 0;
840 switch (cap) {
841 case ACER_CAP_BRIGHTNESS:
842 if (value > max_brightness)
843 return AE_BAD_PARAMETER;
844 method_id = ACER_WMID_SET_BRIGHTNESS_METHODID;
845 break;
846 case ACER_CAP_WIRELESS:
847 if (value > 1)
848 return AE_BAD_PARAMETER;
849 method_id = ACER_WMID_SET_WIRELESS_METHODID;
850 break;
851 case ACER_CAP_BLUETOOTH:
852 if (value > 1)
853 return AE_BAD_PARAMETER;
854 method_id = ACER_WMID_SET_BLUETOOTH_METHODID;
855 break;
856 case ACER_CAP_THREEG:
857 if (value > 1)
858 return AE_BAD_PARAMETER;
859 method_id = ACER_WMID_SET_THREEG_METHODID;
860 break;
861 case ACER_CAP_MAILLED:
862 if (value > 1)
863 return AE_BAD_PARAMETER;
864 if (quirks->mailled == 1) {
865 send_kbd_cmd(0x59, value ? 0x92 : 0x93);
866 return 0;
868 break;
869 case ACER_CAP_TEMPERATURE_OVERRIDE:
870 if (value > ACER_MAX_TEMPERATURE_OVERRIDE)
871 return AE_BAD_PARAMETER;
873 if (quirks->temperature_override == 1) {
874 ec_write(0xa9, value);
875 return 0;
877 default:
878 return AE_BAD_ADDRESS;
880 return WMI_execute_u32(method_id, (u32)value, NULL);
883 static acpi_status WMID_set_capabilities(void) {
884 struct acpi_buffer out = {ACPI_ALLOCATE_BUFFER, NULL};
885 union acpi_object *obj;
886 acpi_status status;
887 u32 devices;
889 status = wmi_acer_query_block(WMID_GUID2, 1, &out);
890 if (ACPI_FAILURE(status))
891 return status;
893 obj = (union acpi_object *) out.pointer;
894 if (obj && obj->type == ACPI_TYPE_BUFFER && obj->buffer.length == sizeof(u32)) {
895 devices = *((u32 *) obj->buffer.pointer);
896 } else {
897 return AE_ERROR;
900 /* Not sure on the meaning of the relevant bits yet */
901 interface->capability |= ACER_CAP_WIRELESS;
902 interface->capability |= ACER_CAP_THREEG;
904 if (devices & 0x10) {
905 DEBUG(1, "Bluetooth hardware available - enabling\n");
906 interface->capability |= ACER_CAP_BLUETOOTH;
909 if (!(devices & 0x20)) {
910 DEBUG(1, "Maximum brightness quirk detected - enabling\n");
911 max_brightness = 0x9;
914 return status;
918 static struct Interface WMID_interface = {
919 .type = ACER_WMID,
920 .capability = ACER_CAP_BRIGHTNESS,
923 #ifdef CONFIG_PROC
925 * High-level Procfs file handlers
928 static int
929 dispatch_read(char *page, char **start, off_t off, int count, int *eof,
930 struct ProcItem *item)
932 char *p = page;
933 int len;
935 DEBUG(2, " dispatch_read: \n");
936 if (off == 0)
937 p = item->read_func(p, item->capability);
938 len = (p - page);
939 if (len <= off + count)
940 *eof = 1;
941 *start = page + off;
942 len -= off;
943 if (len > count)
944 len = count;
945 if (len < 0)
946 len = 0;
947 return len;
950 static int
951 dispatch_write(struct file *file, const char __user *buffer,
952 unsigned long count, struct ProcItem *item)
954 int result;
955 char *tmp_buffer;
958 * Arg buffer points to userspace memory, which can't be accessed
959 * directly. Since we're making a copy, zero-terminate the
960 * destination so that sscanf can be used on it safely.
962 tmp_buffer = kmalloc(count + 1, GFP_KERNEL);
963 if (copy_from_user(tmp_buffer, buffer, count)) {
964 result = -EFAULT;
965 } else {
966 tmp_buffer[count] = 0;
967 result = item->write_func(tmp_buffer, count, item->capability);
969 kfree(tmp_buffer);
970 return result;
972 #endif
975 * Generic Device (interface-independent)
977 static acpi_status get_u32(u32 *value, u32 cap)
979 DEBUG(2, " get_u32: cap=%u, value=%u\n", cap, *value);
981 if (!(interface->capability & cap))
982 return AE_BAD_PARAMETER;
984 switch (interface->type) {
985 case ACER_AMW0:
986 return AMW0_get_u32(value, cap, interface);
987 case ACER_AMW0_V2:
988 if (cap == ACER_CAP_MAILLED)
989 return AMW0_get_u32(value, cap, interface);
990 case ACER_WMID:
991 return WMID_get_u32(value, cap, interface);
992 default:
993 return AE_BAD_PARAMETER;
997 static acpi_status set_u32(u32 value, u32 cap)
999 acpi_status status;
1001 DEBUG(2, " set_u32: cap=%u, value=%u\n", cap, value);
1003 if (!(interface->capability & cap))
1004 return AE_BAD_PARAMETER;
1006 switch (interface->type) {
1007 case ACER_AMW0:
1008 return AMW0_set_u32(value, cap, interface);
1009 case ACER_AMW0_V2:
1010 if (cap == ACER_CAP_MAILLED)
1011 return AMW0_set_u32(value, cap, interface);
1014 * On some models, some WMID methods don't toggle properly.
1015 * For those cases, we want to run the AMW0 method afterwards
1016 * to be certain we've really toggled the device state.
1018 if (cap == ACER_CAP_WIRELESS || cap == ACER_CAP_BLUETOOTH) {
1019 status = WMID_set_u32(value, cap, interface);
1020 if (ACPI_FAILURE(status))
1021 return status;
1023 return AMW0_set_u32(value, cap, interface);
1025 case ACER_WMID:
1026 return WMID_set_u32(value, cap, interface);
1027 default:
1028 return AE_BAD_PARAMETER;
1032 static void __init acer_commandline_init(void)
1034 DEBUG(1, "Commandline args: mailled(%d) wireless(%d) bluetooth(%d) brightness(%d)\n",
1035 mailled, wireless, bluetooth, brightness);
1038 * These will all fail silently if the value given is invalid, or the
1039 * capability isn't available on the given interface
1041 set_u32(mailled, ACER_CAP_MAILLED);
1042 set_u32(wireless, ACER_CAP_WIRELESS);
1043 set_u32(bluetooth, ACER_CAP_BLUETOOTH);
1044 set_u32(threeg, ACER_CAP_THREEG);
1045 set_u32(fan_temperature_override, ACER_CAP_TEMPERATURE_OVERRIDE);
1046 set_u32(brightness, ACER_CAP_BRIGHTNESS);
1049 #ifdef CONFIG_PROC
1051 * Procfs interface (deprecated)
1053 static char *read_u32(char *p, u32 cap)
1055 u32 result;
1056 acpi_status status;
1058 DEBUG(2, " read_u32: cap=%d\n", cap);
1059 status = get_u32(&result, cap);
1060 if (ACPI_SUCCESS(status))
1061 p += sprintf(p, "%u\n", result);
1062 else
1063 p += sprintf(p, "Read error\n");
1064 return p;
1067 static unsigned long write_u32(const char *buffer, unsigned long count, u32 cap)
1069 u32 value;
1071 if (sscanf(buffer, "%u", &value) == 1) {
1072 acpi_status status = set_u32(value, cap);
1073 if (ACPI_FAILURE(status))
1074 return -EINVAL;
1075 } else {
1076 return -EINVAL;
1078 return count;
1081 static char *read_version(char *p, u32 cap)
1083 p += sprintf(p, "%s\n", ACER_ACPI_VERSION);
1084 return p;
1087 static char *read_interface(char *p, u32 cap)
1089 switch (interface->type) {
1090 case ACER_AMW0:
1091 p += sprintf(p, "AMW0\n");
1092 break;
1093 case ACER_AMW0_V2:
1094 p += sprintf(p, "AMW0 v2\n");
1095 break;
1096 case ACER_WMID:
1097 p += sprintf(p, "WMID\n");
1098 break;
1099 default:
1100 p += sprintf(p, "Error!\n");
1101 break;
1103 return p;
1106 static struct ProcItem proc_items[] = {
1107 {"mailled", read_u32, write_u32, ACER_CAP_MAILLED},
1108 {"bluetooth", read_u32, write_u32, ACER_CAP_BLUETOOTH},
1109 {"wireless", read_u32, write_u32, ACER_CAP_WIRELESS},
1110 {"brightness", read_u32, write_u32, ACER_CAP_BRIGHTNESS},
1111 {"threeg", read_u32, write_u32, ACER_CAP_THREEG},
1112 {"touchpad", read_u32, NULL, ACER_CAP_TOUCHPAD_READ},
1113 {"fan_temperature_override", read_u32, write_u32, ACER_CAP_TEMPERATURE_OVERRIDE},
1114 {"version", read_version, NULL, ACER_CAP_ANY},
1115 {"interface", read_interface, NULL, ACER_CAP_ANY},
1116 {NULL}
1119 static int __init add_proc_entries(void)
1121 struct proc_dir_entry *proc;
1122 struct ProcItem *item;
1124 for (item = proc_items; item->name; ++item) {
1126 * Only add the proc file if the current interface actually
1127 * supports it
1129 if (interface->capability & item->capability) {
1130 proc = create_proc_read_entry(item->name,
1131 S_IFREG | S_IRUGO | S_IWUSR,
1132 acer_proc_dir,
1133 (read_proc_t *) dispatch_read,
1134 item);
1135 if (proc)
1136 proc->owner = THIS_MODULE;
1137 if (proc && item->write_func)
1138 proc->write_proc = (write_proc_t *) dispatch_write;
1142 return 0;
1145 static int __exit remove_proc_entries(void)
1147 struct ProcItem *item;
1149 for (item = proc_items; item->name; ++item)
1150 remove_proc_entry(item->name, acer_proc_dir);
1151 return 0;
1153 #endif
1156 * LED device (Mail LED only, no other LEDs known yet)
1158 static void mail_led_set(struct led_classdev *led_cdev, enum led_brightness value)
1160 u32 tmp = value;
1161 set_u32(tmp, ACER_CAP_MAILLED);
1164 static struct led_classdev mail_led = {
1165 .name = "acer_acpi:mail",
1166 .brightness_set = mail_led_set,
1169 static void acer_led_init(struct device *dev)
1171 led_classdev_register(dev, &mail_led);
1174 static void acer_led_exit(void)
1176 led_classdev_unregister(&mail_led);
1179 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,18)
1181 * Backlight device
1183 static struct backlight_device *acer_backlight_device;
1185 static int read_brightness(struct backlight_device *bd)
1187 u32 value;
1188 get_u32(&value, ACER_CAP_BRIGHTNESS);
1189 return value;
1192 #if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,20)
1193 static int update_bl_status(struct backlight_device *bd)
1195 set_u32(bd->props->brightness, ACER_CAP_BRIGHTNESS);
1196 return 0;
1199 static struct backlight_properties acer_backlight_properties = {
1200 .get_brightness = read_brightness,
1201 .update_status = update_bl_status,
1204 static int __init acer_backlight_init(struct device *dev)
1206 struct backlight_device *bd;
1208 DEBUG(1, "Loading backlight driver\n");
1209 bd = backlight_device_register("acer_acpi", dev, NULL, &acer_backlight_properties);
1210 if (IS_ERR(bd)) {
1211 printk(ACER_ERR "Could not register Acer backlight device\n");
1212 acer_backlight_device = NULL;
1213 return PTR_ERR(bd);
1216 acer_backlight_device = bd;
1218 bd->props->max_brightness = max_brightness;
1219 return 0;
1221 #else
1222 static int update_bl_status(struct backlight_device *bd)
1224 set_u32(bd->props.brightness, ACER_CAP_BRIGHTNESS);
1225 return 0;
1228 static struct backlight_ops acer_backlight_ops = {
1229 .get_brightness = read_brightness,
1230 .update_status = update_bl_status,
1233 static int __init acer_backlight_init(struct device *dev)
1235 struct backlight_device *bd;
1237 DEBUG(1, "Loading backlight driver\n");
1238 bd = backlight_device_register("acer_acpi", dev, NULL, &acer_backlight_ops);
1239 if (IS_ERR(bd)) {
1240 printk(ACER_ERR "Could not register Acer backlight device\n");
1241 acer_backlight_device = NULL;
1242 return PTR_ERR(bd);
1245 acer_backlight_device = bd;
1247 bd->props.max_brightness = max_brightness;
1248 bd->props.brightness = read_brightness(NULL);
1249 backlight_update_status(bd);
1250 return 0;
1252 #endif
1254 static void __exit acer_backlight_exit(void)
1256 backlight_device_unregister(acer_backlight_device);
1258 #endif
1261 * Read/ write bool sysfs macro
1263 #define show_set_bool(value, cap) \
1264 static ssize_t \
1265 show_bool_##value(struct device *dev, struct device_attribute *attr, \
1266 char *buf) \
1268 u32 result; \
1269 acpi_status status = get_u32(&result, cap); \
1270 if (ACPI_SUCCESS(status)) \
1271 return sprintf(buf, "%u\n", result); \
1272 return sprintf(buf, "Read error\n"); \
1275 static ssize_t \
1276 set_bool_##value(struct device *dev, struct device_attribute *attr, \
1277 const char *buf, size_t count) \
1279 u32 tmp = simple_strtoul(buf, NULL, 10); \
1280 acpi_status status = set_u32(tmp, cap); \
1281 if (ACPI_FAILURE(status)) \
1282 return -EINVAL; \
1283 return count; \
1285 static DEVICE_ATTR(value, S_IWUGO | S_IRUGO | S_IWUSR, \
1286 show_bool_##value, set_bool_##value);
1288 show_set_bool(wireless, ACER_CAP_WIRELESS);
1289 show_set_bool(bluetooth, ACER_CAP_BLUETOOTH);
1290 show_set_bool(threeg, ACER_CAP_THREEG);
1291 show_set_bool(fan_temperature_override, ACER_CAP_TEMPERATURE_OVERRIDE);
1294 * Read-only bool sysfs macro
1296 #define show_bool(value, cap) \
1297 static ssize_t \
1298 show_bool_##value(struct device *dev, struct device_attribute *attr, \
1299 char *buf) \
1301 u32 result; \
1302 acpi_status status = get_u32(&result, cap); \
1303 if (ACPI_SUCCESS(status)) \
1304 return sprintf(buf, "%u\n", result); \
1305 return sprintf(buf, "Read error\n"); \
1307 static DEVICE_ATTR(value, S_IWUGO | S_IRUGO | S_IWUSR, \
1308 show_bool_##value, NULL);
1310 show_bool(touchpad, ACER_CAP_TOUCHPAD_READ);
1313 * Read interface sysfs macro
1315 static ssize_t show_interface(struct device *dev, struct device_attribute *attr,
1316 char *buf)
1318 switch (interface->type) {
1319 case ACER_AMW0:
1320 return sprintf(buf, "AMW0\n");
1321 case ACER_AMW0_V2:
1322 return sprintf(buf, "AMW0 v2\n");
1323 case ACER_WMID:
1324 return sprintf(buf, "WMID\n");
1325 default:
1326 return sprintf(buf, "Error!\n");
1330 static DEVICE_ATTR(interface, S_IWUGO | S_IRUGO | S_IWUSR, show_interface, NULL);
1332 static ssize_t show_devices(struct device *dev, struct device_attribute *attr,
1333 char *buf)
1335 struct acpi_buffer out = {ACPI_ALLOCATE_BUFFER, NULL};
1336 union acpi_object *obj;
1337 acpi_status status;
1338 u32 tmp;
1340 status = wmi_acer_query_block(WMID_GUID2, 1, &out);
1341 if (ACPI_FAILURE(status))
1342 return sprintf(buf, "Error\n");
1344 obj = (union acpi_object *) out.pointer;
1345 if (obj && obj->type == ACPI_TYPE_BUFFER && obj->buffer.length == sizeof(u32)) {
1346 tmp = *((u32 *) obj->buffer.pointer);
1347 } else {
1348 return sprintf(buf, "Error\n");
1351 return sprintf(buf, "%u\n", tmp);
1354 static DEVICE_ATTR(devices, S_IWUGO | S_IRUGO | S_IWUSR, show_devices, NULL);
1357 * Platform device
1359 static int __devinit acer_platform_probe(struct platform_device *device)
1361 if (has_cap(ACER_CAP_MAILLED))
1362 acer_led_init(&device->dev);
1363 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,18)
1364 if (has_cap(ACER_CAP_BRIGHTNESS))
1365 acer_backlight_init(&device->dev);
1366 #endif
1367 return 0;
1370 static int acer_platform_remove(struct platform_device *device)
1372 if (has_cap(ACER_CAP_MAILLED))
1373 acer_led_exit();
1374 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,18)
1375 if (has_cap(ACER_CAP_BRIGHTNESS))
1376 acer_backlight_exit();
1377 #endif
1378 return 0;
1381 static int acer_platform_suspend(struct platform_device *device, pm_message_t state)
1384 * WMID fix for suspend-to-disk - save all current states now so we can
1385 * restore them on resume
1387 u32 value;
1388 struct acer_data *data = &interface->data;
1390 #define save_device(device, cap) \
1391 if (has_cap(cap)) {\
1392 get_u32(&value, cap);\
1393 data->device = value;\
1396 save_device(wireless, ACER_CAP_WIRELESS);
1397 save_device(bluetooth, ACER_CAP_BLUETOOTH);
1398 save_device(threeg, ACER_CAP_THREEG);
1399 save_device(mailled, ACER_CAP_MAILLED);
1400 save_device(brightness, ACER_CAP_BRIGHTNESS);
1402 return 0;
1405 static int acer_platform_resume(struct platform_device *device)
1407 struct acer_data *data = &interface->data;
1409 #define restore_bool_device(device, cap) \
1410 if (has_cap(cap))\
1411 set_u32(data->device, cap);\
1413 restore_bool_device(wireless, ACER_CAP_WIRELESS);
1414 restore_bool_device(bluetooth, ACER_CAP_BLUETOOTH);
1415 restore_bool_device(threeg, ACER_CAP_THREEG);
1416 restore_bool_device(mailled, ACER_CAP_MAILLED);
1417 restore_bool_device(brightness, ACER_CAP_BRIGHTNESS);
1419 /* Check if this laptop requires the keyboard quirk */
1420 if (quirks->mmkeys != 0) {
1421 set_keyboard_quirk();
1422 printk(ACER_INFO "Setting keyboard quirk to enable multimedia keys\n");
1425 return 0;
1428 static struct platform_driver acer_platform_driver = {
1429 .driver = {
1430 .name = "acer_acpi",
1431 .owner = THIS_MODULE,
1433 .probe = acer_platform_probe,
1434 .remove = acer_platform_remove,
1435 .suspend = acer_platform_suspend,
1436 .resume = acer_platform_resume,
1439 static struct platform_device *acer_platform_device;
1441 static int remove_sysfs(struct platform_device *device)
1443 #define remove_device_file(value, cap) \
1444 if (has_cap(cap)) \
1445 device_remove_file(&device->dev, &dev_attr_##value);
1447 if (wmi_acer_has_guid(WMID_GUID2))
1448 device_remove_file(&device->dev, &dev_attr_devices);
1450 remove_device_file(wireless, ACER_CAP_WIRELESS);
1451 remove_device_file(bluetooth, ACER_CAP_BLUETOOTH);
1452 remove_device_file(threeg, ACER_CAP_THREEG);
1453 remove_device_file(interface, ACER_CAP_ANY);
1454 remove_device_file(fan_temperature_override, ACER_CAP_TEMPERATURE_OVERRIDE);
1455 remove_device_file(touchpad, ACER_CAP_TOUCHPAD_READ);
1456 return 0;
1459 static int create_sysfs(void)
1461 int retval = -ENOMEM;
1463 #define add_device_file(value, cap) \
1464 if (has_cap(cap)) {\
1465 retval = device_create_file(&acer_platform_device->dev, &dev_attr_##value);\
1466 if (retval)\
1467 goto error;\
1470 if (wmi_acer_has_guid(WMID_GUID2)) {
1471 retval = device_create_file(&acer_platform_device->dev, &dev_attr_devices);
1472 if (retval)
1473 goto error;
1476 add_device_file(wireless, ACER_CAP_WIRELESS);
1477 add_device_file(bluetooth, ACER_CAP_BLUETOOTH);
1478 add_device_file(threeg, ACER_CAP_THREEG);
1479 add_device_file(interface, ACER_CAP_ANY);
1480 add_device_file(fan_temperature_override, ACER_CAP_TEMPERATURE_OVERRIDE);
1481 add_device_file(touchpad, ACER_CAP_TOUCHPAD_READ);
1483 return 0;
1485 error:
1486 remove_sysfs(acer_platform_device);
1487 return retval;
1490 static int __init acer_acpi_init(void)
1492 printk(ACER_INFO "Acer Laptop ACPI Extras version %s\n",
1493 ACER_ACPI_VERSION);
1496 * Detect which WMI interface we're using.
1498 if (wmi_acer_has_guid(AMW0_GUID1) && wmi_acer_has_guid(WMID_GUID1)) {
1499 DEBUG(0, "Detected Acer AMW0 version 2 interface\n");
1500 interface = &AMW0_V2_interface;
1503 if (!wmi_acer_has_guid(AMW0_GUID1) && wmi_acer_has_guid(WMID_GUID1)) {
1504 DEBUG(0, "Detected Acer WMID interface\n");
1505 interface = &WMID_interface;
1508 if (wmi_acer_has_guid(WMID_GUID2) && interface) {
1509 if (ACPI_FAILURE(WMID_set_capabilities())) {
1510 printk(ACER_ERR "Unable to detect available WMID devices\n");
1511 return -ENODEV;
1513 } else if (!wmi_acer_has_guid(WMID_GUID2) && interface) {
1514 printk(ACER_ERR "No WMID device detection method found\n");
1515 return -ENODEV;
1518 if (wmi_acer_has_guid(AMW0_GUID1) && !wmi_acer_has_guid(WMID_GUID1)) {
1519 DEBUG(0, "Detected Acer AMW0 version 2 interface\n");
1520 interface = &AMW0_interface;
1522 if (ACPI_FAILURE(AMW0_set_capabilities())) {
1523 printk(ACER_ERR "Unable to detect available AMW0 devices\n");
1524 return -ENODEV;
1528 if (wmi_acer_has_guid(AMW0_GUID1)) {
1529 if (ACPI_FAILURE(AMW0_find_mailled())) {
1530 DEBUG(2, "Unable to detect mail LED\n");
1534 /* Find if this laptop requires any quirks */
1535 DEBUG(1, "Finding quirks\n");
1536 find_quirks();
1538 if (!interface) {
1539 printk(ACER_ERR "No or unsupported WMI interface, unable to load.\n");
1540 return -ENODEV;
1543 #ifdef CONFIG_PROC
1544 /* Create the proc entries */
1545 acer_proc_dir = proc_mkdir(PROC_ACER, acpi_root_dir);
1546 if (!acer_proc_dir) {
1547 printk(ACER_ERR "Unable to create /proc entries, aborting.\n");
1548 goto error_proc_mkdir;
1551 acer_proc_dir->owner = THIS_MODULE;
1552 if (add_proc_entries()) {
1553 printk(ACER_ERR "Unable to create /proc entries, aborting.\n");
1554 goto error_proc_add;
1556 #endif
1559 * Register the driver
1561 if (platform_driver_register(&acer_platform_driver)) {
1562 printk(ACER_ERR "Unable to register platform driver, aborting.\n");
1563 goto error_platform_register;
1565 acer_platform_device = platform_device_alloc("acer_acpi", -1);
1566 platform_device_add(acer_platform_device);
1568 create_sysfs();
1570 DEBUG(1, "Driver registered\n");
1572 /* Override any initial settings with values from the commandline */
1573 acer_commandline_init();
1575 return 0;
1577 error_platform_register:
1578 #ifdef CONFIG_PROC
1579 remove_proc_entries();
1580 error_proc_add:
1581 if (acer_proc_dir)
1582 remove_proc_entry(PROC_ACER, acpi_root_dir);
1583 error_proc_mkdir:
1584 #endif
1585 return -ENODEV;
1588 static void __exit acer_acpi_exit(void)
1590 remove_sysfs(acer_platform_device);
1591 platform_device_del(acer_platform_device);
1592 platform_driver_unregister(&acer_platform_driver);
1594 #ifdef CONFIG_PROC
1595 remove_proc_entries();
1597 if (acer_proc_dir)
1598 remove_proc_entry(PROC_ACER, acpi_root_dir);
1599 #endif
1600 printk(ACER_INFO "Acer Laptop ACPI Extras unloaded\n");
1601 return;
1604 module_init(acer_acpi_init);
1605 module_exit(acer_acpi_exit);