162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/* Industrialio buffer test code.
362306a36Sopenharmony_ci *
462306a36Sopenharmony_ci * Copyright (c) 2008 Jonathan Cameron
562306a36Sopenharmony_ci *
662306a36Sopenharmony_ci * This program is primarily intended as an example application.
762306a36Sopenharmony_ci * Reads the current buffer setup from sysfs and starts a short capture
862306a36Sopenharmony_ci * from the specified device, pretty printing the result after appropriate
962306a36Sopenharmony_ci * conversion.
1062306a36Sopenharmony_ci *
1162306a36Sopenharmony_ci * Command line parameters
1262306a36Sopenharmony_ci * generic_buffer -n <device_name> -t <trigger_name>
1362306a36Sopenharmony_ci * If trigger name is not specified the program assumes you want a dataready
1462306a36Sopenharmony_ci * trigger associated with the device and goes looking for it.
1562306a36Sopenharmony_ci */
1662306a36Sopenharmony_ci
1762306a36Sopenharmony_ci#include <unistd.h>
1862306a36Sopenharmony_ci#include <stdlib.h>
1962306a36Sopenharmony_ci#include <dirent.h>
2062306a36Sopenharmony_ci#include <fcntl.h>
2162306a36Sopenharmony_ci#include <stdio.h>
2262306a36Sopenharmony_ci#include <errno.h>
2362306a36Sopenharmony_ci#include <sys/stat.h>
2462306a36Sopenharmony_ci#include <sys/dir.h>
2562306a36Sopenharmony_ci#include <linux/types.h>
2662306a36Sopenharmony_ci#include <string.h>
2762306a36Sopenharmony_ci#include <poll.h>
2862306a36Sopenharmony_ci#include <endian.h>
2962306a36Sopenharmony_ci#include <getopt.h>
3062306a36Sopenharmony_ci#include <inttypes.h>
3162306a36Sopenharmony_ci#include <stdbool.h>
3262306a36Sopenharmony_ci#include <signal.h>
3362306a36Sopenharmony_ci#include <sys/ioctl.h>
3462306a36Sopenharmony_ci#include <linux/iio/buffer.h>
3562306a36Sopenharmony_ci#include "iio_utils.h"
3662306a36Sopenharmony_ci
3762306a36Sopenharmony_ci/**
3862306a36Sopenharmony_ci * enum autochan - state for the automatic channel enabling mechanism
3962306a36Sopenharmony_ci */
4062306a36Sopenharmony_cienum autochan {
4162306a36Sopenharmony_ci	AUTOCHANNELS_DISABLED,
4262306a36Sopenharmony_ci	AUTOCHANNELS_ENABLED,
4362306a36Sopenharmony_ci	AUTOCHANNELS_ACTIVE,
4462306a36Sopenharmony_ci};
4562306a36Sopenharmony_ci
4662306a36Sopenharmony_ci/**
4762306a36Sopenharmony_ci * size_from_channelarray() - calculate the storage size of a scan
4862306a36Sopenharmony_ci * @channels:		the channel info array
4962306a36Sopenharmony_ci * @num_channels:	number of channels
5062306a36Sopenharmony_ci *
5162306a36Sopenharmony_ci * Has the side effect of filling the channels[i].location values used
5262306a36Sopenharmony_ci * in processing the buffer output.
5362306a36Sopenharmony_ci **/
5462306a36Sopenharmony_cistatic unsigned int size_from_channelarray(struct iio_channel_info *channels, int num_channels)
5562306a36Sopenharmony_ci{
5662306a36Sopenharmony_ci	unsigned int bytes = 0;
5762306a36Sopenharmony_ci	int i = 0, max = 0;
5862306a36Sopenharmony_ci	unsigned int misalignment;
5962306a36Sopenharmony_ci
6062306a36Sopenharmony_ci	while (i < num_channels) {
6162306a36Sopenharmony_ci		if (channels[i].bytes > max)
6262306a36Sopenharmony_ci			max = channels[i].bytes;
6362306a36Sopenharmony_ci		if (bytes % channels[i].bytes == 0)
6462306a36Sopenharmony_ci			channels[i].location = bytes;
6562306a36Sopenharmony_ci		else
6662306a36Sopenharmony_ci			channels[i].location = bytes - bytes % channels[i].bytes
6762306a36Sopenharmony_ci					       + channels[i].bytes;
6862306a36Sopenharmony_ci
6962306a36Sopenharmony_ci		bytes = channels[i].location + channels[i].bytes;
7062306a36Sopenharmony_ci		i++;
7162306a36Sopenharmony_ci	}
7262306a36Sopenharmony_ci	/*
7362306a36Sopenharmony_ci	 * We want the data in next sample to also be properly aligned so
7462306a36Sopenharmony_ci	 * we'll add padding at the end if needed. Adding padding only
7562306a36Sopenharmony_ci	 * works for channel data which size is 2^n bytes.
7662306a36Sopenharmony_ci	 */
7762306a36Sopenharmony_ci	misalignment = bytes % max;
7862306a36Sopenharmony_ci	if (misalignment)
7962306a36Sopenharmony_ci		bytes += max - misalignment;
8062306a36Sopenharmony_ci
8162306a36Sopenharmony_ci	return bytes;
8262306a36Sopenharmony_ci}
8362306a36Sopenharmony_ci
8462306a36Sopenharmony_cistatic void print1byte(uint8_t input, struct iio_channel_info *info)
8562306a36Sopenharmony_ci{
8662306a36Sopenharmony_ci	/*
8762306a36Sopenharmony_ci	 * Shift before conversion to avoid sign extension
8862306a36Sopenharmony_ci	 * of left aligned data
8962306a36Sopenharmony_ci	 */
9062306a36Sopenharmony_ci	input >>= info->shift;
9162306a36Sopenharmony_ci	input &= info->mask;
9262306a36Sopenharmony_ci	if (info->is_signed) {
9362306a36Sopenharmony_ci		int8_t val = (int8_t)(input << (8 - info->bits_used)) >>
9462306a36Sopenharmony_ci			     (8 - info->bits_used);
9562306a36Sopenharmony_ci		printf("%05f ", ((float)val + info->offset) * info->scale);
9662306a36Sopenharmony_ci	} else {
9762306a36Sopenharmony_ci		printf("%05f ", ((float)input + info->offset) * info->scale);
9862306a36Sopenharmony_ci	}
9962306a36Sopenharmony_ci}
10062306a36Sopenharmony_ci
10162306a36Sopenharmony_cistatic void print2byte(uint16_t input, struct iio_channel_info *info)
10262306a36Sopenharmony_ci{
10362306a36Sopenharmony_ci	/* First swap if incorrect endian */
10462306a36Sopenharmony_ci	if (info->be)
10562306a36Sopenharmony_ci		input = be16toh(input);
10662306a36Sopenharmony_ci	else
10762306a36Sopenharmony_ci		input = le16toh(input);
10862306a36Sopenharmony_ci
10962306a36Sopenharmony_ci	/*
11062306a36Sopenharmony_ci	 * Shift before conversion to avoid sign extension
11162306a36Sopenharmony_ci	 * of left aligned data
11262306a36Sopenharmony_ci	 */
11362306a36Sopenharmony_ci	input >>= info->shift;
11462306a36Sopenharmony_ci	input &= info->mask;
11562306a36Sopenharmony_ci	if (info->is_signed) {
11662306a36Sopenharmony_ci		int16_t val = (int16_t)(input << (16 - info->bits_used)) >>
11762306a36Sopenharmony_ci			      (16 - info->bits_used);
11862306a36Sopenharmony_ci		printf("%05f ", ((float)val + info->offset) * info->scale);
11962306a36Sopenharmony_ci	} else {
12062306a36Sopenharmony_ci		printf("%05f ", ((float)input + info->offset) * info->scale);
12162306a36Sopenharmony_ci	}
12262306a36Sopenharmony_ci}
12362306a36Sopenharmony_ci
12462306a36Sopenharmony_cistatic void print4byte(uint32_t input, struct iio_channel_info *info)
12562306a36Sopenharmony_ci{
12662306a36Sopenharmony_ci	/* First swap if incorrect endian */
12762306a36Sopenharmony_ci	if (info->be)
12862306a36Sopenharmony_ci		input = be32toh(input);
12962306a36Sopenharmony_ci	else
13062306a36Sopenharmony_ci		input = le32toh(input);
13162306a36Sopenharmony_ci
13262306a36Sopenharmony_ci	/*
13362306a36Sopenharmony_ci	 * Shift before conversion to avoid sign extension
13462306a36Sopenharmony_ci	 * of left aligned data
13562306a36Sopenharmony_ci	 */
13662306a36Sopenharmony_ci	input >>= info->shift;
13762306a36Sopenharmony_ci	input &= info->mask;
13862306a36Sopenharmony_ci	if (info->is_signed) {
13962306a36Sopenharmony_ci		int32_t val = (int32_t)(input << (32 - info->bits_used)) >>
14062306a36Sopenharmony_ci			      (32 - info->bits_used);
14162306a36Sopenharmony_ci		printf("%05f ", ((float)val + info->offset) * info->scale);
14262306a36Sopenharmony_ci	} else {
14362306a36Sopenharmony_ci		printf("%05f ", ((float)input + info->offset) * info->scale);
14462306a36Sopenharmony_ci	}
14562306a36Sopenharmony_ci}
14662306a36Sopenharmony_ci
14762306a36Sopenharmony_cistatic void print8byte(uint64_t input, struct iio_channel_info *info)
14862306a36Sopenharmony_ci{
14962306a36Sopenharmony_ci	/* First swap if incorrect endian */
15062306a36Sopenharmony_ci	if (info->be)
15162306a36Sopenharmony_ci		input = be64toh(input);
15262306a36Sopenharmony_ci	else
15362306a36Sopenharmony_ci		input = le64toh(input);
15462306a36Sopenharmony_ci
15562306a36Sopenharmony_ci	/*
15662306a36Sopenharmony_ci	 * Shift before conversion to avoid sign extension
15762306a36Sopenharmony_ci	 * of left aligned data
15862306a36Sopenharmony_ci	 */
15962306a36Sopenharmony_ci	input >>= info->shift;
16062306a36Sopenharmony_ci	input &= info->mask;
16162306a36Sopenharmony_ci	if (info->is_signed) {
16262306a36Sopenharmony_ci		int64_t val = (int64_t)(input << (64 - info->bits_used)) >>
16362306a36Sopenharmony_ci			      (64 - info->bits_used);
16462306a36Sopenharmony_ci		/* special case for timestamp */
16562306a36Sopenharmony_ci		if (info->scale == 1.0f && info->offset == 0.0f)
16662306a36Sopenharmony_ci			printf("%" PRId64 " ", val);
16762306a36Sopenharmony_ci		else
16862306a36Sopenharmony_ci			printf("%05f ",
16962306a36Sopenharmony_ci			       ((float)val + info->offset) * info->scale);
17062306a36Sopenharmony_ci	} else {
17162306a36Sopenharmony_ci		printf("%05f ", ((float)input + info->offset) * info->scale);
17262306a36Sopenharmony_ci	}
17362306a36Sopenharmony_ci}
17462306a36Sopenharmony_ci
17562306a36Sopenharmony_ci/**
17662306a36Sopenharmony_ci * process_scan() - print out the values in SI units
17762306a36Sopenharmony_ci * @data:		pointer to the start of the scan
17862306a36Sopenharmony_ci * @channels:		information about the channels.
17962306a36Sopenharmony_ci *			Note: size_from_channelarray must have been called first
18062306a36Sopenharmony_ci *			      to fill the location offsets.
18162306a36Sopenharmony_ci * @num_channels:	number of channels
18262306a36Sopenharmony_ci **/
18362306a36Sopenharmony_cistatic void process_scan(char *data, struct iio_channel_info *channels,
18462306a36Sopenharmony_ci			 int num_channels)
18562306a36Sopenharmony_ci{
18662306a36Sopenharmony_ci	int k;
18762306a36Sopenharmony_ci
18862306a36Sopenharmony_ci	for (k = 0; k < num_channels; k++)
18962306a36Sopenharmony_ci		switch (channels[k].bytes) {
19062306a36Sopenharmony_ci			/* only a few cases implemented so far */
19162306a36Sopenharmony_ci		case 1:
19262306a36Sopenharmony_ci			print1byte(*(uint8_t *)(data + channels[k].location),
19362306a36Sopenharmony_ci				   &channels[k]);
19462306a36Sopenharmony_ci			break;
19562306a36Sopenharmony_ci		case 2:
19662306a36Sopenharmony_ci			print2byte(*(uint16_t *)(data + channels[k].location),
19762306a36Sopenharmony_ci				   &channels[k]);
19862306a36Sopenharmony_ci			break;
19962306a36Sopenharmony_ci		case 4:
20062306a36Sopenharmony_ci			print4byte(*(uint32_t *)(data + channels[k].location),
20162306a36Sopenharmony_ci				   &channels[k]);
20262306a36Sopenharmony_ci			break;
20362306a36Sopenharmony_ci		case 8:
20462306a36Sopenharmony_ci			print8byte(*(uint64_t *)(data + channels[k].location),
20562306a36Sopenharmony_ci				   &channels[k]);
20662306a36Sopenharmony_ci			break;
20762306a36Sopenharmony_ci		default:
20862306a36Sopenharmony_ci			break;
20962306a36Sopenharmony_ci		}
21062306a36Sopenharmony_ci	printf("\n");
21162306a36Sopenharmony_ci}
21262306a36Sopenharmony_ci
21362306a36Sopenharmony_cistatic int enable_disable_all_channels(char *dev_dir_name, int buffer_idx, int enable)
21462306a36Sopenharmony_ci{
21562306a36Sopenharmony_ci	const struct dirent *ent;
21662306a36Sopenharmony_ci	char scanelemdir[256];
21762306a36Sopenharmony_ci	DIR *dp;
21862306a36Sopenharmony_ci	int ret;
21962306a36Sopenharmony_ci
22062306a36Sopenharmony_ci	snprintf(scanelemdir, sizeof(scanelemdir),
22162306a36Sopenharmony_ci		 FORMAT_SCAN_ELEMENTS_DIR, dev_dir_name, buffer_idx);
22262306a36Sopenharmony_ci	scanelemdir[sizeof(scanelemdir)-1] = '\0';
22362306a36Sopenharmony_ci
22462306a36Sopenharmony_ci	dp = opendir(scanelemdir);
22562306a36Sopenharmony_ci	if (!dp) {
22662306a36Sopenharmony_ci		fprintf(stderr, "Enabling/disabling channels: can't open %s\n",
22762306a36Sopenharmony_ci			scanelemdir);
22862306a36Sopenharmony_ci		return -EIO;
22962306a36Sopenharmony_ci	}
23062306a36Sopenharmony_ci
23162306a36Sopenharmony_ci	ret = -ENOENT;
23262306a36Sopenharmony_ci	while (ent = readdir(dp), ent) {
23362306a36Sopenharmony_ci		if (iioutils_check_suffix(ent->d_name, "_en")) {
23462306a36Sopenharmony_ci			printf("%sabling: %s\n",
23562306a36Sopenharmony_ci			       enable ? "En" : "Dis",
23662306a36Sopenharmony_ci			       ent->d_name);
23762306a36Sopenharmony_ci			ret = write_sysfs_int(ent->d_name, scanelemdir,
23862306a36Sopenharmony_ci					      enable);
23962306a36Sopenharmony_ci			if (ret < 0)
24062306a36Sopenharmony_ci				fprintf(stderr, "Failed to enable/disable %s\n",
24162306a36Sopenharmony_ci					ent->d_name);
24262306a36Sopenharmony_ci		}
24362306a36Sopenharmony_ci	}
24462306a36Sopenharmony_ci
24562306a36Sopenharmony_ci	if (closedir(dp) == -1) {
24662306a36Sopenharmony_ci		perror("Enabling/disabling channels: "
24762306a36Sopenharmony_ci		       "Failed to close directory");
24862306a36Sopenharmony_ci		return -errno;
24962306a36Sopenharmony_ci	}
25062306a36Sopenharmony_ci	return 0;
25162306a36Sopenharmony_ci}
25262306a36Sopenharmony_ci
25362306a36Sopenharmony_cistatic void print_usage(void)
25462306a36Sopenharmony_ci{
25562306a36Sopenharmony_ci	fprintf(stderr, "Usage: generic_buffer [options]...\n"
25662306a36Sopenharmony_ci		"Capture, convert and output data from IIO device buffer\n"
25762306a36Sopenharmony_ci		"  -a         Auto-activate all available channels\n"
25862306a36Sopenharmony_ci		"  -A         Force-activate ALL channels\n"
25962306a36Sopenharmony_ci		"  -b <n>     The buffer which to open (by index), default 0\n"
26062306a36Sopenharmony_ci		"  -c <n>     Do n conversions, or loop forever if n < 0\n"
26162306a36Sopenharmony_ci		"  -e         Disable wait for event (new data)\n"
26262306a36Sopenharmony_ci		"  -g         Use trigger-less mode\n"
26362306a36Sopenharmony_ci		"  -l <n>     Set buffer length to n samples\n"
26462306a36Sopenharmony_ci		"  --device-name -n <name>\n"
26562306a36Sopenharmony_ci		"  --device-num -N <num>\n"
26662306a36Sopenharmony_ci		"        Set device by name or number (mandatory)\n"
26762306a36Sopenharmony_ci		"  --trigger-name -t <name>\n"
26862306a36Sopenharmony_ci		"  --trigger-num -T <num>\n"
26962306a36Sopenharmony_ci		"        Set trigger by name or number\n"
27062306a36Sopenharmony_ci		"  -w <n>     Set delay between reads in us (event-less mode)\n");
27162306a36Sopenharmony_ci}
27262306a36Sopenharmony_ci
27362306a36Sopenharmony_cistatic enum autochan autochannels = AUTOCHANNELS_DISABLED;
27462306a36Sopenharmony_cistatic char *dev_dir_name = NULL;
27562306a36Sopenharmony_cistatic char *buf_dir_name = NULL;
27662306a36Sopenharmony_cistatic int buffer_idx = 0;
27762306a36Sopenharmony_cistatic bool current_trigger_set = false;
27862306a36Sopenharmony_ci
27962306a36Sopenharmony_cistatic void cleanup(void)
28062306a36Sopenharmony_ci{
28162306a36Sopenharmony_ci	int ret;
28262306a36Sopenharmony_ci
28362306a36Sopenharmony_ci	/* Disable trigger */
28462306a36Sopenharmony_ci	if (dev_dir_name && current_trigger_set) {
28562306a36Sopenharmony_ci		/* Disconnect the trigger - just write a dummy name. */
28662306a36Sopenharmony_ci		ret = write_sysfs_string("trigger/current_trigger",
28762306a36Sopenharmony_ci					 dev_dir_name, "NULL");
28862306a36Sopenharmony_ci		if (ret < 0)
28962306a36Sopenharmony_ci			fprintf(stderr, "Failed to disable trigger: %s\n",
29062306a36Sopenharmony_ci				strerror(-ret));
29162306a36Sopenharmony_ci		current_trigger_set = false;
29262306a36Sopenharmony_ci	}
29362306a36Sopenharmony_ci
29462306a36Sopenharmony_ci	/* Disable buffer */
29562306a36Sopenharmony_ci	if (buf_dir_name) {
29662306a36Sopenharmony_ci		ret = write_sysfs_int("enable", buf_dir_name, 0);
29762306a36Sopenharmony_ci		if (ret < 0)
29862306a36Sopenharmony_ci			fprintf(stderr, "Failed to disable buffer: %s\n",
29962306a36Sopenharmony_ci				strerror(-ret));
30062306a36Sopenharmony_ci	}
30162306a36Sopenharmony_ci
30262306a36Sopenharmony_ci	/* Disable channels if auto-enabled */
30362306a36Sopenharmony_ci	if (dev_dir_name && autochannels == AUTOCHANNELS_ACTIVE) {
30462306a36Sopenharmony_ci		ret = enable_disable_all_channels(dev_dir_name, buffer_idx, 0);
30562306a36Sopenharmony_ci		if (ret)
30662306a36Sopenharmony_ci			fprintf(stderr, "Failed to disable all channels\n");
30762306a36Sopenharmony_ci		autochannels = AUTOCHANNELS_DISABLED;
30862306a36Sopenharmony_ci	}
30962306a36Sopenharmony_ci}
31062306a36Sopenharmony_ci
31162306a36Sopenharmony_cistatic void sig_handler(int signum)
31262306a36Sopenharmony_ci{
31362306a36Sopenharmony_ci	fprintf(stderr, "Caught signal %d\n", signum);
31462306a36Sopenharmony_ci	cleanup();
31562306a36Sopenharmony_ci	exit(-signum);
31662306a36Sopenharmony_ci}
31762306a36Sopenharmony_ci
31862306a36Sopenharmony_cistatic void register_cleanup(void)
31962306a36Sopenharmony_ci{
32062306a36Sopenharmony_ci	struct sigaction sa = { .sa_handler = sig_handler };
32162306a36Sopenharmony_ci	const int signums[] = { SIGINT, SIGTERM, SIGABRT };
32262306a36Sopenharmony_ci	int ret, i;
32362306a36Sopenharmony_ci
32462306a36Sopenharmony_ci	for (i = 0; i < ARRAY_SIZE(signums); ++i) {
32562306a36Sopenharmony_ci		ret = sigaction(signums[i], &sa, NULL);
32662306a36Sopenharmony_ci		if (ret) {
32762306a36Sopenharmony_ci			perror("Failed to register signal handler");
32862306a36Sopenharmony_ci			exit(-1);
32962306a36Sopenharmony_ci		}
33062306a36Sopenharmony_ci	}
33162306a36Sopenharmony_ci}
33262306a36Sopenharmony_ci
33362306a36Sopenharmony_cistatic const struct option longopts[] = {
33462306a36Sopenharmony_ci	{ "device-name",	1, 0, 'n' },
33562306a36Sopenharmony_ci	{ "device-num",		1, 0, 'N' },
33662306a36Sopenharmony_ci	{ "trigger-name",	1, 0, 't' },
33762306a36Sopenharmony_ci	{ "trigger-num",	1, 0, 'T' },
33862306a36Sopenharmony_ci	{ },
33962306a36Sopenharmony_ci};
34062306a36Sopenharmony_ci
34162306a36Sopenharmony_ciint main(int argc, char **argv)
34262306a36Sopenharmony_ci{
34362306a36Sopenharmony_ci	long long num_loops = 2;
34462306a36Sopenharmony_ci	unsigned long timedelay = 1000000;
34562306a36Sopenharmony_ci	unsigned long buf_len = 128;
34662306a36Sopenharmony_ci
34762306a36Sopenharmony_ci	ssize_t i;
34862306a36Sopenharmony_ci	unsigned long long j;
34962306a36Sopenharmony_ci	unsigned long toread;
35062306a36Sopenharmony_ci	int ret, c;
35162306a36Sopenharmony_ci	struct stat st;
35262306a36Sopenharmony_ci	int fd = -1;
35362306a36Sopenharmony_ci	int buf_fd = -1;
35462306a36Sopenharmony_ci
35562306a36Sopenharmony_ci	int num_channels = 0;
35662306a36Sopenharmony_ci	char *trigger_name = NULL, *device_name = NULL;
35762306a36Sopenharmony_ci
35862306a36Sopenharmony_ci	char *data = NULL;
35962306a36Sopenharmony_ci	ssize_t read_size;
36062306a36Sopenharmony_ci	int dev_num = -1, trig_num = -1;
36162306a36Sopenharmony_ci	char *buffer_access = NULL;
36262306a36Sopenharmony_ci	unsigned int scan_size;
36362306a36Sopenharmony_ci	int noevents = 0;
36462306a36Sopenharmony_ci	int notrigger = 0;
36562306a36Sopenharmony_ci	char *dummy;
36662306a36Sopenharmony_ci	bool force_autochannels = false;
36762306a36Sopenharmony_ci
36862306a36Sopenharmony_ci	struct iio_channel_info *channels = NULL;
36962306a36Sopenharmony_ci
37062306a36Sopenharmony_ci	register_cleanup();
37162306a36Sopenharmony_ci
37262306a36Sopenharmony_ci	while ((c = getopt_long(argc, argv, "aAb:c:egl:n:N:t:T:w:?", longopts,
37362306a36Sopenharmony_ci				NULL)) != -1) {
37462306a36Sopenharmony_ci		switch (c) {
37562306a36Sopenharmony_ci		case 'a':
37662306a36Sopenharmony_ci			autochannels = AUTOCHANNELS_ENABLED;
37762306a36Sopenharmony_ci			break;
37862306a36Sopenharmony_ci		case 'A':
37962306a36Sopenharmony_ci			autochannels = AUTOCHANNELS_ENABLED;
38062306a36Sopenharmony_ci			force_autochannels = true;
38162306a36Sopenharmony_ci			break;
38262306a36Sopenharmony_ci		case 'b':
38362306a36Sopenharmony_ci			errno = 0;
38462306a36Sopenharmony_ci			buffer_idx = strtoll(optarg, &dummy, 10);
38562306a36Sopenharmony_ci			if (errno) {
38662306a36Sopenharmony_ci				ret = -errno;
38762306a36Sopenharmony_ci				goto error;
38862306a36Sopenharmony_ci			}
38962306a36Sopenharmony_ci			if (buffer_idx < 0) {
39062306a36Sopenharmony_ci				ret = -ERANGE;
39162306a36Sopenharmony_ci				goto error;
39262306a36Sopenharmony_ci			}
39362306a36Sopenharmony_ci
39462306a36Sopenharmony_ci			break;
39562306a36Sopenharmony_ci		case 'c':
39662306a36Sopenharmony_ci			errno = 0;
39762306a36Sopenharmony_ci			num_loops = strtoll(optarg, &dummy, 10);
39862306a36Sopenharmony_ci			if (errno) {
39962306a36Sopenharmony_ci				ret = -errno;
40062306a36Sopenharmony_ci				goto error;
40162306a36Sopenharmony_ci			}
40262306a36Sopenharmony_ci
40362306a36Sopenharmony_ci			break;
40462306a36Sopenharmony_ci		case 'e':
40562306a36Sopenharmony_ci			noevents = 1;
40662306a36Sopenharmony_ci			break;
40762306a36Sopenharmony_ci		case 'g':
40862306a36Sopenharmony_ci			notrigger = 1;
40962306a36Sopenharmony_ci			break;
41062306a36Sopenharmony_ci		case 'l':
41162306a36Sopenharmony_ci			errno = 0;
41262306a36Sopenharmony_ci			buf_len = strtoul(optarg, &dummy, 10);
41362306a36Sopenharmony_ci			if (errno) {
41462306a36Sopenharmony_ci				ret = -errno;
41562306a36Sopenharmony_ci				goto error;
41662306a36Sopenharmony_ci			}
41762306a36Sopenharmony_ci
41862306a36Sopenharmony_ci			break;
41962306a36Sopenharmony_ci		case 'n':
42062306a36Sopenharmony_ci			device_name = strdup(optarg);
42162306a36Sopenharmony_ci			break;
42262306a36Sopenharmony_ci		case 'N':
42362306a36Sopenharmony_ci			errno = 0;
42462306a36Sopenharmony_ci			dev_num = strtoul(optarg, &dummy, 10);
42562306a36Sopenharmony_ci			if (errno) {
42662306a36Sopenharmony_ci				ret = -errno;
42762306a36Sopenharmony_ci				goto error;
42862306a36Sopenharmony_ci			}
42962306a36Sopenharmony_ci			break;
43062306a36Sopenharmony_ci		case 't':
43162306a36Sopenharmony_ci			trigger_name = strdup(optarg);
43262306a36Sopenharmony_ci			break;
43362306a36Sopenharmony_ci		case 'T':
43462306a36Sopenharmony_ci			errno = 0;
43562306a36Sopenharmony_ci			trig_num = strtoul(optarg, &dummy, 10);
43662306a36Sopenharmony_ci			if (errno)
43762306a36Sopenharmony_ci				return -errno;
43862306a36Sopenharmony_ci			break;
43962306a36Sopenharmony_ci		case 'w':
44062306a36Sopenharmony_ci			errno = 0;
44162306a36Sopenharmony_ci			timedelay = strtoul(optarg, &dummy, 10);
44262306a36Sopenharmony_ci			if (errno) {
44362306a36Sopenharmony_ci				ret = -errno;
44462306a36Sopenharmony_ci				goto error;
44562306a36Sopenharmony_ci			}
44662306a36Sopenharmony_ci			break;
44762306a36Sopenharmony_ci		case '?':
44862306a36Sopenharmony_ci			print_usage();
44962306a36Sopenharmony_ci			ret = -1;
45062306a36Sopenharmony_ci			goto error;
45162306a36Sopenharmony_ci		}
45262306a36Sopenharmony_ci	}
45362306a36Sopenharmony_ci
45462306a36Sopenharmony_ci	/* Find the device requested */
45562306a36Sopenharmony_ci	if (dev_num < 0 && !device_name) {
45662306a36Sopenharmony_ci		fprintf(stderr, "Device not set\n");
45762306a36Sopenharmony_ci		print_usage();
45862306a36Sopenharmony_ci		ret = -1;
45962306a36Sopenharmony_ci		goto error;
46062306a36Sopenharmony_ci	} else if (dev_num >= 0 && device_name) {
46162306a36Sopenharmony_ci		fprintf(stderr, "Only one of --device-num or --device-name needs to be set\n");
46262306a36Sopenharmony_ci		print_usage();
46362306a36Sopenharmony_ci		ret = -1;
46462306a36Sopenharmony_ci		goto error;
46562306a36Sopenharmony_ci	} else if (dev_num < 0) {
46662306a36Sopenharmony_ci		dev_num = find_type_by_name(device_name, "iio:device");
46762306a36Sopenharmony_ci		if (dev_num < 0) {
46862306a36Sopenharmony_ci			fprintf(stderr, "Failed to find the %s\n", device_name);
46962306a36Sopenharmony_ci			ret = dev_num;
47062306a36Sopenharmony_ci			goto error;
47162306a36Sopenharmony_ci		}
47262306a36Sopenharmony_ci	}
47362306a36Sopenharmony_ci	printf("iio device number being used is %d\n", dev_num);
47462306a36Sopenharmony_ci
47562306a36Sopenharmony_ci	ret = asprintf(&dev_dir_name, "%siio:device%d", iio_dir, dev_num);
47662306a36Sopenharmony_ci	if (ret < 0)
47762306a36Sopenharmony_ci		return -ENOMEM;
47862306a36Sopenharmony_ci	/* Fetch device_name if specified by number */
47962306a36Sopenharmony_ci	if (!device_name) {
48062306a36Sopenharmony_ci		device_name = malloc(IIO_MAX_NAME_LENGTH);
48162306a36Sopenharmony_ci		if (!device_name) {
48262306a36Sopenharmony_ci			ret = -ENOMEM;
48362306a36Sopenharmony_ci			goto error;
48462306a36Sopenharmony_ci		}
48562306a36Sopenharmony_ci		ret = read_sysfs_string("name", dev_dir_name, device_name);
48662306a36Sopenharmony_ci		if (ret < 0) {
48762306a36Sopenharmony_ci			fprintf(stderr, "Failed to read name of device %d\n", dev_num);
48862306a36Sopenharmony_ci			goto error;
48962306a36Sopenharmony_ci		}
49062306a36Sopenharmony_ci	}
49162306a36Sopenharmony_ci
49262306a36Sopenharmony_ci	if (notrigger) {
49362306a36Sopenharmony_ci		printf("trigger-less mode selected\n");
49462306a36Sopenharmony_ci	} else if (trig_num >= 0) {
49562306a36Sopenharmony_ci		char *trig_dev_name;
49662306a36Sopenharmony_ci		ret = asprintf(&trig_dev_name, "%strigger%d", iio_dir, trig_num);
49762306a36Sopenharmony_ci		if (ret < 0) {
49862306a36Sopenharmony_ci			return -ENOMEM;
49962306a36Sopenharmony_ci		}
50062306a36Sopenharmony_ci		trigger_name = malloc(IIO_MAX_NAME_LENGTH);
50162306a36Sopenharmony_ci		ret = read_sysfs_string("name", trig_dev_name, trigger_name);
50262306a36Sopenharmony_ci		free(trig_dev_name);
50362306a36Sopenharmony_ci		if (ret < 0) {
50462306a36Sopenharmony_ci			fprintf(stderr, "Failed to read trigger%d name from\n", trig_num);
50562306a36Sopenharmony_ci			return ret;
50662306a36Sopenharmony_ci		}
50762306a36Sopenharmony_ci		printf("iio trigger number being used is %d\n", trig_num);
50862306a36Sopenharmony_ci	} else {
50962306a36Sopenharmony_ci		if (!trigger_name) {
51062306a36Sopenharmony_ci			/*
51162306a36Sopenharmony_ci			 * Build the trigger name. If it is device associated
51262306a36Sopenharmony_ci			 * its name is <device_name>_dev[n] where n matches
51362306a36Sopenharmony_ci			 * the device number found above.
51462306a36Sopenharmony_ci			 */
51562306a36Sopenharmony_ci			ret = asprintf(&trigger_name,
51662306a36Sopenharmony_ci				       "%s-dev%d", device_name, dev_num);
51762306a36Sopenharmony_ci			if (ret < 0) {
51862306a36Sopenharmony_ci				ret = -ENOMEM;
51962306a36Sopenharmony_ci				goto error;
52062306a36Sopenharmony_ci			}
52162306a36Sopenharmony_ci		}
52262306a36Sopenharmony_ci
52362306a36Sopenharmony_ci		/* Look for this "-devN" trigger */
52462306a36Sopenharmony_ci		trig_num = find_type_by_name(trigger_name, "trigger");
52562306a36Sopenharmony_ci		if (trig_num < 0) {
52662306a36Sopenharmony_ci			/* OK try the simpler "-trigger" suffix instead */
52762306a36Sopenharmony_ci			free(trigger_name);
52862306a36Sopenharmony_ci			ret = asprintf(&trigger_name,
52962306a36Sopenharmony_ci				       "%s-trigger", device_name);
53062306a36Sopenharmony_ci			if (ret < 0) {
53162306a36Sopenharmony_ci				ret = -ENOMEM;
53262306a36Sopenharmony_ci				goto error;
53362306a36Sopenharmony_ci			}
53462306a36Sopenharmony_ci		}
53562306a36Sopenharmony_ci
53662306a36Sopenharmony_ci		trig_num = find_type_by_name(trigger_name, "trigger");
53762306a36Sopenharmony_ci		if (trig_num < 0) {
53862306a36Sopenharmony_ci			fprintf(stderr, "Failed to find the trigger %s\n",
53962306a36Sopenharmony_ci				trigger_name);
54062306a36Sopenharmony_ci			ret = trig_num;
54162306a36Sopenharmony_ci			goto error;
54262306a36Sopenharmony_ci		}
54362306a36Sopenharmony_ci
54462306a36Sopenharmony_ci		printf("iio trigger number being used is %d\n", trig_num);
54562306a36Sopenharmony_ci	}
54662306a36Sopenharmony_ci
54762306a36Sopenharmony_ci	/*
54862306a36Sopenharmony_ci	 * Parse the files in scan_elements to identify what channels are
54962306a36Sopenharmony_ci	 * present
55062306a36Sopenharmony_ci	 */
55162306a36Sopenharmony_ci	ret = build_channel_array(dev_dir_name, buffer_idx, &channels, &num_channels);
55262306a36Sopenharmony_ci	if (ret) {
55362306a36Sopenharmony_ci		fprintf(stderr, "Problem reading scan element information\n"
55462306a36Sopenharmony_ci			"diag %s\n", dev_dir_name);
55562306a36Sopenharmony_ci		goto error;
55662306a36Sopenharmony_ci	}
55762306a36Sopenharmony_ci	if (num_channels && autochannels == AUTOCHANNELS_ENABLED &&
55862306a36Sopenharmony_ci	    !force_autochannels) {
55962306a36Sopenharmony_ci		fprintf(stderr, "Auto-channels selected but some channels "
56062306a36Sopenharmony_ci			"are already activated in sysfs\n");
56162306a36Sopenharmony_ci		fprintf(stderr, "Proceeding without activating any channels\n");
56262306a36Sopenharmony_ci	}
56362306a36Sopenharmony_ci
56462306a36Sopenharmony_ci	if ((!num_channels && autochannels == AUTOCHANNELS_ENABLED) ||
56562306a36Sopenharmony_ci	    (autochannels == AUTOCHANNELS_ENABLED && force_autochannels)) {
56662306a36Sopenharmony_ci		fprintf(stderr, "Enabling all channels\n");
56762306a36Sopenharmony_ci
56862306a36Sopenharmony_ci		ret = enable_disable_all_channels(dev_dir_name, buffer_idx, 1);
56962306a36Sopenharmony_ci		if (ret) {
57062306a36Sopenharmony_ci			fprintf(stderr, "Failed to enable all channels\n");
57162306a36Sopenharmony_ci			goto error;
57262306a36Sopenharmony_ci		}
57362306a36Sopenharmony_ci
57462306a36Sopenharmony_ci		/* This flags that we need to disable the channels again */
57562306a36Sopenharmony_ci		autochannels = AUTOCHANNELS_ACTIVE;
57662306a36Sopenharmony_ci
57762306a36Sopenharmony_ci		ret = build_channel_array(dev_dir_name, buffer_idx, &channels,
57862306a36Sopenharmony_ci					  &num_channels);
57962306a36Sopenharmony_ci		if (ret) {
58062306a36Sopenharmony_ci			fprintf(stderr, "Problem reading scan element "
58162306a36Sopenharmony_ci				"information\n"
58262306a36Sopenharmony_ci				"diag %s\n", dev_dir_name);
58362306a36Sopenharmony_ci			goto error;
58462306a36Sopenharmony_ci		}
58562306a36Sopenharmony_ci		if (!num_channels) {
58662306a36Sopenharmony_ci			fprintf(stderr, "Still no channels after "
58762306a36Sopenharmony_ci				"auto-enabling, giving up\n");
58862306a36Sopenharmony_ci			goto error;
58962306a36Sopenharmony_ci		}
59062306a36Sopenharmony_ci	}
59162306a36Sopenharmony_ci
59262306a36Sopenharmony_ci	if (!num_channels && autochannels == AUTOCHANNELS_DISABLED) {
59362306a36Sopenharmony_ci		fprintf(stderr,
59462306a36Sopenharmony_ci			"No channels are enabled, we have nothing to scan.\n");
59562306a36Sopenharmony_ci		fprintf(stderr, "Enable channels manually in "
59662306a36Sopenharmony_ci			FORMAT_SCAN_ELEMENTS_DIR
59762306a36Sopenharmony_ci			"/*_en or pass -a to autoenable channels and "
59862306a36Sopenharmony_ci			"try again.\n", dev_dir_name, buffer_idx);
59962306a36Sopenharmony_ci		ret = -ENOENT;
60062306a36Sopenharmony_ci		goto error;
60162306a36Sopenharmony_ci	}
60262306a36Sopenharmony_ci
60362306a36Sopenharmony_ci	/*
60462306a36Sopenharmony_ci	 * Construct the directory name for the associated buffer.
60562306a36Sopenharmony_ci	 * As we know that the lis3l02dq has only one buffer this may
60662306a36Sopenharmony_ci	 * be built rather than found.
60762306a36Sopenharmony_ci	 */
60862306a36Sopenharmony_ci	ret = asprintf(&buf_dir_name,
60962306a36Sopenharmony_ci		       "%siio:device%d/buffer%d", iio_dir, dev_num, buffer_idx);
61062306a36Sopenharmony_ci	if (ret < 0) {
61162306a36Sopenharmony_ci		ret = -ENOMEM;
61262306a36Sopenharmony_ci		goto error;
61362306a36Sopenharmony_ci	}
61462306a36Sopenharmony_ci
61562306a36Sopenharmony_ci	if (stat(buf_dir_name, &st)) {
61662306a36Sopenharmony_ci		fprintf(stderr, "Could not stat() '%s', got error %d: %s\n",
61762306a36Sopenharmony_ci			buf_dir_name, errno, strerror(errno));
61862306a36Sopenharmony_ci		ret = -errno;
61962306a36Sopenharmony_ci		goto error;
62062306a36Sopenharmony_ci	}
62162306a36Sopenharmony_ci
62262306a36Sopenharmony_ci	if (!S_ISDIR(st.st_mode)) {
62362306a36Sopenharmony_ci		fprintf(stderr, "File '%s' is not a directory\n", buf_dir_name);
62462306a36Sopenharmony_ci		ret = -EFAULT;
62562306a36Sopenharmony_ci		goto error;
62662306a36Sopenharmony_ci	}
62762306a36Sopenharmony_ci
62862306a36Sopenharmony_ci	if (!notrigger) {
62962306a36Sopenharmony_ci		printf("%s %s\n", dev_dir_name, trigger_name);
63062306a36Sopenharmony_ci		/*
63162306a36Sopenharmony_ci		 * Set the device trigger to be the data ready trigger found
63262306a36Sopenharmony_ci		 * above
63362306a36Sopenharmony_ci		 */
63462306a36Sopenharmony_ci		ret = write_sysfs_string_and_verify("trigger/current_trigger",
63562306a36Sopenharmony_ci						    dev_dir_name,
63662306a36Sopenharmony_ci						    trigger_name);
63762306a36Sopenharmony_ci		if (ret < 0) {
63862306a36Sopenharmony_ci			fprintf(stderr,
63962306a36Sopenharmony_ci				"Failed to write current_trigger file\n");
64062306a36Sopenharmony_ci			goto error;
64162306a36Sopenharmony_ci		}
64262306a36Sopenharmony_ci	}
64362306a36Sopenharmony_ci
64462306a36Sopenharmony_ci	ret = asprintf(&buffer_access, "/dev/iio:device%d", dev_num);
64562306a36Sopenharmony_ci	if (ret < 0) {
64662306a36Sopenharmony_ci		ret = -ENOMEM;
64762306a36Sopenharmony_ci		goto error;
64862306a36Sopenharmony_ci	}
64962306a36Sopenharmony_ci
65062306a36Sopenharmony_ci	/* Attempt to open non blocking the access dev */
65162306a36Sopenharmony_ci	fd = open(buffer_access, O_RDONLY | O_NONBLOCK);
65262306a36Sopenharmony_ci	if (fd == -1) { /* TODO: If it isn't there make the node */
65362306a36Sopenharmony_ci		ret = -errno;
65462306a36Sopenharmony_ci		fprintf(stderr, "Failed to open %s\n", buffer_access);
65562306a36Sopenharmony_ci		goto error;
65662306a36Sopenharmony_ci	}
65762306a36Sopenharmony_ci
65862306a36Sopenharmony_ci	/* specify for which buffer index we want an FD */
65962306a36Sopenharmony_ci	buf_fd = buffer_idx;
66062306a36Sopenharmony_ci
66162306a36Sopenharmony_ci	ret = ioctl(fd, IIO_BUFFER_GET_FD_IOCTL, &buf_fd);
66262306a36Sopenharmony_ci	if (ret == -1 || buf_fd == -1) {
66362306a36Sopenharmony_ci		ret = -errno;
66462306a36Sopenharmony_ci		if (ret == -ENODEV || ret == -EINVAL)
66562306a36Sopenharmony_ci			fprintf(stderr,
66662306a36Sopenharmony_ci				"Device does not have this many buffers\n");
66762306a36Sopenharmony_ci		else
66862306a36Sopenharmony_ci			fprintf(stderr, "Failed to retrieve buffer fd\n");
66962306a36Sopenharmony_ci
67062306a36Sopenharmony_ci		goto error;
67162306a36Sopenharmony_ci	}
67262306a36Sopenharmony_ci
67362306a36Sopenharmony_ci	/* Setup ring buffer parameters */
67462306a36Sopenharmony_ci	ret = write_sysfs_int("length", buf_dir_name, buf_len);
67562306a36Sopenharmony_ci	if (ret < 0)
67662306a36Sopenharmony_ci		goto error;
67762306a36Sopenharmony_ci
67862306a36Sopenharmony_ci	/* Enable the buffer */
67962306a36Sopenharmony_ci	ret = write_sysfs_int("enable", buf_dir_name, 1);
68062306a36Sopenharmony_ci	if (ret < 0) {
68162306a36Sopenharmony_ci		fprintf(stderr,
68262306a36Sopenharmony_ci			"Failed to enable buffer '%s': %s\n",
68362306a36Sopenharmony_ci			buf_dir_name, strerror(-ret));
68462306a36Sopenharmony_ci		goto error;
68562306a36Sopenharmony_ci	}
68662306a36Sopenharmony_ci
68762306a36Sopenharmony_ci	scan_size = size_from_channelarray(channels, num_channels);
68862306a36Sopenharmony_ci
68962306a36Sopenharmony_ci	size_t total_buf_len = scan_size * buf_len;
69062306a36Sopenharmony_ci
69162306a36Sopenharmony_ci	if (scan_size > 0 && total_buf_len / scan_size != buf_len) {
69262306a36Sopenharmony_ci		ret = -EFAULT;
69362306a36Sopenharmony_ci		perror("Integer overflow happened when calculate scan_size * buf_len");
69462306a36Sopenharmony_ci		goto error;
69562306a36Sopenharmony_ci	}
69662306a36Sopenharmony_ci
69762306a36Sopenharmony_ci	data = malloc(total_buf_len);
69862306a36Sopenharmony_ci	if (!data) {
69962306a36Sopenharmony_ci		ret = -ENOMEM;
70062306a36Sopenharmony_ci		goto error;
70162306a36Sopenharmony_ci	}
70262306a36Sopenharmony_ci
70362306a36Sopenharmony_ci	/**
70462306a36Sopenharmony_ci	 * This check is being done here for sanity reasons, however it
70562306a36Sopenharmony_ci	 * should be omitted under normal operation.
70662306a36Sopenharmony_ci	 * If this is buffer0, we check that we get EBUSY after this point.
70762306a36Sopenharmony_ci	 */
70862306a36Sopenharmony_ci	if (buffer_idx == 0) {
70962306a36Sopenharmony_ci		errno = 0;
71062306a36Sopenharmony_ci		read_size = read(fd, data, 1);
71162306a36Sopenharmony_ci		if (read_size > -1 || errno != EBUSY) {
71262306a36Sopenharmony_ci			ret = -EFAULT;
71362306a36Sopenharmony_ci			perror("Reading from '%s' should not be possible after ioctl()");
71462306a36Sopenharmony_ci			goto error;
71562306a36Sopenharmony_ci		}
71662306a36Sopenharmony_ci	}
71762306a36Sopenharmony_ci
71862306a36Sopenharmony_ci	/* close now the main chardev FD and let the buffer FD work */
71962306a36Sopenharmony_ci	if (close(fd) == -1)
72062306a36Sopenharmony_ci		perror("Failed to close character device file");
72162306a36Sopenharmony_ci	fd = -1;
72262306a36Sopenharmony_ci
72362306a36Sopenharmony_ci	for (j = 0; j < num_loops || num_loops < 0; j++) {
72462306a36Sopenharmony_ci		if (!noevents) {
72562306a36Sopenharmony_ci			struct pollfd pfd = {
72662306a36Sopenharmony_ci				.fd = buf_fd,
72762306a36Sopenharmony_ci				.events = POLLIN,
72862306a36Sopenharmony_ci			};
72962306a36Sopenharmony_ci
73062306a36Sopenharmony_ci			ret = poll(&pfd, 1, -1);
73162306a36Sopenharmony_ci			if (ret < 0) {
73262306a36Sopenharmony_ci				ret = -errno;
73362306a36Sopenharmony_ci				goto error;
73462306a36Sopenharmony_ci			} else if (ret == 0) {
73562306a36Sopenharmony_ci				continue;
73662306a36Sopenharmony_ci			}
73762306a36Sopenharmony_ci
73862306a36Sopenharmony_ci		} else {
73962306a36Sopenharmony_ci			usleep(timedelay);
74062306a36Sopenharmony_ci		}
74162306a36Sopenharmony_ci
74262306a36Sopenharmony_ci		toread = buf_len;
74362306a36Sopenharmony_ci
74462306a36Sopenharmony_ci		read_size = read(buf_fd, data, toread * scan_size);
74562306a36Sopenharmony_ci		if (read_size < 0) {
74662306a36Sopenharmony_ci			if (errno == EAGAIN) {
74762306a36Sopenharmony_ci				fprintf(stderr, "nothing available\n");
74862306a36Sopenharmony_ci				continue;
74962306a36Sopenharmony_ci			} else {
75062306a36Sopenharmony_ci				break;
75162306a36Sopenharmony_ci			}
75262306a36Sopenharmony_ci		}
75362306a36Sopenharmony_ci		for (i = 0; i < read_size / scan_size; i++)
75462306a36Sopenharmony_ci			process_scan(data + scan_size * i, channels,
75562306a36Sopenharmony_ci				     num_channels);
75662306a36Sopenharmony_ci	}
75762306a36Sopenharmony_ci
75862306a36Sopenharmony_cierror:
75962306a36Sopenharmony_ci	cleanup();
76062306a36Sopenharmony_ci
76162306a36Sopenharmony_ci	if (fd >= 0 && close(fd) == -1)
76262306a36Sopenharmony_ci		perror("Failed to close character device");
76362306a36Sopenharmony_ci	if (buf_fd >= 0 && close(buf_fd) == -1)
76462306a36Sopenharmony_ci		perror("Failed to close buffer");
76562306a36Sopenharmony_ci	free(buffer_access);
76662306a36Sopenharmony_ci	free(data);
76762306a36Sopenharmony_ci	free(buf_dir_name);
76862306a36Sopenharmony_ci	for (i = num_channels - 1; i >= 0; i--) {
76962306a36Sopenharmony_ci		free(channels[i].name);
77062306a36Sopenharmony_ci		free(channels[i].generic_name);
77162306a36Sopenharmony_ci	}
77262306a36Sopenharmony_ci	free(channels);
77362306a36Sopenharmony_ci	free(trigger_name);
77462306a36Sopenharmony_ci	free(device_name);
77562306a36Sopenharmony_ci	free(dev_dir_name);
77662306a36Sopenharmony_ci
77762306a36Sopenharmony_ci	return ret;
77862306a36Sopenharmony_ci}
779