diff options
Diffstat (limited to 'drivers/iio/industrialio-buffer.c')
-rw-r--r-- | drivers/iio/industrialio-buffer.c | 52 |
1 files changed, 44 insertions, 8 deletions
diff --git a/drivers/iio/industrialio-buffer.c b/drivers/iio/industrialio-buffer.c index ac185b8694bd..4add9bb40eeb 100644 --- a/drivers/iio/industrialio-buffer.c +++ b/drivers/iio/industrialio-buffer.c | |||
@@ -285,11 +285,14 @@ int iio_buffer_register(struct iio_dev *indio_dev, | |||
285 | if (channels) { | 285 | if (channels) { |
286 | /* new magic */ | 286 | /* new magic */ |
287 | for (i = 0; i < num_channels; i++) { | 287 | for (i = 0; i < num_channels; i++) { |
288 | if (channels[i].scan_index < 0) | ||
289 | continue; | ||
290 | |||
288 | /* Establish necessary mask length */ | 291 | /* Establish necessary mask length */ |
289 | if (channels[i].scan_index > | 292 | if (channels[i].scan_index > |
290 | (int)indio_dev->masklength - 1) | 293 | (int)indio_dev->masklength - 1) |
291 | indio_dev->masklength | 294 | indio_dev->masklength |
292 | = indio_dev->channels[i].scan_index + 1; | 295 | = channels[i].scan_index + 1; |
293 | 296 | ||
294 | ret = iio_buffer_add_channel_sysfs(indio_dev, | 297 | ret = iio_buffer_add_channel_sysfs(indio_dev, |
295 | &channels[i]); | 298 | &channels[i]); |
@@ -553,6 +556,10 @@ int iio_sw_buffer_preenable(struct iio_dev *indio_dev) | |||
553 | buffer->scan_mask); | 556 | buffer->scan_mask); |
554 | else | 557 | else |
555 | indio_dev->active_scan_mask = buffer->scan_mask; | 558 | indio_dev->active_scan_mask = buffer->scan_mask; |
559 | |||
560 | if (indio_dev->active_scan_mask == NULL) | ||
561 | return -EINVAL; | ||
562 | |||
556 | iio_update_demux(indio_dev); | 563 | iio_update_demux(indio_dev); |
557 | 564 | ||
558 | if (indio_dev->info->update_scan_mode) | 565 | if (indio_dev->info->update_scan_mode) |
@@ -564,6 +571,31 @@ int iio_sw_buffer_preenable(struct iio_dev *indio_dev) | |||
564 | EXPORT_SYMBOL(iio_sw_buffer_preenable); | 571 | EXPORT_SYMBOL(iio_sw_buffer_preenable); |
565 | 572 | ||
566 | /** | 573 | /** |
574 | * iio_validate_scan_mask_onehot() - Validates that exactly one channel is selected | ||
575 | * @indio_dev: the iio device | ||
576 | * @mask: scan mask to be checked | ||
577 | * | ||
578 | * Return true if exactly one bit is set in the scan mask, false otherwise. It | ||
579 | * can be used for devices where only one channel can be active for sampling at | ||
580 | * a time. | ||
581 | */ | ||
582 | bool iio_validate_scan_mask_onehot(struct iio_dev *indio_dev, | ||
583 | const unsigned long *mask) | ||
584 | { | ||
585 | return bitmap_weight(mask, indio_dev->masklength) == 1; | ||
586 | } | ||
587 | EXPORT_SYMBOL_GPL(iio_validate_scan_mask_onehot); | ||
588 | |||
589 | static bool iio_validate_scan_mask(struct iio_dev *indio_dev, | ||
590 | const unsigned long *mask) | ||
591 | { | ||
592 | if (!indio_dev->setup_ops->validate_scan_mask) | ||
593 | return true; | ||
594 | |||
595 | return indio_dev->setup_ops->validate_scan_mask(indio_dev, mask); | ||
596 | } | ||
597 | |||
598 | /** | ||
567 | * iio_scan_mask_set() - set particular bit in the scan mask | 599 | * iio_scan_mask_set() - set particular bit in the scan mask |
568 | * @buffer: the buffer whose scan mask we are interested in | 600 | * @buffer: the buffer whose scan mask we are interested in |
569 | * @bit: the bit to be set. | 601 | * @bit: the bit to be set. |
@@ -582,27 +614,31 @@ int iio_scan_mask_set(struct iio_dev *indio_dev, | |||
582 | return -ENOMEM; | 614 | return -ENOMEM; |
583 | if (!indio_dev->masklength) { | 615 | if (!indio_dev->masklength) { |
584 | WARN_ON("trying to set scanmask prior to registering buffer\n"); | 616 | WARN_ON("trying to set scanmask prior to registering buffer\n"); |
585 | kfree(trialmask); | 617 | goto err_invalid_mask; |
586 | return -EINVAL; | ||
587 | } | 618 | } |
588 | bitmap_copy(trialmask, buffer->scan_mask, indio_dev->masklength); | 619 | bitmap_copy(trialmask, buffer->scan_mask, indio_dev->masklength); |
589 | set_bit(bit, trialmask); | 620 | set_bit(bit, trialmask); |
590 | 621 | ||
622 | if (!iio_validate_scan_mask(indio_dev, trialmask)) | ||
623 | goto err_invalid_mask; | ||
624 | |||
591 | if (indio_dev->available_scan_masks) { | 625 | if (indio_dev->available_scan_masks) { |
592 | mask = iio_scan_mask_match(indio_dev->available_scan_masks, | 626 | mask = iio_scan_mask_match(indio_dev->available_scan_masks, |
593 | indio_dev->masklength, | 627 | indio_dev->masklength, |
594 | trialmask); | 628 | trialmask); |
595 | if (!mask) { | 629 | if (!mask) |
596 | kfree(trialmask); | 630 | goto err_invalid_mask; |
597 | return -EINVAL; | ||
598 | } | ||
599 | } | 631 | } |
600 | bitmap_copy(buffer->scan_mask, trialmask, indio_dev->masklength); | 632 | bitmap_copy(buffer->scan_mask, trialmask, indio_dev->masklength); |
601 | 633 | ||
602 | kfree(trialmask); | 634 | kfree(trialmask); |
603 | 635 | ||
604 | return 0; | 636 | return 0; |
605 | }; | 637 | |
638 | err_invalid_mask: | ||
639 | kfree(trialmask); | ||
640 | return -EINVAL; | ||
641 | } | ||
606 | EXPORT_SYMBOL_GPL(iio_scan_mask_set); | 642 | EXPORT_SYMBOL_GPL(iio_scan_mask_set); |
607 | 643 | ||
608 | int iio_scan_mask_query(struct iio_dev *indio_dev, | 644 | int iio_scan_mask_query(struct iio_dev *indio_dev, |