clean
[linux-2.4.21-pre4.git] / drivers / acpi / driver.c
1 /*
2  *  driver.c - ACPI driver
3  *
4  *  Copyright (C) 2000 Andrew Henroid
5  *  Copyright (C) 2001 Andrew Grover
6  *
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.
11  *
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.
16  *
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
20  */
21 /*
22  * Changes
23  * David Woodhouse <dwmw2@redhat.com> 2000-12-6
24  * - Fix interruptible_sleep_on() races
25  * Andrew Grover <andrew.grover@intel.com> 2001-2-28
26  * - Major revamping
27  * Peter Breuer <ptb@it.uc3m.es> 2001-5-20
28  * - parse boot time params.
29  */
30
31 #include <linux/config.h>
32 #include <linux/module.h>
33 #include <linux/init.h>
34 #include <linux/kernel.h>
35 #include <linux/types.h>
36 #include <linux/slab.h>
37 #include <linux/proc_fs.h>
38 #include <linux/sysctl.h>
39 #include <linux/pm.h>
40 #include <linux/acpi.h>
41 #include <asm/uaccess.h>
42 #include "acpi.h"
43
44
45 #define _COMPONENT      OS_DEPENDENT
46         MODULE_NAME     ("driver")
47
48 FADT_DESCRIPTOR acpi_fadt;
49
50 static int acpi_disabled = 0;
51
52 enum acpi_blacklist_predicates
53 {
54         all_versions,
55         less_than_or_equal,
56         equal,
57         greater_than_or_equal,
58 };
59
60 struct acpi_blacklist_item
61 {
62         char oem_id[7];
63         char oem_table_id[9];
64         u32  oem_revision;
65         enum acpi_blacklist_predicates oem_revision_predicate;
66 };
67
68 /*
69  * Currently, this blacklists based on items in the FADT. We may want to
70  * expand this to using other ACPI tables in the future, too.
71  */
72 static struct acpi_blacklist_item acpi_blacklist[] __initdata = 
73 {
74         {"TOSHIB", "750     ", 0x970814, less_than_or_equal}, /* Portege 7020, BIOS 8.10 */
75         {""}
76 };
77
78 int
79 acpi_blacklisted(FADT_DESCRIPTOR *fadt)
80 {
81         int i = 0;
82
83         while (acpi_blacklist[i].oem_id[0] != '\0')
84         {
85                 if (strncmp(acpi_blacklist[i].oem_id, fadt->header.oem_id, 6)) {
86                         i++;
87                         continue;
88                 }
89
90                 if (strncmp(acpi_blacklist[i].oem_table_id, fadt->header.oem_table_id, 8)) {
91                         i++;
92                         continue;
93                 }
94
95                 if (acpi_blacklist[i].oem_revision_predicate == all_versions)
96                         return TRUE;
97
98                 if (acpi_blacklist[i].oem_revision_predicate == less_than_or_equal
99                     && fadt->header.oem_revision <= acpi_blacklist[i].oem_revision)
100                         return TRUE;
101
102                 if (acpi_blacklist[i].oem_revision_predicate == greater_than_or_equal
103                     && fadt->header.oem_revision >= acpi_blacklist[i].oem_revision)
104                         return TRUE;
105
106                 if (acpi_blacklist[i].oem_revision_predicate == equal
107                     && fadt->header.oem_revision == acpi_blacklist[i].oem_revision)
108                         return TRUE;
109
110                 i++;
111         }
112
113         return FALSE;
114 }
115
116 /*
117  * Start the interpreter
118  */
119 int
120 acpi_init(void)
121 {
122         acpi_buffer             buffer;
123         acpi_system_info        sys_info;
124
125         if (PM_IS_ACTIVE()) {
126                 printk(KERN_NOTICE "ACPI: APM is already active, exiting\n");
127                 return -ENODEV;
128         }
129
130         if (acpi_disabled) {
131                 printk(KERN_NOTICE "ACPI: disabled by cmdline, exiting\n");
132                 return -ENODEV;
133         }
134
135         if (!ACPI_SUCCESS(acpi_initialize_subsystem())) {
136                 printk(KERN_ERR "ACPI: Driver initialization failed\n");
137                 return -ENODEV;
138         }
139
140         /* from this point on, on error we must call acpi_terminate() */
141         if (!ACPI_SUCCESS(acpi_load_tables())) {
142                 printk(KERN_ERR "ACPI: System description table load failed\n");
143                 acpi_terminate();
144                 return -ENODEV;
145         }
146
147         /* get a separate copy of the FADT for use by other drivers */
148         memset(&acpi_fadt, 0, sizeof(acpi_fadt));
149         buffer.pointer = &acpi_fadt;
150         buffer.length = sizeof(acpi_fadt);
151
152         if (!ACPI_SUCCESS(acpi_get_table(ACPI_TABLE_FADT, 1, &buffer))) {
153                 printk(KERN_ERR "ACPI: Could not get FADT\n");
154                 acpi_terminate();
155                 return -ENODEV;
156         }
157
158         if (acpi_blacklisted(&acpi_fadt)) {
159                 printk(KERN_ERR "ACPI: On blacklist -- BIOS not fully ACPI compliant\n");
160                 acpi_terminate();
161                 return -ENODEV;
162         }
163
164         buffer.length  = sizeof(sys_info);
165         buffer.pointer = &sys_info;
166
167         if (!ACPI_SUCCESS (acpi_get_system_info(&buffer))) {
168                 printk(KERN_ERR "ACPI: Could not get system info\n");
169                 acpi_terminate();
170                 return -ENODEV;
171         }
172
173         printk(KERN_INFO "ACPI: Core Subsystem version [%x]\n", sys_info.acpi_ca_version);
174
175         if (!ACPI_SUCCESS(acpi_enable_subsystem(ACPI_FULL_INITIALIZATION))) {
176                 printk(KERN_ERR "ACPI: Subsystem enable failed\n");
177                 acpi_terminate();
178                 return -ENODEV;
179         }
180
181         printk(KERN_INFO "ACPI: Subsystem enabled\n");
182
183         pm_active = 1;
184
185         return 0;
186 }
187
188 /*
189  * Terminate the interpreter
190  */
191 void
192 acpi_exit(void)
193 {
194         acpi_terminate();
195
196         pm_active = 0;
197
198         printk(KERN_ERR "ACPI: Subsystem disabled\n");
199 }
200
201 module_init(acpi_init);
202 module_exit(acpi_exit);
203
204 #ifndef MODULE
205 static int __init acpi_setup(char *str) {
206         while (str && *str) {
207         if (strncmp(str, "off", 3) == 0)
208                 acpi_disabled = 1;
209         str = strchr(str, ',');
210         if (str)
211                 str += strspn(str, ", \t");
212         }
213         return 1;
214 }
215
216 __setup("acpi=", acpi_setup);
217 #endif