aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--drivers/firmware/dmi_scan.c62
-rw-r--r--include/linux/dmi.h3
2 files changed, 51 insertions, 14 deletions
diff --git a/drivers/firmware/dmi_scan.c b/drivers/firmware/dmi_scan.c
index e0bade73237..1412d7bcdbd 100644
--- a/drivers/firmware/dmi_scan.c
+++ b/drivers/firmware/dmi_scan.c
@@ -43,18 +43,12 @@ static char * __init dmi_string(const struct dmi_header *dm, u8 s)
* We have to be cautious here. We have seen BIOSes with DMI pointers
* pointing to completely the wrong place for example
*/
-static int __init dmi_table(u32 base, int len, int num,
- void (*decode)(const struct dmi_header *))
+static void dmi_table(u8 *buf, int len, int num,
+ void (*decode)(const struct dmi_header *))
{
- u8 *buf, *data;
+ u8 *data = buf;
int i = 0;
- buf = dmi_ioremap(base, len);
- if (buf == NULL)
- return -1;
-
- data = buf;
-
/*
* Stop when we see all the items the table claimed to have
* OR we run off the end of the table (also happens)
@@ -75,7 +69,23 @@ static int __init dmi_table(u32 base, int len, int num,
data += 2;
i++;
}
- dmi_iounmap(buf, len);
+}
+
+static u32 dmi_base;
+static u16 dmi_len;
+static u16 dmi_num;
+
+static int __init dmi_walk_early(void (*decode)(const struct dmi_header *))
+{
+ u8 *buf;
+
+ buf = dmi_ioremap(dmi_base, dmi_len);
+ if (buf == NULL)
+ return -1;
+
+ dmi_table(buf, dmi_len, dmi_num, decode);
+
+ dmi_iounmap(buf, dmi_len);
return 0;
}
@@ -291,9 +301,9 @@ static int __init dmi_present(const char __iomem *p)
memcpy_fromio(buf, p, 15);
if ((memcmp(buf, "_DMI_", 5) == 0) && dmi_checksum(buf)) {
- u16 num = (buf[13] << 8) | buf[12];
- u16 len = (buf[7] << 8) | buf[6];
- u32 base = (buf[11] << 24) | (buf[10] << 16) |
+ dmi_num = (buf[13] << 8) | buf[12];
+ dmi_len = (buf[7] << 8) | buf[6];
+ dmi_base = (buf[11] << 24) | (buf[10] << 16) |
(buf[9] << 8) | buf[8];
/*
@@ -305,7 +315,7 @@ static int __init dmi_present(const char __iomem *p)
buf[14] >> 4, buf[14] & 0xF);
else
printk(KERN_INFO "DMI present.\n");
- if (dmi_table(base,len, num, dmi_decode) == 0)
+ if (dmi_walk_early(dmi_decode) == 0)
return 0;
}
return 1;
@@ -489,3 +499,27 @@ int dmi_get_year(int field)
return year;
}
+
+/**
+ * dmi_walk - Walk the DMI table and get called back for every record
+ * @decode: Callback function
+ *
+ * Returns -1 when the DMI table can't be reached, 0 on success.
+ */
+int dmi_walk(void (*decode)(const struct dmi_header *))
+{
+ u8 *buf;
+
+ if (!dmi_available)
+ return -1;
+
+ buf = ioremap(dmi_base, dmi_len);
+ if (buf == NULL)
+ return -1;
+
+ dmi_table(buf, dmi_len, dmi_num, decode);
+
+ iounmap(buf);
+ return 0;
+}
+EXPORT_SYMBOL_GPL(dmi_walk);
diff --git a/include/linux/dmi.h b/include/linux/dmi.h
index b1251b2af56..bbc9992ec37 100644
--- a/include/linux/dmi.h
+++ b/include/linux/dmi.h
@@ -79,6 +79,7 @@ extern void dmi_scan_machine(void);
extern int dmi_get_year(int field);
extern int dmi_name_in_vendors(const char *str);
extern int dmi_available;
+extern int dmi_walk(void (*decode)(const struct dmi_header *));
#else
@@ -89,6 +90,8 @@ static inline const struct dmi_device * dmi_find_device(int type, const char *na
static inline int dmi_get_year(int year) { return 0; }
static inline int dmi_name_in_vendors(const char *s) { return 0; }
#define dmi_available 0
+static inline int dmi_walk(void (*decode)(const struct dmi_header *))
+ { return -1; }
#endif