diff options
author | Andrey Panin <pazke@donpac.ru> | 2005-09-06 18:18:29 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@g5.osdl.org> | 2005-09-07 19:57:44 -0400 |
commit | ebad6a4230bdb5927495e28bc7837f515bf667a7 (patch) | |
tree | 373339d76d8424dd749957847b6d83707e65e016 | |
parent | c3c7120d552989be94c9137989be5abb6da8954f (diff) |
[PATCH] dmi: add onboard devices discovery
This patch adds onboard devices and IPMI BMC discovery into DMI scan code.
Drivers can use dmi_find_device() function to search for devices by type and
name.
Signed-off-by: Andrey Panin <pazke@donpac.ru>
Signed-off-by: Andrew Morton <akpm@osdl.org>
Signed-off-by: Linus Torvalds <torvalds@osdl.org>
-rw-r--r-- | arch/i386/kernel/dmi_scan.c | 102 | ||||
-rw-r--r-- | include/linux/dmi.h | 36 |
2 files changed, 123 insertions, 15 deletions
diff --git a/arch/i386/kernel/dmi_scan.c b/arch/i386/kernel/dmi_scan.c index ae1a1aed2fc0..c4a73855e38c 100644 --- a/arch/i386/kernel/dmi_scan.c +++ b/arch/i386/kernel/dmi_scan.c | |||
@@ -6,13 +6,6 @@ | |||
6 | #include <linux/bootmem.h> | 6 | #include <linux/bootmem.h> |
7 | 7 | ||
8 | 8 | ||
9 | struct dmi_header { | ||
10 | u8 type; | ||
11 | u8 length; | ||
12 | u16 handle; | ||
13 | }; | ||
14 | |||
15 | |||
16 | static char * __init dmi_string(struct dmi_header *dm, u8 s) | 9 | static char * __init dmi_string(struct dmi_header *dm, u8 s) |
17 | { | 10 | { |
18 | u8 *bp = ((u8 *) dm) + dm->length; | 11 | u8 *bp = ((u8 *) dm) + dm->length; |
@@ -88,6 +81,7 @@ static int __init dmi_checksum(u8 *buf) | |||
88 | } | 81 | } |
89 | 82 | ||
90 | static char *dmi_ident[DMI_STRING_MAX]; | 83 | static char *dmi_ident[DMI_STRING_MAX]; |
84 | static LIST_HEAD(dmi_devices); | ||
91 | 85 | ||
92 | /* | 86 | /* |
93 | * Save a DMI string | 87 | * Save a DMI string |
@@ -106,6 +100,58 @@ static void __init dmi_save_ident(struct dmi_header *dm, int slot, int string) | |||
106 | dmi_ident[slot] = p; | 100 | dmi_ident[slot] = p; |
107 | } | 101 | } |
108 | 102 | ||
103 | static void __init dmi_save_devices(struct dmi_header *dm) | ||
104 | { | ||
105 | int i, count = (dm->length - sizeof(struct dmi_header)) / 2; | ||
106 | struct dmi_device *dev; | ||
107 | |||
108 | for (i = 0; i < count; i++) { | ||
109 | char *d = ((char *) dm) + (i * 2); | ||
110 | |||
111 | /* Skip disabled device */ | ||
112 | if ((*d & 0x80) == 0) | ||
113 | continue; | ||
114 | |||
115 | dev = alloc_bootmem(sizeof(*dev)); | ||
116 | if (!dev) { | ||
117 | printk(KERN_ERR "dmi_save_devices: out of memory.\n"); | ||
118 | break; | ||
119 | } | ||
120 | |||
121 | dev->type = *d++ & 0x7f; | ||
122 | dev->name = dmi_string(dm, *d); | ||
123 | dev->device_data = NULL; | ||
124 | |||
125 | list_add(&dev->list, &dmi_devices); | ||
126 | } | ||
127 | } | ||
128 | |||
129 | static void __init dmi_save_ipmi_device(struct dmi_header *dm) | ||
130 | { | ||
131 | struct dmi_device *dev; | ||
132 | void * data; | ||
133 | |||
134 | data = alloc_bootmem(dm->length); | ||
135 | if (data == NULL) { | ||
136 | printk(KERN_ERR "dmi_save_ipmi_device: out of memory.\n"); | ||
137 | return; | ||
138 | } | ||
139 | |||
140 | memcpy(data, dm, dm->length); | ||
141 | |||
142 | dev = alloc_bootmem(sizeof(*dev)); | ||
143 | if (!dev) { | ||
144 | printk(KERN_ERR "dmi_save_ipmi_device: out of memory.\n"); | ||
145 | return; | ||
146 | } | ||
147 | |||
148 | dev->type = DMI_DEV_TYPE_IPMI; | ||
149 | dev->name = "IPMI controller"; | ||
150 | dev->device_data = data; | ||
151 | |||
152 | list_add(&dev->list, &dmi_devices); | ||
153 | } | ||
154 | |||
109 | /* | 155 | /* |
110 | * Process a DMI table entry. Right now all we care about are the BIOS | 156 | * Process a DMI table entry. Right now all we care about are the BIOS |
111 | * and machine entries. For 2.5 we should pull the smbus controller info | 157 | * and machine entries. For 2.5 we should pull the smbus controller info |
@@ -113,25 +159,28 @@ static void __init dmi_save_ident(struct dmi_header *dm, int slot, int string) | |||
113 | */ | 159 | */ |
114 | static void __init dmi_decode(struct dmi_header *dm) | 160 | static void __init dmi_decode(struct dmi_header *dm) |
115 | { | 161 | { |
116 | u8 *data __attribute__((__unused__)) = (u8 *)dm; | ||
117 | |||
118 | switch(dm->type) { | 162 | switch(dm->type) { |
119 | case 0: | 163 | case 0: /* BIOS Information */ |
120 | dmi_save_ident(dm, DMI_BIOS_VENDOR, 4); | 164 | dmi_save_ident(dm, DMI_BIOS_VENDOR, 4); |
121 | dmi_save_ident(dm, DMI_BIOS_VERSION, 5); | 165 | dmi_save_ident(dm, DMI_BIOS_VERSION, 5); |
122 | dmi_save_ident(dm, DMI_BIOS_DATE, 8); | 166 | dmi_save_ident(dm, DMI_BIOS_DATE, 8); |
123 | break; | 167 | break; |
124 | case 1: | 168 | case 1: /* System Information */ |
125 | dmi_save_ident(dm, DMI_SYS_VENDOR, 4); | 169 | dmi_save_ident(dm, DMI_SYS_VENDOR, 4); |
126 | dmi_save_ident(dm, DMI_PRODUCT_NAME, 5); | 170 | dmi_save_ident(dm, DMI_PRODUCT_NAME, 5); |
127 | dmi_save_ident(dm, DMI_PRODUCT_VERSION, 6); | 171 | dmi_save_ident(dm, DMI_PRODUCT_VERSION, 6); |
128 | dmi_save_ident(dm, DMI_PRODUCT_SERIAL, 7); | 172 | dmi_save_ident(dm, DMI_PRODUCT_SERIAL, 7); |
129 | break; | 173 | break; |
130 | case 2: | 174 | case 2: /* Base Board Information */ |
131 | dmi_save_ident(dm, DMI_BOARD_VENDOR, 4); | 175 | dmi_save_ident(dm, DMI_BOARD_VENDOR, 4); |
132 | dmi_save_ident(dm, DMI_BOARD_NAME, 5); | 176 | dmi_save_ident(dm, DMI_BOARD_NAME, 5); |
133 | dmi_save_ident(dm, DMI_BOARD_VERSION, 6); | 177 | dmi_save_ident(dm, DMI_BOARD_VERSION, 6); |
134 | break; | 178 | break; |
179 | case 10: /* Onboard Devices Information */ | ||
180 | dmi_save_devices(dm); | ||
181 | break; | ||
182 | case 38: /* IPMI Device Information */ | ||
183 | dmi_save_ipmi_device(dm); | ||
135 | } | 184 | } |
136 | } | 185 | } |
137 | 186 | ||
@@ -221,3 +270,32 @@ char *dmi_get_system_info(int field) | |||
221 | return dmi_ident[field]; | 270 | return dmi_ident[field]; |
222 | } | 271 | } |
223 | EXPORT_SYMBOL(dmi_get_system_info); | 272 | EXPORT_SYMBOL(dmi_get_system_info); |
273 | |||
274 | /** | ||
275 | * dmi_find_device - find onboard device by type/name | ||
276 | * @type: device type or %DMI_DEV_TYPE_ANY to match all device types | ||
277 | * @desc: device name string or %NULL to match all | ||
278 | * @from: previous device found in search, or %NULL for new search. | ||
279 | * | ||
280 | * Iterates through the list of known onboard devices. If a device is | ||
281 | * found with a matching @vendor and @device, a pointer to its device | ||
282 | * structure is returned. Otherwise, %NULL is returned. | ||
283 | * A new search is initiated by passing %NULL to the @from argument. | ||
284 | * If @from is not %NULL, searches continue from next device. | ||
285 | */ | ||
286 | struct dmi_device * dmi_find_device(int type, const char *name, | ||
287 | struct dmi_device *from) | ||
288 | { | ||
289 | struct list_head *d, *head = from ? &from->list : &dmi_devices; | ||
290 | |||
291 | for(d = head->next; d != &dmi_devices; d = d->next) { | ||
292 | struct dmi_device *dev = list_entry(d, struct dmi_device, list); | ||
293 | |||
294 | if (((type == DMI_DEV_TYPE_ANY) || (dev->type == type)) && | ||
295 | ((name == NULL) || (strcmp(dev->name, name) == 0))) | ||
296 | return dev; | ||
297 | } | ||
298 | |||
299 | return NULL; | ||
300 | } | ||
301 | EXPORT_SYMBOL(dmi_find_device); | ||
diff --git a/include/linux/dmi.h b/include/linux/dmi.h index 5e93e6dce9a4..c30175e8dec6 100644 --- a/include/linux/dmi.h +++ b/include/linux/dmi.h | |||
@@ -1,6 +1,8 @@ | |||
1 | #ifndef __DMI_H__ | 1 | #ifndef __DMI_H__ |
2 | #define __DMI_H__ | 2 | #define __DMI_H__ |
3 | 3 | ||
4 | #include <linux/list.h> | ||
5 | |||
4 | enum dmi_field { | 6 | enum dmi_field { |
5 | DMI_NONE, | 7 | DMI_NONE, |
6 | DMI_BIOS_VENDOR, | 8 | DMI_BIOS_VENDOR, |
@@ -16,6 +18,24 @@ enum dmi_field { | |||
16 | DMI_STRING_MAX, | 18 | DMI_STRING_MAX, |
17 | }; | 19 | }; |
18 | 20 | ||
21 | enum dmi_device_type { | ||
22 | DMI_DEV_TYPE_ANY = 0, | ||
23 | DMI_DEV_TYPE_OTHER, | ||
24 | DMI_DEV_TYPE_UNKNOWN, | ||
25 | DMI_DEV_TYPE_VIDEO, | ||
26 | DMI_DEV_TYPE_SCSI, | ||
27 | DMI_DEV_TYPE_ETHERNET, | ||
28 | DMI_DEV_TYPE_TOKENRING, | ||
29 | DMI_DEV_TYPE_SOUND, | ||
30 | DMI_DEV_TYPE_IPMI = -1 | ||
31 | }; | ||
32 | |||
33 | struct dmi_header { | ||
34 | u8 type; | ||
35 | u8 length; | ||
36 | u16 handle; | ||
37 | }; | ||
38 | |||
19 | /* | 39 | /* |
20 | * DMI callbacks for problem boards | 40 | * DMI callbacks for problem boards |
21 | */ | 41 | */ |
@@ -26,22 +46,32 @@ struct dmi_strmatch { | |||
26 | 46 | ||
27 | struct dmi_system_id { | 47 | struct dmi_system_id { |
28 | int (*callback)(struct dmi_system_id *); | 48 | int (*callback)(struct dmi_system_id *); |
29 | char *ident; | 49 | const char *ident; |
30 | struct dmi_strmatch matches[4]; | 50 | struct dmi_strmatch matches[4]; |
31 | void *driver_data; | 51 | void *driver_data; |
32 | }; | 52 | }; |
33 | 53 | ||
34 | #define DMI_MATCH(a,b) { a, b } | 54 | #define DMI_MATCH(a, b) { a, b } |
55 | |||
56 | struct dmi_device { | ||
57 | struct list_head list; | ||
58 | int type; | ||
59 | const char *name; | ||
60 | void *device_data; /* Type specific data */ | ||
61 | }; | ||
35 | 62 | ||
36 | #if defined(CONFIG_X86) && !defined(CONFIG_X86_64) | 63 | #if defined(CONFIG_X86) && !defined(CONFIG_X86_64) |
37 | 64 | ||
38 | extern int dmi_check_system(struct dmi_system_id *list); | 65 | extern int dmi_check_system(struct dmi_system_id *list); |
39 | extern char * dmi_get_system_info(int field); | 66 | extern char * dmi_get_system_info(int field); |
40 | 67 | extern struct dmi_device * dmi_find_device(int type, const char *name, | |
68 | struct dmi_device *from); | ||
41 | #else | 69 | #else |
42 | 70 | ||
43 | static inline int dmi_check_system(struct dmi_system_id *list) { return 0; } | 71 | static inline int dmi_check_system(struct dmi_system_id *list) { return 0; } |
44 | static inline char * dmi_get_system_info(int field) { return NULL; } | 72 | static inline char * dmi_get_system_info(int field) { return NULL; } |
73 | static struct dmi_device * dmi_find_device(int type, const char *name, | ||
74 | struct dmi_device *from) { return NULL; } | ||
45 | 75 | ||
46 | #endif | 76 | #endif |
47 | 77 | ||