Skip to content

Commit

Permalink
local: Add support for hwmon devices
Browse files Browse the repository at this point in the history
Add iio_device and iio_channel objects to the local context created from
the local hwmon devices. These objects can then be used the exact same
way as if they were created for IIO devices.

Signed-off-by: Paul Cercueil <[email protected]>
Co-developed-by: Robin Getz <[email protected]>
Signed-off-by: Robin Getz <[email protected]>
  • Loading branch information
pcercuei committed Jan 5, 2022
1 parent e965bb1 commit 145b322
Show file tree
Hide file tree
Showing 3 changed files with 75 additions and 21 deletions.
8 changes: 8 additions & 0 deletions channel.c
Original file line number Diff line number Diff line change
Expand Up @@ -158,6 +158,14 @@ static int iio_channel_find_type(const char *id,
return -EINVAL;
}

#if WITH_HWMON
bool iio_channel_is_hwmon(const char *id)
{
return iio_channel_find_type(id, hwmon_chan_type_name_spec,
ARRAY_SIZE(hwmon_chan_type_name_spec)) >= 0;
}
#endif /* WITH_HWMON */

/*
* Initializes all auto-detected fields of the channel struct. Must be called
* after the channel has been otherwise fully initialized.
Expand Down
2 changes: 2 additions & 0 deletions iio-private.h
Original file line number Diff line number Diff line change
Expand Up @@ -289,6 +289,8 @@ static inline void iio_update_xml_indexes(ssize_t ret, char **ptr, ssize_t *len,
*alen += ret;
}

bool iio_channel_is_hwmon(const char *id);

static inline bool iio_device_is_hwmon(const struct iio_device *dev)
{
return WITH_HWMON && dev->id[0] == 'h';
Expand Down
86 changes: 65 additions & 21 deletions local.c
Original file line number Diff line number Diff line change
Expand Up @@ -676,8 +676,13 @@ static ssize_t local_read_dev_attr(const struct iio_device *dev,

switch (type) {
case IIO_ATTR_TYPE_DEVICE:
iio_snprintf(buf, sizeof(buf), "/sys/bus/iio/devices/%s/%s",
dev->id, attr);
if (iio_device_is_hwmon(dev)) {
iio_snprintf(buf, sizeof(buf), "/sys/class/hwmon/%s/%s",
dev->id, attr);
} else {
iio_snprintf(buf, sizeof(buf), "/sys/bus/iio/devices/%s/%s",
dev->id, attr);
}
break;
case IIO_ATTR_TYPE_DEBUG:
iio_snprintf(buf, sizeof(buf), "/sys/kernel/debug/iio/%s/%s",
Expand Down Expand Up @@ -725,8 +730,13 @@ static ssize_t local_write_dev_attr(const struct iio_device *dev,

switch (type) {
case IIO_ATTR_TYPE_DEVICE:
iio_snprintf(buf, sizeof(buf), "/sys/bus/iio/devices/%s/%s",
if (iio_device_is_hwmon(dev)) {
iio_snprintf(buf, sizeof(buf), "/sys/class/hwmon/%s/%s",
dev->id, attr);
} else {
iio_snprintf(buf, sizeof(buf), "/sys/bus/iio/devices/%s/%s",
dev->id, attr);
}
break;
case IIO_ATTR_TYPE_DEBUG:
iio_snprintf(buf, sizeof(buf), "/sys/kernel/debug/iio/%s/%s",
Expand Down Expand Up @@ -1130,9 +1140,12 @@ static int local_set_trigger(const struct iio_device *dev,
return 0;
}

static bool is_channel(const char *attr, bool strict)
static bool is_channel(const struct iio_device *dev, const char *attr, bool strict)
{
char *ptr = NULL;

if (iio_device_is_hwmon(dev))
return iio_channel_is_hwmon(attr);
if (!strncmp(attr, "in_timestamp_", sizeof("in_timestamp_") - 1))
return true;
if (!strncmp(attr, "in_", 3))
Expand All @@ -1151,15 +1164,23 @@ static bool is_channel(const char *attr, bool strict)
return false;
}

static char * get_channel_id(const char *attr)
static char * get_channel_id(struct iio_device *dev, const char *attr)
{
char *res, *ptr;
char *res, *ptr = strchr(attr, '_');
size_t len;

attr = strchr(attr, '_') + 1;
ptr = strchr(attr, '_');
if (find_channel_modifier(ptr + 1, &len) != IIO_NO_MOD)
ptr += len + 1;
if (!iio_device_is_hwmon(dev)) {
attr = ptr + 1;
ptr = strchr(attr, '_');
if (find_channel_modifier(ptr + 1, &len) != IIO_NO_MOD)
ptr += len + 1;
} else if (!ptr) {
/*
* Attribute is 'pwmX' without underscore: the attribute name
* is our channel ID.
*/
return iio_strdup(attr);
}

res = malloc(ptr - attr + 1);
if (!res)
Expand All @@ -1172,10 +1193,19 @@ static char * get_channel_id(const char *attr)

static char * get_short_attr_name(struct iio_channel *chn, const char *attr)
{
char *ptr = strchr(attr, '_') + 1;
char *ptr = strchr(attr, '_');
size_t len;

ptr = strchr(ptr, '_') + 1;
if (iio_device_is_hwmon(chn->dev)) {
/*
* PWM hwmon devices can have an attribute named directly after
* the channel's ID; in that particular case we don't need to
* strip the prefix.
*/
return iio_strdup(ptr ? ptr + 1 : attr);
}

ptr = strchr(ptr + 1, '_') + 1;
if (find_channel_modifier(ptr, &len) != IIO_NO_MOD)
ptr += len + 1;

Expand Down Expand Up @@ -1427,11 +1457,13 @@ static struct iio_channel *create_channel(struct iio_device *dev,
if (!chn->pdata)
goto err_free_chn;

if (!strncmp(attr, "out_", 4)) {
chn->is_output = true;
} else if (strncmp(attr, "in_", 3)) {
err = -EINVAL;
goto err_free_chn_pdata;
if (!iio_device_is_hwmon(dev)) {
if (!strncmp(attr, "out_", 4)) {
chn->is_output = true;
} else if (strncmp(attr, "in_", 3)) {
err = -EINVAL;
goto err_free_chn_pdata;
}
}

chn->dev = dev;
Expand Down Expand Up @@ -1461,7 +1493,7 @@ static int add_channel(struct iio_device *dev, const char *name,
unsigned int i;
int ret;

channel_id = get_channel_id(name);
channel_id = get_channel_id(dev, name);
if (!channel_id)
return -ENOMEM;

Expand Down Expand Up @@ -1608,7 +1640,7 @@ static int detect_and_move_global_attrs(struct iio_device *dev)
if (!dev->attrs.names[i])
continue;

if (is_channel(attr, false)) {
if (is_channel(dev, attr, false)) {
ret = add_channel(dev, attr, attr, false);
if (ret)
return ret;
Expand Down Expand Up @@ -1655,7 +1687,7 @@ static int add_attr_or_channel_helper(struct iio_device *dev,
iio_snprintf(buf, sizeof(buf), "scan_elements/%s", name);
path = buf;
} else {
if (!is_channel(name, true))
if (!is_channel(dev, name, true))
return add_attr_to_device(dev, name);
path = name;
}
Expand Down Expand Up @@ -2038,6 +2070,7 @@ struct iio_context * local_create_context(void)
char *description;
int ret = -ENOMEM;
struct utsname uts;
bool no_iio;

description = local_get_description(NULL);

Expand All @@ -2049,8 +2082,19 @@ struct iio_context * local_create_context(void)
local_set_timeout(ctx, DEFAULT_TIMEOUT_MS);

ret = foreach_in_dir(ctx, "/sys/bus/iio/devices", true, create_device);
no_iio = ret == -ENOENT;
if (WITH_HWMON && no_iio)
ret = 0; /* Not an error, unless we also have no hwmon devices */
if (ret < 0)
goto err_context_destroy;
goto err_context_destroy;

if (WITH_HWMON) {
ret = foreach_in_dir(ctx, "/sys/class/hwmon", true, create_device);
if (ret == -ENOENT && !no_iio)
ret = 0; /* IIO devices but no hwmon devices - not an error */
if (ret < 0)
goto err_context_destroy;
}

qsort(ctx->devices, ctx->nb_devices, sizeof(struct iio_device *),
iio_device_compare);
Expand Down

0 comments on commit 145b322

Please sign in to comment.