i2cdump: code rework

Split i2cdump_main() into shorter functions. Simplify the code a bit.
Make block an array of ints so that we can store negative results of
read functions (fixes a bug found by Denys Vlasenko).

Signed-off-by: Bartosz Golaszewski <bartekgola@gmail.com>
Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
This commit is contained in:
Bartosz Golaszewski 2015-06-05 10:27:31 +02:00 committed by Denys Vlasenko
parent 2204472497
commit aeb11a9496

View File

@ -816,139 +816,44 @@ int i2cset_main(int argc, char **argv)
#endif /* ENABLE_I2CSET */
#if ENABLE_I2CDUMP
//usage:#define i2cdump_trivial_usage
//usage: "[-f] [-r FIRST-LAST] [-y] 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: "\nMODE is:"
//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 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"
int i2cdump_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE;
int i2cdump_main(int argc UNUSED_PARAM, char **argv)
static int read_block_data(int buf_fd, int mode, int *block)
{
const unsigned opt_f = (1 << 0), opt_y = (1 << 1),
opt_r = (1 << 2);
const char *const optstr = "fyr:";
uint8_t cblock[I2C_SMBUS_BLOCK_MAX + I2C_MAX_REGS];
int res, blen = 0, tmp, i;
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];
char *opt_r_str, *dash;
unsigned opts;
opt_complementary = "-2:?3"; /* from 2 to 3 args */
opts = getopt32(argv, optstr, &opt_r_str);
argv += optind;
bus_num = i2c_bus_lookup(argv[0]);
bus_addr = i2c_parse_bus_addr(argv[1]);
if (argv[2]) {
switch (argv[2][0]) {
case 'b': /* Already set */ break;
case 'c': mode = I2C_SMBUS_BYTE; break;
case 'w': mode = I2C_SMBUS_WORD_DATA; break;
case 'W':
mode = I2C_SMBUS_WORD_DATA;
even = 1;
break;
case 's': mode = I2C_SMBUS_BLOCK_DATA; break;
case 'i': mode = I2C_SMBUS_I2C_BLOCK_DATA; break;
default:
bb_error_msg_and_die("invalid mode");
}
if (argv[2][1] == 'p') {
if (argv[2][0] == 'W' || argv[2][0] == 'i') {
bb_error_msg_and_die(
"pec not supported for -W and -i");
} else {
pec = 1;
}
}
}
if (opts & opt_r) {
first = strtol(opt_r_str, &dash, 0);
if (dash == opt_r_str || *dash != '-' || first > 0xff)
bb_error_msg_and_die("invalid range");
last = xstrtou_range(++dash, 0, first, 0xff);
/* Range is not available for every mode */
switch (mode) {
case I2C_SMBUS_BYTE:
case I2C_SMBUS_BYTE_DATA:
break;
case I2C_SMBUS_WORD_DATA:
if (!even || (!(first % 2) && last % 2))
break;
/* Fall through */
default:
bb_error_msg_and_die(
"range not compatible with selected mode");
}
}
fd = i2c_dev_open(bus_num);
check_read_funcs(fd, mode, -1 /* data_addr */, pec);
i2c_set_slave_addr(fd, bus_addr, opts & opt_f);
if (pec)
i2c_set_pec(fd, 1);
if (!(opts & opt_y))
confirm_action(bus_addr, mode, -1 /* data_addr */, pec);
/* 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);
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(
fd, res, I2C_SMBUS_BLOCK_MAX,
buf_fd, res, I2C_SMBUS_BLOCK_MAX,
cblock + res);
if (tmp < 0) {
bb_error_msg_and_die(
"block read failed");
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;
}
if (mode == I2C_SMBUS_BYTE) {
res = i2c_smbus_write_byte(fd, first);
if (res < 0)
bb_perror_msg_and_die(
"write start address 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");
@ -975,11 +880,11 @@ int i2cdump_main(int argc UNUSED_PARAM, char **argv)
switch (mode) {
case I2C_SMBUS_BYTE_DATA:
res = i2c_smbus_read_byte_data(fd, i+j);
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(fd, i+j);
res = i2c_smbus_read_word_data(bus_fd, i+j);
if (res < 0) {
block[i+j] = res;
block[i+j+1] = res;
@ -989,7 +894,7 @@ int i2cdump_main(int argc UNUSED_PARAM, char **argv)
}
break;
case I2C_SMBUS_BYTE:
res = i2c_smbus_read_byte(fd);
res = i2c_smbus_read_byte(bus_fd);
block[i+j] = res;
break;
default:
@ -1025,7 +930,6 @@ int i2cdump_main(int argc UNUSED_PARAM, char **argv)
res = block[i+j];
if (res < 0) {
//FIXME: impossible, block[] is uchar[]
printf("X");
} else if (res == 0x00 || res == 0xff) {
printf(".");
@ -1037,7 +941,12 @@ int i2cdump_main(int argc UNUSED_PARAM, char **argv)
}
printf("\n");
}
} else {
}
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) {
@ -1054,16 +963,125 @@ int i2cdump_main(int argc UNUSED_PARAM, char **argv)
continue;
}
res = i2c_smbus_read_word_data(fd, i+j);
if (res < 0)
rv = i2c_smbus_read_word_data(bus_fd, i+j);
if (rv < 0)
printf("XXXX ");
else
printf("%04x ", res & 0xffff);
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"
//usage: "Examine I2C registers\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 i I2C block"
//usage: "\n s SMBus block"
//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"
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, opts;
int *block = (int *)bb_common_bufsiz1;
char *opt_r_str, *dash;
int fd, res, blen;
opt_complementary = "-2:?3"; /* from 2 to 3 args */
opts = getopt32(argv, optstr, &opt_r_str);
argv += optind;
bus_num = i2c_bus_lookup(argv[0]);
bus_addr = i2c_parse_bus_addr(argv[1]);
if (argv[2]) {
switch (argv[2][0]) {
case 'b': /* Already set. */ break;
case 'c': mode = I2C_SMBUS_BYTE; break;
case 'w': mode = I2C_SMBUS_WORD_DATA; break;
case 'W':
mode = I2C_SMBUS_WORD_DATA;
even = 1;
break;
case 's': mode = I2C_SMBUS_BLOCK_DATA; break;
case 'i': mode = I2C_SMBUS_I2C_BLOCK_DATA; break;
default:
bb_error_msg_and_die("invalid mode");
}
if (argv[2][1] == 'p') {
if (argv[2][0] == 'W' || argv[2][0] == 'i') {
bb_error_msg_and_die(
"pec not supported for -W and -i");
} else {
pec = 1;
}
}
}
if (opts & opt_r) {
first = strtol(opt_r_str, &dash, 0);
if (dash == opt_r_str || *dash != '-' || first > 0xff)
bb_error_msg_and_die("invalid range");
last = xstrtou_range(++dash, 0, first, 0xff);
/* Range is not available for every mode. */
switch (mode) {
case I2C_SMBUS_BYTE:
case I2C_SMBUS_BYTE_DATA:
break;
case I2C_SMBUS_WORD_DATA:
if (!even || (!(first % 2) && last % 2))
break;
/* Fall through */
default:
bb_error_msg_and_die(
"range not compatible with selected mode");
}
}
fd = i2c_dev_open(bus_num);
check_read_funcs(fd, mode, -1 /* data_addr */, pec);
i2c_set_slave_addr(fd, bus_addr, opts & opt_f);
if (pec)
i2c_set_pec(fd, 1);
if (!(opts & opt_y))
confirm_action(bus_addr, mode, -1 /* data_addr */, pec);
/* All but word data. */
if (mode != I2C_SMBUS_WORD_DATA || even) {
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");
}
dump_data(fd, mode, first, last, block, blen);
} else {
dump_word_data(fd, first, last);
}
return 0;
}
#endif /* ENABLE_I2CDUMP */