diff --git a/miscutils/i2c_tools.c b/miscutils/i2c_tools.c index 16784e948..2f501cd9c 100644 --- a/miscutils/i2c_tools.c +++ b/miscutils/i2c_tools.c @@ -816,6 +816,163 @@ 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 + I2C_MAX_REGS]; + int res, blen = 0, tmp, i; + + if (mode == I2C_SMBUS_BLOCK_DATA || mode == I2C_SMBUS_I2C_BLOCK_DATA) { + res = i2c_smbus_read_block_data(buf_fd, 0, cblock); + blen = res; + } else { + for (res = 0; res < I2C_MAX_REGS; res += tmp) { + tmp = i2c_smbus_read_i2c_block_data( + buf_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++) + block[i] = -1; + } + + return 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; + + 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(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) { + printf(" "); + continue; + } + + res = block[i+j]; + if (res < 0) { + printf("X"); + } else if (res == 0x00 || res == 0xff) { + printf("."); + } else if (res < 32 || res >= 127) { + printf("?"); + } else { + printf("%c", res); + } + } + printf("\n"); + } +} + +static void dump_word_data(int bus_fd, unsigned first, unsigned last) +{ + int i, j, rv; + + /* 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; + } + + rv = i2c_smbus_read_word_data(bus_fd, i+j); + if (rv < 0) + printf("XXXX "); + else + printf("%04x ", rv & 0xffff); + } + printf("\n"); + } +} + //usage:#define i2cdump_trivial_usage //usage: "[-f] [-r FIRST-LAST] [-y] BUS ADDR [MODE]" //usage:#define i2cdump_full_usage "\n\n" @@ -842,12 +999,10 @@ int i2cdump_main(int argc UNUSED_PARAM, char **argv) 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 = (int *)bb_common_bufsiz1; char *opt_r_str, *dash; - unsigned opts; + int fd, res, blen; opt_complementary = "-2:?3"; /* from 2 to 3 args */ opts = getopt32(argv, optstr, &opt_r_str); @@ -858,7 +1013,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 +1042,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 +1067,19 @@ 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; - } + 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;