acer_acpi: Clean up init error handling
[acer_acpi.git] / acer_acpi.c
blob05f01cacadcd381621fe5cbf903dd0048d66983a
1 /*
2 * acer_acpi.c - Acer Laptop ACPI Extras
5 * Copyright (C) 2005-2007 E.M. Smith
6 * Copyright (C) 2007 Carlos Corbacho <cathectic@gmail.com>
8 * This program is free software; you can redistribute it and/or modify
9 * it under the terms of the GNU General Public License as published by
10 * the Free Software Foundation; either version 2 of the License, or
11 * (at your option) any later version.
13 * This program is distributed in the hope that it will be useful,
14 * but WITHOUT ANY WARRANTY; without even the implied warranty of
15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 * GNU General Public License for more details.
18 * You should have received a copy of the GNU General Public License
19 * along with this program; if not, write to the Free Software
20 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
23 * The devolpment page for this driver is located at
24 * http://code.google.com/p/aceracpi
26 * Credits:
28 * John Belmonte - the Toshiba ACPI driver I've adapted for this module.
29 * Julien Lerouge & Karol Kozimor - ASUS Acpi driver authors.
30 * Olaf Tauber - developer of acerhk, the inspiration to solve the 64-bit
31 * driver problem for my Aspire 5024.
32 * Mathieu Segaud - solved the ACPI problem that needed a double-modprobe
33 * in version 0.2 and below.
34 * Carlos Corbacho - added initial status support for wireless/ mail/
35 * bluetooth, added module parameter support to turn
36 * hardware/ LEDs on and off at module loading (thanks
37 * again to acerhk for the inspiration)
38 * Jim Ramsay - Figured out and added support for WMID interface
41 #define ACER_ACPI_VERSION "0.10.0"
44 * Comment the following line out to remove /proc support
46 #define CONFIG_PROC
48 #ifdef CONFIG_PROC
49 #define PROC_ACER "acer"
50 #endif
52 #include <linux/kernel.h>
53 #include <linux/module.h>
54 #include <linux/init.h>
55 #include <linux/types.h>
56 #include <linux/proc_fs.h>
57 #include <linux/delay.h>
58 #include <linux/version.h>
60 #if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,17)
61 #include <asm/uaccess.h>
62 #else
63 #include <linux/uaccess.h>
64 #endif
66 #include <linux/preempt.h>
67 #include <linux/io.h>
68 #include <linux/dmi.h>
69 #include <linux/backlight.h>
70 #include <linux/leds.h>
71 #include <linux/platform_device.h>
73 #include <acpi/acpi_drivers.h>
75 #include "wmi-acer.h"
77 /* Workaround needed for older kernels */
78 #ifndef bool
79 #define bool int
80 #endif
82 MODULE_AUTHOR("Mark Smith, Carlos Corbacho");
83 MODULE_DESCRIPTION("Acer Laptop ACPI Extras Driver");
84 MODULE_LICENSE("GPL");
86 #define ACER_LOGPREFIX "acer_acpi: "
87 #define ACER_ERR KERN_ERR ACER_LOGPREFIX
88 #define ACER_NOTICE KERN_NOTICE ACER_LOGPREFIX
89 #define ACER_INFO KERN_INFO ACER_LOGPREFIX
91 #define DEBUG(level, message...) { \
92 if (debug >= level) \
93 printk(KERN_DEBUG ACER_LOGPREFIX message);\
97 * The maximum temperature one can set for fan control override.
98 * Doesn't propably make much sense if over 80 degrees celsius though...
100 #define ACER_MAX_TEMPERATURE_OVERRIDE 150
103 * The following defines quirks to get some specific functions to work
104 * which are known to not be supported over ACPI (such as the mail LED
105 * on WMID based Acer's)
107 struct acer_quirks {
108 const char *vendor;
109 const char *model;
110 u16 quirks;
114 * Keyboard controller ports
116 #define ACER_KBD_STATUS_REG 0x64 /* Status register (R) */
117 #define ACER_KBD_CNTL_REG 0x64 /* Controller command register (W) */
118 #define ACER_KBD_DATA_REG 0x60 /* Keyboard data register (R/W) */
121 * Magic Number
122 * Meaning is unknown - this number is required for writing to ACPI for AMW0
123 * (it's also used in acerhk when directly accessing the EC)
125 #define ACER_AMW0_WRITE 0x9610
128 * Bit masks for the old AMW0 interface
130 #define ACER_AMW0_WIRELESS_MASK 0x35
131 #define ACER_AMW0_BLUETOOTH_MASK 0x34
132 #define ACER_AMW0_MAILLED_MASK 0x31
135 * Method IDs for new WMID interface
137 #define ACER_WMID_GET_WIRELESS_METHODID 1
138 #define ACER_WMID_GET_BLUETOOTH_METHODID 2
139 #define ACER_WMID_GET_BRIGHTNESS_METHODID 3
140 #define ACER_WMID_SET_WIRELESS_METHODID 4
141 #define ACER_WMID_SET_BLUETOOTH_METHODID 5
142 #define ACER_WMID_SET_BRIGHTNESS_METHODID 6
143 #define ACER_WMID_GET_THREEG_METHODID 10
144 #define ACER_WMID_SET_THREEG_METHODID 11
147 * Acer ACPI method GUIDs
149 #define AMW0_GUID1 "67C3371D-95A3-4C37-BB61-DD47B491DAAB"
150 #define WMID_GUID1 "6AF4F258-B401-42fd-BE91-3D4AC2D7C0D3"
153 * Interface capability flags
155 enum cap_flags {
156 ACER_CAP_MAILLED,
157 ACER_CAP_WIRELESS,
158 ACER_CAP_BLUETOOTH,
159 ACER_CAP_BRIGHTNESS,
160 ACER_CAP_THREEG,
161 ACER_CAP_TOUCHPAD_READ,
162 ACER_CAP_TEMPERATURE_OVERRIDE,
163 ACER_CAP_ANY,
167 * Interface type flags
169 enum interface_flags {
170 ACER_AMW0,
171 ACER_WMID,
175 * Presumed start states -
176 * On some AMW0 laptops, we do not yet know how to get the device status from
177 * the EC, so we must store this ourselves.
179 * Plus, we can't tell which features are enabled or disabled on a specific
180 * model - e.g. The 5020 series can _support_ bluetooth; but the 5021 has no
181 * bluetooth, whilst the 5024 does. However, the BIOS identifies both laptops
182 * as 5020, and you can add bluetooth later.
184 * Basically the code works like this:
185 * - On init, any values specified on the commandline are set.
186 * - For interfaces where the current values cannot be detected and which
187 * have not been set on the commandline, we set them to some sane default
188 * (disabled)
190 * See AMW0_init and acer_commandline_init
193 #define ACER_DEFAULT_WIRELESS 0
194 #define ACER_DEFAULT_BLUETOOTH 0
195 #define ACER_DEFAULT_MAILLED 0
196 #define ACER_DEFAULT_THREEG 0
198 static int max_brightness = 0xF;
200 static int wireless = -1;
201 static int bluetooth = -1;
202 static int mailled = -1;
203 static int brightness = -1;
204 static int threeg = -1;
205 static int fan_temperature_override = -1;
206 static int debug = 0;
207 static int force_series;
209 module_param(mailled, int, 0444);
210 module_param(wireless, int, 0444);
211 module_param(bluetooth, int, 0444);
212 module_param(brightness, int, 0444);
213 module_param(threeg, int, 0444);
214 module_param(force_series, int, 0444);
215 module_param(fan_temperature_override, int, 0444);
216 module_param(debug, int, 0664);
217 MODULE_PARM_DESC(wireless, "Set initial state of Wireless hardware");
218 MODULE_PARM_DESC(bluetooth, "Set initial state of Bluetooth hardware");
219 MODULE_PARM_DESC(mailled, "Set initial state of Mail LED");
220 MODULE_PARM_DESC(brightness, "Set initial LCD backlight brightness");
221 MODULE_PARM_DESC(threeg, "Set initial state of 3G hardware");
222 MODULE_PARM_DESC(fan_temperature_override, "Set initial state of the 'FAN temperature-override'");
223 MODULE_PARM_DESC(debug, "Debugging verbosity level (0=least 2=most)");
224 MODULE_PARM_DESC(force_series, "Force a different laptop series for extra features (5020, 5720 or 2490)");
226 #ifdef CONFIG_PROC
227 struct ProcItem {
228 const char *name;
229 char *(*read_func) (char *, u32);
230 unsigned long (*write_func) (const char *, unsigned long, u32);
231 unsigned int capability;
234 static struct proc_dir_entry *acer_proc_dir;
235 #endif
238 * Wait for the keyboard controller to become ready
240 static int wait_kbd_write(void)
242 int i = 0;
243 while ((inb(ACER_KBD_STATUS_REG) & 0x02) && (i < 10000)) {
244 udelay(50);
245 i++;
247 return -(i == 10000);
250 static void send_kbd_cmd(u8 cmd, u8 val)
252 preempt_disable();
253 if (!wait_kbd_write())
254 outb(cmd, ACER_KBD_CNTL_REG);
255 if (!wait_kbd_write())
256 outb(val, ACER_KBD_DATA_REG);
257 preempt_enable_no_resched();
260 static void set_keyboard_quirk(void)
262 send_kbd_cmd(0x59, 0x90);
265 /* Each low-level interface must define at least some of the following */
266 struct Interface {
268 * The ACPI device type
270 u32 type;
273 * The capabilities this interface provides
274 * In the future, these can be removed/added at runtime when we have a
275 * way of detecting what capabilities are /actually/ present on an
276 * interface
278 u32 capability;
281 * Initializes an interface, should allocate the interface-specific
282 * data
284 void (*init) (struct Interface*);
287 * Frees an interface, should free the interface-specific data
289 void (*free) (struct Interface*);
292 * Interface-specific private data member. Must *not* be touched by
293 * anyone outside of this struct
295 void *data;
298 /* The static interface pointer, points to the currently detected interface */
299 static struct Interface *interface;
301 struct acer_data {
302 int mailled;
303 int wireless;
304 int bluetooth;
305 int threeg;
306 int brightness;
310 * Embedded Controller quirks
311 * Some laptops require us to directly access the EC to either enable or query
312 * features that are not available through ACPI.
315 struct quirk_entry {
316 u8 wireless;
317 u8 mailled;
318 u8 brightness;
319 u8 touchpad;
320 u8 temperature_override;
321 u8 mmkeys;
322 u8 bluetooth;
323 u8 max_brightness;
326 static struct quirk_entry *quirks;
328 static void set_quirks(void)
330 if (quirks->mailled != 0) {
331 interface->capability |= ACER_CAP_MAILLED;
332 DEBUG(1, "Using EC direct-access quirk for mail LED\n");
335 if (quirks->touchpad != 0) {
336 interface->capability |= ACER_CAP_TOUCHPAD_READ;
337 DEBUG(1, "Using EC direct-access quirk for reading touchpad status\n");
340 if (quirks->temperature_override != 0) {
341 interface->capability |= ACER_CAP_TEMPERATURE_OVERRIDE;
342 DEBUG(1, "Using EC direct-access quirk for temperature override setting (fan)\n");
345 if (quirks->brightness != 0) {
346 interface->capability |= ACER_CAP_BRIGHTNESS;
347 DEBUG(1, "Using EC direct-access quirk for backlight brightness\n");
350 if (quirks->mmkeys != 0) {
351 set_keyboard_quirk();
352 printk(ACER_INFO "Setting keyboard quirk to enable multimedia keys\n");
355 if (quirks->bluetooth != 0) {
356 interface->capability |= ACER_CAP_BLUETOOTH;
357 DEBUG(1, "Using EC direct-access quirk for bluetooth\n");
360 if (quirks->wireless != 0) {
361 interface->capability |= ACER_CAP_WIRELESS;
362 DEBUG(1, "Using EC direct-access quirk for wireless\n");
365 if (quirks->max_brightness != 0) {
366 max_brightness = quirks->max_brightness;
367 DEBUG(1, "Changing maximum brightness level\n");
371 static int dmi_matched(struct dmi_system_id *dmi)
373 quirks = dmi->driver_data;
374 return 0;
377 static struct quirk_entry quirk_unknown = {
380 static struct quirk_entry quirk_acer_aspire_5020 = {
381 .wireless = 1,
382 .mailled = 2,
383 .brightness = 1,
384 .bluetooth = 1,
387 static struct quirk_entry quirk_acer_aspire_5680 = {
388 .mmkeys = 1,
391 static struct quirk_entry quirk_acer_aspire_9300 = {
392 .brightness = 2,
395 static struct quirk_entry quirk_acer_travelmate_2490 = {
396 .mmkeys = 1,
397 .mailled = 1,
398 .temperature_override = 1,
399 .touchpad = 1,
403 * This is similar to the Aspire 5020, but with a different wireless quirk
405 static struct quirk_entry quirk_acer_travelmate_5620 = {
406 .wireless = 2,
407 .mailled = 2,
408 .brightness = 1,
409 .bluetooth = 1,
412 static struct quirk_entry quirk_acer_travelmate_5720 = {
413 .max_brightness = 0x9,
414 .touchpad = 2,
415 .wireless = 2,
416 .bluetooth = 2,
417 .brightness = 1,
420 static struct dmi_system_id acer_quirks[] = {
422 .callback = dmi_matched,
423 .ident = "Acer Aspire 3020",
424 .matches = {
425 DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
426 DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 3020"),
428 .driver_data = &quirk_acer_aspire_5020,
431 .callback = dmi_matched,
432 .ident = "Acer Aspire 3040",
433 .matches = {
434 DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
435 DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 3040"),
437 .driver_data = &quirk_acer_aspire_5020,
440 .callback = dmi_matched,
441 .ident = "Acer Aspire 5020",
442 .matches = {
443 DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
444 DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5020"),
446 .driver_data = &quirk_acer_aspire_5020,
449 .callback = dmi_matched,
450 .ident = "Acer Aspire 5040",
451 .matches = {
452 DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
453 DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5040"),
455 .driver_data = &quirk_acer_aspire_5020,
458 .callback = dmi_matched,
459 .ident = "Acer Aspire 5560",
460 .matches = {
461 DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
462 DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5560"),
464 .driver_data = &quirk_acer_travelmate_5620,
467 .callback = dmi_matched,
468 .ident = "Acer Aspire 5650",
469 .matches = {
470 DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
471 DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5650"),
473 .driver_data = &quirk_acer_travelmate_2490,
476 .callback = dmi_matched,
477 .ident = "Acer Aspire 5680",
478 .matches = {
479 DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
480 DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5680"),
482 .driver_data = &quirk_acer_aspire_5680,
485 .callback = dmi_matched,
486 .ident = "Acer Aspire 9300",
487 .matches = {
488 DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
489 DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 9300"),
491 .driver_data = &quirk_acer_aspire_9300,
494 .callback = dmi_matched,
495 .ident = "Acer TravelMate 2420",
496 .matches = {
497 DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
498 DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 2420"),
500 .driver_data = &quirk_acer_aspire_5020,
503 .callback = dmi_matched,
504 .ident = "Acer TravelMate 2490",
505 .matches = {
506 DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
507 DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 2490"),
509 .driver_data = &quirk_acer_travelmate_2490,
512 .callback = dmi_matched,
513 .ident = "Acer TravelMate 5620",
514 .matches = {
515 DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
516 DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 5620"),
518 .driver_data = &quirk_acer_travelmate_5620,
521 .callback = dmi_matched,
522 .ident = "Acer TravelMate 5720",
523 .matches = {
524 DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
525 DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 5720"),
527 .driver_data = &quirk_acer_travelmate_5720,
532 /* Find which quirks are needed for a particular vendor/ model pair */
533 static void find_quirks(void)
535 DEBUG (1, "Looking for quirks\n");
536 if (!force_series) {
537 dmi_check_system(acer_quirks);
538 } else if (force_series == 5020) {
539 DEBUG(0, "Forcing Acer Aspire 5020\n");
540 quirks = &quirk_acer_aspire_5020;
541 } else if (force_series == 2490) {
542 DEBUG(0, "Forcing Acer TravelMate 2490\n");
543 quirks = &quirk_acer_travelmate_2490;
544 } else if (force_series == 5620) {
545 DEBUG(0, "Forcing Acer TravelMate 5620\n");
546 quirks = &quirk_acer_travelmate_5620;
547 } else if (force_series == 5720) {
548 DEBUG(0, "Forcing Acer TravelMate 5720\n");
549 quirks = &quirk_acer_travelmate_5720;
552 if (quirks == NULL) {
553 DEBUG(1, "No quirks known for this laptop\n");
554 quirks = &quirk_unknown;
556 set_quirks();
560 * General interface convenience methods
563 static bool has_cap(u32 cap)
565 if ((interface->capability & cap) != 0) {
566 return 1;
568 return 0;
571 static void interface_free(struct Interface *iface)
573 /* Free our private data structure */
574 kfree(iface->data);
578 * Old interface (now known as the AMW0 interface)
580 struct WMAB_args {
581 u32 eax;
582 u32 ebx;
583 u32 ecx;
584 u32 edx;
587 static acpi_status WMAB_execute(struct WMAB_args *regbuf, struct acpi_buffer *result)
589 struct acpi_buffer input;
590 acpi_status status;
591 input.length = sizeof(struct WMAB_args);
592 input.pointer = (u8*)regbuf;
594 status = wmi_acer_evaluate_method(AMW0_GUID1, 1, 1, &input, result);
595 DEBUG(2, " Args: 0x%08x 0x%08x 0x%08x 0x%08x\n", regbuf->eax, regbuf->ebx, regbuf->ecx, regbuf->edx );
597 return status;
600 static void AMW0_init(struct Interface *iface) {
601 bool help = 0;
602 struct acer_data *data;
604 /* Allocate our private data structure */
605 iface->data = kmalloc(sizeof(struct acer_data), GFP_KERNEL);
606 data = (struct acer_data *) iface->data;
609 * If the commandline doesn't specify these, we need to force them to
610 * the default values
612 if (mailled == -1 && !quirks->mailled)
613 mailled = ACER_DEFAULT_MAILLED;
614 if (wireless == -1 && !quirks->wireless)
615 wireless = ACER_DEFAULT_WIRELESS;
616 if (bluetooth == -1 && !quirks->bluetooth)
617 bluetooth = ACER_DEFAULT_BLUETOOTH;
620 * Set the cached "current" values to impossible ones so that
621 * acer_commandline_init will definitely set them.
623 if (quirks->bluetooth == 0) {
624 help = 1;
625 data->bluetooth = -1;
626 printk(ACER_INFO "No EC data for reading bluetooth - bluetooth value when read will be a 'best guess'\n");
629 if (quirks->wireless == 0) {
630 help = 1;
631 printk(ACER_INFO "No EC data for reading wireless - wireless value when read will be a 'best guess'\n");
632 data->wireless = -1;
634 if (quirks->mailled == 0) {
635 help = 1;
636 printk(ACER_INFO "No EC data for reading mail LED - mail LED value when read will be a 'best guess'\n");
637 data->mailled = -1;
640 if (help) {
641 printk(ACER_INFO "We need more data from your laptop's Embedded Controller (EC) to better support it\n");
642 printk(ACER_INFO "Please see http://code.google.com/p/aceracpi/wiki/EmbeddedController on how to help\n");
646 static acpi_status AMW0_get_bool(bool *value, u32 cap, struct Interface *iface)
648 struct acer_data *data = iface->data;
649 u8 result;
651 DEBUG(2, " AMW0_get_bool: cap=%d\n", cap);
653 * On some models, we can read these values from the EC. On others,
654 * we use a stored value
656 switch (cap) {
657 case ACER_CAP_MAILLED:
658 switch (quirks->mailled) {
659 case 2:
660 ec_read(0x0A, &result);
661 *value = (result >> 7) & 0x01;
662 return 0;
663 default:
664 *value = data->mailled;
666 break;
667 case ACER_CAP_WIRELESS:
668 switch (quirks->wireless) {
669 case 1:
670 ec_read(0x0A, &result);
671 *value = (result >> 2) & 0x01;
672 return 0;
673 case 2:
674 ec_read(0x71, &result);
675 *value = result & 0x01;
676 return 0;
677 default:
678 *value = data->wireless;
680 break;
681 case ACER_CAP_BLUETOOTH:
682 switch (quirks->bluetooth) {
683 case 1:
684 ec_read(0x0A, &result);
685 *value = (result >> 4) & 0x01;
686 return 0;
687 case 2:
688 ec_read(0x71, &result);
689 *value = (result >> 1) & 0x01;
690 return 0;
691 default:
692 *value = data->bluetooth;
694 break;
695 case ACER_CAP_TOUCHPAD_READ:
696 switch (quirks->touchpad) {
697 case 2:
698 ec_read(0x74, &result);
699 *value = (result >> 3) & 0x01;
700 return 0;
701 default:
702 break;
704 default:
705 return AE_BAD_ADDRESS;
707 return AE_OK;
710 static acpi_status AMW0_set_bool(bool value, u32 cap, struct Interface *iface)
712 struct WMAB_args args;
713 acpi_status status;
715 args.eax = ACER_AMW0_WRITE;
716 args.ebx = value ? (1<<8) : 0;
718 switch (cap) {
719 case ACER_CAP_MAILLED:
720 args.ebx |= ACER_AMW0_MAILLED_MASK;
721 break;
722 case ACER_CAP_WIRELESS:
723 args.ebx |= ACER_AMW0_WIRELESS_MASK;
724 break;
725 case ACER_CAP_BLUETOOTH:
726 args.ebx |= ACER_AMW0_BLUETOOTH_MASK;
727 break;
728 default:
729 return AE_BAD_ADDRESS;
732 /* Actually do the set */
733 status = WMAB_execute(&args, NULL);
736 * Currently no way to query the state, so cache the new value on
737 * success
739 if (ACPI_SUCCESS(status)) {
740 struct acer_data *data = iface->data;
741 switch (cap) {
742 case ACER_CAP_MAILLED:
743 data->mailled = value;
744 break;
745 case ACER_CAP_WIRELESS:
746 data->wireless = value;
747 break;
748 case ACER_CAP_BLUETOOTH:
749 data->bluetooth = value;
750 break;
754 return status;
757 static acpi_status AMW0_get_u8(u8 *value, u32 cap, struct Interface *iface) {
758 switch (cap) {
759 case ACER_CAP_BRIGHTNESS:
760 switch (quirks->brightness) {
761 case 1:
762 return ec_read(0x83, value);
763 case 2:
764 return ec_read(0x85, value);
765 default:
766 return AE_BAD_ADDRESS;
768 break;
769 default:
770 return AE_BAD_ADDRESS;
772 return AE_OK;
775 static acpi_status AMW0_set_u8(u8 value, u32 cap, struct Interface *iface) {
776 switch (cap) {
777 case ACER_CAP_BRIGHTNESS:
778 switch (quirks->brightness) {
779 case 1:
780 return ec_write(0x83, value);
781 case 2:
782 return ec_write(0x85, value);
783 default:
784 return AE_BAD_ADDRESS;
785 break;
787 default:
788 return AE_BAD_ADDRESS;
790 return AE_OK;
793 static struct Interface AMW0_interface = {
794 .type = ACER_AMW0,
795 .capability = (
796 ACER_CAP_MAILLED |
797 ACER_CAP_WIRELESS |
798 ACER_CAP_BLUETOOTH
800 .init = AMW0_init,
801 .free = interface_free,
805 * New interface (The WMID interface)
808 static void WMID_init(struct Interface *iface)
810 struct acer_data *data;
812 /* Allocate our private data structure */
813 iface->data = kmalloc(sizeof(struct acer_data), GFP_KERNEL);
814 data = (struct acer_data *) iface->data;
817 static acpi_status
818 WMI_execute_u32(u32 method_id, u32 in, u32 *out)
820 struct acpi_buffer input = { (acpi_size) sizeof(u32), (void *)(&in) };
821 struct acpi_buffer result = { ACPI_ALLOCATE_BUFFER, NULL };
822 union acpi_object *obj;
823 u32 tmp;
824 acpi_status status;
826 DEBUG(2, " WMI_execute_u32:\n");
827 status = wmi_acer_evaluate_method(WMID_GUID1, 1, method_id, &input, &result);
828 DEBUG(2, " In: 0x%08x\n", in);
830 if (ACPI_FAILURE(status))
831 return status;
833 obj = (union acpi_object *) result.pointer;
834 if (obj && obj->type == ACPI_TYPE_BUFFER && obj->buffer.length == sizeof(u32)) {
835 tmp = *((u32 *) obj->buffer.pointer);
836 DEBUG(2, " Out: 0x%08x\n", tmp);
837 } else {
838 tmp = 0;
839 if (obj) {
840 DEBUG(2, " Got unexpected result of type %d\n", obj->type);
841 } else {
842 DEBUG(2, " Got unexpected null result\n");
846 if (out)
847 *out = tmp;
849 if (result.length > 0 && result.pointer)
850 kfree(result.pointer);
852 DEBUG(2, " Returning from WMI_execute_u32:\n");
853 return status;
856 static acpi_status WMID_get_u8(u8 *value, u32 cap, struct Interface *iface) {
857 acpi_status status;
858 u32 result;
859 u32 method_id = 0;
861 DEBUG(2, " WMID_get_u8: cap=%d\n", cap);
862 switch (cap) {
863 case ACER_CAP_WIRELESS:
864 method_id = ACER_WMID_GET_WIRELESS_METHODID;
865 break;
866 case ACER_CAP_BLUETOOTH:
867 method_id = ACER_WMID_GET_BLUETOOTH_METHODID;
868 break;
869 case ACER_CAP_BRIGHTNESS:
870 method_id = ACER_WMID_GET_BRIGHTNESS_METHODID;
871 break;
872 case ACER_CAP_THREEG:
873 method_id = ACER_WMID_GET_THREEG_METHODID;
874 break;
875 case ACER_CAP_MAILLED:
876 if (quirks->mailled == 1) {
877 ec_read(0x9f, value);
878 *value &= 0x01;
879 return 0;
881 case ACER_CAP_TOUCHPAD_READ:
882 switch (quirks->touchpad) {
883 case 1:
884 ec_read(0x9e, value);
885 *value = 1 - ((*value >> 3) & 0x01);
886 return 0;
887 default:
888 break;
890 case ACER_CAP_TEMPERATURE_OVERRIDE:
891 if (quirks->temperature_override == 1) {
892 ec_read(0xa9, value);
893 return 0;
895 default:
896 return AE_BAD_ADDRESS;
898 status = WMI_execute_u32(method_id, 0, &result);
899 DEBUG(2, " WMI_execute_u32 status=%d:\n", status);
901 if (ACPI_SUCCESS(status))
902 *value = (u8)result;
904 DEBUG(2, " Returning from WMID_get_u8:\n");
905 return status;
908 static acpi_status WMID_set_u8(u8 value, u32 cap, struct Interface *iface) {
909 u32 method_id = 0;
911 switch (cap) {
912 case ACER_CAP_BRIGHTNESS:
913 method_id = ACER_WMID_SET_BRIGHTNESS_METHODID;
914 break;
915 case ACER_CAP_WIRELESS:
916 method_id = ACER_WMID_SET_WIRELESS_METHODID;
917 break;
918 case ACER_CAP_BLUETOOTH:
919 method_id = ACER_WMID_SET_BLUETOOTH_METHODID;
920 break;
921 case ACER_CAP_THREEG:
922 method_id = ACER_WMID_SET_THREEG_METHODID;
923 break;
924 case ACER_CAP_MAILLED:
925 if (quirks->mailled == 1) {
926 send_kbd_cmd(0x59, value ? 0x92 : 0x93);
927 return 0;
929 case ACER_CAP_TEMPERATURE_OVERRIDE:
930 if (quirks->temperature_override == 1) {
931 ec_write(0xa9, value);
932 return 0;
934 default:
935 return AE_BAD_ADDRESS;
937 return WMI_execute_u32(method_id, (u32)value, NULL);
941 static struct Interface WMID_interface = {
942 .type = ACER_WMID,
943 .capability = (
944 ACER_CAP_WIRELESS
945 | ACER_CAP_BRIGHTNESS
946 | ACER_CAP_BLUETOOTH
947 | ACER_CAP_THREEG
949 .init = WMID_init,
950 .free = interface_free,
951 .data = NULL,
954 #ifdef CONFIG_PROC
956 * High-level Procfs file handlers
959 static int
960 dispatch_read(char *page, char **start, off_t off, int count, int *eof,
961 struct ProcItem *item)
963 char *p = page;
964 int len;
966 DEBUG(2, " dispatch_read: \n");
967 if (off == 0)
968 p = item->read_func(p, item->capability);
969 len = (p - page);
970 if (len <= off + count)
971 *eof = 1;
972 *start = page + off;
973 len -= off;
974 if (len > count)
975 len = count;
976 if (len < 0)
977 len = 0;
978 return len;
981 static int
982 dispatch_write(struct file *file, const char __user *buffer,
983 unsigned long count, struct ProcItem *item)
985 int result;
986 char *tmp_buffer;
989 * Arg buffer points to userspace memory, which can't be accessed
990 * directly. Since we're making a copy, zero-terminate the
991 * destination so that sscanf can be used on it safely.
993 tmp_buffer = kmalloc(count + 1, GFP_KERNEL);
994 if (copy_from_user(tmp_buffer, buffer, count)) {
995 result = -EFAULT;
996 } else {
997 tmp_buffer[count] = 0;
998 result = item->write_func(tmp_buffer, count, item->capability);
1000 kfree(tmp_buffer);
1001 return result;
1003 #endif
1006 * Generic Device (interface-independent)
1009 static acpi_status get_bool(bool *value, u32 cap) {
1010 acpi_status status = AE_BAD_ADDRESS;
1011 u8 tmp = 0;
1013 DEBUG(2, " get_bool: cap=%d, interface type=%d\n",
1014 cap, interface->type);
1015 switch (interface->type) {
1016 case ACER_AMW0:
1017 status = AMW0_get_bool(value, cap, interface);
1018 break;
1019 case ACER_WMID:
1020 status = WMID_get_u8(&tmp, cap, interface);
1021 *value = (tmp == 1) ? 1 : 0;
1022 break;
1024 DEBUG(2, " Returning from get_bool:\n");
1025 return status;
1028 static acpi_status set_bool(int value, u32 cap) {
1029 acpi_status status = AE_BAD_PARAMETER;
1031 DEBUG(2, " set_bool: cap=%d, interface type=%d, value=%d\n",
1032 cap, interface->type, value);
1033 if ((value == 0 || value == 1) && (interface->capability & cap)) {
1034 switch (interface->type) {
1035 case ACER_AMW0:
1036 status = AMW0_set_bool(value == 1, cap, interface);
1037 break;
1038 case ACER_WMID:
1039 status = WMID_set_u8(value == 1, cap, interface);
1040 break;
1043 return status;
1047 static acpi_status get_u8(u8 *value, u32 cap) {
1048 DEBUG(2, " get_u8: cap=%d\n", cap);
1049 switch (interface->type) {
1050 case ACER_AMW0:
1051 return AMW0_get_u8(value, cap, interface);
1052 break;
1053 case ACER_WMID:
1054 return WMID_get_u8(value, cap, interface);
1055 break;
1056 default:
1057 return AE_BAD_ADDRESS;
1061 static acpi_status set_u8(u8 value, u8 min, u8 max, u32 cap) {
1063 DEBUG(2, " set_u8: cap=%d, interface type=%d, value=%d\n",
1064 cap, interface->type, value);
1066 if ((value >= min && value <= max) && (interface->capability & cap) ) {
1067 switch (interface->type) {
1068 case ACER_AMW0:
1069 return AMW0_set_u8(value, cap, interface);
1070 case ACER_WMID:
1071 return WMID_set_u8(value, cap, interface);
1072 default:
1073 return AE_BAD_PARAMETER;
1076 return AE_BAD_PARAMETER;
1079 /* Each _u8 needs a small wrapper that sets the boundary values */
1080 static acpi_status set_brightness(u8 value)
1082 return set_u8(value, 0, max_brightness, ACER_CAP_BRIGHTNESS);
1085 static acpi_status set_temperature_override(u8 value)
1087 return set_u8(value, 0, ACER_MAX_TEMPERATURE_OVERRIDE, ACER_CAP_TEMPERATURE_OVERRIDE);
1090 static void __init acer_commandline_init(void)
1092 DEBUG(1, "Commandline args: mailled(%d) wireless(%d) bluetooth(%d) brightness(%d)\n",
1093 mailled, wireless, bluetooth, brightness);
1096 * These will all fail silently if the value given is invalid, or the
1097 * capability isn't available on the given interface
1099 set_bool(mailled, ACER_CAP_MAILLED);
1100 set_bool(wireless, ACER_CAP_WIRELESS);
1101 set_bool(bluetooth, ACER_CAP_BLUETOOTH);
1102 set_bool(threeg, ACER_CAP_THREEG);
1103 set_temperature_override(fan_temperature_override);
1104 set_brightness((u8)brightness);
1107 #ifdef CONFIG_PROC
1109 * Procfs interface (deprecated)
1111 static char *read_bool(char *p, u32 cap)
1113 bool result;
1114 acpi_status status;
1116 DEBUG(2, " read_bool: cap=%d\n", cap);
1117 status = get_bool(&result, cap);
1118 if (ACPI_SUCCESS(status))
1119 p += sprintf(p, "%d\n", result);
1120 else
1121 p += sprintf(p, "Read error" );
1122 return p;
1125 static unsigned long write_bool(const char *buffer, unsigned long count, u32 cap)
1127 int value;
1129 DEBUG(2, " write_bool: cap=%d, interface type=%d\n buffer=%s\n",
1130 cap, interface->type, buffer);
1132 if (sscanf(buffer, "%i", &value) == 1) {
1133 acpi_status status = set_bool(value, cap);
1134 if (ACPI_FAILURE(status))
1135 return -EINVAL;
1136 } else {
1137 return -EINVAL;
1139 return count;
1142 static char *read_u8(char *p, u32 cap)
1144 u8 result;
1145 acpi_status status;
1147 DEBUG(2, " read_u8: cap=%d\n", cap);
1148 status = get_u8(&result, cap);
1149 if (ACPI_SUCCESS(status))
1150 p += sprintf(p, "%u\n", result);
1151 else
1152 p += sprintf(p, "Read error" );
1153 return p;
1156 static unsigned long write_u8(const char *buffer, unsigned long count, u32 cap)
1158 int value;
1159 acpi_status (*set_method)(u8);
1161 /* Choose the appropriate set_u8 wrapper here, based on the capability */
1162 switch (cap) {
1163 case ACER_CAP_BRIGHTNESS:
1164 set_method = set_brightness;
1165 break;
1166 case ACER_CAP_TEMPERATURE_OVERRIDE:
1167 set_method = set_temperature_override;
1168 break;
1169 default:
1170 return -EINVAL;
1173 if (sscanf(buffer, "%i", &value) == 1) {
1174 acpi_status status = (*set_method)(value);
1175 if (ACPI_FAILURE(status))
1176 return -EINVAL;
1177 } else {
1178 return -EINVAL;
1180 return count;
1183 static char *read_version(char *p, u32 cap)
1185 p += sprintf(p, "%s\n", ACER_ACPI_VERSION);
1186 return p;
1189 static char *read_interface(char *p, u32 cap)
1191 p += sprintf(p, "%s\n", (interface->type == ACER_AMW0 ) ? "AMW0": "WMID");
1192 return p;
1195 struct ProcItem proc_items[] = {
1196 {"mailled", read_bool, write_bool, ACER_CAP_MAILLED},
1197 {"bluetooth", read_bool, write_bool, ACER_CAP_BLUETOOTH},
1198 {"wireless", read_bool, write_bool, ACER_CAP_WIRELESS},
1199 {"brightness", read_u8, write_u8, ACER_CAP_BRIGHTNESS},
1200 {"threeg", read_bool, write_bool, ACER_CAP_THREEG},
1201 {"touchpad", read_bool, NULL, ACER_CAP_TOUCHPAD_READ},
1202 {"fan_temperature_override", read_u8, write_u8, ACER_CAP_TEMPERATURE_OVERRIDE},
1203 {"version", read_version, NULL, ACER_CAP_ANY},
1204 {"interface", read_interface, NULL, ACER_CAP_ANY},
1205 {NULL}
1208 static int __init add_proc_entries(void)
1210 struct proc_dir_entry *proc;
1211 struct ProcItem *item;
1213 for (item = proc_items; item->name; ++item) {
1215 * Only add the proc file if the current interface actually
1216 * supports it
1218 if (interface->capability & item->capability) {
1219 proc = create_proc_read_entry(item->name,
1220 S_IFREG | S_IRUGO | S_IWUSR,
1221 acer_proc_dir,
1222 (read_proc_t *) dispatch_read,
1223 item);
1224 if (proc)
1225 proc->owner = THIS_MODULE;
1226 if (proc && item->write_func)
1227 proc->write_proc = (write_proc_t *) dispatch_write;
1231 return 0;
1234 static int __exit remove_proc_entries(void)
1236 struct ProcItem *item;
1238 for (item = proc_items; item->name; ++item)
1239 remove_proc_entry(item->name, acer_proc_dir);
1240 return 0;
1242 #endif
1245 * LED device (Mail LED only, no other LEDs known yet)
1247 static void mail_led_set(struct led_classdev *led_cdev, enum led_brightness value)
1249 bool tmp = value;
1250 set_bool(tmp, ACER_CAP_MAILLED);
1253 static struct led_classdev mail_led = {
1254 .name = "acer_acpi:mail",
1255 .brightness_set = mail_led_set,
1258 static void acer_led_init(struct device *dev)
1260 led_classdev_register(dev, &mail_led);
1263 static void acer_led_exit(void)
1265 led_classdev_unregister(&mail_led);
1268 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,18)
1270 * Backlight device
1272 static struct backlight_device *acer_backlight_device;
1274 static int read_brightness(struct backlight_device *bd)
1276 u8 value;
1277 get_u8(&value, ACER_CAP_BRIGHTNESS);
1278 return value;
1281 #if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,20)
1282 static int update_bl_status(struct backlight_device *bd)
1284 set_brightness(bd->props->brightness);
1285 return 0;
1288 static struct backlight_properties acer_backlight_properties = {
1289 .get_brightness = read_brightness,
1290 .update_status = update_bl_status,
1293 static int __init acer_backlight_init(struct device *dev)
1295 struct backlight_device *bd;
1297 DEBUG(1, "Loading backlight driver\n");
1298 bd = backlight_device_register("acer_acpi", dev, NULL, &acer_backlight_properties);
1299 if (IS_ERR(bd)) {
1300 printk(ACER_ERR "Could not register Acer backlight device\n");
1301 acer_backlight_device = NULL;
1302 return PTR_ERR(bd);
1305 acer_backlight_device = bd;
1307 bd->props->max_brightness = max_brightness;
1308 return 0;
1310 #else
1311 static int update_bl_status(struct backlight_device *bd)
1313 set_brightness(bd->props.brightness);
1314 return 0;
1317 static struct backlight_ops acer_backlight_ops = {
1318 .get_brightness = read_brightness,
1319 .update_status = update_bl_status,
1322 static int __init acer_backlight_init(struct device *dev)
1324 struct backlight_device *bd;
1326 DEBUG(1, "Loading backlight driver\n");
1327 bd = backlight_device_register("acer_acpi", dev, NULL, &acer_backlight_ops);
1328 if (IS_ERR(bd)) {
1329 printk(ACER_ERR "Could not register Acer backlight device\n");
1330 acer_backlight_device = NULL;
1331 return PTR_ERR(bd);
1334 acer_backlight_device = bd;
1336 bd->props.max_brightness = max_brightness;
1337 bd->props.brightness = read_brightness(NULL);
1338 backlight_update_status(bd);
1339 return 0;
1341 #endif
1343 static void __exit acer_backlight_exit(void)
1345 backlight_device_unregister(acer_backlight_device);
1347 #endif
1350 * Read/ write bool sysfs macro
1352 #define show_set_bool(value, cap) \
1353 static ssize_t \
1354 show_bool_##value(struct device *dev, struct device_attribute *attr, \
1355 char *buf) \
1357 bool result; \
1358 acpi_status status = get_bool(&result, cap); \
1359 if (ACPI_SUCCESS(status)) \
1360 return sprintf(buf, "%d\n", result); \
1361 return sprintf(buf, "Read error" ); \
1364 static ssize_t \
1365 set_bool_##value(struct device *dev, struct device_attribute *attr, \
1366 const char *buf, size_t count) \
1368 bool tmp = simple_strtoul(buf, NULL, 10); \
1369 acpi_status status = set_bool(tmp, cap); \
1370 if (ACPI_FAILURE(status)) \
1371 return -EINVAL; \
1372 return count; \
1374 static DEVICE_ATTR(value, S_IWUGO | S_IRUGO | S_IWUSR, \
1375 show_bool_##value, set_bool_##value);
1377 show_set_bool(wireless, ACER_CAP_WIRELESS);
1378 show_set_bool(bluetooth, ACER_CAP_BLUETOOTH);
1379 show_set_bool(threeg, ACER_CAP_THREEG);
1380 show_set_bool(fan_temperature_override, ACER_CAP_TEMPERATURE_OVERRIDE);
1383 * Read-only bool sysfs macro
1385 #define show_bool(value, cap) \
1386 static ssize_t \
1387 show_bool_##value(struct device *dev, struct device_attribute *attr, \
1388 char *buf) \
1390 bool result; \
1391 acpi_status status = get_bool(&result, cap); \
1392 if (ACPI_SUCCESS(status)) \
1393 return sprintf(buf, "%d\n", result); \
1394 return sprintf(buf, "Read error" ); \
1396 static DEVICE_ATTR(value, S_IWUGO | S_IRUGO | S_IWUSR, \
1397 show_bool_##value, NULL);
1399 show_bool(touchpad, ACER_CAP_TOUCHPAD_READ);
1402 * Read interface sysfs macro
1404 static ssize_t show_interface(struct device *dev, struct device_attribute *attr,
1405 char *buf)
1407 return sprintf(buf, "%s\n", (interface->type == ACER_AMW0 ) ? "AMW0" : "WMID");
1410 static DEVICE_ATTR(interface, S_IWUGO | S_IRUGO | S_IWUSR, show_interface, NULL);
1413 * Platform device
1415 static int __devinit acer_platform_probe(struct platform_device *device)
1417 if (has_cap(ACER_CAP_MAILLED))
1418 acer_led_init(&device->dev);
1419 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,18)
1420 if (has_cap(ACER_CAP_BRIGHTNESS))
1421 acer_backlight_init(&device->dev);
1422 #endif
1423 return 0;
1426 static int acer_platform_remove(struct platform_device *device)
1428 if (has_cap(ACER_CAP_MAILLED))
1429 acer_led_exit();
1430 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,18)
1431 if (has_cap(ACER_CAP_BRIGHTNESS))
1432 acer_backlight_exit();
1433 #endif
1434 return 0;
1437 static int acer_platform_suspend(struct platform_device *device, pm_message_t state)
1440 * WMID fix for suspend-to-disk - save all current states now so we can
1441 * restore them on resume
1443 bool value;
1444 u8 u8value;
1445 struct acer_data *data = interface->data;
1447 #define save_bool_device(device, cap) \
1448 if (has_cap(cap)) {\
1449 get_bool(&value, cap);\
1450 data->device = value;\
1453 #define save_u8_device(device, cap) \
1454 if (has_cap(cap)) {\
1455 get_u8(&u8value, cap);\
1456 data->device = u8value;\
1459 if (interface->type == ACER_WMID) {
1460 save_bool_device(wireless, ACER_CAP_WIRELESS);
1461 save_bool_device(bluetooth, ACER_CAP_BLUETOOTH);
1462 save_bool_device(threeg, ACER_CAP_THREEG);
1463 save_u8_device(brightness, ACER_CAP_BRIGHTNESS);
1466 return 0;
1469 static int acer_platform_resume(struct platform_device *device)
1471 struct acer_data *data = interface->data;
1473 #define restore_bool_device(device, cap) \
1474 if (has_cap(cap))\
1475 set_bool(data->device, cap);\
1477 restore_bool_device(wireless, ACER_CAP_WIRELESS);
1478 restore_bool_device(bluetooth, ACER_CAP_BLUETOOTH);
1479 restore_bool_device(threeg, ACER_CAP_THREEG);
1480 restore_bool_device(mailled, ACER_CAP_MAILLED);
1482 if (has_cap(ACER_CAP_BRIGHTNESS))
1483 set_brightness((u8)data->brightness);
1485 /* Check if this laptop requires the keyboard quirk */
1486 if (quirks->mmkeys != 0) {
1487 set_keyboard_quirk();
1488 printk(ACER_INFO "Setting keyboard quirk to enable multimedia keys\n");
1491 return 0;
1494 static struct platform_driver acer_platform_driver = {
1495 .driver = {
1496 .name = "acer_acpi",
1497 .owner = THIS_MODULE,
1499 .probe = acer_platform_probe,
1500 .remove = acer_platform_remove,
1501 .suspend = acer_platform_suspend,
1502 .resume = acer_platform_resume,
1505 static struct platform_device *acer_platform_device;
1507 static int remove_sysfs(struct platform_device *device)
1509 #define remove_device_file(value, cap) \
1510 if (has_cap(cap)) \
1511 device_remove_file(&device->dev, &dev_attr_##value);
1513 remove_device_file(wireless, ACER_CAP_WIRELESS);
1514 remove_device_file(bluetooth, ACER_CAP_BLUETOOTH);
1515 remove_device_file(threeg, ACER_CAP_THREEG);
1516 remove_device_file(interface, ACER_CAP_ANY);
1517 remove_device_file(fan_temperature_override, ACER_CAP_TEMPERATURE_OVERRIDE);
1518 remove_device_file(touchpad, ACER_CAP_TOUCHPAD_READ);
1519 return 0;
1522 static int create_sysfs(void)
1524 int retval = -ENOMEM;
1526 #define add_device_file(value, cap) \
1527 if (has_cap(cap)) {\
1528 retval = device_create_file(&acer_platform_device->dev, &dev_attr_##value);\
1529 if (retval)\
1530 goto error;\
1533 add_device_file(wireless, ACER_CAP_WIRELESS);
1534 add_device_file(bluetooth, ACER_CAP_BLUETOOTH);
1535 add_device_file(threeg, ACER_CAP_THREEG);
1536 add_device_file(interface, ACER_CAP_ANY);
1537 add_device_file(fan_temperature_override, ACER_CAP_TEMPERATURE_OVERRIDE);
1538 add_device_file(touchpad, ACER_CAP_TOUCHPAD_READ);
1540 return 0;
1542 error:
1543 remove_sysfs(acer_platform_device);
1544 return retval;
1547 static int __init acer_acpi_init(void)
1549 printk(ACER_INFO "Acer Laptop ACPI Extras version %s\n",
1550 ACER_ACPI_VERSION);
1553 * Detect which WMI interface we're using.
1555 if (wmi_acer_has_guid(WMID_GUID1)) {
1556 DEBUG(0, "Detected Acer WMID interface\n");
1557 interface = &WMID_interface;
1558 } else if (wmi_acer_has_guid(AMW0_GUID1)) {
1559 DEBUG(0, "Detected Acer AMW0 interface\n");
1560 interface = &AMW0_interface;
1561 } else {
1562 printk(ACER_ERR "No or unsupported WMI interface, unable to load.\n");
1563 return -ENODEV;
1565 interface = &AMW0_interface;
1567 /* Find if this laptop requires any quirks */
1568 DEBUG(1, "Finding quirks\n");
1569 find_quirks();
1571 /* Now that we have a known interface, initialize it */
1572 DEBUG(1, "Initialising interface\n");
1573 if (interface->init)
1574 interface->init(interface);
1576 #ifdef CONFIG_PROC
1577 /* Create the proc entries */
1578 acer_proc_dir = proc_mkdir(PROC_ACER, acpi_root_dir);
1579 if (!acer_proc_dir) {
1580 printk(ACER_ERR "Unable to create /proc entries, aborting.\n");
1581 goto error_proc_mkdir;
1584 acer_proc_dir->owner = THIS_MODULE;
1585 if (add_proc_entries()) {
1586 printk(ACER_ERR "Unable to create /proc entries, aborting.\n");
1587 goto error_proc_add;
1589 #endif
1592 * Register the driver
1594 if (platform_driver_register(&acer_platform_driver)) {
1595 printk(ACER_ERR "Unable to register platform driver, aborting.\n");
1596 goto error_platform_register;
1598 acer_platform_device = platform_device_alloc("acer_acpi", -1);
1599 platform_device_add(acer_platform_device);
1601 create_sysfs();
1603 DEBUG(1, "Driver registered\n");
1605 /* Override any initial settings with values from the commandline */
1606 acer_commandline_init();
1608 return 0;
1610 error_platform_register:
1611 #ifdef CONFIG_PROC
1612 remove_proc_entries();
1613 error_proc_add:
1614 if (acer_proc_dir)
1615 remove_proc_entry(PROC_ACER, acpi_root_dir);
1616 error_proc_mkdir:
1617 if (interface->free)
1618 interface->free(interface);
1619 #endif
1620 return -ENODEV;
1623 static void __exit acer_acpi_exit(void)
1625 remove_sysfs(acer_platform_device);
1626 platform_device_del(acer_platform_device);
1627 platform_driver_unregister(&acer_platform_driver);
1629 #ifdef CONFIG_PROC
1630 remove_proc_entries();
1632 if (acer_proc_dir)
1633 remove_proc_entry(PROC_ACER, acpi_root_dir);
1634 #endif
1636 if (interface->free)
1637 interface->free(interface);
1639 printk(ACER_INFO "Acer Laptop ACPI Extras unloaded\n");
1640 return;
1643 module_init(acer_acpi_init);
1644 module_exit(acer_acpi_exit);