gpiod_core/iop/
v2.rs

1use crate::{
2    raw::v2::*, utils::*, Active, AsValuesMut, Bias, Direction, Drive, Edge, EdgeDetect, Event,
3    LineId, LineInfo, LineMap, Result, Values,
4};
5
6/// Raw event ro read from fd
7pub type RawEvent = GpioLineEvent;
8
9impl GpioLineInfo {
10    pub fn as_info(&self) -> Result<LineInfo> {
11        let direction = if is_set(self.flags, GPIO_LINE_FLAG_OUTPUT) {
12            Direction::Output
13        } else {
14            Direction::Input
15        };
16
17        let active = if is_set(self.flags, GPIO_LINE_FLAG_ACTIVE_LOW) {
18            Active::Low
19        } else {
20            Active::High
21        };
22
23        let edge = match (
24            is_set(self.flags, GPIO_LINE_FLAG_EDGE_RISING),
25            is_set(self.flags, GPIO_LINE_FLAG_EDGE_FALLING),
26        ) {
27            (true, false) => EdgeDetect::Rising,
28            (false, true) => EdgeDetect::Falling,
29            (true, true) => EdgeDetect::Both,
30            _ => EdgeDetect::Disable,
31        };
32
33        let used = is_set(self.flags, GPIO_LINE_FLAG_USED);
34
35        let bias = match (
36            is_set(self.flags, GPIO_LINE_FLAG_BIAS_PULL_UP),
37            is_set(self.flags, GPIO_LINE_FLAG_BIAS_PULL_DOWN),
38        ) {
39            (true, false) => Bias::PullUp,
40            (false, true) => Bias::PullDown,
41            _ => Bias::Disable,
42        };
43
44        let drive = match (
45            is_set(self.flags, GPIO_LINE_FLAG_OPEN_DRAIN),
46            is_set(self.flags, GPIO_LINE_FLAG_OPEN_SOURCE),
47        ) {
48            (true, false) => Drive::OpenDrain,
49            (false, true) => Drive::OpenSource,
50            _ => Drive::PushPull,
51        };
52        let name = safe_get_str(&self.name)?.into();
53        let consumer = safe_get_str(&self.consumer)?.into();
54
55        Ok(LineInfo {
56            direction,
57            active,
58            edge,
59            used,
60            bias,
61            drive,
62            name,
63            consumer,
64        })
65    }
66}
67
68impl AsMut<GpioLineValues> for Values {
69    fn as_mut(&mut self) -> &mut GpioLineValues {
70        // it's safe because memory layout is same
71        unsafe { &mut *(self as *mut _ as *mut _) }
72    }
73}
74
75impl GpioLineRequest {
76    #[allow(clippy::too_many_arguments)]
77    pub fn new(
78        lines: &[LineId],
79        direction: Direction,
80        active: Active,
81        edge: Option<EdgeDetect>,
82        bias: Option<Bias>,
83        drive: Option<Drive>,
84        values: Option<Values>,
85        consumer: &str,
86    ) -> Result<Self> {
87        let mut request = GpioLineRequest::default();
88
89        check_len(lines, &request.offsets)?;
90
91        request.num_lines = lines.len() as _;
92
93        request.offsets[..lines.len()].copy_from_slice(lines);
94
95        let config = &mut request.config;
96
97        config.flags |= match direction {
98            Direction::Input => GPIO_LINE_FLAG_INPUT,
99            // Mixing input and output flags is not allowed
100            // see https://github.com/torvalds/linux/blob/v5.18/drivers/gpio/gpiolib-cdev.c#L895-L901
101            Direction::Output => GPIO_LINE_FLAG_OUTPUT,
102        };
103
104        if matches!(active, Active::Low) {
105            config.flags |= GPIO_LINE_FLAG_ACTIVE_LOW;
106        }
107
108        if matches!(direction, Direction::Input) {
109            // Set edge flags is valid only for input
110            // see https://github.com/torvalds/linux/blob/v5.18/drivers/gpio/gpiolib-cdev.c#L903-L906
111            if let Some(edge) = edge {
112                match edge {
113                    EdgeDetect::Rising => config.flags |= GPIO_LINE_FLAG_EDGE_RISING,
114                    EdgeDetect::Falling => config.flags |= GPIO_LINE_FLAG_EDGE_FALLING,
115                    EdgeDetect::Both => config.flags |= GPIO_LINE_FLAG_EDGE_BOTH,
116                    _ => {}
117                }
118            }
119        }
120
121        if let Some(bias) = bias {
122            config.flags |= match bias {
123                Bias::PullUp => GPIO_LINE_FLAG_BIAS_PULL_UP,
124                Bias::PullDown => GPIO_LINE_FLAG_BIAS_PULL_DOWN,
125                Bias::Disable => GPIO_LINE_FLAG_BIAS_DISABLED,
126            }
127        }
128
129        if matches!(direction, Direction::Output) {
130            // Set drive flags is valid only for output
131            // see https://github.com/torvalds/linux/blob/v5.18/drivers/gpio/gpiolib-cdev.c#L917-L920
132            if let Some(drive) = drive {
133                match drive {
134                    Drive::OpenDrain => config.flags |= GPIO_LINE_FLAG_OPEN_DRAIN,
135                    Drive::OpenSource => config.flags |= GPIO_LINE_FLAG_OPEN_SOURCE,
136                    _ => (),
137                }
138            }
139
140            if let Some(mut values) = values {
141                values.truncate(lines.len() as _);
142
143                config.num_attrs = 1;
144                let attr = &mut config.attrs[0];
145                attr.attr.id = GPIO_LINE_ATTR_ID_OUTPUT_VALUES;
146                attr.mask = values.mask;
147                attr.attr.val.values = values.bits;
148            }
149        }
150
151        safe_set_str(&mut request.consumer, consumer)?;
152
153        Ok(request)
154    }
155}
156
157impl GpioLineEvent {
158    pub fn as_event(&self, line_map: &LineMap) -> Result<Event> {
159        let line = line_map.get(self.offset)?;
160
161        let edge = match self.id {
162            GPIO_LINE_EVENT_RISING_EDGE => Edge::Rising,
163            GPIO_LINE_EVENT_FALLING_EDGE => Edge::Falling,
164            _ => return Err(invalid_data("Unknown edge")),
165        };
166
167        let time = time_from_nanos(self.timestamp_ns);
168
169        Ok(Event { line, edge, time })
170    }
171}