Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 0 additions & 2 deletions linux-i2c-dev.h
Original file line number Diff line number Diff line change
Expand Up @@ -47,8 +47,6 @@ struct i2c_msg {
#define I2C_M_NO_RD_ACK 0x0800
short len; /* msg length */
char *buf; /* pointer to msg data */
int err;
short done;
};

/* To determine what functionality is present */
Expand Down
79 changes: 78 additions & 1 deletion smbus_rw.c
Original file line number Diff line number Diff line change
Expand Up @@ -44,6 +44,7 @@ enum SMBUS_SIZE
SMBUS_QUICK,
SMBUS_PROC_CALL,
SMBUS_BLOCK_PROC_CALL,
SMBUS_WRITE_READ,
};

typedef union {
Expand All @@ -56,6 +57,7 @@ struct smbus_op_params {
uint8_t reg;
uint8_t i2c_bus;
uint8_t address;
uint8_t read_count;
int len;
SMBUS_DTYPE data;
};
Expand Down Expand Up @@ -187,6 +189,7 @@ parse_io_width(const char *arg, struct smbus_op_params *params,
break;
case SMBUS_SIZE_BLOCK:
case SMBUS_BLOCK_PROC_CALL:
case SMBUS_WRITE_READ:
{
int len;
const char *src = arg;
Expand Down Expand Up @@ -281,7 +284,9 @@ smbus_prologue(const char *argv[], struct smbus_op_params *params,

/* Only obtain the register if size designates that it is not a byte
* or quick operation. */
if (op->size != SMBUS_SIZE_BYTE && op->size != SMBUS_QUICK) {
if (op->size != SMBUS_SIZE_BYTE &&
op->size != SMBUS_QUICK &&
op->size != SMBUS_WRITE_READ) {
if (parse_uint8(argv[3], &params->reg)) {
fprintf(stderr, "invalid register value\n");
return -1;
Expand Down Expand Up @@ -547,6 +552,73 @@ smbus_block_process_call_op(struct smbus_op_params *params,
return 0;
}

static int
smbus_writeread(int argc, const char *argv[], const struct cmd_info *info)
{
int ret;
struct smbus_op_params params;
memset(&params, 0, sizeof(params));
const struct smbus_op *op = (const struct smbus_op *)info->privdata;

if (smbus_prologue(argv, &params, op) < 0) {
return -1;
}

if (parse_io_width(argv[3], &params, op) < 0) {
fprintf(stderr, "%s: %s: invalid value to write\n",
argv[0], argv[3]);
close(params.fd);
return -1;
}
if(parse_uint8(argv[4], &params.read_count) < 0) {
fprintf(stderr, "invalid read count %s.\n", argv[4]);
return -1;
}
if (params.read_count > I2C_SMBUS_BLOCK_MAX) {
fprintf(stderr, "read count %s > %d.\n",
argv[3], I2C_SMBUS_BLOCK_MAX);
return -1;
}
ret = op->perform_op(&params, op);

close(params.fd);

return ret;
}

static int
smbus_writeread_op(struct smbus_op_params *params, const struct smbus_op *op)
{
struct i2c_msg msg[2];
struct i2c_rdwr_ioctl_data data;

/* First transfer: write the params bytes */
msg[0].addr = params->address;
msg[0].flags = 0;
msg[0].len = params->len;
msg[0].buf = (char*) params->data.array;

/* Second transfer: read `read_count` bytes */
msg[1].addr = params->address;
msg[1].flags = I2C_M_RD;
msg[1].len = params->read_count;
msg[1].buf = (char*) params->data.array;

/* Run the transfers */
data.msgs = msg;
data.nmsgs = 2;
int rv = ioctl(params->fd, I2C_RDWR, &data);

/* Error check */
if (rv < 0) {
fprintf(stderr, "I2C_RDWR failed: %s\n", strerror(errno));
return -1;
}

print_read_data(SMBUS_SIZE_BLOCK, params->read_count, &params->data);
return 0;
}

MAKE_PREREQ_PARAMS_FIXED_ARGS(smbus_read_params, 4,
"<adapter> <address> <register>", 0);
MAKE_PREREQ_PARAMS_FIXED_ARGS(smbus_write_params, 5,
Expand All @@ -557,6 +629,8 @@ MAKE_PREREQ_PARAMS_FIXED_ARGS(smbus_send_byte_params, 4,
"<adapter> <address> <value>", 0);
MAKE_PREREQ_PARAMS_FIXED_ARGS(smbus_quick_params, 4,
"<adapter> <address> <0|1>", 0);
MAKE_PREREQ_PARAMS_FIXED_ARGS(smbus_writeread_params, 5,
"<adapter> <address> <write_value> <read_count>", 0);

#define MAKE_SMBUS_OP(name_, size_, fn_) \
static const struct smbus_op name_ = { \
Expand All @@ -577,6 +651,7 @@ MAKE_SMBUS_OP(smbus_op_quick, SMBUS_QUICK, smbus_write_op);
MAKE_SMBUS_OP(smbus_op_proc_call, SMBUS_PROC_CALL, smbus_process_call_op);
MAKE_SMBUS_OP(smbus_op_block_proc_call, SMBUS_BLOCK_PROC_CALL,
smbus_block_process_call_op);
MAKE_SMBUS_OP(smbus_op_writeread, SMBUS_WRITE_READ, smbus_writeread_op);

#define MAKE_SMBUS_RW_CMDS(size_) \
MAKE_CMD_WITH_PARAMS(smbus_read ##size_, smbus_read, \
Expand All @@ -600,6 +675,8 @@ static const struct cmd_info smbus_cmds[] = {
&smbus_op_proc_call, &smbus_write_params),
MAKE_CMD_WITH_PARAMS(smbus_block_process_call, smbus_process_call,
&smbus_op_block_proc_call, &smbus_write_params),
MAKE_CMD_WITH_PARAMS(smbus_writeread, smbus_writeread,
&smbus_op_writeread, &smbus_writeread_params),
};

MAKE_CMD_GROUP(SMBus, "commands to access the system management bus",
Expand Down