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
22 changes: 18 additions & 4 deletions device.c
Original file line number Diff line number Diff line change
Expand Up @@ -299,6 +299,16 @@ int iio_device_reg_write(struct iio_device *dev,
uint32_t address, uint32_t value)
{
const struct iio_attr *attr;
const struct iio_backend_ops *ops = dev->ctx->ops;

/* Use atomic backend operation if available */
if (ops && ops->reg_write) {
return ops->reg_write(dev, address, value);
}

/* Fallback to the original attribute-based implementation.
* NOTE: This has a potential race condition with reg_read operations
* when multiple clients access the same IIOD server. */
ssize_t ret;
char buf[1024];

Expand All @@ -317,11 +327,15 @@ int iio_device_reg_write(struct iio_device *dev,
int iio_device_reg_read(struct iio_device *dev,
uint32_t address, uint32_t *value)
{
/* NOTE: There is a race condition here. But it is extremely unlikely to
* happen, and as this is a debug function, it shouldn't be used for
* something else than debug. */

const struct iio_attr *attr;
const struct iio_backend_ops *ops = dev->ctx->ops;

/* Use atomic backend operation if available */
if (ops && ops->reg_read) {
return ops->reg_read(dev, address, value);
}

/* Fallback to the original attribute-based implementation. */
long long val;
int ret;

Expand Down
49 changes: 49 additions & 0 deletions iiod-client.c
Original file line number Diff line number Diff line change
Expand Up @@ -1885,3 +1885,52 @@ int iiod_client_read_event(struct iio_event_stream_pdata *pdata,

return ret;
}

int iiod_client_reg_read(struct iiod_client *client,
const struct iio_device *dev,
uint32_t address, uint32_t *value)
{
struct iiod_io *io = iiod_responder_get_default_io(client->responder);
struct iiod_command cmd;
struct iiod_buf buf;
int ret;

cmd.op = IIOD_OP_REG_READ;
cmd.dev = (uint8_t) iio_device_get_index(dev);
cmd.code = (int32_t) address;

buf.ptr = value;
buf.size = sizeof(*value);

ret = iiod_io_exec_command(io, &cmd, NULL, &buf);
if (ret < 0)
return ret;

if (ret != sizeof(*value))
return -EIO;

return 0;
}

int iiod_client_reg_write(struct iiod_client *client,
const struct iio_device *dev,
uint32_t address, uint32_t value)
{
struct iiod_io *io = iiod_responder_get_default_io(client->responder);
struct iiod_command cmd;
struct iiod_buf buf;
int ret;

cmd.op = IIOD_OP_REG_WRITE;
cmd.dev = (uint8_t) iio_device_get_index(dev);
cmd.code = (int32_t) address;

buf.ptr = &value;
buf.size = sizeof(value);

ret = iiod_io_send_command(io, &cmd, &buf, 1);
if (ret < 0)
return ret;

return iiod_io_wait_for_command_done(io);
}
3 changes: 3 additions & 0 deletions iiod-responder.h
Original file line number Diff line number Diff line change
Expand Up @@ -55,6 +55,9 @@ enum iiod_opcode {
IIOD_OP_FREE_EVSTREAM,
IIOD_OP_READ_EVENT,

IIOD_OP_REG_READ,
IIOD_OP_REG_WRITE,

IIOD_NB_OPCODES,
};

Expand Down
67 changes: 67 additions & 0 deletions iiod/responder.c
Original file line number Diff line number Diff line change
Expand Up @@ -1170,6 +1170,70 @@ static void handle_read_event(struct parser_pdata *pdata,
}
}

static void handle_reg_read(struct parser_pdata *pdata,
const struct iiod_command *cmd,
struct iiod_command_data *cmd_data)
{
struct iiod_io *io = iiod_command_get_default_io(cmd_data);
const struct iio_context *ctx = pdata->ctx;
const struct iio_device *dev;
uint32_t address, value;
struct iiod_buf buf;
int ret;

dev = iio_context_get_device(ctx, cmd->dev);
if (!dev) {
ret = -ENODEV;
goto out_send_response;
}

address = (uint32_t) cmd->code;

ret = iio_device_reg_read((struct iio_device *)dev, address, &value);
if (ret < 0) {
iiod_io_send_response_code(io, ret);
} else {
buf.ptr = &value;
buf.size = sizeof(value);
iiod_io_send_response(io, sizeof(value), &buf, 1);
}

return;

out_send_response:
iiod_io_send_response_code(io, ret);
}

static void handle_reg_write(struct parser_pdata *pdata,
const struct iiod_command *cmd,
struct iiod_command_data *cmd_data)
{
struct iiod_io *io = iiod_command_get_default_io(cmd_data);
const struct iio_context *ctx = pdata->ctx;
const struct iio_device *dev;
uint32_t address, value;
struct iiod_buf buf;
int ret;

dev = iio_context_get_device(ctx, cmd->dev);
if (!dev) {
ret = -ENODEV;
goto out_send_response;
}

address = (uint32_t) cmd->code;
buf.ptr = &value;
buf.size = sizeof(value);
ret = iiod_command_data_read(cmd_data, &buf);
if (ret < 0)
goto out_send_response;

ret = iio_device_reg_write((struct iio_device *)dev, address, value);

out_send_response:
iiod_io_send_response_code(io, ret);
}

typedef void (*iiod_opcode_fn)(struct parser_pdata *,
const struct iiod_command *,
struct iiod_command_data *cmd_data);
Expand Down Expand Up @@ -1202,6 +1266,9 @@ static const iiod_opcode_fn iiod_op_functions[] = {
[IIOD_OP_CREATE_EVSTREAM] = handle_create_evstream,
[IIOD_OP_FREE_EVSTREAM] = handle_free_evstream,
[IIOD_OP_READ_EVENT] = handle_read_event,

[IIOD_OP_REG_READ] = handle_reg_read,
[IIOD_OP_REG_WRITE] = handle_reg_write,
};

static int iiod_cmd(const struct iiod_command *cmd,
Expand Down
4 changes: 4 additions & 0 deletions include/iio/iio-backend.h
Original file line number Diff line number Diff line change
Expand Up @@ -138,6 +138,10 @@ struct iio_backend_ops {
int (*read_ev)(struct iio_event_stream_pdata *pdata,
struct iio_event *out_event,
bool nonblock);

/* Atomic register operations */
int (*reg_read)(const struct iio_device *dev, uint32_t address, uint32_t *value);
int (*reg_write)(const struct iio_device *dev, uint32_t address, uint32_t value);
};

/**
Expand Down
7 changes: 7 additions & 0 deletions include/iio/iiod-client.h
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,13 @@ __api int iiod_client_read_event(struct iio_event_stream_pdata *pdata,
struct iio_event *out_event,
bool nonblock);

__api int iiod_client_reg_read(struct iiod_client *client,
const struct iio_device *dev,
uint32_t address, uint32_t *value);
__api int iiod_client_reg_write(struct iiod_client *client,
const struct iio_device *dev,
uint32_t address, uint32_t value);

#undef __api

#endif /* _IIOD_CLIENT_H */
114 changes: 113 additions & 1 deletion local.c
Original file line number Diff line number Diff line change
Expand Up @@ -34,6 +34,8 @@
#include <time.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/file.h>
#include <inttypes.h>

#define NB_BLOCKS 4

Expand Down Expand Up @@ -495,7 +497,6 @@ static ssize_t local_do_read_dev_attr(const char *id, unsigned int buf_id,
else
dst[0] = '\0';

fflush(f);
if (ferror(f))
ret = -errno;
fclose(f);
Expand Down Expand Up @@ -639,6 +640,115 @@ static int local_set_trigger(const struct iio_device *dev,
return 0;
}

static int local_reg_read(const struct iio_device *dev,
uint32_t address, uint32_t *value)
{
char buf[1024];
char addr_str[32];
char val_str[32];
FILE *f;
int fd;
ssize_t ret;

iio_snprintf(buf, sizeof(buf), "/sys/kernel/debug/iio/%s/direct_reg_access",
dev->id);

f = fopen(buf, "r+");
if (!f)
return -errno;

fd = fileno(f);

/* Get exclusive lock for atomic write-then-read */
if (flock(fd, LOCK_EX) < 0) {
ret = -errno;
fclose(f);
return ret;
}

iio_snprintf(addr_str, sizeof(addr_str), "0x%" PRIx32, address);
ret = fwrite(addr_str, 1, strlen(addr_str), f);
fflush(f);
if ((size_t)ret < strlen(addr_str)) {
if (ferror(f))
ret = -errno;
else
ret = -EIO;

goto unlock;
}

rewind(f);
ret = fread(val_str, 1, sizeof(val_str) - 1, f);
if (!feof(f)){
ret = -EFBIG;
goto unlock;
}
if (ferror(f)) {
ret = -errno;
goto unlock;
}

if (ret > 0)
val_str[ret - 1] = '\0';
else
val_str[0] = '\0';

if (sscanf(val_str, "0x%x", value) != 1) {
ret = -EIO;
goto unlock;
}

ret = 0;

unlock:
flock(fd, LOCK_UN);
fclose(f);
return ret;
}

static int local_reg_write(const struct iio_device *dev,
uint32_t address, uint32_t value)
{
char buf[1024];
char write_str[64];
FILE *f;
int fd;
ssize_t ret;

iio_snprintf(buf, sizeof(buf), "/sys/kernel/debug/iio/%s/direct_reg_access",
dev->id);

f = fopen(buf, "w");
if (!f)
return -errno;

fd = fileno(f);

/* Get exclusive lock for atomic write operation */
if (flock(fd, LOCK_EX) < 0) {
ret = -errno;
fclose(f);
return ret;
}

iio_snprintf(write_str, sizeof(write_str), "0x%" PRIx32 " 0x%" PRIx32, address, value);
ret = fwrite(write_str, 1, strlen(write_str), f);
fflush(f);
if ((size_t)ret < strlen(write_str)) {
if (ferror(f))
ret = -errno;
else
ret = -EIO;
} else {
ret = 0;
}

flock(fd, LOCK_UN);
fclose(f);
return ret;
}

static bool is_channel(const struct iio_device *dev, const char *attr, bool strict)
{
char *ptr = NULL;
Expand Down Expand Up @@ -1768,6 +1878,8 @@ static const struct iio_backend_ops local_ops = {

.get_dmabuf_fd = local_get_dmabuf_fd,
.disable_cpu_access = local_disable_cpu_access,
.reg_read = local_reg_read,
.reg_write = local_reg_write,
};

const struct iio_backend iio_local_backend = {
Expand Down
33 changes: 33 additions & 0 deletions network.c
Original file line number Diff line number Diff line change
Expand Up @@ -513,6 +513,36 @@ network_open_events_fd(const struct iio_device *dev)
return iiod_client_open_event_stream(pdata->iiod_client, dev);
}

static int network_reg_read(const struct iio_device *dev,
uint32_t address, uint32_t *value)
{
const struct iio_context *ctx = iio_device_get_context(dev);
struct iio_context_pdata *pdata = iio_context_get_pdata(ctx);
struct iiod_client *client = pdata->iiod_client;

if (!iiod_client_uses_binary_interface(client)) {
/* Fallback to attribute-based method for ASCII protocol */
return -ENOSYS;
}

return iiod_client_reg_read(client, dev, address, value);
}

static int network_reg_write(const struct iio_device *dev,
uint32_t address, uint32_t value)
{
const struct iio_context *ctx = iio_device_get_context(dev);
struct iio_context_pdata *pdata = iio_context_get_pdata(ctx);
struct iiod_client *client = pdata->iiod_client;

if (!iiod_client_uses_binary_interface(client)) {
/* Fallback to attribute-based method for ASCII protocol */
return -ENOSYS;
}

return iiod_client_reg_write(client, dev, address, value);
}

static const struct iio_backend_ops network_ops = {
.scan = IF_ENABLED(HAVE_DNS_SD, dnssd_context_scan),
.create = network_create_context,
Expand All @@ -539,6 +569,9 @@ static const struct iio_backend_ops network_ops = {
.open_ev = network_open_events_fd,
.close_ev = iiod_client_close_event_stream,
.read_ev = iiod_client_read_event,

.reg_read = network_reg_read,
.reg_write = network_reg_write,
};

__api_export_if(WITH_NETWORK_BACKEND_DYNAMIC)
Expand Down
Loading