Add gitignore
[acer_acpi.git] / acer_acpi.c
blobfcb64ae10782576139acf9e526f43b34115eba68
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 I've 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 * Carlos Corbacho - added initial status support for wireless/ mail/
34 * bluetooth, added module parameter support to turn
35 * hardware/ LEDs on and off at module loading (thanks
36 * again to acerhk for the inspiration)
37 * Jim Ramsay - Figured out and added support for WMID interface
40 #define ACER_ACPI_VERSION "0.10.0"
43 * Comment the following line out to remove /proc support
45 #define CONFIG_PROC
47 #ifdef CONFIG_PROC
48 #define PROC_ACER "acer"
49 #endif
51 #include <linux/kernel.h>
52 #include <linux/module.h>
53 #include <linux/init.h>
54 #include <linux/types.h>
55 #include <linux/proc_fs.h>
56 #include <linux/delay.h>
57 #include <linux/version.h>
59 #if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,17)
60 #include <asm/uaccess.h>
61 #else
62 #include <linux/uaccess.h>
63 #endif
65 #include <linux/preempt.h>
66 #include <linux/io.h>
67 #include <linux/dmi.h>
68 #include <linux/backlight.h>
69 #include <linux/leds.h>
70 #include <linux/platform_device.h>
72 #include <acpi/acpi_drivers.h>
74 #include "wmi-acer.h"
76 /* Workaround needed for older kernels */
77 #ifndef bool
78 #define bool int
79 #endif
81 MODULE_AUTHOR("Mark Smith, Carlos Corbacho");
82 MODULE_DESCRIPTION("Acer Laptop ACPI Extras Driver");
83 MODULE_LICENSE("GPL");
85 #define ACER_LOGPREFIX "acer_acpi: "
86 #define ACER_ERR KERN_ERR ACER_LOGPREFIX
87 #define ACER_NOTICE KERN_NOTICE ACER_LOGPREFIX
88 #define ACER_INFO KERN_INFO ACER_LOGPREFIX
90 #define DEBUG(level, message...) { \
91 if (debug >= level) \
92 printk(KERN_DEBUG ACER_LOGPREFIX message);\
96 * The maximum temperature one can set for fan control override.
97 * Doesn't propably make much sense if over 80 degrees celsius though...
99 #define ACER_MAX_TEMPERATURE_OVERRIDE 150
102 * The following defines quirks to get some specific functions to work
103 * which are known to not be supported over ACPI (such as the mail LED
104 * on WMID based Acer's)
106 struct acer_quirks {
107 const char *vendor;
108 const char *model;
109 u16 quirks;
113 * Keyboard controller ports
115 #define ACER_KBD_STATUS_REG 0x64 /* Status register (R) */
116 #define ACER_KBD_CNTL_REG 0x64 /* Controller command register (W) */
117 #define ACER_KBD_DATA_REG 0x60 /* Keyboard data register (R/W) */
120 * Magic Number
121 * Meaning is unknown - this number is required for writing to ACPI for AMW0
122 * (it's also used in acerhk when directly accessing the EC)
124 #define ACER_AMW0_WRITE 0x9610
127 * Bit masks for the old AMW0 interface
129 #define ACER_AMW0_WIRELESS_MASK 0x35
130 #define ACER_AMW0_BLUETOOTH_MASK 0x34
131 #define ACER_AMW0_MAILLED_MASK 0x31
134 * Method IDs for new WMID interface
136 #define ACER_WMID_GET_WIRELESS_METHODID 1
137 #define ACER_WMID_GET_BLUETOOTH_METHODID 2
138 #define ACER_WMID_GET_BRIGHTNESS_METHODID 3
139 #define ACER_WMID_SET_WIRELESS_METHODID 4
140 #define ACER_WMID_SET_BLUETOOTH_METHODID 5
141 #define ACER_WMID_SET_BRIGHTNESS_METHODID 6
142 #define ACER_WMID_GET_THREEG_METHODID 10
143 #define ACER_WMID_SET_THREEG_METHODID 11
146 * Acer ACPI method GUIDs
148 #define AMW0_GUID1 "67C3371D-95A3-4C37-BB61-DD47B491DAAB"
149 #define WMID_GUID1 "6AF4F258-B401-42fd-BE91-3D4AC2D7C0D3"
152 * Interface capability flags
154 enum cap_flags {
155 ACER_CAP_MAILLED,
156 ACER_CAP_WIRELESS,
157 ACER_CAP_BLUETOOTH,
158 ACER_CAP_BRIGHTNESS,
159 ACER_CAP_THREEG,
160 ACER_CAP_TOUCHPAD_READ,
161 ACER_CAP_TEMPERATURE_OVERRIDE,
162 ACER_CAP_ANY,
166 * Interface type flags
168 enum interface_flags {
169 ACER_AMW0,
170 ACER_WMID,
174 * Presumed start states -
175 * On some AMW0 laptops, we do not yet know how to get the device status from
176 * the EC, so we must store this ourselves.
178 * Plus, we can't tell which features are enabled or disabled on a specific
179 * model - e.g. The 5020 series can _support_ bluetooth; but the 5021 has no
180 * bluetooth, whilst the 5024 does. However, the BIOS identifies both laptops
181 * as 5020, and you can add bluetooth later.
183 * Basically the code works like this:
184 * - On init, any values specified on the commandline are set.
185 * - For interfaces where the current values cannot be detected and which
186 * have not been set on the commandline, we set them to some sane default
187 * (disabled)
189 * See AMW0_init and acer_commandline_init
192 #define ACER_DEFAULT_WIRELESS 0
193 #define ACER_DEFAULT_BLUETOOTH 0
194 #define ACER_DEFAULT_MAILLED 0
195 #define ACER_DEFAULT_THREEG 0
197 static int max_brightness = 0xF;
199 static int wireless = -1;
200 static int bluetooth = -1;
201 static int mailled = -1;
202 static int brightness = -1;
203 static int threeg = -1;
204 static int fan_temperature_override = -1;
205 static int debug = 0;
206 static int force_series;
208 module_param(mailled, int, 0444);
209 module_param(wireless, int, 0444);
210 module_param(bluetooth, int, 0444);
211 module_param(brightness, int, 0444);
212 module_param(threeg, int, 0444);
213 module_param(force_series, int, 0444);
214 module_param(fan_temperature_override, int, 0444);
215 module_param(debug, int, 0664);
216 MODULE_PARM_DESC(wireless, "Set initial state of Wireless hardware");
217 MODULE_PARM_DESC(bluetooth, "Set initial state of Bluetooth hardware");
218 MODULE_PARM_DESC(mailled, "Set initial state of Mail LED");
219 MODULE_PARM_DESC(brightness, "Set initial LCD backlight brightness");
220 MODULE_PARM_DESC(threeg, "Set initial state of 3G hardware");
221 MODULE_PARM_DESC(fan_temperature_override, "Set initial state of the 'FAN temperature-override'");
222 MODULE_PARM_DESC(debug, "Debugging verbosity level (0=least 2=most)");
223 MODULE_PARM_DESC(force_series, "Force a different laptop series for extra features (5020, 5720 or 2490)");
225 #ifdef CONFIG_PROC
226 struct ProcItem {
227 const char *name;
228 char *(*read_func) (char *, u32);
229 unsigned long (*write_func) (const char *, unsigned long, u32);
230 unsigned int capability;
233 static struct proc_dir_entry *acer_proc_dir;
234 #endif
237 * Wait for the keyboard controller to become ready
239 static int wait_kbd_write(void)
241 int i = 0;
242 while ((inb(ACER_KBD_STATUS_REG) & 0x02) && (i < 10000)) {
243 udelay(50);
244 i++;
246 return -(i == 10000);
249 static void send_kbd_cmd(u8 cmd, u8 val)
251 preempt_disable();
252 if (!wait_kbd_write())
253 outb(cmd, ACER_KBD_CNTL_REG);
254 if (!wait_kbd_write())
255 outb(val, ACER_KBD_DATA_REG);
256 preempt_enable_no_resched();
259 static void set_keyboard_quirk(void)
261 send_kbd_cmd(0x59, 0x90);
264 /* Each low-level interface must define at least some of the following */
265 struct Interface {
267 * The ACPI device type
269 u32 type;
272 * The capabilities this interface provides
273 * In the future, these can be removed/added at runtime when we have a
274 * way of detecting what capabilities are /actually/ present on an
275 * interface
277 u32 capability;
280 * Initializes an interface, should allocate the interface-specific
281 * data
283 void (*init) (struct Interface *);
286 * Interface-specific private data member. Must *not* be touched by
287 * anyone outside of this struct
289 void *data;
292 /* The static interface pointer, points to the currently detected interface */
293 static struct Interface *interface;
295 struct acer_data {
296 int mailled;
297 int wireless;
298 int bluetooth;
299 int threeg;
300 int brightness;
304 * Embedded Controller quirks
305 * Some laptops require us to directly access the EC to either enable or query
306 * features that are not available through ACPI.
309 struct quirk_entry {
310 u8 wireless;
311 u8 mailled;
312 u8 brightness;
313 u8 touchpad;
314 u8 temperature_override;
315 u8 mmkeys;
316 u8 bluetooth;
317 u8 max_brightness;
320 static struct quirk_entry *quirks;
322 static void set_quirks(void)
324 if (quirks->mailled != 0) {
325 interface->capability |= ACER_CAP_MAILLED;
326 DEBUG(1, "Using EC direct-access quirk for mail LED\n");
329 if (quirks->touchpad != 0) {
330 interface->capability |= ACER_CAP_TOUCHPAD_READ;
331 DEBUG(1, "Using EC direct-access quirk for reading touchpad status\n");
334 if (quirks->temperature_override != 0) {
335 interface->capability |= ACER_CAP_TEMPERATURE_OVERRIDE;
336 DEBUG(1, "Using EC direct-access quirk for temperature override setting (fan)\n");
339 if (quirks->brightness != 0) {
340 interface->capability |= ACER_CAP_BRIGHTNESS;
341 DEBUG(1, "Using EC direct-access quirk for backlight brightness\n");
344 if (quirks->mmkeys != 0) {
345 set_keyboard_quirk();
346 printk(ACER_INFO "Setting keyboard quirk to enable multimedia keys\n");
349 if (quirks->bluetooth != 0) {
350 interface->capability |= ACER_CAP_BLUETOOTH;
351 DEBUG(1, "Using EC direct-access quirk for bluetooth\n");
354 if (quirks->wireless != 0) {
355 interface->capability |= ACER_CAP_WIRELESS;
356 DEBUG(1, "Using EC direct-access quirk for wireless\n");
359 if (quirks->max_brightness != 0) {
360 max_brightness = quirks->max_brightness;
361 DEBUG(1, "Changing maximum brightness level\n");
365 static int dmi_matched(struct dmi_system_id *dmi)
367 quirks = dmi->driver_data;
368 return 0;
371 static struct quirk_entry quirk_unknown = {
374 static struct quirk_entry quirk_acer_aspire_5020 = {
375 .wireless = 1,
376 .mailled = 2,
377 .brightness = 1,
378 .bluetooth = 1,
381 static struct quirk_entry quirk_acer_aspire_5680 = {
382 .mmkeys = 1,
385 static struct quirk_entry quirk_acer_aspire_9300 = {
386 .brightness = 2,
389 static struct quirk_entry quirk_acer_travelmate_2490 = {
390 .mmkeys = 1,
391 .mailled = 1,
392 .temperature_override = 1,
393 .touchpad = 1,
397 * This is similar to the Aspire 5020, but with a different wireless quirk
399 static struct quirk_entry quirk_acer_travelmate_5620 = {
400 .wireless = 2,
401 .mailled = 2,
402 .brightness = 1,
403 .bluetooth = 1,
406 static struct quirk_entry quirk_acer_travelmate_5720 = {
407 .max_brightness = 0x9,
408 .touchpad = 2,
409 .wireless = 2,
410 .bluetooth = 2,
411 .brightness = 1,
414 static struct dmi_system_id acer_quirks[] = {
416 .callback = dmi_matched,
417 .ident = "Acer Aspire 3020",
418 .matches = {
419 DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
420 DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 3020"),
422 .driver_data = &quirk_acer_aspire_5020,
425 .callback = dmi_matched,
426 .ident = "Acer Aspire 3040",
427 .matches = {
428 DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
429 DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 3040"),
431 .driver_data = &quirk_acer_aspire_5020,
434 .callback = dmi_matched,
435 .ident = "Acer Aspire 5020",
436 .matches = {
437 DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
438 DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5020"),
440 .driver_data = &quirk_acer_aspire_5020,
443 .callback = dmi_matched,
444 .ident = "Acer Aspire 5040",
445 .matches = {
446 DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
447 DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5040"),
449 .driver_data = &quirk_acer_aspire_5020,
452 .callback = dmi_matched,
453 .ident = "Acer Aspire 5560",
454 .matches = {
455 DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
456 DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5560"),
458 .driver_data = &quirk_acer_travelmate_5620,
461 .callback = dmi_matched,
462 .ident = "Acer Aspire 5650",
463 .matches = {
464 DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
465 DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5650"),
467 .driver_data = &quirk_acer_travelmate_2490,
470 .callback = dmi_matched,
471 .ident = "Acer Aspire 5680",
472 .matches = {
473 DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
474 DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 5680"),
476 .driver_data = &quirk_acer_aspire_5680,
479 .callback = dmi_matched,
480 .ident = "Acer Aspire 9300",
481 .matches = {
482 DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
483 DMI_MATCH(DMI_PRODUCT_NAME, "Aspire 9300"),
485 .driver_data = &quirk_acer_aspire_9300,
488 .callback = dmi_matched,
489 .ident = "Acer TravelMate 2420",
490 .matches = {
491 DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
492 DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 2420"),
494 .driver_data = &quirk_acer_aspire_5020,
497 .callback = dmi_matched,
498 .ident = "Acer TravelMate 2490",
499 .matches = {
500 DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
501 DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 2490"),
503 .driver_data = &quirk_acer_travelmate_2490,
506 .callback = dmi_matched,
507 .ident = "Acer TravelMate 5620",
508 .matches = {
509 DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
510 DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 5620"),
512 .driver_data = &quirk_acer_travelmate_5620,
515 .callback = dmi_matched,
516 .ident = "Acer TravelMate 5720",
517 .matches = {
518 DMI_MATCH(DMI_SYS_VENDOR, "Acer"),
519 DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 5720"),
521 .driver_data = &quirk_acer_travelmate_5720,
526 /* Find which quirks are needed for a particular vendor/ model pair */
527 static void find_quirks(void)
529 DEBUG (1, "Looking for quirks\n");
530 if (!force_series) {
531 dmi_check_system(acer_quirks);
532 } else if (force_series == 5020) {
533 DEBUG(0, "Forcing Acer Aspire 5020\n");
534 quirks = &quirk_acer_aspire_5020;
535 } else if (force_series == 2490) {
536 DEBUG(0, "Forcing Acer TravelMate 2490\n");
537 quirks = &quirk_acer_travelmate_2490;
538 } else if (force_series == 5620) {
539 DEBUG(0, "Forcing Acer TravelMate 5620\n");
540 quirks = &quirk_acer_travelmate_5620;
541 } else if (force_series == 5720) {
542 DEBUG(0, "Forcing Acer TravelMate 5720\n");
543 quirks = &quirk_acer_travelmate_5720;
546 if (quirks == NULL) {
547 DEBUG(1, "No quirks known for this laptop\n");
548 quirks = &quirk_unknown;
550 set_quirks();
554 * General interface convenience methods
557 static bool has_cap(u32 cap)
559 if ((interface->capability & cap) != 0) {
560 return 1;
562 return 0;
566 * Old interface (now known as the AMW0 interface)
568 struct WMAB_args {
569 u32 eax;
570 u32 ebx;
571 u32 ecx;
572 u32 edx;
575 static acpi_status WMAB_execute(struct WMAB_args *regbuf, struct acpi_buffer *result)
577 struct acpi_buffer input;
578 acpi_status status;
579 input.length = sizeof(struct WMAB_args);
580 input.pointer = (u8*)regbuf;
582 status = wmi_acer_evaluate_method(AMW0_GUID1, 1, 1, &input, result);
583 DEBUG(2, " Args: 0x%08x 0x%08x 0x%08x 0x%08x\n", regbuf->eax, regbuf->ebx, regbuf->ecx, regbuf->edx );
585 return status;
588 static void AMW0_init(struct Interface *iface) {
589 bool help = 0;
590 struct acer_data *data;
592 /* Allocate our private data structure */
593 iface->data = kmalloc(sizeof(struct acer_data), GFP_KERNEL);
594 data = (struct acer_data *) iface->data;
597 * If the commandline doesn't specify these, we need to force them to
598 * the default values
600 if (mailled == -1 && !quirks->mailled)
601 mailled = ACER_DEFAULT_MAILLED;
602 if (wireless == -1 && !quirks->wireless)
603 wireless = ACER_DEFAULT_WIRELESS;
604 if (bluetooth == -1 && !quirks->bluetooth)
605 bluetooth = ACER_DEFAULT_BLUETOOTH;
608 * Set the cached "current" values to impossible ones so that
609 * acer_commandline_init will definitely set them.
611 if (quirks->bluetooth == 0) {
612 help = 1;
613 data->bluetooth = -1;
614 printk(ACER_INFO "No EC data for reading bluetooth - bluetooth value when read will be a 'best guess'\n");
617 if (quirks->wireless == 0) {
618 help = 1;
619 printk(ACER_INFO "No EC data for reading wireless - wireless value when read will be a 'best guess'\n");
620 data->wireless = -1;
622 if (quirks->mailled == 0) {
623 help = 1;
624 printk(ACER_INFO "No EC data for reading mail LED - mail LED value when read will be a 'best guess'\n");
625 data->mailled = -1;
628 if (help) {
629 printk(ACER_INFO "We need more data from your laptop's Embedded Controller (EC) to better support it\n");
630 printk(ACER_INFO "Please see http://code.google.com/p/aceracpi/wiki/EmbeddedController on how to help\n");
634 static acpi_status AMW0_get_bool(bool *value, u32 cap, struct Interface *iface)
636 struct acer_data *data = iface->data;
637 u8 result;
639 DEBUG(2, " AMW0_get_bool: cap=%d\n", cap);
641 * On some models, we can read these values from the EC. On others,
642 * we use a stored value
644 switch (cap) {
645 case ACER_CAP_MAILLED:
646 switch (quirks->mailled) {
647 case 2:
648 ec_read(0x0A, &result);
649 *value = (result >> 7) & 0x01;
650 return 0;
651 default:
652 *value = data->mailled;
654 break;
655 case ACER_CAP_WIRELESS:
656 switch (quirks->wireless) {
657 case 1:
658 ec_read(0x0A, &result);
659 *value = (result >> 2) & 0x01;
660 return 0;
661 case 2:
662 ec_read(0x71, &result);
663 *value = result & 0x01;
664 return 0;
665 default:
666 *value = data->wireless;
668 break;
669 case ACER_CAP_BLUETOOTH:
670 switch (quirks->bluetooth) {
671 case 1:
672 ec_read(0x0A, &result);
673 *value = (result >> 4) & 0x01;
674 return 0;
675 case 2:
676 ec_read(0x71, &result);
677 *value = (result >> 1) & 0x01;
678 return 0;
679 default:
680 *value = data->bluetooth;
682 break;
683 case ACER_CAP_TOUCHPAD_READ:
684 switch (quirks->touchpad) {
685 case 2:
686 ec_read(0x74, &result);
687 *value = (result >> 3) & 0x01;
688 return 0;
689 default:
690 break;
692 default:
693 return AE_BAD_ADDRESS;
695 return AE_OK;
698 static acpi_status AMW0_set_bool(bool value, u32 cap, struct Interface *iface)
700 struct WMAB_args args;
701 acpi_status status;
703 args.eax = ACER_AMW0_WRITE;
704 args.ebx = value ? (1<<8) : 0;
706 switch (cap) {
707 case ACER_CAP_MAILLED:
708 args.ebx |= ACER_AMW0_MAILLED_MASK;
709 break;
710 case ACER_CAP_WIRELESS:
711 args.ebx |= ACER_AMW0_WIRELESS_MASK;
712 break;
713 case ACER_CAP_BLUETOOTH:
714 args.ebx |= ACER_AMW0_BLUETOOTH_MASK;
715 break;
716 default:
717 return AE_BAD_ADDRESS;
720 /* Actually do the set */
721 status = WMAB_execute(&args, NULL);
724 * Currently no way to query the state, so cache the new value on
725 * success
727 if (ACPI_SUCCESS(status)) {
728 struct acer_data *data = iface->data;
729 switch (cap) {
730 case ACER_CAP_MAILLED:
731 data->mailled = value;
732 break;
733 case ACER_CAP_WIRELESS:
734 data->wireless = value;
735 break;
736 case ACER_CAP_BLUETOOTH:
737 data->bluetooth = value;
738 break;
742 return status;
745 static acpi_status AMW0_get_u8(u8 *value, u32 cap, struct Interface *iface) {
746 switch (cap) {
747 case ACER_CAP_BRIGHTNESS:
748 switch (quirks->brightness) {
749 case 1:
750 return ec_read(0x83, value);
751 case 2:
752 return ec_read(0x85, value);
753 default:
754 return AE_BAD_ADDRESS;
756 break;
757 default:
758 return AE_BAD_ADDRESS;
760 return AE_OK;
763 static acpi_status AMW0_set_u8(u8 value, u32 cap, struct Interface *iface) {
764 switch (cap) {
765 case ACER_CAP_BRIGHTNESS:
766 switch (quirks->brightness) {
767 case 1:
768 return ec_write(0x83, value);
769 case 2:
770 return ec_write(0x85, value);
771 default:
772 return AE_BAD_ADDRESS;
773 break;
775 default:
776 return AE_BAD_ADDRESS;
778 return AE_OK;
781 static struct Interface AMW0_interface = {
782 .type = ACER_AMW0,
783 .capability = (
784 ACER_CAP_MAILLED |
785 ACER_CAP_WIRELESS |
786 ACER_CAP_BLUETOOTH
788 .init = AMW0_init,
792 * New interface (The WMID interface)
795 static void WMID_init(struct Interface *iface)
797 struct acer_data *data;
799 /* Allocate our private data structure */
800 iface->data = kmalloc(sizeof(struct acer_data), GFP_KERNEL);
801 data = (struct acer_data *) iface->data;
804 static acpi_status
805 WMI_execute_u32(u32 method_id, u32 in, u32 *out)
807 struct acpi_buffer input = { (acpi_size) sizeof(u32), (void *)(&in) };
808 struct acpi_buffer result = { ACPI_ALLOCATE_BUFFER, NULL };
809 union acpi_object *obj;
810 u32 tmp;
811 acpi_status status;
813 DEBUG(2, " WMI_execute_u32:\n");
814 status = wmi_acer_evaluate_method(WMID_GUID1, 1, method_id, &input, &result);
815 DEBUG(2, " In: 0x%08x\n", in);
817 if (ACPI_FAILURE(status))
818 return status;
820 obj = (union acpi_object *) result.pointer;
821 if (obj && obj->type == ACPI_TYPE_BUFFER && obj->buffer.length == sizeof(u32)) {
822 tmp = *((u32 *) obj->buffer.pointer);
823 DEBUG(2, " Out: 0x%08x\n", tmp);
824 } else {
825 tmp = 0;
826 if (obj) {
827 DEBUG(2, " Got unexpected result of type %d\n", obj->type);
828 } else {
829 DEBUG(2, " Got unexpected null result\n");
833 if (out)
834 *out = tmp;
836 if (result.length > 0 && result.pointer)
837 kfree(result.pointer);
839 DEBUG(2, " Returning from WMI_execute_u32:\n");
840 return status;
843 static acpi_status WMID_get_u8(u8 *value, u32 cap, struct Interface *iface) {
844 acpi_status status;
845 u32 result;
846 u32 method_id = 0;
848 DEBUG(2, " WMID_get_u8: cap=%d\n", cap);
849 switch (cap) {
850 case ACER_CAP_WIRELESS:
851 method_id = ACER_WMID_GET_WIRELESS_METHODID;
852 break;
853 case ACER_CAP_BLUETOOTH:
854 method_id = ACER_WMID_GET_BLUETOOTH_METHODID;
855 break;
856 case ACER_CAP_BRIGHTNESS:
857 method_id = ACER_WMID_GET_BRIGHTNESS_METHODID;
858 break;
859 case ACER_CAP_THREEG:
860 method_id = ACER_WMID_GET_THREEG_METHODID;
861 break;
862 case ACER_CAP_MAILLED:
863 if (quirks->mailled == 1) {
864 ec_read(0x9f, value);
865 *value &= 0x01;
866 return 0;
868 case ACER_CAP_TOUCHPAD_READ:
869 switch (quirks->touchpad) {
870 case 1:
871 ec_read(0x9e, value);
872 *value = 1 - ((*value >> 3) & 0x01);
873 return 0;
874 default:
875 break;
877 case ACER_CAP_TEMPERATURE_OVERRIDE:
878 if (quirks->temperature_override == 1) {
879 ec_read(0xa9, value);
880 return 0;
882 default:
883 return AE_BAD_ADDRESS;
885 status = WMI_execute_u32(method_id, 0, &result);
886 DEBUG(2, " WMI_execute_u32 status=%d:\n", status);
888 if (ACPI_SUCCESS(status))
889 *value = (u8)result;
891 DEBUG(2, " Returning from WMID_get_u8:\n");
892 return status;
895 static acpi_status WMID_set_u8(u8 value, u32 cap, struct Interface *iface) {
896 u32 method_id = 0;
898 switch (cap) {
899 case ACER_CAP_BRIGHTNESS:
900 method_id = ACER_WMID_SET_BRIGHTNESS_METHODID;
901 break;
902 case ACER_CAP_WIRELESS:
903 method_id = ACER_WMID_SET_WIRELESS_METHODID;
904 break;
905 case ACER_CAP_BLUETOOTH:
906 method_id = ACER_WMID_SET_BLUETOOTH_METHODID;
907 break;
908 case ACER_CAP_THREEG:
909 method_id = ACER_WMID_SET_THREEG_METHODID;
910 break;
911 case ACER_CAP_MAILLED:
912 if (quirks->mailled == 1) {
913 send_kbd_cmd(0x59, value ? 0x92 : 0x93);
914 return 0;
916 case ACER_CAP_TEMPERATURE_OVERRIDE:
917 if (quirks->temperature_override == 1) {
918 ec_write(0xa9, value);
919 return 0;
921 default:
922 return AE_BAD_ADDRESS;
924 return WMI_execute_u32(method_id, (u32)value, NULL);
928 static struct Interface WMID_interface = {
929 .type = ACER_WMID,
930 .capability = (
931 ACER_CAP_WIRELESS
932 | ACER_CAP_BRIGHTNESS
933 | ACER_CAP_BLUETOOTH
934 | ACER_CAP_THREEG
936 .init = WMID_init,
937 .data = NULL,
940 #ifdef CONFIG_PROC
942 * High-level Procfs file handlers
945 static int
946 dispatch_read(char *page, char **start, off_t off, int count, int *eof,
947 struct ProcItem *item)
949 char *p = page;
950 int len;
952 DEBUG(2, " dispatch_read: \n");
953 if (off == 0)
954 p = item->read_func(p, item->capability);
955 len = (p - page);
956 if (len <= off + count)
957 *eof = 1;
958 *start = page + off;
959 len -= off;
960 if (len > count)
961 len = count;
962 if (len < 0)
963 len = 0;
964 return len;
967 static int
968 dispatch_write(struct file *file, const char __user *buffer,
969 unsigned long count, struct ProcItem *item)
971 int result;
972 char *tmp_buffer;
975 * Arg buffer points to userspace memory, which can't be accessed
976 * directly. Since we're making a copy, zero-terminate the
977 * destination so that sscanf can be used on it safely.
979 tmp_buffer = kmalloc(count + 1, GFP_KERNEL);
980 if (copy_from_user(tmp_buffer, buffer, count)) {
981 result = -EFAULT;
982 } else {
983 tmp_buffer[count] = 0;
984 result = item->write_func(tmp_buffer, count, item->capability);
986 kfree(tmp_buffer);
987 return result;
989 #endif
992 * Generic Device (interface-independent)
995 static acpi_status get_bool(bool *value, u32 cap) {
996 acpi_status status = AE_BAD_ADDRESS;
997 u8 tmp = 0;
999 DEBUG(2, " get_bool: cap=%d, interface type=%d\n",
1000 cap, interface->type);
1001 switch (interface->type) {
1002 case ACER_AMW0:
1003 status = AMW0_get_bool(value, cap, interface);
1004 break;
1005 case ACER_WMID:
1006 status = WMID_get_u8(&tmp, cap, interface);
1007 *value = (tmp == 1) ? 1 : 0;
1008 break;
1010 DEBUG(2, " Returning from get_bool:\n");
1011 return status;
1014 static acpi_status set_bool(int value, u32 cap) {
1015 acpi_status status = AE_BAD_PARAMETER;
1017 DEBUG(2, " set_bool: cap=%d, interface type=%d, value=%d\n",
1018 cap, interface->type, value);
1019 if ((value == 0 || value == 1) && (interface->capability & cap)) {
1020 switch (interface->type) {
1021 case ACER_AMW0:
1022 status = AMW0_set_bool(value == 1, cap, interface);
1023 break;
1024 case ACER_WMID:
1025 status = WMID_set_u8(value == 1, cap, interface);
1026 break;
1029 return status;
1032 static acpi_status get_u8(u8 *value, u32 cap) {
1033 DEBUG(2, " get_u8: cap=%d\n", cap);
1034 switch (interface->type) {
1035 case ACER_AMW0:
1036 return AMW0_get_u8(value, cap, interface);
1037 break;
1038 case ACER_WMID:
1039 return WMID_get_u8(value, cap, interface);
1040 break;
1041 default:
1042 return AE_BAD_ADDRESS;
1046 static acpi_status set_u8(u8 value, u8 min, u8 max, u32 cap) {
1048 DEBUG(2, " set_u8: cap=%d, interface type=%d, value=%d\n",
1049 cap, interface->type, value);
1051 if ((value >= min && value <= max) && (interface->capability & cap) ) {
1052 switch (interface->type) {
1053 case ACER_AMW0:
1054 return AMW0_set_u8(value, cap, interface);
1055 case ACER_WMID:
1056 return WMID_set_u8(value, cap, interface);
1057 default:
1058 return AE_BAD_PARAMETER;
1061 return AE_BAD_PARAMETER;
1064 /* Each _u8 needs a small wrapper that sets the boundary values */
1065 static acpi_status set_brightness(u8 value)
1067 return set_u8(value, 0, max_brightness, ACER_CAP_BRIGHTNESS);
1070 static acpi_status set_temperature_override(u8 value)
1072 return set_u8(value, 0, ACER_MAX_TEMPERATURE_OVERRIDE, ACER_CAP_TEMPERATURE_OVERRIDE);
1075 static void __init acer_commandline_init(void)
1077 DEBUG(1, "Commandline args: mailled(%d) wireless(%d) bluetooth(%d) brightness(%d)\n",
1078 mailled, wireless, bluetooth, brightness);
1081 * These will all fail silently if the value given is invalid, or the
1082 * capability isn't available on the given interface
1084 set_bool(mailled, ACER_CAP_MAILLED);
1085 set_bool(wireless, ACER_CAP_WIRELESS);
1086 set_bool(bluetooth, ACER_CAP_BLUETOOTH);
1087 set_bool(threeg, ACER_CAP_THREEG);
1088 set_temperature_override(fan_temperature_override);
1089 set_brightness((u8)brightness);
1092 #ifdef CONFIG_PROC
1094 * Procfs interface (deprecated)
1096 static char *read_bool(char *p, u32 cap)
1098 bool result;
1099 acpi_status status;
1101 DEBUG(2, " read_bool: cap=%d\n", cap);
1102 status = get_bool(&result, cap);
1103 if (ACPI_SUCCESS(status))
1104 p += sprintf(p, "%d\n", result);
1105 else
1106 p += sprintf(p, "Read error" );
1107 return p;
1110 static unsigned long write_bool(const char *buffer, unsigned long count, u32 cap)
1112 int value;
1114 DEBUG(2, " write_bool: cap=%d, interface type=%d\n buffer=%s\n",
1115 cap, interface->type, buffer);
1117 if (sscanf(buffer, "%i", &value) == 1) {
1118 acpi_status status = set_bool(value, cap);
1119 if (ACPI_FAILURE(status))
1120 return -EINVAL;
1121 } else {
1122 return -EINVAL;
1124 return count;
1127 static char *read_u8(char *p, u32 cap)
1129 u8 result;
1130 acpi_status status;
1132 DEBUG(2, " read_u8: cap=%d\n", cap);
1133 status = get_u8(&result, cap);
1134 if (ACPI_SUCCESS(status))
1135 p += sprintf(p, "%u\n", result);
1136 else
1137 p += sprintf(p, "Read error" );
1138 return p;
1141 static unsigned long write_u8(const char *buffer, unsigned long count, u32 cap)
1143 int value;
1144 acpi_status (*set_method)(u8);
1146 /* Choose the appropriate set_u8 wrapper here, based on the capability */
1147 switch (cap) {
1148 case ACER_CAP_BRIGHTNESS:
1149 set_method = set_brightness;
1150 break;
1151 case ACER_CAP_TEMPERATURE_OVERRIDE:
1152 set_method = set_temperature_override;
1153 break;
1154 default:
1155 return -EINVAL;
1158 if (sscanf(buffer, "%i", &value) == 1) {
1159 acpi_status status = (*set_method)(value);
1160 if (ACPI_FAILURE(status))
1161 return -EINVAL;
1162 } else {
1163 return -EINVAL;
1165 return count;
1168 static char *read_version(char *p, u32 cap)
1170 p += sprintf(p, "%s\n", ACER_ACPI_VERSION);
1171 return p;
1174 static char *read_interface(char *p, u32 cap)
1176 p += sprintf(p, "%s\n", (interface->type == ACER_AMW0 ) ? "AMW0": "WMID");
1177 return p;
1180 struct ProcItem proc_items[] = {
1181 {"mailled", read_bool, write_bool, ACER_CAP_MAILLED},
1182 {"bluetooth", read_bool, write_bool, ACER_CAP_BLUETOOTH},
1183 {"wireless", read_bool, write_bool, ACER_CAP_WIRELESS},
1184 {"brightness", read_u8, write_u8, ACER_CAP_BRIGHTNESS},
1185 {"threeg", read_bool, write_bool, ACER_CAP_THREEG},
1186 {"touchpad", read_bool, NULL, ACER_CAP_TOUCHPAD_READ},
1187 {"fan_temperature_override", read_u8, write_u8, ACER_CAP_TEMPERATURE_OVERRIDE},
1188 {"version", read_version, NULL, ACER_CAP_ANY},
1189 {"interface", read_interface, NULL, ACER_CAP_ANY},
1190 {NULL}
1193 static int __init add_proc_entries(void)
1195 struct proc_dir_entry *proc;
1196 struct ProcItem *item;
1198 for (item = proc_items; item->name; ++item) {
1200 * Only add the proc file if the current interface actually
1201 * supports it
1203 if (interface->capability & item->capability) {
1204 proc = create_proc_read_entry(item->name,
1205 S_IFREG | S_IRUGO | S_IWUSR,
1206 acer_proc_dir,
1207 (read_proc_t *) dispatch_read,
1208 item);
1209 if (proc)
1210 proc->owner = THIS_MODULE;
1211 if (proc && item->write_func)
1212 proc->write_proc = (write_proc_t *) dispatch_write;
1216 return 0;
1219 static int __exit remove_proc_entries(void)
1221 struct ProcItem *item;
1223 for (item = proc_items; item->name; ++item)
1224 remove_proc_entry(item->name, acer_proc_dir);
1225 return 0;
1227 #endif
1230 * LED device (Mail LED only, no other LEDs known yet)
1232 static void mail_led_set(struct led_classdev *led_cdev, enum led_brightness value)
1234 bool tmp = value;
1235 set_bool(tmp, ACER_CAP_MAILLED);
1238 static struct led_classdev mail_led = {
1239 .name = "acer_acpi:mail",
1240 .brightness_set = mail_led_set,
1243 static void acer_led_init(struct device *dev)
1245 led_classdev_register(dev, &mail_led);
1248 static void acer_led_exit(void)
1250 led_classdev_unregister(&mail_led);
1253 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,18)
1255 * Backlight device
1257 static struct backlight_device *acer_backlight_device;
1259 static int read_brightness(struct backlight_device *bd)
1261 u8 value;
1262 get_u8(&value, ACER_CAP_BRIGHTNESS);
1263 return value;
1266 #if LINUX_VERSION_CODE <= KERNEL_VERSION(2,6,20)
1267 static int update_bl_status(struct backlight_device *bd)
1269 set_brightness(bd->props->brightness);
1270 return 0;
1273 static struct backlight_properties acer_backlight_properties = {
1274 .get_brightness = read_brightness,
1275 .update_status = update_bl_status,
1278 static int __init acer_backlight_init(struct device *dev)
1280 struct backlight_device *bd;
1282 DEBUG(1, "Loading backlight driver\n");
1283 bd = backlight_device_register("acer_acpi", dev, NULL, &acer_backlight_properties);
1284 if (IS_ERR(bd)) {
1285 printk(ACER_ERR "Could not register Acer backlight device\n");
1286 acer_backlight_device = NULL;
1287 return PTR_ERR(bd);
1290 acer_backlight_device = bd;
1292 bd->props->max_brightness = max_brightness;
1293 return 0;
1295 #else
1296 static int update_bl_status(struct backlight_device *bd)
1298 set_brightness(bd->props.brightness);
1299 return 0;
1302 static struct backlight_ops acer_backlight_ops = {
1303 .get_brightness = read_brightness,
1304 .update_status = update_bl_status,
1307 static int __init acer_backlight_init(struct device *dev)
1309 struct backlight_device *bd;
1311 DEBUG(1, "Loading backlight driver\n");
1312 bd = backlight_device_register("acer_acpi", dev, NULL, &acer_backlight_ops);
1313 if (IS_ERR(bd)) {
1314 printk(ACER_ERR "Could not register Acer backlight device\n");
1315 acer_backlight_device = NULL;
1316 return PTR_ERR(bd);
1319 acer_backlight_device = bd;
1321 bd->props.max_brightness = max_brightness;
1322 bd->props.brightness = read_brightness(NULL);
1323 backlight_update_status(bd);
1324 return 0;
1326 #endif
1328 static void __exit acer_backlight_exit(void)
1330 backlight_device_unregister(acer_backlight_device);
1332 #endif
1335 * Read/ write bool sysfs macro
1337 #define show_set_bool(value, cap) \
1338 static ssize_t \
1339 show_bool_##value(struct device *dev, struct device_attribute *attr, \
1340 char *buf) \
1342 bool result; \
1343 acpi_status status = get_bool(&result, cap); \
1344 if (ACPI_SUCCESS(status)) \
1345 return sprintf(buf, "%d\n", result); \
1346 return sprintf(buf, "Read error" ); \
1349 static ssize_t \
1350 set_bool_##value(struct device *dev, struct device_attribute *attr, \
1351 const char *buf, size_t count) \
1353 bool tmp = simple_strtoul(buf, NULL, 10); \
1354 acpi_status status = set_bool(tmp, cap); \
1355 if (ACPI_FAILURE(status)) \
1356 return -EINVAL; \
1357 return count; \
1359 static DEVICE_ATTR(value, S_IWUGO | S_IRUGO | S_IWUSR, \
1360 show_bool_##value, set_bool_##value);
1362 show_set_bool(wireless, ACER_CAP_WIRELESS);
1363 show_set_bool(bluetooth, ACER_CAP_BLUETOOTH);
1364 show_set_bool(threeg, ACER_CAP_THREEG);
1365 show_set_bool(fan_temperature_override, ACER_CAP_TEMPERATURE_OVERRIDE);
1368 * Read-only bool sysfs macro
1370 #define show_bool(value, cap) \
1371 static ssize_t \
1372 show_bool_##value(struct device *dev, struct device_attribute *attr, \
1373 char *buf) \
1375 bool result; \
1376 acpi_status status = get_bool(&result, cap); \
1377 if (ACPI_SUCCESS(status)) \
1378 return sprintf(buf, "%d\n", result); \
1379 return sprintf(buf, "Read error" ); \
1381 static DEVICE_ATTR(value, S_IWUGO | S_IRUGO | S_IWUSR, \
1382 show_bool_##value, NULL);
1384 show_bool(touchpad, ACER_CAP_TOUCHPAD_READ);
1387 * Read interface sysfs macro
1389 static ssize_t show_interface(struct device *dev, struct device_attribute *attr,
1390 char *buf)
1392 return sprintf(buf, "%s\n", (interface->type == ACER_AMW0 ) ? "AMW0" : "WMID");
1395 static DEVICE_ATTR(interface, S_IWUGO | S_IRUGO | S_IWUSR, show_interface, NULL);
1398 * Platform device
1400 static int __devinit acer_platform_probe(struct platform_device *device)
1402 if (has_cap(ACER_CAP_MAILLED))
1403 acer_led_init(&device->dev);
1404 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,18)
1405 if (has_cap(ACER_CAP_BRIGHTNESS))
1406 acer_backlight_init(&device->dev);
1407 #endif
1408 return 0;
1411 static int acer_platform_remove(struct platform_device *device)
1413 if (has_cap(ACER_CAP_MAILLED))
1414 acer_led_exit();
1415 #if LINUX_VERSION_CODE > KERNEL_VERSION(2,6,18)
1416 if (has_cap(ACER_CAP_BRIGHTNESS))
1417 acer_backlight_exit();
1418 #endif
1419 return 0;
1422 static int acer_platform_suspend(struct platform_device *device, pm_message_t state)
1425 * WMID fix for suspend-to-disk - save all current states now so we can
1426 * restore them on resume
1428 bool value;
1429 u8 u8value;
1430 struct acer_data *data = interface->data;
1432 #define save_bool_device(device, cap) \
1433 if (has_cap(cap)) {\
1434 get_bool(&value, cap);\
1435 data->device = value;\
1438 #define save_u8_device(device, cap) \
1439 if (has_cap(cap)) {\
1440 get_u8(&u8value, cap);\
1441 data->device = u8value;\
1444 if (interface->type == ACER_WMID) {
1445 save_bool_device(wireless, ACER_CAP_WIRELESS);
1446 save_bool_device(bluetooth, ACER_CAP_BLUETOOTH);
1447 save_bool_device(threeg, ACER_CAP_THREEG);
1448 save_u8_device(brightness, ACER_CAP_BRIGHTNESS);
1451 return 0;
1454 static int acer_platform_resume(struct platform_device *device)
1456 struct acer_data *data = interface->data;
1458 #define restore_bool_device(device, cap) \
1459 if (has_cap(cap))\
1460 set_bool(data->device, cap);\
1462 restore_bool_device(wireless, ACER_CAP_WIRELESS);
1463 restore_bool_device(bluetooth, ACER_CAP_BLUETOOTH);
1464 restore_bool_device(threeg, ACER_CAP_THREEG);
1465 restore_bool_device(mailled, ACER_CAP_MAILLED);
1467 if (has_cap(ACER_CAP_BRIGHTNESS))
1468 set_brightness((u8)data->brightness);
1470 /* Check if this laptop requires the keyboard quirk */
1471 if (quirks->mmkeys != 0) {
1472 set_keyboard_quirk();
1473 printk(ACER_INFO "Setting keyboard quirk to enable multimedia keys\n");
1476 return 0;
1479 static struct platform_driver acer_platform_driver = {
1480 .driver = {
1481 .name = "acer_acpi",
1482 .owner = THIS_MODULE,
1484 .probe = acer_platform_probe,
1485 .remove = acer_platform_remove,
1486 .suspend = acer_platform_suspend,
1487 .resume = acer_platform_resume,
1490 static struct platform_device *acer_platform_device;
1492 static int remove_sysfs(struct platform_device *device)
1494 #define remove_device_file(value, cap) \
1495 if (has_cap(cap)) \
1496 device_remove_file(&device->dev, &dev_attr_##value);
1498 remove_device_file(wireless, ACER_CAP_WIRELESS);
1499 remove_device_file(bluetooth, ACER_CAP_BLUETOOTH);
1500 remove_device_file(threeg, ACER_CAP_THREEG);
1501 remove_device_file(interface, ACER_CAP_ANY);
1502 remove_device_file(fan_temperature_override, ACER_CAP_TEMPERATURE_OVERRIDE);
1503 remove_device_file(touchpad, ACER_CAP_TOUCHPAD_READ);
1504 return 0;
1507 static int create_sysfs(void)
1509 int retval = -ENOMEM;
1511 #define add_device_file(value, cap) \
1512 if (has_cap(cap)) {\
1513 retval = device_create_file(&acer_platform_device->dev, &dev_attr_##value);\
1514 if (retval)\
1515 goto error;\
1518 add_device_file(wireless, ACER_CAP_WIRELESS);
1519 add_device_file(bluetooth, ACER_CAP_BLUETOOTH);
1520 add_device_file(threeg, ACER_CAP_THREEG);
1521 add_device_file(interface, ACER_CAP_ANY);
1522 add_device_file(fan_temperature_override, ACER_CAP_TEMPERATURE_OVERRIDE);
1523 add_device_file(touchpad, ACER_CAP_TOUCHPAD_READ);
1525 return 0;
1527 error:
1528 remove_sysfs(acer_platform_device);
1529 return retval;
1532 static int __init acer_acpi_init(void)
1534 printk(ACER_INFO "Acer Laptop ACPI Extras version %s\n",
1535 ACER_ACPI_VERSION);
1538 * Detect which WMI interface we're using.
1540 if (wmi_acer_has_guid(WMID_GUID1)) {
1541 DEBUG(0, "Detected Acer WMID interface\n");
1542 interface = &WMID_interface;
1543 } else if (wmi_acer_has_guid(AMW0_GUID1)) {
1544 DEBUG(0, "Detected Acer AMW0 interface\n");
1545 interface = &AMW0_interface;
1546 } else {
1547 printk(ACER_ERR "No or unsupported WMI interface, unable to load.\n");
1548 return -ENODEV;
1550 interface = &AMW0_interface;
1552 /* Find if this laptop requires any quirks */
1553 DEBUG(1, "Finding quirks\n");
1554 find_quirks();
1556 /* Now that we have a known interface, initialize it */
1557 DEBUG(1, "Initialising interface\n");
1558 if (interface->init)
1559 interface->init(interface);
1561 #ifdef CONFIG_PROC
1562 /* Create the proc entries */
1563 acer_proc_dir = proc_mkdir(PROC_ACER, acpi_root_dir);
1564 if (!acer_proc_dir) {
1565 printk(ACER_ERR "Unable to create /proc entries, aborting.\n");
1566 goto error_proc_mkdir;
1569 acer_proc_dir->owner = THIS_MODULE;
1570 if (add_proc_entries()) {
1571 printk(ACER_ERR "Unable to create /proc entries, aborting.\n");
1572 goto error_proc_add;
1574 #endif
1577 * Register the driver
1579 if (platform_driver_register(&acer_platform_driver)) {
1580 printk(ACER_ERR "Unable to register platform driver, aborting.\n");
1581 goto error_platform_register;
1583 acer_platform_device = platform_device_alloc("acer_acpi", -1);
1584 platform_device_add(acer_platform_device);
1586 create_sysfs();
1588 DEBUG(1, "Driver registered\n");
1590 /* Override any initial settings with values from the commandline */
1591 acer_commandline_init();
1593 return 0;
1595 error_platform_register:
1596 #ifdef CONFIG_PROC
1597 remove_proc_entries();
1598 error_proc_add:
1599 if (acer_proc_dir)
1600 remove_proc_entry(PROC_ACER, acpi_root_dir);
1601 error_proc_mkdir:
1602 if (interface->data != NULL)
1603 kfree(interface->data);
1604 #endif
1605 return -ENODEV;
1608 static void __exit acer_acpi_exit(void)
1610 remove_sysfs(acer_platform_device);
1611 platform_device_del(acer_platform_device);
1612 platform_driver_unregister(&acer_platform_driver);
1614 #ifdef CONFIG_PROC
1615 remove_proc_entries();
1617 if (acer_proc_dir)
1618 remove_proc_entry(PROC_ACER, acpi_root_dir);
1619 #endif
1621 if (interface->data != NULL)
1622 kfree(interface->data);
1624 printk(ACER_INFO "Acer Laptop ACPI Extras unloaded\n");
1625 return;
1628 module_init(acer_acpi_init);
1629 module_exit(acer_acpi_exit);