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 /arch/i386/kernel/dmi_scan.c | |
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>
Diffstat (limited to 'arch/i386/kernel/dmi_scan.c')
-rw-r--r-- | arch/i386/kernel/dmi_scan.c | 102 |
1 files changed, 90 insertions, 12 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); | ||