acer_acpi: Remove my name from Credits
[acer_acpi.git] / acer_acpi.c
blob191e25c6122fa9677345b26a848c4cc4fa26c64f
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/version.h>
54 #if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,17)
55 #include <asm/uaccess.h>
56 #else
57 #include <linux/uaccess.h>
58 #endif
60 #include <linux/io.h>
61 #include <linux/dmi.h>
62 #include <linux/backlight.h>
63 #include <linux/leds.h>
64 #include <linux/platform_device.h>
66 #include <acpi/acpi_drivers.h>
68 #include "wmi-acer.h"
70 /* Workaround needed for older kernels */
71 #ifndef bool
72 #define bool int
73 #endif
75 MODULE_AUTHOR("Mark Smith, Carlos Corbacho");
76 MODULE_DESCRIPTION("Acer Laptop ACPI Extras Driver");
77 MODULE_LICENSE("GPL");
79 #define ACER_LOGPREFIX "acer_acpi: "
80 #define ACER_ERR KERN_ERR ACER_LOGPREFIX
81 #define ACER_NOTICE KERN_NOTICE ACER_LOGPREFIX
82 #define ACER_INFO KERN_INFO ACER_LOGPREFIX
84 #define DEBUG(level, message...) { \
85 if (debug >= level) \
86 printk(KERN_DEBUG ACER_LOGPREFIX message);\
90 * The maximum temperature one can set for fan control override.
91 * Doesn't propably make much sense if over 80 degrees celsius though...
93 #define ACER_MAX_TEMPERATURE_OVERRIDE 150
96 * The following defines quirks to get some specific functions to work
97 * which are known to not be supported over ACPI (such as the mail LED
98 * on WMID based Acer's)
100 struct acer_quirks {
101 const char *vendor;
102 const char *model;
103 u16 quirks;
107 * Keyboard controller ports
109 #define ACER_KBD_STATUS_REG 0x64 /* Status register (R) */
110 #define ACER_KBD_CNTL_REG 0x64 /* Controller command register (W) */
111 #define ACER_KBD_DATA_REG 0x60 /* Keyboard data register (R/W) */
114 * Magic Number
115 * Meaning is unknown - this number is required for writing to ACPI for AMW0
116 * (it's also used in acerhk when directly accessing the EC)
118 #define ACER_AMW0_WRITE 0x9610
121 * Bit masks for the old AMW0 interface
123 #define ACER_AMW0_WIRELESS_MASK 0x35
124 #define ACER_AMW0_BLUETOOTH_MASK 0x34
125 #define ACER_AMW0_MAILLED_MASK 0x31
128 * Method IDs for new WMID interface
130 #define ACER_WMID_GET_WIRELESS_METHODID 1
131 #define ACER_WMID_GET_BLUETOOTH_METHODID 2
132 #define ACER_WMID_GET_BRIGHTNESS_METHODID 3
133 #define ACER_WMID_SET_WIRELESS_METHODID 4
134 #define ACER_WMID_SET_BLUETOOTH_METHODID 5
135 #define ACER_WMID_SET_BRIGHTNESS_METHODID 6
136 #define ACER_WMID_GET_THREEG_METHODID 10
137 #define ACER_WMID_SET_THREEG_METHODID 11
140 * Acer ACPI method GUIDs
142 #define AMW0_GUID1 "67C3371D-95A3-4C37-BB61-DD47B491DAAB"
143 #define WMID_GUID1 "6AF4F258-B401-42fd-BE91-3D4AC2D7C0D3"
146 * Interface capability flags
148 enum cap_flags {
149 ACER_CAP_MAILLED,
150 ACER_CAP_WIRELESS,
151 ACER_CAP_BLUETOOTH,
152 ACER_CAP_BRIGHTNESS,
153 ACER_CAP_THREEG,
154 ACER_CAP_TOUCHPAD_READ,
155 ACER_CAP_TEMPERATURE_OVERRIDE,
156 ACER_CAP_ANY,
160 * Interface type flags
162 enum interface_flags {
163 ACER_AMW0,
164 ACER_WMID,
168 * Presumed start states -
169 * On some AMW0 laptops, we do not yet know how to get the device status from
170 * the EC, so we must store this ourselves.
172 * Plus, we can't tell which features are enabled or disabled on a specific
173 * model - e.g. The 5020 series can _support_ bluetooth; but the 5021 has no
174 * bluetooth, whilst the 5024 does. However, the BIOS identifies both laptops
175 * as 5020, and you can add bluetooth later.
177 * Basically the code works like this:
178 * - On init, any values specified on the commandline are set.
179 * - For interfaces where the current values cannot be detected and which
180 * have not been set on the commandline, we set them to some sane default
181 * (disabled)
183 * See AMW0_init and acer_commandline_init
186 #define ACER_DEFAULT_WIRELESS 0
187 #define ACER_DEFAULT_BLUETOOTH 0
188 #define ACER_DEFAULT_MAILLED 0
189 #define ACER_DEFAULT_THREEG 0
191 static int max_brightness = 0xF;
193 static int wireless = -1;
194 static int bluetooth = -1;
195 static int mailled = -1;
196 static int brightness = -1;
197 static int threeg = -1;
198 static int fan_temperature_override = -1;
199 static int debug = 0;
200 static int force_series;
202 module_param(mailled, int, 0444);
203 module_param(wireless, int, 0444);
204 module_param(bluetooth, int, 0444);
205 module_param(brightness, int, 0444);
206 module_param(threeg, int, 0444);
207 module_param(force_series, int, 0444);
208 module_param(fan_temperature_override, int, 0444);
209 module_param(debug, int, 0664);
210 MODULE_PARM_DESC(wireless, "Set initial state of Wireless hardware");
211 MODULE_PARM_DESC(bluetooth, "Set initial state of Bluetooth hardware");
212 MODULE_PARM_DESC(mailled, "Set initial state of Mail LED");
213 MODULE_PARM_DESC(brightness, "Set initial LCD backlight brightness");
214 MODULE_PARM_DESC(threeg, "Set initial state of 3G hardware");
215 MODULE_PARM_DESC(fan_temperature_override, "Set initial state of the 'FAN temperature-override'");
216 MODULE_PARM_DESC(debug, "Debugging verbosity level (0=least 2=most)");
217 MODULE_PARM_DESC(force_series, "Force a different laptop series for extra features (5020, 5720 or 2490)");
219 #ifdef CONFIG_PROC
220 struct ProcItem {
221 const char *name;
222 char *(*read_func) (char *, u32);
223 unsigned long (*write_func) (const char *, unsigned long, u32);
224 unsigned int capability;
227 static struct proc_dir_entry *acer_proc_dir;
228 #endif
231 * Wait for the keyboard controller to become ready
233 static int wait_kbd_write(void)
235 int i = 0;
236 while ((inb(ACER_KBD_STATUS_REG) & 0x02) && (i < 10000)) {
237 udelay(50);
238 i++;
240 return -(i == 10000);
243 static void send_kbd_cmd(u8 cmd, u8 val)
245 preempt_disable();
246 if (!wait_kbd_write())
247 outb(cmd, ACER_KBD_CNTL_REG);
248 if (!wait_kbd_write())
249 outb(val, ACER_KBD_DATA_REG);
250 preempt_enable_no_resched();
253 static void set_keyboard_quirk(void)
255 send_kbd_cmd(0x59, 0x90);
258 /* Each low-level interface must define at least some of the following */
259 struct Interface {
261 * The ACPI device type
263 u32 type;
266 * The capabilities this interface provides
267 * In the future, these can be removed/added at runtime when we have a
268 * way of detecting what capabilities are /actually/ present on an
269 * interface
271 u32 capability;
274 * Initializes an interface, should allocate the interface-specific
275 * data
277 void (*init) (struct Interface *);
280 * Interface-specific private data member. Must *not* be touched by
281 * anyone outside of this struct
283 void *data;
286 /* The static interface pointer, points to the currently detected interface */
287 static struct Interface *interface;
289 struct acer_data {
290 int mailled;
291 int wireless;
292 int bluetooth;
293 int threeg;
294 int brightness;
298 * Embedded Controller quirks
299 * Some laptops require us to directly access the EC to either enable or query
300 * features that are not available through ACPI.
303 struct quirk_entry {
304 u8 wireless;
305 u8 mailled;
306 u8 brightness;
307 u8 touchpad;
308 u8 temperature_override;
309 u8 mmkeys;
310 u8 bluetooth;
311 u8 max_brightness;
314 static struct quirk_entry *quirks;
316 static void set_quirks(void)
318 if (quirks->mailled != 0) {
319 interface->capability |= ACER_CAP_MAILLED;
320 DEBUG(1, "Using EC direct-access quirk for mail LED\n");
323 if (quirks->touchpad != 0) {
324 interface->capability |= ACER_CAP_TOUCHPAD_READ;
325 DEBUG(1, "Using EC direct-access quirk for reading touchpad status\n");
328 if (quirks->temperature_override != 0) {
329 interface->capability |= ACER_CAP_TEMPERATURE_OVERRIDE;
330 DEBUG(1, "Using EC direct-access quirk for temperature override setting (fan)\n");
333 if (quirks->brightness != 0) {
334 interface->capability |= ACER_CAP_BRIGHTNESS;
335 DEBUG(1, "Using EC direct-access quirk for backlight brightness\n");
338 if (quirks->mmkeys != 0) {
339 set_keyboard_quirk();
340 printk(ACER_INFO "Setting keyboard quirk to enable multimedia keys\n");
343 if (quirks->bluetooth != 0) {
344 interface->capability |= ACER_CAP_BLUETOOTH;
345 DEBUG(1, "Using EC direct-access quirk for bluetooth\n");
348 if (quirks->wireless != 0) {
349 interface->capability |= ACER_CAP_WIRELESS;
350 DEBUG(1, "Using EC direct-access quirk for wireless\n");
353 if (quirks->max_brightness != 0) {
354 max_brightness = quirks->max_brightness;
355 DEBUG(1, "Changing maximum brightness level\n");
359 static int dmi_matched(struct dmi_system_id *dmi)
361 quirks = dmi->driver_data;
362 return 0;
365 static struct quirk_entry quirk_unknown = {
368 static struct quirk_entry quirk_acer_aspire_5020 = {
369 .wireless = 1,
370 .mailled = 2,
371 .brightness = 1,
372 .bluetooth = 1,
375 static struct quirk_entry quirk_acer_aspire_5680 = {
376 .mmkeys = 1,
379 static struct quirk_entry quirk_acer_aspire_9300 = {
380 .brightness = 2,
383 static struct quirk_entry quirk_acer_travelmate_2490 = {
384 .mmkeys = 1,
385 .mailled = 1,
386 .temperature_override = 1,
387 .touchpad = 1,
391 * This is similar to the Aspire 5020, but with a different wireless quirk
393 static struct quirk_entry quirk_acer_travelmate_5620 = {
394 .wireless = 2,
395 .mailled = 2,
396 .brightness = 1,
397 .bluetooth = 1,
400 static struct quirk_entry quirk_acer_travelmate_5720 = {
401 .max_brightness = 0x9,
402 .touchpad = 2,
403 .wireless = 2,
404 .bluetooth = 2,
405 .brightness = 1,
408 static struct dmi_system_id acer_quirks[] = {
410 .callback = dmi_matched,
411 .ident = "Acer Aspire 3020",
412 .matches = {
413 DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
414 DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 3020"),
416 .driver_data = &quirk_acer_aspire_5020,
419 .callback = dmi_matched,
420 .ident = "Acer Aspire 3040",
421 .matches = {
422 DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
423 DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 3040"),
425 .driver_data = &quirk_acer_aspire_5020,
428 .callback = dmi_matched,
429 .ident = "Acer Aspire 5020",
430 .matches = {
431 DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
432 DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5020"),
434 .driver_data = &quirk_acer_aspire_5020,
437 .callback = dmi_matched,
438 .ident = "Acer Aspire 5040",
439 .matches = {
440 DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
441 DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5040"),
443 .driver_data = &quirk_acer_aspire_5020,
446 .callback = dmi_matched,
447 .ident = "Acer Aspire 5560",
448 .matches = {
449 DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
450 DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5560"),
452 .driver_data = &quirk_acer_travelmate_5620,
455 .callback = dmi_matched,
456 .ident = "Acer Aspire 5650",
457 .matches = {
458 DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
459 DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5650"),
461 .driver_data = &quirk_acer_travelmate_2490,
464 .callback = dmi_matched,
465 .ident = "Acer Aspire 5680",
466 .matches = {
467 DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
468 DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5680"),
470 .driver_data = &quirk_acer_aspire_5680,
473 .callback = dmi_matched,
474 .ident = "Acer Aspire 9300",
475 .matches = {
476 DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
477 DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 9300"),
479 .driver_data = &quirk_acer_aspire_9300,
482 .callback = dmi_matched,
483 .ident = "Acer TravelMate 2420",
484 .matches = {
485 DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
486 DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 2420"),
488 .driver_data = &quirk_acer_aspire_5020,
491 .callback = dmi_matched,
492 .ident = "Acer TravelMate 2490",
493 .matches = {
494 DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
495 DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 2490"),
497 .driver_data = &quirk_acer_travelmate_2490,
500 .callback = dmi_matched,
501 .ident = "Acer TravelMate 5620",
502 .matches = {
503 DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
504 DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 5620"),
506 .driver_data = &quirk_acer_travelmate_5620,
509 .callback = dmi_matched,
510 .ident = "Acer TravelMate 5720",
511 .matches = {
512 DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
513 DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 5720"),
515 .driver_data = &quirk_acer_travelmate_5720,
520 /* Find which quirks are needed for a particular vendor/ model pair */
521 static void find_quirks(void)
523 DEBUG (1, "Looking for quirks\n");
524 if (!force_series) {
525 dmi_check_system(acer_quirks);
526 } else if (force_series == 5020) {
527 DEBUG(0, "Forcing Acer Aspire 5020\n");
528 quirks = &quirk_acer_aspire_5020;
529 } else if (force_series == 2490) {
530 DEBUG(0, "Forcing Acer TravelMate 2490\n");
531 quirks = &quirk_acer_travelmate_2490;
532 } else if (force_series == 5620) {
533 DEBUG(0, "Forcing Acer TravelMate 5620\n");
534 quirks = &quirk_acer_travelmate_5620;
535 } else if (force_series == 5720) {
536 DEBUG(0, "Forcing Acer TravelMate 5720\n");
537 quirks = &quirk_acer_travelmate_5720;
540 if (quirks == NULL) {
541 DEBUG(1, "No quirks known for this laptop\n");
542 quirks = &quirk_unknown;
544 set_quirks();
548 * General interface convenience methods
551 static bool has_cap(u32 cap)
553 if ((interface->capability & cap) != 0) {
554 return 1;
556 return 0;
560 * Old interface (now known as the AMW0 interface)
562 struct WMAB_args {
563 u32 eax;
564 u32 ebx;
565 u32 ecx;
566 u32 edx;
569 static acpi_status WMAB_execute(struct WMAB_args *regbuf, struct acpi_buffer *result)
571 struct acpi_buffer input;
572 acpi_status status;
573 input.length = sizeof(struct WMAB_args);
574 input.pointer = (u8*)regbuf;
576 status = wmi_acer_evaluate_method(AMW0_GUID1, 1, 1, &input, result);
577 DEBUG(2, " Args: 0x%08x 0x%08x 0x%08x 0x%08x\n", regbuf->eax, regbuf->ebx, regbuf->ecx, regbuf->edx );
579 return status;
582 static void AMW0_init(struct Interface *iface) {
583 bool help = 0;
584 struct acer_data *data;
586 /* Allocate our private data structure */
587 iface->data = kmalloc(sizeof(struct acer_data), GFP_KERNEL);
588 data = (struct acer_data *) iface->data;
591 * If the commandline doesn't specify these, we need to force them to
592 * the default values
594 if (mailled == -1 && !quirks->mailled)
595 mailled = ACER_DEFAULT_MAILLED;
596 if (wireless == -1 && !quirks->wireless)
597 wireless = ACER_DEFAULT_WIRELESS;
598 if (bluetooth == -1 && !quirks->bluetooth)
599 bluetooth = ACER_DEFAULT_BLUETOOTH;
602 * Set the cached "current" values to impossible ones so that
603 * acer_commandline_init will definitely set them.
605 if (quirks->bluetooth == 0) {
606 help = 1;
607 data->bluetooth = -1;
608 printk(ACER_INFO "No EC data for reading bluetooth - bluetooth value when read will be a 'best guess'\n");
611 if (quirks->wireless == 0) {
612 help = 1;
613 printk(ACER_INFO "No EC data for reading wireless - wireless value when read will be a 'best guess'\n");
614 data->wireless = -1;
616 if (quirks->mailled == 0) {
617 help = 1;
618 printk(ACER_INFO "No EC data for reading mail LED - mail LED value when read will be a 'best guess'\n");
619 data->mailled = -1;
622 if (help) {
623 printk(ACER_INFO "We need more data from your laptop's Embedded Controller (EC) to better support it\n");
624 printk(ACER_INFO "Please see http://code.google.com/p/aceracpi/wiki/EmbeddedController on how to help\n");
628 static acpi_status AMW0_get_bool(bool *value, u32 cap, struct Interface *iface)
630 struct acer_data *data = iface->data;
631 u8 result;
633 DEBUG(2, " AMW0_get_bool: cap=%d\n", cap);
635 * On some models, we can read these values from the EC. On others,
636 * we use a stored value
638 switch (cap) {
639 case ACER_CAP_MAILLED:
640 switch (quirks->mailled) {
641 case 2:
642 ec_read(0x0A, &result);
643 *value = (result >> 7) & 0x01;
644 return 0;
645 default:
646 *value = data->mailled;
648 break;
649 case ACER_CAP_WIRELESS:
650 switch (quirks->wireless) {
651 case 1:
652 ec_read(0x0A, &result);
653 *value = (result >> 2) & 0x01;
654 return 0;
655 case 2:
656 ec_read(0x71, &result);
657 *value = result & 0x01;
658 return 0;
659 default:
660 *value = data->wireless;
662 break;
663 case ACER_CAP_BLUETOOTH:
664 switch (quirks->bluetooth) {
665 case 1:
666 ec_read(0x0A, &result);
667 *value = (result >> 4) & 0x01;
668 return 0;
669 case 2:
670 ec_read(0x71, &result);
671 *value = (result >> 1) & 0x01;
672 return 0;
673 default:
674 *value = data->bluetooth;
676 break;
677 case ACER_CAP_TOUCHPAD_READ:
678 switch (quirks->touchpad) {
679 case 2:
680 ec_read(0x74, &result);
681 *value = (result >> 3) & 0x01;
682 return 0;
683 default:
684 break;
686 default:
687 return AE_BAD_ADDRESS;
689 return AE_OK;
692 static acpi_status AMW0_set_bool(bool value, u32 cap, struct Interface *iface)
694 struct WMAB_args args;
695 acpi_status status;
697 args.eax = ACER_AMW0_WRITE;
698 args.ebx = value ? (1<<8) : 0;
700 switch (cap) {
701 case ACER_CAP_MAILLED:
702 args.ebx |= ACER_AMW0_MAILLED_MASK;
703 break;
704 case ACER_CAP_WIRELESS:
705 args.ebx |= ACER_AMW0_WIRELESS_MASK;
706 break;
707 case ACER_CAP_BLUETOOTH:
708 args.ebx |= ACER_AMW0_BLUETOOTH_MASK;
709 break;
710 default:
711 return AE_BAD_ADDRESS;
714 /* Actually do the set */
715 status = WMAB_execute(&args, NULL);
718 * Currently no way to query the state, so cache the new value on
719 * success
721 if (ACPI_SUCCESS(status)) {
722 struct acer_data *data = iface->data;
723 switch (cap) {
724 case ACER_CAP_MAILLED:
725 data->mailled = value;
726 break;
727 case ACER_CAP_WIRELESS:
728 data->wireless = value;
729 break;
730 case ACER_CAP_BLUETOOTH:
731 data->bluetooth = value;
732 break;
736 return status;
739 static acpi_status AMW0_get_u8(u8 *value, u32 cap, struct Interface *iface) {
740 switch (cap) {
741 case ACER_CAP_BRIGHTNESS:
742 switch (quirks->brightness) {
743 case 1:
744 return ec_read(0x83, value);
745 case 2:
746 return ec_read(0x85, value);
747 default:
748 return AE_BAD_ADDRESS;
750 break;
751 default:
752 return AE_BAD_ADDRESS;
754 return AE_OK;
757 static acpi_status AMW0_set_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_write(0x83, value);
763 case 2:
764 return ec_write(0x85, value);
765 default:
766 return AE_BAD_ADDRESS;
767 break;
769 default:
770 return AE_BAD_ADDRESS;
772 return AE_OK;
775 static struct Interface AMW0_interface = {
776 .type = ACER_AMW0,
777 .capability = (
778 ACER_CAP_MAILLED |
779 ACER_CAP_WIRELESS |
780 ACER_CAP_BLUETOOTH
782 .init = AMW0_init,
786 * New interface (The WMID interface)
789 static void WMID_init(struct Interface *iface)
791 struct acer_data *data;
793 /* Allocate our private data structure */
794 iface->data = kmalloc(sizeof(struct acer_data), GFP_KERNEL);
795 data = (struct acer_data *) iface->data;
798 static acpi_status
799 WMI_execute_u32(u32 method_id, u32 in, u32 *out)
801 struct acpi_buffer input = { (acpi_size) sizeof(u32), (void *)(&in) };
802 struct acpi_buffer result = { ACPI_ALLOCATE_BUFFER, NULL };
803 union acpi_object *obj;
804 u32 tmp;
805 acpi_status status;
807 DEBUG(2, " WMI_execute_u32:\n");
808 status = wmi_acer_evaluate_method(WMID_GUID1, 1, method_id, &input, &result);
809 DEBUG(2, " In: 0x%08x\n", in);
811 if (ACPI_FAILURE(status))
812 return status;
814 obj = (union acpi_object *) result.pointer;
815 if (obj && obj->type == ACPI_TYPE_BUFFER && obj->buffer.length == sizeof(u32)) {
816 tmp = *((u32 *) obj->buffer.pointer);
817 DEBUG(2, " Out: 0x%08x\n", tmp);
818 } else {
819 tmp = 0;
820 if (obj) {
821 DEBUG(2, " Got unexpected result of type %d\n", obj->type);
822 } else {
823 DEBUG(2, " Got unexpected null result\n");
827 if (out)
828 *out = tmp;
830 if (result.length > 0 && result.pointer)
831 kfree(result.pointer);
833 DEBUG(2, " Returning from WMI_execute_u32:\n");
834 return status;
837 static acpi_status WMID_get_u8(u8 *value, u32 cap, struct Interface *iface) {
838 acpi_status status;
839 u32 result;
840 u32 method_id = 0;
842 DEBUG(2, " WMID_get_u8: cap=%d\n", cap);
843 switch (cap) {
844 case ACER_CAP_WIRELESS:
845 method_id = ACER_WMID_GET_WIRELESS_METHODID;
846 break;
847 case ACER_CAP_BLUETOOTH:
848 method_id = ACER_WMID_GET_BLUETOOTH_METHODID;
849 break;
850 case ACER_CAP_BRIGHTNESS:
851 method_id = ACER_WMID_GET_BRIGHTNESS_METHODID;
852 break;
853 case ACER_CAP_THREEG:
854 method_id = ACER_WMID_GET_THREEG_METHODID;
855 break;
856 case ACER_CAP_MAILLED:
857 if (quirks->mailled == 1) {
858 ec_read(0x9f, value);
859 *value &= 0x01;
860 return 0;
862 case ACER_CAP_TOUCHPAD_READ:
863 switch (quirks->touchpad) {
864 case 1:
865 ec_read(0x9e, value);
866 *value = 1 - ((*value >> 3) & 0x01);
867 return 0;
868 default:
869 break;
871 case ACER_CAP_TEMPERATURE_OVERRIDE:
872 if (quirks->temperature_override == 1) {
873 ec_read(0xa9, value);
874 return 0;
876 default:
877 return AE_BAD_ADDRESS;
879 status = WMI_execute_u32(method_id, 0, &result);
880 DEBUG(2, " WMI_execute_u32 status=%d:\n", status);
882 if (ACPI_SUCCESS(status))
883 *value = (u8)result;
885 DEBUG(2, " Returning from WMID_get_u8:\n");
886 return status;
889 static acpi_status WMID_set_u8(u8 value, u32 cap, struct Interface *iface) {
890 u32 method_id = 0;
892 switch (cap) {
893 case ACER_CAP_BRIGHTNESS:
894 method_id = ACER_WMID_SET_BRIGHTNESS_METHODID;
895 break;
896 case ACER_CAP_WIRELESS:
897 method_id = ACER_WMID_SET_WIRELESS_METHODID;
898 break;
899 case ACER_CAP_BLUETOOTH:
900 method_id = ACER_WMID_SET_BLUETOOTH_METHODID;
901 break;
902 case ACER_CAP_THREEG:
903 method_id = ACER_WMID_SET_THREEG_METHODID;
904 break;
905 case ACER_CAP_MAILLED:
906 if (quirks->mailled == 1) {
907 send_kbd_cmd(0x59, value ? 0x92 : 0x93);
908 return 0;
910 case ACER_CAP_TEMPERATURE_OVERRIDE:
911 if (quirks->temperature_override == 1) {
912 ec_write(0xa9, value);
913 return 0;
915 default:
916 return AE_BAD_ADDRESS;
918 return WMI_execute_u32(method_id, (u32)value, NULL);
922 static struct Interface WMID_interface = {
923 .type = ACER_WMID,
924 .capability = (
925 ACER_CAP_WIRELESS
926 | ACER_CAP_BRIGHTNESS
927 | ACER_CAP_BLUETOOTH
928 | ACER_CAP_THREEG
930 .init = WMID_init,
931 .data = NULL,
934 #ifdef CONFIG_PROC
936 * High-level Procfs file handlers
939 static int
940 dispatch_read(char *page, char **start, off_t off, int count, int *eof,
941 struct ProcItem *item)
943 char *p = page;
944 int len;
946 DEBUG(2, " dispatch_read: \n");
947 if (off == 0)
948 p = item->read_func(p, item->capability);
949 len = (p - page);
950 if (len <= off + count)
951 *eof = 1;
952 *start = page + off;
953 len -= off;
954 if (len > count)
955 len = count;
956 if (len < 0)
957 len = 0;
958 return len;
961 static int
962 dispatch_write(struct file *file, const char __user *buffer,
963 unsigned long count, struct ProcItem *item)
965 int result;
966 char *tmp_buffer;
969 * Arg buffer points to userspace memory, which can't be accessed
970 * directly. Since we're making a copy, zero-terminate the
971 * destination so that sscanf can be used on it safely.
973 tmp_buffer = kmalloc(count + 1, GFP_KERNEL);
974 if (copy_from_user(tmp_buffer, buffer, count)) {
975 result = -EFAULT;
976 } else {
977 tmp_buffer[count] = 0;
978 result = item->write_func(tmp_buffer, count, item->capability);
980 kfree(tmp_buffer);
981 return result;
983 #endif
986 * Generic Device (interface-independent)
989 static acpi_status get_bool(bool *value, u32 cap) {
990 acpi_status status = AE_BAD_ADDRESS;
991 u8 tmp = 0;
993 DEBUG(2, " get_bool: cap=%d, interface type=%d\n",
994 cap, interface->type);
995 switch (interface->type) {
996 case ACER_AMW0:
997 status = AMW0_get_bool(value, cap, interface);
998 break;
999 case ACER_WMID:
1000 status = WMID_get_u8(&tmp, cap, interface);
1001 *value = (tmp == 1) ? 1 : 0;
1002 break;
1004 DEBUG(2, " Returning from get_bool:\n");
1005 return status;
1008 static acpi_status set_bool(int value, u32 cap) {
1009 acpi_status status = AE_BAD_PARAMETER;
1011 DEBUG(2, " set_bool: cap=%d, interface type=%d, value=%d\n",
1012 cap, interface->type, value);
1013 if ((value == 0 || value == 1) && (interface->capability & cap)) {
1014 switch (interface->type) {
1015 case ACER_AMW0:
1016 status = AMW0_set_bool(value == 1, cap, interface);
1017 break;
1018 case ACER_WMID:
1019 status = WMID_set_u8(value == 1, cap, interface);
1020 break;
1023 return status;
1026 static acpi_status get_u8(u8 *value, u32 cap) {
1027 DEBUG(2, " get_u8: cap=%d\n", cap);
1028 switch (interface->type) {
1029 case ACER_AMW0:
1030 return AMW0_get_u8(value, cap, interface);
1031 break;
1032 case ACER_WMID:
1033 return WMID_get_u8(value, cap, interface);
1034 break;
1035 default:
1036 return AE_BAD_ADDRESS;
1040 static acpi_status set_u8(u8 value, u8 min, u8 max, u32 cap) {
1042 DEBUG(2, " set_u8: cap=%d, interface type=%d, value=%d\n",
1043 cap, interface->type, value);
1045 if ((value >= min && value <= max) && (interface->capability & cap) ) {
1046 switch (interface->type) {
1047 case ACER_AMW0:
1048 return AMW0_set_u8(value, cap, interface);
1049 case ACER_WMID:
1050 return WMID_set_u8(value, cap, interface);
1051 default:
1052 return AE_BAD_PARAMETER;
1055 return AE_BAD_PARAMETER;
1058 /* Each _u8 needs a small wrapper that sets the boundary values */
1059 static acpi_status set_brightness(u8 value)
1061 return set_u8(value, 0, max_brightness, ACER_CAP_BRIGHTNESS);
1064 static acpi_status set_temperature_override(u8 value)
1066 return set_u8(value, 0, ACER_MAX_TEMPERATURE_OVERRIDE, ACER_CAP_TEMPERATURE_OVERRIDE);
1069 static void __init acer_commandline_init(void)
1071 DEBUG(1, "Commandline args: mailled(%d) wireless(%d) bluetooth(%d) brightness(%d)\n",
1072 mailled, wireless, bluetooth, brightness);
1075 * These will all fail silently if the value given is invalid, or the
1076 * capability isn't available on the given interface
1078 set_bool(mailled, ACER_CAP_MAILLED);
1079 set_bool(wireless, ACER_CAP_WIRELESS);
1080 set_bool(bluetooth, ACER_CAP_BLUETOOTH);
1081 set_bool(threeg, ACER_CAP_THREEG);
1082 set_temperature_override(fan_temperature_override);
1083 set_brightness((u8)brightness);
1086 #ifdef CONFIG_PROC
1088 * Procfs interface (deprecated)
1090 static char *read_bool(char *p, u32 cap)
1092 bool result;
1093 acpi_status status;
1095 DEBUG(2, " read_bool: cap=%d\n", cap);
1096 status = get_bool(&result, cap);
1097 if (ACPI_SUCCESS(status))
1098 p += sprintf(p, "%d\n", result);
1099 else
1100 p += sprintf(p, "Read error" );
1101 return p;
1104 static unsigned long write_bool(const char *buffer, unsigned long count, u32 cap)
1106 int value;
1108 DEBUG(2, " write_bool: cap=%d, interface type=%d\n buffer=%s\n",
1109 cap, interface->type, buffer);
1111 if (sscanf(buffer, "%i", &value) == 1) {
1112 acpi_status status = set_bool(value, cap);
1113 if (ACPI_FAILURE(status))
1114 return -EINVAL;
1115 } else {
1116 return -EINVAL;
1118 return count;
1121 static char *read_u8(char *p, u32 cap)
1123 u8 result;
1124 acpi_status status;
1126 DEBUG(2, " read_u8: cap=%d\n", cap);
1127 status = get_u8(&result, cap);
1128 if (ACPI_SUCCESS(status))
1129 p += sprintf(p, "%u\n", result);
1130 else
1131 p += sprintf(p, "Read error" );
1132 return p;
1135 static unsigned long write_u8(const char *buffer, unsigned long count, u32 cap)
1137 int value;
1138 acpi_status (*set_method)(u8);
1140 /* Choose the appropriate set_u8 wrapper here, based on the capability */
1141 switch (cap) {
1142 case ACER_CAP_BRIGHTNESS:
1143 set_method = set_brightness;
1144 break;
1145 case ACER_CAP_TEMPERATURE_OVERRIDE:
1146 set_method = set_temperature_override;
1147 break;
1148 default:
1149 return -EINVAL;
1152 if (sscanf(buffer, "%i", &value) == 1) {
1153 acpi_status status = (*set_method)(value);
1154 if (ACPI_FAILURE(status))
1155 return -EINVAL;
1156 } else {
1157 return -EINVAL;
1159 return count;
1162 static char *read_version(char *p, u32 cap)
1164 p += sprintf(p, "%s\n", ACER_ACPI_VERSION);
1165 return p;
1168 static char *read_interface(char *p, u32 cap)
1170 p += sprintf(p, "%s\n", (interface->type == ACER_AMW0 ) ? "AMW0": "WMID");
1171 return p;
1174 struct ProcItem proc_items[] = {
1175 {"mailled", read_bool, write_bool, ACER_CAP_MAILLED},
1176 {"bluetooth", read_bool, write_bool, ACER_CAP_BLUETOOTH},
1177 {"wireless", read_bool, write_bool, ACER_CAP_WIRELESS},
1178 {"brightness", read_u8, write_u8, ACER_CAP_BRIGHTNESS},
1179 {"threeg", read_bool, write_bool, ACER_CAP_THREEG},
1180 {"touchpad", read_bool, NULL, ACER_CAP_TOUCHPAD_READ},
1181 {"fan_temperature_override", read_u8, write_u8, ACER_CAP_TEMPERATURE_OVERRIDE},
1182 {"version", read_version, NULL, ACER_CAP_ANY},
1183 {"interface", read_interface, NULL, ACER_CAP_ANY},
1184 {NULL}
1187 static int __init add_proc_entries(void)
1189 struct proc_dir_entry *proc;
1190 struct ProcItem *item;
1192 for (item = proc_items; item->name; ++item) {
1194 * Only add the proc file if the current interface actually
1195 * supports it
1197 if (interface->capability & item->capability) {
1198 proc = create_proc_read_entry(item->name,
1199 S_IFREG | S_IRUGO | S_IWUSR,
1200 acer_proc_dir,
1201 (read_proc_t *) dispatch_read,
1202 item);
1203 if (proc)
1204 proc->owner = THIS_MODULE;
1205 if (proc && item->write_func)
1206 proc->write_proc = (write_proc_t *) dispatch_write;
1210 return 0;
1213 static int __exit remove_proc_entries(void)
1215 struct ProcItem *item;
1217 for (item = proc_items; item->name; ++item)
1218 remove_proc_entry(item->name, acer_proc_dir);
1219 return 0;
1221 #endif
1224 * LED device (Mail LED only, no other LEDs known yet)
1226 static void mail_led_set(struct led_classdev *led_cdev, enum led_brightness value)
1228 bool tmp = value;
1229 set_bool(tmp, ACER_CAP_MAILLED);
1232 static struct led_classdev mail_led = {
1233 .name = "acer_acpi:mail",
1234 .brightness_set = mail_led_set,
1237 static void acer_led_init(struct device *dev)
1239 led_classdev_register(dev, &mail_led);
1242 static void acer_led_exit(void)
1244 led_classdev_unregister(&mail_led);
1247 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,18)
1249 * Backlight device
1251 static struct backlight_device *acer_backlight_device;
1253 static int read_brightness(struct backlight_device *bd)
1255 u8 value;
1256 get_u8(&value, ACER_CAP_BRIGHTNESS);
1257 return value;
1260 #if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,20)
1261 static int update_bl_status(struct backlight_device *bd)
1263 set_brightness(bd->props->brightness);
1264 return 0;
1267 static struct backlight_properties acer_backlight_properties = {
1268 .get_brightness = read_brightness,
1269 .update_status = update_bl_status,
1272 static int __init acer_backlight_init(struct device *dev)
1274 struct backlight_device *bd;
1276 DEBUG(1, "Loading backlight driver\n");
1277 bd = backlight_device_register("acer_acpi", dev, NULL, &acer_backlight_properties);
1278 if (IS_ERR(bd)) {
1279 printk(ACER_ERR "Could not register Acer backlight device\n");
1280 acer_backlight_device = NULL;
1281 return PTR_ERR(bd);
1284 acer_backlight_device = bd;
1286 bd->props->max_brightness = max_brightness;
1287 return 0;
1289 #else
1290 static int update_bl_status(struct backlight_device *bd)
1292 set_brightness(bd->props.brightness);
1293 return 0;
1296 static struct backlight_ops acer_backlight_ops = {
1297 .get_brightness = read_brightness,
1298 .update_status = update_bl_status,
1301 static int __init acer_backlight_init(struct device *dev)
1303 struct backlight_device *bd;
1305 DEBUG(1, "Loading backlight driver\n");
1306 bd = backlight_device_register("acer_acpi", dev, NULL, &acer_backlight_ops);
1307 if (IS_ERR(bd)) {
1308 printk(ACER_ERR "Could not register Acer backlight device\n");
1309 acer_backlight_device = NULL;
1310 return PTR_ERR(bd);
1313 acer_backlight_device = bd;
1315 bd->props.max_brightness = max_brightness;
1316 bd->props.brightness = read_brightness(NULL);
1317 backlight_update_status(bd);
1318 return 0;
1320 #endif
1322 static void __exit acer_backlight_exit(void)
1324 backlight_device_unregister(acer_backlight_device);
1326 #endif
1329 * Read/ write bool sysfs macro
1331 #define show_set_bool(value, cap) \
1332 static ssize_t \
1333 show_bool_##value(struct device *dev, struct device_attribute *attr, \
1334 char *buf) \
1336 bool result; \
1337 acpi_status status = get_bool(&result, cap); \
1338 if (ACPI_SUCCESS(status)) \
1339 return sprintf(buf, "%d\n", result); \
1340 return sprintf(buf, "Read error" ); \
1343 static ssize_t \
1344 set_bool_##value(struct device *dev, struct device_attribute *attr, \
1345 const char *buf, size_t count) \
1347 bool tmp = simple_strtoul(buf, NULL, 10); \
1348 acpi_status status = set_bool(tmp, cap); \
1349 if (ACPI_FAILURE(status)) \
1350 return -EINVAL; \
1351 return count; \
1353 static DEVICE_ATTR(value, S_IWUGO | S_IRUGO | S_IWUSR, \
1354 show_bool_##value, set_bool_##value);
1356 show_set_bool(wireless, ACER_CAP_WIRELESS);
1357 show_set_bool(bluetooth, ACER_CAP_BLUETOOTH);
1358 show_set_bool(threeg, ACER_CAP_THREEG);
1359 show_set_bool(fan_temperature_override, ACER_CAP_TEMPERATURE_OVERRIDE);
1362 * Read-only bool sysfs macro
1364 #define show_bool(value, cap) \
1365 static ssize_t \
1366 show_bool_##value(struct device *dev, struct device_attribute *attr, \
1367 char *buf) \
1369 bool result; \
1370 acpi_status status = get_bool(&result, cap); \
1371 if (ACPI_SUCCESS(status)) \
1372 return sprintf(buf, "%d\n", result); \
1373 return sprintf(buf, "Read error" ); \
1375 static DEVICE_ATTR(value, S_IWUGO | S_IRUGO | S_IWUSR, \
1376 show_bool_##value, NULL);
1378 show_bool(touchpad, ACER_CAP_TOUCHPAD_READ);
1381 * Read interface sysfs macro
1383 static ssize_t show_interface(struct device *dev, struct device_attribute *attr,
1384 char *buf)
1386 return sprintf(buf, "%s\n", (interface->type == ACER_AMW0 ) ? "AMW0" : "WMID");
1389 static DEVICE_ATTR(interface, S_IWUGO | S_IRUGO | S_IWUSR, show_interface, NULL);
1392 * Platform device
1394 static int __devinit acer_platform_probe(struct platform_device *device)
1396 if (has_cap(ACER_CAP_MAILLED))
1397 acer_led_init(&device->dev);
1398 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,18)
1399 if (has_cap(ACER_CAP_BRIGHTNESS))
1400 acer_backlight_init(&device->dev);
1401 #endif
1402 return 0;
1405 static int acer_platform_remove(struct platform_device *device)
1407 if (has_cap(ACER_CAP_MAILLED))
1408 acer_led_exit();
1409 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,18)
1410 if (has_cap(ACER_CAP_BRIGHTNESS))
1411 acer_backlight_exit();
1412 #endif
1413 return 0;
1416 static int acer_platform_suspend(struct platform_device *device, pm_message_t state)
1419 * WMID fix for suspend-to-disk - save all current states now so we can
1420 * restore them on resume
1422 bool value;
1423 u8 u8value;
1424 struct acer_data *data = interface->data;
1426 #define save_bool_device(device, cap) \
1427 if (has_cap(cap)) {\
1428 get_bool(&value, cap);\
1429 data->device = value;\
1432 #define save_u8_device(device, cap) \
1433 if (has_cap(cap)) {\
1434 get_u8(&u8value, cap);\
1435 data->device = u8value;\
1438 if (interface->type == ACER_WMID) {
1439 save_bool_device(wireless, ACER_CAP_WIRELESS);
1440 save_bool_device(bluetooth, ACER_CAP_BLUETOOTH);
1441 save_bool_device(threeg, ACER_CAP_THREEG);
1442 save_u8_device(brightness, ACER_CAP_BRIGHTNESS);
1445 return 0;
1448 static int acer_platform_resume(struct platform_device *device)
1450 struct acer_data *data = interface->data;
1452 #define restore_bool_device(device, cap) \
1453 if (has_cap(cap))\
1454 set_bool(data->device, cap);\
1456 restore_bool_device(wireless, ACER_CAP_WIRELESS);
1457 restore_bool_device(bluetooth, ACER_CAP_BLUETOOTH);
1458 restore_bool_device(threeg, ACER_CAP_THREEG);
1459 restore_bool_device(mailled, ACER_CAP_MAILLED);
1461 if (has_cap(ACER_CAP_BRIGHTNESS))
1462 set_brightness((u8)data->brightness);
1464 /* Check if this laptop requires the keyboard quirk */
1465 if (quirks->mmkeys != 0) {
1466 set_keyboard_quirk();
1467 printk(ACER_INFO "Setting keyboard quirk to enable multimedia keys\n");
1470 return 0;
1473 static struct platform_driver acer_platform_driver = {
1474 .driver = {
1475 .name = "acer_acpi",
1476 .owner = THIS_MODULE,
1478 .probe = acer_platform_probe,
1479 .remove = acer_platform_remove,
1480 .suspend = acer_platform_suspend,
1481 .resume = acer_platform_resume,
1484 static struct platform_device *acer_platform_device;
1486 static int remove_sysfs(struct platform_device *device)
1488 #define remove_device_file(value, cap) \
1489 if (has_cap(cap)) \
1490 device_remove_file(&device->dev, &dev_attr_##value);
1492 remove_device_file(wireless, ACER_CAP_WIRELESS);
1493 remove_device_file(bluetooth, ACER_CAP_BLUETOOTH);
1494 remove_device_file(threeg, ACER_CAP_THREEG);
1495 remove_device_file(interface, ACER_CAP_ANY);
1496 remove_device_file(fan_temperature_override, ACER_CAP_TEMPERATURE_OVERRIDE);
1497 remove_device_file(touchpad, ACER_CAP_TOUCHPAD_READ);
1498 return 0;
1501 static int create_sysfs(void)
1503 int retval = -ENOMEM;
1505 #define add_device_file(value, cap) \
1506 if (has_cap(cap)) {\
1507 retval = device_create_file(&acer_platform_device->dev, &dev_attr_##value);\
1508 if (retval)\
1509 goto error;\
1512 add_device_file(wireless, ACER_CAP_WIRELESS);
1513 add_device_file(bluetooth, ACER_CAP_BLUETOOTH);
1514 add_device_file(threeg, ACER_CAP_THREEG);
1515 add_device_file(interface, ACER_CAP_ANY);
1516 add_device_file(fan_temperature_override, ACER_CAP_TEMPERATURE_OVERRIDE);
1517 add_device_file(touchpad, ACER_CAP_TOUCHPAD_READ);
1519 return 0;
1521 error:
1522 remove_sysfs(acer_platform_device);
1523 return retval;
1526 static int __init acer_acpi_init(void)
1528 printk(ACER_INFO "Acer Laptop ACPI Extras version %s\n",
1529 ACER_ACPI_VERSION);
1532 * Detect which WMI interface we're using.
1534 if (wmi_acer_has_guid(WMID_GUID1)) {
1535 DEBUG(0, "Detected Acer WMID interface\n");
1536 interface = &WMID_interface;
1537 } else if (wmi_acer_has_guid(AMW0_GUID1)) {
1538 DEBUG(0, "Detected Acer AMW0 interface\n");
1539 interface = &AMW0_interface;
1540 } else {
1541 printk(ACER_ERR "No or unsupported WMI interface, unable to load.\n");
1542 return -ENODEV;
1544 interface = &AMW0_interface;
1546 /* Find if this laptop requires any quirks */
1547 DEBUG(1, "Finding quirks\n");
1548 find_quirks();
1550 /* Now that we have a known interface, initialize it */
1551 DEBUG(1, "Initialising interface\n");
1552 if (interface->init)
1553 interface->init(interface);
1555 #ifdef CONFIG_PROC
1556 /* Create the proc entries */
1557 acer_proc_dir = proc_mkdir(PROC_ACER, acpi_root_dir);
1558 if (!acer_proc_dir) {
1559 printk(ACER_ERR "Unable to create /proc entries, aborting.\n");
1560 goto error_proc_mkdir;
1563 acer_proc_dir->owner = THIS_MODULE;
1564 if (add_proc_entries()) {
1565 printk(ACER_ERR "Unable to create /proc entries, aborting.\n");
1566 goto error_proc_add;
1568 #endif
1571 * Register the driver
1573 if (platform_driver_register(&acer_platform_driver)) {
1574 printk(ACER_ERR "Unable to register platform driver, aborting.\n");
1575 goto error_platform_register;
1577 acer_platform_device = platform_device_alloc("acer_acpi", -1);
1578 platform_device_add(acer_platform_device);
1580 create_sysfs();
1582 DEBUG(1, "Driver registered\n");
1584 /* Override any initial settings with values from the commandline */
1585 acer_commandline_init();
1587 return 0;
1589 error_platform_register:
1590 #ifdef CONFIG_PROC
1591 remove_proc_entries();
1592 error_proc_add:
1593 if (acer_proc_dir)
1594 remove_proc_entry(PROC_ACER, acpi_root_dir);
1595 error_proc_mkdir:
1596 if (interface->data != NULL)
1597 kfree(interface->data);
1598 #endif
1599 return -ENODEV;
1602 static void __exit acer_acpi_exit(void)
1604 remove_sysfs(acer_platform_device);
1605 platform_device_del(acer_platform_device);
1606 platform_driver_unregister(&acer_platform_driver);
1608 #ifdef CONFIG_PROC
1609 remove_proc_entries();
1611 if (acer_proc_dir)
1612 remove_proc_entry(PROC_ACER, acpi_root_dir);
1613 #endif
1615 if (interface->data != NULL)
1616 kfree(interface->data);
1618 printk(ACER_INFO "Acer Laptop ACPI Extras unloaded\n");
1619 return;
1622 module_init(acer_acpi_init);
1623 module_exit(acer_acpi_exit);