Commit ebad6a42 authored by Andrey Panin's avatar Andrey Panin Committed by Linus Torvalds

[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: default avatarAndrey Panin <pazke@donpac.ru>
Signed-off-by: default avatarAndrew Morton <akpm@osdl.org>
Signed-off-by: default avatarLinus Torvalds <torvalds@osdl.org>
parent c3c7120d
...@@ -6,13 +6,6 @@ ...@@ -6,13 +6,6 @@
#include <linux/bootmem.h> #include <linux/bootmem.h>
struct dmi_header {
u8 type;
u8 length;
u16 handle;
};
static char * __init dmi_string(struct dmi_header *dm, u8 s) static char * __init dmi_string(struct dmi_header *dm, u8 s)
{ {
u8 *bp = ((u8 *) dm) + dm->length; u8 *bp = ((u8 *) dm) + dm->length;
...@@ -88,6 +81,7 @@ static int __init dmi_checksum(u8 *buf) ...@@ -88,6 +81,7 @@ static int __init dmi_checksum(u8 *buf)
} }
static char *dmi_ident[DMI_STRING_MAX]; static char *dmi_ident[DMI_STRING_MAX];
static LIST_HEAD(dmi_devices);
/* /*
* Save a DMI string * Save a DMI string
...@@ -106,6 +100,58 @@ static void __init dmi_save_ident(struct dmi_header *dm, int slot, int string) ...@@ -106,6 +100,58 @@ static void __init dmi_save_ident(struct dmi_header *dm, int slot, int string)
dmi_ident[slot] = p; dmi_ident[slot] = p;
} }
static void __init dmi_save_devices(struct dmi_header *dm)
{
int i, count = (dm->length - sizeof(struct dmi_header)) / 2;
struct dmi_device *dev;
for (i = 0; i < count; i++) {
char *d = ((char *) dm) + (i * 2);
/* Skip disabled device */
if ((*d & 0x80) == 0)
continue;
dev = alloc_bootmem(sizeof(*dev));
if (!dev) {
printk(KERN_ERR "dmi_save_devices: out of memory.\n");
break;
}
dev->type = *d++ & 0x7f;
dev->name = dmi_string(dm, *d);
dev->device_data = NULL;
list_add(&dev->list, &dmi_devices);
}
}
static void __init dmi_save_ipmi_device(struct dmi_header *dm)
{
struct dmi_device *dev;
void * data;
data = alloc_bootmem(dm->length);
if (data == NULL) {
printk(KERN_ERR "dmi_save_ipmi_device: out of memory.\n");
return;
}
memcpy(data, dm, dm->length);
dev = alloc_bootmem(sizeof(*dev));
if (!dev) {
printk(KERN_ERR "dmi_save_ipmi_device: out of memory.\n");
return;
}
dev->type = DMI_DEV_TYPE_IPMI;
dev->name = "IPMI controller";
dev->device_data = data;
list_add(&dev->list, &dmi_devices);
}
/* /*
* Process a DMI table entry. Right now all we care about are the BIOS * Process a DMI table entry. Right now all we care about are the BIOS
* and machine entries. For 2.5 we should pull the smbus controller info * 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,25 +159,28 @@ static void __init dmi_save_ident(struct dmi_header *dm, int slot, int string)
*/ */
static void __init dmi_decode(struct dmi_header *dm) static void __init dmi_decode(struct dmi_header *dm)
{ {
u8 *data __attribute__((__unused__)) = (u8 *)dm;
switch(dm->type) { switch(dm->type) {
case 0: case 0: /* BIOS Information */
dmi_save_ident(dm, DMI_BIOS_VENDOR, 4); dmi_save_ident(dm, DMI_BIOS_VENDOR, 4);
dmi_save_ident(dm, DMI_BIOS_VERSION, 5); dmi_save_ident(dm, DMI_BIOS_VERSION, 5);
dmi_save_ident(dm, DMI_BIOS_DATE, 8); dmi_save_ident(dm, DMI_BIOS_DATE, 8);
break; break;
case 1: case 1: /* System Information */
dmi_save_ident(dm, DMI_SYS_VENDOR, 4); dmi_save_ident(dm, DMI_SYS_VENDOR, 4);
dmi_save_ident(dm, DMI_PRODUCT_NAME, 5); dmi_save_ident(dm, DMI_PRODUCT_NAME, 5);
dmi_save_ident(dm, DMI_PRODUCT_VERSION, 6); dmi_save_ident(dm, DMI_PRODUCT_VERSION, 6);
dmi_save_ident(dm, DMI_PRODUCT_SERIAL, 7); dmi_save_ident(dm, DMI_PRODUCT_SERIAL, 7);
break; break;
case 2: case 2: /* Base Board Information */
dmi_save_ident(dm, DMI_BOARD_VENDOR, 4); dmi_save_ident(dm, DMI_BOARD_VENDOR, 4);
dmi_save_ident(dm, DMI_BOARD_NAME, 5); dmi_save_ident(dm, DMI_BOARD_NAME, 5);
dmi_save_ident(dm, DMI_BOARD_VERSION, 6); dmi_save_ident(dm, DMI_BOARD_VERSION, 6);
break; break;
case 10: /* Onboard Devices Information */
dmi_save_devices(dm);
break;
case 38: /* IPMI Device Information */
dmi_save_ipmi_device(dm);
} }
} }
...@@ -221,3 +270,32 @@ char *dmi_get_system_info(int field) ...@@ -221,3 +270,32 @@ char *dmi_get_system_info(int field)
return dmi_ident[field]; return dmi_ident[field];
} }
EXPORT_SYMBOL(dmi_get_system_info); EXPORT_SYMBOL(dmi_get_system_info);
/**
* dmi_find_device - find onboard device by type/name
* @type: device type or %DMI_DEV_TYPE_ANY to match all device types
* @desc: device name string or %NULL to match all
* @from: previous device found in search, or %NULL for new search.
*
* Iterates through the list of known onboard devices. If a device is
* found with a matching @vendor and @device, a pointer to its device
* structure is returned. Otherwise, %NULL is returned.
* A new search is initiated by passing %NULL to the @from argument.
* If @from is not %NULL, searches continue from next device.
*/
struct dmi_device * dmi_find_device(int type, const char *name,
struct dmi_device *from)
{
struct list_head *d, *head = from ? &from->list : &dmi_devices;
for(d = head->next; d != &dmi_devices; d = d->next) {
struct dmi_device *dev = list_entry(d, struct dmi_device, list);
if (((type == DMI_DEV_TYPE_ANY) || (dev->type == type)) &&
((name == NULL) || (strcmp(dev->name, name) == 0)))
return dev;
}
return NULL;
}
EXPORT_SYMBOL(dmi_find_device);
#ifndef __DMI_H__ #ifndef __DMI_H__
#define __DMI_H__ #define __DMI_H__
#include <linux/list.h>
enum dmi_field { enum dmi_field {
DMI_NONE, DMI_NONE,
DMI_BIOS_VENDOR, DMI_BIOS_VENDOR,
...@@ -16,6 +18,24 @@ enum dmi_field { ...@@ -16,6 +18,24 @@ enum dmi_field {
DMI_STRING_MAX, DMI_STRING_MAX,
}; };
enum dmi_device_type {
DMI_DEV_TYPE_ANY = 0,
DMI_DEV_TYPE_OTHER,
DMI_DEV_TYPE_UNKNOWN,
DMI_DEV_TYPE_VIDEO,
DMI_DEV_TYPE_SCSI,
DMI_DEV_TYPE_ETHERNET,
DMI_DEV_TYPE_TOKENRING,
DMI_DEV_TYPE_SOUND,
DMI_DEV_TYPE_IPMI = -1
};
struct dmi_header {
u8 type;
u8 length;
u16 handle;
};
/* /*
* DMI callbacks for problem boards * DMI callbacks for problem boards
*/ */
...@@ -26,22 +46,32 @@ struct dmi_strmatch { ...@@ -26,22 +46,32 @@ struct dmi_strmatch {
struct dmi_system_id { struct dmi_system_id {
int (*callback)(struct dmi_system_id *); int (*callback)(struct dmi_system_id *);
char *ident; const char *ident;
struct dmi_strmatch matches[4]; struct dmi_strmatch matches[4];
void *driver_data; void *driver_data;
}; };
#define DMI_MATCH(a,b) { a, b } #define DMI_MATCH(a, b) { a, b }
struct dmi_device {
struct list_head list;
int type;
const char *name;
void *device_data; /* Type specific data */
};
#if defined(CONFIG_X86) && !defined(CONFIG_X86_64) #if defined(CONFIG_X86) && !defined(CONFIG_X86_64)
extern int dmi_check_system(struct dmi_system_id *list); extern int dmi_check_system(struct dmi_system_id *list);
extern char * dmi_get_system_info(int field); extern char * dmi_get_system_info(int field);
extern struct dmi_device * dmi_find_device(int type, const char *name,
struct dmi_device *from);
#else #else
static inline int dmi_check_system(struct dmi_system_id *list) { return 0; } static inline int dmi_check_system(struct dmi_system_id *list) { return 0; }
static inline char * dmi_get_system_info(int field) { return NULL; } static inline char * dmi_get_system_info(int field) { return NULL; }
static struct dmi_device * dmi_find_device(int type, const char *name,
struct dmi_device *from) { return NULL; }
#endif #endif
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment