aboutsummaryrefslogtreecommitdiffstats
path: root/include/gpiod.h
blob: b1050f695c8d1535b10ffc3fb50e0717914ac690 (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
409
410
411
412
413
414
415
416
417
418
419
420
421
422
423
424
425
426
427
428
429
430
431
432
433
434
435
436
437
438
439
440
441
442
443
444
445
446
447
448
449
450
451
452
453
454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
506
507
508
509
510
511
512
513
514
515
516
517
518
519
520
521
522
523
524
525
526
527
528
529
530
531
532
533
534
535
536
537
538
539
540
541
542
543
544
545
546
547
548
549
550
551
552
553
554
555
556
557
558
559
560
561
562
563
564
565
566
567
568
569
570
571
572
573
574
575
576
577
578
579
580
581
582
583
584
585
586
587
588
589
590
591
592
593
594
595
596
597
598
599
600
601
602
603
604
605
606
607
608
609
610
611
612
613
614
615
616
617
618
619
620
621
622
623
624
625
626
627
628
629
630
631
632
633
634
635
636
637
638
639
640
641
642
643
644
645
646
647
648
649
650
651
652
653
654
655
656
657
658
659
660
661
662
663
664
665
666
667
668
669
670
671
672
673
674
675
676
677
678
679
680
681
682
683
684
685
686
687
688
689
690
691
692
693
694
695
696
697
698
699
700
701
702
703
704
705
706
707
708
709
710
711
712
713
714
715
716
717
718
719
720
721
722
723
724
725
726
727
728
729
730
731
732
733
734
735
736
737
738
739
740
741
742
743
744
745
746
747
748
749
750
751
752
753
754
755
756
757
758
759
760
761
762
763
764
765
766
767
768
769
770
771
772
773
774
775
776
777
778
779
780
781
782
783
784
785
786
787
788
789
790
791
792
793
794
795
796
797
798
799
800
801
802
803
804
805
806
807
808
809
810
811
812
813
814
815
816
817
818
819
820
821
822
823
824
825
826
827
828
829
830
831
832
833
834
835
836
837
838
839
840
841
842
843
844
845
846
847
848
849
850
851
852
853
854
855
856
857
858
859
860
861
862
863
864
865
866
867
868
869
870
871
872
873
874
875
876
877
878
879
880
881
882
883
884
885
886
887
888
889
890
891
892
893
894
895
896
897
898
899
900
901
902
903
904
905
906
907
908
909
910
911
912
913
914
915
916
917
918
919
920
921
922
923
924
925
926
927
928
929
930
931
932
933
934
935
936
937
938
939
940
941
942
943
944
945
946
947
948
949
950
951
952
953
954
955
956
957
958
959
960
961
962
963
964
965
966
967
968
969
970
971
972
973
974
975
976
977
978
979
980
981
982
983
984
985
986
987
988
989
990
991
992
993
994
995
996
997
998
999
1000
1001
1002
1003
1004
1005
1006
1007
1008
1009
1010
1011
1012
1013
1014
1015
1016
1017
1018
1019
1020
1021
1022
1023
1024
1025
1026
1027
1028
1029
1030
1031
1032
1033
1034
1035
1036
1037
1038
1039
1040
1041
1042
1043
1044
1045
1046
1047
1048
1049
1050
1051
1052
1053
1054
1055
1056
1057
1058
1059
1060
1061
1062
1063
1064
1065
1066
1067
1068
1069
1070
1071
1072
1073
1074
1075
1076
1077
1078
1079
1080
1081
1082
1083
1084
1085
1086
1087
1088
1089
1090
1091
1092
1093
1094
1095
1096
1097
1098
1099
1100
1101
1102
1103
1104
1105
1106
1107
1108
1109
1110
1111
1112
1113
1114
1115
1116
1117
1118
1119
1120
1121
1122
1123
1124
1125
1126
1127
1128
1129
1130
1131
1132
1133
1134
1135
1136
1137
1138
1139
1140
1141
1142
1143
1144
1145
1146
1147
1148
1149
1150
1151
1152
1153
1154
1155
1156
1157
1158
1159
1160
1161
1162
1163
1164
1165
1166
1167
1168
1169
1170
1171
1172
1173
1174
1175
1176
1177
1178
1179
1180
1181
1182
1183
1184
1185
1186
1187
1188
1189
1190
1191
1192
1193
1194
1195
1196
1197
1198
1199
1200
1201
1202
1203
1204
1205
1206
1207
1208
1209
1210
1211
1212
1213
1214
1215
1216
1217
1218
1219
1220
1221
1222
1223
1224
1225
1226
1227
1228
1229
1230
1231
1232
1233
1234
1235
1236
1237
1238
1239
1240
1241
1242
1243
1244
1245
1246
1247
1248
1249
1250
1251
1252
1253
1254
1255
1256
1257
1258
1259
1260
1261
1262
1263
1264
1265
1266
1267
1268
1269
1270
1271
1272
1273
1274
1275
1276
1277
1278
1279
1280
1281
1282
1283
1284
1285
1286
1287
1288
1289
1290
1291
1292
1293
1294
1295
1296
1297
1298
1299
1300
1301
1302
1303
1304
1305
1306
1307
1308
1309
1310
1311
1312
1313
1314
1315
1316
1317
1318
1319
1320
1321
1322
1323
1324
1325
1326
1327
1328
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340
1341
1342
1343
1344
1345
1346
1347
1348
1349
1350
1351
1352
1353
1354
1355
1356
1357
1358
1359
1360
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
/*
 * This file is part of libgpiod.
 *
 * Copyright (C) 2017 Bartosz Golaszewski <bartekgola@gmail.com>
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of version 2.1 of the GNU Lesser General Public License
 * as published by the Free Software Foundation.
 */

#ifndef __LIBGPIOD_GPIOD_H__
#define __LIBGPIOD_GPIOD_H__

#include <stdlib.h>
#include <stdbool.h>
#include <time.h>

#ifdef __cplusplus
extern "C" {
#endif

/**
 * @mainpage libgpiod public API
 *
 * This is the complete documentation of the public API made available to
 * users of libgpiod.
 *
 * <p>The public header is logically split into two high-level parts: the
 * simple API and the low-level API. The former allows users to easily
 * interact with the GPIOs in the system without dealing with the low-level
 * data structures and resource control. The latter gives the user much more
 * fine-grained control over the GPIO interface.
 *
 * <p>The low-level API is further logically split into several parts such
 * as: GPIO chip & line operators, iterators, GPIO events handling etc.
 *
 * <p>General note on error handling: all routines exported by libgpiod  set
 * errno to one of the error values defined in errno.h upon failure. The way
 * of notifying the caller that an error occurred varies between functions,
 * but in general a function that returns an int, returns -1 on error, while
 * a function returning a pointer bails out on error condition by returning
 * a NULL pointer.
 */

struct gpiod_chip;
struct gpiod_line;
struct gpiod_chip_iter;

/**
 * @defgroup __common__ Common helper macros
 * @{
 *
 * Commonly used utility macros.
 */

/**
 * @brief Makes symbol visible.
 */
#define GPIOD_API		__attribute__((visibility("default")))

/**
 * @brief Marks a function argument or variable as potentially unused.
 */
#define GPIOD_UNUSED		__attribute__((unused))

/**
 * @brief Shift 1 by given offset.
 * @param nr Bit position.
 * @return 1 shifted by nr.
 */
#define GPIOD_BIT(nr)		(1UL << (nr))

/**
 * @}
 *
 * @defgroup __high_level__ High-level API
 * @{
 *
 * Simple high-level routines for straightforward GPIO manipulation without
 * the need to use the gpiod_* structures or to keep track of resources.
 */

/**
 * @brief Read current value from a single GPIO line.
 * @param device Name, path or number of the gpiochip.
 * @param offset GPIO line offset on the chip.
 * @param active_low The active state of this line - true if low.
 * @param consumer Name of the consumer.
 * @return 0 or 1 (GPIO value) if the operation succeeds, -1 on error.
 */
int gpiod_simple_get_value(const char *device, unsigned int offset,
			   bool active_low, const char *consumer) GPIOD_API;

/**
 * @brief Read current values from a set of GPIO lines.
 * @param device Name, path or number of the gpiochip.
 * @param offsets An array of offsets of lines whose values should be read.
 * @param values A buffer in which the values will be stored.
 * @param num_lines Number of lines, must be > 0.
 * @param active_low The active state of the lines - true if low.
 * @param consumer Name of the consumer.
 * @return 0 if the operation succeeds, -1 on error.
 */
int gpiod_simple_get_value_multiple(const char *device,
				    const unsigned int *offsets, int *values,
				    unsigned int num_lines, bool active_low,
				    const char *consumer) GPIOD_API;

/**
 * @brief Simple set value callback signature.
 */
typedef void (*gpiod_simple_set_value_cb)(void *);

/**
 * @brief Set value of a single GPIO line.
 * @param device Name, path or number of the gpiochip.
 * @param offset GPIO line offset on the chip.
 * @param value New value.
 * @param active_low The active state of this line - true if low.
 * @param consumer Name of the consumer.
 * @param cb Callback function that will be called right after the value is
 *        set. Users can use this, for example, to pause the execution after
 *        toggling a GPIO.
 * @param data User data that will be passed to the callback function.
 * @return 0 if the operation succeeds, -1 on error.
 */
int gpiod_simple_set_value(const char *device, unsigned int offset, int value,
			   bool active_low, const char *consumer,
			   gpiod_simple_set_value_cb cb, void *data) GPIOD_API;

/**
 * @brief Set values of a set of a set of GPIO lines.
 * @param device Name, path or number of the gpiochip.
 * @param offsets An array of offsets of lines whose values should be set.
 * @param values An array of integers containing new values.
 * @param num_lines Number of lines, must be > 0.
 * @param active_low The active state of the lines - true if low.
 * @param consumer Name of the consumer.
 * @param cb Callback function that will be called right after the values are
 *        set.
 * @param data User data that will be passed to the callback function.
 * @return 0 if the operation succeeds, -1 on error.
 */
int gpiod_simple_set_value_multiple(const char *device,
				    const unsigned int *offsets,
				    const int *values, unsigned int num_lines,
				    bool active_low, const char *consumer,
				    gpiod_simple_set_value_cb cb,
				    void *data) GPIOD_API;

/**
 * @brief Event types that can be passed to the simple event callback.
 */
enum {
	GPIOD_SIMPLE_EVENT_CB_TIMEOUT,
	/**< Waiting for events timed out. */
	GPIOD_SIMPLE_EVENT_CB_RISING_EDGE,
	/**< Rising edge event occured. */
	GPIOD_SIMPLE_EVENT_CB_FALLING_EDGE,
	/**< Falling edge event occured. */
};

/**
 * @brief Return status values that the simple event callback can return.
 */
enum {
	GPIOD_SIMPLE_EVENT_CB_RET_ERR = -1,
	/**< Stop processing events and indicate an error. */
	GPIOD_SIMPLE_EVENT_CB_RET_OK = 0,
	/**< Continue processing events. */
	GPIOD_SIMPLE_EVENT_CB_RET_STOP = 1,
	/**< Stop processing events. */
};

/**
 * @brief Simple event callack signature.
 *
 * The callback function takes the following arguments: event type (int),
 * GPIO line offset (unsigned int), event timestamp (const struct timespec *)
 * and a pointer to user data (void *).
 */
typedef int (*gpiod_simple_event_handle_cb)(int, unsigned int,
					    const struct timespec *, void *);

/**
 * @brief Return status values that the simple event poll callback can return.
 *
 * Positive value returned from the polling callback indicates the number of
 * events that occurred on the set of monitored lines.
 */
enum {
	GPIOD_SIMPLE_EVENT_POLL_RET_STOP = -2,
	/**< The event loop should stop processing events. */
	GPIOD_SIMPLE_EVENT_POLL_RET_ERR = -1,
	/**< Polling error occurred (the polling function should set errno). */
	GPIOD_SIMPLE_EVENT_POLL_RET_TIMEOUT = 0,
	/**< Poll timed out. */
};

/**
 * @brief Helper structure for the simple event loop poll callback.
 */
struct gpiod_simple_event_poll_fd {
	int fd;
	/**< File descriptor number. */
	bool event;
	/**< Indicates whether an event occurred on this file descriptor. */
};

/**
 * @brief Simple event poll callback signature.
 *
 * The poll callback function takes the following arguments: number of lines
 * (unsigned int), an array of file descriptors on which input events should
 * be monitored (struct gpiod_simple_event_poll_fd *), poll timeout
 * (const struct timespec *) and a pointer to user data (void *).
 *
 * The callback should poll for input events on the set of descriptors and
 * return an appropriate value that can be interpreted by the event loop
 * routine.
 */
typedef int (*gpiod_simple_event_poll_cb)(unsigned int,
					  struct gpiod_simple_event_poll_fd *,
					  const struct timespec *, void *);

/**
 * @brief Wait for events on a single GPIO line.
 * @param device Name, path or number of the gpiochip.
 * @param offset GPIO line offset to monitor.
 * @param active_low The active state of this line - true if low.
 * @param consumer Name of the consumer.
 * @param timeout Maximum wait time for each iteration.
 * @param poll_cb Callback function to call when waiting for events.
 * @param event_cb Callback function to call on event occurrence.
 * @param data User data passed to the callback.
 * @return 0 no errors were encountered, -1 if an error occurred.
 *
 * The poll callback can be NULL in which case the routine will fall back to
 * a basic, ppoll() based callback.
 */
int gpiod_simple_event_loop(const char *device, unsigned int offset,
			    bool active_low, const char *consumer,
			    const struct timespec *timeout,
			    gpiod_simple_event_poll_cb poll_cb,
			    gpiod_simple_event_handle_cb event_cb,
			    void *data) GPIOD_API;

/**
 * @brief Wait for events on multiple GPIO lines.
 * @param device Name, path or number of the gpiochip.
 * @param offsets Array of GPIO line offsets to monitor.
 * @param num_lines Number of lines to monitor.
 * @param active_low The active state of this line - true if low.
 * @param consumer Name of the consumer.
 * @param timeout Maximum wait time for each iteration.
 * @param poll_cb Callback function to call when waiting for events.
 * @param event_cb Callback function to call on event occurrence.
 * @param data User data passed to the callback.
 * @return 0 no errors were encountered, -1 if an error occurred.
 *
 * The callback functions work just like in the single line variant.
 */
int gpiod_simple_event_loop_multiple(const char *device,
				     const unsigned int *offsets,
				     unsigned int num_lines, bool active_low,
				     const char *consumer,
				     const struct timespec *timeout,
				     gpiod_simple_event_poll_cb poll_cb,
				     gpiod_simple_event_handle_cb event_cb,
				     void *data) GPIOD_API;

/**
 * @brief Determine the chip name and line offset of a line with given name.
 * @param name The name of the GPIO line to lookup.
 * @param chipname Buffer in which the name of the GPIO chip will be stored.
 * @param chipname_size Size of the chip name buffer.
 * @param offset Pointer to an integer in which the line offset will be stored.
 * @return -1 on error, 0 if the line with given name doesn't exist and 1 if
 *         the line was found. In the first two cases the contents of chipname
 *         and offset remain unchanged.
 *
 * The chip name is truncated if the buffer can't hold its entire size.
 */
int gpiod_simple_find_line(const char *name, char *chipname,
			   size_t chipname_size,
			   unsigned int *offset) GPIOD_API;

/**
 * @}
 *
 * @defgroup __chips__ GPIO chip operations
 * @{
 *
 * Functions and data structures dealing with GPIO chips.
 */

/**
 * @brief Open a gpiochip by path.
 * @param path Path to the gpiochip device file.
 * @return GPIO chip handle or NULL if an error occurred.
 */
struct gpiod_chip * gpiod_chip_open(const char *path) GPIOD_API;

/**
 * @brief Open a gpiochip by name.
 * @param name Name of the gpiochip to open.
 * @return GPIO chip handle or NULL if an error occurred.
 *
 * This routine appends name to '/dev/' to create the path.
 */
struct gpiod_chip * gpiod_chip_open_by_name(const char *name) GPIOD_API;

/**
 * @brief Open a gpiochip by number.
 * @param num Number of the gpiochip.
 * @return GPIO chip handle or NULL if an error occurred.
 *
 * This routine appends num to '/dev/gpiochip' to create the path.
 */
struct gpiod_chip * gpiod_chip_open_by_number(unsigned int num) GPIOD_API;

/**
 * @brief Open a gpiochip by label.
 * @param label Label of the gpiochip to open.
 * @return GPIO chip handle or NULL if the chip with given label was not found
 *         or an error occured.
 */
struct gpiod_chip * gpiod_chip_open_by_label(const char *label) GPIOD_API;

/**
 * @brief Open a gpiochip based on the best guess what the path is.
 * @param descr String describing the gpiochip.
 * @return GPIO chip handle or NULL if an error occurred.
 *
 * This routine tries to figure out whether the user passed it the path to
 * the GPIO chip, its name, label or number as a string. Then it tries to
 * open it using one of the other gpiod_chip_open** routines.
 */
struct gpiod_chip * gpiod_chip_open_lookup(const char *descr) GPIOD_API;

/**
 * @brief Close a GPIO chip handle and release all allocated resources.
 * @param chip The GPIO chip object.
 */
void gpiod_chip_close(struct gpiod_chip *chip) GPIOD_API;

/**
 * @brief Get the GPIO chip name as represented in the kernel.
 * @param chip The GPIO chip object.
 * @return Pointer to a human-readable string containing the chip name.
 */
const char * gpiod_chip_name(struct gpiod_chip *chip) GPIOD_API;

/**
 * @brief Get the GPIO chip label as represented in the kernel.
 * @param chip The GPIO chip object.
 * @return Pointer to a human-readable string containing the chip label.
 */
const char * gpiod_chip_label(struct gpiod_chip *chip) GPIOD_API;

/**
 * @brief Get the number of GPIO lines exposed by this chip.
 * @param chip The GPIO chip object.
 * @return Number of GPIO lines.
 */
unsigned int gpiod_chip_num_lines(struct gpiod_chip *chip) GPIOD_API;

/**
 * @brief Get the handle to the GPIO line at given offset.
 * @param chip The GPIO chip object.
 * @param offset The offset of the GPIO line.
 * @return Pointer to the GPIO line handle or NULL if an error occured.
 */
struct gpiod_line *
gpiod_chip_get_line(struct gpiod_chip *chip, unsigned int offset) GPIOD_API;

/**
 * @brief Find a GPIO line by name among lines associated with given GPIO chip.
 * @param chip The GPIO chip object.
 * @param name The name of the GPIO line.
 * @return Pointer to the GPIO line handle or NULL if the line could not be
 *         found or an error occurred.
 *
 * In case a line with given name is not associated with given chip, the
 * functions sets errno to ENOENT.
 */
struct gpiod_line *
gpiod_chip_find_line(struct gpiod_chip *chip, const char *name) GPIOD_API;

/**
 * @}
 *
 * @defgroup __lines__ GPIO line operations
 * @{
 *
 * Functions and data structures dealing with GPIO lines.
 *
 * @defgroup __line_bulk__ Operating on multiple lines
 * @{
 */

/**
 * @brief Maximum number of GPIO lines that can be requested at once.
 */
#define GPIOD_LINE_BULK_MAX_LINES		64

/**
 * @brief Helper structure for storing a set of GPIO line objects.
 *
 * This structure is used in all operations involving sets of GPIO lines. If
 * a bulk object is being passed to a function while containing zero lines,
 * the result is undefined.
 */
struct gpiod_line_bulk {
	struct gpiod_line *lines[GPIOD_LINE_BULK_MAX_LINES];
	/**< Buffer for line pointers. */
	unsigned int num_lines;
	/**< Number of lines currently held in this structure. */
};

/**
 * @brief Static initializer for GPIO bulk objects.
 *
 * This macro simply sets the internally held number of lines to 0.
 */
#define GPIOD_LINE_BULK_INITIALIZER	{ { NULL }, 0 }

/**
 * @brief Initialize a GPIO bulk object.
 * @param bulk Line bulk object.
 *
 * This routine simply sets the internally held number of lines to 0.
 */
static inline void gpiod_line_bulk_init(struct gpiod_line_bulk *bulk)
{
	bulk->num_lines = 0;
}

/**
 * @brief Add a single line to a GPIO bulk object.
 * @param bulk Line bulk object.
 * @param line Line to add.
 */
static inline void gpiod_line_bulk_add(struct gpiod_line_bulk *bulk,
				       struct gpiod_line *line)
{
	bulk->lines[bulk->num_lines++] = line;
}

/**
 * @brief Retrieve the line handle from a line bulk object at given offset.
 * @param bulk Line bulk object.
 * @param offset Line offset.
 * @return Line handle at given offset.
 */
static inline struct gpiod_line *
gpiod_line_bulk_get_line(struct gpiod_line_bulk *bulk, unsigned int offset)
{
	return bulk->lines[offset];
}

/**
 * @brief Retrieve the number of GPIO lines held by this line bulk object.
 * @param bulk Line bulk object.
 * @return Number of lines held by this line bulk.
 */
static inline unsigned int
gpiod_line_bulk_num_lines(struct gpiod_line_bulk *bulk)
{
	return bulk->num_lines;
}

/**
 * @brief Iterate over all line handles held by a line bulk object.
 * @param bulk Line bulk object.
 * @param line GPIO line handle. On each iteration, the subsequent line handle
 *             is assigned to this pointer.
 * @param lineptr Pointer to a GPIO line handle used to store the loop state.
 */
#define gpiod_line_bulk_foreach_line(bulk, line, lineptr)		\
	for ((lineptr) = (bulk)->lines, (line) = *(lineptr);		\
	     (lineptr) <= (bulk)->lines + ((bulk)->num_lines - 1);	\
	     (lineptr)++, (line) = *(lineptr))

/**
 * @brief Iterate over all line handles held by a line bulk object.
 * @param bulk Line bulk object.
 * @param line GPIO line handle. On each iteration, the subsequent line handle
 *             is assigned to this pointer.
 * @param offset An integer variable used to store the loop state.
 *
 * This is a variant of ::gpiod_line_bulk_foreach_line which uses an integer
 * variable (either signed or unsigned) to store the loop state. This offset
 * variable is guaranteed to correspond with the offset of the current line in
 * the bulk->lines array.
 */
#define gpiod_line_bulk_foreach_line_off(bulk, line, offset)		\
	for ((offset) = 0, (line) = (bulk)->lines[0];			\
	     (offset) < (bulk)->num_lines;				\
	     (offset)++, (line) = (bulk)->lines[(offset)])

/**
 * @}
 *
 * @defgroup __line_info__ Line info
 * @{
 */

/**
 * @brief Possible direction settings.
 */
enum {
	GPIOD_LINE_DIRECTION_INPUT,
	/**< Direction is input - we're reading the state of a GPIO line. */
	GPIOD_LINE_DIRECTION_OUTPUT,
	/**< Direction is output - we're driving the GPIO line. */
};

/**
 * @brief Possible active state settings.
 */
enum {
	GPIOD_LINE_ACTIVE_STATE_HIGH,
	/**< The active state of a GPIO is active-high. */
	GPIOD_LINE_ACTIVE_STATE_LOW,
	/**< The active state of a GPIO is active-low. */
};

/**
 * @brief Read the GPIO line offset.
 * @param line GPIO line object.
 * @return Line offset.
 */
unsigned int gpiod_line_offset(struct gpiod_line *line) GPIOD_API;

/**
 * @brief Read the GPIO line name.
 * @param line GPIO line object.
 * @return Name of the GPIO line as it is represented in the kernel. This
 *         routine returns a pointer to a null-terminated string or NULL if
 *         the line is unnamed.
 */
const char * gpiod_line_name(struct gpiod_line *line) GPIOD_API;

/**
 * @brief Read the GPIO line consumer name.
 * @param line GPIO line object.
 * @return Name of the GPIO consumer name as it is represented in the
 *         kernel. This routine returns a pointer to a null-terminated string
 *         or NULL if the line is not used.
 */
const char * gpiod_line_consumer(struct gpiod_line *line) GPIOD_API;

/**
 * @brief Read the GPIO line direction setting.
 * @param line GPIO line object.
 * @return Returns GPIOD_DIRECTION_INPUT or GPIOD_DIRECTION_OUTPUT.
 */
int gpiod_line_direction(struct gpiod_line *line) GPIOD_API;

/**
 * @brief Read the GPIO line active state setting.
 * @param line GPIO line object.
 * @return Returns GPIOD_ACTIVE_STATE_HIGH or GPIOD_ACTIVE_STATE_LOW.
 */
int gpiod_line_active_state(struct gpiod_line *line) GPIOD_API;

/**
 * @brief Check if the line is currently in use.
 * @param line GPIO line object.
 * @return True if the line is in use, false otherwise.
 *
 * The user space can't know exactly why a line is busy. It may have been
 * requested by another process or hogged by the kernel. It only matters that
 * the line is used and we can't request it.
 */
bool gpiod_line_is_used(struct gpiod_line *line) GPIOD_API;

/**
 * @brief Check if the line is an open-drain GPIO.
 * @param line GPIO line object.
 * @return True if the line is an open-drain GPIO, false otherwise.
 */
bool gpiod_line_is_open_drain(struct gpiod_line *line) GPIOD_API;

/**
 * @brief Check if the line is an open-source GPIO.
 * @param line GPIO line object.
 * @return True if the line is an open-source GPIO, false otherwise.
 */
bool gpiod_line_is_open_source(struct gpiod_line *line) GPIOD_API;

/**
 * @brief Re-read the line info.
 * @param line GPIO line object.
 * @return 0 is the operation succeeds. In case of an error this routine
 *         returns -1 and sets the last error number.
 *
 * The line info is initially retrieved from the kernel by
 * gpiod_chip_get_line(). Users can use this line to manually re-read the line
 * info.
 */
int gpiod_line_update(struct gpiod_line *line) GPIOD_API;

/**
 * @brief Check if the line info needs to be updated.
 * @param line GPIO line object.
 * @return Returns false if the line is up-to-date. True otherwise.
 *
 * The line is updated by calling gpiod_line_update() from within
 * gpiod_chip_get_line() and on every line request/release. However: an error
 * returned from gpiod_line_update() only breaks the execution of the former.
 * The request/release routines only set the internal up-to-date flag to false
 * and continue their execution. This routine allows to check if a line info
 * update failed at some point and we should call gpiod_line_update()
 * explicitly.
 */
bool gpiod_line_needs_update(struct gpiod_line *line) GPIOD_API;

/**
 * @}
 *
 * @defgroup __line_request__ Line requests
 * @{
 */

/**
 * @brief Available types of requests.
 */
enum {
	GPIOD_LINE_REQUEST_DIRECTION_AS_IS,
	/**< Request the line(s), but don't change current direction. */
	GPIOD_LINE_REQUEST_DIRECTION_INPUT,
	/**< Request the line(s) for reading the GPIO line state. */
	GPIOD_LINE_REQUEST_DIRECTION_OUTPUT,
	/**< Request the line(s) for setting the GPIO line state. */
	GPIOD_LINE_REQUEST_EVENT_FALLING_EDGE,
	/**< Monitor both types of events. */
	GPIOD_LINE_REQUEST_EVENT_RISING_EDGE,
	/**< Only watch rising edge events. */
	GPIOD_LINE_REQUEST_EVENT_BOTH_EDGES,
	/**< Only watch falling edge events. */
};

/**
 * @brief Miscellaneous GPIO request flags.
 */
enum {
	GPIOD_LINE_REQUEST_OPEN_DRAIN	= GPIOD_BIT(0),
	/**< The line is an open-drain port. */
	GPIOD_LINE_REQUEST_OPEN_SOURCE	= GPIOD_BIT(1),
	/**< The line is an open-source port. */
	GPIOD_LINE_REQUEST_ACTIVE_LOW	= GPIOD_BIT(2),
	/**< The active state of the line is low (high is the default). */
};

/**
 * @brief Structure holding configuration of a line request.
 */
struct gpiod_line_request_config {
	const char *consumer;
	/**< Name of the consumer. */
	int request_type;
	/**< Request type. */
	int flags;
	/**< Other configuration flags. */
};

/**
 * @brief Reserve a single line.
 * @param line GPIO line object.
 * @param config Request options.
 * @param default_val Default line value - only relevant if we're setting
 *        the direction to output.
 * @return 0 if the line was properly reserved. In case of an error this
 *         routine returns -1 and sets the last error number.
 *
 * If this routine succeeds, the caller takes ownership of the GPIO line until
 * it's released.
 */
int gpiod_line_request(struct gpiod_line *line,
		       const struct gpiod_line_request_config *config,
		       int default_val) GPIOD_API;

/**
 * @brief Reserve a single line, set the direction to input.
 * @param line GPIO line object.
 * @param consumer Name of the consumer.
 * @return 0 if the line was properly reserved, -1 on failure.
 */
int gpiod_line_request_input(struct gpiod_line *line,
			     const char *consumer) GPIOD_API;

/**
 * @brief Reserve a single line, set the direction to output.
 * @param line GPIO line object.
 * @param consumer Name of the consumer.
 * @param default_val Default line value.
 * @return 0 if the line was properly reserved, -1 on failure.
 */
int gpiod_line_request_output(struct gpiod_line *line,
			      const char *consumer, int default_val) GPIOD_API;

/**
 * @brief Request rising edge event notifications on a single line.
 * @param line GPIO line object.
 * @param consumer Name of the consumer.
 * @return 0 if the operation succeeds, -1 on failure.
 */
int gpiod_line_request_rising_edge_events(struct gpiod_line *line,
					  const char *consumer) GPIOD_API;

/**
 * @brief Request falling edge event notifications on a single line.
 * @param line GPIO line object.
 * @param consumer Name of the consumer.
 * @return 0 if the operation succeeds, -1 on failure.
 */
int gpiod_line_request_falling_edge_events(struct gpiod_line *line,
					   const char *consumer) GPIOD_API;

/**
 * @brief Request all event type notifications on a single line.
 * @param line GPIO line object.
 * @param consumer Name of the consumer.
 * @return 0 if the operation succeeds, -1 on failure.
 */
int gpiod_line_request_both_edges_events(struct gpiod_line *line,
					 const char *consumer) GPIOD_API;

/**
 * @brief Reserve a single line, set the direction to input.
 * @param line GPIO line object.
 * @param consumer Name of the consumer.
 * @param flags Additional request flags.
 * @return 0 if the line was properly reserved, -1 on failure.
 */
int gpiod_line_request_input_flags(struct gpiod_line *line,
				   const char *consumer, int flags) GPIOD_API;

/**
 * @brief Reserve a single line, set the direction to output.
 * @param line GPIO line object.
 * @param consumer Name of the consumer.
 * @param flags Additional request flags.
 * @param default_val Default line value.
 * @return 0 if the line was properly reserved, -1 on failure.
 */
int gpiod_line_request_output_flags(struct gpiod_line *line,
				    const char *consumer, int flags,
				    int default_val) GPIOD_API;

/**
 * @brief Request rising edge event notifications on a single line.
 * @param line GPIO line object.
 * @param consumer Name of the consumer.
 * @param flags Additional request flags.
 * @return 0 if the operation succeeds, -1 on failure.
 */
int gpiod_line_request_rising_edge_events_flags(struct gpiod_line *line,
						const char *consumer,
						int flags) GPIOD_API;

/**
 * @brief Request falling edge event notifications on a single line.
 * @param line GPIO line object.
 * @param consumer Name of the consumer.
 * @param flags Additional request flags.
 * @return 0 if the operation succeeds, -1 on failure.
 */
int gpiod_line_request_falling_edge_events_flags(struct gpiod_line *line,
						 const char *consumer,
						 int flags) GPIOD_API;

/**
 * @brief Request all event type notifications on a single line.
 * @param line GPIO line object.
 * @param consumer Name of the consumer.
 * @param flags Additional request flags.
 * @return 0 if the operation succeeds, -1 on failure.
 */
int gpiod_line_request_both_edges_events_flags(struct gpiod_line *line,
					       const char *consumer,
					       int flags) GPIOD_API;

/**
 * @brief Reserve a set of GPIO lines.
 * @param bulk Set of GPIO lines to reserve.
 * @param config Request options.
 * @param default_vals Default line values - only relevant if we're setting
 *        the direction to output.
 * @return 0 if the all lines were properly requested. In case of an error
 *         this routine returns -1 and sets the last error number.
 *
 * If this routine succeeds, the caller takes ownership of the GPIO lines
 * until they're released. All the requested lines must be prodivided by the
 * same gpiochip.
 */
int gpiod_line_request_bulk(struct gpiod_line_bulk *bulk,
			    const struct gpiod_line_request_config *config,
			    const int *default_vals) GPIOD_API;

/**
 * @brief Reserve a set of GPIO lines, set the direction to input.
 * @param bulk Set of GPIO lines to reserve.
 * @param consumer Name of the consumer.
 * @return 0 if the lines were properly reserved, -1 on failure.
 */
int gpiod_line_request_bulk_input(struct gpiod_line_bulk *bulk,
				  const char *consumer) GPIOD_API;

/**
 * @brief Reserve a set of GPIO lines, set the direction to output.
 * @param bulk Set of GPIO lines to reserve.
 * @param consumer Name of the consumer.
 * @param default_vals Default line values.
 * @return 0 if the lines were properly reserved, -1 on failure.
 */
int gpiod_line_request_bulk_output(struct gpiod_line_bulk *bulk,
				   const char *consumer,
				   const int *default_vals) GPIOD_API;

/**
 * @brief Request rising edge event notifications on a set of lines.
 * @param bulk Set of GPIO lines to request.
 * @param consumer Name of the consumer.
 * @return 0 if the operation succeeds, -1 on failure.
 */
int gpiod_line_request_bulk_rising_edge_events(struct gpiod_line_bulk *bulk,
					       const char *consumer) GPIOD_API;

/**
 * @brief Request falling edge event notifications on a set of lines.
 * @param bulk Set of GPIO lines to request.
 * @param consumer Name of the consumer.
 * @return 0 if the operation succeeds, -1 on failure.
 */
int gpiod_line_request_bulk_falling_edge_events(struct gpiod_line_bulk *bulk,
						const char *consumer) GPIOD_API;

/**
 * @brief Request all event type notifications on a set of lines.
 * @param bulk Set of GPIO lines to request.
 * @param consumer Name of the consumer.
 * @return 0 if the operation succeeds, -1 on failure.
 */
int gpiod_line_request_bulk_both_edges_events(struct gpiod_line_bulk *bulk,
					      const char *consumer) GPIOD_API;

/**
 * @brief Reserve a set of GPIO lines, set the direction to input.
 * @param bulk Set of GPIO lines to reserve.
 * @param consumer Name of the consumer.
 * @param flags Additional request flags.
 * @return 0 if the lines were properly reserved, -1 on failure.
 */
int gpiod_line_request_bulk_input_flags(struct gpiod_line_bulk *bulk,
					const char *consumer,
					int flags) GPIOD_API;

/**
 * @brief Reserve a set of GPIO lines, set the direction to output.
 * @param bulk Set of GPIO lines to reserve.
 * @param consumer Name of the consumer.
 * @param flags Additional request flags.
 * @param default_vals Default line values.
 * @return 0 if the lines were properly reserved, -1 on failure.
 */
int gpiod_line_request_bulk_output_flags(struct gpiod_line_bulk *bulk,
					 const char *consumer, int flags,
					 const int *default_vals) GPIOD_API;

/**
 * @brief Request rising edge event notifications on a set of lines.
 * @param bulk Set of GPIO lines to request.
 * @param consumer Name of the consumer.
 * @param flags Additional request flags.
 * @return 0 if the operation succeeds, -1 on failure.
 */
int gpiod_line_request_bulk_rising_edge_events_flags(
					struct gpiod_line_bulk *bulk,
					const char *consumer,
					int flags) GPIOD_API;

/**
 * @brief Request falling edge event notifications on a set of lines.
 * @param bulk Set of GPIO lines to request.
 * @param consumer Name of the consumer.
 * @param flags Additional request flags.
 * @return 0 if the operation succeeds, -1 on failure.
 */
int gpiod_line_request_bulk_falling_edge_events_flags(
					struct gpiod_line_bulk *bulk,
					const char *consumer,
					int flags) GPIOD_API;

/**
 * @brief Request all event type notifications on a set of lines.
 * @param bulk Set of GPIO lines to request.
 * @param consumer Name of the consumer.
 * @param flags Additional request flags.
 * @return 0 if the operation succeeds, -1 on failure.
 */
int gpiod_line_request_bulk_both_edges_events_flags(
					struct gpiod_line_bulk *bulk,
					const char *consumer,
					int flags) GPIOD_API;

/**
 * @brief Release a previously reserved line.
 * @param line GPIO line object.
 */
void gpiod_line_release(struct gpiod_line *line) GPIOD_API;

/**
 * @brief Release a set of previously reserved lines.
 * @param bulk Set of GPIO lines to release.
 *
 * If the lines were not previously requested together, the behavior is
 * undefined.
 */
void gpiod_line_release_bulk(struct gpiod_line_bulk *bulk) GPIOD_API;

/**
 * @brief Check if the calling user has ownership of this line.
 * @param line GPIO line object.
 * @return True if given line was requested, false otherwise.
 */
bool gpiod_line_is_requested(struct gpiod_line *line) GPIOD_API;

/**
 * @brief Check if the calling user has neither requested ownership of this
 *        line nor configured any event notifications.
 * @param line GPIO line object.
 * @return True if given line is free, false otherwise.
 */
bool gpiod_line_is_free(struct gpiod_line *line) GPIOD_API;

/**
 * @}
 *
 * @defgroup __line_value__ Reading & setting line values
 * @{
 */

/**
 * @brief Read current value of a single GPIO line.
 * @param line GPIO line object.
 * @return 0 or 1 if the operation succeeds. On error this routine returns -1
 *         and sets the last error number.
 */
int gpiod_line_get_value(struct gpiod_line *line) GPIOD_API;

/**
 * @brief Read current values of a set of GPIO lines.
 * @param bulk Set of GPIO lines to reserve.
 * @param values An array big enough to hold line_bulk->num_lines values.
 * @return 0 is the operation succeeds. In case of an error this routine
 *         returns -1 and sets the last error number.
 *
 * If succeeds, this routine fills the values array with a set of values in
 * the same order, the lines are added to line_bulk. If the lines were not
 * previously requested together, the behavior is undefined.
 */
int gpiod_line_get_value_bulk(struct gpiod_line_bulk *bulk,
			      int *values) GPIOD_API;

/**
 * @brief Set the value of a single GPIO line.
 * @param line GPIO line object.
 * @param value New value.
 * @return 0 is the operation succeeds. In case of an error this routine
 *         returns -1 and sets the last error number.
 */
int gpiod_line_set_value(struct gpiod_line *line, int value) GPIOD_API;

/**
 * @brief Set the values of a set of GPIO lines.
 * @param bulk Set of GPIO lines to reserve.
 * @param values An array holding line_bulk->num_lines new values for lines.
 * @return 0 is the operation succeeds. In case of an error this routine
 *         returns -1 and sets the last error number.
 *
 * If the lines were not previously requested together, the behavior is
 * undefined.
 */
int gpiod_line_set_value_bulk(struct gpiod_line_bulk *bulk,
			      int *values) GPIOD_API;

/**
 * @}
 *
 * @defgroup __line_event__ Line events handling
 * @{
 */

/**
 * @brief Event types.
 */
enum {
	GPIOD_LINE_EVENT_RISING_EDGE,
	/**< Rising edge event. */
	GPIOD_LINE_EVENT_FALLING_EDGE,
	/**< Falling edge event. */
};

/**
 * @brief Structure holding event info.
 */
struct gpiod_line_event {
	struct timespec ts;
	/**< Best estimate of time of event occurrence. */
	int event_type;
	/**< Type of the event that occurred. */
};

/**
 * @brief Wait for an event on a single line.
 * @param line GPIO line object.
 * @param timeout Wait time limit.
 * @return 0 if wait timed out, -1 if an error occurred, 1 if an event
 *         occurred.
 */
int gpiod_line_event_wait(struct gpiod_line *line,
			  const struct timespec *timeout) GPIOD_API;

/**
 * @brief Wait for events on a set of lines.
 * @param bulk Set of GPIO lines to monitor.
 * @param timeout Wait time limit.
 * @param event_bulk Bulk object in which to store the line handles on which
 *        events occurred. Can be NULL.
 * @return 0 if wait timed out, -1 if an error occurred, 1 if at least one
 *         event occurred.
 */
int gpiod_line_event_wait_bulk(struct gpiod_line_bulk *bulk,
			       const struct timespec *timeout,
			       struct gpiod_line_bulk *event_bulk) GPIOD_API;

/**
 * @brief Read the last event from the GPIO line.
 * @param line GPIO line object.
 * @param event Buffer to which the event data will be copied.
 * @return 0 if the event was read correctly, -1 on error.
 */
int gpiod_line_event_read(struct gpiod_line *line,
			  struct gpiod_line_event *event) GPIOD_API;

/**
 * @brief Get the event file descriptor.
 * @param line GPIO line object.
 * @return Number of the event file descriptor or -1 on error.
 *
 * Users may want to poll the event file descriptor on their own. This routine
 * allows to access it.
 */
int gpiod_line_event_get_fd(struct gpiod_line *line) GPIOD_API;

/**
 * @brief Read the last GPIO event directly from a file descriptor.
 * @param fd File descriptor.
 * @param event Buffer to which the event data will be copied.
 * @return 0 if the event was read correctly, -1 on error.
 *
 * Users who directly poll the file descriptor for incoming events can also
 * directly read the event data from it using this routine. This function
 * translates the kernel representation of the event to the libgpiod format.
 */
int gpiod_line_event_read_fd(int fd, struct gpiod_line_event *event) GPIOD_API;

/**
 * @}
 *
 * @defgroup __line_misc__ Misc line functions
 * @{
 */

/**
 * @brief Get a GPIO line handle by GPIO chip description and offset.
 * @param device String describing the gpiochip.
 * @param offset The offset of the GPIO line.
 * @return GPIO line handle or NULL if an error occurred.
 *
 * This routine provides a shorter alternative to calling
 * ::gpiod_chip_open_lookup and ::gpiod_chip_get_line.
 *
 * If this function succeeds, the caller is responsible for closing the
 * associated GPIO chip.
 */
struct gpiod_line *
gpiod_line_get(const char *device, unsigned int offset) GPIOD_API;

/**
 * @brief Find a GPIO line by its name.
 * @param name Name of the GPIO line.
 * @return Returns the GPIO line handle if the line exists in the system or
 *         NULL if it couldn't be located or an error occurred.
 *
 * If this routine succeeds, the user must manually close the GPIO chip owning
 * this line to avoid memory leaks. If the line could not be found, this
 * functions sets errno to ENOENT.
 */
struct gpiod_line * gpiod_line_find(const char *name) GPIOD_API;

/**
 * @brief Close a GPIO chip owning this line and release all resources.
 * @param line GPIO line object
 *
 * After this function returns, the line must no longer be used.
 */
void gpiod_line_close_chip(struct gpiod_line *line) GPIOD_API;

/**
 * @brief Get the handle to the GPIO chip controlling this line.
 * @param line The GPIO line object.
 * @return Pointer to the GPIO chip handle controlling this line.
 */
struct gpiod_chip * gpiod_line_get_chip(struct gpiod_line *line) GPIOD_API;

/**
 * @}
 *
 * @}
 *
 * @defgroup __iterators__ Iterators for GPIO chips and lines
 * @{
 *
 * These functions and data structures allow easy iterating over GPIO
 * chips and lines.
 */

/**
 * @brief Create a new gpiochip iterator.
 * @return Pointer to a new chip iterator object or NULL if an error occurred.
 */
struct gpiod_chip_iter * gpiod_chip_iter_new(void) GPIOD_API;

/**
 * @brief Release all resources allocated for the gpiochip iterator and close
 *        the most recently opened gpiochip (if any).
 * @param iter The gpiochip iterator object.
 */
void gpiod_chip_iter_free(struct gpiod_chip_iter *iter) GPIOD_API;

/**
 * @brief Release all resources allocated for the gpiochip iterator but
 *        don't close the most recently opened gpiochip (if any).
 * @param iter The gpiochip iterator object.
 *
 * Users may want to break the loop when iterating over gpiochips and keep
 * the most recently opened chip active while freeing the iterator data.
 * This routine enables that.
 */
void gpiod_chip_iter_free_noclose(struct gpiod_chip_iter *iter) GPIOD_API;

/**
 * @brief Get the next gpiochip handle.
 * @param iter The gpiochip iterator object.
 * @return Pointer to an open gpiochip handle or NULL if the next chip can't
 *         be accessed.
 *
 * Internally this routine scans the /dev/ directory, storing current state
 * in the chip iterator structure, and tries to open the next /dev/gpiochipX
 * device file. If an error occurs or no more chips are present, the function
 * returns NULL.
 */
struct gpiod_chip *
gpiod_chip_iter_next(struct gpiod_chip_iter *iter) GPIOD_API;

/**
 * @brief Get the next gpiochip handle without closing the previous one.
 * @param iter The gpiochip iterator object.
 * @return Pointer to an open gpiochip handle or NULL if the next chip can't
 *         be accessed.
 *
 * Internally this routine scans the /dev/ directory, storing current state
 * in the chip iterator structure, and tries to open the next /dev/gpiochipX
 * device file. If an error occurs or no more chips are present, the function
 * returns NULL.
 * Note: The user is responsible for closing the chips after use.
 */
struct gpiod_chip *
gpiod_chip_iter_next_noclose(struct gpiod_chip_iter *iter) GPIOD_API;

/**
 * @brief Iterate over all gpiochip present in the system.
 * @param iter An initialized GPIO chip iterator.
 * @param chip Pointer to a GPIO chip handle. On each iteration the newly
 *             opened chip handle is assigned to this argument.
 *
 * The user must not close the GPIO chip manually - instead the previous chip
 * handle is closed automatically on the next iteration. The last chip to be
 * opened is closed internally by gpiod_chip_iter_free().
 */
#define gpiod_foreach_chip(iter, chip)					\
	for ((chip) = gpiod_chip_iter_next(iter);			\
	     !gpiod_chip_iter_done(iter);				\
	     (chip) = gpiod_chip_iter_next(iter))

/**
 * @brief Iterate over all gpiochip present in the system without closing them.
 * @param iter An initialized GPIO chip iterator.
 * @param chip Pointer to a GPIO chip handle. On each iteration the newly
 *             opened chip handle is assigned to this argument.
 *
 * The user must close the GPIO chip manually after use, until then, the chip
 * remains open. Free the iterator by calling gpiod_chip_iter_free_noclose to
 * avoid closing the last chip automatically.
 */
#define gpiod_foreach_chip_noclose(iter, chip)				\
	for ((chip) = gpiod_chip_iter_next_noclose(iter);		\
	     !gpiod_chip_iter_done(iter);				\
	     (chip) = gpiod_chip_iter_next_noclose(iter))

/**
 * @brief Check if we're done iterating over gpiochips on this iterator.
 * @param iter The gpiochip iterator object.
 * @return True if we've iterated over all chips, false otherwise.
 */
bool gpiod_chip_iter_done(struct gpiod_chip_iter *iter) GPIOD_API;

/**
 * @brief Check if we've encountered an error condition while opening a
 *        gpiochip.
 * @param iter The gpiochip iterator object.
 * @return True if there was an error opening a gpiochip device file,
 *         false otherwise.
 */
bool gpiod_chip_iter_err(struct gpiod_chip_iter *iter) GPIOD_API;

/**
 * @brief Get the name of the gpiochip that we failed to access.
 * @param iter The gpiochip iterator object.
 * @return If gpiod_chip_iter_iserr() returned true, this function returns a
 *         pointer to the name of the gpiochip that we failed to access.
 *         If there was no error this function returns NULL.
 *
 * NOTE: this function will return NULL if the internal memory allocation
 * fails.
 */
const char *
gpiod_chip_iter_failed_chip(struct gpiod_chip_iter *iter) GPIOD_API;

/**
 * @brief Possible states of a line iterator.
 */
enum {
	GPIOD_LINE_ITER_STATE_INIT = 0,
	/**< Line iterator is initiated or iterating over lines. */
	GPIOD_LINE_ITER_STATE_DONE,
	/**< Line iterator is done with all lines on this chip. */
	GPIOD_LINE_ITER_STATE_ERR,
	/**< There was an error retrieving info for a line. */
};

/**
 * @brief GPIO line iterator structure.
 *
 * This structure is used in conjunction with gpiod_line_iter_next() to
 * iterate over all GPIO lines of a single GPIO chip.
 */
struct gpiod_line_iter {
	unsigned int offset;
	/**< Current line offset. */
	struct gpiod_chip *chip;
	/**< GPIO chip whose line we're iterating over. */
	int state;
	/**< Current state of the iterator. */
};

/**
 * @brief Static initializer for line iterators.
 * @param chip The gpiochip object whose lines we want to iterate over.
 */
#define GPIOD_LINE_ITER_INITIALIZER(chip)				\
	{ 0, (chip), GPIOD_LINE_ITER_STATE_INIT }

/**
 * @brief Initialize a GPIO line iterator.
 * @param iter Pointer to a GPIO line iterator.
 * @param chip The gpiochip object whose lines we want to iterate over.
 */
static inline void gpiod_line_iter_init(struct gpiod_line_iter *iter,
					struct gpiod_chip *chip)
{
	iter->offset = 0;
	iter->chip = chip;
	iter->state = GPIOD_LINE_ITER_STATE_INIT;
}

/**
 * @brief Get the next GPIO line handle.
 * @param iter The GPIO line iterator object.
 * @return Pointer to the next GPIO line handle or NULL if no more lines or
 *         and error occured.
 */
struct gpiod_line *
gpiod_line_iter_next(struct gpiod_line_iter *iter) GPIOD_API;

/**
 * @brief Check if we're done iterating over lines on this iterator.
 * @param iter The GPIO line iterator object.
 * @return True if we've iterated over all lines, false otherwise.
 */
static inline bool gpiod_line_iter_done(const struct gpiod_line_iter *iter)
{
	return iter->state == GPIOD_LINE_ITER_STATE_DONE;
}

/**
 * @brief Check if we've encountered an error condition while retrieving
 *        info for a line.
 * @param iter The GPIO line iterator object.
 * @return True if there was an error retrieving info about a GPIO line,
 *         false otherwise.
 */
static inline bool gpiod_line_iter_err(const struct gpiod_line_iter *iter)
{
	return iter->state == GPIOD_LINE_ITER_STATE_ERR;
}

/**
 * @brief Get the offset of the last line we tried to open.
 * @param iter The GPIO line iterator object.
 * @return The offset of the last line we tried to open - whether we failed
 *         or succeeded to do so.
 *
 * If this function is called before gpiod_line_iter_next() is called at least
 * once, the results are undefined.
 */
static inline unsigned int
gpiod_line_iter_last_offset(const struct gpiod_line_iter *iter)
{
	return iter->offset - 1;
}

/**
 * @brief Iterate over all GPIO lines of a single chip.
 * @param iter An initialized GPIO line iterator.
 * @param line Pointer to a GPIO line handle - on each iteration, the
 *             next GPIO line will be assigned to this argument.
 */
#define gpiod_foreach_line(iter, line)					\
	for ((line) = gpiod_line_iter_next(iter);			\
	     !gpiod_line_iter_done(iter);				\
	     (line) = gpiod_line_iter_next(iter))

/**
 * @}
 *
 * @defgroup __misc__ Stuff that didn't fit anywhere else
 * @{
 *
 * Various libgpiod-related functions.
 */

/**
 * @brief Get the version of the library as a human-readable string.
 * @return Human-readable string containing the library version.
 */
const char * gpiod_version_string(void) GPIOD_API;

/**
 * @}
 */

#ifdef __cplusplus
} /* extern "C" */
#endif

#endif /* __LIBGPIOD_GPIOD_H__ */