Commit | Line | Data |
---|---|---|
1da177e4 LT |
1 | #include <linux/types.h> |
2 | #include <linux/kernel.h> | |
3 | #include <linux/string.h> | |
4 | #include <linux/init.h> | |
5 | #include <linux/module.h> | |
6 | #include <linux/slab.h> | |
7 | #include <linux/acpi.h> | |
8 | #include <asm/io.h> | |
9 | #include <linux/pm.h> | |
10 | #include <asm/system.h> | |
11 | #include <linux/dmi.h> | |
12 | #include <linux/bootmem.h> | |
13 | ||
14 | ||
15 | struct dmi_header | |
16 | { | |
17 | u8 type; | |
18 | u8 length; | |
19 | u16 handle; | |
20 | }; | |
21 | ||
22 | #undef DMI_DEBUG | |
23 | ||
24 | #ifdef DMI_DEBUG | |
25 | #define dmi_printk(x) printk x | |
26 | #else | |
27 | #define dmi_printk(x) | |
28 | #endif | |
29 | ||
30 | static char * __init dmi_string(struct dmi_header *dm, u8 s) | |
31 | { | |
32 | u8 *bp=(u8 *)dm; | |
33 | bp+=dm->length; | |
34 | if(!s) | |
35 | return ""; | |
36 | s--; | |
37 | while(s>0 && *bp) | |
38 | { | |
39 | bp+=strlen(bp); | |
40 | bp++; | |
41 | s--; | |
42 | } | |
43 | return bp; | |
44 | } | |
45 | ||
46 | /* | |
47 | * We have to be cautious here. We have seen BIOSes with DMI pointers | |
48 | * pointing to completely the wrong place for example | |
49 | */ | |
50 | ||
51 | static int __init dmi_table(u32 base, int len, int num, void (*decode)(struct dmi_header *)) | |
52 | { | |
53 | u8 *buf; | |
54 | struct dmi_header *dm; | |
55 | u8 *data; | |
56 | int i=0; | |
57 | ||
58 | buf = bt_ioremap(base, len); | |
59 | if(buf==NULL) | |
60 | return -1; | |
61 | ||
62 | data = buf; | |
63 | ||
64 | /* | |
65 | * Stop when we see all the items the table claimed to have | |
66 | * OR we run off the end of the table (also happens) | |
67 | */ | |
68 | ||
69 | while(i<num && data-buf+sizeof(struct dmi_header)<=len) | |
70 | { | |
71 | dm=(struct dmi_header *)data; | |
72 | /* | |
73 | * We want to know the total length (formated area and strings) | |
74 | * before decoding to make sure we won't run off the table in | |
75 | * dmi_decode or dmi_string | |
76 | */ | |
77 | data+=dm->length; | |
78 | while(data-buf<len-1 && (data[0] || data[1])) | |
79 | data++; | |
80 | if(data-buf<len-1) | |
81 | decode(dm); | |
82 | data+=2; | |
83 | i++; | |
84 | } | |
85 | bt_iounmap(buf, len); | |
86 | return 0; | |
87 | } | |
88 | ||
89 | ||
90 | inline static int __init dmi_checksum(u8 *buf) | |
91 | { | |
92 | u8 sum=0; | |
93 | int a; | |
94 | ||
95 | for(a=0; a<15; a++) | |
96 | sum+=buf[a]; | |
97 | return (sum==0); | |
98 | } | |
99 | ||
100 | static int __init dmi_iterate(void (*decode)(struct dmi_header *)) | |
101 | { | |
102 | u8 buf[15]; | |
103 | char __iomem *p, *q; | |
104 | ||
105 | /* | |
106 | * no iounmap() for that ioremap(); it would be a no-op, but it's | |
107 | * so early in setup that sucker gets confused into doing what | |
108 | * it shouldn't if we actually call it. | |
109 | */ | |
110 | p = ioremap(0xF0000, 0x10000); | |
111 | if (p == NULL) | |
112 | return -1; | |
113 | for (q = p; q < p + 0x10000; q += 16) { | |
114 | memcpy_fromio(buf, q, 15); | |
115 | if(memcmp(buf, "_DMI_", 5)==0 && dmi_checksum(buf)) | |
116 | { | |
117 | u16 num=buf[13]<<8|buf[12]; | |
118 | u16 len=buf[7]<<8|buf[6]; | |
119 | u32 base=buf[11]<<24|buf[10]<<16|buf[9]<<8|buf[8]; | |
120 | ||
121 | /* | |
122 | * DMI version 0.0 means that the real version is taken from | |
123 | * the SMBIOS version, which we don't know at this point. | |
124 | */ | |
125 | if(buf[14]!=0) | |
126 | printk(KERN_INFO "DMI %d.%d present.\n", | |
127 | buf[14]>>4, buf[14]&0x0F); | |
128 | else | |
129 | printk(KERN_INFO "DMI present.\n"); | |
130 | dmi_printk((KERN_INFO "%d structures occupying %d bytes.\n", | |
131 | num, len)); | |
132 | dmi_printk((KERN_INFO "DMI table at 0x%08X.\n", | |
133 | base)); | |
134 | if(dmi_table(base,len, num, decode)==0) | |
135 | return 0; | |
136 | } | |
137 | } | |
138 | return -1; | |
139 | } | |
140 | ||
141 | static char *dmi_ident[DMI_STRING_MAX]; | |
142 | ||
143 | /* | |
144 | * Save a DMI string | |
145 | */ | |
146 | ||
147 | static void __init dmi_save_ident(struct dmi_header *dm, int slot, int string) | |
148 | { | |
149 | char *d = (char*)dm; | |
150 | char *p = dmi_string(dm, d[string]); | |
151 | if(p==NULL || *p == 0) | |
152 | return; | |
153 | if (dmi_ident[slot]) | |
154 | return; | |
155 | dmi_ident[slot] = alloc_bootmem(strlen(p)+1); | |
156 | if(dmi_ident[slot]) | |
157 | strcpy(dmi_ident[slot], p); | |
158 | else | |
159 | printk(KERN_ERR "dmi_save_ident: out of memory.\n"); | |
160 | } | |
161 | ||
1da177e4 LT |
162 | /* |
163 | * Process a DMI table entry. Right now all we care about are the BIOS | |
164 | * and machine entries. For 2.5 we should pull the smbus controller info | |
165 | * out of here. | |
166 | */ | |
1da177e4 LT |
167 | static void __init dmi_decode(struct dmi_header *dm) |
168 | { | |
169 | #ifdef DMI_DEBUG | |
170 | u8 *data = (u8 *)dm; | |
171 | #endif | |
172 | ||
173 | switch(dm->type) | |
174 | { | |
175 | case 0: | |
176 | dmi_printk(("BIOS Vendor: %s\n", | |
177 | dmi_string(dm, data[4]))); | |
178 | dmi_save_ident(dm, DMI_BIOS_VENDOR, 4); | |
179 | dmi_printk(("BIOS Version: %s\n", | |
180 | dmi_string(dm, data[5]))); | |
181 | dmi_save_ident(dm, DMI_BIOS_VERSION, 5); | |
182 | dmi_printk(("BIOS Release: %s\n", | |
183 | dmi_string(dm, data[8]))); | |
184 | dmi_save_ident(dm, DMI_BIOS_DATE, 8); | |
185 | break; | |
186 | case 1: | |
187 | dmi_printk(("System Vendor: %s\n", | |
188 | dmi_string(dm, data[4]))); | |
189 | dmi_save_ident(dm, DMI_SYS_VENDOR, 4); | |
190 | dmi_printk(("Product Name: %s\n", | |
191 | dmi_string(dm, data[5]))); | |
192 | dmi_save_ident(dm, DMI_PRODUCT_NAME, 5); | |
193 | dmi_printk(("Version: %s\n", | |
194 | dmi_string(dm, data[6]))); | |
195 | dmi_save_ident(dm, DMI_PRODUCT_VERSION, 6); | |
196 | dmi_printk(("Serial Number: %s\n", | |
197 | dmi_string(dm, data[7]))); | |
e70c9d5e | 198 | dmi_save_ident(dm, DMI_PRODUCT_SERIAL, 7); |
1da177e4 LT |
199 | break; |
200 | case 2: | |
201 | dmi_printk(("Board Vendor: %s\n", | |
202 | dmi_string(dm, data[4]))); | |
203 | dmi_save_ident(dm, DMI_BOARD_VENDOR, 4); | |
204 | dmi_printk(("Board Name: %s\n", | |
205 | dmi_string(dm, data[5]))); | |
206 | dmi_save_ident(dm, DMI_BOARD_NAME, 5); | |
207 | dmi_printk(("Board Version: %s\n", | |
208 | dmi_string(dm, data[6]))); | |
209 | dmi_save_ident(dm, DMI_BOARD_VERSION, 6); | |
210 | break; | |
211 | } | |
212 | } | |
213 | ||
214 | void __init dmi_scan_machine(void) | |
215 | { | |
b625883f | 216 | if (dmi_iterate(dmi_decode)) |
1da177e4 LT |
217 | printk(KERN_INFO "DMI not present.\n"); |
218 | } | |
219 | ||
220 | ||
221 | /** | |
222 | * dmi_check_system - check system DMI data | |
223 | * @list: array of dmi_system_id structures to match against | |
224 | * | |
225 | * Walk the blacklist table running matching functions until someone | |
226 | * returns non zero or we hit the end. Callback function is called for | |
227 | * each successfull match. Returns the number of matches. | |
228 | */ | |
229 | int dmi_check_system(struct dmi_system_id *list) | |
230 | { | |
231 | int i, count = 0; | |
232 | struct dmi_system_id *d = list; | |
233 | ||
234 | while (d->ident) { | |
235 | for (i = 0; i < ARRAY_SIZE(d->matches); i++) { | |
236 | int s = d->matches[i].slot; | |
237 | if (s == DMI_NONE) | |
238 | continue; | |
239 | if (dmi_ident[s] && strstr(dmi_ident[s], d->matches[i].substr)) | |
240 | continue; | |
241 | /* No match */ | |
242 | goto fail; | |
243 | } | |
244 | if (d->callback && d->callback(d)) | |
245 | break; | |
246 | count++; | |
247 | fail: d++; | |
248 | } | |
249 | ||
250 | return count; | |
251 | } | |
1da177e4 LT |
252 | EXPORT_SYMBOL(dmi_check_system); |
253 | ||
254 | /** | |
255 | * dmi_get_system_info - return DMI data value | |
256 | * @field: data index (see enum dmi_filed) | |
257 | * | |
258 | * Returns one DMI data value, can be used to perform | |
259 | * complex DMI data checks. | |
260 | */ | |
e70c9d5e | 261 | char *dmi_get_system_info(int field) |
1da177e4 LT |
262 | { |
263 | return dmi_ident[field]; | |
264 | } | |
e70c9d5e | 265 | EXPORT_SYMBOL(dmi_get_system_info); |