X-Git-Url: https://git.librecmc.org/?a=blobdiff_plain;f=miscutils%2Fi2c_tools.c;h=6a213406317ad5478b4b86049ae69f209203246b;hb=4c9455f967e21d30db0de2e13b6e1115ab8f36ce;hp=16784e948fc192ce355a4b54f74fe687a9f5eddc;hpb=2204472497285dd6fd7b686bb49732fda7394492;p=oweals%2Fbusybox.git diff --git a/miscutils/i2c_tools.c b/miscutils/i2c_tools.c index 16784e948..6a2134063 100644 --- a/miscutils/i2c_tools.c +++ b/miscutils/i2c_tools.c @@ -8,40 +8,40 @@ * * Licensed under GPLv2 or later, see file LICENSE in this source tree. */ - //config:config I2CGET -//config: bool "i2cget" +//config: bool "i2cget (5.6 kb)" //config: default y //config: select PLATFORM_LINUX //config: help -//config: Read from I2C/SMBus chip registers. +//config: Read from I2C/SMBus chip registers. //config: //config:config I2CSET -//config: bool "i2cset" +//config: bool "i2cset (6.9 kb)" //config: default y //config: select PLATFORM_LINUX //config: help -//config: Set I2C registers. +//config: Set I2C registers. //config: //config:config I2CDUMP -//config: bool "i2cdump" +//config: bool "i2cdump (7.2 kb)" //config: default y //config: select PLATFORM_LINUX //config: help -//config: Examine I2C registers. +//config: Examine I2C registers. //config: //config:config I2CDETECT -//config: bool "i2cdetect" +//config: bool "i2cdetect (7.2 kb)" //config: default y //config: select PLATFORM_LINUX //config: help -//config: Detect I2C chips. +//config: Detect I2C chips. //config: //applet:IF_I2CGET(APPLET(i2cget, BB_DIR_USR_SBIN, BB_SUID_DROP)) //applet:IF_I2CSET(APPLET(i2cset, BB_DIR_USR_SBIN, BB_SUID_DROP)) //applet:IF_I2CDUMP(APPLET(i2cdump, BB_DIR_USR_SBIN, BB_SUID_DROP)) //applet:IF_I2CDETECT(APPLET(i2cdetect, BB_DIR_USR_SBIN, BB_SUID_DROP)) +/* not NOEXEC: if hw operation stalls, use less memory in "hung" process */ //kbuild:lib-$(CONFIG_I2CGET) += i2c_tools.o //kbuild:lib-$(CONFIG_I2CSET) += i2c_tools.o @@ -61,112 +61,32 @@ #include "libbb.h" -/* - * /dev/i2c-X ioctl commands. The ioctl's parameter is always an unsigned long, - * except for: - * - I2C_FUNCS, takes pointer to an unsigned long - * - I2C_RDWR, takes pointer to struct i2c_rdwr_ioctl_data - * - I2C_SMBUS, takes pointer to struct i2c_smbus_ioctl_data - */ +#include -/* - * NOTE: Slave address is 7 or 10 bits, but 10-bit addresses - * are not supported due to code brokenness. - */ +#define I2CDUMP_NUM_REGS 256 -/* Use this slave address. */ -#define I2C_SLAVE 0x0703 -/* Use this slave address, even if it is already in use by a driver. */ -#define I2C_SLAVE_FORCE 0x0706 -/* 0 for 7 bit addrs, != 0 for 10 bit. */ -#define I2C_TENBIT 0x0704 -/* Get the adapter functionality mask. */ -#define I2C_FUNCS 0x0705 -/* Combined R/W transfer (one STOP only). */ -#define I2C_RDWR 0x0707 -/* != 0 to use PEC with SMBus. */ -#define I2C_PEC 0x0708 -/* SMBus transfer. */ -#define I2C_SMBUS 0x0720 - -/* Structure used in the I2C_SMBUS ioctl call. */ +#define I2CDETECT_MODE_AUTO 0 +#define I2CDETECT_MODE_QUICK 1 +#define I2CDETECT_MODE_READ 2 + +/* linux/i2c-dev.h from i2c-tools overwrites the one from linux uapi + * and defines symbols already defined by linux/i2c.h. + * Also, it defines a bunch of static inlines which we would rather NOT + * inline. What a mess. + * We need only these definitions from linux/i2c-dev.h: + */ +#define I2C_SLAVE 0x0703 +#define I2C_SLAVE_FORCE 0x0706 +#define I2C_FUNCS 0x0705 +#define I2C_PEC 0x0708 +#define I2C_SMBUS 0x0720 struct i2c_smbus_ioctl_data { - uint8_t read_write; - uint8_t command; - uint32_t size; + __u8 read_write; + __u8 command; + __u32 size; union i2c_smbus_data *data; }; - -/* Structure used in the I2C_RDWR ioctl call. */ -struct i2c_rdwr_ioctl_data { - struct i2c_msg *msgs; /* Pointers to i2c_msgs. */ - uint32_t nmsgs; /* Number of i2c_msgs. */ -}; - -/* As specified in SMBus standard. */ -#define I2C_SMBUS_BLOCK_MAX 32 -/* Not specified but we use same structure. */ -#define I2C_SMBUS_I2C_BLOCK_MAX 32 - -/* Data for SMBus Messages. */ -union i2c_smbus_data { - uint8_t byte; - uint16_t word; - /* block[0] is used for length and one more for PEC */ - uint8_t block[I2C_SMBUS_BLOCK_MAX + 2]; -}; - -#define I2C_RDRW_IOCTL_MAX_MSGS 42 -#define I2C_MAX_REGS 256 - -/* Smbus_access read or write markers. */ -#define I2C_SMBUS_READ 1 -#define I2C_SMBUS_WRITE 0 - -/* SMBus transaction types (size parameter in the below functions). */ -#define I2C_SMBUS_QUICK 0 -#define I2C_SMBUS_BYTE 1 -#define I2C_SMBUS_BYTE_DATA 2 -#define I2C_SMBUS_WORD_DATA 3 -#define I2C_SMBUS_PROC_CALL 4 -#define I2C_SMBUS_BLOCK_DATA 5 -#define I2C_SMBUS_I2C_BLOCK_BROKEN 6 -#define I2C_SMBUS_BLOCK_PROC_CALL 7 -#define I2C_SMBUS_I2C_BLOCK_DATA 8 - -#define DETECT_MODE_AUTO 0 -#define DETECT_MODE_QUICK 1 -#define DETECT_MODE_READ 2 - -/* Defines to determine what functionality is present. */ -#define I2C_FUNC_I2C 0x00000001 -#define I2C_FUNC_10BIT_ADDR 0x00000002 -#define I2C_FUNC_PROTOCOL_MANGLING 0x00000004 -#define I2C_FUNC_SMBUS_PEC 0x00000008 -#define I2C_FUNC_SMBUS_BLOCK_PROC_CALL 0x00008000 -#define I2C_FUNC_SMBUS_QUICK 0x00010000 -#define I2C_FUNC_SMBUS_READ_BYTE 0x00020000 -#define I2C_FUNC_SMBUS_WRITE_BYTE 0x00040000 -#define I2C_FUNC_SMBUS_READ_BYTE_DATA 0x00080000 -#define I2C_FUNC_SMBUS_WRITE_BYTE_DATA 0x00100000 -#define I2C_FUNC_SMBUS_READ_WORD_DATA 0x00200000 -#define I2C_FUNC_SMBUS_WRITE_WORD_DATA 0x00400000 -#define I2C_FUNC_SMBUS_PROC_CALL 0x00800000 -#define I2C_FUNC_SMBUS_READ_BLOCK_DATA 0x01000000 -#define I2C_FUNC_SMBUS_WRITE_BLOCK_DATA 0x02000000 -#define I2C_FUNC_SMBUS_READ_I2C_BLOCK 0x04000000 -#define I2C_FUNC_SMBUS_WRITE_I2C_BLOCK 0x08000000 - -#define I2C_FUNC_SMBUS_BYTE (I2C_FUNC_SMBUS_READ_BYTE | \ - I2C_FUNC_SMBUS_WRITE_BYTE) -#define I2C_FUNC_SMBUS_BYTE_DATA (I2C_FUNC_SMBUS_READ_BYTE_DATA | \ - I2C_FUNC_SMBUS_WRITE_BYTE_DATA) -#define I2C_FUNC_SMBUS_WORD_DATA (I2C_FUNC_SMBUS_READ_WORD_DATA | \ - I2C_FUNC_SMBUS_WRITE_WORD_DATA) -#define I2C_FUNC_SMBUS_BLOCK_DATA (I2C_FUNC_SMBUS_READ_BLOCK_DATA | \ - I2C_FUNC_SMBUS_WRITE_BLOCK_DATA) -#define I2C_FUNC_SMBUS_I2C_BLOCK (I2C_FUNC_SMBUS_READ_I2C_BLOCK | \ - I2C_FUNC_SMBUS_WRITE_I2C_BLOCK) +/* end linux/i2c-dev.h */ /* * This is needed for ioctl_or_perror_and_die() since it only accepts pointers. @@ -456,7 +376,7 @@ static void check_read_funcs(int fd, int mode, int data_addr, int pec) break; #endif /* ENABLE_I2CDUMP */ default: - bb_error_msg_and_die("Programmer goofed!"); + bb_error_msg_and_die("internal error"); } check_funcs_test_end(funcs, pec, err); } @@ -501,8 +421,7 @@ static void check_write_funcs(int fd, int mode, int pec) static void confirm_or_abort(void) { fprintf(stderr, "Continue? [y/N] "); - fflush_all(); - if (!bb_ask_confirmation()) + if (!bb_ask_y_confirmation()) bb_error_msg_and_die("aborting"); } @@ -534,31 +453,30 @@ static void confirm_action(int bus_addr, int mode, int data_addr, int pec) #if ENABLE_I2CGET //usage:#define i2cget_trivial_usage -//usage: "[-f] [-y] BUS CHIP-ADDRESS [DATA-ADDRESS [MODE]]" +//usage: "[-fy] BUS CHIP-ADDRESS [DATA-ADDRESS [MODE]]" //usage:#define i2cget_full_usage "\n\n" -//usage: "Read from I2C/SMBus chip registers\n" -//usage: "\n I2CBUS i2c bus number" -//usage: "\n ADDRESS 0x03 - 0x77" +//usage: "Read from I2C/SMBus chip registers" +//usage: "\n" +//usage: "\n I2CBUS I2C bus number" +//usage: "\n ADDRESS 0x03-0x77" //usage: "\nMODE is:" -//usage: "\n b read byte data (default)" -//usage: "\n w read word data" -//usage: "\n c write byte/read byte" +//usage: "\n b Read byte data (default)" +//usage: "\n w Read word data" +//usage: "\n c Write byte/read byte" //usage: "\n Append p for SMBus PEC" //usage: "\n" -//usage: "\n -f force access" -//usage: "\n -y disable interactive mode" +//usage: "\n -f Force access" +//usage: "\n -y Disable interactive mode" int i2cget_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; int i2cget_main(int argc UNUSED_PARAM, char **argv) { const unsigned opt_f = (1 << 0), opt_y = (1 << 1); - const char *const optstr = "fy"; int bus_num, bus_addr, data_addr = -1, status; int mode = I2C_SMBUS_BYTE, pec = 0, fd; unsigned opts; - opt_complementary = "-2:?4"; /* from 2 to 4 args */ - opts = getopt32(argv, optstr); + opts = getopt32(argv, "^" "fy" "\0" "-2:?4"/*from 2 to 4 args*/); argv += optind; bus_num = i2c_bus_lookup(argv[0]); @@ -618,40 +536,44 @@ int i2cget_main(int argc UNUSED_PARAM, char **argv) #if ENABLE_I2CSET //usage:#define i2cset_trivial_usage -//usage: "[-f] [-y] [-m MASK] BUS CHIP-ADDR DATA-ADDR [VALUE] ... [MODE]" +//usage: "[-fy] [-m MASK] BUS CHIP-ADDRESS DATA-ADDRESS [VALUE] ... [MODE]" //usage:#define i2cset_full_usage "\n\n" -//usage: "Set I2C registers\n" -//usage: "\n I2CBUS i2c bus number" -//usage: "\n ADDRESS 0x03 - 0x77" +//usage: "Set I2C registers" +//usage: "\n" +//usage: "\n I2CBUS I2C bus number" +//usage: "\n ADDRESS 0x03-0x77" //usage: "\nMODE is:" -//usage: "\n c byte, no value" -//usage: "\n b byte data (default)" -//usage: "\n w word data" +//usage: "\n c Byte, no value" +//usage: "\n b Byte data (default)" +//usage: "\n w Word data" //usage: "\n i I2C block data" //usage: "\n s SMBus block data" //usage: "\n Append p for SMBus PEC" //usage: "\n" -//usage: "\n -f force access" -//usage: "\n -y disable interactive mode" -//usage: "\n -r read back and compare the result" -//usage: "\n -m MASK mask specifying which bits to write" +//usage: "\n -f Force access" +//usage: "\n -y Disable interactive mode" +//usage: "\n -r Read back and compare the result" +//usage: "\n -m MASK Mask specifying which bits to write" int i2cset_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; int i2cset_main(int argc, char **argv) { const unsigned opt_f = (1 << 0), opt_y = (1 << 1), opt_m = (1 << 2), opt_r = (1 << 3); - const char *const optstr = "fym:r"; int bus_num, bus_addr, data_addr, mode = I2C_SMBUS_BYTE, pec = 0; - int val, blen = 0, mask = 0, fd, status; + int val, blen, mask, fd, status; unsigned char block[I2C_SMBUS_BLOCK_MAX]; char *opt_m_arg = NULL; unsigned opts; - opt_complementary = "-3"; /* from 3 to ? args */ - opts = getopt32(argv, optstr, &opt_m_arg); + opts = getopt32(argv, "^" + "fym:r" + "\0" "-3", /* minimum 3 args */ + &opt_m_arg + ); argv += optind; argc -= optind; + argc--; /* now argv[argc] is last arg */ bus_num = i2c_bus_lookup(argv[0]); bus_addr = i2c_parse_bus_addr(argv[1]); @@ -661,20 +583,26 @@ int i2cset_main(int argc, char **argv) if (!argv[4] && argv[3][0] != 'c') { mode = I2C_SMBUS_BYTE_DATA; /* Implicit b */ } else { - switch (argv[argc-1][0]) { - case 'c': /* Already set */ break; - case 'b': mode = I2C_SMBUS_BYTE_DATA; break; - case 'w': mode = I2C_SMBUS_WORD_DATA; break; - case 's': mode = I2C_SMBUS_BLOCK_DATA; break; - case 'i': mode = I2C_SMBUS_I2C_BLOCK_DATA; break; + switch (argv[argc][0]) { + case 'c': /* Already set */ + break; + case 'b': mode = I2C_SMBUS_BYTE_DATA; + break; + case 'w': mode = I2C_SMBUS_WORD_DATA; + break; + case 's': mode = I2C_SMBUS_BLOCK_DATA; + break; + case 'i': mode = I2C_SMBUS_I2C_BLOCK_DATA; + break; default: bb_error_msg("invalid mode"); bb_show_usage(); } - pec = argv[argc-1][1] == 'p'; - if (mode == I2C_SMBUS_BLOCK_DATA || - mode == I2C_SMBUS_I2C_BLOCK_DATA) { + pec = (argv[argc][1] == 'p'); + if (mode == I2C_SMBUS_BLOCK_DATA + || mode == I2C_SMBUS_I2C_BLOCK_DATA + ) { if (pec && mode == I2C_SMBUS_I2C_BLOCK_DATA) bb_error_msg_and_die( "PEC not supported for I2C " @@ -688,6 +616,8 @@ int i2cset_main(int argc, char **argv) } /* Prepare the value(s) to be written according to current mode. */ + mask = 0; + blen = 0; switch (mode) { case I2C_SMBUS_BYTE_DATA: val = xstrtou_range(argv[3], 0, 0, 0xff); @@ -697,8 +627,9 @@ int i2cset_main(int argc, char **argv) break; case I2C_SMBUS_BLOCK_DATA: case I2C_SMBUS_I2C_BLOCK_DATA: - for (blen = 3; blen < (argc - 1); blen++) - block[blen] = xstrtou_range(argv[blen], 0, 0, 0xff); + for (blen = 3; blen < argc; blen++) + block[blen - 3] = xstrtou_range(argv[blen], 0, 0, 0xff); + blen -= 3; val = -1; break; default: @@ -799,7 +730,7 @@ int i2cset_main(int argc, char **argv) } if (status < 0) { - printf("Warning - readback failed\n"); + puts("Warning - readback failed"); } else if (status != val) { printf("Warning - data mismatch - wrote " @@ -816,41 +747,204 @@ int i2cset_main(int argc, char **argv) #endif /* ENABLE_I2CSET */ #if ENABLE_I2CDUMP +static int read_block_data(int buf_fd, int mode, int *block) +{ + uint8_t cblock[I2C_SMBUS_BLOCK_MAX + I2CDUMP_NUM_REGS]; + int res, blen = 0, tmp, i; + + if (mode == I2C_SMBUS_BLOCK_DATA) { + blen = i2c_smbus_read_block_data(buf_fd, 0, cblock); + if (blen <= 0) + goto fail; + } else { + for (res = 0; res < I2CDUMP_NUM_REGS; res += tmp) { + tmp = i2c_smbus_read_i2c_block_data( + buf_fd, res, I2C_SMBUS_BLOCK_MAX, + cblock + res); + if (tmp <= 0) { + blen = tmp; + goto fail; + } + } + + if (res >= I2CDUMP_NUM_REGS) + res = I2CDUMP_NUM_REGS; + + for (i = 0; i < res; i++) + block[i] = cblock[i]; + + if (mode != I2C_SMBUS_BLOCK_DATA) + for (i = res; i < I2CDUMP_NUM_REGS; i++) + block[i] = -1; + } + + return blen; + + fail: + bb_error_msg_and_die("block read failed: %d", blen); +} + +/* Dump all but word data. */ +static void dump_data(int bus_fd, int mode, unsigned first, + unsigned last, int *block, int blen) +{ + int i, j, res; + + puts(" 0 1 2 3 4 5 6 7 8 9 a b c d e f" + " 0123456789abcdef"); + + for (i = 0; i < I2CDUMP_NUM_REGS; i += 0x10) { + if (mode == I2C_SMBUS_BLOCK_DATA && i >= blen) + break; + if (i/16 < first/16) + continue; + if (i/16 > last/16) + break; + + printf("%02x: ", i); + for (j = 0; j < 16; j++) { + fflush_all(); + /* Skip unwanted registers */ + if (i+j < first || i+j > last) { + printf(" "); + if (mode == I2C_SMBUS_WORD_DATA) { + printf(" "); + j++; + } + continue; + } + + switch (mode) { + case I2C_SMBUS_BYTE_DATA: + res = i2c_smbus_read_byte_data(bus_fd, i+j); + block[i+j] = res; + break; + case I2C_SMBUS_WORD_DATA: + res = i2c_smbus_read_word_data(bus_fd, i+j); + if (res < 0) { + block[i+j] = res; + block[i+j+1] = res; + } else { + block[i+j] = res & 0xff; + block[i+j+1] = res >> 8; + } + break; + case I2C_SMBUS_BYTE: + res = i2c_smbus_read_byte(bus_fd); + block[i+j] = res; + break; + default: + res = block[i+j]; + } + + if (mode == I2C_SMBUS_BLOCK_DATA && + i+j >= blen) { + printf(" "); + } else if (res < 0) { + printf("XX "); + if (mode == I2C_SMBUS_WORD_DATA) + printf("XX "); + } else { + printf("%02x ", block[i+j]); + if (mode == I2C_SMBUS_WORD_DATA) + printf("%02x ", block[i+j+1]); + } + + if (mode == I2C_SMBUS_WORD_DATA) + j++; + } + printf(" "); + + for (j = 0; j < 16; j++) { + if (mode == I2C_SMBUS_BLOCK_DATA && i+j >= blen) + break; + /* Skip unwanted registers */ + if (i+j < first || i+j > last) { + bb_putchar(' '); + continue; + } + + res = block[i+j]; + if (res < 0) { + bb_putchar('X'); + } else if (res == 0x00 || res == 0xff) { + bb_putchar('.'); + } else if (res < 32 || res >= 127) { + bb_putchar('?'); + } else { + bb_putchar(res); + } + } + bb_putchar('\n'); + } +} + +static void dump_word_data(int bus_fd, unsigned first, unsigned last) +{ + int i, j, rv; + + /* Word data. */ + puts(" 0,8 1,9 2,a 3,b 4,c 5,d 6,e 7,f"); + for (i = 0; i < 256; i += 8) { + if (i/8 < first/8) + continue; + if (i/8 > last/8) + break; + + printf("%02x: ", i); + for (j = 0; j < 8; j++) { + /* Skip unwanted registers. */ + if (i+j < first || i+j > last) { + printf(" "); + continue; + } + + rv = i2c_smbus_read_word_data(bus_fd, i+j); + if (rv < 0) + printf("XXXX "); + else + printf("%04x ", rv & 0xffff); + } + bb_putchar('\n'); + } +} + //usage:#define i2cdump_trivial_usage -//usage: "[-f] [-r FIRST-LAST] [-y] BUS ADDR [MODE]" +//usage: "[-fy] [-r FIRST-LAST] BUS ADDR [MODE]" //usage:#define i2cdump_full_usage "\n\n" -//usage: "Examine I2C registers\n" -//usage: "\n I2CBUS i2c bus number" -//usage: "\n ADDRESS 0x03 - 0x77" +//usage: "Examine I2C registers" +//usage: "\n" +//usage: "\n I2CBUS I2C bus number" +//usage: "\n ADDRESS 0x03-0x77" //usage: "\nMODE is:" -//usage: "\n b byte (default)" -//usage: "\n w word" -//usage: "\n W word on even register addresses" +//usage: "\n b Byte (default)" +//usage: "\n w Word" +//usage: "\n W Word on even register addresses" //usage: "\n i I2C block" //usage: "\n s SMBus block" -//usage: "\n c consecutive byte" +//usage: "\n c Consecutive byte" //usage: "\n Append p for SMBus PEC" //usage: "\n" -//usage: "\n -f force access" -//usage: "\n -y disable interactive mode" -//usage: "\n -r limit the number of registers being accessed" +//usage: "\n -f Force access" +//usage: "\n -y Disable interactive mode" +//usage: "\n -r Limit the number of registers being accessed" int i2cdump_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; int i2cdump_main(int argc UNUSED_PARAM, char **argv) { const unsigned opt_f = (1 << 0), opt_y = (1 << 1), opt_r = (1 << 2); - const char *const optstr = "fyr:"; int bus_num, bus_addr, mode = I2C_SMBUS_BYTE_DATA, even = 0, pec = 0; - unsigned first = 0x00, last = 0xff; - int fd, i, j, res, blen = 0, tmp; - unsigned char cblock[I2C_SMBUS_BLOCK_MAX + I2C_MAX_REGS]; - unsigned char block[I2C_SMBUS_BLOCK_MAX]; + unsigned first = 0x00, last = 0xff, opts; + int block[I2CDUMP_NUM_REGS]; char *opt_r_str, *dash; - unsigned opts; + int fd, res; - opt_complementary = "-2:?3"; /* from 2 to 3 args */ - opts = getopt32(argv, optstr, &opt_r_str); + opts = getopt32(argv, "^" + "fyr:" + "\0" "-2:?3" /* from 2 to 3 args */, + &opt_r_str + ); argv += optind; bus_num = i2c_bus_lookup(argv[0]); @@ -858,7 +952,7 @@ int i2cdump_main(int argc UNUSED_PARAM, char **argv) if (argv[2]) { switch (argv[2][0]) { - case 'b': /* Already set */ break; + case 'b': /* Already set. */ break; case 'c': mode = I2C_SMBUS_BYTE; break; case 'w': mode = I2C_SMBUS_WORD_DATA; break; case 'W': @@ -887,7 +981,7 @@ int i2cdump_main(int argc UNUSED_PARAM, char **argv) bb_error_msg_and_die("invalid range"); last = xstrtou_range(++dash, 0, first, 0xff); - /* Range is not available for every mode */ + /* Range is not available for every mode. */ switch (mode) { case I2C_SMBUS_BYTE: case I2C_SMBUS_BYTE_DATA: @@ -912,156 +1006,22 @@ int i2cdump_main(int argc UNUSED_PARAM, char **argv) if (!(opts & opt_y)) confirm_action(bus_addr, mode, -1 /* data_addr */, pec); - /* All but word data */ + /* All but word data. */ if (mode != I2C_SMBUS_WORD_DATA || even) { - /* - * FIXME This section has been ported from upstream i2cdump. - * It has been reworked a bit but is still pretty spaghetti - * and needs splitting into several functions. - */ - if (mode == I2C_SMBUS_BLOCK_DATA || - mode == I2C_SMBUS_I2C_BLOCK_DATA) { - res = i2c_smbus_read_block_data(fd, 0, cblock); - blen = res; - } else { - for (res = 0; res < I2C_MAX_REGS; res += tmp) { - tmp = i2c_smbus_read_i2c_block_data( - fd, res, I2C_SMBUS_BLOCK_MAX, - cblock + res); - if (tmp < 0) { - bb_error_msg_and_die( - "block read failed"); - } - } - if (res >= I2C_MAX_REGS) - res = I2C_MAX_REGS; - for (i = 0; i < res; i++) - block[i] = cblock[i]; - if (mode != I2C_SMBUS_BLOCK_DATA) - for (i = res; i < I2C_MAX_REGS; i++) - cblock[i] = -1; - } + int blen = 0; + + if (mode == I2C_SMBUS_BLOCK_DATA || mode == I2C_SMBUS_I2C_BLOCK_DATA) + blen = read_block_data(fd, mode, block); if (mode == I2C_SMBUS_BYTE) { res = i2c_smbus_write_byte(fd, first); if (res < 0) - bb_perror_msg_and_die( - "write start address failed"); + bb_perror_msg_and_die("write start address"); } - printf(" 0 1 2 3 4 5 6 7 8 9 a b c d e f" - " 0123456789abcdef\n"); - - for (i = 0; i < I2C_MAX_REGS; i += 0x10) { - if (mode == I2C_SMBUS_BLOCK_DATA && i >= blen) - break; - if (i/16 < first/16) - continue; - if (i/16 > last/16) - break; - - printf("%02x: ", i); - for (j = 0; j < 16; j++) { - fflush_all(); - /* Skip unwanted registers */ - if (i+j < first || i+j > last) { - printf(" "); - if (mode == I2C_SMBUS_WORD_DATA) { - printf(" "); - j++; - } - continue; - } - - switch (mode) { - case I2C_SMBUS_BYTE_DATA: - res = i2c_smbus_read_byte_data(fd, i+j); - block[i+j] = res; - break; - case I2C_SMBUS_WORD_DATA: - res = i2c_smbus_read_word_data(fd, i+j); - if (res < 0) { - block[i+j] = res; - block[i+j+1] = res; - } else { - block[i+j] = res & 0xff; - block[i+j+1] = res >> 8; - } - break; - case I2C_SMBUS_BYTE: - res = i2c_smbus_read_byte(fd); - block[i+j] = res; - break; - default: - res = block[i+j]; - } - - if (mode == I2C_SMBUS_BLOCK_DATA && - i+j >= blen) { - printf(" "); - } else if (res < 0) { - printf("XX "); - if (mode == I2C_SMBUS_WORD_DATA) - printf("XX "); - } else { - printf("%02x ", block[i+j]); - if (mode == I2C_SMBUS_WORD_DATA) - printf("%02x ", block[i+j+1]); - } - - if (mode == I2C_SMBUS_WORD_DATA) - j++; - } - printf(" "); - - for (j = 0; j < 16; j++) { - if (mode == I2C_SMBUS_BLOCK_DATA && i+j >= blen) - break; - /* Skip unwanted registers */ - if (i+j < first || i+j > last) { - printf(" "); - continue; - } - - res = block[i+j]; - if (res < 0) { -//FIXME: impossible, block[] is uchar[] - printf("X"); - } else if (res == 0x00 || res == 0xff) { - printf("."); - } else if (res < 32 || res >= 127) { - printf("?"); - } else { - printf("%c", res); - } - } - printf("\n"); - } + dump_data(fd, mode, first, last, block, blen); } else { - /* Word data. */ - printf(" 0,8 1,9 2,a 3,b 4,c 5,d 6,e 7,f\n"); - for (i = 0; i < 256; i += 8) { - if (i/8 < first/8) - continue; - if (i/8 > last/8) - break; - - printf("%02x: ", i); - for (j = 0; j < 8; j++) { - /* Skip unwanted registers. */ - if (i+j < first || i+j > last) { - printf(" "); - continue; - } - - res = i2c_smbus_read_word_data(fd, i+j); - if (res < 0) - printf("XXXX "); - else - printf("%04x ", res & 0xffff); - } - printf("\n"); - } + dump_word_data(fd, first, last); } return 0; @@ -1102,33 +1062,33 @@ static const struct i2c_func i2c_funcs_tab[] = { { .value = I2C_FUNC_I2C, .name = "I2C" }, { .value = I2C_FUNC_SMBUS_QUICK, - .name = "SMBus Quick Command" }, + .name = "SMBus quick command" }, { .value = I2C_FUNC_SMBUS_WRITE_BYTE, - .name = "SMBus Send Byte" }, + .name = "SMBus send byte" }, { .value = I2C_FUNC_SMBUS_READ_BYTE, - .name = "SMBus Receive Byte" }, + .name = "SMBus receive byte" }, { .value = I2C_FUNC_SMBUS_WRITE_BYTE_DATA, - .name = "SMBus Write Byte" }, + .name = "SMBus write byte" }, { .value = I2C_FUNC_SMBUS_READ_BYTE_DATA, - .name = "SMBus Read Byte" }, + .name = "SMBus read byte" }, { .value = I2C_FUNC_SMBUS_WRITE_WORD_DATA, - .name = "SMBus Write Word" }, + .name = "SMBus write word" }, { .value = I2C_FUNC_SMBUS_READ_WORD_DATA, - .name = "SMBus Read Word" }, + .name = "SMBus read word" }, { .value = I2C_FUNC_SMBUS_PROC_CALL, - .name = "SMBus Process Call" }, + .name = "SMBus process call" }, { .value = I2C_FUNC_SMBUS_WRITE_BLOCK_DATA, - .name = "SMBus Block Write" }, + .name = "SMBus block write" }, { .value = I2C_FUNC_SMBUS_READ_BLOCK_DATA, - .name = "SMBus Block Read" }, + .name = "SMBus block read" }, { .value = I2C_FUNC_SMBUS_BLOCK_PROC_CALL, - .name = "SMBus Block Process Call" }, + .name = "SMBus block process call" }, { .value = I2C_FUNC_SMBUS_PEC, .name = "SMBus PEC" }, { .value = I2C_FUNC_SMBUS_WRITE_I2C_BLOCK, - .name = "I2C Block Write" }, + .name = "I2C block write" }, { .value = I2C_FUNC_SMBUS_READ_I2C_BLOCK, - .name = "I2C Block Read" }, + .name = "I2C block read" }, { .value = 0, .name = NULL } }; @@ -1208,12 +1168,11 @@ static void NORETURN list_i2c_busses_and_exit(void) i2cdev_path, de->d_name, subde->d_name); fp = fopen(path, "r"); - goto found; + break; } } } -found: if (fp != NULL) { /* * Get the rest of the info and display a line @@ -1261,33 +1220,34 @@ static void will_skip(const char *cmd) } //usage:#define i2cdetect_trivial_usage -//usage: "[-F I2CBUS] [-l] [-y] [-a] [-q|-r] I2CBUS [FIRST LAST]" +//usage: "-l | -F I2CBUS | [-ya] [-q|-r] I2CBUS [FIRST LAST]" //usage:#define i2cdetect_full_usage "\n\n" -//usage: "Detect I2C chips.\n" -//usage: "\n I2CBUS i2c bus number" -//usage: "\n FIRST and LAST limit the probing range" +//usage: "Detect I2C chips" //usage: "\n" -//usage: "\n -l output list of installed busses" -//usage: "\n -y disable interactive mode" -//usage: "\n -a force scanning of non-regular addresses" -//usage: "\n -q use smbus quick write commands for probing (default)" -//usage: "\n -r use smbus read byte commands for probing" -//usage: "\n -F display list of functionalities" +//usage: "\n -l List installed buses" +//usage: "\n -F BUS# List functionalities on this bus" +//usage: "\n -y Disable interactive mode" +//usage: "\n -a Force scanning of non-regular addresses" +//usage: "\n -q Use smbus quick write commands for probing (default)" +//usage: "\n -r Use smbus read byte commands for probing" +//usage: "\n FIRST and LAST limit probing range" int i2cdetect_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; int i2cdetect_main(int argc UNUSED_PARAM, char **argv) { const unsigned opt_y = (1 << 0), opt_a = (1 << 1), opt_q = (1 << 2), opt_r = (1 << 3), opt_F = (1 << 4), opt_l = (1 << 5); - const char *const optstr = "yaqrFl"; - int fd, bus_num, i, j, mode = DETECT_MODE_AUTO, status; + int fd, bus_num, i, j, mode = I2CDETECT_MODE_AUTO, status, cmd; unsigned first = 0x03, last = 0x77, opts; unsigned long funcs; - opt_complementary = "q--r:r--q:" /* mutually exclusive */ - "?3"; /* up to 3 args */ - opts = getopt32(argv, optstr); + opts = getopt32(argv, "^" + "yaqrFl" + "\0" + "q--r:r--q:"/*mutually exclusive*/ + "?3"/*up to 3 args*/ + ); argv += optind; if (opts & opt_l) @@ -1312,9 +1272,9 @@ int i2cdetect_main(int argc UNUSED_PARAM, char **argv) } if (opts & opt_r) - mode = DETECT_MODE_READ; + mode = I2CDETECT_MODE_READ; else if (opts & opt_q) - mode = DETECT_MODE_QUICK; + mode = I2CDETECT_MODE_QUICK; if (opts & opt_a) { first = 0x00; @@ -1331,42 +1291,43 @@ int i2cdetect_main(int argc UNUSED_PARAM, char **argv) if (!(funcs & (I2C_FUNC_SMBUS_QUICK | I2C_FUNC_SMBUS_READ_BYTE))) { no_support("detection commands"); } else - if (mode == DETECT_MODE_QUICK && !(funcs & I2C_FUNC_SMBUS_QUICK)) { - no_support("SMBus Quick Write command"); + if (mode == I2CDETECT_MODE_QUICK && !(funcs & I2C_FUNC_SMBUS_QUICK)) { + no_support("SMBus quick write"); } else - if (mode == DETECT_MODE_READ && !(funcs & I2C_FUNC_SMBUS_READ_BYTE)) { - no_support("SMBus Receive Byte command"); + if (mode == I2CDETECT_MODE_READ && !(funcs & I2C_FUNC_SMBUS_READ_BYTE)) { + no_support("SMBus receive byte"); } - if (mode == DETECT_MODE_AUTO) { + if (mode == I2CDETECT_MODE_AUTO) { if (!(funcs & I2C_FUNC_SMBUS_QUICK)) - will_skip("SMBus Quick Write"); + will_skip("SMBus quick write"); if (!(funcs & I2C_FUNC_SMBUS_READ_BYTE)) - will_skip("SMBus Receive Byte"); + will_skip("SMBus receive byte"); } if (!(opts & opt_y)) confirm_action(-1, -1, -1, 0); - printf(" 0 1 2 3 4 5 6 7 8 9 a b c d e f\n"); + puts(" 0 1 2 3 4 5 6 7 8 9 a b c d e f"); for (i = 0; i < 128; i += 16) { printf("%02x: ", i); - for(j = 0; j < 16; j++) { + for (j = 0; j < 16; j++) { fflush_all(); - if (mode == DETECT_MODE_AUTO) { + cmd = mode; + if (mode == I2CDETECT_MODE_AUTO) { if ((i+j >= 0x30 && i+j <= 0x37) || (i+j >= 0x50 && i+j <= 0x5F)) - mode = DETECT_MODE_READ; + cmd = I2CDETECT_MODE_READ; else - mode = DETECT_MODE_QUICK; + cmd = I2CDETECT_MODE_QUICK; } /* Skip unwanted addresses. */ if (i+j < first || i+j > last - || (mode == DETECT_MODE_READ && !(funcs & I2C_FUNC_SMBUS_READ_BYTE)) - || (mode == DETECT_MODE_QUICK && !(funcs & I2C_FUNC_SMBUS_QUICK))) + || (cmd == I2CDETECT_MODE_READ && !(funcs & I2C_FUNC_SMBUS_READ_BYTE)) + || (cmd == I2CDETECT_MODE_QUICK && !(funcs & I2C_FUNC_SMBUS_QUICK))) { printf(" "); continue; @@ -1383,15 +1344,15 @@ int i2cdetect_main(int argc UNUSED_PARAM, char **argv) "can't set address to 0x%02x", i + j); } - switch (mode) { - case DETECT_MODE_READ: + switch (cmd) { + case I2CDETECT_MODE_READ: /* * This is known to lock SMBus on various * write-only chips (mainly clock chips). */ status = i2c_smbus_read_byte(fd); break; - default: /* DETECT_MODE_QUICK: */ + default: /* I2CDETECT_MODE_QUICK: */ /* * This is known to corrupt the Atmel * AT24RF08 EEPROM. @@ -1406,7 +1367,7 @@ int i2cdetect_main(int argc UNUSED_PARAM, char **argv) else printf("%02x ", i+j); } - printf("\n"); + bb_putchar('\n'); } return 0;