|
|
@@ -577,66 +577,82 @@ int of_iio_read_mount_matrix(const struct device *dev,
|
|
|
#endif
|
|
|
EXPORT_SYMBOL(of_iio_read_mount_matrix);
|
|
|
|
|
|
-/**
|
|
|
- * iio_format_value() - Formats a IIO value into its string representation
|
|
|
- * @buf: The buffer to which the formatted value gets written
|
|
|
- * @type: One of the IIO_VAL_... constants. This decides how the val
|
|
|
- * and val2 parameters are formatted.
|
|
|
- * @size: Number of IIO value entries contained in vals
|
|
|
- * @vals: Pointer to the values, exact meaning depends on the
|
|
|
- * type parameter.
|
|
|
- *
|
|
|
- * Return: 0 by default, a negative number on failure or the
|
|
|
- * total number of characters written for a type that belongs
|
|
|
- * to the IIO_VAL_... constant.
|
|
|
- */
|
|
|
-ssize_t iio_format_value(char *buf, unsigned int type, int size, int *vals)
|
|
|
+static ssize_t __iio_format_value(char *buf, size_t len, unsigned int type,
|
|
|
+ int size, const int *vals)
|
|
|
{
|
|
|
unsigned long long tmp;
|
|
|
+ int tmp0, tmp1;
|
|
|
bool scale_db = false;
|
|
|
|
|
|
switch (type) {
|
|
|
case IIO_VAL_INT:
|
|
|
- return sprintf(buf, "%d\n", vals[0]);
|
|
|
+ return snprintf(buf, len, "%d", vals[0]);
|
|
|
case IIO_VAL_INT_PLUS_MICRO_DB:
|
|
|
scale_db = true;
|
|
|
case IIO_VAL_INT_PLUS_MICRO:
|
|
|
if (vals[1] < 0)
|
|
|
- return sprintf(buf, "-%d.%06u%s\n", abs(vals[0]),
|
|
|
- -vals[1], scale_db ? " dB" : "");
|
|
|
+ return snprintf(buf, len, "-%d.%06u%s", abs(vals[0]),
|
|
|
+ -vals[1], scale_db ? " dB" : "");
|
|
|
else
|
|
|
- return sprintf(buf, "%d.%06u%s\n", vals[0], vals[1],
|
|
|
- scale_db ? " dB" : "");
|
|
|
+ return snprintf(buf, len, "%d.%06u%s", vals[0], vals[1],
|
|
|
+ scale_db ? " dB" : "");
|
|
|
case IIO_VAL_INT_PLUS_NANO:
|
|
|
if (vals[1] < 0)
|
|
|
- return sprintf(buf, "-%d.%09u\n", abs(vals[0]),
|
|
|
- -vals[1]);
|
|
|
+ return snprintf(buf, len, "-%d.%09u", abs(vals[0]),
|
|
|
+ -vals[1]);
|
|
|
else
|
|
|
- return sprintf(buf, "%d.%09u\n", vals[0], vals[1]);
|
|
|
+ return snprintf(buf, len, "%d.%09u", vals[0], vals[1]);
|
|
|
case IIO_VAL_FRACTIONAL:
|
|
|
tmp = div_s64((s64)vals[0] * 1000000000LL, vals[1]);
|
|
|
- vals[0] = (int)div_s64_rem(tmp, 1000000000, &vals[1]);
|
|
|
- return sprintf(buf, "%d.%09u\n", vals[0], abs(vals[1]));
|
|
|
+ tmp1 = vals[1];
|
|
|
+ tmp0 = (int)div_s64_rem(tmp, 1000000000, &tmp1);
|
|
|
+ return snprintf(buf, len, "%d.%09u", tmp0, abs(tmp1));
|
|
|
case IIO_VAL_FRACTIONAL_LOG2:
|
|
|
tmp = (s64)vals[0] * 1000000000LL >> vals[1];
|
|
|
- vals[1] = do_div(tmp, 1000000000LL);
|
|
|
- vals[0] = tmp;
|
|
|
- return sprintf(buf, "%d.%09u\n", vals[0], vals[1]);
|
|
|
+ tmp1 = do_div(tmp, 1000000000LL);
|
|
|
+ tmp0 = tmp;
|
|
|
+ return snprintf(buf, len, "%d.%09u", tmp0, tmp1);
|
|
|
case IIO_VAL_INT_MULTIPLE:
|
|
|
{
|
|
|
int i;
|
|
|
- int len = 0;
|
|
|
+ int l = 0;
|
|
|
|
|
|
- for (i = 0; i < size; ++i)
|
|
|
- len += snprintf(&buf[len], PAGE_SIZE - len, "%d ",
|
|
|
- vals[i]);
|
|
|
- len += snprintf(&buf[len], PAGE_SIZE - len, "\n");
|
|
|
- return len;
|
|
|
+ for (i = 0; i < size; ++i) {
|
|
|
+ l += snprintf(&buf[l], len - l, "%d ", vals[i]);
|
|
|
+ if (l >= len)
|
|
|
+ break;
|
|
|
+ }
|
|
|
+ return l;
|
|
|
}
|
|
|
default:
|
|
|
return 0;
|
|
|
}
|
|
|
}
|
|
|
+
|
|
|
+/**
|
|
|
+ * iio_format_value() - Formats a IIO value into its string representation
|
|
|
+ * @buf: The buffer to which the formatted value gets written
|
|
|
+ * which is assumed to be big enough (i.e. PAGE_SIZE).
|
|
|
+ * @type: One of the IIO_VAL_... constants. This decides how the val
|
|
|
+ * and val2 parameters are formatted.
|
|
|
+ * @size: Number of IIO value entries contained in vals
|
|
|
+ * @vals: Pointer to the values, exact meaning depends on the
|
|
|
+ * type parameter.
|
|
|
+ *
|
|
|
+ * Return: 0 by default, a negative number on failure or the
|
|
|
+ * total number of characters written for a type that belongs
|
|
|
+ * to the IIO_VAL_... constant.
|
|
|
+ */
|
|
|
+ssize_t iio_format_value(char *buf, unsigned int type, int size, int *vals)
|
|
|
+{
|
|
|
+ ssize_t len;
|
|
|
+
|
|
|
+ len = __iio_format_value(buf, PAGE_SIZE, type, size, vals);
|
|
|
+ if (len >= PAGE_SIZE - 1)
|
|
|
+ return -EFBIG;
|
|
|
+
|
|
|
+ return len + sprintf(buf + len, "\n");
|
|
|
+}
|
|
|
EXPORT_SYMBOL_GPL(iio_format_value);
|
|
|
|
|
|
static ssize_t iio_read_channel_info(struct device *dev,
|
|
|
@@ -664,6 +680,119 @@ static ssize_t iio_read_channel_info(struct device *dev,
|
|
|
return iio_format_value(buf, ret, val_len, vals);
|
|
|
}
|
|
|
|
|
|
+static ssize_t iio_format_avail_list(char *buf, const int *vals,
|
|
|
+ int type, int length)
|
|
|
+{
|
|
|
+ int i;
|
|
|
+ ssize_t len = 0;
|
|
|
+
|
|
|
+ switch (type) {
|
|
|
+ case IIO_VAL_INT:
|
|
|
+ for (i = 0; i < length; i++) {
|
|
|
+ len += __iio_format_value(buf + len, PAGE_SIZE - len,
|
|
|
+ type, 1, &vals[i]);
|
|
|
+ if (len >= PAGE_SIZE)
|
|
|
+ return -EFBIG;
|
|
|
+ if (i < length - 1)
|
|
|
+ len += snprintf(buf + len, PAGE_SIZE - len,
|
|
|
+ " ");
|
|
|
+ else
|
|
|
+ len += snprintf(buf + len, PAGE_SIZE - len,
|
|
|
+ "\n");
|
|
|
+ if (len >= PAGE_SIZE)
|
|
|
+ return -EFBIG;
|
|
|
+ }
|
|
|
+ break;
|
|
|
+ default:
|
|
|
+ for (i = 0; i < length / 2; i++) {
|
|
|
+ len += __iio_format_value(buf + len, PAGE_SIZE - len,
|
|
|
+ type, 2, &vals[i * 2]);
|
|
|
+ if (len >= PAGE_SIZE)
|
|
|
+ return -EFBIG;
|
|
|
+ if (i < length / 2 - 1)
|
|
|
+ len += snprintf(buf + len, PAGE_SIZE - len,
|
|
|
+ " ");
|
|
|
+ else
|
|
|
+ len += snprintf(buf + len, PAGE_SIZE - len,
|
|
|
+ "\n");
|
|
|
+ if (len >= PAGE_SIZE)
|
|
|
+ return -EFBIG;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ return len;
|
|
|
+}
|
|
|
+
|
|
|
+static ssize_t iio_format_avail_range(char *buf, const int *vals, int type)
|
|
|
+{
|
|
|
+ int i;
|
|
|
+ ssize_t len;
|
|
|
+
|
|
|
+ len = snprintf(buf, PAGE_SIZE, "[");
|
|
|
+ switch (type) {
|
|
|
+ case IIO_VAL_INT:
|
|
|
+ for (i = 0; i < 3; i++) {
|
|
|
+ len += __iio_format_value(buf + len, PAGE_SIZE - len,
|
|
|
+ type, 1, &vals[i]);
|
|
|
+ if (len >= PAGE_SIZE)
|
|
|
+ return -EFBIG;
|
|
|
+ if (i < 2)
|
|
|
+ len += snprintf(buf + len, PAGE_SIZE - len,
|
|
|
+ " ");
|
|
|
+ else
|
|
|
+ len += snprintf(buf + len, PAGE_SIZE - len,
|
|
|
+ "]\n");
|
|
|
+ if (len >= PAGE_SIZE)
|
|
|
+ return -EFBIG;
|
|
|
+ }
|
|
|
+ break;
|
|
|
+ default:
|
|
|
+ for (i = 0; i < 3; i++) {
|
|
|
+ len += __iio_format_value(buf + len, PAGE_SIZE - len,
|
|
|
+ type, 2, &vals[i * 2]);
|
|
|
+ if (len >= PAGE_SIZE)
|
|
|
+ return -EFBIG;
|
|
|
+ if (i < 2)
|
|
|
+ len += snprintf(buf + len, PAGE_SIZE - len,
|
|
|
+ " ");
|
|
|
+ else
|
|
|
+ len += snprintf(buf + len, PAGE_SIZE - len,
|
|
|
+ "]\n");
|
|
|
+ if (len >= PAGE_SIZE)
|
|
|
+ return -EFBIG;
|
|
|
+ }
|
|
|
+ }
|
|
|
+
|
|
|
+ return len;
|
|
|
+}
|
|
|
+
|
|
|
+static ssize_t iio_read_channel_info_avail(struct device *dev,
|
|
|
+ struct device_attribute *attr,
|
|
|
+ char *buf)
|
|
|
+{
|
|
|
+ struct iio_dev *indio_dev = dev_to_iio_dev(dev);
|
|
|
+ struct iio_dev_attr *this_attr = to_iio_dev_attr(attr);
|
|
|
+ const int *vals;
|
|
|
+ int ret;
|
|
|
+ int length;
|
|
|
+ int type;
|
|
|
+
|
|
|
+ ret = indio_dev->info->read_avail(indio_dev, this_attr->c,
|
|
|
+ &vals, &type, &length,
|
|
|
+ this_attr->address);
|
|
|
+
|
|
|
+ if (ret < 0)
|
|
|
+ return ret;
|
|
|
+ switch (ret) {
|
|
|
+ case IIO_AVAIL_LIST:
|
|
|
+ return iio_format_avail_list(buf, vals, type, length);
|
|
|
+ case IIO_AVAIL_RANGE:
|
|
|
+ return iio_format_avail_range(buf, vals, type);
|
|
|
+ default:
|
|
|
+ return -EINVAL;
|
|
|
+ }
|
|
|
+}
|
|
|
+
|
|
|
/**
|
|
|
* iio_str_to_fixpoint() - Parse a fixed-point number from a string
|
|
|
* @str: The string to parse
|
|
|
@@ -980,6 +1109,40 @@ static int iio_device_add_info_mask_type(struct iio_dev *indio_dev,
|
|
|
return attrcount;
|
|
|
}
|
|
|
|
|
|
+static int iio_device_add_info_mask_type_avail(struct iio_dev *indio_dev,
|
|
|
+ struct iio_chan_spec const *chan,
|
|
|
+ enum iio_shared_by shared_by,
|
|
|
+ const long *infomask)
|
|
|
+{
|
|
|
+ int i, ret, attrcount = 0;
|
|
|
+ char *avail_postfix;
|
|
|
+
|
|
|
+ for_each_set_bit(i, infomask, sizeof(infomask) * 8) {
|
|
|
+ avail_postfix = kasprintf(GFP_KERNEL,
|
|
|
+ "%s_available",
|
|
|
+ iio_chan_info_postfix[i]);
|
|
|
+ if (!avail_postfix)
|
|
|
+ return -ENOMEM;
|
|
|
+
|
|
|
+ ret = __iio_add_chan_devattr(avail_postfix,
|
|
|
+ chan,
|
|
|
+ &iio_read_channel_info_avail,
|
|
|
+ NULL,
|
|
|
+ i,
|
|
|
+ shared_by,
|
|
|
+ &indio_dev->dev,
|
|
|
+ &indio_dev->channel_attr_list);
|
|
|
+ kfree(avail_postfix);
|
|
|
+ if ((ret == -EBUSY) && (shared_by != IIO_SEPARATE))
|
|
|
+ continue;
|
|
|
+ else if (ret < 0)
|
|
|
+ return ret;
|
|
|
+ attrcount++;
|
|
|
+ }
|
|
|
+
|
|
|
+ return attrcount;
|
|
|
+}
|
|
|
+
|
|
|
static int iio_device_add_channel_sysfs(struct iio_dev *indio_dev,
|
|
|
struct iio_chan_spec const *chan)
|
|
|
{
|
|
|
@@ -995,6 +1158,14 @@ static int iio_device_add_channel_sysfs(struct iio_dev *indio_dev,
|
|
|
return ret;
|
|
|
attrcount += ret;
|
|
|
|
|
|
+ ret = iio_device_add_info_mask_type_avail(indio_dev, chan,
|
|
|
+ IIO_SEPARATE,
|
|
|
+ &chan->
|
|
|
+ info_mask_separate_available);
|
|
|
+ if (ret < 0)
|
|
|
+ return ret;
|
|
|
+ attrcount += ret;
|
|
|
+
|
|
|
ret = iio_device_add_info_mask_type(indio_dev, chan,
|
|
|
IIO_SHARED_BY_TYPE,
|
|
|
&chan->info_mask_shared_by_type);
|
|
|
@@ -1002,6 +1173,14 @@ static int iio_device_add_channel_sysfs(struct iio_dev *indio_dev,
|
|
|
return ret;
|
|
|
attrcount += ret;
|
|
|
|
|
|
+ ret = iio_device_add_info_mask_type_avail(indio_dev, chan,
|
|
|
+ IIO_SHARED_BY_TYPE,
|
|
|
+ &chan->
|
|
|
+ info_mask_shared_by_type_available);
|
|
|
+ if (ret < 0)
|
|
|
+ return ret;
|
|
|
+ attrcount += ret;
|
|
|
+
|
|
|
ret = iio_device_add_info_mask_type(indio_dev, chan,
|
|
|
IIO_SHARED_BY_DIR,
|
|
|
&chan->info_mask_shared_by_dir);
|
|
|
@@ -1009,6 +1188,13 @@ static int iio_device_add_channel_sysfs(struct iio_dev *indio_dev,
|
|
|
return ret;
|
|
|
attrcount += ret;
|
|
|
|
|
|
+ ret = iio_device_add_info_mask_type_avail(indio_dev, chan,
|
|
|
+ IIO_SHARED_BY_DIR,
|
|
|
+ &chan->info_mask_shared_by_dir_available);
|
|
|
+ if (ret < 0)
|
|
|
+ return ret;
|
|
|
+ attrcount += ret;
|
|
|
+
|
|
|
ret = iio_device_add_info_mask_type(indio_dev, chan,
|
|
|
IIO_SHARED_BY_ALL,
|
|
|
&chan->info_mask_shared_by_all);
|
|
|
@@ -1016,6 +1202,13 @@ static int iio_device_add_channel_sysfs(struct iio_dev *indio_dev,
|
|
|
return ret;
|
|
|
attrcount += ret;
|
|
|
|
|
|
+ ret = iio_device_add_info_mask_type_avail(indio_dev, chan,
|
|
|
+ IIO_SHARED_BY_ALL,
|
|
|
+ &chan->info_mask_shared_by_all_available);
|
|
|
+ if (ret < 0)
|
|
|
+ return ret;
|
|
|
+ attrcount += ret;
|
|
|
+
|
|
|
if (chan->ext_info) {
|
|
|
unsigned int i = 0;
|
|
|
for (ext_info = chan->ext_info; ext_info->name; ext_info++) {
|