18 #include <linux/gpio.h> 20 #include <sys/ioctl.h> 24 #include <type_traits> 30 switch (errno_input) {
35 status = Os::File::Status::NOT_OPENED;
38 status = Os::File::Status::INVALID_ARGUMENT;
41 status = Os::File::Status::DOESNT_EXIST;
47 status = Os::File::Status::NO_PERMISSION;
50 status = Os::File::Status::INVALID_MODE;
66 switch (errno_input) {
68 status = Drv::GpioStatus::T::NOT_OPENED;
80 status = Drv::GpioStatus::T::UNKNOWN_ERROR;
88 switch (configuration) {
90 flags = GPIOHANDLE_REQUEST_OUTPUT;
97 flags = GPIOHANDLE_REQUEST_INPUT;
100 FW_ASSERT(
false, static_cast<FwAssertArgType>(configuration));
106 #ifdef GPIO_V2_GET_LINE_IOCTL 109 switch (configuration) {
111 flags = GPIO_V2_LINE_FLAG_OUTPUT;
114 flags = GPIO_V2_LINE_FLAG_INPUT;
117 flags = GPIO_V2_LINE_FLAG_INPUT | GPIO_V2_LINE_FLAG_EDGE_RISING;
120 flags = GPIO_V2_LINE_FLAG_INPUT | GPIO_V2_LINE_FLAG_EDGE_FALLING;
123 flags = GPIO_V2_LINE_FLAG_INPUT | GPIO_V2_LINE_FLAG_EDGE_RISING | GPIO_V2_LINE_FLAG_EDGE_FALLING;
126 FW_ASSERT(
false, static_cast<FwAssertArgType>(configuration));
135 switch (configuration) {
137 flags = GPIOEVENT_REQUEST_RISING_EDGE;
140 flags = GPIOEVENT_REQUEST_FALLING_EDGE;
143 flags = GPIOEVENT_REQUEST_RISING_EDGE | GPIOEVENT_REQUEST_FALLING_EDGE;
146 FW_ASSERT(
false, static_cast<FwAssertArgType>(configuration));
153 if (this->m_fd >= 0) {
154 (void)::close(this->m_fd);
162 Os::File::Status LinuxGpioDriver ::setupLineRequestV2(
const int chip_descriptor,
164 const GpioConfiguration& configuration,
168 #ifdef GPIO_V2_GET_LINE_IOCTL 171 struct gpio_v2_line_request request;
172 (void)::memset(&request, 0,
sizeof request);
173 request.offsets[0] = gpio;
175 static_cast<FwSizeType>(
sizeof request.consumer));
176 request.num_lines = 1;
178 request.config.flags = configuration_to_line_flags_v2(configuration);
181 request.config.num_attrs = 1;
182 request.config.attrs[0].attr.id = GPIO_V2_LINE_ATTR_ID_OUTPUT_VALUES;
183 request.config.attrs[0].attr.values = (default_state ==
Fw::Logic::HIGH) ? 1 : 0;
184 request.config.attrs[0].mask = 1;
188 int return_value = ioctl(chip_descriptor, GPIO_V2_GET_LINE_IOCTL, &request);
190 if (return_value != 0) {
197 return Os::File::Status::NOT_SUPPORTED;
201 Os::File::Status LinuxGpioDriver ::setupLineHandle(
const int chip_descriptor,
203 const GpioConfiguration& configuration,
208 struct gpiohandle_request request;
209 (void)::memset(&request, 0,
sizeof request);
210 request.lineoffsets[0] = gpio;
212 static_cast<FwSizeType>(
sizeof request.consumer_label));
213 request.default_values[0] = (default_state ==
Fw::Logic::HIGH) ? 1 : 0;
219 int return_value = ioctl(chip_descriptor, GPIO_GET_LINEHANDLE_IOCTL, &request);
221 if (return_value != 0) {
228 Os::File::Status LinuxGpioDriver ::setupLineEvent(
const int chip_descriptor,
230 const GpioConfiguration& configuration,
234 struct gpioevent_request event;
235 (void)::memset(&event, 0,
sizeof event);
236 event.lineoffset = gpio;
238 static_cast<FwSizeType>(
sizeof event.consumer_label));
243 int return_value = ioctl(chip_descriptor, GPIO_GET_LINEEVENT_IOCTL, &event);
245 if (return_value != 0) {
259 FW_ASSERT(configuration < MAX_GPIO_CONFIGURATION and configuration >= 0,
260 static_cast<FwAssertArgType>(configuration));
263 status = chip_file.
open(device, Os::File::Mode::OPEN_WRITE);
270 struct gpiochip_info chip_info;
271 (void)::memset(&chip_info, 0,
sizeof chip_info);
272 int return_value = ioctl(chip_descriptor, GPIO_GET_CHIPINFO_IOCTL, &chip_info);
273 if (return_value != 0) {
279 if (gpio >= chip_info.lines) {
280 status = Os::File::Status::DOESNT_EXIST;
288 bool supports_v2 =
false;
289 #ifdef GPIO_V2_GET_LINEINFO_IOCTL 290 struct gpio_v2_line_info pin_info_v2;
291 (void)::memset(&pin_info_v2, 0,
sizeof pin_info_v2);
292 pin_info_v2.offset = gpio;
293 return_value = ioctl(chip_descriptor, GPIO_V2_GET_LINEINFO_IOCTL, &pin_info_v2);
294 if (return_value == 0) {
295 const bool has_consumer = pin_info_v2.consumer[0] !=
'\0';
296 (void)pin_message.
format(
"%s%s%s", pin_info_v2.name, has_consumer ?
" with current consumer " :
"",
297 has_consumer ? pin_info_v2.consumer :
"");
301 if (not supports_v2) {
302 struct gpioline_info pin_info;
303 (void)::memset(&pin_info, 0,
sizeof pin_info);
304 pin_info.line_offset = gpio;
305 return_value = ioctl(chip_descriptor, GPIO_GET_LINEINFO_IOCTL, &pin_info);
306 if (return_value == 0) {
307 const bool has_consumer = pin_info.consumer[0] !=
'\0';
308 (void)pin_message.
format(
"%s%s%s", pin_info.name, has_consumer ?
" with current consumer " :
"",
309 has_consumer ? pin_info.consumer :
"");
318 api_version = ApiVersion::API_V2;
319 status = this->setupLineRequestV2(chip_descriptor, gpio, configuration, default_state, pin_fd);
321 switch (configuration) {
325 status = this->setupLineHandle(chip_descriptor, gpio, configuration, default_state, pin_fd);
331 status = this->setupLineEvent(chip_descriptor, gpio, configuration, pin_fd);
345 this->m_configuration = configuration;
346 this->m_apiVersion = api_version;
353 if (this->m_configuration == GpioConfiguration::GPIO_INPUT) {
354 #ifdef GPIO_V2_GET_LINE_IOCTL 355 if (this->m_apiVersion == ApiVersion::API_V2) {
356 struct gpio_v2_line_values values;
357 (void)::memset(&values, 0,
sizeof values);
359 int return_value = ioctl(this->m_fd, GPIO_V2_LINE_GET_VALUES_IOCTL, &values);
360 if (return_value != 0) {
369 struct gpiohandle_data values;
370 (void)::memset(&values, 0,
sizeof values);
371 int return_value = ioctl(this->m_fd, GPIOHANDLE_GET_LINE_VALUES_IOCTL, &values);
372 if (return_value != 0) {
384 if (this->m_configuration == GpioConfiguration::GPIO_OUTPUT) {
385 #ifdef GPIO_V2_GET_LINE_IOCTL 386 if (this->m_apiVersion == ApiVersion::API_V2) {
387 struct gpio_v2_line_values values;
388 (void)::memset(&values, 0,
sizeof values);
391 int return_value = ioctl(this->m_fd, GPIO_V2_LINE_SET_VALUES_IOCTL, &values);
392 if (return_value != 0) {
400 struct gpiohandle_data values;
401 (void)::memset(&values, 0,
sizeof values);
403 int return_value = ioctl(this->m_fd, GPIOHANDLE_SET_LINE_VALUES_IOCTL, &values);
404 if (return_value != 0) {
413 void LinuxGpioDriver ::pollLoop() {
417 static_assert(
GPIO_POLL_TIMEOUT < static_cast<unsigned int>(std::numeric_limits<int>::max()),
418 "Poll timeout would overflow");
419 static_assert(
sizeof(
struct gpioevent_data) < std::numeric_limits<FwSizeType>::max(),
"FwSizeType too small");
420 #ifdef GPIO_V2_GET_LINE_IOCTL 421 static_assert(
sizeof(
struct gpio_v2_line_event) < std::numeric_limits<FwSizeType>::max(),
"FwSizeType too small");
423 using unsigned_ssize_t = std::make_unsigned<ssize_t>::type;
425 static_cast<unsigned_ssize_t>(std::numeric_limits<ssize_t>::max()) <= std::numeric_limits<FwSizeType>::max(),
426 "FwSizeType too small");
428 pollfd file_descriptors[1];
431 while (this->getRunning()) {
433 (void)::memset(file_descriptors, 0,
sizeof file_descriptors);
434 file_descriptors[0].fd = this->m_fd;
435 file_descriptors[0].events = POLLIN;
441 struct gpioevent_data v1;
442 #ifdef GPIO_V2_GET_LINE_IOCTL 443 struct gpio_v2_line_event v2;
446 FwSizeType expected_bytes =
sizeof event_data.v1;
447 #ifdef GPIO_V2_GET_LINE_IOCTL 448 if (this->m_apiVersion == ApiVersion::API_V2) {
449 expected_bytes =
sizeof event_data.v2;
452 FwSizeType read_bytes =
static_cast<FwSizeType>(::read(this->m_fd, &event_data, expected_bytes));
453 if (read_bytes == expected_bytes) {
468 else if (status < 0) {
void log_WARNING_HI_OpenChipError(const Fw::StringBase &chip, const Os::FileStatus &status) const
Log event OpenChipError.
A catch-all for other errors. Have to look in implementation-specific code.
FPP shadow-enum representing Os::RawTime::Status.
PlatformSizeType FwSizeType
Input GPIO pin triggers interrupt port on falling edge.
void log_WARNING_HI_InterruptReadError(U32 expected, U32 got) const
Log event InterruptReadError.
Status now() override
Get the current time.
void gpioInterrupt_out(FwIndexType portNum, Os::RawTime &cycleStart) const
Invoke output port gpioInterrupt.
#define FW_OPTIONAL_NAME(name)
Os::FileInterface::Status open(const char *path, Mode mode)
open file with supplied path and mode
Operation not permitted with current configuration.
char * string_copy(char *destination, const char *source, FwSizeType num)
copy string with null-termination guaranteed
void log_WARNING_HI_OpenPinError(const Fw::StringBase &chip, U32 pin, const Fw::StringBase &pinMessage, const Os::FileStatus &status) const
Log event OpenPinError.
void log_DIAGNOSTIC_OpenChip(const Fw::StringBase &chip, const Fw::StringBase &chipLabel, U32 pin, const Fw::StringBase &pinMessage) const
Log event OpenChip.
FileHandle * getHandle() override
returns the raw file handle
GpioConfiguration
configure the GPIO pin
Input GPIO pin triggers interrupt port on both edges.
FormatStatus format(const CHAR *formatString,...)
write formatted string to buffer
Drv::GpioStatus errno_to_gpio_status(int errno_input)
No space left on the device for writing.
Os::File::Status open(const char *device, const U32 gpio, const GpioConfiguration &configuration, const Fw::Logic &default_state=Fw::Logic::LOW)
open a GPIO pin for use in the system
Operation was successful.
PlatformIndexType FwIndexType
void log_WARNING_HI_PollingError(I32 error_number) const
Log event PollingError.
Output GPIO pin for direct writing.
void log_WARNING_HI_InterruptTimeError(const Os::RawTimeStatus &status) const
Log event InterruptTimeError.
U32 configuration_to_event_flags(Drv::LinuxGpioDriver::GpioConfiguration configuration)
Input GPIO pin for direct reading.
Input GPIO pin triggers interrupt port on rising edge.
U32 configuration_to_handler_flags(Drv::LinuxGpioDriver::GpioConfiguration configuration)
FPP shadow-enum representing Os::File::Status.
ApiVersion
Linux GPIO character device uAPI version used for the opened pin.
Os::File::Status errno_to_file_status(int errno_input)
static constexpr FwSizeType GPIO_POLL_TIMEOUT