14f705ae3SBjorn Helgaas #include <linux/types.h> 24f705ae3SBjorn Helgaas #include <linux/string.h> 34f705ae3SBjorn Helgaas #include <linux/init.h> 44f705ae3SBjorn Helgaas #include <linux/module.h> 54f705ae3SBjorn Helgaas #include <linux/dmi.h> 64f705ae3SBjorn Helgaas #include <linux/efi.h> 74f705ae3SBjorn Helgaas #include <linux/bootmem.h> 84f705ae3SBjorn Helgaas #include <linux/slab.h> 94f705ae3SBjorn Helgaas #include <asm/dmi.h> 104f705ae3SBjorn Helgaas 11*79da4721SParag Warudkar static char dmi_empty_string[] = " "; 12*79da4721SParag Warudkar 131855256cSJeff Garzik static char * __init dmi_string(const struct dmi_header *dm, u8 s) 144f705ae3SBjorn Helgaas { 151855256cSJeff Garzik const u8 *bp = ((u8 *) dm) + dm->length; 164f705ae3SBjorn Helgaas char *str = ""; 174f705ae3SBjorn Helgaas 184f705ae3SBjorn Helgaas if (s) { 194f705ae3SBjorn Helgaas s--; 204f705ae3SBjorn Helgaas while (s > 0 && *bp) { 214f705ae3SBjorn Helgaas bp += strlen(bp) + 1; 224f705ae3SBjorn Helgaas s--; 234f705ae3SBjorn Helgaas } 244f705ae3SBjorn Helgaas 254f705ae3SBjorn Helgaas if (*bp != 0) { 26*79da4721SParag Warudkar size_t len = strlen(bp)+1; 27*79da4721SParag Warudkar size_t cmp_len = len > 8 ? 8 : len; 28*79da4721SParag Warudkar 29*79da4721SParag Warudkar if (!memcmp(bp, dmi_empty_string, cmp_len)) 30*79da4721SParag Warudkar return dmi_empty_string; 31*79da4721SParag Warudkar str = dmi_alloc(len); 324f705ae3SBjorn Helgaas if (str != NULL) 334f705ae3SBjorn Helgaas strcpy(str, bp); 344f705ae3SBjorn Helgaas else 35*79da4721SParag Warudkar printk(KERN_ERR "dmi_string: cannot allocate %Zu bytes.\n", len); 364f705ae3SBjorn Helgaas } 374f705ae3SBjorn Helgaas } 384f705ae3SBjorn Helgaas 394f705ae3SBjorn Helgaas return str; 404f705ae3SBjorn Helgaas } 414f705ae3SBjorn Helgaas 424f705ae3SBjorn Helgaas /* 434f705ae3SBjorn Helgaas * We have to be cautious here. We have seen BIOSes with DMI pointers 444f705ae3SBjorn Helgaas * pointing to completely the wrong place for example 454f705ae3SBjorn Helgaas */ 464f705ae3SBjorn Helgaas static int __init dmi_table(u32 base, int len, int num, 471855256cSJeff Garzik void (*decode)(const struct dmi_header *)) 484f705ae3SBjorn Helgaas { 494f705ae3SBjorn Helgaas u8 *buf, *data; 504f705ae3SBjorn Helgaas int i = 0; 514f705ae3SBjorn Helgaas 524f705ae3SBjorn Helgaas buf = dmi_ioremap(base, len); 534f705ae3SBjorn Helgaas if (buf == NULL) 544f705ae3SBjorn Helgaas return -1; 554f705ae3SBjorn Helgaas 564f705ae3SBjorn Helgaas data = buf; 574f705ae3SBjorn Helgaas 584f705ae3SBjorn Helgaas /* 594f705ae3SBjorn Helgaas * Stop when we see all the items the table claimed to have 604f705ae3SBjorn Helgaas * OR we run off the end of the table (also happens) 614f705ae3SBjorn Helgaas */ 624f705ae3SBjorn Helgaas while ((i < num) && (data - buf + sizeof(struct dmi_header)) <= len) { 631855256cSJeff Garzik const struct dmi_header *dm = (const struct dmi_header *)data; 641855256cSJeff Garzik 654f705ae3SBjorn Helgaas /* 664f705ae3SBjorn Helgaas * We want to know the total length (formated area and strings) 674f705ae3SBjorn Helgaas * before decoding to make sure we won't run off the table in 684f705ae3SBjorn Helgaas * dmi_decode or dmi_string 694f705ae3SBjorn Helgaas */ 704f705ae3SBjorn Helgaas data += dm->length; 714f705ae3SBjorn Helgaas while ((data - buf < len - 1) && (data[0] || data[1])) 724f705ae3SBjorn Helgaas data++; 734f705ae3SBjorn Helgaas if (data - buf < len - 1) 744f705ae3SBjorn Helgaas decode(dm); 754f705ae3SBjorn Helgaas data += 2; 764f705ae3SBjorn Helgaas i++; 774f705ae3SBjorn Helgaas } 784f705ae3SBjorn Helgaas dmi_iounmap(buf, len); 794f705ae3SBjorn Helgaas return 0; 804f705ae3SBjorn Helgaas } 814f705ae3SBjorn Helgaas 821855256cSJeff Garzik static int __init dmi_checksum(const u8 *buf) 834f705ae3SBjorn Helgaas { 844f705ae3SBjorn Helgaas u8 sum = 0; 854f705ae3SBjorn Helgaas int a; 864f705ae3SBjorn Helgaas 874f705ae3SBjorn Helgaas for (a = 0; a < 15; a++) 884f705ae3SBjorn Helgaas sum += buf[a]; 894f705ae3SBjorn Helgaas 904f705ae3SBjorn Helgaas return sum == 0; 914f705ae3SBjorn Helgaas } 924f705ae3SBjorn Helgaas 934f705ae3SBjorn Helgaas static char *dmi_ident[DMI_STRING_MAX]; 944f705ae3SBjorn Helgaas static LIST_HEAD(dmi_devices); 954f5c791aSLennart Poettering int dmi_available; 964f705ae3SBjorn Helgaas 974f705ae3SBjorn Helgaas /* 984f705ae3SBjorn Helgaas * Save a DMI string 994f705ae3SBjorn Helgaas */ 1001855256cSJeff Garzik static void __init dmi_save_ident(const struct dmi_header *dm, int slot, int string) 1014f705ae3SBjorn Helgaas { 1021855256cSJeff Garzik const char *d = (const char*) dm; 1031855256cSJeff Garzik char *p; 1044f705ae3SBjorn Helgaas 1054f705ae3SBjorn Helgaas if (dmi_ident[slot]) 1064f705ae3SBjorn Helgaas return; 1074f705ae3SBjorn Helgaas 1084f705ae3SBjorn Helgaas p = dmi_string(dm, d[string]); 1094f705ae3SBjorn Helgaas if (p == NULL) 1104f705ae3SBjorn Helgaas return; 1114f705ae3SBjorn Helgaas 1124f705ae3SBjorn Helgaas dmi_ident[slot] = p; 1134f705ae3SBjorn Helgaas } 1144f705ae3SBjorn Helgaas 1151855256cSJeff Garzik static void __init dmi_save_uuid(const struct dmi_header *dm, int slot, int index) 1164f5c791aSLennart Poettering { 1171855256cSJeff Garzik const u8 *d = (u8*) dm + index; 1184f5c791aSLennart Poettering char *s; 1194f5c791aSLennart Poettering int is_ff = 1, is_00 = 1, i; 1204f5c791aSLennart Poettering 1214f5c791aSLennart Poettering if (dmi_ident[slot]) 1224f5c791aSLennart Poettering return; 1234f5c791aSLennart Poettering 1244f5c791aSLennart Poettering for (i = 0; i < 16 && (is_ff || is_00); i++) { 1254f5c791aSLennart Poettering if(d[i] != 0x00) is_ff = 0; 1264f5c791aSLennart Poettering if(d[i] != 0xFF) is_00 = 0; 1274f5c791aSLennart Poettering } 1284f5c791aSLennart Poettering 1294f5c791aSLennart Poettering if (is_ff || is_00) 1304f5c791aSLennart Poettering return; 1314f5c791aSLennart Poettering 1324f5c791aSLennart Poettering s = dmi_alloc(16*2+4+1); 1334f5c791aSLennart Poettering if (!s) 1344f5c791aSLennart Poettering return; 1354f5c791aSLennart Poettering 1364f5c791aSLennart Poettering sprintf(s, 1374f5c791aSLennart Poettering "%02X%02X%02X%02X-%02X%02X-%02X%02X-%02X%02X-%02X%02X%02X%02X%02X%02X", 1384f5c791aSLennart Poettering d[0], d[1], d[2], d[3], d[4], d[5], d[6], d[7], 1394f5c791aSLennart Poettering d[8], d[9], d[10], d[11], d[12], d[13], d[14], d[15]); 1404f5c791aSLennart Poettering 1414f5c791aSLennart Poettering dmi_ident[slot] = s; 1424f5c791aSLennart Poettering } 1434f5c791aSLennart Poettering 1441855256cSJeff Garzik static void __init dmi_save_type(const struct dmi_header *dm, int slot, int index) 1454f5c791aSLennart Poettering { 1461855256cSJeff Garzik const u8 *d = (u8*) dm + index; 1474f5c791aSLennart Poettering char *s; 1484f5c791aSLennart Poettering 1494f5c791aSLennart Poettering if (dmi_ident[slot]) 1504f5c791aSLennart Poettering return; 1514f5c791aSLennart Poettering 1524f5c791aSLennart Poettering s = dmi_alloc(4); 1534f5c791aSLennart Poettering if (!s) 1544f5c791aSLennart Poettering return; 1554f5c791aSLennart Poettering 1564f5c791aSLennart Poettering sprintf(s, "%u", *d & 0x7F); 1574f5c791aSLennart Poettering dmi_ident[slot] = s; 1584f5c791aSLennart Poettering } 1594f5c791aSLennart Poettering 1601855256cSJeff Garzik static void __init dmi_save_devices(const struct dmi_header *dm) 1614f705ae3SBjorn Helgaas { 1624f705ae3SBjorn Helgaas int i, count = (dm->length - sizeof(struct dmi_header)) / 2; 1634f705ae3SBjorn Helgaas struct dmi_device *dev; 1644f705ae3SBjorn Helgaas 1654f705ae3SBjorn Helgaas for (i = 0; i < count; i++) { 1661855256cSJeff Garzik const char *d = (char *)(dm + 1) + (i * 2); 1674f705ae3SBjorn Helgaas 1684f705ae3SBjorn Helgaas /* Skip disabled device */ 1694f705ae3SBjorn Helgaas if ((*d & 0x80) == 0) 1704f705ae3SBjorn Helgaas continue; 1714f705ae3SBjorn Helgaas 1724f705ae3SBjorn Helgaas dev = dmi_alloc(sizeof(*dev)); 1734f705ae3SBjorn Helgaas if (!dev) { 1744f705ae3SBjorn Helgaas printk(KERN_ERR "dmi_save_devices: out of memory.\n"); 1754f705ae3SBjorn Helgaas break; 1764f705ae3SBjorn Helgaas } 1774f705ae3SBjorn Helgaas 1784f705ae3SBjorn Helgaas dev->type = *d++ & 0x7f; 1794f705ae3SBjorn Helgaas dev->name = dmi_string(dm, *d); 1804f705ae3SBjorn Helgaas dev->device_data = NULL; 1812e0c1f6cSShem Multinymous list_add(&dev->list, &dmi_devices); 1822e0c1f6cSShem Multinymous } 1832e0c1f6cSShem Multinymous } 1842e0c1f6cSShem Multinymous 185*79da4721SParag Warudkar static struct dmi_device empty_oem_string_dev = { 186*79da4721SParag Warudkar .name = dmi_empty_string, 187*79da4721SParag Warudkar }; 188*79da4721SParag Warudkar 1891855256cSJeff Garzik static void __init dmi_save_oem_strings_devices(const struct dmi_header *dm) 1902e0c1f6cSShem Multinymous { 1912e0c1f6cSShem Multinymous int i, count = *(u8 *)(dm + 1); 1922e0c1f6cSShem Multinymous struct dmi_device *dev; 1932e0c1f6cSShem Multinymous 1942e0c1f6cSShem Multinymous for (i = 1; i <= count; i++) { 195*79da4721SParag Warudkar char *devname = dmi_string(dm, i); 196*79da4721SParag Warudkar 197*79da4721SParag Warudkar if (!strcmp(devname, dmi_empty_string)) { 198*79da4721SParag Warudkar list_add(&empty_oem_string_dev.list, &dmi_devices); 199*79da4721SParag Warudkar continue; 200*79da4721SParag Warudkar } 201*79da4721SParag Warudkar 2022e0c1f6cSShem Multinymous dev = dmi_alloc(sizeof(*dev)); 2032e0c1f6cSShem Multinymous if (!dev) { 2042e0c1f6cSShem Multinymous printk(KERN_ERR 2052e0c1f6cSShem Multinymous "dmi_save_oem_strings_devices: out of memory.\n"); 2062e0c1f6cSShem Multinymous break; 2072e0c1f6cSShem Multinymous } 2082e0c1f6cSShem Multinymous 2092e0c1f6cSShem Multinymous dev->type = DMI_DEV_TYPE_OEM_STRING; 210*79da4721SParag Warudkar dev->name = devname; 2112e0c1f6cSShem Multinymous dev->device_data = NULL; 2124f705ae3SBjorn Helgaas 2134f705ae3SBjorn Helgaas list_add(&dev->list, &dmi_devices); 2144f705ae3SBjorn Helgaas } 2154f705ae3SBjorn Helgaas } 2164f705ae3SBjorn Helgaas 2171855256cSJeff Garzik static void __init dmi_save_ipmi_device(const struct dmi_header *dm) 2184f705ae3SBjorn Helgaas { 2194f705ae3SBjorn Helgaas struct dmi_device *dev; 2204f705ae3SBjorn Helgaas void * data; 2214f705ae3SBjorn Helgaas 2224f705ae3SBjorn Helgaas data = dmi_alloc(dm->length); 2234f705ae3SBjorn Helgaas if (data == NULL) { 2244f705ae3SBjorn Helgaas printk(KERN_ERR "dmi_save_ipmi_device: out of memory.\n"); 2254f705ae3SBjorn Helgaas return; 2264f705ae3SBjorn Helgaas } 2274f705ae3SBjorn Helgaas 2284f705ae3SBjorn Helgaas memcpy(data, dm, dm->length); 2294f705ae3SBjorn Helgaas 2304f705ae3SBjorn Helgaas dev = dmi_alloc(sizeof(*dev)); 2314f705ae3SBjorn Helgaas if (!dev) { 2324f705ae3SBjorn Helgaas printk(KERN_ERR "dmi_save_ipmi_device: out of memory.\n"); 2334f705ae3SBjorn Helgaas return; 2344f705ae3SBjorn Helgaas } 2354f705ae3SBjorn Helgaas 2364f705ae3SBjorn Helgaas dev->type = DMI_DEV_TYPE_IPMI; 2374f705ae3SBjorn Helgaas dev->name = "IPMI controller"; 2384f705ae3SBjorn Helgaas dev->device_data = data; 2394f705ae3SBjorn Helgaas 2404f705ae3SBjorn Helgaas list_add(&dev->list, &dmi_devices); 2414f705ae3SBjorn Helgaas } 2424f705ae3SBjorn Helgaas 2434f705ae3SBjorn Helgaas /* 2444f705ae3SBjorn Helgaas * Process a DMI table entry. Right now all we care about are the BIOS 2454f705ae3SBjorn Helgaas * and machine entries. For 2.5 we should pull the smbus controller info 2464f705ae3SBjorn Helgaas * out of here. 2474f705ae3SBjorn Helgaas */ 2481855256cSJeff Garzik static void __init dmi_decode(const struct dmi_header *dm) 2494f705ae3SBjorn Helgaas { 2504f705ae3SBjorn Helgaas switch(dm->type) { 2514f705ae3SBjorn Helgaas case 0: /* BIOS Information */ 2524f705ae3SBjorn Helgaas dmi_save_ident(dm, DMI_BIOS_VENDOR, 4); 2534f705ae3SBjorn Helgaas dmi_save_ident(dm, DMI_BIOS_VERSION, 5); 2544f705ae3SBjorn Helgaas dmi_save_ident(dm, DMI_BIOS_DATE, 8); 2554f705ae3SBjorn Helgaas break; 2564f705ae3SBjorn Helgaas case 1: /* System Information */ 2574f705ae3SBjorn Helgaas dmi_save_ident(dm, DMI_SYS_VENDOR, 4); 2584f705ae3SBjorn Helgaas dmi_save_ident(dm, DMI_PRODUCT_NAME, 5); 2594f705ae3SBjorn Helgaas dmi_save_ident(dm, DMI_PRODUCT_VERSION, 6); 2604f705ae3SBjorn Helgaas dmi_save_ident(dm, DMI_PRODUCT_SERIAL, 7); 2614f5c791aSLennart Poettering dmi_save_uuid(dm, DMI_PRODUCT_UUID, 8); 2624f705ae3SBjorn Helgaas break; 2634f705ae3SBjorn Helgaas case 2: /* Base Board Information */ 2644f705ae3SBjorn Helgaas dmi_save_ident(dm, DMI_BOARD_VENDOR, 4); 2654f705ae3SBjorn Helgaas dmi_save_ident(dm, DMI_BOARD_NAME, 5); 2664f705ae3SBjorn Helgaas dmi_save_ident(dm, DMI_BOARD_VERSION, 6); 2674f5c791aSLennart Poettering dmi_save_ident(dm, DMI_BOARD_SERIAL, 7); 2684f5c791aSLennart Poettering dmi_save_ident(dm, DMI_BOARD_ASSET_TAG, 8); 2694f5c791aSLennart Poettering break; 2704f5c791aSLennart Poettering case 3: /* Chassis Information */ 2714f5c791aSLennart Poettering dmi_save_ident(dm, DMI_CHASSIS_VENDOR, 4); 2724f5c791aSLennart Poettering dmi_save_type(dm, DMI_CHASSIS_TYPE, 5); 2734f5c791aSLennart Poettering dmi_save_ident(dm, DMI_CHASSIS_VERSION, 6); 2744f5c791aSLennart Poettering dmi_save_ident(dm, DMI_CHASSIS_SERIAL, 7); 2754f5c791aSLennart Poettering dmi_save_ident(dm, DMI_CHASSIS_ASSET_TAG, 8); 2764f705ae3SBjorn Helgaas break; 2774f705ae3SBjorn Helgaas case 10: /* Onboard Devices Information */ 2784f705ae3SBjorn Helgaas dmi_save_devices(dm); 2794f705ae3SBjorn Helgaas break; 2802e0c1f6cSShem Multinymous case 11: /* OEM Strings */ 2812e0c1f6cSShem Multinymous dmi_save_oem_strings_devices(dm); 2822e0c1f6cSShem Multinymous break; 2834f705ae3SBjorn Helgaas case 38: /* IPMI Device Information */ 2844f705ae3SBjorn Helgaas dmi_save_ipmi_device(dm); 2854f705ae3SBjorn Helgaas } 2864f705ae3SBjorn Helgaas } 2874f705ae3SBjorn Helgaas 2881855256cSJeff Garzik static int __init dmi_present(const char __iomem *p) 2894f705ae3SBjorn Helgaas { 2904f705ae3SBjorn Helgaas u8 buf[15]; 2911855256cSJeff Garzik 2924f705ae3SBjorn Helgaas memcpy_fromio(buf, p, 15); 2934f705ae3SBjorn Helgaas if ((memcmp(buf, "_DMI_", 5) == 0) && dmi_checksum(buf)) { 2944f705ae3SBjorn Helgaas u16 num = (buf[13] << 8) | buf[12]; 2954f705ae3SBjorn Helgaas u16 len = (buf[7] << 8) | buf[6]; 2964f705ae3SBjorn Helgaas u32 base = (buf[11] << 24) | (buf[10] << 16) | 2974f705ae3SBjorn Helgaas (buf[9] << 8) | buf[8]; 2984f705ae3SBjorn Helgaas 2994f705ae3SBjorn Helgaas /* 3004f705ae3SBjorn Helgaas * DMI version 0.0 means that the real version is taken from 3014f705ae3SBjorn Helgaas * the SMBIOS version, which we don't know at this point. 3024f705ae3SBjorn Helgaas */ 3034f705ae3SBjorn Helgaas if (buf[14] != 0) 3044f705ae3SBjorn Helgaas printk(KERN_INFO "DMI %d.%d present.\n", 3054f705ae3SBjorn Helgaas buf[14] >> 4, buf[14] & 0xF); 3064f705ae3SBjorn Helgaas else 3074f705ae3SBjorn Helgaas printk(KERN_INFO "DMI present.\n"); 3084f705ae3SBjorn Helgaas if (dmi_table(base,len, num, dmi_decode) == 0) 3094f705ae3SBjorn Helgaas return 0; 3104f705ae3SBjorn Helgaas } 3114f705ae3SBjorn Helgaas return 1; 3124f705ae3SBjorn Helgaas } 3134f705ae3SBjorn Helgaas 3144f705ae3SBjorn Helgaas void __init dmi_scan_machine(void) 3154f705ae3SBjorn Helgaas { 3164f705ae3SBjorn Helgaas char __iomem *p, *q; 3174f705ae3SBjorn Helgaas int rc; 3184f705ae3SBjorn Helgaas 3194f705ae3SBjorn Helgaas if (efi_enabled) { 3204f705ae3SBjorn Helgaas if (efi.smbios == EFI_INVALID_TABLE_ADDR) 3214f705ae3SBjorn Helgaas goto out; 3224f705ae3SBjorn Helgaas 3234f705ae3SBjorn Helgaas /* This is called as a core_initcall() because it isn't 3244f705ae3SBjorn Helgaas * needed during early boot. This also means we can 3254f705ae3SBjorn Helgaas * iounmap the space when we're done with it. 3264f705ae3SBjorn Helgaas */ 3274f705ae3SBjorn Helgaas p = dmi_ioremap(efi.smbios, 32); 3284f705ae3SBjorn Helgaas if (p == NULL) 3294f705ae3SBjorn Helgaas goto out; 3304f705ae3SBjorn Helgaas 3314f705ae3SBjorn Helgaas rc = dmi_present(p + 0x10); /* offset of _DMI_ string */ 3324f705ae3SBjorn Helgaas dmi_iounmap(p, 32); 3334f5c791aSLennart Poettering if (!rc) { 3344f5c791aSLennart Poettering dmi_available = 1; 3354f705ae3SBjorn Helgaas return; 3364f705ae3SBjorn Helgaas } 3374f5c791aSLennart Poettering } 3384f705ae3SBjorn Helgaas else { 3394f705ae3SBjorn Helgaas /* 3404f705ae3SBjorn Helgaas * no iounmap() for that ioremap(); it would be a no-op, but 3414f705ae3SBjorn Helgaas * it's so early in setup that sucker gets confused into doing 3424f705ae3SBjorn Helgaas * what it shouldn't if we actually call it. 3434f705ae3SBjorn Helgaas */ 3444f705ae3SBjorn Helgaas p = dmi_ioremap(0xF0000, 0x10000); 3454f705ae3SBjorn Helgaas if (p == NULL) 3464f705ae3SBjorn Helgaas goto out; 3474f705ae3SBjorn Helgaas 3484f705ae3SBjorn Helgaas for (q = p; q < p + 0x10000; q += 16) { 3494f705ae3SBjorn Helgaas rc = dmi_present(q); 3504f5c791aSLennart Poettering if (!rc) { 3514f5c791aSLennart Poettering dmi_available = 1; 3524f705ae3SBjorn Helgaas return; 3534f705ae3SBjorn Helgaas } 3544f705ae3SBjorn Helgaas } 3554f5c791aSLennart Poettering } 3564f705ae3SBjorn Helgaas out: printk(KERN_INFO "DMI not present or invalid.\n"); 3574f705ae3SBjorn Helgaas } 3584f705ae3SBjorn Helgaas 3594f705ae3SBjorn Helgaas /** 3604f705ae3SBjorn Helgaas * dmi_check_system - check system DMI data 3614f705ae3SBjorn Helgaas * @list: array of dmi_system_id structures to match against 362b0ef371eSRandy Dunlap * All non-null elements of the list must match 363b0ef371eSRandy Dunlap * their slot's (field index's) data (i.e., each 364b0ef371eSRandy Dunlap * list string must be a substring of the specified 365b0ef371eSRandy Dunlap * DMI slot's string data) to be considered a 366b0ef371eSRandy Dunlap * successful match. 3674f705ae3SBjorn Helgaas * 3684f705ae3SBjorn Helgaas * Walk the blacklist table running matching functions until someone 3694f705ae3SBjorn Helgaas * returns non zero or we hit the end. Callback function is called for 370b0ef371eSRandy Dunlap * each successful match. Returns the number of matches. 3714f705ae3SBjorn Helgaas */ 3721855256cSJeff Garzik int dmi_check_system(const struct dmi_system_id *list) 3734f705ae3SBjorn Helgaas { 3744f705ae3SBjorn Helgaas int i, count = 0; 3751855256cSJeff Garzik const struct dmi_system_id *d = list; 3764f705ae3SBjorn Helgaas 3774f705ae3SBjorn Helgaas while (d->ident) { 3784f705ae3SBjorn Helgaas for (i = 0; i < ARRAY_SIZE(d->matches); i++) { 3794f705ae3SBjorn Helgaas int s = d->matches[i].slot; 3804f705ae3SBjorn Helgaas if (s == DMI_NONE) 3814f705ae3SBjorn Helgaas continue; 3824f705ae3SBjorn Helgaas if (dmi_ident[s] && strstr(dmi_ident[s], d->matches[i].substr)) 3834f705ae3SBjorn Helgaas continue; 3844f705ae3SBjorn Helgaas /* No match */ 3854f705ae3SBjorn Helgaas goto fail; 3864f705ae3SBjorn Helgaas } 3874f705ae3SBjorn Helgaas count++; 3884f705ae3SBjorn Helgaas if (d->callback && d->callback(d)) 3894f705ae3SBjorn Helgaas break; 3904f705ae3SBjorn Helgaas fail: d++; 3914f705ae3SBjorn Helgaas } 3924f705ae3SBjorn Helgaas 3934f705ae3SBjorn Helgaas return count; 3944f705ae3SBjorn Helgaas } 3954f705ae3SBjorn Helgaas EXPORT_SYMBOL(dmi_check_system); 3964f705ae3SBjorn Helgaas 3974f705ae3SBjorn Helgaas /** 3984f705ae3SBjorn Helgaas * dmi_get_system_info - return DMI data value 399b0ef371eSRandy Dunlap * @field: data index (see enum dmi_field) 4004f705ae3SBjorn Helgaas * 4014f705ae3SBjorn Helgaas * Returns one DMI data value, can be used to perform 4024f705ae3SBjorn Helgaas * complex DMI data checks. 4034f705ae3SBjorn Helgaas */ 4041855256cSJeff Garzik const char *dmi_get_system_info(int field) 4054f705ae3SBjorn Helgaas { 4064f705ae3SBjorn Helgaas return dmi_ident[field]; 4074f705ae3SBjorn Helgaas } 4084f705ae3SBjorn Helgaas EXPORT_SYMBOL(dmi_get_system_info); 4094f705ae3SBjorn Helgaas 410a1bae672SAndi Kleen 411a1bae672SAndi Kleen /** 412a1bae672SAndi Kleen * dmi_name_in_vendors - Check if string is anywhere in the DMI vendor information. 413a1bae672SAndi Kleen * @str: Case sensitive Name 414a1bae672SAndi Kleen */ 4151855256cSJeff Garzik int dmi_name_in_vendors(const char *str) 416a1bae672SAndi Kleen { 417a1bae672SAndi Kleen static int fields[] = { DMI_BIOS_VENDOR, DMI_BIOS_VERSION, DMI_SYS_VENDOR, 418a1bae672SAndi Kleen DMI_PRODUCT_NAME, DMI_PRODUCT_VERSION, DMI_BOARD_VENDOR, 419a1bae672SAndi Kleen DMI_BOARD_NAME, DMI_BOARD_VERSION, DMI_NONE }; 420a1bae672SAndi Kleen int i; 421a1bae672SAndi Kleen for (i = 0; fields[i] != DMI_NONE; i++) { 422a1bae672SAndi Kleen int f = fields[i]; 423a1bae672SAndi Kleen if (dmi_ident[f] && strstr(dmi_ident[f], str)) 424a1bae672SAndi Kleen return 1; 425a1bae672SAndi Kleen } 426a1bae672SAndi Kleen return 0; 427a1bae672SAndi Kleen } 428a1bae672SAndi Kleen EXPORT_SYMBOL(dmi_name_in_vendors); 429a1bae672SAndi Kleen 4304f705ae3SBjorn Helgaas /** 4314f705ae3SBjorn Helgaas * dmi_find_device - find onboard device by type/name 4324f705ae3SBjorn Helgaas * @type: device type or %DMI_DEV_TYPE_ANY to match all device types 433b0ef371eSRandy Dunlap * @name: device name string or %NULL to match all 4344f705ae3SBjorn Helgaas * @from: previous device found in search, or %NULL for new search. 4354f705ae3SBjorn Helgaas * 4364f705ae3SBjorn Helgaas * Iterates through the list of known onboard devices. If a device is 4374f705ae3SBjorn Helgaas * found with a matching @vendor and @device, a pointer to its device 4384f705ae3SBjorn Helgaas * structure is returned. Otherwise, %NULL is returned. 439b0ef371eSRandy Dunlap * A new search is initiated by passing %NULL as the @from argument. 4404f705ae3SBjorn Helgaas * If @from is not %NULL, searches continue from next device. 4414f705ae3SBjorn Helgaas */ 4421855256cSJeff Garzik const struct dmi_device * dmi_find_device(int type, const char *name, 4431855256cSJeff Garzik const struct dmi_device *from) 4444f705ae3SBjorn Helgaas { 4451855256cSJeff Garzik const struct list_head *head = from ? &from->list : &dmi_devices; 4461855256cSJeff Garzik struct list_head *d; 4474f705ae3SBjorn Helgaas 4484f705ae3SBjorn Helgaas for(d = head->next; d != &dmi_devices; d = d->next) { 4491855256cSJeff Garzik const struct dmi_device *dev = 4501855256cSJeff Garzik list_entry(d, struct dmi_device, list); 4514f705ae3SBjorn Helgaas 4524f705ae3SBjorn Helgaas if (((type == DMI_DEV_TYPE_ANY) || (dev->type == type)) && 4534f705ae3SBjorn Helgaas ((name == NULL) || (strcmp(dev->name, name) == 0))) 4544f705ae3SBjorn Helgaas return dev; 4554f705ae3SBjorn Helgaas } 4564f705ae3SBjorn Helgaas 4574f705ae3SBjorn Helgaas return NULL; 4584f705ae3SBjorn Helgaas } 4594f705ae3SBjorn Helgaas EXPORT_SYMBOL(dmi_find_device); 4604f705ae3SBjorn Helgaas 4614f705ae3SBjorn Helgaas /** 4624f705ae3SBjorn Helgaas * dmi_get_year - Return year of a DMI date 4634f705ae3SBjorn Helgaas * @field: data index (like dmi_get_system_info) 4644f705ae3SBjorn Helgaas * 4654f705ae3SBjorn Helgaas * Returns -1 when the field doesn't exist. 0 when it is broken. 4664f705ae3SBjorn Helgaas */ 4674f705ae3SBjorn Helgaas int dmi_get_year(int field) 4684f705ae3SBjorn Helgaas { 4694f705ae3SBjorn Helgaas int year; 4701855256cSJeff Garzik const char *s = dmi_get_system_info(field); 4714f705ae3SBjorn Helgaas 4724f705ae3SBjorn Helgaas if (!s) 4734f705ae3SBjorn Helgaas return -1; 4744f705ae3SBjorn Helgaas if (*s == '\0') 4754f705ae3SBjorn Helgaas return 0; 4764f705ae3SBjorn Helgaas s = strrchr(s, '/'); 4774f705ae3SBjorn Helgaas if (!s) 4784f705ae3SBjorn Helgaas return 0; 4794f705ae3SBjorn Helgaas 4804f705ae3SBjorn Helgaas s += 1; 4814f705ae3SBjorn Helgaas year = simple_strtoul(s, NULL, 0); 4824f705ae3SBjorn Helgaas if (year && year < 100) { /* 2-digit year */ 4834f705ae3SBjorn Helgaas year += 1900; 4844f705ae3SBjorn Helgaas if (year < 1996) /* no dates < spec 1.0 */ 4854f705ae3SBjorn Helgaas year += 100; 4864f705ae3SBjorn Helgaas } 4874f705ae3SBjorn Helgaas 4884f705ae3SBjorn Helgaas return year; 4894f705ae3SBjorn Helgaas } 4904f5c791aSLennart Poettering 491f89e3b06SLen Brown /** 492f89e3b06SLen Brown * dmi_get_slot - return dmi_ident[slot] 493f89e3b06SLen Brown * @slot: index into dmi_ident[] 494f89e3b06SLen Brown */ 495f89e3b06SLen Brown char *dmi_get_slot(int slot) 496f89e3b06SLen Brown { 497f89e3b06SLen Brown return(dmi_ident[slot]); 498f89e3b06SLen Brown } 499