/*	$OpenBSD: i2c_scan.c,v 1.145 2015/05/29 00:37:10 uebayasi 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 publically 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 > 11)
		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);
			}
		}
	}
}
