From 783c6a0ed6fa065e9fb8a0bd7dfdb6f1ffdc50e7 Mon Sep 17 00:00:00 2001 From: Jean Delvare Date: Wed, 21 Apr 2004 20:58:05 +0000 Subject: [PATCH] Adapt probing method to address. Should prevent any kind of EEPROM corruption. Previous method (quick writes for every address) can be forced with -q. Read bytes can be forced with -r. git-svn-id: http://lm-sensors.org/svn/lm-sensors/trunk@2465 7894878c-1315-0410-8ee3-d5d059ff63e0 --- prog/detect/i2cdetect.8 | 13 +++++ prog/detect/i2cdetect.c | 123 ++++++++++++++++++++++++++++------------ 2 files changed, 100 insertions(+), 36 deletions(-) diff --git a/prog/detect/i2cdetect.8 b/prog/detect/i2cdetect.8 index f0844b96..8c717857 100644 --- a/prog/detect/i2cdetect.8 +++ b/prog/detect/i2cdetect.8 @@ -5,6 +5,7 @@ i2cdetect \- detect I\u2\dC chips .SH SYNOPSIS .B i2cdetect .RI [ -f ] +.RI [ -q | -r ] .I i2cbus .br .B i2cdetect @@ -24,6 +25,18 @@ This program can confuse your I\u2\dC bus, cause data loss and worse! .B "\-f" Force scanning of non-regular addresses. Not recommended. .TP +.B "\-q" +Use SMBus "quick write" commands for probing (by default, the command +used is the one believed to be the safest for each address). +Not recommended. This is known to corrupt the Atmel AT24RF08 EEPROM +found on many IBM Thinkpad laptops. +.TP +.B "\-r" +Use SMBus "read byte" commands for probing (by default, the command +used is the one believed to be the safest for each address). +Not recommended. This is known to lock SMBus on various write-only +chips (most notably clock chips at address 0x69). +.TP .B "\-l" Output a list of installed busses. diff --git a/prog/detect/i2cdetect.c b/prog/detect/i2cdetect.c index 8d965914..75ff2176 100644 --- a/prog/detect/i2cdetect.c +++ b/prog/detect/i2cdetect.c @@ -28,13 +28,19 @@ #include "i2c-dev.h" #include "version.h" +#define MODE_AUTO 0 +#define MODE_QUICK 1 +#define MODE_READ 2 + void print_i2c_busses(int); void help(void) { - fprintf(stderr,"Syntax: i2cdetect [-f] I2CBUS\n"); + fprintf(stderr,"Syntax: i2cdetect [-f] [-q|-r] I2CBUS\n"); fprintf(stderr," I2CBUS is an integer\n"); fprintf(stderr," With -f, scans all addresses (NOT RECOMMENDED)\n"); + fprintf(stderr," With -q, uses only quick write commands for probing (NOT RECOMMENDED)\n"); + fprintf(stderr," With -r, uses only read byte commands for probing (NOT RECOMMENDED)\n"); fprintf(stderr," i2cdetect -l lists installed busses only\n"); print_i2c_busses(0); } @@ -42,7 +48,7 @@ void help(void) int main(int argc, char *argv[]) { char *end; - int i,j,res,i2cbus,file; + int i=1,j,res,i2cbus=-1,file; int e1, e2, e3; char filename1[20]; char filename2[20]; @@ -50,45 +56,59 @@ int main(int argc, char *argv[]) char *filename; long funcs; int force = 0; + int mode = MODE_AUTO; - if (argc < 2) { - fprintf(stderr,"Error: No i2c-bus specified!\n"); - help(); - exit(1); - } - - if((!strcmp(argv[1], "-v")) || (!strcmp(argv[1], "-V"))) { - fprintf(stderr,"i2cdetect version %s\n", LM_VERSION); - exit(0); - } - - if(!strcmp(argv[1], "-l")) { - print_i2c_busses(1); - exit(0); - } - - if(!strcmp(argv[1], "-f")) { - force = 1; - if (argc < 3) { + while(i2cbus == -1) { + if (i >= argc) { fprintf(stderr,"Error: No i2c-bus specified!\n"); help(); exit(1); } - } - i2cbus = strtol(argv[force?2:1],&end,0); - if (*end) { - fprintf(stderr,"Error: I2CBUS argument not a number!\n"); - help(); - exit(1); - } - if ((i2cbus < 0) || (i2cbus > 0xff)) { - fprintf(stderr,"Error: I2CBUS argument out of range!\n"); - help(); - exit(1); - } + if(!strcasecmp(argv[i], "-v")) { + fprintf(stderr,"i2cdetect version %s\n", LM_VERSION); + exit(0); + } + if(!strcmp(argv[i], "-l")) { + print_i2c_busses(1); + exit(0); + } + + if(!strcmp(argv[i], "-f")) { + force = 1; + i++; + } else + if(!strcmp(argv[i], "-q")) { + if (mode != MODE_AUTO) { + fprintf(stderr,"Error: Different modes specified!\n"); + exit(1); + } + mode = MODE_QUICK; + i++; + } else + if(!strcmp(argv[i], "-r")) { + if (mode != MODE_AUTO) { + fprintf(stderr,"Error: Different modes specified!\n"); + exit(1); + } + mode = MODE_READ; + i++; + } else { + i2cbus = strtol(argv[i],&end,0); + if (*end) { + fprintf(stderr,"Error: I2CBUS argument not a number!\n"); + help(); + exit(1); + } + if ((i2cbus < 0) || (i2cbus > 0xff)) { + fprintf(stderr,"Error: I2CBUS argument out of range!\n"); + help(); + exit(1); + } + } + } /* * Try all three variants and give the correct error message * upon failure @@ -140,18 +160,29 @@ int main(int argc, char *argv[]) fprintf(stderr, "Error: Could not get the adapter functionality matrix: %s\n", strerror(errno)); + close(file); exit(1); } - if (! (funcs & I2C_FUNC_SMBUS_QUICK)) { + if (mode != MODE_READ && !(funcs & I2C_FUNC_SMBUS_QUICK)) { fprintf(stderr, "Error: Can't use SMBus Quick Write command " "on this bus (ISA bus?)\n"); + close(file); + exit(1); + } + if (mode != MODE_QUICK && !(funcs & I2C_FUNC_SMBUS_READ_BYTE)) { + fprintf(stderr, + "Error: Can't use SMBus Read Byte command " + "on this bus (ISA bus?)\n"); + close(file); exit(1); } fprintf(stderr," WARNING! This program can confuse your I2C bus, " "cause data loss and worse!\n"); - fprintf(stderr," I will probe file %s\n", filename); + fprintf(stderr," I will probe file %s%s\n", filename, + mode==MODE_QUICK?" using quick write commands": + mode==MODE_READ?" using read byte commands":""); fprintf(stderr," You have five seconds to reconsider and press CTRL-C!\n\n"); sleep(5); @@ -170,11 +201,30 @@ int main(int argc, char *argv[]) } else { fprintf(stderr,"Error: Could not set address to %02x: %s\n",i+j, strerror(errno)); + close(file); exit(1); } } - res = i2c_smbus_write_quick(file, I2C_SMBUS_WRITE); + switch(mode) { + case MODE_QUICK: + /* This is known to corrupt the Atmel AT24RF08 EEPROM */ + res = i2c_smbus_write_quick(file, I2C_SMBUS_WRITE); + break; + case MODE_READ: + /* This is known to lock SMBus on various write-only chips + (mainly clock chips) */ + res = i2c_smbus_read_byte(file); + break; + default: + if((i+j>=0x30 && i+j<=0x37) + || (i+j>=0x50 && i+j<=0x5F)) { + res = i2c_smbus_write_quick(file, I2C_SMBUS_WRITE); + } else { + res = i2c_smbus_read_byte(file); + } + } + if (res < 0) printf("XX "); else @@ -182,5 +232,6 @@ int main(int argc, char *argv[]) } printf("\n"); } + close(file); exit(0); }