Skip to content

Commit

Permalink
[PATCH] dmi: add onboard devices discovery
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Andrey Panin authored and Linus Torvalds committed Sep 7, 2005
1 parent c3c7120 commit ebad6a4
Show file tree
Hide file tree
Showing 2 changed files with 123 additions and 15 deletions.
102 changes: 90 additions & 12 deletions arch/i386/kernel/dmi_scan.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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
Expand All @@ -106,32 +100,87 @@ 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
* out of here.
*/
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);
}
}

Expand Down Expand Up @@ -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);
36 changes: 33 additions & 3 deletions include/linux/dmi.h
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
#ifndef __DMI_H__
#define __DMI_H__

#include <linux/list.h>

enum dmi_field {
DMI_NONE,
DMI_BIOS_VENDOR,
Expand All @@ -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
*/
Expand All @@ -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

Expand Down

0 comments on commit ebad6a4

Please sign in to comment.