Skip to content

Commit

Permalink
iio: Track enabled channels on a per channel basis
Browse files Browse the repository at this point in the history
commit 9e2e3e2 m2k branch.

Now that we support multiple channels with the same scan index we can no
longer use the scan mask to track which channels have been enabled.
Otherwise it is not possible to enable channels with the same scan index
independently.

Introduce a new channel mask which is used instead of the scan mask to
track which channels are enabled. Whenever the channel mask is changed a
new scan mask is computed based on it.

Signed-off-by: Lars-Peter Clausen <lars@metafoo.de>
  • Loading branch information
larsclausen authored and stefpopa committed Mar 6, 2018
1 parent a87de8e commit 81d0079
Show file tree
Hide file tree
Showing 4 changed files with 64 additions and 16 deletions.
60 changes: 46 additions & 14 deletions drivers/iio/industrialio-buffer.c
Original file line number Diff line number Diff line change
Expand Up @@ -276,12 +276,18 @@ int iio_buffer_alloc_scanmask(struct iio_buffer *buffer,
if (buffer->scan_mask == NULL)
return -ENOMEM;

buffer->channel_mask = kcalloc(BITS_TO_LONGS(indio_dev->num_channels),
sizeof(*buffer->channel_mask), GFP_KERNEL);
if (buffer->channel_mask == NULL)
return -ENOMEM;

return 0;
}
EXPORT_SYMBOL(iio_buffer_alloc_scanmask);

void iio_buffer_free_scanmask(struct iio_buffer *buffer)
{
kfree(buffer->channel_mask);
kfree(buffer->scan_mask);
}
EXPORT_SYMBOL(iio_buffer_free_scanmask);
Expand Down Expand Up @@ -333,7 +339,7 @@ static ssize_t iio_scan_el_show(struct device *dev,

/* Ensure ret is 0 or 1. */
ret = !!test_bit(to_iio_dev_attr(attr)->address,
indio_dev->buffer->scan_mask);
indio_dev->buffer->channel_mask);

return sprintf(buf, "%d\n", ret);
}
Expand Down Expand Up @@ -378,13 +384,14 @@ static bool iio_validate_scan_mask(struct iio_dev *indio_dev,
* buffers might request, hence this code only verifies that the
* individual buffers request is plausible.
*/
static int iio_scan_mask_set(struct iio_dev *indio_dev,
static int iio_channel_mask_set(struct iio_dev *indio_dev,
struct iio_buffer *buffer, int bit)
{
const unsigned long *mask;
unsigned long *trialmask;
unsigned int ch;

trialmask = kmalloc(sizeof(*trialmask)*
trialmask = kzalloc(sizeof(*trialmask)*
BITS_TO_LONGS(indio_dev->masklength),
GFP_KERNEL);

Expand All @@ -394,8 +401,11 @@ static int iio_scan_mask_set(struct iio_dev *indio_dev,
WARN(1, "Trying to set scanmask prior to registering buffer\n");
goto err_invalid_mask;
}
bitmap_copy(trialmask, buffer->scan_mask, indio_dev->masklength);
set_bit(bit, trialmask);

set_bit(bit, buffer->channel_mask);

for_each_set_bit(ch, buffer->channel_mask, indio_dev->num_channels)
set_bit(indio_dev->channels[ch].scan_index, trialmask);

if (!iio_validate_scan_mask(indio_dev, trialmask))
goto err_invalid_mask;
Expand All @@ -414,16 +424,37 @@ static int iio_scan_mask_set(struct iio_dev *indio_dev,
return 0;

err_invalid_mask:
clear_bit(bit, buffer->channel_mask);
kfree(trialmask);
return -EINVAL;
}

static int iio_scan_mask_clear(struct iio_buffer *buffer, int bit)
static int iio_channel_mask_clear(struct iio_dev *indio_dev,
struct iio_buffer *buffer, int bit)
{
clear_bit(bit, buffer->scan_mask);
unsigned int ch;

clear_bit(bit, buffer->channel_mask);

memset(buffer->scan_mask, 0, BITS_TO_LONGS(indio_dev->masklength));
for_each_set_bit(ch, buffer->channel_mask, indio_dev->num_channels)
set_bit(indio_dev->channels[ch].scan_index, buffer->scan_mask);
return 0;
}

static int iio_channel_mask_query(struct iio_dev *indio_dev,
struct iio_buffer *buffer, int bit)
{
if (bit > indio_dev->num_channels)
return -EINVAL;

if (!buffer->channel_mask)
return 0;

/* Ensure return value is 0 or 1. */
return !!test_bit(bit, buffer->channel_mask);
}

static ssize_t iio_scan_el_store(struct device *dev,
struct device_attribute *attr,
const char *buf,
Expand All @@ -443,15 +474,15 @@ static ssize_t iio_scan_el_store(struct device *dev,
ret = -EBUSY;
goto error_ret;
}
ret = iio_scan_mask_query(indio_dev, buffer, this_attr->address);
ret = iio_channel_mask_query(indio_dev, buffer, this_attr->address);
if (ret < 0)
goto error_ret;
if (!state && ret) {
ret = iio_scan_mask_clear(buffer, this_attr->address);
ret = iio_channel_mask_clear(indio_dev, buffer, this_attr->address);
if (ret)
goto error_ret;
} else if (state && !ret) {
ret = iio_scan_mask_set(indio_dev, buffer, this_attr->address);
ret = iio_channel_mask_set(indio_dev, buffer, this_attr->address);
if (ret)
goto error_ret;
}
Expand Down Expand Up @@ -497,7 +528,8 @@ static ssize_t iio_scan_el_ts_store(struct device *dev,
}

static int iio_buffer_add_channel_sysfs(struct iio_dev *indio_dev,
const struct iio_chan_spec *chan)
const struct iio_chan_spec *chan,
unsigned int address)
{
int ret, attrcount = 0;
struct iio_buffer *buffer = indio_dev->buffer;
Expand Down Expand Up @@ -529,7 +561,7 @@ static int iio_buffer_add_channel_sysfs(struct iio_dev *indio_dev,
chan,
&iio_scan_el_show,
&iio_scan_el_store,
chan->scan_index,
address,
0,
&indio_dev->dev,
&buffer->scan_el_dev_attr_list);
Expand All @@ -538,7 +570,7 @@ static int iio_buffer_add_channel_sysfs(struct iio_dev *indio_dev,
chan,
&iio_scan_el_ts_show,
&iio_scan_el_ts_store,
chan->scan_index,
address,
0,
&indio_dev->dev,
&buffer->scan_el_dev_attr_list);
Expand Down Expand Up @@ -1238,7 +1270,7 @@ int iio_buffer_alloc_sysfs_and_mask(struct iio_dev *indio_dev)
continue;

ret = iio_buffer_add_channel_sysfs(indio_dev,
&channels[i]);
&channels[i], i);
if (ret < 0)
goto error_cleanup_dynamic;
attrcount += ret;
Expand Down
17 changes: 15 additions & 2 deletions drivers/iio/inkern.c
Original file line number Diff line number Diff line change
Expand Up @@ -153,6 +153,7 @@ static int __of_iio_channel_get(struct iio_channel *channel,
if (index < 0)
goto err_put;
channel->channel = &indio_dev->channels[index];
channel->channel_index = index;

return 0;

Expand Down Expand Up @@ -751,13 +752,25 @@ EXPORT_SYMBOL_GPL(iio_write_channel_raw);
void iio_buffer_channel_enable(struct iio_buffer *buffer,
const struct iio_channel *chan)
{
set_bit(chan->channel->scan_index, buffer->scan_mask);
unsigned int ch;

set_bit(chan->channel_index, buffer->channel_mask);

memset(buffer->scan_mask, 0, BITS_TO_LONGS(chan->indio_dev->masklength));
for_each_set_bit(ch, buffer->channel_mask, chan->indio_dev->num_channels)
set_bit(chan->indio_dev->channels[ch].scan_index, buffer->scan_mask);
}
EXPORT_SYMBOL(iio_buffer_channel_enable);

void iio_buffer_channel_disable(struct iio_buffer *buffer,
const struct iio_channel *chan)
{
clear_bit(chan->channel->scan_index, buffer->scan_mask);
unsigned int ch;

clear_bit(chan->channel_index, buffer->channel_mask);

memset(buffer->scan_mask, 0, BITS_TO_LONGS(chan->indio_dev->masklength));
for_each_set_bit(ch, buffer->channel_mask, chan->indio_dev->num_channels)
set_bit(chan->indio_dev->channels[ch].scan_index, buffer->scan_mask);
}
EXPORT_SYMBOL(iio_buffer_channel_disable);
1 change: 1 addition & 0 deletions include/linux/iio/buffer.h
Original file line number Diff line number Diff line change
Expand Up @@ -141,6 +141,7 @@ struct iio_buffer {
int length;
int bytes_per_datum;
struct attribute_group *scan_el_attrs;
long *channel_mask;
long *scan_mask;
bool scan_timestamp;
const struct iio_buffer_access_funcs *access;
Expand Down
2 changes: 2 additions & 0 deletions include/linux/iio/consumer.h
Original file line number Diff line number Diff line change
Expand Up @@ -21,11 +21,13 @@ struct device;
* struct iio_channel - everything needed for a consumer to use a channel
* @indio_dev: Device on which the channel exists.
* @channel: Full description of the channel.
* @channel_index: Offset of the channel into the devices channel array.
* @data: Data about the channel used by consumer.
*/
struct iio_channel {
struct iio_dev *indio_dev;
const struct iio_chan_spec *channel;
unsigned int channel_index;
void *data;
};

Expand Down

0 comments on commit 81d0079

Please sign in to comment.