├── 34.1.1 ├── binary │ ├── ar0234.ko │ ├── max96712.ko │ ├── tegra194-p2888-0001-p2822-0000.dtb │ └── tegra234-p3701-0000-p3737-0000.dtb ├── document │ └── AR0234-STEREO-GMSL2_Orin_max96712_R34.1.1_20220616_Driver_Guide.docx └── isp │ └── camera_overrides.isp_xavier ├── 35.1 ├── app │ ├── Readme.txt │ ├── iio_generic_buffer │ ├── iio_generic_buffer.c │ ├── iio_utils.c │ └── iio_utils.h ├── binary │ ├── bmi088.ko │ ├── max96712.ko │ ├── nv_ar0234.ko │ ├── tegra194-p2888-0001-p2822-0000.dtb │ └── tegra234-p3701-0000-p3737-0000.dtb ├── document │ └── AR0234CS-STEREO-GMSL2-30-DUAL-R35.1-AGX-Orin-20221214_Driver_Guide.pdf └── isp │ └── camera_overrides.isp ├── 35.2_GA ├── AR0234CS-STEREO-GMSL2-30-DUAL-R35.1-AGX-Orin-20221214_Driver_Guide.pdf ├── ISP │ └── camera_overrides.isp ├── app │ ├── Readme.txt │ ├── iio_generic_buffer │ ├── iio_generic_buffer.c │ ├── iio_utils.c │ └── iio_utils.h └── binary │ ├── bmi088.ko │ ├── max96712.ko │ ├── nv_ar0234.ko │ ├── tegra194-p2888-0001-p2822-0000.dtb │ └── tegra234-p3701-0000-p3737-0000.dtb ├── 35.3.1 ├── AR0234CS-GMSL2-STEREO-R35.3.1-AGX-ORIN-20230505_Driver_Guide.docx ├── ISP │ └── camera_overrides.isp ├── app │ ├── Readme.txt │ ├── iio_generic_buffer │ ├── iio_generic_buffer.c │ ├── iio_utils.c │ └── iio_utils.h └── binary │ ├── bmi088.ko │ ├── max96712.ko │ ├── nv_ar0234.ko │ ├── tegra194-p2888-0001-p2822-0000.dtb │ └── tegra234-p3701-0000-p3737-0000.dtb ├── README.md └── Xavier_Driver ├── 32.6.1 ├── binary │ ├── Image │ ├── ar0234.ko │ ├── max96712.ko │ ├── nvs_bmi088_accel.ko │ ├── nvs_bmi088_gyro.ko │ └── tegra194-p2888-0001-p2822-0000.dtb ├── document │ └── AR0234CS-STEREO-GMSL2_Xavier_EVA_R32.6.1_202100812_Driver_Guide.pdf └── isp │ └── camera_overrides.isp └── 32.7 ├── binary ├── Image ├── ar0234.ko ├── max96712.ko └── tegra194-p2888-0001-p2822-0000.dtb ├── document └── AR0234CS-STEREO-GMSL2_R32.7_Xavier_NV_max96712_20220316_Driver_Guide.pdf └── isp └── camera_overrides.isp /34.1.1/binary/ar0234.ko: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LPXingxing/LI-AR0234CS-STEREO-GMSL2/f4455da7dc1c05b3b235903f521104db219a6acc/34.1.1/binary/ar0234.ko -------------------------------------------------------------------------------- /34.1.1/binary/max96712.ko: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LPXingxing/LI-AR0234CS-STEREO-GMSL2/f4455da7dc1c05b3b235903f521104db219a6acc/34.1.1/binary/max96712.ko -------------------------------------------------------------------------------- /34.1.1/binary/tegra194-p2888-0001-p2822-0000.dtb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LPXingxing/LI-AR0234CS-STEREO-GMSL2/f4455da7dc1c05b3b235903f521104db219a6acc/34.1.1/binary/tegra194-p2888-0001-p2822-0000.dtb -------------------------------------------------------------------------------- /34.1.1/binary/tegra234-p3701-0000-p3737-0000.dtb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LPXingxing/LI-AR0234CS-STEREO-GMSL2/f4455da7dc1c05b3b235903f521104db219a6acc/34.1.1/binary/tegra234-p3701-0000-p3737-0000.dtb -------------------------------------------------------------------------------- /34.1.1/document/AR0234-STEREO-GMSL2_Orin_max96712_R34.1.1_20220616_Driver_Guide.docx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LPXingxing/LI-AR0234CS-STEREO-GMSL2/f4455da7dc1c05b3b235903f521104db219a6acc/34.1.1/document/AR0234-STEREO-GMSL2_Orin_max96712_R34.1.1_20220616_Driver_Guide.docx -------------------------------------------------------------------------------- /35.1/app/Readme.txt: -------------------------------------------------------------------------------- 1 | gcc iio_utils.c iio_generic_buffer.c -o iio_generic_buffer 2 | 3 | 4 | sudo ./iio_generic_buffer -N 0 -g -a -c 100 5 | 6 | sudo ./iio_generic_buffer -N 1 -g -a -c 100 7 | 8 | sudo ./iio_generic_buffer -N 2 -g -a -c 100 9 | 10 | sudo ./iio_generic_buffer -N 3 -g -a -c 100 -------------------------------------------------------------------------------- /35.1/app/iio_generic_buffer: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LPXingxing/LI-AR0234CS-STEREO-GMSL2/f4455da7dc1c05b3b235903f521104db219a6acc/35.1/app/iio_generic_buffer -------------------------------------------------------------------------------- /35.1/app/iio_generic_buffer.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0-only 2 | /* Industrialio buffer test code. 3 | * 4 | * Copyright (c) 2008 Jonathan Cameron 5 | * 6 | * This program is primarily intended as an example application. 7 | * Reads the current buffer setup from sysfs and starts a short capture 8 | * from the specified device, pretty printing the result after appropriate 9 | * conversion. 10 | * 11 | * Command line parameters 12 | * generic_buffer -n -t 13 | * If trigger name is not specified the program assumes you want a dataready 14 | * trigger associated with the device and goes looking for it. 15 | */ 16 | 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include "iio_utils.h" 34 | 35 | /** 36 | * enum autochan - state for the automatic channel enabling mechanism 37 | */ 38 | enum autochan { 39 | AUTOCHANNELS_DISABLED, 40 | AUTOCHANNELS_ENABLED, 41 | AUTOCHANNELS_ACTIVE, 42 | }; 43 | 44 | /** 45 | * size_from_channelarray() - calculate the storage size of a scan 46 | * @channels: the channel info array 47 | * @num_channels: number of channels 48 | * 49 | * Has the side effect of filling the channels[i].location values used 50 | * in processing the buffer output. 51 | **/ 52 | int size_from_channelarray(struct iio_channel_info *channels, int num_channels) 53 | { 54 | int bytes = 0; 55 | int i = 0; 56 | 57 | while (i < num_channels) { 58 | if (bytes % channels[i].bytes == 0) 59 | channels[i].location = bytes; 60 | else 61 | channels[i].location = bytes - bytes % channels[i].bytes 62 | + channels[i].bytes; 63 | 64 | bytes = channels[i].location + channels[i].bytes; 65 | i++; 66 | } 67 | 68 | return bytes; 69 | } 70 | 71 | void print1byte(uint8_t input, struct iio_channel_info *info) 72 | { 73 | /* 74 | * Shift before conversion to avoid sign extension 75 | * of left aligned data 76 | */ 77 | input >>= info->shift; 78 | input &= info->mask; 79 | if (info->is_signed) { 80 | int8_t val = (int8_t)(input << (8 - info->bits_used)) >> 81 | (8 - info->bits_used); 82 | printf("%05f ", ((float)val + info->offset) * info->scale); 83 | } else { 84 | printf("%05f ", ((float)input + info->offset) * info->scale); 85 | } 86 | } 87 | 88 | void print2byte(uint16_t input, struct iio_channel_info *info) 89 | { 90 | /* First swap if incorrect endian */ 91 | if (info->be) 92 | input = be16toh(input); 93 | else 94 | input = le16toh(input); 95 | 96 | /* 97 | * Shift before conversion to avoid sign extension 98 | * of left aligned data 99 | */ 100 | input >>= info->shift; 101 | input &= info->mask; 102 | if (info->is_signed) { 103 | int16_t val = (int16_t)(input << (16 - info->bits_used)) >> 104 | (16 - info->bits_used); 105 | printf("%05f ", ((float)val + info->offset) * info->scale); 106 | } else { 107 | printf("%05f ", ((float)input + info->offset) * info->scale); 108 | } 109 | } 110 | 111 | void print4byte(uint32_t input, struct iio_channel_info *info) 112 | { 113 | /* First swap if incorrect endian */ 114 | if (info->be) 115 | input = be32toh(input); 116 | else 117 | input = le32toh(input); 118 | 119 | /* 120 | * Shift before conversion to avoid sign extension 121 | * of left aligned data 122 | */ 123 | input >>= info->shift; 124 | input &= info->mask; 125 | if (info->is_signed) { 126 | int32_t val = (int32_t)(input << (32 - info->bits_used)) >> 127 | (32 - info->bits_used); 128 | printf("%05f ", ((float)val + info->offset) * info->scale); 129 | } else { 130 | printf("%05f ", ((float)input + info->offset) * info->scale); 131 | } 132 | } 133 | 134 | void print8byte(uint64_t input, struct iio_channel_info *info) 135 | { 136 | /* First swap if incorrect endian */ 137 | if (info->be) 138 | input = be64toh(input); 139 | else 140 | input = le64toh(input); 141 | 142 | /* 143 | * Shift before conversion to avoid sign extension 144 | * of left aligned data 145 | */ 146 | input >>= info->shift; 147 | input &= info->mask; 148 | if (info->is_signed) { 149 | int64_t val = (int64_t)(input << (64 - info->bits_used)) >> 150 | (64 - info->bits_used); 151 | /* special case for timestamp */ 152 | if (info->scale == 1.0f && info->offset == 0.0f) 153 | printf("%" PRId64 " ", val); 154 | else 155 | printf("%05f ", 156 | ((float)val + info->offset) * info->scale); 157 | } else { 158 | printf("%05f ", ((float)input + info->offset) * info->scale); 159 | } 160 | } 161 | 162 | /** 163 | * process_scan() - print out the values in SI units 164 | * @data: pointer to the start of the scan 165 | * @channels: information about the channels. 166 | * Note: size_from_channelarray must have been called first 167 | * to fill the location offsets. 168 | * @num_channels: number of channels 169 | **/ 170 | void process_scan(char *data, 171 | struct iio_channel_info *channels, 172 | int num_channels) 173 | { 174 | int k; 175 | 176 | for (k = 0; k < num_channels; k++) 177 | switch (channels[k].bytes) { 178 | /* only a few cases implemented so far */ 179 | case 1: 180 | print1byte(*(uint8_t *)(data + channels[k].location), 181 | &channels[k]); 182 | break; 183 | case 2: 184 | print2byte(*(uint16_t *)(data + channels[k].location), 185 | &channels[k]); 186 | break; 187 | case 4: 188 | print4byte(*(uint32_t *)(data + channels[k].location), 189 | &channels[k]); 190 | break; 191 | case 8: 192 | print8byte(*(uint64_t *)(data + channels[k].location), 193 | &channels[k]); 194 | break; 195 | default: 196 | break; 197 | } 198 | printf("\n"); 199 | } 200 | 201 | static int enable_disable_all_channels(char *dev_dir_name, int enable) 202 | { 203 | const struct dirent *ent; 204 | char scanelemdir[256]; 205 | DIR *dp; 206 | int ret; 207 | 208 | snprintf(scanelemdir, sizeof(scanelemdir), 209 | FORMAT_SCAN_ELEMENTS_DIR, dev_dir_name); 210 | scanelemdir[sizeof(scanelemdir)-1] = '\0'; 211 | 212 | dp = opendir(scanelemdir); 213 | if (!dp) { 214 | fprintf(stderr, "Enabling/disabling channels: can't open %s\n", 215 | scanelemdir); 216 | return -EIO; 217 | } 218 | 219 | ret = -ENOENT; 220 | while (ent = readdir(dp), ent) { 221 | if (iioutils_check_suffix(ent->d_name, "_en")) { 222 | printf("%sabling: %s\n", 223 | enable ? "En" : "Dis", 224 | ent->d_name); 225 | ret = write_sysfs_int(ent->d_name, scanelemdir, 226 | enable); 227 | if (ret < 0) 228 | fprintf(stderr, "Failed to enable/disable %s\n", 229 | ent->d_name); 230 | } 231 | } 232 | 233 | if (closedir(dp) == -1) { 234 | perror("Enabling/disabling channels: " 235 | "Failed to close directory"); 236 | return -errno; 237 | } 238 | return 0; 239 | } 240 | 241 | void print_usage(void) 242 | { 243 | fprintf(stderr, "Usage: generic_buffer [options]...\n" 244 | "Capture, convert and output data from IIO device buffer\n" 245 | " -a Auto-activate all available channels\n" 246 | " -A Force-activate ALL channels\n" 247 | " -c Do n conversions, or loop forever if n < 0\n" 248 | " -e Disable wait for event (new data)\n" 249 | " -g Use trigger-less mode\n" 250 | " -l Set buffer length to n samples\n" 251 | " --device-name -n \n" 252 | " --device-num -N \n" 253 | " Set device by name or number (mandatory)\n" 254 | " --trigger-name -t \n" 255 | " --trigger-num -T \n" 256 | " Set trigger by name or number\n" 257 | " -w Set delay between reads in us (event-less mode)\n"); 258 | } 259 | 260 | enum autochan autochannels = AUTOCHANNELS_DISABLED; 261 | char *dev_dir_name = NULL; 262 | char *buf_dir_name = NULL; 263 | bool current_trigger_set = false; 264 | 265 | void cleanup(void) 266 | { 267 | int ret; 268 | 269 | /* Disable trigger */ 270 | if (dev_dir_name && current_trigger_set) { 271 | /* Disconnect the trigger - just write a dummy name. */ 272 | ret = write_sysfs_string("trigger/current_trigger", 273 | dev_dir_name, "NULL"); 274 | if (ret < 0) 275 | fprintf(stderr, "Failed to disable trigger: %s\n", 276 | strerror(-ret)); 277 | current_trigger_set = false; 278 | } 279 | 280 | /* Disable buffer */ 281 | if (buf_dir_name) { 282 | ret = write_sysfs_int("enable", buf_dir_name, 0); 283 | if (ret < 0) 284 | fprintf(stderr, "Failed to disable buffer: %s\n", 285 | strerror(-ret)); 286 | } 287 | 288 | /* Disable channels if auto-enabled */ 289 | if (dev_dir_name && autochannels == AUTOCHANNELS_ACTIVE) { 290 | ret = enable_disable_all_channels(dev_dir_name, 0); 291 | if (ret) 292 | fprintf(stderr, "Failed to disable all channels\n"); 293 | autochannels = AUTOCHANNELS_DISABLED; 294 | } 295 | } 296 | 297 | void sig_handler(int signum) 298 | { 299 | fprintf(stderr, "Caught signal %d\n", signum); 300 | cleanup(); 301 | exit(-signum); 302 | } 303 | 304 | void register_cleanup(void) 305 | { 306 | struct sigaction sa = { .sa_handler = sig_handler }; 307 | const int signums[] = { SIGINT, SIGTERM, SIGABRT }; 308 | int ret, i; 309 | 310 | for (i = 0; i < ARRAY_SIZE(signums); ++i) { 311 | ret = sigaction(signums[i], &sa, NULL); 312 | if (ret) { 313 | perror("Failed to register signal handler"); 314 | exit(-1); 315 | } 316 | } 317 | } 318 | 319 | static const struct option longopts[] = { 320 | { "device-name", 1, 0, 'n' }, 321 | { "device-num", 1, 0, 'N' }, 322 | { "trigger-name", 1, 0, 't' }, 323 | { "trigger-num", 1, 0, 'T' }, 324 | { }, 325 | }; 326 | 327 | int main(int argc, char **argv) 328 | { 329 | long long num_loops = 2; 330 | unsigned long timedelay = 1000000; 331 | unsigned long buf_len = 128; 332 | 333 | ssize_t i; 334 | unsigned long long j; 335 | unsigned long toread; 336 | int ret, c; 337 | int fp = -1; 338 | 339 | int num_channels = 0; 340 | char *trigger_name = NULL, *device_name = NULL; 341 | 342 | char *data = NULL; 343 | ssize_t read_size; 344 | int dev_num = -1, trig_num = -1; 345 | char *buffer_access = NULL; 346 | int scan_size; 347 | int noevents = 0; 348 | int notrigger = 0; 349 | char *dummy; 350 | bool force_autochannels = false; 351 | 352 | struct iio_channel_info *channels = NULL; 353 | 354 | register_cleanup(); 355 | 356 | while ((c = getopt_long(argc, argv, "aAc:egl:n:N:t:T:w:?", longopts, 357 | NULL)) != -1) { 358 | switch (c) { 359 | case 'a': 360 | autochannels = AUTOCHANNELS_ENABLED; 361 | break; 362 | case 'A': 363 | autochannels = AUTOCHANNELS_ENABLED; 364 | force_autochannels = true; 365 | break; 366 | case 'c': 367 | errno = 0; 368 | num_loops = strtoll(optarg, &dummy, 10); 369 | if (errno) { 370 | ret = -errno; 371 | goto error; 372 | } 373 | 374 | break; 375 | case 'e': 376 | noevents = 1; 377 | break; 378 | case 'g': 379 | notrigger = 1; 380 | break; 381 | case 'l': 382 | errno = 0; 383 | buf_len = strtoul(optarg, &dummy, 10); 384 | if (errno) { 385 | ret = -errno; 386 | goto error; 387 | } 388 | 389 | break; 390 | case 'n': 391 | device_name = strdup(optarg); 392 | break; 393 | case 'N': 394 | errno = 0; 395 | dev_num = strtoul(optarg, &dummy, 10); 396 | if (errno) { 397 | ret = -errno; 398 | goto error; 399 | } 400 | break; 401 | case 't': 402 | trigger_name = strdup(optarg); 403 | break; 404 | case 'T': 405 | errno = 0; 406 | trig_num = strtoul(optarg, &dummy, 10); 407 | if (errno) 408 | return -errno; 409 | break; 410 | case 'w': 411 | errno = 0; 412 | timedelay = strtoul(optarg, &dummy, 10); 413 | if (errno) { 414 | ret = -errno; 415 | goto error; 416 | } 417 | break; 418 | case '?': 419 | print_usage(); 420 | ret = -1; 421 | goto error; 422 | } 423 | } 424 | 425 | /* Find the device requested */ 426 | if (dev_num < 0 && !device_name) { 427 | fprintf(stderr, "Device not set\n"); 428 | print_usage(); 429 | ret = -1; 430 | goto error; 431 | } else if (dev_num >= 0 && device_name) { 432 | fprintf(stderr, "Only one of --device-num or --device-name needs to be set\n"); 433 | print_usage(); 434 | ret = -1; 435 | goto error; 436 | } else if (dev_num < 0) { 437 | dev_num = find_type_by_name(device_name, "iio:device"); 438 | if (dev_num < 0) { 439 | fprintf(stderr, "Failed to find the %s\n", device_name); 440 | ret = dev_num; 441 | goto error; 442 | } 443 | } 444 | printf("iio device number being used is %d\n", dev_num); 445 | 446 | ret = asprintf(&dev_dir_name, "%siio:device%d", iio_dir, dev_num); 447 | if (ret < 0) 448 | return -ENOMEM; 449 | /* Fetch device_name if specified by number */ 450 | if (!device_name) { 451 | device_name = malloc(IIO_MAX_NAME_LENGTH); 452 | if (!device_name) { 453 | ret = -ENOMEM; 454 | goto error; 455 | } 456 | ret = read_sysfs_string("name", dev_dir_name, device_name); 457 | if (ret < 0) { 458 | fprintf(stderr, "Failed to read name of device %d\n", dev_num); 459 | goto error; 460 | } 461 | } 462 | 463 | if (notrigger) { 464 | printf("trigger-less mode selected\n"); 465 | } else if (trig_num >= 0) { 466 | char *trig_dev_name; 467 | ret = asprintf(&trig_dev_name, "%strigger%d", iio_dir, trig_num); 468 | if (ret < 0) { 469 | return -ENOMEM; 470 | } 471 | trigger_name = malloc(IIO_MAX_NAME_LENGTH); 472 | ret = read_sysfs_string("name", trig_dev_name, trigger_name); 473 | free(trig_dev_name); 474 | if (ret < 0) { 475 | fprintf(stderr, "Failed to read trigger%d name from\n", trig_num); 476 | return ret; 477 | } 478 | printf("iio trigger number being used is %d\n", trig_num); 479 | } else { 480 | if (!trigger_name) { 481 | /* 482 | * Build the trigger name. If it is device associated 483 | * its name is _dev[n] where n matches 484 | * the device number found above. 485 | */ 486 | ret = asprintf(&trigger_name, 487 | "%s-dev%d", device_name, dev_num); 488 | if (ret < 0) { 489 | ret = -ENOMEM; 490 | goto error; 491 | } 492 | } 493 | 494 | /* Look for this "-devN" trigger */ 495 | trig_num = find_type_by_name(trigger_name, "trigger"); 496 | if (trig_num < 0) { 497 | /* OK try the simpler "-trigger" suffix instead */ 498 | free(trigger_name); 499 | ret = asprintf(&trigger_name, 500 | "%s-trigger", device_name); 501 | if (ret < 0) { 502 | ret = -ENOMEM; 503 | goto error; 504 | } 505 | } 506 | 507 | trig_num = find_type_by_name(trigger_name, "trigger"); 508 | if (trig_num < 0) { 509 | fprintf(stderr, "Failed to find the trigger %s\n", 510 | trigger_name); 511 | ret = trig_num; 512 | goto error; 513 | } 514 | 515 | printf("iio trigger number being used is %d\n", trig_num); 516 | } 517 | 518 | /* 519 | * Parse the files in scan_elements to identify what channels are 520 | * present 521 | */ 522 | ret = build_channel_array(dev_dir_name, &channels, &num_channels); 523 | if (ret) { 524 | fprintf(stderr, "Problem reading scan element information\n" 525 | "diag %s\n", dev_dir_name); 526 | goto error; 527 | } 528 | if (num_channels && autochannels == AUTOCHANNELS_ENABLED && 529 | !force_autochannels) { 530 | fprintf(stderr, "Auto-channels selected but some channels " 531 | "are already activated in sysfs\n"); 532 | fprintf(stderr, "Proceeding without activating any channels\n"); 533 | } 534 | 535 | if ((!num_channels && autochannels == AUTOCHANNELS_ENABLED) || 536 | (autochannels == AUTOCHANNELS_ENABLED && force_autochannels)) { 537 | fprintf(stderr, "Enabling all channels\n"); 538 | 539 | ret = enable_disable_all_channels(dev_dir_name, 1); 540 | if (ret) { 541 | fprintf(stderr, "Failed to enable all channels\n"); 542 | goto error; 543 | } 544 | 545 | /* This flags that we need to disable the channels again */ 546 | autochannels = AUTOCHANNELS_ACTIVE; 547 | 548 | ret = build_channel_array(dev_dir_name, &channels, 549 | &num_channels); 550 | if (ret) { 551 | fprintf(stderr, "Problem reading scan element " 552 | "information\n" 553 | "diag %s\n", dev_dir_name); 554 | goto error; 555 | } 556 | if (!num_channels) { 557 | fprintf(stderr, "Still no channels after " 558 | "auto-enabling, giving up\n"); 559 | goto error; 560 | } 561 | } 562 | 563 | if (!num_channels && autochannels == AUTOCHANNELS_DISABLED) { 564 | fprintf(stderr, 565 | "No channels are enabled, we have nothing to scan.\n"); 566 | fprintf(stderr, "Enable channels manually in " 567 | FORMAT_SCAN_ELEMENTS_DIR 568 | "/*_en or pass -a to autoenable channels and " 569 | "try again.\n", dev_dir_name); 570 | ret = -ENOENT; 571 | goto error; 572 | } 573 | 574 | /* 575 | * Construct the directory name for the associated buffer. 576 | * As we know that the lis3l02dq has only one buffer this may 577 | * be built rather than found. 578 | */ 579 | ret = asprintf(&buf_dir_name, 580 | "%siio:device%d/buffer", iio_dir, dev_num); 581 | if (ret < 0) { 582 | ret = -ENOMEM; 583 | goto error; 584 | } 585 | 586 | if (!notrigger) { 587 | printf("%s %s\n", dev_dir_name, trigger_name); 588 | /* 589 | * Set the device trigger to be the data ready trigger found 590 | * above 591 | */ 592 | ret = write_sysfs_string_and_verify("trigger/current_trigger", 593 | dev_dir_name, 594 | trigger_name); 595 | if (ret < 0) { 596 | fprintf(stderr, 597 | "Failed to write current_trigger file\n"); 598 | goto error; 599 | } 600 | } 601 | 602 | /* Setup ring buffer parameters */ 603 | ret = write_sysfs_int("length", buf_dir_name, buf_len); 604 | if (ret < 0) 605 | goto error; 606 | 607 | /* Enable the buffer */ 608 | ret = write_sysfs_int("enable", buf_dir_name, 1); 609 | if (ret < 0) { 610 | fprintf(stderr, 611 | "Failed to enable buffer: %s\n", strerror(-ret)); 612 | goto error; 613 | } 614 | 615 | scan_size = size_from_channelarray(channels, num_channels); 616 | data = malloc(scan_size * buf_len); 617 | if (!data) { 618 | ret = -ENOMEM; 619 | goto error; 620 | } 621 | 622 | ret = asprintf(&buffer_access, "/dev/iio:device%d", dev_num); 623 | if (ret < 0) { 624 | ret = -ENOMEM; 625 | goto error; 626 | } 627 | 628 | /* Attempt to open non blocking the access dev */ 629 | fp = open(buffer_access, O_RDONLY | O_NONBLOCK); 630 | if (fp == -1) { /* TODO: If it isn't there make the node */ 631 | ret = -errno; 632 | fprintf(stderr, "Failed to open %s\n", buffer_access); 633 | goto error; 634 | } 635 | 636 | for (j = 0; j < num_loops || num_loops < 0; j++) { 637 | if (!noevents) { 638 | struct pollfd pfd = { 639 | .fd = fp, 640 | .events = POLLIN, 641 | }; 642 | 643 | ret = poll(&pfd, 1, -1); 644 | if (ret < 0) { 645 | ret = -errno; 646 | goto error; 647 | } else if (ret == 0) { 648 | continue; 649 | } 650 | 651 | toread = buf_len; 652 | } else { 653 | usleep(timedelay); 654 | toread = 64; 655 | } 656 | 657 | read_size = read(fp, data, toread * scan_size); 658 | if (read_size < 0) { 659 | if (errno == EAGAIN) { 660 | fprintf(stderr, "nothing available\n"); 661 | continue; 662 | } else { 663 | break; 664 | } 665 | } 666 | for (i = 0; i < read_size / scan_size; i++) 667 | process_scan(data + scan_size * i, channels, 668 | num_channels); 669 | } 670 | 671 | error: 672 | cleanup(); 673 | 674 | if (fp >= 0 && close(fp) == -1) 675 | perror("Failed to close buffer"); 676 | free(buffer_access); 677 | free(data); 678 | free(buf_dir_name); 679 | for (i = num_channels - 1; i >= 0; i--) { 680 | free(channels[i].name); 681 | free(channels[i].generic_name); 682 | } 683 | free(channels); 684 | free(trigger_name); 685 | free(device_name); 686 | free(dev_dir_name); 687 | 688 | return ret; 689 | } 690 | -------------------------------------------------------------------------------- /35.1/app/iio_utils.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0-only 2 | /* IIO - useful set of util functionality 3 | * 4 | * Copyright (c) 2008 Jonathan Cameron 5 | */ 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include "iio_utils.h" 14 | 15 | const char *iio_dir = "/sys/bus/iio/devices/"; 16 | 17 | static char * const iio_direction[] = { 18 | "in", 19 | "out", 20 | }; 21 | 22 | /** 23 | * iioutils_break_up_name() - extract generic name from full channel name 24 | * @full_name: the full channel name 25 | * @generic_name: the output generic channel name 26 | * 27 | * Returns 0 on success, or a negative error code if string extraction failed. 28 | **/ 29 | int iioutils_break_up_name(const char *full_name, char **generic_name) 30 | { 31 | char *current; 32 | char *w, *r; 33 | char *working, *prefix = ""; 34 | int i, ret; 35 | 36 | for (i = 0; i < ARRAY_SIZE(iio_direction); i++) 37 | if (!strncmp(full_name, iio_direction[i], 38 | strlen(iio_direction[i]))) { 39 | prefix = iio_direction[i]; 40 | break; 41 | } 42 | 43 | current = strdup(full_name + strlen(prefix) + 1); 44 | if (!current) 45 | return -ENOMEM; 46 | 47 | working = strtok(current, "_\0"); 48 | if (!working) { 49 | free(current); 50 | return -EINVAL; 51 | } 52 | 53 | w = working; 54 | r = working; 55 | 56 | while (*r != '\0') { 57 | if (!isdigit(*r)) { 58 | *w = *r; 59 | w++; 60 | } 61 | 62 | r++; 63 | } 64 | *w = '\0'; 65 | ret = asprintf(generic_name, "%s_%s", prefix, working); 66 | free(current); 67 | 68 | return (ret == -1) ? -ENOMEM : 0; 69 | } 70 | 71 | /** 72 | * iioutils_get_type() - find and process _type attribute data 73 | * @is_signed: output whether channel is signed 74 | * @bytes: output how many bytes the channel storage occupies 75 | * @bits_used: output number of valid bits of data 76 | * @shift: output amount of bits to shift right data before applying bit mask 77 | * @mask: output a bit mask for the raw data 78 | * @be: output if data in big endian 79 | * @device_dir: the IIO device directory 80 | * @name: the channel name 81 | * @generic_name: the channel type name 82 | * 83 | * Returns a value >= 0 on success, otherwise a negative error code. 84 | **/ 85 | int iioutils_get_type(unsigned *is_signed, unsigned *bytes, unsigned *bits_used, 86 | unsigned *shift, uint64_t *mask, unsigned *be, 87 | const char *device_dir, const char *name, 88 | const char *generic_name) 89 | { 90 | FILE *sysfsfp; 91 | int ret; 92 | DIR *dp; 93 | char *scan_el_dir, *builtname, *builtname_generic, *filename = 0; 94 | char signchar, endianchar; 95 | unsigned padint; 96 | const struct dirent *ent; 97 | 98 | ret = asprintf(&scan_el_dir, FORMAT_SCAN_ELEMENTS_DIR, device_dir); 99 | if (ret < 0) 100 | return -ENOMEM; 101 | 102 | ret = asprintf(&builtname, FORMAT_TYPE_FILE, name); 103 | if (ret < 0) { 104 | ret = -ENOMEM; 105 | goto error_free_scan_el_dir; 106 | } 107 | ret = asprintf(&builtname_generic, FORMAT_TYPE_FILE, generic_name); 108 | if (ret < 0) { 109 | ret = -ENOMEM; 110 | goto error_free_builtname; 111 | } 112 | 113 | dp = opendir(scan_el_dir); 114 | if (!dp) { 115 | ret = -errno; 116 | goto error_free_builtname_generic; 117 | } 118 | 119 | ret = -ENOENT; 120 | while (ent = readdir(dp), ent) 121 | if ((strcmp(builtname, ent->d_name) == 0) || 122 | (strcmp(builtname_generic, ent->d_name) == 0)) { 123 | ret = asprintf(&filename, 124 | "%s/%s", scan_el_dir, ent->d_name); 125 | if (ret < 0) { 126 | ret = -ENOMEM; 127 | goto error_closedir; 128 | } 129 | 130 | sysfsfp = fopen(filename, "r"); 131 | if (!sysfsfp) { 132 | ret = -errno; 133 | fprintf(stderr, "failed to open %s\n", 134 | filename); 135 | goto error_free_filename; 136 | } 137 | 138 | ret = fscanf(sysfsfp, 139 | "%ce:%c%u/%u>>%u", 140 | &endianchar, 141 | &signchar, 142 | bits_used, 143 | &padint, shift); 144 | if (ret < 0) { 145 | ret = -errno; 146 | fprintf(stderr, 147 | "failed to pass scan type description\n"); 148 | goto error_close_sysfsfp; 149 | } else if (ret != 5) { 150 | ret = -EIO; 151 | fprintf(stderr, 152 | "scan type description didn't match\n"); 153 | goto error_close_sysfsfp; 154 | } 155 | 156 | *be = (endianchar == 'b'); 157 | *bytes = padint / 8; 158 | if (*bits_used == 64) 159 | *mask = ~(0ULL); 160 | else 161 | *mask = (1ULL << *bits_used) - 1ULL; 162 | 163 | *is_signed = (signchar == 's'); 164 | if (fclose(sysfsfp)) { 165 | ret = -errno; 166 | fprintf(stderr, "Failed to close %s\n", 167 | filename); 168 | goto error_free_filename; 169 | } 170 | 171 | sysfsfp = 0; 172 | free(filename); 173 | filename = 0; 174 | 175 | /* 176 | * Avoid having a more generic entry overwriting 177 | * the settings. 178 | */ 179 | if (strcmp(builtname, ent->d_name) == 0) 180 | break; 181 | } 182 | 183 | error_close_sysfsfp: 184 | if (sysfsfp) 185 | if (fclose(sysfsfp)) 186 | perror("iioutils_get_type(): Failed to close file"); 187 | 188 | error_free_filename: 189 | if (filename) 190 | free(filename); 191 | 192 | error_closedir: 193 | if (closedir(dp) == -1) 194 | perror("iioutils_get_type(): Failed to close directory"); 195 | 196 | error_free_builtname_generic: 197 | free(builtname_generic); 198 | error_free_builtname: 199 | free(builtname); 200 | error_free_scan_el_dir: 201 | free(scan_el_dir); 202 | 203 | return ret; 204 | } 205 | 206 | /** 207 | * iioutils_get_param_float() - read a float value from a channel parameter 208 | * @output: output the float value 209 | * @param_name: the parameter name to read 210 | * @device_dir: the IIO device directory in sysfs 211 | * @name: the channel name 212 | * @generic_name: the channel type name 213 | * 214 | * Returns a value >= 0 on success, otherwise a negative error code. 215 | **/ 216 | int iioutils_get_param_float(float *output, const char *param_name, 217 | const char *device_dir, const char *name, 218 | const char *generic_name) 219 | { 220 | FILE *sysfsfp; 221 | int ret; 222 | DIR *dp; 223 | char *builtname, *builtname_generic; 224 | char *filename = NULL; 225 | const struct dirent *ent; 226 | 227 | ret = asprintf(&builtname, "%s_%s", name, param_name); 228 | if (ret < 0) 229 | return -ENOMEM; 230 | 231 | ret = asprintf(&builtname_generic, 232 | "%s_%s", generic_name, param_name); 233 | if (ret < 0) { 234 | ret = -ENOMEM; 235 | goto error_free_builtname; 236 | } 237 | 238 | dp = opendir(device_dir); 239 | if (!dp) { 240 | ret = -errno; 241 | goto error_free_builtname_generic; 242 | } 243 | 244 | ret = -ENOENT; 245 | while (ent = readdir(dp), ent) 246 | if ((strcmp(builtname, ent->d_name) == 0) || 247 | (strcmp(builtname_generic, ent->d_name) == 0)) { 248 | ret = asprintf(&filename, 249 | "%s/%s", device_dir, ent->d_name); 250 | if (ret < 0) { 251 | ret = -ENOMEM; 252 | goto error_closedir; 253 | } 254 | 255 | sysfsfp = fopen(filename, "r"); 256 | if (!sysfsfp) { 257 | ret = -errno; 258 | goto error_free_filename; 259 | } 260 | 261 | errno = 0; 262 | if (fscanf(sysfsfp, "%f", output) != 1) 263 | ret = errno ? -errno : -ENODATA; 264 | 265 | break; 266 | } 267 | error_free_filename: 268 | if (filename) 269 | free(filename); 270 | 271 | error_closedir: 272 | if (closedir(dp) == -1) 273 | perror("iioutils_get_param_float(): Failed to close directory"); 274 | 275 | error_free_builtname_generic: 276 | free(builtname_generic); 277 | error_free_builtname: 278 | free(builtname); 279 | 280 | return ret; 281 | } 282 | 283 | /** 284 | * bsort_channel_array_by_index() - sort the array in index order 285 | * @ci_array: the iio_channel_info array to be sorted 286 | * @cnt: the amount of array elements 287 | **/ 288 | 289 | void bsort_channel_array_by_index(struct iio_channel_info *ci_array, int cnt) 290 | { 291 | struct iio_channel_info temp; 292 | int x, y; 293 | 294 | for (x = 0; x < cnt; x++) 295 | for (y = 0; y < (cnt - 1); y++) 296 | if (ci_array[y].index > ci_array[y + 1].index) { 297 | temp = ci_array[y + 1]; 298 | ci_array[y + 1] = ci_array[y]; 299 | ci_array[y] = temp; 300 | } 301 | } 302 | 303 | /** 304 | * build_channel_array() - function to figure out what channels are present 305 | * @device_dir: the IIO device directory in sysfs 306 | * @ci_array: output the resulting array of iio_channel_info 307 | * @counter: output the amount of array elements 308 | * 309 | * Returns 0 on success, otherwise a negative error code. 310 | **/ 311 | int build_channel_array(const char *device_dir, 312 | struct iio_channel_info **ci_array, int *counter) 313 | { 314 | DIR *dp; 315 | FILE *sysfsfp; 316 | int count = 0, i; 317 | struct iio_channel_info *current; 318 | int ret; 319 | const struct dirent *ent; 320 | char *scan_el_dir; 321 | char *filename; 322 | 323 | *counter = 0; 324 | ret = asprintf(&scan_el_dir, FORMAT_SCAN_ELEMENTS_DIR, device_dir); 325 | if (ret < 0) 326 | return -ENOMEM; 327 | 328 | dp = opendir(scan_el_dir); 329 | if (!dp) { 330 | ret = -errno; 331 | goto error_free_name; 332 | } 333 | 334 | while (ent = readdir(dp), ent) 335 | if (strcmp(ent->d_name + strlen(ent->d_name) - strlen("_en"), 336 | "_en") == 0) { 337 | ret = asprintf(&filename, 338 | "%s/%s", scan_el_dir, ent->d_name); 339 | if (ret < 0) { 340 | ret = -ENOMEM; 341 | goto error_close_dir; 342 | } 343 | 344 | sysfsfp = fopen(filename, "r"); 345 | if (!sysfsfp) { 346 | ret = -errno; 347 | free(filename); 348 | goto error_close_dir; 349 | } 350 | 351 | errno = 0; 352 | if (fscanf(sysfsfp, "%i", &ret) != 1) { 353 | ret = errno ? -errno : -ENODATA; 354 | if (fclose(sysfsfp)) 355 | perror("build_channel_array(): Failed to close file"); 356 | 357 | free(filename); 358 | goto error_close_dir; 359 | } 360 | if (ret == 1) 361 | (*counter)++; 362 | 363 | if (fclose(sysfsfp)) { 364 | ret = -errno; 365 | free(filename); 366 | goto error_close_dir; 367 | } 368 | 369 | free(filename); 370 | } 371 | 372 | *ci_array = malloc(sizeof(**ci_array) * (*counter)); 373 | if (!*ci_array) { 374 | ret = -ENOMEM; 375 | goto error_close_dir; 376 | } 377 | 378 | seekdir(dp, 0); 379 | while (ent = readdir(dp), ent) { 380 | if (strcmp(ent->d_name + strlen(ent->d_name) - strlen("_en"), 381 | "_en") == 0) { 382 | int current_enabled = 0; 383 | 384 | current = &(*ci_array)[count++]; 385 | ret = asprintf(&filename, 386 | "%s/%s", scan_el_dir, ent->d_name); 387 | if (ret < 0) { 388 | ret = -ENOMEM; 389 | /* decrement count to avoid freeing name */ 390 | count--; 391 | goto error_cleanup_array; 392 | } 393 | 394 | sysfsfp = fopen(filename, "r"); 395 | if (!sysfsfp) { 396 | ret = -errno; 397 | free(filename); 398 | count--; 399 | goto error_cleanup_array; 400 | } 401 | 402 | errno = 0; 403 | if (fscanf(sysfsfp, "%i", ¤t_enabled) != 1) { 404 | ret = errno ? -errno : -ENODATA; 405 | free(filename); 406 | count--; 407 | goto error_cleanup_array; 408 | } 409 | 410 | if (fclose(sysfsfp)) { 411 | ret = -errno; 412 | free(filename); 413 | count--; 414 | goto error_cleanup_array; 415 | } 416 | 417 | if (!current_enabled) { 418 | free(filename); 419 | count--; 420 | continue; 421 | } 422 | 423 | current->scale = 1.0; 424 | current->offset = 0; 425 | current->name = strndup(ent->d_name, 426 | strlen(ent->d_name) - 427 | strlen("_en")); 428 | if (!current->name) { 429 | free(filename); 430 | ret = -ENOMEM; 431 | count--; 432 | goto error_cleanup_array; 433 | } 434 | 435 | /* Get the generic and specific name elements */ 436 | ret = iioutils_break_up_name(current->name, 437 | ¤t->generic_name); 438 | if (ret) { 439 | free(filename); 440 | free(current->name); 441 | count--; 442 | goto error_cleanup_array; 443 | } 444 | 445 | ret = asprintf(&filename, 446 | "%s/%s_index", 447 | scan_el_dir, 448 | current->name); 449 | if (ret < 0) { 450 | free(filename); 451 | ret = -ENOMEM; 452 | goto error_cleanup_array; 453 | } 454 | 455 | sysfsfp = fopen(filename, "r"); 456 | if (!sysfsfp) { 457 | ret = -errno; 458 | fprintf(stderr, "failed to open %s\n", 459 | filename); 460 | free(filename); 461 | goto error_cleanup_array; 462 | } 463 | 464 | errno = 0; 465 | if (fscanf(sysfsfp, "%u", ¤t->index) != 1) { 466 | ret = errno ? -errno : -ENODATA; 467 | if (fclose(sysfsfp)) 468 | perror("build_channel_array(): Failed to close file"); 469 | 470 | free(filename); 471 | goto error_cleanup_array; 472 | } 473 | 474 | if (fclose(sysfsfp)) { 475 | ret = -errno; 476 | free(filename); 477 | goto error_cleanup_array; 478 | } 479 | 480 | free(filename); 481 | /* Find the scale */ 482 | ret = iioutils_get_param_float(¤t->scale, 483 | "scale", 484 | device_dir, 485 | current->name, 486 | current->generic_name); 487 | if ((ret < 0) && (ret != -ENOENT)) 488 | goto error_cleanup_array; 489 | 490 | ret = iioutils_get_param_float(¤t->offset, 491 | "offset", 492 | device_dir, 493 | current->name, 494 | current->generic_name); 495 | if ((ret < 0) && (ret != -ENOENT)) 496 | goto error_cleanup_array; 497 | 498 | ret = iioutils_get_type(¤t->is_signed, 499 | ¤t->bytes, 500 | ¤t->bits_used, 501 | ¤t->shift, 502 | ¤t->mask, 503 | ¤t->be, 504 | device_dir, 505 | current->name, 506 | current->generic_name); 507 | if (ret < 0) 508 | goto error_cleanup_array; 509 | } 510 | } 511 | 512 | if (closedir(dp) == -1) { 513 | ret = -errno; 514 | goto error_cleanup_array; 515 | } 516 | 517 | free(scan_el_dir); 518 | /* reorder so that the array is in index order */ 519 | bsort_channel_array_by_index(*ci_array, *counter); 520 | 521 | return 0; 522 | 523 | error_cleanup_array: 524 | for (i = count - 1; i >= 0; i--) { 525 | free((*ci_array)[i].name); 526 | free((*ci_array)[i].generic_name); 527 | } 528 | free(*ci_array); 529 | *ci_array = NULL; 530 | *counter = 0; 531 | error_close_dir: 532 | if (dp) 533 | if (closedir(dp) == -1) 534 | perror("build_channel_array(): Failed to close dir"); 535 | 536 | error_free_name: 537 | free(scan_el_dir); 538 | 539 | return ret; 540 | } 541 | 542 | static int calc_digits(int num) 543 | { 544 | int count = 0; 545 | 546 | while (num != 0) { 547 | num /= 10; 548 | count++; 549 | } 550 | 551 | return count; 552 | } 553 | 554 | /** 555 | * find_type_by_name() - function to match top level types by name 556 | * @name: top level type instance name 557 | * @type: the type of top level instance being searched 558 | * 559 | * Returns the device number of a matched IIO device on success, otherwise a 560 | * negative error code. 561 | * Typical types this is used for are device and trigger. 562 | **/ 563 | int find_type_by_name(const char *name, const char *type) 564 | { 565 | const struct dirent *ent; 566 | int number, numstrlen, ret; 567 | 568 | FILE *namefp; 569 | DIR *dp; 570 | char thisname[IIO_MAX_NAME_LENGTH]; 571 | char *filename; 572 | 573 | dp = opendir(iio_dir); 574 | if (!dp) { 575 | fprintf(stderr, "No industrialio devices available\n"); 576 | return -ENODEV; 577 | } 578 | 579 | while (ent = readdir(dp), ent) { 580 | if (strcmp(ent->d_name, ".") != 0 && 581 | strcmp(ent->d_name, "..") != 0 && 582 | strlen(ent->d_name) > strlen(type) && 583 | strncmp(ent->d_name, type, strlen(type)) == 0) { 584 | errno = 0; 585 | ret = sscanf(ent->d_name + strlen(type), "%d", &number); 586 | if (ret < 0) { 587 | ret = -errno; 588 | fprintf(stderr, 589 | "failed to read element number\n"); 590 | goto error_close_dir; 591 | } else if (ret != 1) { 592 | ret = -EIO; 593 | fprintf(stderr, 594 | "failed to match element number\n"); 595 | goto error_close_dir; 596 | } 597 | 598 | numstrlen = calc_digits(number); 599 | /* verify the next character is not a colon */ 600 | if (strncmp(ent->d_name + strlen(type) + numstrlen, 601 | ":", 1) != 0) { 602 | filename = malloc(strlen(iio_dir) + strlen(type) 603 | + numstrlen + 6); 604 | if (!filename) { 605 | ret = -ENOMEM; 606 | goto error_close_dir; 607 | } 608 | 609 | ret = sprintf(filename, "%s%s%d/name", iio_dir, 610 | type, number); 611 | if (ret < 0) { 612 | free(filename); 613 | goto error_close_dir; 614 | } 615 | 616 | namefp = fopen(filename, "r"); 617 | if (!namefp) { 618 | free(filename); 619 | continue; 620 | } 621 | 622 | free(filename); 623 | errno = 0; 624 | if (fscanf(namefp, "%s", thisname) != 1) { 625 | ret = errno ? -errno : -ENODATA; 626 | goto error_close_dir; 627 | } 628 | 629 | if (fclose(namefp)) { 630 | ret = -errno; 631 | goto error_close_dir; 632 | } 633 | 634 | if (strcmp(name, thisname) == 0) { 635 | if (closedir(dp) == -1) 636 | return -errno; 637 | 638 | return number; 639 | } 640 | } 641 | } 642 | } 643 | if (closedir(dp) == -1) 644 | return -errno; 645 | 646 | return -ENODEV; 647 | 648 | error_close_dir: 649 | if (closedir(dp) == -1) 650 | perror("find_type_by_name(): Failed to close directory"); 651 | 652 | return ret; 653 | } 654 | 655 | static int _write_sysfs_int(const char *filename, const char *basedir, int val, 656 | int verify) 657 | { 658 | int ret = 0; 659 | FILE *sysfsfp; 660 | int test; 661 | char *temp = malloc(strlen(basedir) + strlen(filename) + 2); 662 | 663 | if (!temp) 664 | return -ENOMEM; 665 | 666 | ret = sprintf(temp, "%s/%s", basedir, filename); 667 | if (ret < 0) 668 | goto error_free; 669 | 670 | sysfsfp = fopen(temp, "w"); 671 | if (!sysfsfp) { 672 | ret = -errno; 673 | fprintf(stderr, "failed to open %s\n", temp); 674 | goto error_free; 675 | } 676 | 677 | ret = fprintf(sysfsfp, "%d", val); 678 | if (ret < 0) { 679 | if (fclose(sysfsfp)) 680 | perror("_write_sysfs_int(): Failed to close dir"); 681 | 682 | goto error_free; 683 | } 684 | 685 | if (fclose(sysfsfp)) { 686 | ret = -errno; 687 | goto error_free; 688 | } 689 | 690 | if (verify) { 691 | sysfsfp = fopen(temp, "r"); 692 | if (!sysfsfp) { 693 | ret = -errno; 694 | fprintf(stderr, "failed to open %s\n", temp); 695 | goto error_free; 696 | } 697 | 698 | if (fscanf(sysfsfp, "%d", &test) != 1) { 699 | ret = errno ? -errno : -ENODATA; 700 | if (fclose(sysfsfp)) 701 | perror("_write_sysfs_int(): Failed to close dir"); 702 | 703 | goto error_free; 704 | } 705 | 706 | if (fclose(sysfsfp)) { 707 | ret = -errno; 708 | goto error_free; 709 | } 710 | 711 | if (test != val) { 712 | fprintf(stderr, 713 | "Possible failure in int write %d to %s/%s\n", 714 | val, basedir, filename); 715 | ret = -1; 716 | } 717 | } 718 | 719 | error_free: 720 | free(temp); 721 | return ret; 722 | } 723 | 724 | /** 725 | * write_sysfs_int() - write an integer value to a sysfs file 726 | * @filename: name of the file to write to 727 | * @basedir: the sysfs directory in which the file is to be found 728 | * @val: integer value to write to file 729 | * 730 | * Returns a value >= 0 on success, otherwise a negative error code. 731 | **/ 732 | int write_sysfs_int(const char *filename, const char *basedir, int val) 733 | { 734 | return _write_sysfs_int(filename, basedir, val, 0); 735 | } 736 | 737 | /** 738 | * write_sysfs_int_and_verify() - write an integer value to a sysfs file 739 | * and verify 740 | * @filename: name of the file to write to 741 | * @basedir: the sysfs directory in which the file is to be found 742 | * @val: integer value to write to file 743 | * 744 | * Returns a value >= 0 on success, otherwise a negative error code. 745 | **/ 746 | int write_sysfs_int_and_verify(const char *filename, const char *basedir, 747 | int val) 748 | { 749 | return _write_sysfs_int(filename, basedir, val, 1); 750 | } 751 | 752 | static int _write_sysfs_string(const char *filename, const char *basedir, 753 | const char *val, int verify) 754 | { 755 | int ret = 0; 756 | FILE *sysfsfp; 757 | char *temp = malloc(strlen(basedir) + strlen(filename) + 2); 758 | 759 | if (!temp) { 760 | fprintf(stderr, "Memory allocation failed\n"); 761 | return -ENOMEM; 762 | } 763 | 764 | ret = sprintf(temp, "%s/%s", basedir, filename); 765 | if (ret < 0) 766 | goto error_free; 767 | 768 | sysfsfp = fopen(temp, "w"); 769 | if (!sysfsfp) { 770 | ret = -errno; 771 | fprintf(stderr, "Could not open %s\n", temp); 772 | goto error_free; 773 | } 774 | 775 | ret = fprintf(sysfsfp, "%s", val); 776 | if (ret < 0) { 777 | if (fclose(sysfsfp)) 778 | perror("_write_sysfs_string(): Failed to close dir"); 779 | 780 | goto error_free; 781 | } 782 | 783 | if (fclose(sysfsfp)) { 784 | ret = -errno; 785 | goto error_free; 786 | } 787 | 788 | if (verify) { 789 | sysfsfp = fopen(temp, "r"); 790 | if (!sysfsfp) { 791 | ret = -errno; 792 | fprintf(stderr, "Could not open file to verify\n"); 793 | goto error_free; 794 | } 795 | 796 | if (fscanf(sysfsfp, "%s", temp) != 1) { 797 | ret = errno ? -errno : -ENODATA; 798 | if (fclose(sysfsfp)) 799 | perror("_write_sysfs_string(): Failed to close dir"); 800 | 801 | goto error_free; 802 | } 803 | 804 | if (fclose(sysfsfp)) { 805 | ret = -errno; 806 | goto error_free; 807 | } 808 | 809 | if (strcmp(temp, val) != 0) { 810 | fprintf(stderr, 811 | "Possible failure in string write of %s " 812 | "Should be %s written to %s/%s\n", temp, val, 813 | basedir, filename); 814 | ret = -1; 815 | } 816 | } 817 | 818 | error_free: 819 | free(temp); 820 | 821 | return ret; 822 | } 823 | 824 | /** 825 | * write_sysfs_string_and_verify() - string write, readback and verify 826 | * @filename: name of file to write to 827 | * @basedir: the sysfs directory in which the file is to be found 828 | * @val: the string to write 829 | * 830 | * Returns a value >= 0 on success, otherwise a negative error code. 831 | **/ 832 | int write_sysfs_string_and_verify(const char *filename, const char *basedir, 833 | const char *val) 834 | { 835 | return _write_sysfs_string(filename, basedir, val, 1); 836 | } 837 | 838 | /** 839 | * write_sysfs_string() - write string to a sysfs file 840 | * @filename: name of file to write to 841 | * @basedir: the sysfs directory in which the file is to be found 842 | * @val: the string to write 843 | * 844 | * Returns a value >= 0 on success, otherwise a negative error code. 845 | **/ 846 | int write_sysfs_string(const char *filename, const char *basedir, 847 | const char *val) 848 | { 849 | return _write_sysfs_string(filename, basedir, val, 0); 850 | } 851 | 852 | /** 853 | * read_sysfs_posint() - read an integer value from file 854 | * @filename: name of file to read from 855 | * @basedir: the sysfs directory in which the file is to be found 856 | * 857 | * Returns the read integer value >= 0 on success, otherwise a negative error 858 | * code. 859 | **/ 860 | int read_sysfs_posint(const char *filename, const char *basedir) 861 | { 862 | int ret; 863 | FILE *sysfsfp; 864 | char *temp = malloc(strlen(basedir) + strlen(filename) + 2); 865 | 866 | if (!temp) { 867 | fprintf(stderr, "Memory allocation failed"); 868 | return -ENOMEM; 869 | } 870 | 871 | ret = sprintf(temp, "%s/%s", basedir, filename); 872 | if (ret < 0) 873 | goto error_free; 874 | 875 | sysfsfp = fopen(temp, "r"); 876 | if (!sysfsfp) { 877 | ret = -errno; 878 | goto error_free; 879 | } 880 | 881 | errno = 0; 882 | if (fscanf(sysfsfp, "%d\n", &ret) != 1) { 883 | ret = errno ? -errno : -ENODATA; 884 | if (fclose(sysfsfp)) 885 | perror("read_sysfs_posint(): Failed to close dir"); 886 | 887 | goto error_free; 888 | } 889 | 890 | if (fclose(sysfsfp)) 891 | ret = -errno; 892 | 893 | error_free: 894 | free(temp); 895 | 896 | return ret; 897 | } 898 | 899 | /** 900 | * read_sysfs_float() - read a float value from file 901 | * @filename: name of file to read from 902 | * @basedir: the sysfs directory in which the file is to be found 903 | * @val: output the read float value 904 | * 905 | * Returns a value >= 0 on success, otherwise a negative error code. 906 | **/ 907 | int read_sysfs_float(const char *filename, const char *basedir, float *val) 908 | { 909 | int ret = 0; 910 | FILE *sysfsfp; 911 | char *temp = malloc(strlen(basedir) + strlen(filename) + 2); 912 | 913 | if (!temp) { 914 | fprintf(stderr, "Memory allocation failed"); 915 | return -ENOMEM; 916 | } 917 | 918 | ret = sprintf(temp, "%s/%s", basedir, filename); 919 | if (ret < 0) 920 | goto error_free; 921 | 922 | sysfsfp = fopen(temp, "r"); 923 | if (!sysfsfp) { 924 | ret = -errno; 925 | goto error_free; 926 | } 927 | 928 | errno = 0; 929 | if (fscanf(sysfsfp, "%f\n", val) != 1) { 930 | ret = errno ? -errno : -ENODATA; 931 | if (fclose(sysfsfp)) 932 | perror("read_sysfs_float(): Failed to close dir"); 933 | 934 | goto error_free; 935 | } 936 | 937 | if (fclose(sysfsfp)) 938 | ret = -errno; 939 | 940 | error_free: 941 | free(temp); 942 | 943 | return ret; 944 | } 945 | 946 | /** 947 | * read_sysfs_string() - read a string from file 948 | * @filename: name of file to read from 949 | * @basedir: the sysfs directory in which the file is to be found 950 | * @str: output the read string 951 | * 952 | * Returns a value >= 0 on success, otherwise a negative error code. 953 | **/ 954 | int read_sysfs_string(const char *filename, const char *basedir, char *str) 955 | { 956 | int ret = 0; 957 | FILE *sysfsfp; 958 | char *temp = malloc(strlen(basedir) + strlen(filename) + 2); 959 | 960 | if (!temp) { 961 | fprintf(stderr, "Memory allocation failed"); 962 | return -ENOMEM; 963 | } 964 | 965 | ret = sprintf(temp, "%s/%s", basedir, filename); 966 | if (ret < 0) 967 | goto error_free; 968 | 969 | sysfsfp = fopen(temp, "r"); 970 | if (!sysfsfp) { 971 | ret = -errno; 972 | goto error_free; 973 | } 974 | 975 | errno = 0; 976 | if (fscanf(sysfsfp, "%s\n", str) != 1) { 977 | ret = errno ? -errno : -ENODATA; 978 | if (fclose(sysfsfp)) 979 | perror("read_sysfs_string(): Failed to close dir"); 980 | 981 | goto error_free; 982 | } 983 | 984 | if (fclose(sysfsfp)) 985 | ret = -errno; 986 | 987 | error_free: 988 | free(temp); 989 | 990 | return ret; 991 | } 992 | -------------------------------------------------------------------------------- /35.1/app/iio_utils.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0-only */ 2 | #ifndef _IIO_UTILS_H_ 3 | #define _IIO_UTILS_H_ 4 | 5 | /* IIO - useful set of util functionality 6 | * 7 | * Copyright (c) 2008 Jonathan Cameron 8 | */ 9 | 10 | #include 11 | 12 | /* Made up value to limit allocation sizes */ 13 | #define IIO_MAX_NAME_LENGTH 64 14 | 15 | #define FORMAT_SCAN_ELEMENTS_DIR "%s/scan_elements" 16 | #define FORMAT_TYPE_FILE "%s_type" 17 | 18 | #define ARRAY_SIZE(arr) (sizeof(arr) / sizeof(arr[0])) 19 | 20 | extern const char *iio_dir; 21 | 22 | /** 23 | * struct iio_channel_info - information about a given channel 24 | * @name: channel name 25 | * @generic_name: general name for channel type 26 | * @scale: scale factor to be applied for conversion to si units 27 | * @offset: offset to be applied for conversion to si units 28 | * @index: the channel index in the buffer output 29 | * @bytes: number of bytes occupied in buffer output 30 | * @bits_used: number of valid bits of data 31 | * @shift: amount of bits to shift right data before applying bit mask 32 | * @mask: a bit mask for the raw output 33 | * @be: flag if data is big endian 34 | * @is_signed: is the raw value stored signed 35 | * @location: data offset for this channel inside the buffer (in bytes) 36 | **/ 37 | struct iio_channel_info { 38 | char *name; 39 | char *generic_name; 40 | float scale; 41 | float offset; 42 | unsigned index; 43 | unsigned bytes; 44 | unsigned bits_used; 45 | unsigned shift; 46 | uint64_t mask; 47 | unsigned be; 48 | unsigned is_signed; 49 | unsigned location; 50 | }; 51 | 52 | static inline int iioutils_check_suffix(const char *str, const char *suffix) 53 | { 54 | return strlen(str) >= strlen(suffix) && 55 | strncmp(str+strlen(str)-strlen(suffix), 56 | suffix, strlen(suffix)) == 0; 57 | } 58 | 59 | int iioutils_break_up_name(const char *full_name, char **generic_name); 60 | int iioutils_get_type(unsigned *is_signed, unsigned *bytes, unsigned *bits_used, 61 | unsigned *shift, uint64_t *mask, unsigned *be, 62 | const char *device_dir, const char *name, 63 | const char *generic_name); 64 | int iioutils_get_param_float(float *output, const char *param_name, 65 | const char *device_dir, const char *name, 66 | const char *generic_name); 67 | void bsort_channel_array_by_index(struct iio_channel_info *ci_array, int cnt); 68 | int build_channel_array(const char *device_dir, 69 | struct iio_channel_info **ci_array, int *counter); 70 | int find_type_by_name(const char *name, const char *type); 71 | int write_sysfs_int(const char *filename, const char *basedir, int val); 72 | int write_sysfs_int_and_verify(const char *filename, const char *basedir, 73 | int val); 74 | int write_sysfs_string_and_verify(const char *filename, const char *basedir, 75 | const char *val); 76 | int write_sysfs_string(const char *filename, const char *basedir, 77 | const char *val); 78 | int read_sysfs_posint(const char *filename, const char *basedir); 79 | int read_sysfs_float(const char *filename, const char *basedir, float *val); 80 | int read_sysfs_string(const char *filename, const char *basedir, char *str); 81 | 82 | #endif /* _IIO_UTILS_H_ */ 83 | -------------------------------------------------------------------------------- /35.1/binary/bmi088.ko: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LPXingxing/LI-AR0234CS-STEREO-GMSL2/f4455da7dc1c05b3b235903f521104db219a6acc/35.1/binary/bmi088.ko -------------------------------------------------------------------------------- /35.1/binary/max96712.ko: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LPXingxing/LI-AR0234CS-STEREO-GMSL2/f4455da7dc1c05b3b235903f521104db219a6acc/35.1/binary/max96712.ko -------------------------------------------------------------------------------- /35.1/binary/nv_ar0234.ko: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LPXingxing/LI-AR0234CS-STEREO-GMSL2/f4455da7dc1c05b3b235903f521104db219a6acc/35.1/binary/nv_ar0234.ko -------------------------------------------------------------------------------- /35.1/binary/tegra194-p2888-0001-p2822-0000.dtb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LPXingxing/LI-AR0234CS-STEREO-GMSL2/f4455da7dc1c05b3b235903f521104db219a6acc/35.1/binary/tegra194-p2888-0001-p2822-0000.dtb -------------------------------------------------------------------------------- /35.1/binary/tegra234-p3701-0000-p3737-0000.dtb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LPXingxing/LI-AR0234CS-STEREO-GMSL2/f4455da7dc1c05b3b235903f521104db219a6acc/35.1/binary/tegra234-p3701-0000-p3737-0000.dtb -------------------------------------------------------------------------------- /35.1/document/AR0234CS-STEREO-GMSL2-30-DUAL-R35.1-AGX-Orin-20221214_Driver_Guide.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LPXingxing/LI-AR0234CS-STEREO-GMSL2/f4455da7dc1c05b3b235903f521104db219a6acc/35.1/document/AR0234CS-STEREO-GMSL2-30-DUAL-R35.1-AGX-Orin-20221214_Driver_Guide.pdf -------------------------------------------------------------------------------- /35.2_GA/AR0234CS-STEREO-GMSL2-30-DUAL-R35.1-AGX-Orin-20221214_Driver_Guide.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LPXingxing/LI-AR0234CS-STEREO-GMSL2/f4455da7dc1c05b3b235903f521104db219a6acc/35.2_GA/AR0234CS-STEREO-GMSL2-30-DUAL-R35.1-AGX-Orin-20221214_Driver_Guide.pdf -------------------------------------------------------------------------------- /35.2_GA/app/Readme.txt: -------------------------------------------------------------------------------- 1 | gcc iio_utils.c iio_generic_buffer.c -o iio_generic_buffer 2 | 3 | 4 | sudo ./iio_generic_buffer -N 0 -g -a -c 100 5 | 6 | sudo ./iio_generic_buffer -N 1 -g -a -c 100 7 | 8 | sudo ./iio_generic_buffer -N 2 -g -a -c 100 9 | 10 | sudo ./iio_generic_buffer -N 3 -g -a -c 100 -------------------------------------------------------------------------------- /35.2_GA/app/iio_generic_buffer: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LPXingxing/LI-AR0234CS-STEREO-GMSL2/f4455da7dc1c05b3b235903f521104db219a6acc/35.2_GA/app/iio_generic_buffer -------------------------------------------------------------------------------- /35.2_GA/app/iio_generic_buffer.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0-only 2 | /* Industrialio buffer test code. 3 | * 4 | * Copyright (c) 2008 Jonathan Cameron 5 | * 6 | * This program is primarily intended as an example application. 7 | * Reads the current buffer setup from sysfs and starts a short capture 8 | * from the specified device, pretty printing the result after appropriate 9 | * conversion. 10 | * 11 | * Command line parameters 12 | * generic_buffer -n -t 13 | * If trigger name is not specified the program assumes you want a dataready 14 | * trigger associated with the device and goes looking for it. 15 | */ 16 | 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include "iio_utils.h" 34 | 35 | /** 36 | * enum autochan - state for the automatic channel enabling mechanism 37 | */ 38 | enum autochan { 39 | AUTOCHANNELS_DISABLED, 40 | AUTOCHANNELS_ENABLED, 41 | AUTOCHANNELS_ACTIVE, 42 | }; 43 | 44 | /** 45 | * size_from_channelarray() - calculate the storage size of a scan 46 | * @channels: the channel info array 47 | * @num_channels: number of channels 48 | * 49 | * Has the side effect of filling the channels[i].location values used 50 | * in processing the buffer output. 51 | **/ 52 | int size_from_channelarray(struct iio_channel_info *channels, int num_channels) 53 | { 54 | int bytes = 0; 55 | int i = 0; 56 | 57 | while (i < num_channels) { 58 | if (bytes % channels[i].bytes == 0) 59 | channels[i].location = bytes; 60 | else 61 | channels[i].location = bytes - bytes % channels[i].bytes 62 | + channels[i].bytes; 63 | 64 | bytes = channels[i].location + channels[i].bytes; 65 | i++; 66 | } 67 | 68 | return bytes; 69 | } 70 | 71 | void print1byte(uint8_t input, struct iio_channel_info *info) 72 | { 73 | /* 74 | * Shift before conversion to avoid sign extension 75 | * of left aligned data 76 | */ 77 | input >>= info->shift; 78 | input &= info->mask; 79 | if (info->is_signed) { 80 | int8_t val = (int8_t)(input << (8 - info->bits_used)) >> 81 | (8 - info->bits_used); 82 | printf("%05f ", ((float)val + info->offset) * info->scale); 83 | } else { 84 | printf("%05f ", ((float)input + info->offset) * info->scale); 85 | } 86 | } 87 | 88 | void print2byte(uint16_t input, struct iio_channel_info *info) 89 | { 90 | /* First swap if incorrect endian */ 91 | if (info->be) 92 | input = be16toh(input); 93 | else 94 | input = le16toh(input); 95 | 96 | /* 97 | * Shift before conversion to avoid sign extension 98 | * of left aligned data 99 | */ 100 | input >>= info->shift; 101 | input &= info->mask; 102 | if (info->is_signed) { 103 | int16_t val = (int16_t)(input << (16 - info->bits_used)) >> 104 | (16 - info->bits_used); 105 | printf("%05f ", ((float)val + info->offset) * info->scale); 106 | } else { 107 | printf("%05f ", ((float)input + info->offset) * info->scale); 108 | } 109 | } 110 | 111 | void print4byte(uint32_t input, struct iio_channel_info *info) 112 | { 113 | /* First swap if incorrect endian */ 114 | if (info->be) 115 | input = be32toh(input); 116 | else 117 | input = le32toh(input); 118 | 119 | /* 120 | * Shift before conversion to avoid sign extension 121 | * of left aligned data 122 | */ 123 | input >>= info->shift; 124 | input &= info->mask; 125 | if (info->is_signed) { 126 | int32_t val = (int32_t)(input << (32 - info->bits_used)) >> 127 | (32 - info->bits_used); 128 | printf("%05f ", ((float)val + info->offset) * info->scale); 129 | } else { 130 | printf("%05f ", ((float)input + info->offset) * info->scale); 131 | } 132 | } 133 | 134 | void print8byte(uint64_t input, struct iio_channel_info *info) 135 | { 136 | /* First swap if incorrect endian */ 137 | if (info->be) 138 | input = be64toh(input); 139 | else 140 | input = le64toh(input); 141 | 142 | /* 143 | * Shift before conversion to avoid sign extension 144 | * of left aligned data 145 | */ 146 | input >>= info->shift; 147 | input &= info->mask; 148 | if (info->is_signed) { 149 | int64_t val = (int64_t)(input << (64 - info->bits_used)) >> 150 | (64 - info->bits_used); 151 | /* special case for timestamp */ 152 | if (info->scale == 1.0f && info->offset == 0.0f) 153 | printf("%" PRId64 " ", val); 154 | else 155 | printf("%05f ", 156 | ((float)val + info->offset) * info->scale); 157 | } else { 158 | printf("%05f ", ((float)input + info->offset) * info->scale); 159 | } 160 | } 161 | 162 | /** 163 | * process_scan() - print out the values in SI units 164 | * @data: pointer to the start of the scan 165 | * @channels: information about the channels. 166 | * Note: size_from_channelarray must have been called first 167 | * to fill the location offsets. 168 | * @num_channels: number of channels 169 | **/ 170 | void process_scan(char *data, 171 | struct iio_channel_info *channels, 172 | int num_channels) 173 | { 174 | int k; 175 | 176 | for (k = 0; k < num_channels; k++) 177 | switch (channels[k].bytes) { 178 | /* only a few cases implemented so far */ 179 | case 1: 180 | print1byte(*(uint8_t *)(data + channels[k].location), 181 | &channels[k]); 182 | break; 183 | case 2: 184 | print2byte(*(uint16_t *)(data + channels[k].location), 185 | &channels[k]); 186 | break; 187 | case 4: 188 | print4byte(*(uint32_t *)(data + channels[k].location), 189 | &channels[k]); 190 | break; 191 | case 8: 192 | print8byte(*(uint64_t *)(data + channels[k].location), 193 | &channels[k]); 194 | break; 195 | default: 196 | break; 197 | } 198 | printf("\n"); 199 | } 200 | 201 | static int enable_disable_all_channels(char *dev_dir_name, int enable) 202 | { 203 | const struct dirent *ent; 204 | char scanelemdir[256]; 205 | DIR *dp; 206 | int ret; 207 | 208 | snprintf(scanelemdir, sizeof(scanelemdir), 209 | FORMAT_SCAN_ELEMENTS_DIR, dev_dir_name); 210 | scanelemdir[sizeof(scanelemdir)-1] = '\0'; 211 | 212 | dp = opendir(scanelemdir); 213 | if (!dp) { 214 | fprintf(stderr, "Enabling/disabling channels: can't open %s\n", 215 | scanelemdir); 216 | return -EIO; 217 | } 218 | 219 | ret = -ENOENT; 220 | while (ent = readdir(dp), ent) { 221 | if (iioutils_check_suffix(ent->d_name, "_en")) { 222 | printf("%sabling: %s\n", 223 | enable ? "En" : "Dis", 224 | ent->d_name); 225 | ret = write_sysfs_int(ent->d_name, scanelemdir, 226 | enable); 227 | if (ret < 0) 228 | fprintf(stderr, "Failed to enable/disable %s\n", 229 | ent->d_name); 230 | } 231 | } 232 | 233 | if (closedir(dp) == -1) { 234 | perror("Enabling/disabling channels: " 235 | "Failed to close directory"); 236 | return -errno; 237 | } 238 | return 0; 239 | } 240 | 241 | void print_usage(void) 242 | { 243 | fprintf(stderr, "Usage: generic_buffer [options]...\n" 244 | "Capture, convert and output data from IIO device buffer\n" 245 | " -a Auto-activate all available channels\n" 246 | " -A Force-activate ALL channels\n" 247 | " -c Do n conversions, or loop forever if n < 0\n" 248 | " -e Disable wait for event (new data)\n" 249 | " -g Use trigger-less mode\n" 250 | " -l Set buffer length to n samples\n" 251 | " --device-name -n \n" 252 | " --device-num -N \n" 253 | " Set device by name or number (mandatory)\n" 254 | " --trigger-name -t \n" 255 | " --trigger-num -T \n" 256 | " Set trigger by name or number\n" 257 | " -w Set delay between reads in us (event-less mode)\n"); 258 | } 259 | 260 | enum autochan autochannels = AUTOCHANNELS_DISABLED; 261 | char *dev_dir_name = NULL; 262 | char *buf_dir_name = NULL; 263 | bool current_trigger_set = false; 264 | 265 | void cleanup(void) 266 | { 267 | int ret; 268 | 269 | /* Disable trigger */ 270 | if (dev_dir_name && current_trigger_set) { 271 | /* Disconnect the trigger - just write a dummy name. */ 272 | ret = write_sysfs_string("trigger/current_trigger", 273 | dev_dir_name, "NULL"); 274 | if (ret < 0) 275 | fprintf(stderr, "Failed to disable trigger: %s\n", 276 | strerror(-ret)); 277 | current_trigger_set = false; 278 | } 279 | 280 | /* Disable buffer */ 281 | if (buf_dir_name) { 282 | ret = write_sysfs_int("enable", buf_dir_name, 0); 283 | if (ret < 0) 284 | fprintf(stderr, "Failed to disable buffer: %s\n", 285 | strerror(-ret)); 286 | } 287 | 288 | /* Disable channels if auto-enabled */ 289 | if (dev_dir_name && autochannels == AUTOCHANNELS_ACTIVE) { 290 | ret = enable_disable_all_channels(dev_dir_name, 0); 291 | if (ret) 292 | fprintf(stderr, "Failed to disable all channels\n"); 293 | autochannels = AUTOCHANNELS_DISABLED; 294 | } 295 | } 296 | 297 | void sig_handler(int signum) 298 | { 299 | fprintf(stderr, "Caught signal %d\n", signum); 300 | cleanup(); 301 | exit(-signum); 302 | } 303 | 304 | void register_cleanup(void) 305 | { 306 | struct sigaction sa = { .sa_handler = sig_handler }; 307 | const int signums[] = { SIGINT, SIGTERM, SIGABRT }; 308 | int ret, i; 309 | 310 | for (i = 0; i < ARRAY_SIZE(signums); ++i) { 311 | ret = sigaction(signums[i], &sa, NULL); 312 | if (ret) { 313 | perror("Failed to register signal handler"); 314 | exit(-1); 315 | } 316 | } 317 | } 318 | 319 | static const struct option longopts[] = { 320 | { "device-name", 1, 0, 'n' }, 321 | { "device-num", 1, 0, 'N' }, 322 | { "trigger-name", 1, 0, 't' }, 323 | { "trigger-num", 1, 0, 'T' }, 324 | { }, 325 | }; 326 | 327 | int main(int argc, char **argv) 328 | { 329 | long long num_loops = 2; 330 | unsigned long timedelay = 1000000; 331 | unsigned long buf_len = 128; 332 | 333 | ssize_t i; 334 | unsigned long long j; 335 | unsigned long toread; 336 | int ret, c; 337 | int fp = -1; 338 | 339 | int num_channels = 0; 340 | char *trigger_name = NULL, *device_name = NULL; 341 | 342 | char *data = NULL; 343 | ssize_t read_size; 344 | int dev_num = -1, trig_num = -1; 345 | char *buffer_access = NULL; 346 | int scan_size; 347 | int noevents = 0; 348 | int notrigger = 0; 349 | char *dummy; 350 | bool force_autochannels = false; 351 | 352 | struct iio_channel_info *channels = NULL; 353 | 354 | register_cleanup(); 355 | 356 | while ((c = getopt_long(argc, argv, "aAc:egl:n:N:t:T:w:?", longopts, 357 | NULL)) != -1) { 358 | switch (c) { 359 | case 'a': 360 | autochannels = AUTOCHANNELS_ENABLED; 361 | break; 362 | case 'A': 363 | autochannels = AUTOCHANNELS_ENABLED; 364 | force_autochannels = true; 365 | break; 366 | case 'c': 367 | errno = 0; 368 | num_loops = strtoll(optarg, &dummy, 10); 369 | if (errno) { 370 | ret = -errno; 371 | goto error; 372 | } 373 | 374 | break; 375 | case 'e': 376 | noevents = 1; 377 | break; 378 | case 'g': 379 | notrigger = 1; 380 | break; 381 | case 'l': 382 | errno = 0; 383 | buf_len = strtoul(optarg, &dummy, 10); 384 | if (errno) { 385 | ret = -errno; 386 | goto error; 387 | } 388 | 389 | break; 390 | case 'n': 391 | device_name = strdup(optarg); 392 | break; 393 | case 'N': 394 | errno = 0; 395 | dev_num = strtoul(optarg, &dummy, 10); 396 | if (errno) { 397 | ret = -errno; 398 | goto error; 399 | } 400 | break; 401 | case 't': 402 | trigger_name = strdup(optarg); 403 | break; 404 | case 'T': 405 | errno = 0; 406 | trig_num = strtoul(optarg, &dummy, 10); 407 | if (errno) 408 | return -errno; 409 | break; 410 | case 'w': 411 | errno = 0; 412 | timedelay = strtoul(optarg, &dummy, 10); 413 | if (errno) { 414 | ret = -errno; 415 | goto error; 416 | } 417 | break; 418 | case '?': 419 | print_usage(); 420 | ret = -1; 421 | goto error; 422 | } 423 | } 424 | 425 | /* Find the device requested */ 426 | if (dev_num < 0 && !device_name) { 427 | fprintf(stderr, "Device not set\n"); 428 | print_usage(); 429 | ret = -1; 430 | goto error; 431 | } else if (dev_num >= 0 && device_name) { 432 | fprintf(stderr, "Only one of --device-num or --device-name needs to be set\n"); 433 | print_usage(); 434 | ret = -1; 435 | goto error; 436 | } else if (dev_num < 0) { 437 | dev_num = find_type_by_name(device_name, "iio:device"); 438 | if (dev_num < 0) { 439 | fprintf(stderr, "Failed to find the %s\n", device_name); 440 | ret = dev_num; 441 | goto error; 442 | } 443 | } 444 | printf("iio device number being used is %d\n", dev_num); 445 | 446 | ret = asprintf(&dev_dir_name, "%siio:device%d", iio_dir, dev_num); 447 | if (ret < 0) 448 | return -ENOMEM; 449 | /* Fetch device_name if specified by number */ 450 | if (!device_name) { 451 | device_name = malloc(IIO_MAX_NAME_LENGTH); 452 | if (!device_name) { 453 | ret = -ENOMEM; 454 | goto error; 455 | } 456 | ret = read_sysfs_string("name", dev_dir_name, device_name); 457 | if (ret < 0) { 458 | fprintf(stderr, "Failed to read name of device %d\n", dev_num); 459 | goto error; 460 | } 461 | } 462 | 463 | if (notrigger) { 464 | printf("trigger-less mode selected\n"); 465 | } else if (trig_num >= 0) { 466 | char *trig_dev_name; 467 | ret = asprintf(&trig_dev_name, "%strigger%d", iio_dir, trig_num); 468 | if (ret < 0) { 469 | return -ENOMEM; 470 | } 471 | trigger_name = malloc(IIO_MAX_NAME_LENGTH); 472 | ret = read_sysfs_string("name", trig_dev_name, trigger_name); 473 | free(trig_dev_name); 474 | if (ret < 0) { 475 | fprintf(stderr, "Failed to read trigger%d name from\n", trig_num); 476 | return ret; 477 | } 478 | printf("iio trigger number being used is %d\n", trig_num); 479 | } else { 480 | if (!trigger_name) { 481 | /* 482 | * Build the trigger name. If it is device associated 483 | * its name is _dev[n] where n matches 484 | * the device number found above. 485 | */ 486 | ret = asprintf(&trigger_name, 487 | "%s-dev%d", device_name, dev_num); 488 | if (ret < 0) { 489 | ret = -ENOMEM; 490 | goto error; 491 | } 492 | } 493 | 494 | /* Look for this "-devN" trigger */ 495 | trig_num = find_type_by_name(trigger_name, "trigger"); 496 | if (trig_num < 0) { 497 | /* OK try the simpler "-trigger" suffix instead */ 498 | free(trigger_name); 499 | ret = asprintf(&trigger_name, 500 | "%s-trigger", device_name); 501 | if (ret < 0) { 502 | ret = -ENOMEM; 503 | goto error; 504 | } 505 | } 506 | 507 | trig_num = find_type_by_name(trigger_name, "trigger"); 508 | if (trig_num < 0) { 509 | fprintf(stderr, "Failed to find the trigger %s\n", 510 | trigger_name); 511 | ret = trig_num; 512 | goto error; 513 | } 514 | 515 | printf("iio trigger number being used is %d\n", trig_num); 516 | } 517 | 518 | /* 519 | * Parse the files in scan_elements to identify what channels are 520 | * present 521 | */ 522 | ret = build_channel_array(dev_dir_name, &channels, &num_channels); 523 | if (ret) { 524 | fprintf(stderr, "Problem reading scan element information\n" 525 | "diag %s\n", dev_dir_name); 526 | goto error; 527 | } 528 | if (num_channels && autochannels == AUTOCHANNELS_ENABLED && 529 | !force_autochannels) { 530 | fprintf(stderr, "Auto-channels selected but some channels " 531 | "are already activated in sysfs\n"); 532 | fprintf(stderr, "Proceeding without activating any channels\n"); 533 | } 534 | 535 | if ((!num_channels && autochannels == AUTOCHANNELS_ENABLED) || 536 | (autochannels == AUTOCHANNELS_ENABLED && force_autochannels)) { 537 | fprintf(stderr, "Enabling all channels\n"); 538 | 539 | ret = enable_disable_all_channels(dev_dir_name, 1); 540 | if (ret) { 541 | fprintf(stderr, "Failed to enable all channels\n"); 542 | goto error; 543 | } 544 | 545 | /* This flags that we need to disable the channels again */ 546 | autochannels = AUTOCHANNELS_ACTIVE; 547 | 548 | ret = build_channel_array(dev_dir_name, &channels, 549 | &num_channels); 550 | if (ret) { 551 | fprintf(stderr, "Problem reading scan element " 552 | "information\n" 553 | "diag %s\n", dev_dir_name); 554 | goto error; 555 | } 556 | if (!num_channels) { 557 | fprintf(stderr, "Still no channels after " 558 | "auto-enabling, giving up\n"); 559 | goto error; 560 | } 561 | } 562 | 563 | if (!num_channels && autochannels == AUTOCHANNELS_DISABLED) { 564 | fprintf(stderr, 565 | "No channels are enabled, we have nothing to scan.\n"); 566 | fprintf(stderr, "Enable channels manually in " 567 | FORMAT_SCAN_ELEMENTS_DIR 568 | "/*_en or pass -a to autoenable channels and " 569 | "try again.\n", dev_dir_name); 570 | ret = -ENOENT; 571 | goto error; 572 | } 573 | 574 | /* 575 | * Construct the directory name for the associated buffer. 576 | * As we know that the lis3l02dq has only one buffer this may 577 | * be built rather than found. 578 | */ 579 | ret = asprintf(&buf_dir_name, 580 | "%siio:device%d/buffer", iio_dir, dev_num); 581 | if (ret < 0) { 582 | ret = -ENOMEM; 583 | goto error; 584 | } 585 | 586 | if (!notrigger) { 587 | printf("%s %s\n", dev_dir_name, trigger_name); 588 | /* 589 | * Set the device trigger to be the data ready trigger found 590 | * above 591 | */ 592 | ret = write_sysfs_string_and_verify("trigger/current_trigger", 593 | dev_dir_name, 594 | trigger_name); 595 | if (ret < 0) { 596 | fprintf(stderr, 597 | "Failed to write current_trigger file\n"); 598 | goto error; 599 | } 600 | } 601 | 602 | /* Setup ring buffer parameters */ 603 | ret = write_sysfs_int("length", buf_dir_name, buf_len); 604 | if (ret < 0) 605 | goto error; 606 | 607 | /* Enable the buffer */ 608 | ret = write_sysfs_int("enable", buf_dir_name, 1); 609 | if (ret < 0) { 610 | fprintf(stderr, 611 | "Failed to enable buffer: %s\n", strerror(-ret)); 612 | goto error; 613 | } 614 | 615 | scan_size = size_from_channelarray(channels, num_channels); 616 | data = malloc(scan_size * buf_len); 617 | if (!data) { 618 | ret = -ENOMEM; 619 | goto error; 620 | } 621 | 622 | ret = asprintf(&buffer_access, "/dev/iio:device%d", dev_num); 623 | if (ret < 0) { 624 | ret = -ENOMEM; 625 | goto error; 626 | } 627 | 628 | /* Attempt to open non blocking the access dev */ 629 | fp = open(buffer_access, O_RDONLY | O_NONBLOCK); 630 | if (fp == -1) { /* TODO: If it isn't there make the node */ 631 | ret = -errno; 632 | fprintf(stderr, "Failed to open %s\n", buffer_access); 633 | goto error; 634 | } 635 | 636 | for (j = 0; j < num_loops || num_loops < 0; j++) { 637 | if (!noevents) { 638 | struct pollfd pfd = { 639 | .fd = fp, 640 | .events = POLLIN, 641 | }; 642 | 643 | ret = poll(&pfd, 1, -1); 644 | if (ret < 0) { 645 | ret = -errno; 646 | goto error; 647 | } else if (ret == 0) { 648 | continue; 649 | } 650 | 651 | toread = buf_len; 652 | } else { 653 | usleep(timedelay); 654 | toread = 64; 655 | } 656 | 657 | read_size = read(fp, data, toread * scan_size); 658 | if (read_size < 0) { 659 | if (errno == EAGAIN) { 660 | fprintf(stderr, "nothing available\n"); 661 | continue; 662 | } else { 663 | break; 664 | } 665 | } 666 | for (i = 0; i < read_size / scan_size; i++) 667 | process_scan(data + scan_size * i, channels, 668 | num_channels); 669 | } 670 | 671 | error: 672 | cleanup(); 673 | 674 | if (fp >= 0 && close(fp) == -1) 675 | perror("Failed to close buffer"); 676 | free(buffer_access); 677 | free(data); 678 | free(buf_dir_name); 679 | for (i = num_channels - 1; i >= 0; i--) { 680 | free(channels[i].name); 681 | free(channels[i].generic_name); 682 | } 683 | free(channels); 684 | free(trigger_name); 685 | free(device_name); 686 | free(dev_dir_name); 687 | 688 | return ret; 689 | } 690 | -------------------------------------------------------------------------------- /35.2_GA/app/iio_utils.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0-only 2 | /* IIO - useful set of util functionality 3 | * 4 | * Copyright (c) 2008 Jonathan Cameron 5 | */ 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include "iio_utils.h" 14 | 15 | const char *iio_dir = "/sys/bus/iio/devices/"; 16 | 17 | static char * const iio_direction[] = { 18 | "in", 19 | "out", 20 | }; 21 | 22 | /** 23 | * iioutils_break_up_name() - extract generic name from full channel name 24 | * @full_name: the full channel name 25 | * @generic_name: the output generic channel name 26 | * 27 | * Returns 0 on success, or a negative error code if string extraction failed. 28 | **/ 29 | int iioutils_break_up_name(const char *full_name, char **generic_name) 30 | { 31 | char *current; 32 | char *w, *r; 33 | char *working, *prefix = ""; 34 | int i, ret; 35 | 36 | for (i = 0; i < ARRAY_SIZE(iio_direction); i++) 37 | if (!strncmp(full_name, iio_direction[i], 38 | strlen(iio_direction[i]))) { 39 | prefix = iio_direction[i]; 40 | break; 41 | } 42 | 43 | current = strdup(full_name + strlen(prefix) + 1); 44 | if (!current) 45 | return -ENOMEM; 46 | 47 | working = strtok(current, "_\0"); 48 | if (!working) { 49 | free(current); 50 | return -EINVAL; 51 | } 52 | 53 | w = working; 54 | r = working; 55 | 56 | while (*r != '\0') { 57 | if (!isdigit(*r)) { 58 | *w = *r; 59 | w++; 60 | } 61 | 62 | r++; 63 | } 64 | *w = '\0'; 65 | ret = asprintf(generic_name, "%s_%s", prefix, working); 66 | free(current); 67 | 68 | return (ret == -1) ? -ENOMEM : 0; 69 | } 70 | 71 | /** 72 | * iioutils_get_type() - find and process _type attribute data 73 | * @is_signed: output whether channel is signed 74 | * @bytes: output how many bytes the channel storage occupies 75 | * @bits_used: output number of valid bits of data 76 | * @shift: output amount of bits to shift right data before applying bit mask 77 | * @mask: output a bit mask for the raw data 78 | * @be: output if data in big endian 79 | * @device_dir: the IIO device directory 80 | * @name: the channel name 81 | * @generic_name: the channel type name 82 | * 83 | * Returns a value >= 0 on success, otherwise a negative error code. 84 | **/ 85 | int iioutils_get_type(unsigned *is_signed, unsigned *bytes, unsigned *bits_used, 86 | unsigned *shift, uint64_t *mask, unsigned *be, 87 | const char *device_dir, const char *name, 88 | const char *generic_name) 89 | { 90 | FILE *sysfsfp; 91 | int ret; 92 | DIR *dp; 93 | char *scan_el_dir, *builtname, *builtname_generic, *filename = 0; 94 | char signchar, endianchar; 95 | unsigned padint; 96 | const struct dirent *ent; 97 | 98 | ret = asprintf(&scan_el_dir, FORMAT_SCAN_ELEMENTS_DIR, device_dir); 99 | if (ret < 0) 100 | return -ENOMEM; 101 | 102 | ret = asprintf(&builtname, FORMAT_TYPE_FILE, name); 103 | if (ret < 0) { 104 | ret = -ENOMEM; 105 | goto error_free_scan_el_dir; 106 | } 107 | ret = asprintf(&builtname_generic, FORMAT_TYPE_FILE, generic_name); 108 | if (ret < 0) { 109 | ret = -ENOMEM; 110 | goto error_free_builtname; 111 | } 112 | 113 | dp = opendir(scan_el_dir); 114 | if (!dp) { 115 | ret = -errno; 116 | goto error_free_builtname_generic; 117 | } 118 | 119 | ret = -ENOENT; 120 | while (ent = readdir(dp), ent) 121 | if ((strcmp(builtname, ent->d_name) == 0) || 122 | (strcmp(builtname_generic, ent->d_name) == 0)) { 123 | ret = asprintf(&filename, 124 | "%s/%s", scan_el_dir, ent->d_name); 125 | if (ret < 0) { 126 | ret = -ENOMEM; 127 | goto error_closedir; 128 | } 129 | 130 | sysfsfp = fopen(filename, "r"); 131 | if (!sysfsfp) { 132 | ret = -errno; 133 | fprintf(stderr, "failed to open %s\n", 134 | filename); 135 | goto error_free_filename; 136 | } 137 | 138 | ret = fscanf(sysfsfp, 139 | "%ce:%c%u/%u>>%u", 140 | &endianchar, 141 | &signchar, 142 | bits_used, 143 | &padint, shift); 144 | if (ret < 0) { 145 | ret = -errno; 146 | fprintf(stderr, 147 | "failed to pass scan type description\n"); 148 | goto error_close_sysfsfp; 149 | } else if (ret != 5) { 150 | ret = -EIO; 151 | fprintf(stderr, 152 | "scan type description didn't match\n"); 153 | goto error_close_sysfsfp; 154 | } 155 | 156 | *be = (endianchar == 'b'); 157 | *bytes = padint / 8; 158 | if (*bits_used == 64) 159 | *mask = ~(0ULL); 160 | else 161 | *mask = (1ULL << *bits_used) - 1ULL; 162 | 163 | *is_signed = (signchar == 's'); 164 | if (fclose(sysfsfp)) { 165 | ret = -errno; 166 | fprintf(stderr, "Failed to close %s\n", 167 | filename); 168 | goto error_free_filename; 169 | } 170 | 171 | sysfsfp = 0; 172 | free(filename); 173 | filename = 0; 174 | 175 | /* 176 | * Avoid having a more generic entry overwriting 177 | * the settings. 178 | */ 179 | if (strcmp(builtname, ent->d_name) == 0) 180 | break; 181 | } 182 | 183 | error_close_sysfsfp: 184 | if (sysfsfp) 185 | if (fclose(sysfsfp)) 186 | perror("iioutils_get_type(): Failed to close file"); 187 | 188 | error_free_filename: 189 | if (filename) 190 | free(filename); 191 | 192 | error_closedir: 193 | if (closedir(dp) == -1) 194 | perror("iioutils_get_type(): Failed to close directory"); 195 | 196 | error_free_builtname_generic: 197 | free(builtname_generic); 198 | error_free_builtname: 199 | free(builtname); 200 | error_free_scan_el_dir: 201 | free(scan_el_dir); 202 | 203 | return ret; 204 | } 205 | 206 | /** 207 | * iioutils_get_param_float() - read a float value from a channel parameter 208 | * @output: output the float value 209 | * @param_name: the parameter name to read 210 | * @device_dir: the IIO device directory in sysfs 211 | * @name: the channel name 212 | * @generic_name: the channel type name 213 | * 214 | * Returns a value >= 0 on success, otherwise a negative error code. 215 | **/ 216 | int iioutils_get_param_float(float *output, const char *param_name, 217 | const char *device_dir, const char *name, 218 | const char *generic_name) 219 | { 220 | FILE *sysfsfp; 221 | int ret; 222 | DIR *dp; 223 | char *builtname, *builtname_generic; 224 | char *filename = NULL; 225 | const struct dirent *ent; 226 | 227 | ret = asprintf(&builtname, "%s_%s", name, param_name); 228 | if (ret < 0) 229 | return -ENOMEM; 230 | 231 | ret = asprintf(&builtname_generic, 232 | "%s_%s", generic_name, param_name); 233 | if (ret < 0) { 234 | ret = -ENOMEM; 235 | goto error_free_builtname; 236 | } 237 | 238 | dp = opendir(device_dir); 239 | if (!dp) { 240 | ret = -errno; 241 | goto error_free_builtname_generic; 242 | } 243 | 244 | ret = -ENOENT; 245 | while (ent = readdir(dp), ent) 246 | if ((strcmp(builtname, ent->d_name) == 0) || 247 | (strcmp(builtname_generic, ent->d_name) == 0)) { 248 | ret = asprintf(&filename, 249 | "%s/%s", device_dir, ent->d_name); 250 | if (ret < 0) { 251 | ret = -ENOMEM; 252 | goto error_closedir; 253 | } 254 | 255 | sysfsfp = fopen(filename, "r"); 256 | if (!sysfsfp) { 257 | ret = -errno; 258 | goto error_free_filename; 259 | } 260 | 261 | errno = 0; 262 | if (fscanf(sysfsfp, "%f", output) != 1) 263 | ret = errno ? -errno : -ENODATA; 264 | 265 | break; 266 | } 267 | error_free_filename: 268 | if (filename) 269 | free(filename); 270 | 271 | error_closedir: 272 | if (closedir(dp) == -1) 273 | perror("iioutils_get_param_float(): Failed to close directory"); 274 | 275 | error_free_builtname_generic: 276 | free(builtname_generic); 277 | error_free_builtname: 278 | free(builtname); 279 | 280 | return ret; 281 | } 282 | 283 | /** 284 | * bsort_channel_array_by_index() - sort the array in index order 285 | * @ci_array: the iio_channel_info array to be sorted 286 | * @cnt: the amount of array elements 287 | **/ 288 | 289 | void bsort_channel_array_by_index(struct iio_channel_info *ci_array, int cnt) 290 | { 291 | struct iio_channel_info temp; 292 | int x, y; 293 | 294 | for (x = 0; x < cnt; x++) 295 | for (y = 0; y < (cnt - 1); y++) 296 | if (ci_array[y].index > ci_array[y + 1].index) { 297 | temp = ci_array[y + 1]; 298 | ci_array[y + 1] = ci_array[y]; 299 | ci_array[y] = temp; 300 | } 301 | } 302 | 303 | /** 304 | * build_channel_array() - function to figure out what channels are present 305 | * @device_dir: the IIO device directory in sysfs 306 | * @ci_array: output the resulting array of iio_channel_info 307 | * @counter: output the amount of array elements 308 | * 309 | * Returns 0 on success, otherwise a negative error code. 310 | **/ 311 | int build_channel_array(const char *device_dir, 312 | struct iio_channel_info **ci_array, int *counter) 313 | { 314 | DIR *dp; 315 | FILE *sysfsfp; 316 | int count = 0, i; 317 | struct iio_channel_info *current; 318 | int ret; 319 | const struct dirent *ent; 320 | char *scan_el_dir; 321 | char *filename; 322 | 323 | *counter = 0; 324 | ret = asprintf(&scan_el_dir, FORMAT_SCAN_ELEMENTS_DIR, device_dir); 325 | if (ret < 0) 326 | return -ENOMEM; 327 | 328 | dp = opendir(scan_el_dir); 329 | if (!dp) { 330 | ret = -errno; 331 | goto error_free_name; 332 | } 333 | 334 | while (ent = readdir(dp), ent) 335 | if (strcmp(ent->d_name + strlen(ent->d_name) - strlen("_en"), 336 | "_en") == 0) { 337 | ret = asprintf(&filename, 338 | "%s/%s", scan_el_dir, ent->d_name); 339 | if (ret < 0) { 340 | ret = -ENOMEM; 341 | goto error_close_dir; 342 | } 343 | 344 | sysfsfp = fopen(filename, "r"); 345 | if (!sysfsfp) { 346 | ret = -errno; 347 | free(filename); 348 | goto error_close_dir; 349 | } 350 | 351 | errno = 0; 352 | if (fscanf(sysfsfp, "%i", &ret) != 1) { 353 | ret = errno ? -errno : -ENODATA; 354 | if (fclose(sysfsfp)) 355 | perror("build_channel_array(): Failed to close file"); 356 | 357 | free(filename); 358 | goto error_close_dir; 359 | } 360 | if (ret == 1) 361 | (*counter)++; 362 | 363 | if (fclose(sysfsfp)) { 364 | ret = -errno; 365 | free(filename); 366 | goto error_close_dir; 367 | } 368 | 369 | free(filename); 370 | } 371 | 372 | *ci_array = malloc(sizeof(**ci_array) * (*counter)); 373 | if (!*ci_array) { 374 | ret = -ENOMEM; 375 | goto error_close_dir; 376 | } 377 | 378 | seekdir(dp, 0); 379 | while (ent = readdir(dp), ent) { 380 | if (strcmp(ent->d_name + strlen(ent->d_name) - strlen("_en"), 381 | "_en") == 0) { 382 | int current_enabled = 0; 383 | 384 | current = &(*ci_array)[count++]; 385 | ret = asprintf(&filename, 386 | "%s/%s", scan_el_dir, ent->d_name); 387 | if (ret < 0) { 388 | ret = -ENOMEM; 389 | /* decrement count to avoid freeing name */ 390 | count--; 391 | goto error_cleanup_array; 392 | } 393 | 394 | sysfsfp = fopen(filename, "r"); 395 | if (!sysfsfp) { 396 | ret = -errno; 397 | free(filename); 398 | count--; 399 | goto error_cleanup_array; 400 | } 401 | 402 | errno = 0; 403 | if (fscanf(sysfsfp, "%i", ¤t_enabled) != 1) { 404 | ret = errno ? -errno : -ENODATA; 405 | free(filename); 406 | count--; 407 | goto error_cleanup_array; 408 | } 409 | 410 | if (fclose(sysfsfp)) { 411 | ret = -errno; 412 | free(filename); 413 | count--; 414 | goto error_cleanup_array; 415 | } 416 | 417 | if (!current_enabled) { 418 | free(filename); 419 | count--; 420 | continue; 421 | } 422 | 423 | current->scale = 1.0; 424 | current->offset = 0; 425 | current->name = strndup(ent->d_name, 426 | strlen(ent->d_name) - 427 | strlen("_en")); 428 | if (!current->name) { 429 | free(filename); 430 | ret = -ENOMEM; 431 | count--; 432 | goto error_cleanup_array; 433 | } 434 | 435 | /* Get the generic and specific name elements */ 436 | ret = iioutils_break_up_name(current->name, 437 | ¤t->generic_name); 438 | if (ret) { 439 | free(filename); 440 | free(current->name); 441 | count--; 442 | goto error_cleanup_array; 443 | } 444 | 445 | ret = asprintf(&filename, 446 | "%s/%s_index", 447 | scan_el_dir, 448 | current->name); 449 | if (ret < 0) { 450 | free(filename); 451 | ret = -ENOMEM; 452 | goto error_cleanup_array; 453 | } 454 | 455 | sysfsfp = fopen(filename, "r"); 456 | if (!sysfsfp) { 457 | ret = -errno; 458 | fprintf(stderr, "failed to open %s\n", 459 | filename); 460 | free(filename); 461 | goto error_cleanup_array; 462 | } 463 | 464 | errno = 0; 465 | if (fscanf(sysfsfp, "%u", ¤t->index) != 1) { 466 | ret = errno ? -errno : -ENODATA; 467 | if (fclose(sysfsfp)) 468 | perror("build_channel_array(): Failed to close file"); 469 | 470 | free(filename); 471 | goto error_cleanup_array; 472 | } 473 | 474 | if (fclose(sysfsfp)) { 475 | ret = -errno; 476 | free(filename); 477 | goto error_cleanup_array; 478 | } 479 | 480 | free(filename); 481 | /* Find the scale */ 482 | ret = iioutils_get_param_float(¤t->scale, 483 | "scale", 484 | device_dir, 485 | current->name, 486 | current->generic_name); 487 | if ((ret < 0) && (ret != -ENOENT)) 488 | goto error_cleanup_array; 489 | 490 | ret = iioutils_get_param_float(¤t->offset, 491 | "offset", 492 | device_dir, 493 | current->name, 494 | current->generic_name); 495 | if ((ret < 0) && (ret != -ENOENT)) 496 | goto error_cleanup_array; 497 | 498 | ret = iioutils_get_type(¤t->is_signed, 499 | ¤t->bytes, 500 | ¤t->bits_used, 501 | ¤t->shift, 502 | ¤t->mask, 503 | ¤t->be, 504 | device_dir, 505 | current->name, 506 | current->generic_name); 507 | if (ret < 0) 508 | goto error_cleanup_array; 509 | } 510 | } 511 | 512 | if (closedir(dp) == -1) { 513 | ret = -errno; 514 | goto error_cleanup_array; 515 | } 516 | 517 | free(scan_el_dir); 518 | /* reorder so that the array is in index order */ 519 | bsort_channel_array_by_index(*ci_array, *counter); 520 | 521 | return 0; 522 | 523 | error_cleanup_array: 524 | for (i = count - 1; i >= 0; i--) { 525 | free((*ci_array)[i].name); 526 | free((*ci_array)[i].generic_name); 527 | } 528 | free(*ci_array); 529 | *ci_array = NULL; 530 | *counter = 0; 531 | error_close_dir: 532 | if (dp) 533 | if (closedir(dp) == -1) 534 | perror("build_channel_array(): Failed to close dir"); 535 | 536 | error_free_name: 537 | free(scan_el_dir); 538 | 539 | return ret; 540 | } 541 | 542 | static int calc_digits(int num) 543 | { 544 | int count = 0; 545 | 546 | while (num != 0) { 547 | num /= 10; 548 | count++; 549 | } 550 | 551 | return count; 552 | } 553 | 554 | /** 555 | * find_type_by_name() - function to match top level types by name 556 | * @name: top level type instance name 557 | * @type: the type of top level instance being searched 558 | * 559 | * Returns the device number of a matched IIO device on success, otherwise a 560 | * negative error code. 561 | * Typical types this is used for are device and trigger. 562 | **/ 563 | int find_type_by_name(const char *name, const char *type) 564 | { 565 | const struct dirent *ent; 566 | int number, numstrlen, ret; 567 | 568 | FILE *namefp; 569 | DIR *dp; 570 | char thisname[IIO_MAX_NAME_LENGTH]; 571 | char *filename; 572 | 573 | dp = opendir(iio_dir); 574 | if (!dp) { 575 | fprintf(stderr, "No industrialio devices available\n"); 576 | return -ENODEV; 577 | } 578 | 579 | while (ent = readdir(dp), ent) { 580 | if (strcmp(ent->d_name, ".") != 0 && 581 | strcmp(ent->d_name, "..") != 0 && 582 | strlen(ent->d_name) > strlen(type) && 583 | strncmp(ent->d_name, type, strlen(type)) == 0) { 584 | errno = 0; 585 | ret = sscanf(ent->d_name + strlen(type), "%d", &number); 586 | if (ret < 0) { 587 | ret = -errno; 588 | fprintf(stderr, 589 | "failed to read element number\n"); 590 | goto error_close_dir; 591 | } else if (ret != 1) { 592 | ret = -EIO; 593 | fprintf(stderr, 594 | "failed to match element number\n"); 595 | goto error_close_dir; 596 | } 597 | 598 | numstrlen = calc_digits(number); 599 | /* verify the next character is not a colon */ 600 | if (strncmp(ent->d_name + strlen(type) + numstrlen, 601 | ":", 1) != 0) { 602 | filename = malloc(strlen(iio_dir) + strlen(type) 603 | + numstrlen + 6); 604 | if (!filename) { 605 | ret = -ENOMEM; 606 | goto error_close_dir; 607 | } 608 | 609 | ret = sprintf(filename, "%s%s%d/name", iio_dir, 610 | type, number); 611 | if (ret < 0) { 612 | free(filename); 613 | goto error_close_dir; 614 | } 615 | 616 | namefp = fopen(filename, "r"); 617 | if (!namefp) { 618 | free(filename); 619 | continue; 620 | } 621 | 622 | free(filename); 623 | errno = 0; 624 | if (fscanf(namefp, "%s", thisname) != 1) { 625 | ret = errno ? -errno : -ENODATA; 626 | goto error_close_dir; 627 | } 628 | 629 | if (fclose(namefp)) { 630 | ret = -errno; 631 | goto error_close_dir; 632 | } 633 | 634 | if (strcmp(name, thisname) == 0) { 635 | if (closedir(dp) == -1) 636 | return -errno; 637 | 638 | return number; 639 | } 640 | } 641 | } 642 | } 643 | if (closedir(dp) == -1) 644 | return -errno; 645 | 646 | return -ENODEV; 647 | 648 | error_close_dir: 649 | if (closedir(dp) == -1) 650 | perror("find_type_by_name(): Failed to close directory"); 651 | 652 | return ret; 653 | } 654 | 655 | static int _write_sysfs_int(const char *filename, const char *basedir, int val, 656 | int verify) 657 | { 658 | int ret = 0; 659 | FILE *sysfsfp; 660 | int test; 661 | char *temp = malloc(strlen(basedir) + strlen(filename) + 2); 662 | 663 | if (!temp) 664 | return -ENOMEM; 665 | 666 | ret = sprintf(temp, "%s/%s", basedir, filename); 667 | if (ret < 0) 668 | goto error_free; 669 | 670 | sysfsfp = fopen(temp, "w"); 671 | if (!sysfsfp) { 672 | ret = -errno; 673 | fprintf(stderr, "failed to open %s\n", temp); 674 | goto error_free; 675 | } 676 | 677 | ret = fprintf(sysfsfp, "%d", val); 678 | if (ret < 0) { 679 | if (fclose(sysfsfp)) 680 | perror("_write_sysfs_int(): Failed to close dir"); 681 | 682 | goto error_free; 683 | } 684 | 685 | if (fclose(sysfsfp)) { 686 | ret = -errno; 687 | goto error_free; 688 | } 689 | 690 | if (verify) { 691 | sysfsfp = fopen(temp, "r"); 692 | if (!sysfsfp) { 693 | ret = -errno; 694 | fprintf(stderr, "failed to open %s\n", temp); 695 | goto error_free; 696 | } 697 | 698 | if (fscanf(sysfsfp, "%d", &test) != 1) { 699 | ret = errno ? -errno : -ENODATA; 700 | if (fclose(sysfsfp)) 701 | perror("_write_sysfs_int(): Failed to close dir"); 702 | 703 | goto error_free; 704 | } 705 | 706 | if (fclose(sysfsfp)) { 707 | ret = -errno; 708 | goto error_free; 709 | } 710 | 711 | if (test != val) { 712 | fprintf(stderr, 713 | "Possible failure in int write %d to %s/%s\n", 714 | val, basedir, filename); 715 | ret = -1; 716 | } 717 | } 718 | 719 | error_free: 720 | free(temp); 721 | return ret; 722 | } 723 | 724 | /** 725 | * write_sysfs_int() - write an integer value to a sysfs file 726 | * @filename: name of the file to write to 727 | * @basedir: the sysfs directory in which the file is to be found 728 | * @val: integer value to write to file 729 | * 730 | * Returns a value >= 0 on success, otherwise a negative error code. 731 | **/ 732 | int write_sysfs_int(const char *filename, const char *basedir, int val) 733 | { 734 | return _write_sysfs_int(filename, basedir, val, 0); 735 | } 736 | 737 | /** 738 | * write_sysfs_int_and_verify() - write an integer value to a sysfs file 739 | * and verify 740 | * @filename: name of the file to write to 741 | * @basedir: the sysfs directory in which the file is to be found 742 | * @val: integer value to write to file 743 | * 744 | * Returns a value >= 0 on success, otherwise a negative error code. 745 | **/ 746 | int write_sysfs_int_and_verify(const char *filename, const char *basedir, 747 | int val) 748 | { 749 | return _write_sysfs_int(filename, basedir, val, 1); 750 | } 751 | 752 | static int _write_sysfs_string(const char *filename, const char *basedir, 753 | const char *val, int verify) 754 | { 755 | int ret = 0; 756 | FILE *sysfsfp; 757 | char *temp = malloc(strlen(basedir) + strlen(filename) + 2); 758 | 759 | if (!temp) { 760 | fprintf(stderr, "Memory allocation failed\n"); 761 | return -ENOMEM; 762 | } 763 | 764 | ret = sprintf(temp, "%s/%s", basedir, filename); 765 | if (ret < 0) 766 | goto error_free; 767 | 768 | sysfsfp = fopen(temp, "w"); 769 | if (!sysfsfp) { 770 | ret = -errno; 771 | fprintf(stderr, "Could not open %s\n", temp); 772 | goto error_free; 773 | } 774 | 775 | ret = fprintf(sysfsfp, "%s", val); 776 | if (ret < 0) { 777 | if (fclose(sysfsfp)) 778 | perror("_write_sysfs_string(): Failed to close dir"); 779 | 780 | goto error_free; 781 | } 782 | 783 | if (fclose(sysfsfp)) { 784 | ret = -errno; 785 | goto error_free; 786 | } 787 | 788 | if (verify) { 789 | sysfsfp = fopen(temp, "r"); 790 | if (!sysfsfp) { 791 | ret = -errno; 792 | fprintf(stderr, "Could not open file to verify\n"); 793 | goto error_free; 794 | } 795 | 796 | if (fscanf(sysfsfp, "%s", temp) != 1) { 797 | ret = errno ? -errno : -ENODATA; 798 | if (fclose(sysfsfp)) 799 | perror("_write_sysfs_string(): Failed to close dir"); 800 | 801 | goto error_free; 802 | } 803 | 804 | if (fclose(sysfsfp)) { 805 | ret = -errno; 806 | goto error_free; 807 | } 808 | 809 | if (strcmp(temp, val) != 0) { 810 | fprintf(stderr, 811 | "Possible failure in string write of %s " 812 | "Should be %s written to %s/%s\n", temp, val, 813 | basedir, filename); 814 | ret = -1; 815 | } 816 | } 817 | 818 | error_free: 819 | free(temp); 820 | 821 | return ret; 822 | } 823 | 824 | /** 825 | * write_sysfs_string_and_verify() - string write, readback and verify 826 | * @filename: name of file to write to 827 | * @basedir: the sysfs directory in which the file is to be found 828 | * @val: the string to write 829 | * 830 | * Returns a value >= 0 on success, otherwise a negative error code. 831 | **/ 832 | int write_sysfs_string_and_verify(const char *filename, const char *basedir, 833 | const char *val) 834 | { 835 | return _write_sysfs_string(filename, basedir, val, 1); 836 | } 837 | 838 | /** 839 | * write_sysfs_string() - write string to a sysfs file 840 | * @filename: name of file to write to 841 | * @basedir: the sysfs directory in which the file is to be found 842 | * @val: the string to write 843 | * 844 | * Returns a value >= 0 on success, otherwise a negative error code. 845 | **/ 846 | int write_sysfs_string(const char *filename, const char *basedir, 847 | const char *val) 848 | { 849 | return _write_sysfs_string(filename, basedir, val, 0); 850 | } 851 | 852 | /** 853 | * read_sysfs_posint() - read an integer value from file 854 | * @filename: name of file to read from 855 | * @basedir: the sysfs directory in which the file is to be found 856 | * 857 | * Returns the read integer value >= 0 on success, otherwise a negative error 858 | * code. 859 | **/ 860 | int read_sysfs_posint(const char *filename, const char *basedir) 861 | { 862 | int ret; 863 | FILE *sysfsfp; 864 | char *temp = malloc(strlen(basedir) + strlen(filename) + 2); 865 | 866 | if (!temp) { 867 | fprintf(stderr, "Memory allocation failed"); 868 | return -ENOMEM; 869 | } 870 | 871 | ret = sprintf(temp, "%s/%s", basedir, filename); 872 | if (ret < 0) 873 | goto error_free; 874 | 875 | sysfsfp = fopen(temp, "r"); 876 | if (!sysfsfp) { 877 | ret = -errno; 878 | goto error_free; 879 | } 880 | 881 | errno = 0; 882 | if (fscanf(sysfsfp, "%d\n", &ret) != 1) { 883 | ret = errno ? -errno : -ENODATA; 884 | if (fclose(sysfsfp)) 885 | perror("read_sysfs_posint(): Failed to close dir"); 886 | 887 | goto error_free; 888 | } 889 | 890 | if (fclose(sysfsfp)) 891 | ret = -errno; 892 | 893 | error_free: 894 | free(temp); 895 | 896 | return ret; 897 | } 898 | 899 | /** 900 | * read_sysfs_float() - read a float value from file 901 | * @filename: name of file to read from 902 | * @basedir: the sysfs directory in which the file is to be found 903 | * @val: output the read float value 904 | * 905 | * Returns a value >= 0 on success, otherwise a negative error code. 906 | **/ 907 | int read_sysfs_float(const char *filename, const char *basedir, float *val) 908 | { 909 | int ret = 0; 910 | FILE *sysfsfp; 911 | char *temp = malloc(strlen(basedir) + strlen(filename) + 2); 912 | 913 | if (!temp) { 914 | fprintf(stderr, "Memory allocation failed"); 915 | return -ENOMEM; 916 | } 917 | 918 | ret = sprintf(temp, "%s/%s", basedir, filename); 919 | if (ret < 0) 920 | goto error_free; 921 | 922 | sysfsfp = fopen(temp, "r"); 923 | if (!sysfsfp) { 924 | ret = -errno; 925 | goto error_free; 926 | } 927 | 928 | errno = 0; 929 | if (fscanf(sysfsfp, "%f\n", val) != 1) { 930 | ret = errno ? -errno : -ENODATA; 931 | if (fclose(sysfsfp)) 932 | perror("read_sysfs_float(): Failed to close dir"); 933 | 934 | goto error_free; 935 | } 936 | 937 | if (fclose(sysfsfp)) 938 | ret = -errno; 939 | 940 | error_free: 941 | free(temp); 942 | 943 | return ret; 944 | } 945 | 946 | /** 947 | * read_sysfs_string() - read a string from file 948 | * @filename: name of file to read from 949 | * @basedir: the sysfs directory in which the file is to be found 950 | * @str: output the read string 951 | * 952 | * Returns a value >= 0 on success, otherwise a negative error code. 953 | **/ 954 | int read_sysfs_string(const char *filename, const char *basedir, char *str) 955 | { 956 | int ret = 0; 957 | FILE *sysfsfp; 958 | char *temp = malloc(strlen(basedir) + strlen(filename) + 2); 959 | 960 | if (!temp) { 961 | fprintf(stderr, "Memory allocation failed"); 962 | return -ENOMEM; 963 | } 964 | 965 | ret = sprintf(temp, "%s/%s", basedir, filename); 966 | if (ret < 0) 967 | goto error_free; 968 | 969 | sysfsfp = fopen(temp, "r"); 970 | if (!sysfsfp) { 971 | ret = -errno; 972 | goto error_free; 973 | } 974 | 975 | errno = 0; 976 | if (fscanf(sysfsfp, "%s\n", str) != 1) { 977 | ret = errno ? -errno : -ENODATA; 978 | if (fclose(sysfsfp)) 979 | perror("read_sysfs_string(): Failed to close dir"); 980 | 981 | goto error_free; 982 | } 983 | 984 | if (fclose(sysfsfp)) 985 | ret = -errno; 986 | 987 | error_free: 988 | free(temp); 989 | 990 | return ret; 991 | } 992 | -------------------------------------------------------------------------------- /35.2_GA/app/iio_utils.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0-only */ 2 | #ifndef _IIO_UTILS_H_ 3 | #define _IIO_UTILS_H_ 4 | 5 | /* IIO - useful set of util functionality 6 | * 7 | * Copyright (c) 2008 Jonathan Cameron 8 | */ 9 | 10 | #include 11 | 12 | /* Made up value to limit allocation sizes */ 13 | #define IIO_MAX_NAME_LENGTH 64 14 | 15 | #define FORMAT_SCAN_ELEMENTS_DIR "%s/scan_elements" 16 | #define FORMAT_TYPE_FILE "%s_type" 17 | 18 | #define ARRAY_SIZE(arr) (sizeof(arr) / sizeof(arr[0])) 19 | 20 | extern const char *iio_dir; 21 | 22 | /** 23 | * struct iio_channel_info - information about a given channel 24 | * @name: channel name 25 | * @generic_name: general name for channel type 26 | * @scale: scale factor to be applied for conversion to si units 27 | * @offset: offset to be applied for conversion to si units 28 | * @index: the channel index in the buffer output 29 | * @bytes: number of bytes occupied in buffer output 30 | * @bits_used: number of valid bits of data 31 | * @shift: amount of bits to shift right data before applying bit mask 32 | * @mask: a bit mask for the raw output 33 | * @be: flag if data is big endian 34 | * @is_signed: is the raw value stored signed 35 | * @location: data offset for this channel inside the buffer (in bytes) 36 | **/ 37 | struct iio_channel_info { 38 | char *name; 39 | char *generic_name; 40 | float scale; 41 | float offset; 42 | unsigned index; 43 | unsigned bytes; 44 | unsigned bits_used; 45 | unsigned shift; 46 | uint64_t mask; 47 | unsigned be; 48 | unsigned is_signed; 49 | unsigned location; 50 | }; 51 | 52 | static inline int iioutils_check_suffix(const char *str, const char *suffix) 53 | { 54 | return strlen(str) >= strlen(suffix) && 55 | strncmp(str+strlen(str)-strlen(suffix), 56 | suffix, strlen(suffix)) == 0; 57 | } 58 | 59 | int iioutils_break_up_name(const char *full_name, char **generic_name); 60 | int iioutils_get_type(unsigned *is_signed, unsigned *bytes, unsigned *bits_used, 61 | unsigned *shift, uint64_t *mask, unsigned *be, 62 | const char *device_dir, const char *name, 63 | const char *generic_name); 64 | int iioutils_get_param_float(float *output, const char *param_name, 65 | const char *device_dir, const char *name, 66 | const char *generic_name); 67 | void bsort_channel_array_by_index(struct iio_channel_info *ci_array, int cnt); 68 | int build_channel_array(const char *device_dir, 69 | struct iio_channel_info **ci_array, int *counter); 70 | int find_type_by_name(const char *name, const char *type); 71 | int write_sysfs_int(const char *filename, const char *basedir, int val); 72 | int write_sysfs_int_and_verify(const char *filename, const char *basedir, 73 | int val); 74 | int write_sysfs_string_and_verify(const char *filename, const char *basedir, 75 | const char *val); 76 | int write_sysfs_string(const char *filename, const char *basedir, 77 | const char *val); 78 | int read_sysfs_posint(const char *filename, const char *basedir); 79 | int read_sysfs_float(const char *filename, const char *basedir, float *val); 80 | int read_sysfs_string(const char *filename, const char *basedir, char *str); 81 | 82 | #endif /* _IIO_UTILS_H_ */ 83 | -------------------------------------------------------------------------------- /35.2_GA/binary/bmi088.ko: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LPXingxing/LI-AR0234CS-STEREO-GMSL2/f4455da7dc1c05b3b235903f521104db219a6acc/35.2_GA/binary/bmi088.ko -------------------------------------------------------------------------------- /35.2_GA/binary/max96712.ko: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LPXingxing/LI-AR0234CS-STEREO-GMSL2/f4455da7dc1c05b3b235903f521104db219a6acc/35.2_GA/binary/max96712.ko -------------------------------------------------------------------------------- /35.2_GA/binary/nv_ar0234.ko: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LPXingxing/LI-AR0234CS-STEREO-GMSL2/f4455da7dc1c05b3b235903f521104db219a6acc/35.2_GA/binary/nv_ar0234.ko -------------------------------------------------------------------------------- /35.2_GA/binary/tegra194-p2888-0001-p2822-0000.dtb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LPXingxing/LI-AR0234CS-STEREO-GMSL2/f4455da7dc1c05b3b235903f521104db219a6acc/35.2_GA/binary/tegra194-p2888-0001-p2822-0000.dtb -------------------------------------------------------------------------------- /35.2_GA/binary/tegra234-p3701-0000-p3737-0000.dtb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LPXingxing/LI-AR0234CS-STEREO-GMSL2/f4455da7dc1c05b3b235903f521104db219a6acc/35.2_GA/binary/tegra234-p3701-0000-p3737-0000.dtb -------------------------------------------------------------------------------- /35.3.1/AR0234CS-GMSL2-STEREO-R35.3.1-AGX-ORIN-20230505_Driver_Guide.docx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LPXingxing/LI-AR0234CS-STEREO-GMSL2/f4455da7dc1c05b3b235903f521104db219a6acc/35.3.1/AR0234CS-GMSL2-STEREO-R35.3.1-AGX-ORIN-20230505_Driver_Guide.docx -------------------------------------------------------------------------------- /35.3.1/app/Readme.txt: -------------------------------------------------------------------------------- 1 | gcc iio_utils.c iio_generic_buffer.c -o iio_generic_buffer 2 | 3 | 4 | sudo ./iio_generic_buffer -N 0 -g -a -c 100 5 | 6 | sudo ./iio_generic_buffer -N 1 -g -a -c 100 7 | 8 | sudo ./iio_generic_buffer -N 2 -g -a -c 100 9 | 10 | sudo ./iio_generic_buffer -N 3 -g -a -c 100 -------------------------------------------------------------------------------- /35.3.1/app/iio_generic_buffer: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LPXingxing/LI-AR0234CS-STEREO-GMSL2/f4455da7dc1c05b3b235903f521104db219a6acc/35.3.1/app/iio_generic_buffer -------------------------------------------------------------------------------- /35.3.1/app/iio_generic_buffer.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0-only 2 | /* Industrialio buffer test code. 3 | * 4 | * Copyright (c) 2008 Jonathan Cameron 5 | * 6 | * This program is primarily intended as an example application. 7 | * Reads the current buffer setup from sysfs and starts a short capture 8 | * from the specified device, pretty printing the result after appropriate 9 | * conversion. 10 | * 11 | * Command line parameters 12 | * generic_buffer -n -t 13 | * If trigger name is not specified the program assumes you want a dataready 14 | * trigger associated with the device and goes looking for it. 15 | */ 16 | 17 | #include 18 | #include 19 | #include 20 | #include 21 | #include 22 | #include 23 | #include 24 | #include 25 | #include 26 | #include 27 | #include 28 | #include 29 | #include 30 | #include 31 | #include 32 | #include 33 | #include "iio_utils.h" 34 | 35 | /** 36 | * enum autochan - state for the automatic channel enabling mechanism 37 | */ 38 | enum autochan { 39 | AUTOCHANNELS_DISABLED, 40 | AUTOCHANNELS_ENABLED, 41 | AUTOCHANNELS_ACTIVE, 42 | }; 43 | 44 | /** 45 | * size_from_channelarray() - calculate the storage size of a scan 46 | * @channels: the channel info array 47 | * @num_channels: number of channels 48 | * 49 | * Has the side effect of filling the channels[i].location values used 50 | * in processing the buffer output. 51 | **/ 52 | int size_from_channelarray(struct iio_channel_info *channels, int num_channels) 53 | { 54 | int bytes = 0; 55 | int i = 0; 56 | 57 | while (i < num_channels) { 58 | if (bytes % channels[i].bytes == 0) 59 | channels[i].location = bytes; 60 | else 61 | channels[i].location = bytes - bytes % channels[i].bytes 62 | + channels[i].bytes; 63 | 64 | bytes = channels[i].location + channels[i].bytes; 65 | i++; 66 | } 67 | 68 | return bytes; 69 | } 70 | 71 | void print1byte(uint8_t input, struct iio_channel_info *info) 72 | { 73 | /* 74 | * Shift before conversion to avoid sign extension 75 | * of left aligned data 76 | */ 77 | input >>= info->shift; 78 | input &= info->mask; 79 | if (info->is_signed) { 80 | int8_t val = (int8_t)(input << (8 - info->bits_used)) >> 81 | (8 - info->bits_used); 82 | printf("%05f ", ((float)val + info->offset) * info->scale); 83 | } else { 84 | printf("%05f ", ((float)input + info->offset) * info->scale); 85 | } 86 | } 87 | 88 | void print2byte(uint16_t input, struct iio_channel_info *info) 89 | { 90 | /* First swap if incorrect endian */ 91 | if (info->be) 92 | input = be16toh(input); 93 | else 94 | input = le16toh(input); 95 | 96 | /* 97 | * Shift before conversion to avoid sign extension 98 | * of left aligned data 99 | */ 100 | input >>= info->shift; 101 | input &= info->mask; 102 | if (info->is_signed) { 103 | int16_t val = (int16_t)(input << (16 - info->bits_used)) >> 104 | (16 - info->bits_used); 105 | printf("%05f ", ((float)val + info->offset) * info->scale); 106 | } else { 107 | printf("%05f ", ((float)input + info->offset) * info->scale); 108 | } 109 | } 110 | 111 | void print4byte(uint32_t input, struct iio_channel_info *info) 112 | { 113 | /* First swap if incorrect endian */ 114 | if (info->be) 115 | input = be32toh(input); 116 | else 117 | input = le32toh(input); 118 | 119 | /* 120 | * Shift before conversion to avoid sign extension 121 | * of left aligned data 122 | */ 123 | input >>= info->shift; 124 | input &= info->mask; 125 | if (info->is_signed) { 126 | int32_t val = (int32_t)(input << (32 - info->bits_used)) >> 127 | (32 - info->bits_used); 128 | printf("%05f ", ((float)val + info->offset) * info->scale); 129 | } else { 130 | printf("%05f ", ((float)input + info->offset) * info->scale); 131 | } 132 | } 133 | 134 | void print8byte(uint64_t input, struct iio_channel_info *info) 135 | { 136 | /* First swap if incorrect endian */ 137 | if (info->be) 138 | input = be64toh(input); 139 | else 140 | input = le64toh(input); 141 | 142 | /* 143 | * Shift before conversion to avoid sign extension 144 | * of left aligned data 145 | */ 146 | input >>= info->shift; 147 | input &= info->mask; 148 | if (info->is_signed) { 149 | int64_t val = (int64_t)(input << (64 - info->bits_used)) >> 150 | (64 - info->bits_used); 151 | /* special case for timestamp */ 152 | if (info->scale == 1.0f && info->offset == 0.0f) 153 | printf("%" PRId64 " ", val); 154 | else 155 | printf("%05f ", 156 | ((float)val + info->offset) * info->scale); 157 | } else { 158 | printf("%05f ", ((float)input + info->offset) * info->scale); 159 | } 160 | } 161 | 162 | /** 163 | * process_scan() - print out the values in SI units 164 | * @data: pointer to the start of the scan 165 | * @channels: information about the channels. 166 | * Note: size_from_channelarray must have been called first 167 | * to fill the location offsets. 168 | * @num_channels: number of channels 169 | **/ 170 | void process_scan(char *data, 171 | struct iio_channel_info *channels, 172 | int num_channels) 173 | { 174 | int k; 175 | 176 | for (k = 0; k < num_channels; k++) 177 | switch (channels[k].bytes) { 178 | /* only a few cases implemented so far */ 179 | case 1: 180 | print1byte(*(uint8_t *)(data + channels[k].location), 181 | &channels[k]); 182 | break; 183 | case 2: 184 | print2byte(*(uint16_t *)(data + channels[k].location), 185 | &channels[k]); 186 | break; 187 | case 4: 188 | print4byte(*(uint32_t *)(data + channels[k].location), 189 | &channels[k]); 190 | break; 191 | case 8: 192 | print8byte(*(uint64_t *)(data + channels[k].location), 193 | &channels[k]); 194 | break; 195 | default: 196 | break; 197 | } 198 | printf("\n"); 199 | } 200 | 201 | static int enable_disable_all_channels(char *dev_dir_name, int enable) 202 | { 203 | const struct dirent *ent; 204 | char scanelemdir[256]; 205 | DIR *dp; 206 | int ret; 207 | 208 | snprintf(scanelemdir, sizeof(scanelemdir), 209 | FORMAT_SCAN_ELEMENTS_DIR, dev_dir_name); 210 | scanelemdir[sizeof(scanelemdir)-1] = '\0'; 211 | 212 | dp = opendir(scanelemdir); 213 | if (!dp) { 214 | fprintf(stderr, "Enabling/disabling channels: can't open %s\n", 215 | scanelemdir); 216 | return -EIO; 217 | } 218 | 219 | ret = -ENOENT; 220 | while (ent = readdir(dp), ent) { 221 | if (iioutils_check_suffix(ent->d_name, "_en")) { 222 | printf("%sabling: %s\n", 223 | enable ? "En" : "Dis", 224 | ent->d_name); 225 | ret = write_sysfs_int(ent->d_name, scanelemdir, 226 | enable); 227 | if (ret < 0) 228 | fprintf(stderr, "Failed to enable/disable %s\n", 229 | ent->d_name); 230 | } 231 | } 232 | 233 | if (closedir(dp) == -1) { 234 | perror("Enabling/disabling channels: " 235 | "Failed to close directory"); 236 | return -errno; 237 | } 238 | return 0; 239 | } 240 | 241 | void print_usage(void) 242 | { 243 | fprintf(stderr, "Usage: generic_buffer [options]...\n" 244 | "Capture, convert and output data from IIO device buffer\n" 245 | " -a Auto-activate all available channels\n" 246 | " -A Force-activate ALL channels\n" 247 | " -c Do n conversions, or loop forever if n < 0\n" 248 | " -e Disable wait for event (new data)\n" 249 | " -g Use trigger-less mode\n" 250 | " -l Set buffer length to n samples\n" 251 | " --device-name -n \n" 252 | " --device-num -N \n" 253 | " Set device by name or number (mandatory)\n" 254 | " --trigger-name -t \n" 255 | " --trigger-num -T \n" 256 | " Set trigger by name or number\n" 257 | " -w Set delay between reads in us (event-less mode)\n"); 258 | } 259 | 260 | enum autochan autochannels = AUTOCHANNELS_DISABLED; 261 | char *dev_dir_name = NULL; 262 | char *buf_dir_name = NULL; 263 | bool current_trigger_set = false; 264 | 265 | void cleanup(void) 266 | { 267 | int ret; 268 | 269 | /* Disable trigger */ 270 | if (dev_dir_name && current_trigger_set) { 271 | /* Disconnect the trigger - just write a dummy name. */ 272 | ret = write_sysfs_string("trigger/current_trigger", 273 | dev_dir_name, "NULL"); 274 | if (ret < 0) 275 | fprintf(stderr, "Failed to disable trigger: %s\n", 276 | strerror(-ret)); 277 | current_trigger_set = false; 278 | } 279 | 280 | /* Disable buffer */ 281 | if (buf_dir_name) { 282 | ret = write_sysfs_int("enable", buf_dir_name, 0); 283 | if (ret < 0) 284 | fprintf(stderr, "Failed to disable buffer: %s\n", 285 | strerror(-ret)); 286 | } 287 | 288 | /* Disable channels if auto-enabled */ 289 | if (dev_dir_name && autochannels == AUTOCHANNELS_ACTIVE) { 290 | ret = enable_disable_all_channels(dev_dir_name, 0); 291 | if (ret) 292 | fprintf(stderr, "Failed to disable all channels\n"); 293 | autochannels = AUTOCHANNELS_DISABLED; 294 | } 295 | } 296 | 297 | void sig_handler(int signum) 298 | { 299 | fprintf(stderr, "Caught signal %d\n", signum); 300 | cleanup(); 301 | exit(-signum); 302 | } 303 | 304 | void register_cleanup(void) 305 | { 306 | struct sigaction sa = { .sa_handler = sig_handler }; 307 | const int signums[] = { SIGINT, SIGTERM, SIGABRT }; 308 | int ret, i; 309 | 310 | for (i = 0; i < ARRAY_SIZE(signums); ++i) { 311 | ret = sigaction(signums[i], &sa, NULL); 312 | if (ret) { 313 | perror("Failed to register signal handler"); 314 | exit(-1); 315 | } 316 | } 317 | } 318 | 319 | static const struct option longopts[] = { 320 | { "device-name", 1, 0, 'n' }, 321 | { "device-num", 1, 0, 'N' }, 322 | { "trigger-name", 1, 0, 't' }, 323 | { "trigger-num", 1, 0, 'T' }, 324 | { }, 325 | }; 326 | 327 | int main(int argc, char **argv) 328 | { 329 | long long num_loops = 2; 330 | unsigned long timedelay = 1000000; 331 | unsigned long buf_len = 128; 332 | 333 | ssize_t i; 334 | unsigned long long j; 335 | unsigned long toread; 336 | int ret, c; 337 | int fp = -1; 338 | 339 | int num_channels = 0; 340 | char *trigger_name = NULL, *device_name = NULL; 341 | 342 | char *data = NULL; 343 | ssize_t read_size; 344 | int dev_num = -1, trig_num = -1; 345 | char *buffer_access = NULL; 346 | int scan_size; 347 | int noevents = 0; 348 | int notrigger = 0; 349 | char *dummy; 350 | bool force_autochannels = false; 351 | 352 | struct iio_channel_info *channels = NULL; 353 | 354 | register_cleanup(); 355 | 356 | while ((c = getopt_long(argc, argv, "aAc:egl:n:N:t:T:w:?", longopts, 357 | NULL)) != -1) { 358 | switch (c) { 359 | case 'a': 360 | autochannels = AUTOCHANNELS_ENABLED; 361 | break; 362 | case 'A': 363 | autochannels = AUTOCHANNELS_ENABLED; 364 | force_autochannels = true; 365 | break; 366 | case 'c': 367 | errno = 0; 368 | num_loops = strtoll(optarg, &dummy, 10); 369 | if (errno) { 370 | ret = -errno; 371 | goto error; 372 | } 373 | 374 | break; 375 | case 'e': 376 | noevents = 1; 377 | break; 378 | case 'g': 379 | notrigger = 1; 380 | break; 381 | case 'l': 382 | errno = 0; 383 | buf_len = strtoul(optarg, &dummy, 10); 384 | if (errno) { 385 | ret = -errno; 386 | goto error; 387 | } 388 | 389 | break; 390 | case 'n': 391 | device_name = strdup(optarg); 392 | break; 393 | case 'N': 394 | errno = 0; 395 | dev_num = strtoul(optarg, &dummy, 10); 396 | if (errno) { 397 | ret = -errno; 398 | goto error; 399 | } 400 | break; 401 | case 't': 402 | trigger_name = strdup(optarg); 403 | break; 404 | case 'T': 405 | errno = 0; 406 | trig_num = strtoul(optarg, &dummy, 10); 407 | if (errno) 408 | return -errno; 409 | break; 410 | case 'w': 411 | errno = 0; 412 | timedelay = strtoul(optarg, &dummy, 10); 413 | if (errno) { 414 | ret = -errno; 415 | goto error; 416 | } 417 | break; 418 | case '?': 419 | print_usage(); 420 | ret = -1; 421 | goto error; 422 | } 423 | } 424 | 425 | /* Find the device requested */ 426 | if (dev_num < 0 && !device_name) { 427 | fprintf(stderr, "Device not set\n"); 428 | print_usage(); 429 | ret = -1; 430 | goto error; 431 | } else if (dev_num >= 0 && device_name) { 432 | fprintf(stderr, "Only one of --device-num or --device-name needs to be set\n"); 433 | print_usage(); 434 | ret = -1; 435 | goto error; 436 | } else if (dev_num < 0) { 437 | dev_num = find_type_by_name(device_name, "iio:device"); 438 | if (dev_num < 0) { 439 | fprintf(stderr, "Failed to find the %s\n", device_name); 440 | ret = dev_num; 441 | goto error; 442 | } 443 | } 444 | printf("iio device number being used is %d\n", dev_num); 445 | 446 | ret = asprintf(&dev_dir_name, "%siio:device%d", iio_dir, dev_num); 447 | if (ret < 0) 448 | return -ENOMEM; 449 | /* Fetch device_name if specified by number */ 450 | if (!device_name) { 451 | device_name = malloc(IIO_MAX_NAME_LENGTH); 452 | if (!device_name) { 453 | ret = -ENOMEM; 454 | goto error; 455 | } 456 | ret = read_sysfs_string("name", dev_dir_name, device_name); 457 | if (ret < 0) { 458 | fprintf(stderr, "Failed to read name of device %d\n", dev_num); 459 | goto error; 460 | } 461 | } 462 | 463 | if (notrigger) { 464 | printf("trigger-less mode selected\n"); 465 | } else if (trig_num >= 0) { 466 | char *trig_dev_name; 467 | ret = asprintf(&trig_dev_name, "%strigger%d", iio_dir, trig_num); 468 | if (ret < 0) { 469 | return -ENOMEM; 470 | } 471 | trigger_name = malloc(IIO_MAX_NAME_LENGTH); 472 | ret = read_sysfs_string("name", trig_dev_name, trigger_name); 473 | free(trig_dev_name); 474 | if (ret < 0) { 475 | fprintf(stderr, "Failed to read trigger%d name from\n", trig_num); 476 | return ret; 477 | } 478 | printf("iio trigger number being used is %d\n", trig_num); 479 | } else { 480 | if (!trigger_name) { 481 | /* 482 | * Build the trigger name. If it is device associated 483 | * its name is _dev[n] where n matches 484 | * the device number found above. 485 | */ 486 | ret = asprintf(&trigger_name, 487 | "%s-dev%d", device_name, dev_num); 488 | if (ret < 0) { 489 | ret = -ENOMEM; 490 | goto error; 491 | } 492 | } 493 | 494 | /* Look for this "-devN" trigger */ 495 | trig_num = find_type_by_name(trigger_name, "trigger"); 496 | if (trig_num < 0) { 497 | /* OK try the simpler "-trigger" suffix instead */ 498 | free(trigger_name); 499 | ret = asprintf(&trigger_name, 500 | "%s-trigger", device_name); 501 | if (ret < 0) { 502 | ret = -ENOMEM; 503 | goto error; 504 | } 505 | } 506 | 507 | trig_num = find_type_by_name(trigger_name, "trigger"); 508 | if (trig_num < 0) { 509 | fprintf(stderr, "Failed to find the trigger %s\n", 510 | trigger_name); 511 | ret = trig_num; 512 | goto error; 513 | } 514 | 515 | printf("iio trigger number being used is %d\n", trig_num); 516 | } 517 | 518 | /* 519 | * Parse the files in scan_elements to identify what channels are 520 | * present 521 | */ 522 | ret = build_channel_array(dev_dir_name, &channels, &num_channels); 523 | if (ret) { 524 | fprintf(stderr, "Problem reading scan element information\n" 525 | "diag %s\n", dev_dir_name); 526 | goto error; 527 | } 528 | if (num_channels && autochannels == AUTOCHANNELS_ENABLED && 529 | !force_autochannels) { 530 | fprintf(stderr, "Auto-channels selected but some channels " 531 | "are already activated in sysfs\n"); 532 | fprintf(stderr, "Proceeding without activating any channels\n"); 533 | } 534 | 535 | if ((!num_channels && autochannels == AUTOCHANNELS_ENABLED) || 536 | (autochannels == AUTOCHANNELS_ENABLED && force_autochannels)) { 537 | fprintf(stderr, "Enabling all channels\n"); 538 | 539 | ret = enable_disable_all_channels(dev_dir_name, 1); 540 | if (ret) { 541 | fprintf(stderr, "Failed to enable all channels\n"); 542 | goto error; 543 | } 544 | 545 | /* This flags that we need to disable the channels again */ 546 | autochannels = AUTOCHANNELS_ACTIVE; 547 | 548 | ret = build_channel_array(dev_dir_name, &channels, 549 | &num_channels); 550 | if (ret) { 551 | fprintf(stderr, "Problem reading scan element " 552 | "information\n" 553 | "diag %s\n", dev_dir_name); 554 | goto error; 555 | } 556 | if (!num_channels) { 557 | fprintf(stderr, "Still no channels after " 558 | "auto-enabling, giving up\n"); 559 | goto error; 560 | } 561 | } 562 | 563 | if (!num_channels && autochannels == AUTOCHANNELS_DISABLED) { 564 | fprintf(stderr, 565 | "No channels are enabled, we have nothing to scan.\n"); 566 | fprintf(stderr, "Enable channels manually in " 567 | FORMAT_SCAN_ELEMENTS_DIR 568 | "/*_en or pass -a to autoenable channels and " 569 | "try again.\n", dev_dir_name); 570 | ret = -ENOENT; 571 | goto error; 572 | } 573 | 574 | /* 575 | * Construct the directory name for the associated buffer. 576 | * As we know that the lis3l02dq has only one buffer this may 577 | * be built rather than found. 578 | */ 579 | ret = asprintf(&buf_dir_name, 580 | "%siio:device%d/buffer", iio_dir, dev_num); 581 | if (ret < 0) { 582 | ret = -ENOMEM; 583 | goto error; 584 | } 585 | 586 | if (!notrigger) { 587 | printf("%s %s\n", dev_dir_name, trigger_name); 588 | /* 589 | * Set the device trigger to be the data ready trigger found 590 | * above 591 | */ 592 | ret = write_sysfs_string_and_verify("trigger/current_trigger", 593 | dev_dir_name, 594 | trigger_name); 595 | if (ret < 0) { 596 | fprintf(stderr, 597 | "Failed to write current_trigger file\n"); 598 | goto error; 599 | } 600 | } 601 | 602 | /* Setup ring buffer parameters */ 603 | ret = write_sysfs_int("length", buf_dir_name, buf_len); 604 | if (ret < 0) 605 | goto error; 606 | 607 | /* Enable the buffer */ 608 | ret = write_sysfs_int("enable", buf_dir_name, 1); 609 | if (ret < 0) { 610 | fprintf(stderr, 611 | "Failed to enable buffer: %s\n", strerror(-ret)); 612 | goto error; 613 | } 614 | 615 | scan_size = size_from_channelarray(channels, num_channels); 616 | data = malloc(scan_size * buf_len); 617 | if (!data) { 618 | ret = -ENOMEM; 619 | goto error; 620 | } 621 | 622 | ret = asprintf(&buffer_access, "/dev/iio:device%d", dev_num); 623 | if (ret < 0) { 624 | ret = -ENOMEM; 625 | goto error; 626 | } 627 | 628 | /* Attempt to open non blocking the access dev */ 629 | fp = open(buffer_access, O_RDONLY | O_NONBLOCK); 630 | if (fp == -1) { /* TODO: If it isn't there make the node */ 631 | ret = -errno; 632 | fprintf(stderr, "Failed to open %s\n", buffer_access); 633 | goto error; 634 | } 635 | 636 | for (j = 0; j < num_loops || num_loops < 0; j++) { 637 | if (!noevents) { 638 | struct pollfd pfd = { 639 | .fd = fp, 640 | .events = POLLIN, 641 | }; 642 | 643 | ret = poll(&pfd, 1, -1); 644 | if (ret < 0) { 645 | ret = -errno; 646 | goto error; 647 | } else if (ret == 0) { 648 | continue; 649 | } 650 | 651 | toread = buf_len; 652 | } else { 653 | usleep(timedelay); 654 | toread = 64; 655 | } 656 | 657 | read_size = read(fp, data, toread * scan_size); 658 | if (read_size < 0) { 659 | if (errno == EAGAIN) { 660 | fprintf(stderr, "nothing available\n"); 661 | continue; 662 | } else { 663 | break; 664 | } 665 | } 666 | for (i = 0; i < read_size / scan_size; i++) 667 | process_scan(data + scan_size * i, channels, 668 | num_channels); 669 | } 670 | 671 | error: 672 | cleanup(); 673 | 674 | if (fp >= 0 && close(fp) == -1) 675 | perror("Failed to close buffer"); 676 | free(buffer_access); 677 | free(data); 678 | free(buf_dir_name); 679 | for (i = num_channels - 1; i >= 0; i--) { 680 | free(channels[i].name); 681 | free(channels[i].generic_name); 682 | } 683 | free(channels); 684 | free(trigger_name); 685 | free(device_name); 686 | free(dev_dir_name); 687 | 688 | return ret; 689 | } 690 | -------------------------------------------------------------------------------- /35.3.1/app/iio_utils.c: -------------------------------------------------------------------------------- 1 | // SPDX-License-Identifier: GPL-2.0-only 2 | /* IIO - useful set of util functionality 3 | * 4 | * Copyright (c) 2008 Jonathan Cameron 5 | */ 6 | #include 7 | #include 8 | #include 9 | #include 10 | #include 11 | #include 12 | #include 13 | #include "iio_utils.h" 14 | 15 | const char *iio_dir = "/sys/bus/iio/devices/"; 16 | 17 | static char * const iio_direction[] = { 18 | "in", 19 | "out", 20 | }; 21 | 22 | /** 23 | * iioutils_break_up_name() - extract generic name from full channel name 24 | * @full_name: the full channel name 25 | * @generic_name: the output generic channel name 26 | * 27 | * Returns 0 on success, or a negative error code if string extraction failed. 28 | **/ 29 | int iioutils_break_up_name(const char *full_name, char **generic_name) 30 | { 31 | char *current; 32 | char *w, *r; 33 | char *working, *prefix = ""; 34 | int i, ret; 35 | 36 | for (i = 0; i < ARRAY_SIZE(iio_direction); i++) 37 | if (!strncmp(full_name, iio_direction[i], 38 | strlen(iio_direction[i]))) { 39 | prefix = iio_direction[i]; 40 | break; 41 | } 42 | 43 | current = strdup(full_name + strlen(prefix) + 1); 44 | if (!current) 45 | return -ENOMEM; 46 | 47 | working = strtok(current, "_\0"); 48 | if (!working) { 49 | free(current); 50 | return -EINVAL; 51 | } 52 | 53 | w = working; 54 | r = working; 55 | 56 | while (*r != '\0') { 57 | if (!isdigit(*r)) { 58 | *w = *r; 59 | w++; 60 | } 61 | 62 | r++; 63 | } 64 | *w = '\0'; 65 | ret = asprintf(generic_name, "%s_%s", prefix, working); 66 | free(current); 67 | 68 | return (ret == -1) ? -ENOMEM : 0; 69 | } 70 | 71 | /** 72 | * iioutils_get_type() - find and process _type attribute data 73 | * @is_signed: output whether channel is signed 74 | * @bytes: output how many bytes the channel storage occupies 75 | * @bits_used: output number of valid bits of data 76 | * @shift: output amount of bits to shift right data before applying bit mask 77 | * @mask: output a bit mask for the raw data 78 | * @be: output if data in big endian 79 | * @device_dir: the IIO device directory 80 | * @name: the channel name 81 | * @generic_name: the channel type name 82 | * 83 | * Returns a value >= 0 on success, otherwise a negative error code. 84 | **/ 85 | int iioutils_get_type(unsigned *is_signed, unsigned *bytes, unsigned *bits_used, 86 | unsigned *shift, uint64_t *mask, unsigned *be, 87 | const char *device_dir, const char *name, 88 | const char *generic_name) 89 | { 90 | FILE *sysfsfp; 91 | int ret; 92 | DIR *dp; 93 | char *scan_el_dir, *builtname, *builtname_generic, *filename = 0; 94 | char signchar, endianchar; 95 | unsigned padint; 96 | const struct dirent *ent; 97 | 98 | ret = asprintf(&scan_el_dir, FORMAT_SCAN_ELEMENTS_DIR, device_dir); 99 | if (ret < 0) 100 | return -ENOMEM; 101 | 102 | ret = asprintf(&builtname, FORMAT_TYPE_FILE, name); 103 | if (ret < 0) { 104 | ret = -ENOMEM; 105 | goto error_free_scan_el_dir; 106 | } 107 | ret = asprintf(&builtname_generic, FORMAT_TYPE_FILE, generic_name); 108 | if (ret < 0) { 109 | ret = -ENOMEM; 110 | goto error_free_builtname; 111 | } 112 | 113 | dp = opendir(scan_el_dir); 114 | if (!dp) { 115 | ret = -errno; 116 | goto error_free_builtname_generic; 117 | } 118 | 119 | ret = -ENOENT; 120 | while (ent = readdir(dp), ent) 121 | if ((strcmp(builtname, ent->d_name) == 0) || 122 | (strcmp(builtname_generic, ent->d_name) == 0)) { 123 | ret = asprintf(&filename, 124 | "%s/%s", scan_el_dir, ent->d_name); 125 | if (ret < 0) { 126 | ret = -ENOMEM; 127 | goto error_closedir; 128 | } 129 | 130 | sysfsfp = fopen(filename, "r"); 131 | if (!sysfsfp) { 132 | ret = -errno; 133 | fprintf(stderr, "failed to open %s\n", 134 | filename); 135 | goto error_free_filename; 136 | } 137 | 138 | ret = fscanf(sysfsfp, 139 | "%ce:%c%u/%u>>%u", 140 | &endianchar, 141 | &signchar, 142 | bits_used, 143 | &padint, shift); 144 | if (ret < 0) { 145 | ret = -errno; 146 | fprintf(stderr, 147 | "failed to pass scan type description\n"); 148 | goto error_close_sysfsfp; 149 | } else if (ret != 5) { 150 | ret = -EIO; 151 | fprintf(stderr, 152 | "scan type description didn't match\n"); 153 | goto error_close_sysfsfp; 154 | } 155 | 156 | *be = (endianchar == 'b'); 157 | *bytes = padint / 8; 158 | if (*bits_used == 64) 159 | *mask = ~(0ULL); 160 | else 161 | *mask = (1ULL << *bits_used) - 1ULL; 162 | 163 | *is_signed = (signchar == 's'); 164 | if (fclose(sysfsfp)) { 165 | ret = -errno; 166 | fprintf(stderr, "Failed to close %s\n", 167 | filename); 168 | goto error_free_filename; 169 | } 170 | 171 | sysfsfp = 0; 172 | free(filename); 173 | filename = 0; 174 | 175 | /* 176 | * Avoid having a more generic entry overwriting 177 | * the settings. 178 | */ 179 | if (strcmp(builtname, ent->d_name) == 0) 180 | break; 181 | } 182 | 183 | error_close_sysfsfp: 184 | if (sysfsfp) 185 | if (fclose(sysfsfp)) 186 | perror("iioutils_get_type(): Failed to close file"); 187 | 188 | error_free_filename: 189 | if (filename) 190 | free(filename); 191 | 192 | error_closedir: 193 | if (closedir(dp) == -1) 194 | perror("iioutils_get_type(): Failed to close directory"); 195 | 196 | error_free_builtname_generic: 197 | free(builtname_generic); 198 | error_free_builtname: 199 | free(builtname); 200 | error_free_scan_el_dir: 201 | free(scan_el_dir); 202 | 203 | return ret; 204 | } 205 | 206 | /** 207 | * iioutils_get_param_float() - read a float value from a channel parameter 208 | * @output: output the float value 209 | * @param_name: the parameter name to read 210 | * @device_dir: the IIO device directory in sysfs 211 | * @name: the channel name 212 | * @generic_name: the channel type name 213 | * 214 | * Returns a value >= 0 on success, otherwise a negative error code. 215 | **/ 216 | int iioutils_get_param_float(float *output, const char *param_name, 217 | const char *device_dir, const char *name, 218 | const char *generic_name) 219 | { 220 | FILE *sysfsfp; 221 | int ret; 222 | DIR *dp; 223 | char *builtname, *builtname_generic; 224 | char *filename = NULL; 225 | const struct dirent *ent; 226 | 227 | ret = asprintf(&builtname, "%s_%s", name, param_name); 228 | if (ret < 0) 229 | return -ENOMEM; 230 | 231 | ret = asprintf(&builtname_generic, 232 | "%s_%s", generic_name, param_name); 233 | if (ret < 0) { 234 | ret = -ENOMEM; 235 | goto error_free_builtname; 236 | } 237 | 238 | dp = opendir(device_dir); 239 | if (!dp) { 240 | ret = -errno; 241 | goto error_free_builtname_generic; 242 | } 243 | 244 | ret = -ENOENT; 245 | while (ent = readdir(dp), ent) 246 | if ((strcmp(builtname, ent->d_name) == 0) || 247 | (strcmp(builtname_generic, ent->d_name) == 0)) { 248 | ret = asprintf(&filename, 249 | "%s/%s", device_dir, ent->d_name); 250 | if (ret < 0) { 251 | ret = -ENOMEM; 252 | goto error_closedir; 253 | } 254 | 255 | sysfsfp = fopen(filename, "r"); 256 | if (!sysfsfp) { 257 | ret = -errno; 258 | goto error_free_filename; 259 | } 260 | 261 | errno = 0; 262 | if (fscanf(sysfsfp, "%f", output) != 1) 263 | ret = errno ? -errno : -ENODATA; 264 | 265 | break; 266 | } 267 | error_free_filename: 268 | if (filename) 269 | free(filename); 270 | 271 | error_closedir: 272 | if (closedir(dp) == -1) 273 | perror("iioutils_get_param_float(): Failed to close directory"); 274 | 275 | error_free_builtname_generic: 276 | free(builtname_generic); 277 | error_free_builtname: 278 | free(builtname); 279 | 280 | return ret; 281 | } 282 | 283 | /** 284 | * bsort_channel_array_by_index() - sort the array in index order 285 | * @ci_array: the iio_channel_info array to be sorted 286 | * @cnt: the amount of array elements 287 | **/ 288 | 289 | void bsort_channel_array_by_index(struct iio_channel_info *ci_array, int cnt) 290 | { 291 | struct iio_channel_info temp; 292 | int x, y; 293 | 294 | for (x = 0; x < cnt; x++) 295 | for (y = 0; y < (cnt - 1); y++) 296 | if (ci_array[y].index > ci_array[y + 1].index) { 297 | temp = ci_array[y + 1]; 298 | ci_array[y + 1] = ci_array[y]; 299 | ci_array[y] = temp; 300 | } 301 | } 302 | 303 | /** 304 | * build_channel_array() - function to figure out what channels are present 305 | * @device_dir: the IIO device directory in sysfs 306 | * @ci_array: output the resulting array of iio_channel_info 307 | * @counter: output the amount of array elements 308 | * 309 | * Returns 0 on success, otherwise a negative error code. 310 | **/ 311 | int build_channel_array(const char *device_dir, 312 | struct iio_channel_info **ci_array, int *counter) 313 | { 314 | DIR *dp; 315 | FILE *sysfsfp; 316 | int count = 0, i; 317 | struct iio_channel_info *current; 318 | int ret; 319 | const struct dirent *ent; 320 | char *scan_el_dir; 321 | char *filename; 322 | 323 | *counter = 0; 324 | ret = asprintf(&scan_el_dir, FORMAT_SCAN_ELEMENTS_DIR, device_dir); 325 | if (ret < 0) 326 | return -ENOMEM; 327 | 328 | dp = opendir(scan_el_dir); 329 | if (!dp) { 330 | ret = -errno; 331 | goto error_free_name; 332 | } 333 | 334 | while (ent = readdir(dp), ent) 335 | if (strcmp(ent->d_name + strlen(ent->d_name) - strlen("_en"), 336 | "_en") == 0) { 337 | ret = asprintf(&filename, 338 | "%s/%s", scan_el_dir, ent->d_name); 339 | if (ret < 0) { 340 | ret = -ENOMEM; 341 | goto error_close_dir; 342 | } 343 | 344 | sysfsfp = fopen(filename, "r"); 345 | if (!sysfsfp) { 346 | ret = -errno; 347 | free(filename); 348 | goto error_close_dir; 349 | } 350 | 351 | errno = 0; 352 | if (fscanf(sysfsfp, "%i", &ret) != 1) { 353 | ret = errno ? -errno : -ENODATA; 354 | if (fclose(sysfsfp)) 355 | perror("build_channel_array(): Failed to close file"); 356 | 357 | free(filename); 358 | goto error_close_dir; 359 | } 360 | if (ret == 1) 361 | (*counter)++; 362 | 363 | if (fclose(sysfsfp)) { 364 | ret = -errno; 365 | free(filename); 366 | goto error_close_dir; 367 | } 368 | 369 | free(filename); 370 | } 371 | 372 | *ci_array = malloc(sizeof(**ci_array) * (*counter)); 373 | if (!*ci_array) { 374 | ret = -ENOMEM; 375 | goto error_close_dir; 376 | } 377 | 378 | seekdir(dp, 0); 379 | while (ent = readdir(dp), ent) { 380 | if (strcmp(ent->d_name + strlen(ent->d_name) - strlen("_en"), 381 | "_en") == 0) { 382 | int current_enabled = 0; 383 | 384 | current = &(*ci_array)[count++]; 385 | ret = asprintf(&filename, 386 | "%s/%s", scan_el_dir, ent->d_name); 387 | if (ret < 0) { 388 | ret = -ENOMEM; 389 | /* decrement count to avoid freeing name */ 390 | count--; 391 | goto error_cleanup_array; 392 | } 393 | 394 | sysfsfp = fopen(filename, "r"); 395 | if (!sysfsfp) { 396 | ret = -errno; 397 | free(filename); 398 | count--; 399 | goto error_cleanup_array; 400 | } 401 | 402 | errno = 0; 403 | if (fscanf(sysfsfp, "%i", ¤t_enabled) != 1) { 404 | ret = errno ? -errno : -ENODATA; 405 | free(filename); 406 | count--; 407 | goto error_cleanup_array; 408 | } 409 | 410 | if (fclose(sysfsfp)) { 411 | ret = -errno; 412 | free(filename); 413 | count--; 414 | goto error_cleanup_array; 415 | } 416 | 417 | if (!current_enabled) { 418 | free(filename); 419 | count--; 420 | continue; 421 | } 422 | 423 | current->scale = 1.0; 424 | current->offset = 0; 425 | current->name = strndup(ent->d_name, 426 | strlen(ent->d_name) - 427 | strlen("_en")); 428 | if (!current->name) { 429 | free(filename); 430 | ret = -ENOMEM; 431 | count--; 432 | goto error_cleanup_array; 433 | } 434 | 435 | /* Get the generic and specific name elements */ 436 | ret = iioutils_break_up_name(current->name, 437 | ¤t->generic_name); 438 | if (ret) { 439 | free(filename); 440 | free(current->name); 441 | count--; 442 | goto error_cleanup_array; 443 | } 444 | 445 | ret = asprintf(&filename, 446 | "%s/%s_index", 447 | scan_el_dir, 448 | current->name); 449 | if (ret < 0) { 450 | free(filename); 451 | ret = -ENOMEM; 452 | goto error_cleanup_array; 453 | } 454 | 455 | sysfsfp = fopen(filename, "r"); 456 | if (!sysfsfp) { 457 | ret = -errno; 458 | fprintf(stderr, "failed to open %s\n", 459 | filename); 460 | free(filename); 461 | goto error_cleanup_array; 462 | } 463 | 464 | errno = 0; 465 | if (fscanf(sysfsfp, "%u", ¤t->index) != 1) { 466 | ret = errno ? -errno : -ENODATA; 467 | if (fclose(sysfsfp)) 468 | perror("build_channel_array(): Failed to close file"); 469 | 470 | free(filename); 471 | goto error_cleanup_array; 472 | } 473 | 474 | if (fclose(sysfsfp)) { 475 | ret = -errno; 476 | free(filename); 477 | goto error_cleanup_array; 478 | } 479 | 480 | free(filename); 481 | /* Find the scale */ 482 | ret = iioutils_get_param_float(¤t->scale, 483 | "scale", 484 | device_dir, 485 | current->name, 486 | current->generic_name); 487 | if ((ret < 0) && (ret != -ENOENT)) 488 | goto error_cleanup_array; 489 | 490 | ret = iioutils_get_param_float(¤t->offset, 491 | "offset", 492 | device_dir, 493 | current->name, 494 | current->generic_name); 495 | if ((ret < 0) && (ret != -ENOENT)) 496 | goto error_cleanup_array; 497 | 498 | ret = iioutils_get_type(¤t->is_signed, 499 | ¤t->bytes, 500 | ¤t->bits_used, 501 | ¤t->shift, 502 | ¤t->mask, 503 | ¤t->be, 504 | device_dir, 505 | current->name, 506 | current->generic_name); 507 | if (ret < 0) 508 | goto error_cleanup_array; 509 | } 510 | } 511 | 512 | if (closedir(dp) == -1) { 513 | ret = -errno; 514 | goto error_cleanup_array; 515 | } 516 | 517 | free(scan_el_dir); 518 | /* reorder so that the array is in index order */ 519 | bsort_channel_array_by_index(*ci_array, *counter); 520 | 521 | return 0; 522 | 523 | error_cleanup_array: 524 | for (i = count - 1; i >= 0; i--) { 525 | free((*ci_array)[i].name); 526 | free((*ci_array)[i].generic_name); 527 | } 528 | free(*ci_array); 529 | *ci_array = NULL; 530 | *counter = 0; 531 | error_close_dir: 532 | if (dp) 533 | if (closedir(dp) == -1) 534 | perror("build_channel_array(): Failed to close dir"); 535 | 536 | error_free_name: 537 | free(scan_el_dir); 538 | 539 | return ret; 540 | } 541 | 542 | static int calc_digits(int num) 543 | { 544 | int count = 0; 545 | 546 | while (num != 0) { 547 | num /= 10; 548 | count++; 549 | } 550 | 551 | return count; 552 | } 553 | 554 | /** 555 | * find_type_by_name() - function to match top level types by name 556 | * @name: top level type instance name 557 | * @type: the type of top level instance being searched 558 | * 559 | * Returns the device number of a matched IIO device on success, otherwise a 560 | * negative error code. 561 | * Typical types this is used for are device and trigger. 562 | **/ 563 | int find_type_by_name(const char *name, const char *type) 564 | { 565 | const struct dirent *ent; 566 | int number, numstrlen, ret; 567 | 568 | FILE *namefp; 569 | DIR *dp; 570 | char thisname[IIO_MAX_NAME_LENGTH]; 571 | char *filename; 572 | 573 | dp = opendir(iio_dir); 574 | if (!dp) { 575 | fprintf(stderr, "No industrialio devices available\n"); 576 | return -ENODEV; 577 | } 578 | 579 | while (ent = readdir(dp), ent) { 580 | if (strcmp(ent->d_name, ".") != 0 && 581 | strcmp(ent->d_name, "..") != 0 && 582 | strlen(ent->d_name) > strlen(type) && 583 | strncmp(ent->d_name, type, strlen(type)) == 0) { 584 | errno = 0; 585 | ret = sscanf(ent->d_name + strlen(type), "%d", &number); 586 | if (ret < 0) { 587 | ret = -errno; 588 | fprintf(stderr, 589 | "failed to read element number\n"); 590 | goto error_close_dir; 591 | } else if (ret != 1) { 592 | ret = -EIO; 593 | fprintf(stderr, 594 | "failed to match element number\n"); 595 | goto error_close_dir; 596 | } 597 | 598 | numstrlen = calc_digits(number); 599 | /* verify the next character is not a colon */ 600 | if (strncmp(ent->d_name + strlen(type) + numstrlen, 601 | ":", 1) != 0) { 602 | filename = malloc(strlen(iio_dir) + strlen(type) 603 | + numstrlen + 6); 604 | if (!filename) { 605 | ret = -ENOMEM; 606 | goto error_close_dir; 607 | } 608 | 609 | ret = sprintf(filename, "%s%s%d/name", iio_dir, 610 | type, number); 611 | if (ret < 0) { 612 | free(filename); 613 | goto error_close_dir; 614 | } 615 | 616 | namefp = fopen(filename, "r"); 617 | if (!namefp) { 618 | free(filename); 619 | continue; 620 | } 621 | 622 | free(filename); 623 | errno = 0; 624 | if (fscanf(namefp, "%s", thisname) != 1) { 625 | ret = errno ? -errno : -ENODATA; 626 | goto error_close_dir; 627 | } 628 | 629 | if (fclose(namefp)) { 630 | ret = -errno; 631 | goto error_close_dir; 632 | } 633 | 634 | if (strcmp(name, thisname) == 0) { 635 | if (closedir(dp) == -1) 636 | return -errno; 637 | 638 | return number; 639 | } 640 | } 641 | } 642 | } 643 | if (closedir(dp) == -1) 644 | return -errno; 645 | 646 | return -ENODEV; 647 | 648 | error_close_dir: 649 | if (closedir(dp) == -1) 650 | perror("find_type_by_name(): Failed to close directory"); 651 | 652 | return ret; 653 | } 654 | 655 | static int _write_sysfs_int(const char *filename, const char *basedir, int val, 656 | int verify) 657 | { 658 | int ret = 0; 659 | FILE *sysfsfp; 660 | int test; 661 | char *temp = malloc(strlen(basedir) + strlen(filename) + 2); 662 | 663 | if (!temp) 664 | return -ENOMEM; 665 | 666 | ret = sprintf(temp, "%s/%s", basedir, filename); 667 | if (ret < 0) 668 | goto error_free; 669 | 670 | sysfsfp = fopen(temp, "w"); 671 | if (!sysfsfp) { 672 | ret = -errno; 673 | fprintf(stderr, "failed to open %s\n", temp); 674 | goto error_free; 675 | } 676 | 677 | ret = fprintf(sysfsfp, "%d", val); 678 | if (ret < 0) { 679 | if (fclose(sysfsfp)) 680 | perror("_write_sysfs_int(): Failed to close dir"); 681 | 682 | goto error_free; 683 | } 684 | 685 | if (fclose(sysfsfp)) { 686 | ret = -errno; 687 | goto error_free; 688 | } 689 | 690 | if (verify) { 691 | sysfsfp = fopen(temp, "r"); 692 | if (!sysfsfp) { 693 | ret = -errno; 694 | fprintf(stderr, "failed to open %s\n", temp); 695 | goto error_free; 696 | } 697 | 698 | if (fscanf(sysfsfp, "%d", &test) != 1) { 699 | ret = errno ? -errno : -ENODATA; 700 | if (fclose(sysfsfp)) 701 | perror("_write_sysfs_int(): Failed to close dir"); 702 | 703 | goto error_free; 704 | } 705 | 706 | if (fclose(sysfsfp)) { 707 | ret = -errno; 708 | goto error_free; 709 | } 710 | 711 | if (test != val) { 712 | fprintf(stderr, 713 | "Possible failure in int write %d to %s/%s\n", 714 | val, basedir, filename); 715 | ret = -1; 716 | } 717 | } 718 | 719 | error_free: 720 | free(temp); 721 | return ret; 722 | } 723 | 724 | /** 725 | * write_sysfs_int() - write an integer value to a sysfs file 726 | * @filename: name of the file to write to 727 | * @basedir: the sysfs directory in which the file is to be found 728 | * @val: integer value to write to file 729 | * 730 | * Returns a value >= 0 on success, otherwise a negative error code. 731 | **/ 732 | int write_sysfs_int(const char *filename, const char *basedir, int val) 733 | { 734 | return _write_sysfs_int(filename, basedir, val, 0); 735 | } 736 | 737 | /** 738 | * write_sysfs_int_and_verify() - write an integer value to a sysfs file 739 | * and verify 740 | * @filename: name of the file to write to 741 | * @basedir: the sysfs directory in which the file is to be found 742 | * @val: integer value to write to file 743 | * 744 | * Returns a value >= 0 on success, otherwise a negative error code. 745 | **/ 746 | int write_sysfs_int_and_verify(const char *filename, const char *basedir, 747 | int val) 748 | { 749 | return _write_sysfs_int(filename, basedir, val, 1); 750 | } 751 | 752 | static int _write_sysfs_string(const char *filename, const char *basedir, 753 | const char *val, int verify) 754 | { 755 | int ret = 0; 756 | FILE *sysfsfp; 757 | char *temp = malloc(strlen(basedir) + strlen(filename) + 2); 758 | 759 | if (!temp) { 760 | fprintf(stderr, "Memory allocation failed\n"); 761 | return -ENOMEM; 762 | } 763 | 764 | ret = sprintf(temp, "%s/%s", basedir, filename); 765 | if (ret < 0) 766 | goto error_free; 767 | 768 | sysfsfp = fopen(temp, "w"); 769 | if (!sysfsfp) { 770 | ret = -errno; 771 | fprintf(stderr, "Could not open %s\n", temp); 772 | goto error_free; 773 | } 774 | 775 | ret = fprintf(sysfsfp, "%s", val); 776 | if (ret < 0) { 777 | if (fclose(sysfsfp)) 778 | perror("_write_sysfs_string(): Failed to close dir"); 779 | 780 | goto error_free; 781 | } 782 | 783 | if (fclose(sysfsfp)) { 784 | ret = -errno; 785 | goto error_free; 786 | } 787 | 788 | if (verify) { 789 | sysfsfp = fopen(temp, "r"); 790 | if (!sysfsfp) { 791 | ret = -errno; 792 | fprintf(stderr, "Could not open file to verify\n"); 793 | goto error_free; 794 | } 795 | 796 | if (fscanf(sysfsfp, "%s", temp) != 1) { 797 | ret = errno ? -errno : -ENODATA; 798 | if (fclose(sysfsfp)) 799 | perror("_write_sysfs_string(): Failed to close dir"); 800 | 801 | goto error_free; 802 | } 803 | 804 | if (fclose(sysfsfp)) { 805 | ret = -errno; 806 | goto error_free; 807 | } 808 | 809 | if (strcmp(temp, val) != 0) { 810 | fprintf(stderr, 811 | "Possible failure in string write of %s " 812 | "Should be %s written to %s/%s\n", temp, val, 813 | basedir, filename); 814 | ret = -1; 815 | } 816 | } 817 | 818 | error_free: 819 | free(temp); 820 | 821 | return ret; 822 | } 823 | 824 | /** 825 | * write_sysfs_string_and_verify() - string write, readback and verify 826 | * @filename: name of file to write to 827 | * @basedir: the sysfs directory in which the file is to be found 828 | * @val: the string to write 829 | * 830 | * Returns a value >= 0 on success, otherwise a negative error code. 831 | **/ 832 | int write_sysfs_string_and_verify(const char *filename, const char *basedir, 833 | const char *val) 834 | { 835 | return _write_sysfs_string(filename, basedir, val, 1); 836 | } 837 | 838 | /** 839 | * write_sysfs_string() - write string to a sysfs file 840 | * @filename: name of file to write to 841 | * @basedir: the sysfs directory in which the file is to be found 842 | * @val: the string to write 843 | * 844 | * Returns a value >= 0 on success, otherwise a negative error code. 845 | **/ 846 | int write_sysfs_string(const char *filename, const char *basedir, 847 | const char *val) 848 | { 849 | return _write_sysfs_string(filename, basedir, val, 0); 850 | } 851 | 852 | /** 853 | * read_sysfs_posint() - read an integer value from file 854 | * @filename: name of file to read from 855 | * @basedir: the sysfs directory in which the file is to be found 856 | * 857 | * Returns the read integer value >= 0 on success, otherwise a negative error 858 | * code. 859 | **/ 860 | int read_sysfs_posint(const char *filename, const char *basedir) 861 | { 862 | int ret; 863 | FILE *sysfsfp; 864 | char *temp = malloc(strlen(basedir) + strlen(filename) + 2); 865 | 866 | if (!temp) { 867 | fprintf(stderr, "Memory allocation failed"); 868 | return -ENOMEM; 869 | } 870 | 871 | ret = sprintf(temp, "%s/%s", basedir, filename); 872 | if (ret < 0) 873 | goto error_free; 874 | 875 | sysfsfp = fopen(temp, "r"); 876 | if (!sysfsfp) { 877 | ret = -errno; 878 | goto error_free; 879 | } 880 | 881 | errno = 0; 882 | if (fscanf(sysfsfp, "%d\n", &ret) != 1) { 883 | ret = errno ? -errno : -ENODATA; 884 | if (fclose(sysfsfp)) 885 | perror("read_sysfs_posint(): Failed to close dir"); 886 | 887 | goto error_free; 888 | } 889 | 890 | if (fclose(sysfsfp)) 891 | ret = -errno; 892 | 893 | error_free: 894 | free(temp); 895 | 896 | return ret; 897 | } 898 | 899 | /** 900 | * read_sysfs_float() - read a float value from file 901 | * @filename: name of file to read from 902 | * @basedir: the sysfs directory in which the file is to be found 903 | * @val: output the read float value 904 | * 905 | * Returns a value >= 0 on success, otherwise a negative error code. 906 | **/ 907 | int read_sysfs_float(const char *filename, const char *basedir, float *val) 908 | { 909 | int ret = 0; 910 | FILE *sysfsfp; 911 | char *temp = malloc(strlen(basedir) + strlen(filename) + 2); 912 | 913 | if (!temp) { 914 | fprintf(stderr, "Memory allocation failed"); 915 | return -ENOMEM; 916 | } 917 | 918 | ret = sprintf(temp, "%s/%s", basedir, filename); 919 | if (ret < 0) 920 | goto error_free; 921 | 922 | sysfsfp = fopen(temp, "r"); 923 | if (!sysfsfp) { 924 | ret = -errno; 925 | goto error_free; 926 | } 927 | 928 | errno = 0; 929 | if (fscanf(sysfsfp, "%f\n", val) != 1) { 930 | ret = errno ? -errno : -ENODATA; 931 | if (fclose(sysfsfp)) 932 | perror("read_sysfs_float(): Failed to close dir"); 933 | 934 | goto error_free; 935 | } 936 | 937 | if (fclose(sysfsfp)) 938 | ret = -errno; 939 | 940 | error_free: 941 | free(temp); 942 | 943 | return ret; 944 | } 945 | 946 | /** 947 | * read_sysfs_string() - read a string from file 948 | * @filename: name of file to read from 949 | * @basedir: the sysfs directory in which the file is to be found 950 | * @str: output the read string 951 | * 952 | * Returns a value >= 0 on success, otherwise a negative error code. 953 | **/ 954 | int read_sysfs_string(const char *filename, const char *basedir, char *str) 955 | { 956 | int ret = 0; 957 | FILE *sysfsfp; 958 | char *temp = malloc(strlen(basedir) + strlen(filename) + 2); 959 | 960 | if (!temp) { 961 | fprintf(stderr, "Memory allocation failed"); 962 | return -ENOMEM; 963 | } 964 | 965 | ret = sprintf(temp, "%s/%s", basedir, filename); 966 | if (ret < 0) 967 | goto error_free; 968 | 969 | sysfsfp = fopen(temp, "r"); 970 | if (!sysfsfp) { 971 | ret = -errno; 972 | goto error_free; 973 | } 974 | 975 | errno = 0; 976 | if (fscanf(sysfsfp, "%s\n", str) != 1) { 977 | ret = errno ? -errno : -ENODATA; 978 | if (fclose(sysfsfp)) 979 | perror("read_sysfs_string(): Failed to close dir"); 980 | 981 | goto error_free; 982 | } 983 | 984 | if (fclose(sysfsfp)) 985 | ret = -errno; 986 | 987 | error_free: 988 | free(temp); 989 | 990 | return ret; 991 | } 992 | -------------------------------------------------------------------------------- /35.3.1/app/iio_utils.h: -------------------------------------------------------------------------------- 1 | /* SPDX-License-Identifier: GPL-2.0-only */ 2 | #ifndef _IIO_UTILS_H_ 3 | #define _IIO_UTILS_H_ 4 | 5 | /* IIO - useful set of util functionality 6 | * 7 | * Copyright (c) 2008 Jonathan Cameron 8 | */ 9 | 10 | #include 11 | 12 | /* Made up value to limit allocation sizes */ 13 | #define IIO_MAX_NAME_LENGTH 64 14 | 15 | #define FORMAT_SCAN_ELEMENTS_DIR "%s/scan_elements" 16 | #define FORMAT_TYPE_FILE "%s_type" 17 | 18 | #define ARRAY_SIZE(arr) (sizeof(arr) / sizeof(arr[0])) 19 | 20 | extern const char *iio_dir; 21 | 22 | /** 23 | * struct iio_channel_info - information about a given channel 24 | * @name: channel name 25 | * @generic_name: general name for channel type 26 | * @scale: scale factor to be applied for conversion to si units 27 | * @offset: offset to be applied for conversion to si units 28 | * @index: the channel index in the buffer output 29 | * @bytes: number of bytes occupied in buffer output 30 | * @bits_used: number of valid bits of data 31 | * @shift: amount of bits to shift right data before applying bit mask 32 | * @mask: a bit mask for the raw output 33 | * @be: flag if data is big endian 34 | * @is_signed: is the raw value stored signed 35 | * @location: data offset for this channel inside the buffer (in bytes) 36 | **/ 37 | struct iio_channel_info { 38 | char *name; 39 | char *generic_name; 40 | float scale; 41 | float offset; 42 | unsigned index; 43 | unsigned bytes; 44 | unsigned bits_used; 45 | unsigned shift; 46 | uint64_t mask; 47 | unsigned be; 48 | unsigned is_signed; 49 | unsigned location; 50 | }; 51 | 52 | static inline int iioutils_check_suffix(const char *str, const char *suffix) 53 | { 54 | return strlen(str) >= strlen(suffix) && 55 | strncmp(str+strlen(str)-strlen(suffix), 56 | suffix, strlen(suffix)) == 0; 57 | } 58 | 59 | int iioutils_break_up_name(const char *full_name, char **generic_name); 60 | int iioutils_get_type(unsigned *is_signed, unsigned *bytes, unsigned *bits_used, 61 | unsigned *shift, uint64_t *mask, unsigned *be, 62 | const char *device_dir, const char *name, 63 | const char *generic_name); 64 | int iioutils_get_param_float(float *output, const char *param_name, 65 | const char *device_dir, const char *name, 66 | const char *generic_name); 67 | void bsort_channel_array_by_index(struct iio_channel_info *ci_array, int cnt); 68 | int build_channel_array(const char *device_dir, 69 | struct iio_channel_info **ci_array, int *counter); 70 | int find_type_by_name(const char *name, const char *type); 71 | int write_sysfs_int(const char *filename, const char *basedir, int val); 72 | int write_sysfs_int_and_verify(const char *filename, const char *basedir, 73 | int val); 74 | int write_sysfs_string_and_verify(const char *filename, const char *basedir, 75 | const char *val); 76 | int write_sysfs_string(const char *filename, const char *basedir, 77 | const char *val); 78 | int read_sysfs_posint(const char *filename, const char *basedir); 79 | int read_sysfs_float(const char *filename, const char *basedir, float *val); 80 | int read_sysfs_string(const char *filename, const char *basedir, char *str); 81 | 82 | #endif /* _IIO_UTILS_H_ */ 83 | -------------------------------------------------------------------------------- /35.3.1/binary/bmi088.ko: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LPXingxing/LI-AR0234CS-STEREO-GMSL2/f4455da7dc1c05b3b235903f521104db219a6acc/35.3.1/binary/bmi088.ko -------------------------------------------------------------------------------- /35.3.1/binary/max96712.ko: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LPXingxing/LI-AR0234CS-STEREO-GMSL2/f4455da7dc1c05b3b235903f521104db219a6acc/35.3.1/binary/max96712.ko -------------------------------------------------------------------------------- /35.3.1/binary/nv_ar0234.ko: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LPXingxing/LI-AR0234CS-STEREO-GMSL2/f4455da7dc1c05b3b235903f521104db219a6acc/35.3.1/binary/nv_ar0234.ko -------------------------------------------------------------------------------- /35.3.1/binary/tegra194-p2888-0001-p2822-0000.dtb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LPXingxing/LI-AR0234CS-STEREO-GMSL2/f4455da7dc1c05b3b235903f521104db219a6acc/35.3.1/binary/tegra194-p2888-0001-p2822-0000.dtb -------------------------------------------------------------------------------- /35.3.1/binary/tegra234-p3701-0000-p3737-0000.dtb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LPXingxing/LI-AR0234CS-STEREO-GMSL2/f4455da7dc1c05b3b235903f521104db219a6acc/35.3.1/binary/tegra234-p3701-0000-p3737-0000.dtb -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # LI-AR0234CS-STEREO-GMSL2 2 | LI-AR0234CS-STEREO-GMSL2 Driver on Xavier 3 | -------------------------------------------------------------------------------- /Xavier_Driver/32.6.1/binary/Image: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LPXingxing/LI-AR0234CS-STEREO-GMSL2/f4455da7dc1c05b3b235903f521104db219a6acc/Xavier_Driver/32.6.1/binary/Image -------------------------------------------------------------------------------- /Xavier_Driver/32.6.1/binary/ar0234.ko: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LPXingxing/LI-AR0234CS-STEREO-GMSL2/f4455da7dc1c05b3b235903f521104db219a6acc/Xavier_Driver/32.6.1/binary/ar0234.ko -------------------------------------------------------------------------------- /Xavier_Driver/32.6.1/binary/max96712.ko: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LPXingxing/LI-AR0234CS-STEREO-GMSL2/f4455da7dc1c05b3b235903f521104db219a6acc/Xavier_Driver/32.6.1/binary/max96712.ko -------------------------------------------------------------------------------- /Xavier_Driver/32.6.1/binary/nvs_bmi088_accel.ko: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LPXingxing/LI-AR0234CS-STEREO-GMSL2/f4455da7dc1c05b3b235903f521104db219a6acc/Xavier_Driver/32.6.1/binary/nvs_bmi088_accel.ko -------------------------------------------------------------------------------- /Xavier_Driver/32.6.1/binary/nvs_bmi088_gyro.ko: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LPXingxing/LI-AR0234CS-STEREO-GMSL2/f4455da7dc1c05b3b235903f521104db219a6acc/Xavier_Driver/32.6.1/binary/nvs_bmi088_gyro.ko -------------------------------------------------------------------------------- /Xavier_Driver/32.6.1/binary/tegra194-p2888-0001-p2822-0000.dtb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LPXingxing/LI-AR0234CS-STEREO-GMSL2/f4455da7dc1c05b3b235903f521104db219a6acc/Xavier_Driver/32.6.1/binary/tegra194-p2888-0001-p2822-0000.dtb -------------------------------------------------------------------------------- /Xavier_Driver/32.6.1/document/AR0234CS-STEREO-GMSL2_Xavier_EVA_R32.6.1_202100812_Driver_Guide.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LPXingxing/LI-AR0234CS-STEREO-GMSL2/f4455da7dc1c05b3b235903f521104db219a6acc/Xavier_Driver/32.6.1/document/AR0234CS-STEREO-GMSL2_Xavier_EVA_R32.6.1_202100812_Driver_Guide.pdf -------------------------------------------------------------------------------- /Xavier_Driver/32.7/binary/Image: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LPXingxing/LI-AR0234CS-STEREO-GMSL2/f4455da7dc1c05b3b235903f521104db219a6acc/Xavier_Driver/32.7/binary/Image -------------------------------------------------------------------------------- /Xavier_Driver/32.7/binary/ar0234.ko: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LPXingxing/LI-AR0234CS-STEREO-GMSL2/f4455da7dc1c05b3b235903f521104db219a6acc/Xavier_Driver/32.7/binary/ar0234.ko -------------------------------------------------------------------------------- /Xavier_Driver/32.7/binary/max96712.ko: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LPXingxing/LI-AR0234CS-STEREO-GMSL2/f4455da7dc1c05b3b235903f521104db219a6acc/Xavier_Driver/32.7/binary/max96712.ko -------------------------------------------------------------------------------- /Xavier_Driver/32.7/binary/tegra194-p2888-0001-p2822-0000.dtb: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LPXingxing/LI-AR0234CS-STEREO-GMSL2/f4455da7dc1c05b3b235903f521104db219a6acc/Xavier_Driver/32.7/binary/tegra194-p2888-0001-p2822-0000.dtb -------------------------------------------------------------------------------- /Xavier_Driver/32.7/document/AR0234CS-STEREO-GMSL2_R32.7_Xavier_NV_max96712_20220316_Driver_Guide.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/LPXingxing/LI-AR0234CS-STEREO-GMSL2/f4455da7dc1c05b3b235903f521104db219a6acc/Xavier_Driver/32.7/document/AR0234CS-STEREO-GMSL2_R32.7_Xavier_NV_max96712_20220316_Driver_Guide.pdf --------------------------------------------------------------------------------