summaryrefslogtreecommitdiff
path: root/sys/dev
diff options
context:
space:
mode:
Diffstat (limited to 'sys/dev')
-rw-r--r--sys/dev/i2c/i2c_scan.c43
1 files changed, 39 insertions, 4 deletions
diff --git a/sys/dev/i2c/i2c_scan.c b/sys/dev/i2c/i2c_scan.c
index 9a7ab32e54f..1338cb22f5f 100644
--- a/sys/dev/i2c/i2c_scan.c
+++ b/sys/dev/i2c/i2c_scan.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: i2c_scan.c,v 1.34 2005/12/29 01:25:31 deraadt Exp $ */
+/* $OpenBSD: i2c_scan.c,v 1.35 2005/12/29 09:20:04 deraadt Exp $ */
/*
* Copyright (c) 2005 Theo de Raadt <deraadt@openbsd.org>
@@ -52,6 +52,22 @@ u_int8_t probereg[] = {
0x58, 0xfe, 0xff
};
+/*
+ * 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];
@@ -75,6 +91,12 @@ 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);
probe_ic->ic_acquire_bus(probe_ic->ic_cookie, I2C_F_POLL);
if (iic_exec(probe_ic, I2C_OP_READ_WITH_STOP,
probe_addr, &cmd, 1, &data, 1, I2C_F_POLL) != 0)
@@ -88,6 +110,12 @@ iicprobew(u_int8_t cmd)
{
u_int16_t data2;
+ /*
+ * 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);
probe_ic->ic_acquire_bus(probe_ic->ic_cookie, I2C_F_POLL);
if (iic_exec(probe_ic, I2C_OP_READ_WITH_STOP,
probe_addr, &cmd, 1, &data2, 2, I2C_F_POLL) != 0)
@@ -174,7 +202,7 @@ xeonprobe(u_int8_t addr)
if (zero > 6 || copy > 6)
return (NULL);
val = iicprobe(0x09);
- for (reg = 0x0a; reg < 0xfe; reg++) {
+ for (reg = 0x0a; reg < 0xfc; reg++) {
if (iicprobe(reg) != val)
return (NULL);
}
@@ -211,6 +239,7 @@ iic_probe(struct device *self, struct i2cbus_attach_args *iba, u_int8_t addr)
return;
iicprobeinit(iba, addr);
+ skip_fc = 0;
switch (iicprobe(0x3e)) {
case 0x41:
@@ -372,11 +401,13 @@ iic_probe(struct device *self, struct i2cbus_attach_args *iba, u_int8_t addr)
} else if (iicprobe(0xfe) == 0x41 && (addr == 0x4c || addr == 0x4d) &&
(iicprobe(0x03) & 0x2a) == 0 && iicprobe(0x04) <= 0x09) {
name = "adm1032";
+ skip_fc = 1;
} else if (iicprobe(0xfe) == 0x41 && iicprobe(0x3c) == 0x00 &&
(addr == 0x18 || addr == 0x19 || addr == 0x1a ||
addr == 0x29 || addr == 0x2a || addr == 0x2b ||
addr == 0x4c || addr == 0x4d || addr == 0x4e)) {
name = "adm1021"; /* lots of addresses... bleah */
+ skip_fc = 1;
} else if (iicprobe(0x4f) == 0x5c && (iicprobe(0x4e) & 0x80)) {
/*
* We should toggle 0x4e bit 0x80, then re-read
@@ -392,17 +423,21 @@ iic_probe(struct device *self, struct i2cbus_attach_args *iba, u_int8_t addr)
#ifdef __i386__
} else if (name == NULL) {
name = xeonprobe(addr);
+ if (name)
+ skip_fc = 1;
#endif
}
#ifdef I2C_DEBUG
printf("%s: addr 0x%x", self->dv_xname, addr);
-// for (i = 0; i < sizeof(probereg); i++)
+// for (i = 0; i < sizeof(probereg); i++) {
// if (iicprobe(probereg[i]) != 0xff)
// printf(" %02x=%02x", probereg[i], iicprobe(probereg[i]));
- for (i = 0; i <= 0xff; i++)
+// }
+ for (i = 0; i <= 0xff; i++) {
if (iicprobe(i) != 0xff)
printf(" %02x=%02x", i, iicprobe(i));
+ }
if (name)
printf(": %s", name);
printf("\n");