Edit

IABSD.fr/src/sys/dev/i2c/i2c_scan.c

Branch :

  • Show log

    Commit

  • Author : mglocker
    Date : 2024-09-04 07:54:51
    Hash : 9593dc34
    Message : Fix some spelling. Input and ok jmc@, jsg@

  • sys/dev/i2c/i2c_scan.c
  • /*	$OpenBSD: i2c_scan.c,v 1.147 2024/09/04 07:54:52 mglocker Exp $	*/
    
    /*
     * Copyright (c) 2005 Theo de Raadt <deraadt@openbsd.org>
     *
     * Permission to use, copy, modify, and distribute this software for any
     * purpose with or without fee is hereby granted, provided that the above
     * copyright notice and this permission notice appear in all copies.
     *
     * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
     * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
     * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
     * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
     * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
     * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
     * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
     */
    
    /*
     * I2C bus scanning.  We apologize in advance for the massive overuse of 0x.
     */
    
    #include "ipmi.h"
    
    #include <sys/param.h>
    #include <sys/systm.h>
    #include <sys/device.h>
    
    #define _I2C_PRIVATE
    #include <dev/i2c/i2cvar.h>
    
    #undef I2C_DEBUG
    #define I2C_VERBOSE
    
    #define MAX_IGNORE 8
    u_int8_t ignore_addrs[MAX_IGNORE];
    
    struct iicprobelist {
    	u_int8_t start, end;
    };
    
    /*
     * Addresses at which to probe for sensors.  Skip address 0x4f, since
     * probing it seems to crash at least one Sony VAIO laptop.  Only a
     * few chips can actually sit at that address, and vendors seem to
     * place those at other addresses, so this isn't a big loss.
     */
    struct iicprobelist probe_addrs_sensor[] = {
    	{ 0x18, 0x1f },
    	{ 0x20, 0x2f },
    	{ 0x48, 0x4e },
    	{ 0, 0 }
    };
    
    /*
     * Addresses at which to probe for eeprom devices.
     */
    struct iicprobelist probe_addrs_eeprom[] = {
    	{ 0x50, 0x57 },
    	{ 0, 0 }
    };
    
    char 	*iic_probe_sensor(struct device *, u_int8_t);
    char	*iic_probe_eeprom(struct device *, u_int8_t);
    
    #define PFLAG_SENSOR	1
    static struct {
    	struct iicprobelist *pl;
    	char	*(*probe)(struct device *, u_int8_t);
    	int	flags;
    } probes[] = {
    	{ probe_addrs_sensor, iic_probe_sensor, PFLAG_SENSOR },
    	{ probe_addrs_eeprom, iic_probe_eeprom, 0 },
    	{ NULL, NULL }
    };
    
    /*
     * Some Maxim 1617 clones MAY NOT even read cmd 0xfc!  When it is
     * read, they will power-on-reset.  Their default condition
     * (control register bit 0x80) therefore will be that they assert
     * /ALERT for the 5 potential errors that may occur.  One of those
     * errors is that the external temperature diode is missing.  This
     * is unfortunately a common choice of system designers, except
     * suddenly now we get a /ALERT, which may on some chipsets cause
     * us to receive an entirely unexpected SMI .. and then an NMI.
     *
     * As we probe each device, if we hit something which looks suspiciously
     * like it may potentially be a 1617 or clone, we immediately set this
     * variable to avoid reading that register offset.
     */
    int	skip_fc;
    
    static i2c_tag_t probe_ic;
    static u_int8_t probe_addr;
    static u_int8_t probe_val[256];
    
    void		iicprobeinit(struct i2cbus_attach_args *, u_int8_t);
    u_int8_t	iicprobenc(u_int8_t);
    u_int8_t	iicprobe(u_int8_t);
    u_int16_t	iicprobew(u_int8_t);
    char		*lm75probe(void);
    char		*adm1032cloneprobe(u_int8_t);
    void		iic_dump(struct device *, u_int8_t, char *);
    
    void
    iicprobeinit(struct i2cbus_attach_args *iba, u_int8_t addr)
    {
    	probe_ic = iba->iba_tag;
    	probe_addr = addr;
    	memset(probe_val, 0xff, sizeof probe_val);
    }
    
    u_int8_t
    iicprobenc(u_int8_t cmd)
    {
    	u_int8_t data;
    
    	/*
    	 * If we think we are talking to an evil Maxim 1617 or clone,
    	 * avoid accessing this register because it is death.
    	 */
    	if (skip_fc && cmd == 0xfc)
    		return (0xff);
    	iic_acquire_bus(probe_ic, 0);
    	if (iic_exec(probe_ic, I2C_OP_READ_WITH_STOP,
    	    probe_addr, &cmd, sizeof cmd, &data, sizeof data, 0) != 0)
    		data = 0xff;
    	iic_release_bus(probe_ic, 0);
    	return (data);
    }
    
    u_int16_t
    iicprobew(u_int8_t cmd)
    {
    	u_int16_t data;
    
    	/*
    	 * If we think we are talking to an evil Maxim 1617 or clone,
    	 * avoid accessing this register because it is death.
    	 */
    	if (skip_fc && cmd == 0xfc)
    		return (0xffff);
    	iic_acquire_bus(probe_ic, 0);
    	if (iic_exec(probe_ic, I2C_OP_READ_WITH_STOP,
    	    probe_addr, &cmd, sizeof cmd, &data, sizeof data, 0) != 0)
    		data = 0xffff;
    	iic_release_bus(probe_ic, 0);
    	return betoh16(data);
    }
    
    u_int8_t
    iicprobe(u_int8_t cmd)
    {
    	if (probe_val[cmd] != 0xff)
    		return probe_val[cmd];
    	probe_val[cmd] = iicprobenc(cmd);
    	return (probe_val[cmd]);
    }
    
    #define LM75TEMP	0x00
    #define LM75CONF	0x01
    #define LM75Thyst	0x02
    #define LM75Tos		0x03
    #define LM77Tlow	0x04
    #define LM77Thigh	0x05
    #define LM75TMASK	0xff80	/* 9 bits in temperature registers */
    #define LM77TMASK	0xfff8	/* 13 bits in temperature registers */
    
    /*
     * The LM75/LM75A/LM77 family are very hard to detect.  Thus, we check
     * for all other possible chips first.  These chips do not have an
     * ID register.  They do have a few quirks though:
     * -  on the LM75 and LM77, registers 0x06 and 0x07 return whatever
     *    value was read before
     * -  the LM75 lacks registers 0x04 and 0x05, so those act as above
     * -  the LM75A returns 0xffff for registers 0x04, 0x05, 0x06 and 0x07
     * -  the chip registers loop every 8 registers
     * The downside is that we must read almost every register to guess
     * if this is an LM75, LM75A or LM77.
     */
    char *
    lm75probe(void)
    {
    	u_int16_t temp, thyst, tos, tlow, thigh, mask = LM75TMASK;
    	u_int8_t conf;
    	int i, echocount, ffffcount, score;
    	int echoreg67, echoreg45, ffffreg67, ffffreg45;
    
    	temp = iicprobew(LM75TEMP);
    
    	/*
    	 * Sometimes the other probes can upset the chip, if we get 0xffff
    	 * the first time, try it once more.
    	 */
    	if (temp == 0xffff)
    		temp = iicprobew(LM75TEMP);
    
    	conf = iicprobenc(LM75CONF);
    	thyst = iicprobew(LM75Thyst);
    	tos = iicprobew(LM75Tos);
    
    	/* totally bogus data */
    	if (conf == 0xff && temp == 0xffff && thyst == 0xffff)
    		return (NULL);
    
    	temp &= mask;
    	thyst &= mask;
    	tos &= mask;
    
    	/* All values the same?  Very unlikely */
    	if (temp == thyst && thyst == tos)
    		return (NULL);
    
    #if notsure
    	/* more register aliasing effects that indicate not a lm75 */
    	if ((temp >> 8) == conf)
    		return (NULL);
    #endif
    
    	/*
    	 * LM77/LM75 registers 6, 7
    	 * echo whatever was read just before them from reg 0, 1, or 2
    	 *
    	 * LM75A doesn't appear to do this, but does appear to reliably
    	 * return 0xffff
    	 */
    	for (i = 6, echocount = 2, ffffcount = 0; i <= 7; i++) {
    		if ((iicprobew(LM75TEMP) & mask) != (iicprobew(i) & mask) ||
    		    (iicprobew(LM75Thyst) & mask) != (iicprobew(i) & mask) ||
    		    (iicprobew(LM75Tos) & mask) != (iicprobew(i) & mask))
    			echocount--;
    		if (iicprobew(i) == 0xffff)
    			ffffcount++;
    	}
    
    	/* Make sure either both registers echo, or neither does */
    	if (echocount == 1 || ffffcount == 1)
    		return (NULL);
    
    	echoreg67 = (echocount == 0) ? 0 : 1;
    	ffffreg67 = (ffffcount == 0) ? 0 : 1;
    
    	/*
    	 * LM75 has no registers 4 or 5, and they will act as echos too
    	 *
    	 * LM75A doesn't appear to do this either, but does appear to
    	 * reliably return 0xffff
    	 */
    	for (i = 4, echocount = 2, ffffcount = 0; i <= 5; i++) {
    		if ((iicprobew(LM75TEMP) & mask) != (iicprobew(i) & mask) ||
    		    (iicprobew(LM75Thyst) & mask) != (iicprobew(i) & mask) ||
    		    (iicprobew(LM75Tos) & mask) != (iicprobew(i) & mask))
    			echocount--;
    		if (iicprobew(i) == 0xffff)
    			ffffcount++;
    	}
    
    	/* Make sure either both registers echo, or neither does */
    	if (echocount == 1 || ffffcount == 1)
    		return (NULL);
    
    	echoreg45 = (echocount == 0) ? 0 : 1;
    	ffffreg45 = (ffffcount == 0) ? 0 : 1;
    
    	/*
    	 * If we find that 4 and 5 are not echos, and don't return 0xffff
    	 * then based on whether the echo test of registers 6 and 7
    	 * succeeded or not, we may have an LM77
    	 */
    	if (echoreg45 == 0 && ffffreg45 == 0 && echoreg67 == 1) {
    		mask = LM77TMASK;
    
    		/* mask size changed, must re-read for the next checks */
    		thyst = iicprobew(LM75Thyst) & mask;
    		tos = iicprobew(LM75Tos) & mask;
    		tlow = iicprobew(LM77Tlow) & mask;
    		thigh = iicprobew(LM77Thigh) & mask;
    	}
    
    	/* a real LM75/LM75A/LM77 repeats its registers.... */
    	for (i = 0x08; i <= 0xf8; i += 8) {
    		if (conf != iicprobenc(LM75CONF + i) ||
    		    thyst != (iicprobew(LM75Thyst + i) & mask) ||
    		    tos != (iicprobew(LM75Tos + i) & mask))
    			return (NULL);
    
    		/*
    		 * Check that the repeated registers 0x06 and 0x07 still
    		 * either echo or return 0xffff
    		 */
    		if (echoreg67 == 1) {
    			tos = iicprobew(LM75Tos) & mask;
    			if (tos != (iicprobew(0x06 + i) & mask) ||
    			    tos != (iicprobew(0x07 + i) & mask))
    				return (NULL);
    		} else if (ffffreg67 == 1)
    			if (iicprobew(0x06 + i) != 0xffff ||
    			    iicprobew(0x07 + i) != 0xffff)
    				return (NULL);
    
    		/*
    		 * Check that the repeated registers 0x04 and 0x05 still
    		 * either echo or return 0xffff. If they do neither, and
    		 * registers 0x06 and 0x07 echo, then we will be probing
    		 * for an LM77, so make sure those still repeat
    		 */
    		if (echoreg45 == 1) {
    			tos = iicprobew(LM75Tos) & mask;
    			if (tos != (iicprobew(LM77Tlow + i) & mask) ||
    			    tos != (iicprobew(LM77Thigh + i) & mask))
    				return (NULL);
    		} else if (ffffreg45 == 1) {
    			if (iicprobew(LM77Tlow + i) != 0xffff ||
    			    iicprobew(LM77Thigh + i) != 0xffff)
    				return (NULL);
    		} else if (echoreg67 == 1)
    			if (tlow != (iicprobew(LM77Tlow + i) & mask) ||
    			    thigh != (iicprobew(LM77Thigh + i) & mask))
    				return (NULL);
    	}
    
    	/*
    	 * Given that we now know how the first eight registers behave and
    	 * that this behaviour is consistently repeated, we can now use
    	 * the following table:
    	 *
    	 * echoreg67 | echoreg45 | ffffreg67 | ffffreg45 | chip
    	 * ----------+-----------+-----------+-----------+------
    	 *     1     |     1     |     0     |     0     | LM75
    	 *     1     |     0     |     0     |     0     | LM77
    	 *     0     |     0     |     1     |     1     | LM75A
    	 */
    
    	/* Convert the various flags into a single score */
    	score = (echoreg67 << 3) + (echoreg45 << 2) + (ffffreg67 << 1) +
    	    ffffreg45;
    
    	switch (score) {
    	case 12:
    		return ("lm75");
    	case 8:
    		return ("lm77");
    	case 3:
    		return ("lm75a");
    	default:
    #if defined(I2C_DEBUG)
    		printf("lm75probe: unknown chip, scored %d\n", score);
    #endif /* defined(I2C_DEBUG) */
    		return (NULL);
    	}
    }
    
    char *
    adm1032cloneprobe(u_int8_t addr)
    {
    	if (addr == 0x18 || addr == 0x1a || addr == 0x29 ||
    	    addr == 0x2b || addr == 0x4c || addr == 0x4e) {
    		u_int8_t reg, val;
    		int zero = 0, copy = 0;
    
    		val = iicprobe(0x00);
    		for (reg = 0x00; reg < 0x09; reg++) {
    			if (iicprobe(reg) == 0xff)
    				return (NULL);
    			if (iicprobe(reg) == 0x00)
    				zero++;
    			if (val == iicprobe(reg))
    				copy++;
    		}
    		if (zero > 6 || copy > 6)
    			return (NULL);
    		val = iicprobe(0x09);
    		for (reg = 0x0a; reg < 0xfc; reg++) {
    			if (iicprobe(reg) != val)
    				return (NULL);
    		}
    		/* 0xfe may be Maxim, or some other vendor */
    		if (iicprobe(0xfe) == 0x4d)
    			return ("max1617");
    		/*
    		 * "xeontemp" is the name we choose for clone chips
    		 * which have all sorts of buggy bus interactions, such
    		 * as those we just probed.  Why?
    		 * Intel is partly to blame for this situation.
    		 */
    		return ("xeontemp");
    	}
    	return (NULL);
    }
    
    void
    iic_ignore_addr(u_int8_t addr)
    {
    	int i;
    
    	for (i = 0; i < sizeof(ignore_addrs); i++)
    		if (ignore_addrs[i] == 0) {
    			ignore_addrs[i] = addr;
    			return;
    		}
    }
    
    #ifdef I2C_VERBOSE
    void
    iic_dump(struct device *dv, u_int8_t addr, char *name)
    {
    	static u_int8_t iicvalcnt[256];
    	u_int8_t val, val2, max;
    	int i, cnt = 0;
    
    	/*
    	 * Don't bother printing the most often repeated register
    	 * value, since it is often weird devices that respond
    	 * incorrectly, busted controller driver, or in the worst
    	 * case, it in mosts cases, the value 0xff.
    	 */
    	bzero(iicvalcnt, sizeof iicvalcnt);
    	val = iicprobe(0);
    	iicvalcnt[val]++;
    	for (i = 1; i <= 0xff; i++) {
    		val2 = iicprobe(i);
    		iicvalcnt[val2]++;
    		if (val == val2)
    			cnt++;
    	}
    
    	for (val = max = i = 0; i <= 0xff; i++)
    		if (max < iicvalcnt[i]) {
    			max = iicvalcnt[i];
    			val = i;
    		}
    
    	if (cnt == 255)
    		return;
    
    	printf("%s: addr 0x%x", dv->dv_xname, addr);
    	for (i = 0; i <= 0xff; i++) {
    		if (iicprobe(i) != val)
    			printf(" %02x=%02x", i, iicprobe(i));
    	}
    	printf(" words");
    	for (i = 0; i < 8; i++)
    		printf(" %02x=%04x", i, iicprobew(i));
    	if (name)
    		printf(": %s", name);
    	printf("\n");
    }
    #endif /* I2C_VERBOSE */
    
    char *
    iic_probe_sensor(struct device *self, u_int8_t addr)
    {
    	char *name = NULL;
    
    	skip_fc = 0;
    
    	/*
    	 * Many I2C/SMBus devices use register 0x3e as a vendor ID
    	 * register.
    	 */
    	switch (iicprobe(0x3e)) {
    	case 0x01:		/* National Semiconductor */
    		/*
    		 * Some newer National products use a vendor code at
    		 * 0x3e of 0x01, and then 0x3f contains a product code
    		 * But some older products are missing a product code,
    		 * and contain who knows what in that register.  We assume
    		 * that some employee was smart enough to keep the numbers
    		 * unique.
    		 */
    		if ((addr == 0x2c || addr == 0x2d || addr == 0x2e) &&
    		    (iicprobe(0x3f) == 0x73 || iicprobe(0x3f) == 0x72) &&
    		    iicprobe(0x00) == 0x00)
    			name = "lm93";	/* product 0x72 is the prototype */
    		else if ((addr == 0x2c || addr == 0x2d || addr == 0x2e) &&
    		    iicprobe(0x3f) == 0x68)
    			name = "lm96000";	/* adt7460 compat? */
    		else if ((addr == 0x2c || addr == 0x2d || addr == 0x2e) &&
    		    (iicprobe(0x3f) == 0x60 || iicprobe(0x3f) == 0x62))
    			name = "lm85";		/* lm85C/B == adt7460 compat */
    		else if ((addr & 0x7c) == 0x2c &&	/* addr 0b01011xx */
    		    iicprobe(0x48) == addr &&
    		    (iicprobe(0x3f) == 0x03 || iicprobe(0x3f) == 0x04) &&
    		    (iicprobe(0x40) & 0x80) == 0x00)
    			name = "lm81";
    		break;
    	case 0x02:		/* National Semiconductor? */
    		if ((iicprobe(0x3f) & 0xfc) == 0x04)
    			name = "lm87";		/* complete check */
    		break;
    	case 0x23:		/* Analog Devices? */
    		if (iicprobe(0x48) == addr &&
    		    (iicprobe(0x40) & 0x80) == 0x00 &&
    		    (addr & 0x7c) == 0x2c)
    			name = "adm9240";	/* lm87 clone */
    		break;
    	case 0x41:		/* Analog Devices */
    		/*
    		 * Newer chips have a valid 0x3d product number, while
    		 * older ones sometimes encoded the product into the
    		 * upper half of the "step register" at 0x3f.
    		 */
    		if ((addr == 0x2c || addr == 0x2e || addr == 0x2f) &&
    		    iicprobe(0x3d) == 0x70)
    			name = "adt7470";
    		else if ((addr == 0x2c || addr == 0x2d || addr == 0x2e) &&
    		    iicprobe(0x3d) == 0x76)
    			name = "adt7476"; /* or adt7476a */
    		else if (addr == 0x2e && iicprobe(0x3d) == 0x75)
    			name = "adt7475";
    		else if (iicprobe(0x3d) == 0x27 &&
    		    (iicprobe(0x3f) == 0x60 || iicprobe(0x3f) == 0x6a))
    			name = "adm1027";	/* or adt7463 */
    		else if (iicprobe(0x3d) == 0x27 &&
    		    (iicprobe(0x3f) == 0x62 || iicprobe(0x3f) == 0x6a))
    			name = "adt7460";	/* complete check */
    		else if ((addr == 0x2c || addr == 0x2e) &&
    		    iicprobe(0x3d) == 0x62 && iicprobe(0x3f) == 0x04)
    			name = "adt7462";
    		else if (addr == 0x4c &&
    		    iicprobe(0x3d) == 0x66 && iicprobe(0x3f) == 0x02)
    			name = "adt7466";
    		else if (addr == 0x2e &&
    		    iicprobe(0x3d) == 0x68 && (iicprobe(0x3f) & 0xf0) == 0x70)
    			name = "adt7467"; /* or adt7468 */
    		else if (iicprobe(0x3d) == 0x33 && iicprobe(0x3f) == 0x02)
    			name = "adm1033";
    		else if (iicprobe(0x3d) == 0x34 && iicprobe(0x3f) == 0x02)
    			name = "adm1034";
    		else if ((addr == 0x2c || addr == 0x2d || addr == 0x2e) &&
    		    iicprobe(0x3d) == 0x30 &&
    		    (iicprobe(0x01) & 0x80) == 0x00 &&
    		    (iicprobe(0x0d) & 0x70) == 0x00 &&
    		    (iicprobe(0x0e) & 0x70) == 0x00)
    			/*
    			 * Revision 3 seems to be an adm1031 with
    			 * remote diode 2 shorted.  Therefore we
    			 * cannot assume the reserved/unused bits of
    			 * register 0x03 and 0x06 are set to zero.
    			 */
    			name = "adm1030";	/* complete check */
    		else if ((addr == 0x2c || addr == 0x2d || addr == 0x2e) &&
    		    iicprobe(0x3d) == 0x31 &&
    		    (iicprobe(0x01) & 0x80) == 0x00 &&
    		    (iicprobe(0x0d) & 0x70) == 0x00 &&
    		    (iicprobe(0x0e) & 0x70) == 0x00 &&
    		    (iicprobe(0x0f) & 0x70) == 0x00)
    			name = "adm1031";	/* complete check */
    		else if ((addr & 0x7c) == 0x2c &&	/* addr 0b01011xx */
    		    (iicprobe(0x3f) & 0xf0) == 0x20 &&
    		    (iicprobe(0x40) & 0x80) == 0x00 &&
    		    (iicprobe(0x41) & 0xc0) == 0x00 &&
    		    (iicprobe(0x42) & 0xbc) == 0x00)
    			name = "adm1025";	/* complete check */
    		else if ((addr & 0x7c) == 0x2c &&	/* addr 0b01011xx */
    		    (iicprobe(0x3f) & 0xf0) == 0x10 &&
    		    (iicprobe(0x40) & 0x80) == 0x00)
    			name = "adm1024";	/* complete check */
    		else if ((iicprobe(0xff) & 0xf0) == 0x30)
    			name = "adm1023";
    		else if (addr == 0x2e &&
    		    (iicprobe(0x3f) & 0xf0) == 0xd0 &&
    		    (iicprobe(0x40) & 0x80) == 0x00)
    			name = "adm1028";	/* adm1022 clone? */
    		else if ((addr == 0x2c || addr == 0x2e || addr == 0x2f) &&
    		    (iicprobe(0x3f) & 0xf0) == 0xc0 &&
    		    (iicprobe(0x40) & 0x80) == 0x00)
    			name = "adm1022";
    		break;
    	case 0x49:		/* Texas Instruments */
    		if ((addr == 0x2c || addr == 0x2e || addr == 0x2f) &&
    		    (iicprobe(0x3f) & 0xf0) == 0xc0 &&
    		    (iicprobe(0x40) & 0x80) == 0x00)
    			name = "thmc50";	/* adm1022 clone */
    		break;
    	case 0x55:		/* SMSC */
    		if ((addr & 0x7c) == 0x2c &&		/* addr 0b01011xx */
    		    iicprobe(0x3f) == 0x20 &&
    		    (iicprobe(0x47) & 0x70) == 0x00 &&
    		    (iicprobe(0x49) & 0xfe) == 0x80)
    			name = "47m192";	/* adm1025 compat */
    		break;
    	case 0x5c:		/* SMSC */
    		if ((addr == 0x2c || addr == 0x2d || addr == 0x2e) &&
    		    (iicprobe(0x3f) == 0x69))
    			name = "sch5027";
    		else if ((addr == 0x2c || addr == 0x2d || addr == 0x2e) &&
    		    (iicprobe(0x3f) & 0xf0) == 0x60)
    			name = "emc6d100";   /* emc6d101, emc6d102, emc6d103 */
    		else if ((addr == 0x2c || addr == 0x2d || addr == 0x2e) &&
    		    (iicprobe(0x3f) & 0xf0) == 0x80)
    			name = "sch5017";
    		else if ((addr == 0x2c || addr == 0x2d || addr == 0x2e) &&
    		    (iicprobe(0x3f) & 0xf0) == 0xb0)
    			name = "emc6w201";
    		break;
    	case 0x61:		/* Andigilog */
    		if ((addr == 0x2c || addr == 0x2d || addr == 0x2e) &&
    		    iicprobe(0x3f) == 0x69 &&
    		    iicprobe(0x22) >= 0xaf &&		/* Vdd */
    		    (iicprobe(0x09) & 0xbf) == 0x00 && iicprobe(0x0f) == 0x00 &&
    		    (iicprobe(0x40) & 0xf0) == 0x00)
    			name = "asc7611";
    		else if ((addr == 0x2c || addr == 0x2d || addr == 0x2e) &&
    		    iicprobe(0x3f) == 0x6c &&
    		    iicprobe(0x22) >= 0xae)		/* Vdd */
    			name = "asc7621";
    		break;
    	case 0xa1:		/* Philips */
    		if ((iicprobe(0x3f) & 0xf0) == 0x20 &&
    		    (iicprobe(0x40) & 0x80) == 0x00 &&
    		    (iicprobe(0x41) & 0xc0) == 0x00 &&
    		    (iicprobe(0x42) & 0xbc) == 0x00)
    			name = "ne1619";	/* adm1025 compat */
    		break;
    	case 0xda:		/* Dallas Semiconductor */
    		if (iicprobe(0x3f) == 0x01 && iicprobe(0x48) == addr &&
    		    (iicprobe(0x40) & 0x80) == 0x00)
    			name = "ds1780";	/* lm87 clones */
    		break;
    	}
    
    	switch (iicprobe(0x4e)) {
    	case 0x41:		/* Analog Devices */
    		if ((addr == 0x48 || addr == 0x4a || addr == 0x4b) &&
    		    (iicprobe(0x4d) == 0x03 || iicprobe(0x4d) == 0x08 ||
    		    iicprobe(0x4d) == 0x07))
    			name = "adt7516";	/* adt7517, adt7519 */
    		break;
    	}
    
    	switch (iicprobe(0xfe)) {
    	case 0x01:		/* National Semiconductor */
    		if (addr == 0x4c &&
    		    iicprobe(0xff) == 0x41 && (iicprobe(0x03) & 0x18) == 0 &&
    		    iicprobe(0x04) <= 0x0f && (iicprobe(0xbf) & 0xf8) == 0)
    			name = "lm63";
    		else if (addr == 0x4c &&
    		    iicprobe(0xff) == 0x11 && (iicprobe(0x03) & 0x2a) == 0 &&
    		    iicprobe(0x04) <= 0x09 && (iicprobe(0xbf) & 0xf8) == 0)
    			name = "lm86";
    		else if (addr == 0x4c &&
    		    iicprobe(0xff) == 0x31 && (iicprobe(0x03) & 0x2a) == 0 &&
    		    iicprobe(0x04) <= 0x09 && (iicprobe(0xbf) & 0xf8) == 0)
    			name = "lm89";		/* or lm99 */
    		else if (addr == 0x4d &&
    		    iicprobe(0xff) == 0x34 && (iicprobe(0x03) & 0x2a) == 0 &&
    		    iicprobe(0x04) <= 0x09 && (iicprobe(0xbf) & 0xf8) == 0)
    			name = "lm89-1";	/* or lm99-1 */
    		else if (addr == 0x4c &&
    		    iicprobe(0xff) == 0x21 && (iicprobe(0x03) & 0x2a) == 0 &&
    		    iicprobe(0x04) <= 0x09 && (iicprobe(0xbf) & 0xf8) == 0)
    			name = "lm90";
    		break;
    	case 0x23:		/* Genesys Logic? */
    		if ((addr == 0x4c) &&
    		    (iicprobe(0x03) & 0x3f) == 0x00 && iicprobe(0x04) <= 0x08)
    			/*
    			 * Genesys Logic doesn't make the datasheet
    			 * for the GL523SM publicly available, so
    			 * the checks above are nothing more than a
    			 * (conservative) educated guess.
    			 */
    			name = "gl523sm";
    		break;
    	case 0x41:		/* Analog Devices */
    		if ((addr == 0x4c || addr == 0x4d) &&
    		    iicprobe(0xff) == 0x51 &&
    		    (iicprobe(0x03) & 0x1f) == 0x04 &&
    		    iicprobe(0x04) <= 0x0a) {
    			/* If not in adm1032 compatibility mode. */
    			name = "adt7461";
    		} else if ((addr == 0x18 || addr == 0x19 || addr == 0x1a ||
    		    addr == 0x29 || addr == 0x2a || addr == 0x2b ||
    		    addr == 0x4c || addr == 0x4d || addr == 0x4e) &&
    		    (iicprobe(0xff) & 0xf0) == 0x00 &&
    		    (iicprobe(0x03) & 0x3f) == 0x00 &&
    		    iicprobe(0x04) <= 0x07) {
    			name = "adm1021";
    			skip_fc = 1;
    		} else if ((addr == 0x18 || addr == 0x19 || addr == 0x1a ||
    		    addr == 0x29 || addr == 0x2a || addr == 0x2b ||
    		    addr == 0x4c || addr == 0x4d || addr == 0x4e) &&
    		    (iicprobe(0xff) & 0xf0) == 0x30 &&
    		    (iicprobe(0x03) & 0x3f) == 0x00 &&
    		    iicprobe(0x04) <= 0x07) {
    			name = "adm1023";	/* or adm1021a */
    			skip_fc = 1;
    		} else if ((addr == 0x4c || addr == 0x4d || addr == 0x4e) &&
    		    (iicprobe(0x03) & 0x3f) == 0x00 &&
    		    iicprobe(0x04) <= 0x0a) {
    			name = "adm1032";	/* or adm1020 */
    			skip_fc = 1;
    		}
    		break;
    	case 0x47:		/* Global Mixed-mode Technology */
    		if (addr == 0x4c && iicprobe(0xff) == 0x01 &&
    		    (iicprobe(0x03) & 0x3f) == 0x00 && iicprobe(0x04) <= 0x08)
    			name = "g781";
    		if (addr == 0x4d && iicprobe(0xff) == 0x03 &&
    		    (iicprobe(0x03) & 0x3f) == 0x00 && iicprobe(0x04) <= 0x08)
    			name = "g781-1";
    		break;
    	case 0x4d:		/* Maxim */
    		if ((addr == 0x18 || addr == 0x19 || addr == 0x1a ||
    		     addr == 0x29 || addr == 0x2a || addr == 0x2b ||
    		     addr == 0x4c || addr == 0x4d || addr == 0x4e) &&
    		    iicprobe(0xff) == 0x08 && (iicprobe(0x02) & 0x03) == 0 &&
    		    (iicprobe(0x03) & 0x07) == 0 && iicprobe(0x04) <= 0x08)
    			name = "max6690";
    		else if ((addr == 0x4c || addr == 0x4d || addr == 0x4e) &&
    		    iicprobe(0xff) == 0x59 && (iicprobe(0x03) & 0x1f) == 0 &&
    		    iicprobe(0x04) <= 0x07)
    			name = "max6646";	/* max6647/8/9, max6692 */
    		else if ((addr == 0x4c || addr == 0x4d || addr == 0x4e) &&
    		    (iicprobe(0x02) & 0x2b) == 0 &&
    		    (iicprobe(0x03) & 0x0f) == 0 && iicprobe(0x04) <= 0x09) {
    			name = "max6657";	/* max6658, max6659 */
    			skip_fc = 1;
    		} else if ((addr >= 0x48 && addr <= 0x4f) &&
    		    (iicprobe(0x02) & 0x2b) == 0 &&
    		    (iicprobe(0x03) & 0x0f) == 0)
    			name = "max6642";
    		break;
    	case 0x55:		/* Texas Instruments */
    		if (addr == 0x4c && iicprobe(0xff) == 0x11 &&
    		    (iicprobe(0x03) & 0x1b) == 0x00 &&
    		    (iicprobe(0x04) & 0xf0) == 0x00 &&
    		    (iicprobe(0x10) & 0x0f) == 0x00 &&
    		    (iicprobe(0x13) & 0x0f) == 0x00 &&
    		    (iicprobe(0x14) & 0x0f) == 0x00 &&
    		    (iicprobe(0x15) & 0x0f) == 0x00 &&
    		    (iicprobe(0x16) & 0x0f) == 0x00 &&
    		    (iicprobe(0x17) & 0x0f) == 0x00)
    			name = "tmp401";
    		break;
    	case 0xa1:
    		if ((addr >= 0x48 && addr <= 0x4f) &&
    		    iicprobe(0xff) == 0x00 &&
    		    (iicprobe(0x03) & 0xf8) == 0x00 &&
    		    iicprobe(0x04) <= 0x09) {
    			name = "sa56004x";	/* NXP sa56004x */
    			skip_fc = 1;
    		}
    		break;
    	}
    
    	if (addr == iicprobe(0x48) &&
    	    ((iicprobe(0x4f) == 0x5c && (iicprobe(0x4e) & 0x80)) ||
    	    (iicprobe(0x4f) == 0xa3 && !(iicprobe(0x4e) & 0x80)))) {
    		/*
    		 * We could toggle 0x4e bit 0x80, then re-read 0x4f to
    		 * see if the value changes to 0xa3 (indicating Winbond).
    		 * But we are trying to avoid writes.
    		 */
    		if ((iicprobe(0x4e) & 0x07) == 0) {
    			switch (iicprobe(0x58)) {
    			case 0x10:
    			case 0x11:			/* rev 2? */
    				name = "w83781d";
    				break;
    			case 0x21:
    				name = "w83627hf";
    				break;
    			case 0x30:
    				name = "w83782d";
    				break;
    			case 0x31:
    				name = "as99127f";	/* rev 2 */
    				break;
    			case 0x40:
    				name = "w83783s";
    				break;
    			case 0x71:
    				name = "w83791d";
    				break;
    			case 0x72:
    				name = "w83791sd";
    				break;
    			case 0x7a:
    				name = "w83792d";
    				break;
    			case 0xc1:
    				name = "w83627dhg";
    				break;
    			}
    		} else {
    			/*
    			 * The BIOS left the chip in a non-zero
    			 * register bank.  Assume it's a W83781D and
    			 * let lm(4) sort out the real model.
    			 */
    			name = "w83781d";
    		}
    	} else if (addr == (iicprobe(0xfc) & 0x7f) &&
    	    iicprobe(0xfe) == 0x79 && iicprobe(0xfb) == 0x51 &&
    	    ((iicprobe(0xfd) == 0x5c && (iicprobe(0x00) & 0x80)) ||
    	    (iicprobe(0xfd) == 0xa3 && !(iicprobe(0x00) & 0x80)))) {
    		/*
    		 * We could toggle 0x00 bit 0x80, then re-read 0xfd to
    		 * see if the value changes to 0xa3 (indicating Nuvoton).
    		 * But we are trying to avoid writes.
    		 */
    		name = "w83795g";
    	} else if (addr == iicprobe(0x4a) && iicprobe(0x4e) == 0x50 &&
    	    iicprobe(0x4c) == 0xa3 && iicprobe(0x4d) == 0x5c) {
    		name = "w83l784r";
    	} else if (addr == 0x2d && iicprobe(0x4e) == 0x60 &&
    	    iicprobe(0x4c) == 0xa3 && iicprobe(0x4d) == 0x5c) {
    		name = "w83l785r";
    	} else if (addr == 0x2e && iicprobe(0x4e) == 0x70 &&
    	    iicprobe(0x4c) == 0xa3 && iicprobe(0x4d) == 0x5c) {
    		name = "w83l785ts-l";
    	} else if (addr >= 0x2c && addr <= 0x2f &&
    	    ((iicprobe(0x00) & 0x07) != 0x0 ||
    	    ((iicprobe(0x00) & 0x07) == 0x0 && addr * 2 == iicprobe(0x0b) &&
    	    (iicprobe(0x0c) & 0x40) && !(iicprobe(0x0c) & 0x04))) &&
    	    iicprobe(0x0e) == 0x7b &&
    	    (iicprobe(0x0f) & 0xf0) == 0x10 &&
    	    ((iicprobe(0x0d) == 0x5c && (iicprobe(0x00) & 0x80)) ||
    	    (iicprobe(0x0d) == 0xa3 && !(iicprobe(0x00) & 0x80)))) {
    		name = "w83793g";
    	} else if (addr >= 0x28 && addr <= 0x2f &&
    	    iicprobe(0x4f) == 0x12 && (iicprobe(0x4e) & 0x80)) {
    		/*
    		 * We could toggle 0x4e bit 0x80, then re-read 0x4f to
    		 * see if the value changes to 0xc3 (indicating ASUS).
    		 * But we are trying to avoid writes.
    		 */
    		if (iicprobe(0x58) == 0x31)
    			name = "as99127f";	/* rev 1 */
    	} else if ((addr == 0x2d || addr == 0x2e) &&
    	    addr * 2 == iicprobe(0x04) &&
    	    iicprobe(0x5d) == 0x19 && iicprobe(0x5e) == 0x34 &&
    	    iicprobe(0x5a) == 0x03 && iicprobe(0x5b) == 0x06) {
    		name = "f75375";	/* Fintek */
    	} else if (addr == 0x2d &&
    	    ((iicprobe(0x4f) == 0x06 && (iicprobe(0x4e) & 0x80)) ||
    	    (iicprobe(0x4f) == 0x94 && !(iicprobe(0x4e) & 0x80)))) {
    		/*
    		 * We could toggle 0x4e bit 0x80, then re-read 0x4f to
    		 * see if the value changes to 0x94 (indicating ASUS).
    		 * But we are trying to avoid writes.
    		 *
    		 * NB. we won't match if the BIOS has selected a non-zero
    		 * register bank (set via 0x4e). We could select bank 0 so
    		 * we see the right registers, but that would require a
    		 * write.  In general though, we bet no BIOS would leave us
    		 * in the wrong state.
    		 */
    		if ((iicprobe(0x58) & 0x7f) == 0x31 &&
    		    (iicprobe(0x4e) & 0xf) == 0x00)
    			name = "asb100";
    	} else if ((addr == 0x2c || addr == 0x2d) &&
    	    iicprobe(0x00) == 0x80 &&
    	    (iicprobe(0x01) == 0x00 || iicprobe(0x01) == 0x80) &&
    	    iicprobe(0x02) == 0x00 && (iicprobe(0x03) & 0x83) == 0x00 &&
    	    (iicprobe(0x0f) & 0x07) == 0x00 &&
    	    (iicprobe(0x11) & 0x80) == 0x00 &&
    	    (iicprobe(0x12) & 0x80) == 0x00) {
    		/*
    		 * The GL518SM is really crappy.  It has both byte and
    		 * word registers, and reading a word register with a
    		 * byte read command will make the device crap out and
    		 * hang the bus.  This has nasty consequences on some
    		 * machines, like preventing warm reboots.  The word
    		 * registers are 0x07 through 0x0c, so make sure the
    		 * checks above don't access those registers.  We
    		 * don't want to do this check right up front though
    		 * since this chip is somewhat hard to detect (which
    		 * is why we check for every single fixed bit it has).
    		 */
    		name = "gl518sm";
    	} else if ((addr == 0x2c || addr == 0x2d || addr == 0x2e) &&
    	    iicprobe(0x16) == 0x41 && ((iicprobe(0x17) & 0xf0) == 0x40)) {
    		name = "adm1026";
    	} else if ((addr & 0x78) == 0x18 && iicprobew(0x06) == 0x1131 &&
    	    (iicprobew(0x07) & 0xfffc) == 0xa200) {
    		name = "se97";		/* or se97b */
    	} else if ((addr & 0x78) == 0x18 && iicprobew(0x06) == 0x1131 &&
    	    (iicprobew(0x07) & 0xfffc) == 0xa100 &&
    	    (iicprobew(0x00) & 0xfff0) == 0x0010) {
    		name = "se98";
    	} else if ((addr & 0x78) == 0x18 && iicprobew(0x06) == 0x004d &&
    	    iicprobew(0x07) == 0x3e00 &&
    	    (iicprobew(0x00) & 0xffe0) == 0x0000) {
    		name = "max6604";
    	} else if ((addr & 0x78) == 0x18 && iicprobew(0x06) == 0x0054 &&
    	    (iicprobew(0x07) & 0xfffc) == 0x0200 &&
    	    (iicprobew(0x00) & 0xffe0) == 0x0000) {
    		name = "mcp9804";
    	} else if ((addr & 0x78) == 0x18 && iicprobew(0x06) == 0x0054 &&
    	    (iicprobew(0x07) & 0xff00) == 0x0000 &&
    	    (iicprobew(0x00) & 0xffe0) == 0x0000) {
    		name = "mcp9805";		/* or mcp9843 */
    	} else if ((addr & 0x78) == 0x18 && iicprobew(0x06) == 0x0054 &&
    	    (iicprobew(0x07) & 0xfffc) == 0x2000 &&
    	    (iicprobew(0x00) & 0xffe0) == 0x0000) {
    		name = "mcp98242";
    	} else if ((addr & 0x78) == 0x18 && iicprobew(0x06) == 0x0054 &&
    	    (iicprobew(0x07) & 0xff00) == 0x2100 &&
    	    (iicprobew(0x00) & 0xff00) == 0x0000) {
    		name = "mcp98243";
    	} else if ((addr & 0x78) == 0x18 && iicprobew(0x06) == 0x0054 &&
    	    (iicprobew(0x07) & 0xfffc) == 0x2200 &&
    	    (iicprobew(0x00) & 0xff00) == 0x0000) {
    		name = "mcp98244";
    	} else if ((addr & 0x78) == 0x18 && iicprobew(0x06) == 0x11d4 &&
    	    iicprobew(0x07) == 0x0800 &&
    	    iicprobew(0x00) == 0x001d) {
    		name = "adt7408";
    	} else if ((addr & 0x78) == 0x18 && iicprobew(0x06) == 0x104a &&
    	    (iicprobew(0x07) & 0xfffe) == 0x0000 &&
    	    (iicprobew(0x00) == 0x002d || iicprobew(0x00) == 0x002f)) {
    		name = "stts424e02";
    	} else if ((addr & 0x78) == 0x18 && iicprobew(0x06) == 0x104a &&
    	    (iicprobew(0x07) & 0xfffe) == 0x0300 &&
    	    (iicprobew(0x00) == 0x006f)) {
    		name = "stts2002";
    	} else if ((addr & 0x78) == 0x18 && iicprobew(0x06) == 0x104a &&
    	    (iicprobew(0x07) & 0xffff) == 0x2201 &&
    	    (iicprobew(0x00) == 0x00ef)) {
    		name = "stts2004";
    	} else if ((addr & 0x78) == 0x18 && iicprobew(0x06) == 0x104a &&
    	    (iicprobew(0x07) & 0xffff) == 0x0200 &&
    	    (iicprobew(0x00) == 0x006f)) {
    		name = "stts3000";
    	} else if ((addr & 0x78) == 0x18 && iicprobew(0x06) == 0x104a &&
    	    (iicprobew(0x07) & 0xffff) == 0x0101 &&
    	    (iicprobew(0x00) == 0x002d || iicprobew(0x00) == 0x002f)) {
    		name = "stts424";
    	} else if ((addr & 0x78) == 0x18 && iicprobew(0x06) == 0x1b09 &&
    	    (iicprobew(0x07) & 0xffe0) == 0x0800 &&
    	    (iicprobew(0x00) & 0x001f) == 0x001f) {
    		name = "cat34ts02";		/* or cat6095, prod 0x0813 */
    	} else if ((addr & 0x78) == 0x18 && iicprobew(0x06) == 0x1b09 &&
    	    (iicprobew(0x07) & 0xffff) == 0x0a00 &&
    	    (iicprobew(0x00) & 0x001f) == 0x001f) {
    		name = "cat34ts02c";
    	} else if ((addr & 0x78) == 0x18 && iicprobew(0x06) == 0x1b09 &&
    	    (iicprobew(0x07) & 0xffff) == 0x2200 &&
    	    (iicprobew(0x00) == 0x007f)) {
    		name = "cat34ts04";
    	} else if ((addr & 0x78) == 0x18 && iicprobew(0x06) == 0x00b3 &&
    	    (iicprobew(0x07) & 0xffff) == 0x2903 &&
    	    (iicprobew(0x00) == 0x004f)) {
    		name = "ts3000b3";		/* or tse2002b3 */
    	} else if ((addr & 0x78) == 0x18 && iicprobew(0x06) == 0x00b3 &&
    	    (iicprobew(0x07) & 0xffff) == 0x2912 &&
    	    (iicprobew(0x00) == 0x006f)) {
    		name = "ts3000gb2";		/* or tse2002gb2 */
    	} else if ((addr & 0x78) == 0x18 && iicprobew(0x06) == 0x00b3 &&
    	    (iicprobew(0x07) & 0xffff) == 0x2913 &&
    	    (iicprobew(0x00) == 0x0077)) {
    		name = "ts3000gb0";
    	} else if ((addr & 0x78) == 0x18 && iicprobew(0x06) == 0x00b3 &&
    	    (iicprobew(0x07) & 0xffff) == 0x3001 &&
    	    (iicprobew(0x00) == 0x006f)) {
    		name = "ts3001gb2";
    	} else if ((addr & 0x78) == 0x18 && iicprobew(0x06) == 0x00b3 &&
    	    (iicprobew(0x07) & 0xffff) == 0x2214 &&
    	    (iicprobew(0x00) == 0x00ff)) {
    		name = "tse2004gb2";
    	} else if ((addr & 0x78) == 0x18 && iicprobew(0x06) == 0x001f &&
    	    (iicprobew(0x07) & 0xffff) == 0x8201 &&
    	    (iicprobew(0x00) & 0xff00) == 0x0000) {
    		name = "at30ts00";		/* or at30tse002 */
    	} else if ((addr & 0x78) == 0x18 && iicprobew(0x06) == 0x1114 &&
    	    (iicprobew(0x07) & 0xffff) == 0x2200 &&
    	    (iicprobew(0x00) & 0xff00) == 0x0000) {
    		name = "at30tse004";
    	} else if ((addr & 0x78) == 0x18 && iicprobew(0x06) == 0x1c68 &&
    	    (iicprobew(0x07) & 0xffff) == 0x2201 &&
    	    (iicprobew(0x00) & 0xff00) == 0x0000) {
    		name = "gt30ts00";
    	} else if ((addr & 0x78) == 0x18 && iicprobew(0x06) == 0x132d &&
    	    (iicprobew(0x07) & 0xffff) == 0x3300 &&
    	    (iicprobew(0x00) & 0x001f) == 0x001f) {
    		name = "gt34ts02";
    	} else if ((addr & 0x7e) == 0x1c && iicprobe(0x0f) == 0x3b &&
    	    (iicprobe(0x21) & 0x60) == 0x00 &&
    	    iicprobe(0x0f) == iicprobe(0x8f) &&	/* registers address is 7 bits */
    	    iicprobe(0x20) == iicprobe(0xa0) &&
    	    iicprobe(0x21) == iicprobe(0xa1) &&
    	    iicprobe(0x22) == iicprobe(0xa2) &&
    	    iicprobe(0x07) == 0x00) {		/* 0x00 to 0x0e are reserved */
    		name = "lis331dl";
    	} else if (name == NULL &&
    	    (addr & 0x78) == 0x48) {		/* addr 0b1001xxx */
    		name = lm75probe();
    	}
    #if 0
    	/*
    	 * XXX This probe needs to be improved; the driver does some
    	 * dangerous writes.
    	 */
    	if (name == NULL && (addr & 0x7c) == 0x48 &&	/* addr 0b1001xxx */
    	    (iicprobew(0xaa) & 0x0007) == 0x0000 &&
    	    (iicprobew(0xa1) & 0x0007) == 0x0000 &&
    	    (iicprobew(0xa2) & 0x0007) == 0x0000 &&
    	    (iicprobe(0xac) & 0x10) == 0x00) {
    		if ((iicprobe(0xac) & 0x7e) == 0x0a &&
    		    iicprobe(0xab) == 0x00 && iicprobe(0xa8) == 0x00)
    			name = "ds1624";
    		else if ((iicprobe(0xac) & 0x7e) == 0x0c)
    			name = "ds1631";	/* terrible probe */
    		else if ((iicprobe(0xac) & 0x2e) == 0x2e)
    			name = "ds1721";	/* terrible probe */
    	}
    #endif
    	if (name == NULL && (addr & 0xf8) == 0x28 && iicprobe(0x48) == addr &&
    	    (iicprobe(0x00) & 0x90) == 0x10 && iicprobe(0x58) == 0x90) {
    		if (iicprobe(0x5b) == 0x12)
    			name = "it8712";
    		else if (iicprobe(0x5b) == 0x00)
    			name = "it8712f-a";		/* sis950 too */
    	}
    
    	if (name == NULL && iicprobe(0x48) == addr &&
    	    (iicprobe(0x40) & 0x80) == 0x00 && iicprobe(0x58) == 0xac)
    		name = "mtp008";
    
    	if (name == NULL) {
    		name = adm1032cloneprobe(addr);
    		if (name)
    			skip_fc = 1;
    	}
    
    	return (name);
    }
    
    char *
    iic_probe_eeprom(struct device *self, u_int8_t addr)
    {
    	u_int8_t type;
    	char *name = NULL;
    
    	type = iicprobe(0x02);
    	/* limit to SPD types seen in the wild */
    	if (type < 4 || type > 16)
    		return (name);
    
    	/* more matching in driver(s) */
    	name = "eeprom";
    
    	return (name);
    }
    
    void
    iic_scan(struct device *self, struct i2cbus_attach_args *iba)
    {
    	i2c_tag_t ic = iba->iba_tag;
    	struct i2c_attach_args ia;
    	struct iicprobelist *pl;
    	u_int8_t cmd = 0, addr;
    	char *name;
    	int i, j, k;
    
    	bzero(ignore_addrs, sizeof(ignore_addrs));
    
    	for (i = 0; probes[i].probe; i++) {
    #if NIPMI > 0
    		extern int ipmi_enabled;
    
    		if ((probes[i].flags & PFLAG_SENSOR) && ipmi_enabled) {
    			printf("%s: skipping sensors to avoid ipmi0 interactions\n",
    			    self->dv_xname);
    			continue;
    		}
    #endif
    		pl = probes[i].pl;
    		for (j = 0; pl[j].start && pl[j].end; j++) {
    			for (addr = pl[j].start; addr <= pl[j].end; addr++) {
    				for (k = 0; k < sizeof(ignore_addrs); k++)
    					if (ignore_addrs[k] == addr)
    						break;
    				if (k < sizeof(ignore_addrs))
    					continue;
    
    				/* Perform RECEIVE BYTE command */
    				iic_acquire_bus(ic, 0);
    				if (iic_exec(ic, I2C_OP_READ_WITH_STOP, addr,
    				    &cmd, sizeof cmd, NULL, 0, 0) == 0) {
    					iic_release_bus(ic, 0);
    
    					/* Some device exists */
    					iicprobeinit(iba, addr);
    					name = (*probes[i].probe)(self, addr);
    #ifndef I2C_VERBOSE
    					if (name == NULL)
    						name = "unknown";
    #endif /* !I2C_VERBOSE */
    					if (name) {
    						memset(&ia, 0, sizeof(ia));
    						ia.ia_tag = iba->iba_tag;
    						ia.ia_addr = addr;
    						ia.ia_size = 1;
    						ia.ia_name = name;
    						if (config_found(self,
    						    &ia, iic_print))
    							continue;
    					}
    #ifdef I2C_VERBOSE
    					if ((probes[i].flags & PFLAG_SENSOR))
    						iic_dump(self, addr, name);
    #endif /* I2C_VERBOSE */
    				} else
    					iic_release_bus(ic, 0);
    			}
    		}
    	}
    }