[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>
This commit is contained in:
parent
c3c7120d55
commit
ebad6a4230
|
@ -6,13 +6,6 @@
|
|||
#include <linux/bootmem.h>
|
||||
|
||||
|
||||
struct dmi_header {
|
||||
u8 type;
|
||||
u8 length;
|
||||
u16 handle;
|
||||
};
|
||||
|
||||
|
||||
static char * __init dmi_string(struct dmi_header *dm, u8 s)
|
||||
{
|
||||
u8 *bp = ((u8 *) dm) + dm->length;
|
||||
|
@ -88,6 +81,7 @@ static int __init dmi_checksum(u8 *buf)
|
|||
}
|
||||
|
||||
static char *dmi_ident[DMI_STRING_MAX];
|
||||
static LIST_HEAD(dmi_devices);
|
||||
|
||||
/*
|
||||
* Save a DMI string
|
||||
|
@ -106,6 +100,58 @@ static void __init dmi_save_ident(struct dmi_header *dm, int slot, int string)
|
|||
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
|
||||
* 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)
|
|||
*/
|
||||
static void __init dmi_decode(struct dmi_header *dm)
|
||||
{
|
||||
u8 *data __attribute__((__unused__)) = (u8 *)dm;
|
||||
|
||||
switch(dm->type) {
|
||||
case 0:
|
||||
case 0: /* BIOS Information */
|
||||
dmi_save_ident(dm, DMI_BIOS_VENDOR, 4);
|
||||
dmi_save_ident(dm, DMI_BIOS_VERSION, 5);
|
||||
dmi_save_ident(dm, DMI_BIOS_DATE, 8);
|
||||
break;
|
||||
case 1:
|
||||
case 1: /* System Information */
|
||||
dmi_save_ident(dm, DMI_SYS_VENDOR, 4);
|
||||
dmi_save_ident(dm, DMI_PRODUCT_NAME, 5);
|
||||
dmi_save_ident(dm, DMI_PRODUCT_VERSION, 6);
|
||||
dmi_save_ident(dm, DMI_PRODUCT_SERIAL, 7);
|
||||
break;
|
||||
case 2:
|
||||
case 2: /* Base Board Information */
|
||||
dmi_save_ident(dm, DMI_BOARD_VENDOR, 4);
|
||||
dmi_save_ident(dm, DMI_BOARD_NAME, 5);
|
||||
dmi_save_ident(dm, DMI_BOARD_VERSION, 6);
|
||||
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)
|
|||
return dmi_ident[field];
|
||||
}
|
||||
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);
|
||||
|
|
|
@ -1,6 +1,8 @@
|
|||
#ifndef __DMI_H__
|
||||
#define __DMI_H__
|
||||
|
||||
#include <linux/list.h>
|
||||
|
||||
enum dmi_field {
|
||||
DMI_NONE,
|
||||
DMI_BIOS_VENDOR,
|
||||
|
@ -16,6 +18,24 @@ enum dmi_field {
|
|||
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
|
||||
*/
|
||||
|
@ -26,22 +46,32 @@ struct dmi_strmatch {
|
|||
|
||||
struct dmi_system_id {
|
||||
int (*callback)(struct dmi_system_id *);
|
||||
char *ident;
|
||||
const char *ident;
|
||||
struct dmi_strmatch matches[4];
|
||||
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)
|
||||
|
||||
extern int dmi_check_system(struct dmi_system_id *list);
|
||||
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
|
||||
|
||||
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 struct dmi_device * dmi_find_device(int type, const char *name,
|
||||
struct dmi_device *from) { return NULL; }
|
||||
|
||||
#endif
|
||||
|
||||
|
|
Loading…
Reference in New Issue