[PATCH V2 1/2] RTEMS GPIO API definition and implementation.

Ketul Shah ketulshah1993 at gmail.com
Thu Aug 13 12:04:24 UTC 2015


Hi Andre,

Great API and happy to know that it is merged with main line.

Eventually I implemented GPIO driver for BBB using this API. After
debugging for rtems_gpio_get_value() on BBB I found the following bug.

For BBB, GPIO pin nos. varies from 0 to 32. So function return type would
be uint32_t instead of uint8_t.

For BBB I wrote :-

uint32_t rtems_gpio_bsp_get_value(uint32_t bank, uint32_t pin)
{
  return (mmio_read(bbb_reg(bank, AM335X_GPIO_DATAIN)) & BIT(pin));
}

Thanks.

Best Regards,
Ketul

On 27 July 2015 at 21:31, Andre Marques <andre.lousa.marques at gmail.com>
wrote:

> Changes relative to the previous patch set:
>
> - Moved GPIO pin interrupts to rtems chains, instead of a local linked
> list;
> - Restructured the pin tracking structure, separating the interrupt
> information for each pin meaning that a pin without any interrupt enabled
> only requires 8 bytes, while keeping interrupt information (handling
> information, handler chain control, ...) requires 24 additional bytes
> (total of 32 bytes per pin with interrupts enabled);
> -  Added support for 'parallel' pin function assignment, allowing the
> function assignment to be set for multiple pins in a single GPIO hardware
> call. If a BSP does not support this feature it becomes a sequence of
> individual calls per pin. Also added support for GPIO pin groupings,
> allowing to write and read byte data to a series of pins which behave as a
> single entity;
> - Added bank tracking structure to maintain the bank lock and bank level
> interrupt information (threaded/normal handling, interrupt counter);
> - Changed GPIO settings to BSP defined constants, reducing dynamic memory
> allocation;
> - Switched interrupt tasks for a rtems interrupt server, with the
> possibility of using normal interrupts (user handlers being called within
> ISR context).
> ---
>  c/src/lib/libbsp/Makefile.am           |    3 +-
>  c/src/lib/libbsp/preinstall.am         |    4 +
>  c/src/lib/libbsp/shared/gpio.c         | 1977
> ++++++++++++++++++++++++++++++++
>  c/src/lib/libbsp/shared/include/gpio.h |  948 +++++++++++++++
>  4 files changed, 2931 insertions(+), 1 deletion(-)
>  create mode 100644 c/src/lib/libbsp/shared/gpio.c
>  create mode 100644 c/src/lib/libbsp/shared/include/gpio.h
>
> diff --git a/c/src/lib/libbsp/Makefile.am b/c/src/lib/libbsp/Makefile.am
> index 3cab4d7..a039a98 100644
> --- a/c/src/lib/libbsp/Makefile.am
> +++ b/c/src/lib/libbsp/Makefile.am
> @@ -9,7 +9,7 @@ EXTRA_DIST = MERGE.PROCEDURE bsp.am
>  EXTRA_DIST += shared/bootcard.c shared/bspclean.c \
>      shared/bsplibc.c shared/bsppost.c shared/console-polled.c \
>      shared/console.c shared/gnatinstallhandler.c shared/sbrk.c \
> -    shared/tod.c
> +    shared/tod.c shared/gpio.c
>  EXTRA_DIST += shared/vmeUniverse/vmeUniverse.c \
>      shared/vmeUniverse/vmeUniverse.h \
>      shared/vmeUniverse/vmeUniverseDMA.h \
> @@ -35,6 +35,7 @@ include_bsp_HEADERS =
>  include_bsp_HEADERS += shared/include/default-initial-extension.h
>  include_bsp_HEADERS += shared/include/fatal.h
>  include_bsp_HEADERS += shared/include/console-termios.h
> +include_bsp_HEADERS += shared/include/gpio.h
>
>  include $(srcdir)/preinstall.am
>  include $(top_srcdir)/automake/subdirs.am
> diff --git a/c/src/lib/libbsp/preinstall.am b/c/src/lib/libbsp/
> preinstall.am
> index 651f136..bbcb7c5 100644
> --- a/c/src/lib/libbsp/preinstall.am
> +++ b/c/src/lib/libbsp/preinstall.am
> @@ -30,3 +30,7 @@ $(PROJECT_INCLUDE)/bsp/console-termios.h:
> shared/include/console-termios.h $(PRO
>         $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/bsp/console-termios.h
>  PREINSTALL_FILES += $(PROJECT_INCLUDE)/bsp/console-termios.h
>
> +$(PROJECT_INCLUDE)/bsp/gpio.h: shared/include/gpio.h
> $(PROJECT_INCLUDE)/bsp/$(dirstamp)
> +       $(INSTALL_DATA) $< $(PROJECT_INCLUDE)/bsp/gpio.h
> +PREINSTALL_FILES += $(PROJECT_INCLUDE)/bsp/gpio.h
> +
> diff --git a/c/src/lib/libbsp/shared/gpio.c
> b/c/src/lib/libbsp/shared/gpio.c
> new file mode 100644
> index 0000000..a87b39f
> --- /dev/null
> +++ b/c/src/lib/libbsp/shared/gpio.c
> @@ -0,0 +1,1977 @@
> +/**
> + * @file gpio.c
> + *
> + * @ingroup rtems_gpio
> + *
> + * @brief RTEMS GPIO API implementation.
> + */
> +
> +/*
> + *  Copyright (c) 2014-2015 Andre Marques <andre.lousa.marques at
> gmail.com>
> + *
> + *  The license and distribution terms for this file may be
> + *  found in the file LICENSE in this distribution or at
> + *  http://www.rtems.org/license/LICENSE.
> + */
> +
> +#include <rtems/score/atomic.h>
> +#include <rtems/chain.h>
> +#include <bsp/irq-generic.h>
> +#include <bsp/gpio.h>
> +#include <assert.h>
> +#include <stdlib.h>
> +
> +/**
> + * @brief GPIO API mutex attributes.
> + */
> +#define MUTEX_ATTRIBUTES (     \
> +  RTEMS_LOCAL                  \
> +  | RTEMS_PRIORITY             \
> +  | RTEMS_BINARY_SEMAPHORE     \
> +  | RTEMS_INHERIT_PRIORITY     \
> +  | RTEMS_NO_PRIORITY_CEILING  \
> +)
> +
> +#define CREATE_LOCK(name, lock_id) rtems_semaphore_create(   \
> +  name,                                                      \
> +  1,                                                         \
> +  MUTEX_ATTRIBUTES,                                          \
> +  0,                                                         \
> +  lock_id                                                    \
> +)
> +
> +#define ACQUIRE_LOCK(m) assert ( rtems_semaphore_obtain(m,               \
> +                                                        RTEMS_WAIT,      \
> +                                                        RTEMS_NO_TIMEOUT \
> +                                                        ) ==
> RTEMS_SUCCESSFUL )
> +
> +#define RELEASE_LOCK(m) assert ( rtems_semaphore_release(m) ==
> RTEMS_SUCCESSFUL )
> +
> +/**
> + * @brief Object containing relevant information about a GPIO group.
> + *
> + * Encapsulates relevant data for a GPIO pin group.
> + */
> +struct rtems_gpio_group
> +{
> +  rtems_chain_node node;
> +
> +  uint32_t *digital_inputs;
> +  uint32_t digital_input_bank;
> +  uint32_t input_count;
> +
> +  uint32_t *digital_outputs;
> +  uint32_t digital_output_bank;
> +  uint32_t output_count;
> +
> +  uint32_t *bsp_speficifc_pins;
> +  uint32_t bsp_specific_bank;
> +  uint32_t bsp_specific_pin_count;
> +
> +  rtems_id group_lock;
> +};
> +
> +/**
> + * @brief Object containing relevant information to a list of user-defined
> + *        interrupt handlers.
> + *
> + * Encapsulates relevant data for a GPIO interrupt handler.
> + */
> +typedef struct
> +{
> +  rtems_chain_node node;
> +
> +  /* User-defined ISR routine. */
> +  rtems_gpio_irq_state (*handler) (void *arg);
> +
> +  /* User-defined arguments for the ISR routine. */
> +  void *arg;
> +} gpio_handler_node;
> +
> +/**
> + * @brief Object containing relevant information of a pin's interrupt
> + *        configuration/state.
> + *
> + * Encapsulates relevant data of a GPIO pin interrupt state.
> + */
> +typedef struct
> +{
> +  /* Currently active interrupt. */
> +  rtems_gpio_interrupt active_interrupt;
> +
> +  /* ISR shared flag. */
> +  rtems_gpio_handler_flag handler_flag;
> +
> +  /* Linked list of interrupt handlers. */
> +  rtems_chain_control handler_chain;
> +
> +  /* Switch-deboucing information. */
> +  uint32_t debouncing_tick_count;
> +  rtems_interval last_isr_tick;
> +} gpio_pin_interrupt_state;
> +
> +/**
> + * @brief Object containing information on a GPIO pin.
> + *
> + * Encapsulates relevant data about a GPIO pin.
> + */
> +typedef struct
> +{
> +  rtems_gpio_function pin_function;
> +
> +  /* GPIO pull resistor configuration. */
> +  rtems_gpio_pull_mode resistor_mode;
> +
> +  /* If true inverts digital in/out applicational logic. */
> +  bool logic_invert;
> +
> +  /* True if the pin is on a group. */
> +  bool on_group;
> +
> +  /* Interrupt data for a pin. This field is NULL if no interrupt is
> enabled
> +   * on the pin. */
> +  gpio_pin_interrupt_state *interrupt_state;
> +} gpio_pin;
> +
> +/**
> + * @brief Object containing relevant information regarding a GPIO bank
> state.
> + *
> + * Encapsulates relevant data for a GPIO bank.
> + */
> +typedef struct
> +{
> +  uint32_t bank_number;
> +  uint32_t interrupt_counter;
> +  rtems_id lock;
> +
> +  /* If TRUE the interrupts on the bank will be called
> +   * by a rtems interrupt server, otherwise they will be handled
> +   * in the normal ISR context. */
> +  bool threaded_interrupts;
> +} gpio_bank;
> +
> +static gpio_pin gpio_pin_state[BSP_GPIO_PIN_COUNT];
> +static Atomic_Flag init_flag = ATOMIC_INITIALIZER_FLAG;
> +static gpio_bank gpio_bank_state[GPIO_BANK_COUNT];
> +static Atomic_Uint threaded_interrupt_counter =
> ATOMIC_INITIALIZER_UINT(0);
> +static rtems_chain_control gpio_group;
> +
> +#define BANK_NUMBER(pin_number) pin_number / BSP_GPIO_PINS_PER_BANK
> +#define PIN_NUMBER(pin_number) pin_number % BSP_GPIO_PINS_PER_BANK
> +
> +static int debounce_switch(gpio_pin_interrupt_state *interrupt_state)
> +{
> +  rtems_interval time;
> +
> +  time = rtems_clock_get_ticks_since_boot();
> +
> +  /* If not enough time has elapsed since last interrupt. */
> +  if (
> +      (time - interrupt_state->last_isr_tick) <
> +      interrupt_state->debouncing_tick_count
> +  ) {
> +    return -1;
> +  }
> +
> +  interrupt_state->last_isr_tick = time;
> +
> +  return 0;
> +}
> +
> +/* Returns the amount of pins in a bank. */
> +static uint32_t get_bank_pin_count(uint32_t bank)
> +{
> +  /* If the current bank is the last bank, which may not be completely
> filled. */
> +  if ( bank == GPIO_BANK_COUNT - 1 ) {
> +    return GPIO_LAST_BANK_PINS;
> +  }
> +
> +  return BSP_GPIO_PINS_PER_BANK;
> +}
> +
> +/* GPIO generic bank ISR. This may be called directly as response to an
> + * interrupt, or by the rtems interrupt server task if the GPIO bank
> + * uses threading interrupt handling. */
> +static void generic_bank_isr(void *arg)
> +{
> +  gpio_pin_interrupt_state *interrupt_state;
> +  rtems_chain_control *handler_list;
> +  rtems_chain_node *node;
> +  rtems_chain_node *next_node;
> +  gpio_handler_node *isr_node;
> +  rtems_vector_number vector;
> +  uint32_t event_status;
> +  uint32_t bank_number;
> +  uint32_t bank_start_pin;
> +  uint8_t handled_count;
> +  uint8_t rv;
> +  uint8_t i;
> +
> +  bank_number = *((uint32_t*) arg);
> +
> +  assert ( bank_number >= 0 && bank_number < GPIO_BANK_COUNT );
> +
> +  /* Calculate bank start address in the pin_state array. */
> +  bank_start_pin = bank_number * BSP_GPIO_PINS_PER_BANK;
> +
> +  vector = rtems_gpio_bsp_get_vector(bank_number);
> +
> +  /* If this bank does not use threaded interrupts we have to
> +   * disable the vector. Otherwise the interrupt server does it. */
> +  if ( gpio_bank_state[bank_number].threaded_interrupts == false ) {
> +    /* Prevents more interrupts from being generated on GPIO. */
> +    bsp_interrupt_vector_disable(vector);
> +  }
> +
> +  /* Obtains a 32-bit bitmask, with the pins currently reporting
> interrupts
> +   * signaled with 1. */
> +  event_status = rtems_gpio_bsp_interrupt_line(vector);
> +
> +  /* Iterates through the bitmask and calls the corresponding handler
> +   * for active interrupts. */
> +  for ( i = 0; i < get_bank_pin_count(bank_number); ++i ) {
> +    /* If active, wake the corresponding pin's ISR task. */
> +    if ( event_status & (1 << i) ) {
> +      interrupt_state = gpio_pin_state[bank_start_pin +
> i].interrupt_state;
> +
> +      assert ( interrupt_state != NULL );
> +
> +      handled_count = 0;
> +
> +      if ( gpio_bank_state[bank_number].threaded_interrupts ) {
> +        ACQUIRE_LOCK(gpio_bank_state[bank_number].lock);
> +      }
> +
> +      /* If this pin has the debouncing function attached, call it. */
> +      if ( interrupt_state->debouncing_tick_count > 0 ) {
> +        rv = debounce_switch(interrupt_state);
> +
> +        /* If the handler call was caused by a switch bounce,
> +         * ignores and move on. */
> +        if ( rv < 0 ) {
> +          if ( gpio_bank_state[bank_number].threaded_interrupts ) {
> +            RELEASE_LOCK(gpio_bank_state[bank_number].lock);
> +          }
> +
> +          continue;
> +        }
> +      }
> +
> +      handler_list = &interrupt_state->handler_chain;
> +
> +      node = rtems_chain_first(handler_list);
> +
> +      /* Iterate the ISR list. */
> +      while ( !rtems_chain_is_tail(handler_list, node) ) {
> +        isr_node = (gpio_handler_node *) node;
> +
> +        next_node = node->next;
> +
> +        if ( (isr_node->handler)(isr_node->arg) == IRQ_HANDLED ) {
> +          ++handled_count;
> +        }
> +
> +        node = next_node;
> +      }
> +
> +      /* If no handler assumed the interrupt,
> +       * treat it as a spurious interrupt. */
> +      if ( handled_count == 0 ) {
> +
> bsp_interrupt_handler_default(rtems_gpio_bsp_get_vector(bank_number));
> +      }
> +
> +      if ( gpio_bank_state[bank_number].threaded_interrupts ) {
> +        RELEASE_LOCK(gpio_bank_state[bank_number].lock);
> +      }
> +    }
> +  }
> +
> +  if ( gpio_bank_state[bank_number].threaded_interrupts == false ) {
> +    bsp_interrupt_vector_enable(vector);
> +  }
> +}
> +
> +/* Verifies if all pins in the received pin array are from the same bank
> and
> + * have the defined GPIO function. Produces bitmask of the received pins.
> */
> +static rtems_status_code get_pin_bitmask(
> +  uint32_t *pins,
> +  uint32_t pin_count,
> +  uint32_t *bank_number,
> +  uint32_t *bitmask,
> +  rtems_gpio_function function
> +) {
> +  uint32_t pin_number;
> +  uint32_t bank;
> +  uint8_t i;
> +
> +  if ( pin_count < 1 ) {
> +    return RTEMS_UNSATISFIED;
> +  }
> +
> +  *bitmask = 0;
> +
> +  for ( i = 0; i < pin_count; ++i ) {
> +    pin_number = pins[i];
> +
> +    if ( pin_number < 0 || pin_number >= BSP_GPIO_PIN_COUNT ) {
> +      return RTEMS_INVALID_ID;
> +    }
> +
> +    bank = BANK_NUMBER(pin_number);
> +
> +    if ( i == 0 ) {
> +      *bank_number = bank;
> +
> +      ACQUIRE_LOCK(gpio_bank_state[bank].lock);
> +    }
> +    else if ( bank != *bank_number ) {
> +      RELEASE_LOCK(gpio_bank_state[*bank_number].lock);
> +
> +      return RTEMS_UNSATISFIED;
> +    }
> +
> +    if (
> +        gpio_pin_state[pin_number].pin_function != function ||
> +        gpio_pin_state[pin_number].on_group
> +    ) {
> +      RELEASE_LOCK(gpio_bank_state[bank].lock);
> +
> +      return RTEMS_NOT_CONFIGURED;
> +    }
> +
> +    *bitmask |= (1 << PIN_NUMBER(pin_number));
> +  }
> +
> +  RELEASE_LOCK(gpio_bank_state[bank].lock);
> +
> +  return RTEMS_SUCCESSFUL;
> +}
> +
> +static rtems_status_code check_same_bank_and_availability(
> +  const rtems_gpio_pin_conf *pin_confs,
> +  uint32_t pin_count,
> +  uint32_t *bank_number,
> +  uint32_t *pins
> +) {
> +  uint32_t pin_number;
> +  uint32_t bank;
> +  uint8_t i;
> +
> +  for ( i = 0; i < pin_count; ++i ) {
> +    pin_number = pin_confs[i].pin_number;
> +
> +    bank = BANK_NUMBER(pin_number);
> +
> +    if ( i == 0 ) {
> +      *bank_number = bank;
> +
> +      ACQUIRE_LOCK(gpio_bank_state[bank].lock);
> +    }
> +    else if ( bank != *bank_number ) {
> +      RELEASE_LOCK(gpio_bank_state[*bank_number].lock);
> +
> +      return RTEMS_UNSATISFIED;
> +    }
> +
> +    if ( gpio_pin_state[pin_number].pin_function != NOT_USED ) {
> +      RELEASE_LOCK(gpio_bank_state[bank].lock);
> +
> +      return RTEMS_RESOURCE_IN_USE;
> +    }
> +
> +    pins[i] = PIN_NUMBER(pin_number);
> +  }
> +
> +  RELEASE_LOCK(gpio_bank_state[*bank_number].lock);
> +
> +  return RTEMS_SUCCESSFUL;
> +}
> +
> +static rtems_status_code setup_resistor_and_interrupt_configuration(
> +  uint32_t pin_number,
> +  rtems_gpio_pull_mode pull_mode,
> +  rtems_gpio_interrupt_configuration *interrupt_conf
> +) {
> +  gpio_pin_interrupt_state *interrupt_state;
> +  rtems_status_code sc;
> +  uint32_t bank;
> +
> +  sc = rtems_gpio_resistor_mode(pin_number, pull_mode);
> +
> +  if ( sc != RTEMS_SUCCESSFUL ) {
> +#if defined(DEBUG)
> +    printk("rtems_gpio_resistor_mode failed with status code %d\n", sc);
> +#endif
> +
> +    return RTEMS_UNSATISFIED;
> +  }
> +
> +  if ( interrupt_conf != NULL ) {
> +    bank = BANK_NUMBER(pin_number);
> +
> +    ACQUIRE_LOCK(gpio_bank_state[bank].lock);
> +
> +    sc = rtems_gpio_enable_interrupt(
> +           pin_number,
> +           interrupt_conf->active_interrupt,
> +           interrupt_conf->handler_flag,
> +           interrupt_conf->threaded_interrupts,
> +           interrupt_conf->handler,
> +           interrupt_conf->arg
> +         );
> +
> +    if ( sc != RTEMS_SUCCESSFUL ) {
> +      RELEASE_LOCK(gpio_bank_state[bank].lock);
> +
> +#if defined(DEBUG)
> +      printk(
> +        "rtems_gpio_enable_interrupt failed with status code %d\n",
> +        sc
> +      );
> +#endif
> +
> +      return RTEMS_UNSATISFIED;
> +    }
> +
> +    interrupt_state = gpio_pin_state[pin_number].interrupt_state;
> +
> +    interrupt_state->debouncing_tick_count =
> +      interrupt_conf->debounce_clock_tick_interval;
> +
> +    interrupt_state->last_isr_tick = 0;
> +
> +    RELEASE_LOCK(gpio_bank_state[bank].lock);
> +  }
> +
> +  return RTEMS_SUCCESSFUL;
> +}
> +
> +static rtems_status_code gpio_multi_select(
> +  const rtems_gpio_pin_conf *pins,
> +  uint8_t pin_count,
> +  bool on_group
> +) {
> +  rtems_status_code sc;
> +  uint32_t pin_number;
> +  uint32_t bank;
> +  uint8_t i;
> +
> +  /* If the BSP has multi select capabilities. */
> +#ifdef BSP_GPIO_PINS_PER_SELECT_BANK
> +  rtems_gpio_multiple_pin_select
> +    pin_data[GPIO_SELECT_BANK_COUNT][BSP_GPIO_PINS_PER_SELECT_BANK];
> +  rtems_gpio_specific_data *bsp_data;
> +
> +  /* Since each platform may have more than two functions to assign to a
> pin,
> +   * each pin requires more than one bit in the selection register to
> +   * properly assign a function to it.
> +   * Therefore a selection bank (pin selection register) will support
> fewer pins
> +   * than a regular bank, meaning that there will be more selection banks
> than
> +   * regular banks, which have to be handled separately.
> +   *
> +   * This field records the select bank number relative to the GPIO bank.
> */
> +  uint32_t select_bank;
> +  uint32_t bank_number;
> +  uint32_t select_bank_counter[GPIO_SELECT_BANK_COUNT];
> +  uint32_t select_count;
> +  uint32_t pin;
> +
> +  if ( pin_count == 0 ) {
> +    return RTEMS_SUCCESSFUL;
> +  }
> +
> +  for ( i = 0; i < GPIO_SELECT_BANK_COUNT; ++i ) {
> +    select_bank_counter[i] = 0;
> +  }
> +
> +  for ( i = 0; i < pin_count; ++i ) {
> +    pin_number = pins[i].pin_number;
> +
> +    if ( pin_number < 0 || pin_number >= BSP_GPIO_PIN_COUNT ) {
> +      return RTEMS_INVALID_ID;
> +    }
> +
> +    bank = BANK_NUMBER(pin_number);
> +    pin = PIN_NUMBER(pin_number);
> +
> +    if ( i == 0 ) {
> +      bank_number = bank;
> +
> +      ACQUIRE_LOCK(gpio_bank_state[bank].lock);
> +    }
> +    else if ( bank != bank_number ) {
> +      RELEASE_LOCK(gpio_bank_state[bank_number].lock);
> +
> +      return RTEMS_UNSATISFIED;
> +    }
> +
> +    /* If the pin is already being used returns with an error. */
> +    if ( gpio_pin_state[pin_number].pin_function != NOT_USED ) {
> +      RELEASE_LOCK(gpio_bank_state[bank_number].lock);
> +
> +      return RTEMS_RESOURCE_IN_USE;
> +    }
> +
> +    select_bank = (pin_number / BSP_GPIO_PINS_PER_SELECT_BANK) -
> +                  (bank * GPIO_SELECT_BANK_COUNT);
> +
> +    select_count = select_bank_counter[select_bank];
> +
> +    pin_data[select_bank][select_count].pin_number = pin_number;
> +    pin_data[select_bank][select_count].function = pins[i].function;
> +
> +    if ( pins[i].function == BSP_SPECIFIC ) {
> +      bsp_data = (rtems_gpio_specific_data *) pins[i].bsp_specific;
> +
> +      if ( bsp_data == NULL ) {
> +        RELEASE_LOCK(gpio_bank_state[bank_number].lock);
> +
> +        return RTEMS_UNSATISFIED;
> +      }
> +
> +      pin_data[select_bank][select_count].io_function =
> bsp_data->io_function;
> +      pin_data[select_bank][select_count].bsp_specific =
> bsp_data->pin_data;
> +    }
> +    else {
> +      /* io_function takes a dummy value, as it will not be used. */
> +      pin_data[select_bank][select_count].io_function = 0;
> +      pin_data[select_bank][select_count].bsp_specific =
> pins[i].bsp_specific;
> +    }
> +
> +    ++select_bank_counter[select_bank];
> +  }
> +
> +  for ( i = 0; i < GPIO_SELECT_BANK_COUNT; ++i ) {
> +    if ( select_bank_counter[i] == 0 ) {
> +      continue;
> +    }
> +
> +    sc = rtems_gpio_bsp_multi_select(
> +           pin_data[i], select_bank_counter[i], i +
> +           (bank_number * GPIO_SELECT_BANK_COUNT)
> +         );
> +
> +    if ( sc != RTEMS_SUCCESSFUL ) {
> +      RELEASE_LOCK(gpio_bank_state[bank_number].lock);
> +
> +      return sc;
> +    }
> +  }
> +
> +  for ( i = 0; i < pin_count; ++i ) {
> +    pin_number = pins[i].pin_number;
> +
> +    /* Fill other pin state information. */
> +    gpio_pin_state[pin_number].pin_function = pins[i].function;
> +    gpio_pin_state[pin_number].logic_invert = pins[i].logic_invert;
> +    gpio_pin_state[pin_number].on_group = on_group;
> +
> +    sc = setup_resistor_and_interrupt_configuration(
> +           pin_number,
> +           pins[i].pull_mode,
> +           pins[i].interrupt
> +         );
> +
> +    if ( sc != RTEMS_SUCCESSFUL ) {
> +      RELEASE_LOCK(gpio_bank_state[bank_number].lock);
> +
> +      return sc;
> +    }
> +
> +    bank = BANK_NUMBER(pin_number);
> +    pin = PIN_NUMBER(pin_number);
> +
> +    if ( pins[i].function == DIGITAL_OUTPUT ) {
> +      if ( pins[i].output_enabled == true ) {
> +        sc = rtems_gpio_bsp_set(bank, pin);
> +      }
> +      else {
> +        sc = rtems_gpio_bsp_clear(bank, pin);
> +      }
> +
> +      if ( sc != RTEMS_SUCCESSFUL ) {
> +        RELEASE_LOCK(gpio_bank_state[bank_number].lock);
> +
> +        return sc;
> +      }
> +    }
> +  }
> +
> +  RELEASE_LOCK(gpio_bank_state[bank_number].lock);
> +
> +  return sc;
> +
> +  /* If the BSP does not provide pin multi-selection,
> +   * configures each pin sequentially. */
> +#else
> +  for ( i = 0; i < pin_count; ++i ) {
> +    pin_number = pins[i].pin_number;
> +
> +    if ( pin_number < 0 || pin_number >= BSP_GPIO_PIN_COUNT ) {
> +      return RTEMS_INVALID_ID;
> +    }
> +
> +    bank = BANK_NUMBER(pin_number);
> +
> +    ACQUIRE_LOCK(gpio_bank_state[bank].lock);
> +
> +    /* If the pin is already being used returns with an error. */
> +    if ( gpio_pin_state[pin_number].pin_function != NOT_USED ) {
> +      RELEASE_LOCK(gpio_bank_state[bank].lock);
> +
> +      return RTEMS_RESOURCE_IN_USE;
> +    }
> +  }
> +
> +  for ( i = 0; i < pin_count; ++i ) {
> +    sc = rtems_gpio_request_configuration(&pins[i]);
> +
> +    if ( sc != RTEMS_SUCCESSFUL ) {
> +      return sc;
> +    }
> +
> +    gpio_pin_state[pins[i].pin_number].on_group = on_group;
> +  }
> +
> +  return RTEMS_SUCCESSFUL;
> +#endif
> +}
> +
> +rtems_status_code rtems_gpio_initialize(void)
> +{
> +  rtems_status_code sc;
> +  uint32_t i;
> +
> +  if ( _Atomic_Flag_test_and_set(&init_flag, ATOMIC_ORDER_RELAXED) ==
> true ) {
> +    return RTEMS_SUCCESSFUL;
> +  }
> +
> +  for ( i = 0; i < GPIO_BANK_COUNT; ++i ) {
> +    sc = CREATE_LOCK(
> +           rtems_build_name('G', 'I', 'N', 'T'),
> +           &gpio_bank_state[i].lock
> +         );
> +
> +    if ( sc != RTEMS_SUCCESSFUL ) {
> +      return sc;
> +    }
> +
> +    gpio_bank_state[i].bank_number = i;
> +    gpio_bank_state[i].interrupt_counter = 0;
> +
> +    /* The threaded_interrupts field is initialized during
> +     * rtems_gpio_enable_interrupt(), as its value is never used before.
> */
> +  }
> +
> +  for ( i = 0; i < BSP_GPIO_PIN_COUNT; ++i ) {
> +    gpio_pin_state[i].pin_function = NOT_USED;
> +    gpio_pin_state[i].resistor_mode = NO_PULL_RESISTOR;
> +    gpio_pin_state[i].logic_invert = false;
> +    gpio_pin_state[i].on_group = false;
> +    gpio_pin_state[i].interrupt_state = NULL;
> +  }
> +
> +  /* Initialize GPIO groups chain. */
> +  rtems_chain_initialize_empty(&gpio_group);
> +
> +  return RTEMS_SUCCESSFUL;
> +}
> +
> +rtems_gpio_group *rtems_gpio_create_pin_group(void)
> +{
> +  struct rtems_gpio_group *group;
> +
> +  group = (struct rtems_gpio_group *) malloc(sizeof(struct
> rtems_gpio_group));
> +
> +  return group;
> +}
> +
> +rtems_status_code rtems_gpio_define_pin_group(
> +  const rtems_gpio_group_definition *group_definition,
> +  rtems_gpio_group *group
> +) {
> +  rtems_status_code sc;
> +
> +  if ( group_definition == NULL || group == NULL ) {
> +    return RTEMS_UNSATISFIED;
> +  }
> +
> +  if (
> +      group_definition->input_count == 0 &&
> +      group_definition->output_count == 0 &&
> +      group_definition->bsp_specific_pin_count == 0
> +  ) {
> +    return RTEMS_UNSATISFIED;
> +  }
> +
> +  group->input_count = group_definition->input_count;
> +
> +  if ( group->input_count > 0 ) {
> +    group->digital_inputs =
> +      (uint32_t *) malloc(group->input_count * sizeof(uint32_t));
> +
> +    /* Evaluate if the pins that will constitute the group are available
> and
> +     * that pins with the same function within the group all belong
> +     * to the same pin group. */
> +    sc = check_same_bank_and_availability(
> +           group_definition->digital_inputs,
> +           group->input_count,
> +           &group->digital_input_bank,
> +           group->digital_inputs
> +         );
> +
> +    if ( sc != RTEMS_SUCCESSFUL ) {
> +      return sc;
> +    }
> +  }
> +  else {
> +    group->digital_inputs = NULL;
> +  }
> +
> +  group->output_count = group_definition->output_count;
> +
> +  if ( group->output_count > 0 ) {
> +    group->digital_outputs =
> +      (uint32_t *) malloc(group->output_count * sizeof(uint32_t));
> +
> +    sc = check_same_bank_and_availability(
> +           group_definition->digital_outputs,
> +           group->output_count,
> +           &group->digital_output_bank,
> +           group->digital_outputs
> +         );
> +
> +    if ( sc != RTEMS_SUCCESSFUL ) {
> +      return sc;
> +    }
> +  }
> +  else {
> +    group->digital_outputs = NULL;
> +  }
> +
> +  group->bsp_specific_pin_count =
> group_definition->bsp_specific_pin_count;
> +
> +  if ( group->bsp_specific_pin_count > 0 ) {
> +    group->bsp_speficifc_pins =
> +      (uint32_t *) malloc(
> +                     group->bsp_specific_pin_count *
> +                     sizeof(uint32_t)
> +                   );
> +
> +    sc = check_same_bank_and_availability(
> +           group_definition->bsp_specifics,
> +           group->bsp_specific_pin_count,
> +           &group->bsp_specific_bank,
> +           group->bsp_speficifc_pins
> +         );
> +
> +    if ( sc != RTEMS_SUCCESSFUL ) {
> +      return sc;
> +    }
> +  }
> +  else {
> +    group->bsp_speficifc_pins = NULL;
> +  }
> +
> +  /* Request the pins. */
> +  sc = gpio_multi_select(
> +         group_definition->digital_inputs,
> +         group_definition->input_count,
> +         true
> +       );
> +
> +  if ( sc != RTEMS_SUCCESSFUL ) {
> +    return RTEMS_UNSATISFIED;
> +  }
> +
> +  sc = gpio_multi_select(
> +         group_definition->digital_outputs,
> +         group_definition->output_count,
> +         true
> +       );
> +
> +  if ( sc != RTEMS_SUCCESSFUL ) {
> +    sc = rtems_gpio_release_multiple_pins(
> +           group_definition->digital_inputs,
> +           group_definition->input_count
> +         );
> +
> +    assert ( sc == RTEMS_SUCCESSFUL );
> +
> +    return RTEMS_UNSATISFIED;
> +  }
> +
> +  sc = gpio_multi_select(
> +         group_definition->bsp_specifics,
> +         group_definition->bsp_specific_pin_count,
> +         true
> +       );
> +
> +  if ( sc != RTEMS_SUCCESSFUL ) {
> +    sc = rtems_gpio_release_multiple_pins(
> +           group_definition->digital_inputs,
> +           group_definition->input_count
> +         );
> +
> +    assert ( sc == RTEMS_SUCCESSFUL );
> +
> +    sc = rtems_gpio_release_multiple_pins(
> +           group_definition->digital_outputs,
> +           group_definition->output_count
> +         );
> +
> +    assert ( sc == RTEMS_SUCCESSFUL );
> +
> +    return RTEMS_UNSATISFIED;
> +  }
> +
> +  /* Create group lock. */
> +  sc = CREATE_LOCK(rtems_build_name('G', 'R', 'P', 'L'),
> &group->group_lock);
> +
> +  if ( sc != RTEMS_SUCCESSFUL ) {
> +    return sc;
> +  }
> +
> +  rtems_chain_append(&gpio_group, &group->node);
> +
> +  return RTEMS_SUCCESSFUL;
> +}
> +
> +rtems_status_code rtems_gpio_write_group(uint32_t data, rtems_gpio_group
> *group)
> +{
> +  rtems_status_code sc = RTEMS_SUCCESSFUL;
> +  uint32_t set_bitmask;
> +  uint32_t clear_bitmask;
> +  uint32_t bank;
> +  uint32_t pin;
> +  uint8_t i;
> +
> +  if ( group->output_count == 0 ) {
> +    return RTEMS_NOT_DEFINED;
> +  }
> +
> +  bank = group->digital_output_bank;
> +
> +  /* Acquire bank lock for the digital output pins. */
> +  ACQUIRE_LOCK(gpio_bank_state[bank].lock);
> +
> +  /* Acquire group lock. */
> +  ACQUIRE_LOCK(group->group_lock);
> +
> +  set_bitmask = 0;
> +  clear_bitmask = 0;
> +
> +  for ( i = 0; i < group->output_count; ++i ) {
> +    pin = group->digital_outputs[i];
> +
> +    if ( (data & (1 << i)) == 0 ) {
> +      clear_bitmask |= (1 << pin);
> +    }
> +    else {
> +      set_bitmask |= (1 << pin);
> +    }
> +  }
> +
> +  /* Set the logical highs. */
> +  if ( set_bitmask > 0 ) {
> +    sc = rtems_gpio_bsp_multi_set(bank, set_bitmask);
> +
> +    if ( sc != RTEMS_SUCCESSFUL ) {
> +      RELEASE_LOCK(group->group_lock);
> +      RELEASE_LOCK(gpio_bank_state[bank].lock);
> +
> +      return sc;
> +    }
> +  }
> +
> +  /* Set the logical lows. */
> +  if ( clear_bitmask > 0 ) {
> +    sc = rtems_gpio_bsp_multi_clear(bank, clear_bitmask);
> +
> +    if ( sc != RTEMS_SUCCESSFUL ) {
> +      RELEASE_LOCK(group->group_lock);
> +      RELEASE_LOCK(gpio_bank_state[bank].lock);
> +
> +      return sc;
> +    }
> +  }
> +
> +  RELEASE_LOCK(group->group_lock);
> +  RELEASE_LOCK(gpio_bank_state[bank].lock);
> +
> +  return RTEMS_SUCCESSFUL;
> +}
> +
> +uint32_t rtems_gpio_read_group(rtems_gpio_group *group)
> +{
> +  uint32_t read_bitmask;
> +  uint32_t bank;
> +  uint32_t pin;
> +  uint32_t rv;
> +  uint8_t i;
> +
> +  if ( group->input_count == 0 ) {
> +    return 0xDEADBEEF;
> +  }
> +
> +  bank = group->digital_input_bank;
> +
> +  /* Acquire bank lock for the digital input pins. */
> +  ACQUIRE_LOCK(gpio_bank_state[bank].lock);
> +
> +  /* Acquire group lock. */
> +  ACQUIRE_LOCK(group->group_lock);
> +
> +  read_bitmask = 0;
> +
> +  for ( i = 0; i < group->input_count; ++i ) {
> +    pin = group->digital_inputs[i];
> +
> +    read_bitmask |= (1 << pin);
> +  }
> +
> +  rv = rtems_gpio_bsp_multi_read(bank, read_bitmask);
> +
> +  RELEASE_LOCK(gpio_bank_state[bank].lock);
> +  RELEASE_LOCK(group->group_lock);
> +
> +  return rv;
> +}
> +
> +rtems_status_code rtems_gpio_group_bsp_specific_operation(
> +  rtems_gpio_group *group,
> +  void *arg
> +) {
> +  rtems_status_code sc;
> +  uint32_t bank;
> +
> +  if ( group->bsp_specific_pin_count == 0 ) {
> +    return RTEMS_NOT_DEFINED;
> +  }
> +
> +  bank = group->bsp_specific_bank;
> +
> +  /* Acquire bank lock for the BSP specific function pins. */
> +  ACQUIRE_LOCK(gpio_bank_state[bank].lock);
> +
> +  /* Acquire group lock. */
> +  ACQUIRE_LOCK(group->group_lock);
> +
> +  sc = rtems_gpio_bsp_specific_group_operation(
> +         bank,
> +         group->bsp_speficifc_pins,
> +         group->bsp_specific_pin_count,
> +         arg
> +       );
> +
> +  RELEASE_LOCK(gpio_bank_state[bank].lock);
> +  RELEASE_LOCK(group->group_lock);
> +
> +  return sc;
> +}
> +
> +rtems_status_code rtems_gpio_multi_select(
> +  const rtems_gpio_pin_conf *pins,
> +  uint8_t pin_count
> +) {
> +  return gpio_multi_select(pins, pin_count, false);
> +}
> +
> +rtems_status_code rtems_gpio_request_configuration(
> +  const rtems_gpio_pin_conf *conf
> +) {
> +  rtems_status_code sc;
> +
> +  sc = rtems_gpio_request_pin(
> +         conf->pin_number,
> +         conf->function,
> +         conf->output_enabled,
> +         conf->logic_invert,
> +         conf->bsp_specific
> +       );
> +
> +  if ( sc != RTEMS_SUCCESSFUL ) {
> +#if defined(DEBUG)
> +    printk("rtems_gpio_request_pin failed with status code %d\n",sc);
> +#endif
> +
> +    return RTEMS_UNSATISFIED;
> +  }
> +
> +  return setup_resistor_and_interrupt_configuration(
> +           conf->pin_number,
> +           conf->pull_mode,
> +           conf->interrupt
> +         );
> +}
> +
> +rtems_status_code rtems_gpio_update_configuration(
> +  const rtems_gpio_pin_conf *conf
> +) {
> +  rtems_gpio_interrupt_configuration *interrupt_conf;
> +  gpio_pin_interrupt_state *interrupt_state;
> +  rtems_status_code sc;
> +  uint32_t bank;
> +
> +  if ( conf->pin_number < 0 || conf->pin_number >= BSP_GPIO_PIN_COUNT ) {
> +    return RTEMS_INVALID_ID;
> +  }
> +
> +  bank = BANK_NUMBER(conf->pin_number);
> +
> +  ACQUIRE_LOCK(gpio_bank_state[bank].lock);
> +
> +  /* If the pin is not being used returns with an error. */
> +  if ( gpio_pin_state[conf->pin_number].pin_function == NOT_USED ) {
> +    RELEASE_LOCK(gpio_bank_state[bank].lock);
> +
> +    return RTEMS_NOT_CONFIGURED;
> +  }
> +
> +  sc = rtems_gpio_resistor_mode(conf->pin_number, conf->pull_mode);
> +
> +  if ( sc != RTEMS_SUCCESSFUL ) {
> +#if defined(DEBUG)
> +    printk("rtems_gpio_resistor_mode failed with status code %d\n", sc);
> +#endif
> +
> +    return RTEMS_UNSATISFIED;
> +  }
> +
> +  interrupt_conf = (rtems_gpio_interrupt_configuration *) conf->interrupt;
> +
> +  interrupt_state = gpio_pin_state[conf->pin_number].interrupt_state;
> +
> +  if ( interrupt_state != NULL ) {
> +    sc = rtems_gpio_disable_interrupt(conf->pin_number);
> +
> +    if ( sc != RTEMS_SUCCESSFUL ) {
> +      RELEASE_LOCK(gpio_bank_state[bank].lock);
> +
> +#if defined(DEBUG)
> +      printk(
> +        "rtems_gpio_disable_interrupt failed with status code %d\n",
> +        sc
> +      );
> +#endif
> +
> +      return RTEMS_UNSATISFIED;
> +    }
> +  }
> +
> +  if ( interrupt_conf != NULL ) {
> +    sc = rtems_gpio_enable_interrupt(
> +           conf->pin_number,
> +           interrupt_conf->active_interrupt,
> +           interrupt_conf->handler_flag,
> +           interrupt_conf->threaded_interrupts,
> +           interrupt_conf->handler,
> +           interrupt_conf->arg
> +         );
> +
> +    if ( sc != RTEMS_SUCCESSFUL ) {
> +      RELEASE_LOCK(gpio_bank_state[bank].lock);
> +
> +#if defined(DEBUG)
> +      printk(
> +        "rtems_gpio_enable_interrupt failed with status code %d\n",
> +        sc
> +      );
> +#endif
> +
> +      return RTEMS_UNSATISFIED;
> +    }
> +  }
> +
> +  if ( interrupt_conf != NULL && interrupt_state != NULL ) {
> +    if (
> +        interrupt_conf->debounce_clock_tick_interval !=
> +        interrupt_state->debouncing_tick_count
> +    ) {
> +      interrupt_state->debouncing_tick_count =
> +        interrupt_conf->debounce_clock_tick_interval;
> +
> +      interrupt_state->last_isr_tick = 0;
> +    }
> +  }
> +
> +  RELEASE_LOCK(gpio_bank_state[bank].lock);
> +
> +  return RTEMS_SUCCESSFUL;
> +}
> +
> +rtems_status_code rtems_gpio_multi_set(
> + uint32_t *pin_numbers,
> + uint32_t pin_count
> +) {
> +  rtems_status_code sc;
> +  uint32_t bitmask;
> +  uint32_t bank;
> +
> +  sc = get_pin_bitmask(pin_numbers, pin_count, &bank, &bitmask,
> DIGITAL_OUTPUT);
> +
> +  if ( sc != RTEMS_SUCCESSFUL ) {
> +    return sc;
> +  }
> +
> +  ACQUIRE_LOCK(gpio_bank_state[bank].lock);
> +
> +  sc = rtems_gpio_bsp_multi_set(bank, bitmask);
> +
> +  RELEASE_LOCK(gpio_bank_state[bank].lock);
> +
> +  return sc;
> +}
> +
> +rtems_status_code rtems_gpio_multi_clear(
> +  uint32_t *pin_numbers,
> +  uint32_t pin_count
> +) {
> +  rtems_status_code sc;
> +  uint32_t bitmask;
> +  uint32_t bank;
> +
> +  sc = get_pin_bitmask(pin_numbers, pin_count, &bank, &bitmask,
> DIGITAL_OUTPUT);
> +
> +  if ( sc != RTEMS_SUCCESSFUL ) {
> +    return sc;
> +  }
> +
> +  ACQUIRE_LOCK(gpio_bank_state[bank].lock);
> +
> +  sc = rtems_gpio_bsp_multi_clear(bank, bitmask);
> +
> +  RELEASE_LOCK(gpio_bank_state[bank].lock);
> +
> +  return sc;
> +}
> +
> +uint32_t rtems_gpio_multi_read(
> +  uint32_t *pin_numbers,
> +  uint32_t pin_count
> +) {
> +  rtems_status_code sc;
> +  uint32_t bitmask;
> +  uint32_t bank;
> +  uint32_t rv;
> +
> +  sc = get_pin_bitmask(pin_numbers, pin_count, &bank, &bitmask,
> DIGITAL_INPUT);
> +
> +  if ( sc != RTEMS_SUCCESSFUL ) {
> +    return 0xDEADBEEF;
> +  }
> +
> +  ACQUIRE_LOCK(gpio_bank_state[bank].lock);
> +
> +  rv = rtems_gpio_bsp_multi_read(bank, bitmask);
> +
> +  RELEASE_LOCK(gpio_bank_state[bank].lock);
> +
> +  return rv;
> +}
> +
> +rtems_status_code rtems_gpio_set(uint32_t pin_number)
> +{
> +  rtems_status_code sc;
> +  uint32_t bank;
> +  uint32_t pin;
> +
> +  if ( pin_number < 0 || pin_number >= BSP_GPIO_PIN_COUNT ) {
> +    return RTEMS_INVALID_ID;
> +  }
> +
> +  bank = BANK_NUMBER(pin_number);
> +  pin = PIN_NUMBER(pin_number);
> +
> +  ACQUIRE_LOCK(gpio_bank_state[bank].lock);
> +
> +  if (
> +      gpio_pin_state[pin_number].pin_function != DIGITAL_OUTPUT ||
> +      gpio_pin_state[pin_number].on_group
> +  ) {
> +    RELEASE_LOCK(gpio_bank_state[bank].lock);
> +
> +#if defined(DEBUG)
> +    printk("Can only set digital output pins\n");
> +#endif
> +
> +    return RTEMS_NOT_CONFIGURED;
> +  }
> +
> +  if ( gpio_pin_state[pin_number].logic_invert ) {
> +    sc = rtems_gpio_bsp_clear(bank, pin);
> +  }
> +  else {
> +    sc = rtems_gpio_bsp_set(bank, pin);
> +  }
> +
> +  RELEASE_LOCK(gpio_bank_state[bank].lock);
> +
> +  return sc;
> +}
> +
> +rtems_status_code rtems_gpio_clear(uint32_t pin_number)
> +{
> +  rtems_status_code sc;
> +  uint32_t bank;
> +  uint32_t pin;
> +
> +  if ( pin_number < 0 || pin_number >= BSP_GPIO_PIN_COUNT ) {
> +    return RTEMS_INVALID_ID;
> +  }
> +
> +  bank = BANK_NUMBER(pin_number);
> +  pin = PIN_NUMBER(pin_number);
> +
> +  ACQUIRE_LOCK(gpio_bank_state[bank].lock);
> +
> +  if (
> +      gpio_pin_state[pin_number].pin_function != DIGITAL_OUTPUT ||
> +      gpio_pin_state[pin_number].on_group
> +  ) {
> +    RELEASE_LOCK(gpio_bank_state[bank].lock);
> +
> +#if defined(DEBUG)
> +    printk("Can only clear digital output pins\n");
> +#endif
> +
> +    return RTEMS_NOT_CONFIGURED;
> +  }
> +
> +  if ( gpio_pin_state[pin_number].logic_invert ) {
> +    sc = rtems_gpio_bsp_set(bank, pin);
> +  }
> +  else {
> +    sc = rtems_gpio_bsp_clear(bank, pin);
> +  }
> +
> +  RELEASE_LOCK(gpio_bank_state[bank].lock);
> +
> +  return sc;
> +}
> +
> +uint8_t rtems_gpio_get_value(uint32_t pin_number)
>
 uint32_t rtems_gpio_get_value(uint32_t pin_number)

> +{
> +  uint32_t bank;
> +  uint32_t pin;
> +  int rv;
>
uint32_t rv;

> +
> +  if ( pin_number < 0 || pin_number >= BSP_GPIO_PIN_COUNT ) {
> +    return -1;
> +  }
> +
> +  bank = BANK_NUMBER(pin_number);
> +  pin = PIN_NUMBER(pin_number);
> +
> +  ACQUIRE_LOCK(gpio_bank_state[bank].lock);
> +
> +  if (
> +      gpio_pin_state[pin_number].pin_function != DIGITAL_INPUT ||
> +      gpio_pin_state[pin_number].on_group
> +  ) {
> +    RELEASE_LOCK(gpio_bank_state[bank].lock);
> +
> +#if defined(DEBUG)
> +    printk("Can only read digital input pins\n");
> +#endif
> +
> +    return -1;
> +  }
> +
> +  rv = rtems_gpio_bsp_get_value(bank, pin);
> +
> +  if ( gpio_pin_state[pin_number].logic_invert && rv > 0 ) {
> +    RELEASE_LOCK(gpio_bank_state[bank].lock);
> +
> +    return !rv;
> +  }
> +
> +  RELEASE_LOCK(gpio_bank_state[bank].lock);
> +
> +  return ( rv > 0 ) ? 1 : rv;
> +}
> +
> +rtems_status_code rtems_gpio_request_pin(
> +  uint32_t pin_number,
> +  rtems_gpio_function function,
> +  bool output_enabled,
> +  bool logic_invert,
> +  void *bsp_specific
> +) {
> +  rtems_gpio_specific_data *bsp_data;
> +  rtems_status_code sc = RTEMS_SUCCESSFUL;
> +  uint32_t bank;
> +  uint32_t pin;
> +
> +  if ( pin_number < 0 || pin_number >= BSP_GPIO_PIN_COUNT ) {
> +    return RTEMS_INVALID_ID;
> +  }
> +
> +  bank = BANK_NUMBER(pin_number);
> +  pin = PIN_NUMBER(pin_number);
> +
> +  ACQUIRE_LOCK(gpio_bank_state[bank].lock);
> +
> +  /* If the pin is already being used returns with an error. */
> +  if ( gpio_pin_state[pin_number].pin_function != NOT_USED ) {
> +    RELEASE_LOCK(gpio_bank_state[bank].lock);
> +
> +    return RTEMS_RESOURCE_IN_USE;
> +  }
> +
> +  switch ( function ) {
> +    case DIGITAL_INPUT:
> +      sc = rtems_gpio_bsp_select_input(bank, pin, bsp_specific);
> +      break;
> +    case DIGITAL_OUTPUT:
> +      sc = rtems_gpio_bsp_select_output(bank, pin, bsp_specific);
> +      break;
> +    case BSP_SPECIFIC:
> +      bsp_data = (rtems_gpio_specific_data *) bsp_specific;
> +
> +      if ( bsp_data == NULL ) {
> +        RELEASE_LOCK(gpio_bank_state[bank].lock);
> +
> +        return RTEMS_UNSATISFIED;
> +      }
> +
> +      sc = rtems_bsp_select_specific_io(
> +             bank,
> +             pin,
> +             bsp_data->io_function,
> +             bsp_data->pin_data
> +           );
> +      break;
> +    case NOT_USED:
> +    default:
> +      RELEASE_LOCK(gpio_bank_state[bank].lock);
> +
> +      return RTEMS_NOT_DEFINED;
> +  }
> +
> +  if ( sc != RTEMS_SUCCESSFUL ) {
> +    RELEASE_LOCK(gpio_bank_state[bank].lock);
> +
> +    return sc;
> +  }
> +
> +  /* If the function was successfully assigned to the pin,
> +   * record that information on the gpio_pin_state structure. */
> +  gpio_pin_state[pin_number].pin_function = function;
> +  gpio_pin_state[pin_number].logic_invert = logic_invert;
> +
> +  if ( function == DIGITAL_OUTPUT ) {
> +    if ( output_enabled == true ) {
> +      sc = rtems_gpio_bsp_set(bank, pin);
> +    }
> +    else {
> +      sc = rtems_gpio_bsp_clear(bank, pin);
> +    }
> +  }
> +
> +  RELEASE_LOCK(gpio_bank_state[bank].lock);
> +
> +  return sc;
> +}
> +
> +rtems_status_code rtems_gpio_resistor_mode(
> +  uint32_t pin_number,
> +  rtems_gpio_pull_mode mode
> +) {
> +  rtems_status_code sc;
> +  uint32_t bank;
> +  uint32_t pin;
> +
> +  if ( pin_number < 0 || pin_number >= BSP_GPIO_PIN_COUNT ) {
> +    return RTEMS_INVALID_ID;
> +  }
> +
> +  bank = BANK_NUMBER(pin_number);
> +  pin = PIN_NUMBER(pin_number);
> +
> +  ACQUIRE_LOCK(gpio_bank_state[bank].lock);
> +
> +  /* If the desired actuation mode is already set, silently exits.
> +   * The NO_PULL_RESISTOR is a special case, as some platforms have
> +   * pull-up resistors enabled on startup, so this state may have to
> +   * be reinforced in the hardware. */
> +  if (
> +      gpio_pin_state[pin_number].resistor_mode == mode &&
> +      mode != NO_PULL_RESISTOR
> +  ) {
> +    RELEASE_LOCK(gpio_bank_state[bank].lock);
> +
> +    return RTEMS_SUCCESSFUL;
> +  }
> +
> +  sc = rtems_gpio_bsp_set_resistor_mode(bank, pin, mode);
> +
> +  if ( sc != RTEMS_SUCCESSFUL ) {
> +    RELEASE_LOCK(gpio_bank_state[bank].lock);
> +
> +    return sc;
> +  }
> +
> +  gpio_pin_state[pin_number].resistor_mode = mode;
> +
> +  RELEASE_LOCK(gpio_bank_state[bank].lock);
> +
> +  return RTEMS_SUCCESSFUL;
> +}
> +
> +rtems_status_code rtems_gpio_release_pin(uint32_t pin_number)
> +{
> +  gpio_pin_interrupt_state *interrupt_state;
> +  rtems_status_code sc;
> +  uint32_t bank;
> +
> +  if ( pin_number < 0 || pin_number >= BSP_GPIO_PIN_COUNT ) {
> +    return RTEMS_INVALID_ID;
> +  }
> +
> +  bank = BANK_NUMBER(pin_number);
> +
> +  ACQUIRE_LOCK(gpio_bank_state[bank].lock);
> +
> +  interrupt_state = gpio_pin_state[pin_number].interrupt_state;
> +
> +  /* If the pin has an enabled interrupt then remove the handler(s)
> +   * and disable interrupts on that pin. */
> +  if ( interrupt_state != NULL ) {
> +    sc = rtems_gpio_disable_interrupt(pin_number);
> +
> +    if ( sc != RTEMS_SUCCESSFUL ) {
> +      RELEASE_LOCK(gpio_bank_state[bank].lock);
> +
> +      return sc;
> +    }
> +  }
> +
> +  gpio_pin_state[pin_number].pin_function = NOT_USED;
> +  gpio_pin_state[pin_number].resistor_mode = NO_PULL_RESISTOR;
> +  gpio_pin_state[pin_number].logic_invert = false;
> +  gpio_pin_state[pin_number].on_group = false;
> +
> +  RELEASE_LOCK(gpio_bank_state[bank].lock);
> +
> +  return RTEMS_SUCCESSFUL;
> +}
> +
> +rtems_status_code rtems_gpio_release_configuration(
> +  const rtems_gpio_pin_conf *conf
> +) {
> +  if ( conf == NULL ) {
> +    return RTEMS_UNSATISFIED;
> +  }
> +
> +  return rtems_gpio_release_pin(conf->pin_number);
> +}
> +
> +rtems_status_code rtems_gpio_release_multiple_pins(
> +  const rtems_gpio_pin_conf *pins,
> +  uint32_t pin_count
> +) {
> +  rtems_status_code sc;
> +  uint32_t i;
> +
> +  if ( pins == NULL ) {
> +    return RTEMS_UNSATISFIED;
> +  }
> +
> +  for ( i = 0; i < pin_count; ++i ) {
> +    sc = rtems_gpio_release_pin(pins[i].pin_number);
> +
> +    if ( sc != RTEMS_SUCCESSFUL ) {
> +      return sc;
> +    }
> +  }
> +
> +  return RTEMS_SUCCESSFUL;
> +}
> +
> +rtems_status_code rtems_gpio_release_pin_group(
> +  rtems_gpio_group *group
> +) {
> +  rtems_status_code sc;
> +  uint8_t i;
> +
> +  ACQUIRE_LOCK(group->group_lock);
> +
> +  sc = rtems_semaphore_flush(group->group_lock);
> +
> +  if ( sc != RTEMS_SUCCESSFUL ) {
> +    RELEASE_LOCK(group->group_lock);
> +
> +    return sc;
> +  }
> +
> +  RELEASE_LOCK(group->group_lock);
> +
> +  /* Deletes the group lock. */
> +  sc = rtems_semaphore_delete(group->group_lock);
> +
> +  if ( sc != RTEMS_SUCCESSFUL ) {
> +    return sc;
> +  }
> +
> +  /* Pin releasing. */
> +  for ( i = 0; i < group->input_count; ++i ) {
> +    sc = rtems_gpio_release_pin(group->digital_inputs[i]);
> +
> +    if ( sc != RTEMS_SUCCESSFUL ) {
> +      return sc;
> +    }
> +  }
> +
> +  if ( group->input_count > 0 ) {
> +    free(group->digital_inputs);
> +  }
> +
> +  for ( i = 0; i < group->output_count; ++i ) {
> +    sc = rtems_gpio_release_pin(group->digital_outputs[i]);
> +
> +    if ( sc != RTEMS_SUCCESSFUL ) {
> +      return sc;
> +    }
> +  }
> +
> +  if ( group->output_count > 0 ) {
> +    free(group->digital_outputs);
> +  }
> +
> +  for ( i = 0; i < group->bsp_specific_pin_count; ++i ) {
> +    sc = rtems_gpio_release_pin(group->bsp_speficifc_pins[i]);
> +
> +    if ( sc != RTEMS_SUCCESSFUL ) {
> +      return sc;
> +    }
> +  }
> +
> +  if ( group->bsp_specific_pin_count > 0 ) {
> +    free(group->bsp_speficifc_pins);
> +  }
> +
> +  rtems_chain_extract(&group->node);
> +
> +  free(group);
> +
> +  return RTEMS_SUCCESSFUL;
> +}
> +
> +rtems_status_code rtems_gpio_debounce_switch(uint32_t pin_number, int
> ticks)
> +{
> +  gpio_pin_interrupt_state *interrupt_state;
> +  uint32_t bank;
> +
> +  if ( pin_number < 0 || pin_number >= BSP_GPIO_PIN_COUNT ) {
> +    return RTEMS_INVALID_ID;
> +  }
> +
> +  bank = BANK_NUMBER(pin_number);
> +
> +  ACQUIRE_LOCK(gpio_bank_state[bank].lock);
> +
> +  interrupt_state = gpio_pin_state[pin_number].interrupt_state;
> +
> +  /* If no interrupt configuration is set for this pin, or if the pin is
> +   * not set as a digital input, or the pin in on a group. */
> +  if (
> +      interrupt_state == NULL ||
> +      gpio_pin_state[pin_number].pin_function != DIGITAL_INPUT ||
> +      gpio_pin_state[pin_number].on_group
> +  ) {
> +    RELEASE_LOCK(gpio_bank_state[bank].lock);
> +
> +    return RTEMS_NOT_CONFIGURED;
> +  }
> +
> +  interrupt_state->debouncing_tick_count = ticks;
> +  interrupt_state->last_isr_tick = 0;
> +
> +  RELEASE_LOCK(gpio_bank_state[bank].lock);
> +
> +  return RTEMS_SUCCESSFUL;
> +}
> +
> +rtems_status_code rtems_gpio_interrupt_handler_install(
> +  uint32_t pin_number,
> +  rtems_gpio_irq_state (*handler) (void *arg),
> +  void *arg
> +) {
> +  gpio_pin_interrupt_state *interrupt_state;
> +  gpio_handler_node *isr_node;
> +  uint32_t bank;
> +
> +  if ( pin_number < 0 || pin_number >= BSP_GPIO_PIN_COUNT ) {
> +    return RTEMS_INVALID_ID;
> +  }
> +
> +  bank = BANK_NUMBER(pin_number);
> +
> +  ACQUIRE_LOCK(gpio_bank_state[bank].lock);
> +
> +  interrupt_state = gpio_pin_state[pin_number].interrupt_state;
> +
> +  /* If no interrupt configuration is set for this pin. */
> +   if ( interrupt_state == NULL ) {
> +    RELEASE_LOCK(gpio_bank_state[bank].lock);
> +
> +    return RTEMS_NOT_CONFIGURED;
> +  }
> +
> +  /* If the current pin has no interrupt enabled
> +   * then it does not need an handler. */
> +  if ( interrupt_state->active_interrupt == NONE ) {
> +    RELEASE_LOCK(gpio_bank_state[bank].lock);
> +
> +    return RTEMS_NOT_CONFIGURED;
> +  }
> +  /* If the pin already has an enabled interrupt but the installed handler
> +   * is set as unique. */
> +  else if (
> +           interrupt_state->handler_flag == UNIQUE_HANDLER &&
> +           !rtems_chain_is_empty(&interrupt_state->handler_chain)
> +  ) {
> +    RELEASE_LOCK(gpio_bank_state[bank].lock);
> +
> +    return RTEMS_TOO_MANY;
> +  }
> +
> +  /* Update the pin's ISR list. */
> +  isr_node = (gpio_handler_node *) malloc(sizeof(gpio_handler_node));
> +
> +  if ( isr_node == NULL ) {
> +    RELEASE_LOCK(gpio_bank_state[bank].lock);
> +
> +    return RTEMS_NO_MEMORY;
> +  }
> +
> +  isr_node->handler = handler;
> +  isr_node->arg = arg;
> +
> +  rtems_chain_append(&interrupt_state->handler_chain, &isr_node->node);
> +
> +  RELEASE_LOCK(gpio_bank_state[bank].lock);
> +
> +  return RTEMS_SUCCESSFUL;
> +}
> +
> +rtems_status_code rtems_gpio_enable_interrupt(
> +  uint32_t pin_number,
> +  rtems_gpio_interrupt interrupt,
> +  rtems_gpio_handler_flag flag,
> +  bool threaded_handling,
> +  rtems_gpio_irq_state (*handler) (void *arg),
> +  void *arg
> +) {
> +  gpio_pin_interrupt_state *interrupt_state;
> +  rtems_vector_number vector;
> +  rtems_status_code sc;
> +  uint32_t bank;
> +  uint32_t pin;
> +
> +  if ( pin_number < 0 || pin_number >= BSP_GPIO_PIN_COUNT ) {
> +    return RTEMS_INVALID_ID;
> +  }
> +
> +  bank = BANK_NUMBER(pin_number);
> +  pin = PIN_NUMBER(pin_number);
> +
> +  vector = rtems_gpio_bsp_get_vector(bank);
> +
> +  ACQUIRE_LOCK(gpio_bank_state[bank].lock);
> +
> +  if (
> +      gpio_pin_state[pin_number].pin_function != DIGITAL_INPUT ||
> +      gpio_pin_state[pin_number].on_group
> +  ) {
> +    RELEASE_LOCK(gpio_bank_state[bank].lock);
> +
> +    return RTEMS_NOT_CONFIGURED;
> +  }
> +
> +  /* If the bank already has at least one interrupt enabled on a pin,
> +   * then new interrupts on this bank must follow the current
> +   * threading policy. */
> +  if (
> +      gpio_bank_state[bank].interrupt_counter > 0 &&
> +      gpio_bank_state[bank].threaded_interrupts != threaded_handling
> +  ) {
> +    RELEASE_LOCK(gpio_bank_state[bank].lock);
> +
> +    return RTEMS_RESOURCE_IN_USE;
> +  }
> +
> +  interrupt_state = gpio_pin_state[pin_number].interrupt_state;
> +
> +  /* If an interrupt configuration is already in place for this pin. */
> +  if ( interrupt_state != NULL ) {
> +    RELEASE_LOCK(gpio_bank_state[bank].lock);
> +
> +    return RTEMS_RESOURCE_IN_USE;
> +  }
> +
> +  gpio_pin_state[pin_number].interrupt_state =
> +    (gpio_pin_interrupt_state *) malloc(sizeof(gpio_pin_interrupt_state));
> +
> +  if ( gpio_pin_state[pin_number].interrupt_state == NULL ) {
> +    return RTEMS_NO_MEMORY;
> +  }
> +
> +  gpio_pin_state[pin_number].interrupt_state->active_interrupt = NONE;
> +  gpio_pin_state[pin_number].interrupt_state->debouncing_tick_count = 0;
> +  gpio_pin_state[pin_number].interrupt_state->last_isr_tick = 0;
> +
> +  rtems_chain_initialize_empty(
> +    &gpio_pin_state[pin_number].interrupt_state->handler_chain
> +  );
> +
> +  interrupt_state = gpio_pin_state[pin_number].interrupt_state;
> +
> +  interrupt_state->active_interrupt = interrupt;
> +  interrupt_state->handler_flag = flag;
> +
> +  /* Installs the interrupt handler on the GPIO pin
> +   * tracking structure. */
> +  sc = rtems_gpio_interrupt_handler_install(pin_number, handler, arg);
> +
> +  if ( sc != RTEMS_SUCCESSFUL ) {
> +    RELEASE_LOCK(gpio_bank_state[bank].lock);
> +
> +    return RTEMS_UNSATISFIED;
> +  }
> +
> +  if ( threaded_handling ) {
> +    if (
> +        _Atomic_Load_uint(&threaded_interrupt_counter,
> ATOMIC_ORDER_RELAXED) == 0
> +    ) {
> +      sc = rtems_interrupt_server_initialize(
> +             INTERRUPT_SERVER_PRIORITY,
> +             INTERRUPT_SERVER_STACK_SIZE,
> +             INTERRUPT_SERVER_MODES,
> +             INTERRUPT_SERVER_ATTRIBUTES,
> +             NULL
> +           );
> +
> +      if ( sc != RTEMS_SUCCESSFUL ) {
> +        RELEASE_LOCK(gpio_bank_state[bank].lock);
> +
> +        return RTEMS_UNSATISFIED;
> +      }
> +    }
> +
> +    if ( gpio_bank_state[bank].interrupt_counter == 0 ) {
> +      sc = rtems_interrupt_server_handler_install(
> +             RTEMS_ID_NONE,
> +             vector,
> +             "GPIO_HANDLER",
> +             RTEMS_INTERRUPT_UNIQUE,
> +             (rtems_interrupt_handler) generic_bank_isr,
> +             &gpio_bank_state[bank].bank_number
> +           );
> +
> +      if ( sc != RTEMS_SUCCESSFUL ) {
> +        RELEASE_LOCK(gpio_bank_state[bank].lock);
> +
> +        return RTEMS_UNSATISFIED;
> +      }
> +
> +      _Atomic_Fetch_add_uint(
> +        &threaded_interrupt_counter,
> +        1,
> +        ATOMIC_ORDER_RELAXED
> +      );
> +    }
> +  }
> +  else if ( gpio_bank_state[bank].interrupt_counter == 0 ) {
> +    sc = rtems_interrupt_handler_install(
> +           vector,
> +           "GPIO_HANDLER",
> +           RTEMS_INTERRUPT_UNIQUE,
> +           (rtems_interrupt_handler) generic_bank_isr,
> +           &gpio_bank_state[bank].bank_number
> +         );
> +
> +    if ( sc != RTEMS_SUCCESSFUL ) {
> +      RELEASE_LOCK(gpio_bank_state[bank].lock);
> +
> +      return RTEMS_UNSATISFIED;
> +    }
> +  }
> +
> +  sc = rtems_bsp_enable_interrupt(bank, pin, interrupt);
> +
> +  if ( sc != RTEMS_SUCCESSFUL ) {
> +    RELEASE_LOCK(gpio_bank_state[bank].lock);
> +
> +    return RTEMS_UNSATISFIED;
> +  }
> +
> +  /* If this was the first interrupt enabled on this GPIO bank,
> +   * record the threading policy. */
> +  if ( gpio_bank_state[bank].interrupt_counter == 0 ) {
> +    gpio_bank_state[bank].threaded_interrupts = threaded_handling;
> +  }
> +
> +  ++gpio_bank_state[bank].interrupt_counter;
> +
> +  RELEASE_LOCK(gpio_bank_state[bank].lock);
> +
> +  return RTEMS_SUCCESSFUL;
> +}
> +
> +rtems_status_code rtems_gpio_interrupt_handler_remove(
> +  uint32_t pin_number,
> +  rtems_gpio_irq_state (*handler) (void *arg),
> +  void *arg
> +) {
> +  gpio_pin_interrupt_state *interrupt_state;
> +  rtems_chain_control *handler_list;
> +  rtems_chain_node *node;
> +  rtems_chain_node *next_node;
> +  gpio_handler_node *isr_node;
> +  uint32_t bank;
> +
> +  if ( pin_number < 0 || pin_number >= BSP_GPIO_PIN_COUNT ) {
> +    return RTEMS_INVALID_ID;
> +  }
> +
> +  bank = BANK_NUMBER(pin_number);
> +
> +  ACQUIRE_LOCK(gpio_bank_state[bank].lock);
> +
> +  interrupt_state = gpio_pin_state[pin_number].interrupt_state;
> +
> +  /* If no interrupt configuration is set for this pin. */
> +  if ( interrupt_state == NULL ) {
> +    RELEASE_LOCK(gpio_bank_state[bank].lock);
> +
> +    return RTEMS_NOT_CONFIGURED;
> +  }
> +
> +  handler_list = &interrupt_state->handler_chain;
> +
> +  node = rtems_chain_first(handler_list);
> +
> +  /* If the first node is also the last handler for this pin, disables
> +   * interrupts on this pin as there will be no handler to handle it.
> +   * This also removes the remaining handler. */
> +  if ( rtems_chain_is_last(node) ) {
> +    RELEASE_LOCK(gpio_bank_state[bank].lock);
> +
> +    return rtems_gpio_disable_interrupt(pin_number);
> +  }
> +
> +  /* Iterate the ISR list. */
> +  while ( !rtems_chain_is_tail(handler_list, node) ) {
> +    isr_node = (gpio_handler_node *) node;
> +
> +    next_node = node->next;
> +
> +    if ( isr_node->handler == handler && isr_node->arg == arg ) {
> +      rtems_chain_extract(node);
> +
> +      break;
> +    }
> +
> +    node = next_node;
> +  }
> +
> +  RELEASE_LOCK(gpio_bank_state[bank].lock);
> +
> +  return RTEMS_SUCCESSFUL;
> +}
> +
> +rtems_status_code rtems_gpio_disable_interrupt(uint32_t pin_number)
> +{
> +  gpio_pin_interrupt_state *interrupt_state;
> +  rtems_chain_control *handler_list;
> +  rtems_chain_node *node;
> +  rtems_chain_node *next_node;
> +  rtems_vector_number vector;
> +  rtems_status_code sc;
> +  uint32_t bank;
> +  uint32_t pin;
> +
> +  if ( pin_number < 0 || pin_number >= BSP_GPIO_PIN_COUNT ) {
> +    return RTEMS_INVALID_ID;
> +  }
> +
> +  bank = BANK_NUMBER(pin_number);
> +  pin = PIN_NUMBER(pin_number);
> +
> +  vector = rtems_gpio_bsp_get_vector(bank);
> +
> +  ACQUIRE_LOCK(gpio_bank_state[bank].lock);
> +
> +  interrupt_state = gpio_pin_state[pin_number].interrupt_state;
> +
> +  /* If no interrupt configuration is set for this pin. */
> +  if ( interrupt_state == NULL ) {
> +    RELEASE_LOCK(gpio_bank_state[bank].lock);
> +
> +    return RTEMS_NOT_CONFIGURED;
> +  }
> +
> +  sc = rtems_bsp_disable_interrupt(bank, pin,
> interrupt_state->active_interrupt);
> +
> +  if ( sc != RTEMS_SUCCESSFUL ) {
> +    RELEASE_LOCK(gpio_bank_state[bank].lock);
> +
> +    return RTEMS_UNSATISFIED;
> +  }
> +
> +  interrupt_state->active_interrupt = NONE;
> +
> +  handler_list = &interrupt_state->handler_chain;
> +
> +  node = rtems_chain_first(handler_list);
> +
> +  /* Iterate the ISR list. */
> +  while ( !rtems_chain_is_tail(handler_list, node) ) {
> +    next_node = node->next;
> +
> +    rtems_chain_extract(node);
> +
> +    node = next_node;
> +  }
> +
> +  /* If this is the last GPIO interrupt are left in this bank,
> +   * removes the handler. */
> +  if ( gpio_bank_state[bank].interrupt_counter == 1 ) {
> +    if ( gpio_bank_state[bank].threaded_interrupts ) {
> +      sc = rtems_interrupt_server_handler_remove(
> +             RTEMS_ID_NONE,
> +             vector,
> +             (rtems_interrupt_handler) generic_bank_isr,
> +             &gpio_bank_state[bank].bank_number
> +           );
> +    }
> +    else {
> +      sc = rtems_interrupt_handler_remove(
> +             vector,
> +             (rtems_interrupt_handler) generic_bank_isr,
> +             &gpio_bank_state[bank].bank_number
> +           );
> +    }
> +
> +    if ( sc != RTEMS_SUCCESSFUL ) {
> +      RELEASE_LOCK(gpio_bank_state[bank].lock);
> +
> +      return RTEMS_UNSATISFIED;
> +    }
> +  }
> +
> +  /* Free the pin's interrupt state structure. */
> +  free(interrupt_state);
> +
> +  --gpio_bank_state[bank].interrupt_counter;
> +
> +  if ( gpio_bank_state[bank].threaded_interrupts ) {
> +    _Atomic_Fetch_sub_uint(&threaded_interrupt_counter, 1,
> ATOMIC_ORDER_RELAXED);
> +  }
> +
> +  RELEASE_LOCK(gpio_bank_state[bank].lock);
> +
> +  return RTEMS_SUCCESSFUL;
> +}
> diff --git a/c/src/lib/libbsp/shared/include/gpio.h
> b/c/src/lib/libbsp/shared/include/gpio.h
> new file mode 100644
> index 0000000..b2deb1e
> --- /dev/null
> +++ b/c/src/lib/libbsp/shared/include/gpio.h
> @@ -0,0 +1,948 @@
> +/**
> + * @file gpio.h
> + *
> + * @ingroup rtems_gpio
> + *
> + * @brief RTEMS GPIO API definition.
> + */
> +
> +/*
> + *  Copyright (c) 2014-2015 Andre Marques <andre.lousa.marques at
> gmail.com>
> + *
> + *  The license and distribution terms for this file may be
> + *  found in the file LICENSE in this distribution or at
> + *  http://www.rtems.org/license/LICENSE.
> + */
> +
> +#ifndef LIBBSP_SHARED_GPIO_H
> +#define LIBBSP_SHARED_GPIO_H
> +
> +#include <bsp.h>
> +#include <rtems.h>
> +
> +#ifdef __cplusplus
> +extern "C" {
> +#endif /* __cplusplus */
> +
> +#if !defined(BSP_GPIO_PIN_COUNT) || !defined(BSP_GPIO_PINS_PER_BANK)
> +  #error "BSP_GPIO_PIN_COUNT or BSP_GPIO_PINS_PER_BANK is not defined."
> +#endif
> +
> +#if BSP_GPIO_PIN_COUNT <= 0 || BSP_GPIO_PINS_PER_BANK <= 0
> +  #error "Invalid BSP_GPIO_PIN_COUNT or BSP_GPIO_PINS_PER_BANK."
> +#endif
> +
> +#if BSP_GPIO_PINS_PER_BANK > 32
> +  #error "Invalid BSP_GPIO_PINS_PER_BANK. Must be in the range of 1 to
> 32."
> +#endif
> +
> +#define GPIO_LAST_BANK_PINS BSP_GPIO_PIN_COUNT % BSP_GPIO_PINS_PER_BANK
> +
> +#if GPIO_LAST_BANK_PINS > 0
> +  #define GPIO_BANK_COUNT (BSP_GPIO_PIN_COUNT / BSP_GPIO_PINS_PER_BANK) +
> 1
> +#else
> +  #define GPIO_BANK_COUNT BSP_GPIO_PIN_COUNT / BSP_GPIO_PINS_PER_BANK
> +  #define GPIO_LAST_BANK_PINS BSP_GPIO_PINS_PER_BANK
> +#endif
> +
> +#if defined(BSP_GPIO_PINS_PER_SELECT_BANK) &&
> BSP_GPIO_PINS_PER_SELECT_BANK > 32
> +  #error "Invalid BSP_GPIO_PINS_PER_SELECT_BANK. Must under and including
> 32."
> +#elif defined(BSP_GPIO_PINS_PER_SELECT_BANK) <= 32
> +  #define GPIO_SELECT_BANK_COUNT \
> +    BSP_GPIO_PINS_PER_BANK / BSP_GPIO_PINS_PER_SELECT_BANK
> +#endif
> +
> +#define INTERRUPT_SERVER_PRIORITY 1
> +#define INTERRUPT_SERVER_STACK_SIZE 2 * RTEMS_MINIMUM_STACK_SIZE
> +#define INTERRUPT_SERVER_MODES RTEMS_TIMESLICE | RTEMS_PREEMPT
> +#define INTERRUPT_SERVER_ATTRIBUTES RTEMS_DEFAULT_ATTRIBUTES
> +
> +/**
> + * @name GPIO data structures
> + *
> + * @{
> + */
> +
> +/**
> + * @brief The set of possible configurations for a GPIO pull-up resistor.
> + *
> + * Enumerated type to define the possible pull-up resistor configurations
> + * for a GPIO pin.
> + */
> +typedef enum
> +{
> +  PULL_UP = 1,
> +  PULL_DOWN,
> +  NO_PULL_RESISTOR
> +} rtems_gpio_pull_mode;
> +
> +/**
> + * @brief The set of possible functions a pin can have.
> + *
> + * Enumerated type to define a pin function.
> + */
> +typedef enum
> +{
> +  DIGITAL_INPUT = 0,
> +  DIGITAL_OUTPUT,
> +  BSP_SPECIFIC,
> +  NOT_USED
> +} rtems_gpio_function;
> +
> +/**
> + * @brief The set of possible interrupts a GPIO pin can generate.
> + *
> + * Enumerated type to define a GPIO pin interrupt.
> + */
> +typedef enum
> +{
> +  FALLING_EDGE = 0,
> +  RISING_EDGE,
> +  LOW_LEVEL,
> +  HIGH_LEVEL,
> +  BOTH_EDGES,
> +  BOTH_LEVELS,
> +  NONE
> +} rtems_gpio_interrupt;
> +
> +/**
> + * @brief The set of possible handled states an user-defined interrupt
> + *        handler can return.
> + *
> + * Enumerated type to define an interrupt handler handled state.
> + */
> +typedef enum
> +{
> +  IRQ_HANDLED,
> +  IRQ_NONE
> +} rtems_gpio_irq_state;
> +
> +/**
> + * @brief The set of flags to specify an user-defined interrupt handler
> + *        uniqueness on a GPIO pin.
> + *
> + * Enumerated type to define an interrupt handler shared flag.
> + */
> +typedef enum
> +{
> +  SHARED_HANDLER,
> +  UNIQUE_HANDLER
> +} rtems_gpio_handler_flag;
> +
> +/**
> + * @brief Object containing relevant information for assigning a BSP
> specific
> + *        function to a pin.
> + *
> + * Encapsulates relevant data for a BSP specific GPIO function.
> + */
> +typedef struct
> +{
> +  /* The BSP defined function code. */
> +  uint32_t io_function;
> +
> +  void *pin_data;
> +} rtems_gpio_specific_data;
> +
> +/**
> + * @brief Object containing configuration information
> + *        regarding interrupts.
> + */
> +typedef struct
> +{
> +  rtems_gpio_interrupt active_interrupt;
> +
> +  rtems_gpio_handler_flag handler_flag;
> +
> +  bool threaded_interrupts;
> +
> +  /* Interrupt handler function. */
> +  rtems_gpio_irq_state (*handler) (void *arg);
> +
> +  /* Interrupt handler function arguments. */
> +  void *arg;
> +
> +  /* Software switch debounce settings. It should contain the amount of
> clock
> +   * ticks that must pass between interrupts to ensure that the interrupt
> +   * was not caused by a switch bounce.
> +   * If set to 0 this feature is disabled . */
> +  uint32_t debounce_clock_tick_interval;
> +} rtems_gpio_interrupt_configuration;
> +
> +/**
> + * @brief Object containing configuration information
> + *        to request/update a GPIO pin.
> + */
> +typedef struct
> +{
> +  /* Processor pin number. */
> +  uint32_t pin_number;
> +  rtems_gpio_function function;
> +
> +  /* Pull resistor setting. */
> +  rtems_gpio_pull_mode pull_mode;
> +
> +  /* If digital out pin, set to TRUE to set the pin to logical high,
> +   * or FALSE for logical low. If not a digital out then this
> +   * is ignored. */
> +  bool output_enabled;
> +
> +  /* If true inverts digital in/out applicational logic. */
> +  bool logic_invert;
> +
> +  /* Pin interrupt configuration. Should be NULL if not used. */
> +  rtems_gpio_interrupt_configuration *interrupt;
> +
> +  /* Structure with BSP specific data, to use during the pin request.
> +   * If function == BSP_SPECIFIC this should have a pointer to
> +   * a rtems_gpio_specific_data structure.
> +   *
> +   * If not this field may be NULL. This is passed to the BSP function
> +   * so any BSP specific data can be passed to it through this pointer. */
> +  void *bsp_specific;
> +} rtems_gpio_pin_conf;
> +
> +/**
> + * @brief Object containing configuration information
> + *        to assign GPIO functions to multiple pins
> + *        at the same time. To be used by BSP code only.
> + */
> +typedef struct
> +{
> +  /* Global GPIO pin number. */
> +  uint32_t pin_number;
> +
> +  /* RTEMS GPIO pin function code. */
> +  rtems_gpio_function function;
> +
> +  /* BSP specific function code. Only used if function == BSP_SPECIFIC */
> +  uint32_t io_function;
> +
> +  /* BSP specific data. */
> +  void *bsp_specific;
> +} rtems_gpio_multiple_pin_select;
> +
> +/**
> + * @brief Object containing configuration information
> + *        to request a GPIO pin group.
> + */
> +typedef struct
> +{
> +  const rtems_gpio_pin_conf *digital_inputs;
> +  uint32_t input_count;
> +
> +  const rtems_gpio_pin_conf *digital_outputs;
> +  uint32_t output_count;
> +
> +  const rtems_gpio_pin_conf *bsp_specifics;
> +  uint32_t bsp_specific_pin_count;
> +} rtems_gpio_group_definition;
> +
> +/**
> + * @brief Opaque type for a GPIO pin group.
> + */
> +typedef struct rtems_gpio_group rtems_gpio_group;
> +
> +/** @} */
> +
> +/**
> + * @name gpio Usage
> + *
> + * @{
> + */
> +
> +/**
> + * @brief Initializes the GPIO API.
> + *
> + * @retval RTEMS_SUCCESSFUL API successfully initialized.
> + * @retval * @see rtems_semaphore_create().
> + */
> +extern rtems_status_code rtems_gpio_initialize(void);
> +
> +/**
> + * @brief Instantiates a GPIO pin group.
> + *        To define the group @see rtems_gpio_define_pin_group().
> + *
> + * @retval rtems_gpio_group pointer.
> + */
> +extern rtems_gpio_group *rtems_gpio_create_pin_group(void);
> +
> +/**
> + * @brief Requests a GPIO pin group configuration.
> + *
> + * @param[in] group_definition rtems_gpio_group_definition structure
> filled with
> + *                             the group pins configurations.
> + * @param[out] group Reference to the created group.
> + *
> + * @retval RTEMS_SUCCESSFUL Pin group was configured successfully.
> + * @retval RTEMS_UNSATISFIED @var group_definition or @var group is NULL,
> + *                           the @var pins are not from the same bank,
> + *                           no pins were defined or could not satisfy at
> + *                           least one given configuration.
> + * @retval RTEMS_RESOURCE_IN_USE At least one pin is already being used.
> + * @retval * @see rtems_semaphore_create().
> + */
> +extern rtems_status_code rtems_gpio_define_pin_group(
> +  const rtems_gpio_group_definition *group_definition,
> +  rtems_gpio_group *group
> +);
> +
> +/**
> + * @brief Writes a value to the group's digital outputs. The pins order
> + *        is as defined in the group definition.
> + *
> + * @param[in] data Data to write/send.
> + * @param[in] group Reference to the group.
> + *
> + * @retval RTEMS_SUCCESSFUL Data successfully written.
> + * @retval RTEMS_NOT_DEFINED Group has no output pins.
> + * @retval RTEMS_UNSATISFIED Could not operate on at least one of the
> pins.
> + */
> +extern rtems_status_code rtems_gpio_write_group(
> +  uint32_t data,
> +  rtems_gpio_group *group
> +);
> +
> +/**
> + * @brief Reads the value/level of the group's digital inputs. The pins
> order
> + *        is as defined in the group definition.
> + *
> + * @param[in] group Reference to the group.
> + *
> + * @retval The function returns a 32-bit bitmask with the group's input
> pins
> + *         current logical values.
> + * @retval 0xDEADBEEF Group has no input pins.
> + */
> +extern uint32_t rtems_gpio_read_group(rtems_gpio_group *group);
> +
> +/**
> + * @brief Performs a BSP specific operation on a group of pins. The pins
> order
> + *        is as defined in the group definition.
> + *
> + * @param[in] group Reference to the group.
> + * @param[in] arg Pointer to a BSP defined structure with BSP-specific
> + *                data. This field is handled by the BSP.
> + *
> + * @retval RTEMS_SUCCESSFUL Operation completed with success.
> + * @retval RTEMS_NOT_DEFINED Group has no BSP specific pins, or the BSP
> does not
> + *                           support BSP specific operations for groups.
> + * @retval RTEMS_UNSATISFIED Could not operate on at least one of the
> pins.
> + */
> +extern rtems_status_code rtems_gpio_group_bsp_specific_operation(
> +  rtems_gpio_group *group,
> +  void *arg
> +);
> +
> +/**
> + * @brief Requests a GPIO pin configuration.
> + *
> + * @param[in] conf rtems_gpio_pin_conf structure filled with the pin
> information
> + *                 and desired configurations.
> + *
> + * @retval RTEMS_SUCCESSFUL Pin was configured successfully.
> + * @retval RTEMS_UNSATISFIED Could not satisfy the given configuration.
> + */
> +extern rtems_status_code rtems_gpio_request_configuration(
> +  const rtems_gpio_pin_conf *conf
> +);
> +
> +/**
> + * @brief Updates the current configuration of a GPIO pin .
> + *
> + * @param[in] conf rtems_gpio_pin_conf structure filled with the pin
> information
> + *                 and desired configurations.
> + *
> + * @retval RTEMS_SUCCESSFUL Pin configuration was updated successfully.
> + * @retval RTEMS_INVALID_ID Pin number is invalid.
> + * @retval RTEMS_NOT_CONFIGURED The pin is not being used.
> + * @retval RTEMS_UNSATISFIED Could not update the pin's configuration.
> + */
> +extern rtems_status_code rtems_gpio_update_configuration(
> +  const rtems_gpio_pin_conf *conf
> +);
> +
> +/**
> + * @brief Sets multiple output GPIO pins with the logical high.
> + *
> + * @param[in] pin_numbers Array with the GPIO pin numbers to set.
> + * @param[in] count Number of GPIO pins to set.
> + *
> + * @retval RTEMS_SUCCESSFUL All pins were set successfully.
> + * @retval RTEMS_INVALID_ID At least one pin number is invalid.
> + * @retval RTEMS_NOT_CONFIGURED At least one of the received pins
> + *                              is not configured as a digital output.
> + * @retval RTEMS_UNSATISFIED Could not set the GPIO pins.
> + */
> +extern rtems_status_code rtems_gpio_multi_set(
> +  uint32_t *pin_numbers,
> +  uint32_t pin_count
> +);
> +
> +/**
> + * @brief Sets multiple output GPIO pins with the logical low.
> + *
> + * @param[in] pin_numbers Array with the GPIO pin numbers to clear.
> + * @param[in] count Number of GPIO pins to clear.
> + *
> + * @retval RTEMS_SUCCESSFUL All pins were cleared successfully.
> + * @retval RTEMS_INVALID_ID At least one pin number is invalid.
> + * @retval RTEMS_NOT_CONFIGURED At least one of the received pins
> + *                              is not configured as a digital output.
> + * @retval RTEMS_UNSATISFIED Could not clear the GPIO pins.
> + */
> +extern rtems_status_code rtems_gpio_multi_clear(
> +  uint32_t *pin_numbers,
> +  uint32_t pin_count
> +);
> +
> +/**
> + * @brief Returns the value (level) of multiple GPIO input pins.
> + *
> + * @param[in] pin_numbers Array with the GPIO pin numbers to read.
> + * @param[in] count Number of GPIO pins to read.
> + *
> + * @retval Bitmask with the values of the corresponding pins.
> + *         0 for logical low and 1 for logical high.
> + * @retval 0xDEADBEEF Could not read at least one pin level.
> + */
> +extern uint32_t rtems_gpio_multi_read(
> +  uint32_t *pin_numbers,
> +  uint32_t pin_count
> +);
> +
> +/**
> + * @brief Sets an output GPIO pin with the logical high.
> + *
> + * @param[in] pin_number GPIO pin number.
> + *
> + * @retval RTEMS_SUCCESSFUL Pin was set successfully.
> + * @retval RTEMS_INVALID_ID Pin number is invalid.
> + * @retval RTEMS_NOT_CONFIGURED The received pin is not configured
> + *                              as a digital output.
> + * @retval RTEMS_UNSATISFIED Could not set the GPIO pin.
> + */
> +extern rtems_status_code rtems_gpio_set(uint32_t pin_number);
> +
> +/**
> + * @brief Sets an output GPIO pin with the logical low.
> + *
> + * @param[in] pin_number GPIO pin number.
> + *
> + * @retval RTEMS_SUCCESSFUL Pin was cleared successfully.
> + * @retval RTEMS_INVALID_ID Pin number is invalid.
> + * @retval RTEMS_NOT_CONFIGURED The received pin is not configured
> + *                              as a digital output.
> + * @retval RTEMS_UNSATISFIED Could not clear the GPIO pin.
> + */
> +extern rtems_status_code rtems_gpio_clear(uint32_t pin_number);
> +
> +/**
> + * @brief Returns the value (level) of a GPIO input pin.
> + *
> + * @param[in] pin_number GPIO pin number.
> + *
> + * @retval The function returns 0 or 1 depending on the pin current
> + *         logical value.
> + * @retval -1 Pin number is invalid, or not a digital input pin.
> + */
> +extern uint8_t rtems_gpio_get_value(uint32_t pin_number);
>
extern uint32_t rtems_gpio_get_value(uint32_t pin_number);

> +
> +/**
> + * @brief Requests multiple GPIO pin configurations. If the BSP provides
> + *        support for parallel selection each call to this function will
> + *        result in a single call to the GPIO hardware, else each pin
> + *        configuration will be done in individual and sequential calls.
> + *        All pins must belong to the same GPIO bank.
> + *
> + * @param[in] pins Array of rtems_gpio_pin_conf structures filled with
> the pins
> + *                 information and desired configurations. All pins must
> belong
> + *                 to the same GPIO bank.
> + * @param[in] pin_count Number of pin configurations in the @var pins
> array.
> + *
> + * @retval RTEMS_SUCCESSFUL All pins were configured successfully.
> + * @retval RTEMS_INVALID_ID At least one pin number in the @var pins array
> + *                          is invalid.
> + * @retval RTEMS_RESOURCE_IN_USE At least one pin is already being used.
> + * @retval RTEMS_UNSATISFIED Could not satisfy at least one given
> configuration.
> + */
> +extern rtems_status_code rtems_gpio_multi_select(
> +  const rtems_gpio_pin_conf *pins,
> +  uint8_t pin_count
> +);
> +
> +/**
> + * @brief Assigns a certain function to a GPIO pin.
> + *
> + * @param[in] pin_number GPIO pin number.
> + * @param[in] function The new function for the pin.
> + * @param[in] output_enabled If TRUE and @var function is DIGITAL_OUTPUT,
> + *                           then the pin is set with the logical high.
> + *                           Otherwise it is set with logical low.
> + * @param[in] logic_invert Reverses the digital I/O logic for
> DIGITAL_INPUT
> + *                         and DIGITAL_OUTPUT pins.
> + * @param[in] bsp_specific Pointer to a BSP defined structure with
> BSP-specific
> + *                         data. This field is handled by the BSP.
> + *
> + * @retval RTEMS_SUCCESSFUL Pin was configured successfully.
> + * @retval RTEMS_INVALID_ID Pin number is invalid.
> + * @retval RTEMS_RESOURCE_IN_USE The received pin is already being used.
> + * @retval RTEMS_UNSATISFIED Could not assign the GPIO function.
> + * @retval RTEMS_NOT_DEFINED GPIO function not defined, or NOT_USED.
> + */
> +extern rtems_status_code rtems_gpio_request_pin(
> +  uint32_t pin_number,
> +  rtems_gpio_function function,
> +  bool output_enable,
> +  bool logic_invert,
> +  void *bsp_specific
> +);
> +
> +/**
> + * @brief Configures a single GPIO pin pull resistor.
> + *
> + * @param[in] pin_number GPIO pin number.
> + * @param[in] mode The pull resistor mode.
> + *
> + * @retval RTEMS_SUCCESSFUL Pull resistor successfully configured.
> + * @retval RTEMS_INVALID_ID Pin number is invalid.
> + * @retval RTEMS_UNSATISFIED Could not set the pull mode.
> + */
> +extern rtems_status_code rtems_gpio_resistor_mode(
> +  uint32_t pin_number,
> +  rtems_gpio_pull_mode mode
> +);
> +
> +/**
> + * @brief Releases a GPIO pin, making it available to be used again.
> + *
> + * @param[in] pin_number GPIO pin number.
> + *
> + * @retval RTEMS_SUCCESSFUL Pin successfully disabled.
> + * @retval RTEMS_INVALID_ID Pin number is invalid.
> + * @retval * Could not disable an active interrupt on this pin,
> + *           @see rtems_gpio_disable_interrupt().
> + */
> +extern rtems_status_code rtems_gpio_release_pin(uint32_t pin_number);
> +
> +/**
> + * @brief Releases a GPIO pin, making it available to be used again.
> + *
> + * @param[in] conf GPIO pin configuration to be released.
> + *
> + * @retval RTEMS_SUCCESSFUL Pin successfully disabled.
> + * @retval RTEMS_UNSATISFIED Pin configuration is NULL.
> + * @retval * @see rtems_gpio_release_pin().
> + */
> +extern rtems_status_code rtems_gpio_release_configuration(
> +  const rtems_gpio_pin_conf *conf
> +);
> +
> +/**
> + * @brief Releases multiple GPIO pins, making them available to be used
> again.
> + *
> + * @param[in] pins Array of rtems_gpio_pin_conf structures.
> + * @param[in] pin_count Number of pin configurations in the @var pins
> array.
> + *
> + * @retval RTEMS_SUCCESSFUL Pins successfully disabled.
> + * @retval RTEMS_UNSATISFIED @var pins array is NULL.
> + * @retval * @see rtems_gpio_release_pin().
> + */
> +extern rtems_status_code rtems_gpio_release_multiple_pins(
> +  const rtems_gpio_pin_conf *pins,
> +  uint32_t pin_count
> +);
> +
> +/**
> + * @brief Releases a GPIO pin group, making the pins used available to be
> + *        repurposed.
> + *
> + * @param[in] conf GPIO pin configuration to be released.
> + *
> + * @retval RTEMS_SUCCESSFUL Pins successfully disabled.
> + * @retval * @see rtems_gpio_release_pin(), @see rtems_semaphore_delete()
> or
> + *           @see rtems_semaphore_flush().
> + */
> +extern rtems_status_code rtems_gpio_release_pin_group(
> +  rtems_gpio_group *group
> +);
> +
> +/**
> + * @brief Attaches a debouncing function to a given pin/switch.
> + *        Debouncing is done by requiring a certain number of clock ticks
> to
> + *        pass between interrupts. Any interrupt fired too close to the
> last
> + *        will be ignored as it is probably the result of an involuntary
> + *        switch/button bounce after being released.
> + *
> + * @param[in] pin_number GPIO pin number.
> + * @param[in] ticks Minimum number of clock ticks that must pass between
> + *                  interrupts so it can be considered a legitimate
> + *                  interrupt.
> + *
> + * @retval RTEMS_SUCCESSFUL Debounce function successfully attached to
> the pin.
> + * @retval RTEMS_INVALID_ID Pin number is invalid.
> + * @retval RTEMS_NOT_CONFIGURED The current pin is not configured as a
> digital
> + *                              input, hence it can not be connected to a
> switch,
> + *                              or interrupts are not enabled for this
> pin.
> + */
> +extern rtems_status_code rtems_gpio_debounce_switch(
> +  uint32_t pin_number,
> +  int ticks
> +);
> +
> +/**
> + * @brief Connects a new user-defined interrupt handler to a given pin.
> + *
> + * @param[in] pin_number GPIO pin number.
> + * @param[in] handler Pointer to a function that will be called every time
> + *                    the enabled interrupt for the given pin is
> generated.
> + *                    This function must return information about its
> + *                    handled/unhandled state.
> + * @param[in] arg Void pointer to the arguments of the user-defined
> handler.
> + *
> + * @retval RTEMS_SUCCESSFUL Handler successfully connected to this pin.
> + * @retval RTEMS_NO_MEMORY Could not connect more user-defined handlers to
> + *                         the given pin.
> + * @retval RTEMS_NOT_CONFIGURED The given pin has no interrupt configured.
> + * @retval RTEMS_INVALID_ID Pin number is invalid.
> + * @retval RTEMS_TOO_MANY The pin's current handler is set as unique.
> + * @retval RTEMS_RESOURCE_IN_USE The current user-defined handler for
> this pin
> + *                               is unique.
> + */
> +extern rtems_status_code rtems_gpio_interrupt_handler_install(
> +  uint32_t pin_number,
> +  rtems_gpio_irq_state (*handler) (void *arg),
> +  void *arg
> +);
> +
> +/**
> + * @brief Enables interrupts to be generated on a given GPIO pin.
> + *        When fired that interrupt will call the given handler.
> + *
> + * @param[in] pin_number GPIO pin number.
> + * @param[in] interrupt Type of interrupt to enable for the pin.
> + * @param[in] flag Defines the uniqueness of the interrupt handler for
> the pin.
> + * @param[in] threaded_handling Defines if the handler should be called
> from a
> + *                              thread/task or from normal ISR contex.
> + * @param[in] handler Pointer to a function that will be called every time
> + *                    @var interrupt is generated. This function must
> return
> + *                    information about its handled/unhandled state.
> + * @param[in] arg Void pointer to the arguments of the user-defined
> handler.
> + *
> + * @retval RTEMS_SUCCESSFUL Interrupt successfully enabled for this pin.
> + * @retval RTEMS_UNSATISFIED Could not install the GPIO ISR, create/start
> + *                           the handler task, or enable the interrupt
> + *                           on the pin.
> + * @retval RTEMS_INVALID_ID Pin number is invalid.
> + * @retval RTEMS_NOT_CONFIGURED The received pin is not configured
> + *                              as a digital input, the pin is on a
> + *                              pin grouping.
> + * @retval RTEMS_RESOURCE_IN_USE The pin already has an enabled interrupt,
> + *                               or the handler threading policy does not
> match
> + *                               the bank's policy.
> + * @retval RTEMS_NO_MEMORY Could not store the pin's interrupt
> configuration.
> + */
> +extern rtems_status_code rtems_gpio_enable_interrupt(
> +  uint32_t pin_number,
> +  rtems_gpio_interrupt interrupt,
> +  rtems_gpio_handler_flag flag,
> +  bool threaded_handling,
> +  rtems_gpio_irq_state (*handler) (void *arg),
> +  void *arg
> +);
> +
> +/**
> + * @brief Disconnects an user-defined interrupt handler from the given
> pin.
> + *        If in the end there are no more user-defined handlers connected
> + *        to the pin, interrupts are disabled on the given pin.
> + *
> + * @param[in] pin_number GPIO pin number.
> + * @param[in] handler Pointer to the user-defined handler
> + * @param[in] arg Void pointer to the arguments of the user-defined
> handler.
> + *
> + * @retval RTEMS_SUCCESSFUL Handler successfully disconnected from this
> pin.
> + * @retval RTEMS_INVALID_ID Pin number is invalid.
> + * @retval RTEMS_NOT_CONFIGURED Pin has no active interrupts.
> + * @retval * @see rtems_gpio_disable_interrupt()
> + */
> +extern rtems_status_code rtems_gpio_interrupt_handler_remove(
> +  uint32_t pin_number,
> +  rtems_gpio_irq_state (*handler) (void *arg),
> +  void *arg
> +);
> +
> +/**
> + * @brief Stops interrupts from being generated on a given GPIO pin
> + *        and removes the corresponding handler.
> + *
> + * @param[in] pin_number GPIO pin number.
> + *
> + * @retval RTEMS_SUCCESSFUL Interrupt successfully disabled for this pin.
> + * @retval RTEMS_INVALID_ID Pin number is invalid.
> + * @retval RTEMS_NOT_CONFIGURED Pin has no active interrupts.
> + * @retval RTEMS_UNSATISFIED Could not remove the current interrupt
> handler,
> + *                           could not recognize the current active
> interrupt
> + *                           on this pin or could not disable interrupts
> on
> + *                           this pin.
> + */
> +extern rtems_status_code rtems_gpio_disable_interrupt(uint32_t
> pin_number);
> +
> +/**
> + * @brief Sets multiple output GPIO pins with the logical high.
> + *        This must be implemented by each BSP.
> + *
> + * @param[in] bank GPIO bank number.
> + * @param[in] bitmask Bitmask of GPIO pins to set in the given bank.
> + *
> + * @retval RTEMS_SUCCESSFUL All pins were set successfully.
> + * @retval RTEMS_UNSATISFIED Could not set at least one of the pins.
> + */
> +extern rtems_status_code rtems_gpio_bsp_multi_set(
> +  uint32_t bank,
> +  uint32_t bitmask
> +);
> +
> +/**
> + * @brief Sets multiple output GPIO pins with the logical low.
> + *        This must be implemented by each BSP.
> + *
> + * @param[in] bank GPIO bank number.
> + * @param[in] bitmask Bitmask of GPIO pins to clear in the given bank.
> + *
> + * @retval RTEMS_SUCCESSFUL All pins were cleared successfully.
> + * @retval RTEMS_UNSATISFIED Could not clear at least one of the pins.
> + */
> +extern rtems_status_code rtems_gpio_bsp_multi_clear(
> +  uint32_t bank,
> +  uint32_t bitmask
> +);
> +
> +/**
> + * @brief Returns the value (level) of multiple GPIO input pins.
> + *        This must be implemented by each BSP.
> + *
> + * @param[in] bank GPIO bank number.
> + * @param[in] bitmask Bitmask of GPIO pins to read in the given bank.
> + *
> + * @retval The function must return a bitmask with the values of the
> + *         corresponding pins. 0 for logical low and 1 for logical high.
> + * @retval 0xDEADBEEF Could not read at least one pin level.
> + */
> +extern uint32_t rtems_gpio_bsp_multi_read(uint32_t bank, uint32_t
> bitmask);
> +
> +/**
> + * @brief Performs a BSP specific operation on a group of pins.
> + *        The implementation for this function may be omitted if the
> target
> + *        does not support the feature, by returning RTEMS_NOT_DEFINED.
> + *
> + * @param[in] bank GPIO bank number.
> + * @param[in] bitmask Bitmask of GPIO pins to clear in the given bank.
> + *
> + * @retval RTEMS_SUCCESSFUL All pins were cleared successfully.
> + * @retval RTEMS_NOT_DEFINED The BSP does not support BSP specific
> operations
> + *                           for groups.
> + * @retval RTEMS_UNSATISFIED Could not clear at least one of the pins.
> + */
> +extern rtems_status_code rtems_gpio_bsp_specific_group_operation(
> +  uint32_t bank,
> +  uint32_t *pins,
> +  uint32_t pin_count,
> +  void *arg
> +);
> +
> +/**
> + * @brief Assigns GPIO functions to all the given pins in a single
> register
> + *        operation.
> + *        The implementation for this function may be omitted if the
> target
> + *        does not support the feature, by returning RTEMS_NOT_DEFINED.
> + *
> + * @param[in] pins Array of rtems_gpio_multiple_pin_select structures
> filled
> + *                 with the pins desired functions. All pins belong to the
> + *                 same select bank.
> + * @param[in] pin_count Number of pin configurations in the @var pins
> array.
> + * @param[in] select_bank Select bank number of the received pins.
> + *
> + * @retval RTEMS_SUCCESSFUL Functions were assigned successfully.
> + * @retval RTEMS_NOT_DEFINED The BSP does not support multiple pin
> function
> + *                           assignment.
> + * @retval RTEMS_UNSATISFIED Could not assign the functions to the pins.
> + */
> +extern rtems_status_code rtems_gpio_bsp_multi_select(
> +  rtems_gpio_multiple_pin_select *pins,
> +  uint32_t pin_count,
> +  uint32_t select_bank
> +);
> +
> +/**
> + * @brief Sets an output GPIO pin with the logical high.
> + *        This must be implemented by each BSP.
> + *
> + * @param[in] bank GPIO bank number.
> + * @param[in] pin GPIO pin number within the given bank.
> + *
> + * @retval RTEMS_SUCCESSFUL Pin was set successfully.
> + * @retval RTEMS_UNSATISFIED Could not set the given pin.
> + */
> +extern rtems_status_code rtems_gpio_bsp_set(uint32_t bank, uint32_t pin);
> +
> +/**
> + * @brief Sets an output GPIO pin with the logical low.
> + *        This must be implemented by each BSP.
> + *
> + * @param[in] bank GPIO bank number.
> + * @param[in] pin GPIO pin number within the given bank.
> + *
> + * @retval RTEMS_SUCCESSFUL Pin was cleared successfully.
> + * @retval RTEMS_UNSATISFIED Could not clear the given pin.
> + */
> +extern rtems_status_code rtems_gpio_bsp_clear(uint32_t bank, uint32_t
> pin);
> +
> +/**
> + * @brief Returns the value (level) of a GPIO input pin.
> + *        This must be implemented by each BSP.
> + *
> + * @param[in] bank GPIO bank number.
> + * @param[in] pin GPIO pin number within the given bank.
> + *
> + * @retval The function must return 0 or 1 depending on the pin current
> + *         logical value.
> + * @retval -1 Could not read the pin level.
> + */
> +extern uint8_t rtems_gpio_bsp_get_value(uint32_t bank, uint32_t pin);
>
extern uint32_t rtems_gpio_bsp_get_value(uint32_t bank, uint32_t pin);

> +
> +/**
> + * @brief Assigns the digital input function to the given pin.
> + *        This must be implemented by each BSP.
> + *
> + * @param[in] bank GPIO bank number.
> + * @param[in] pin GPIO pin number within the given bank.
> + * @param[in] bsp_specific Pointer to a BSP defined structure with
> BSP-specific
> + *                         data.
> + *
> + * @retval RTEMS_SUCCESSFUL Function was assigned successfully.
> + * @retval RTEMS_UNSATISFIED Could not assign the function to the pin.
> + */
> +extern rtems_status_code rtems_gpio_bsp_select_input(
> +  uint32_t bank,
> +  uint32_t pin,
> +  void *bsp_specific
> +);
> +
> +/**
> + * @brief Assigns the digital output function to the given pin.
> + *        This must be implemented by each BSP.
> + *
> + * @param[in] bank GPIO bank number.
> + * @param[in] pin GPIO pin number within the given bank.
> + * @param[in] bsp_specific Pointer to a BSP defined structure with
> BSP-specific
> + *                         data.
> + *
> + * @retval RTEMS_SUCCESSFUL Function was assigned successfully.
> + * @retval RTEMS_UNSATISFIED Could not assign the function to the pin.
> + */
> +extern rtems_status_code rtems_gpio_bsp_select_output(
> +  uint32_t bank,
> +  uint32_t pin,
> +  void *bsp_specific
> +);
> +
> +/**
> + * @brief Assigns a BSP specific function to the given pin.
> + *        This must be implemented by each BSP.
> + *
> + * @param[in] bank GPIO bank number.
> + * @param[in] pin GPIO pin number within the given bank.
> + * @param[in] function BSP defined GPIO function.
> + * @param[in] pin_data Pointer to a BSP defined structure with
> BSP-specific
> + *                     data.
> + *
> + * @retval RTEMS_SUCCESSFUL Function was assigned successfully.
> + * @retval RTEMS_UNSATISFIED Could not assign the function to the pin.
> + */
> +extern rtems_status_code rtems_bsp_select_specific_io(
> +  uint32_t bank,
> +  uint32_t pin,
> +  uint32_t function,
> +  void *pin_data
> +);
> +
> +/**
> + * @brief Configures a single GPIO pin pull resistor.
> + *        This must be implemented by each BSP.
> + *
> + * @param[in] bank GPIO bank number.
> + * @param[in] pin GPIO pin number within the given bank.
> + * @param[in] mode The pull resistor mode.
> + *
> + * @retval RTEMS_SUCCESSFUL Pull resistor successfully configured.
> + * @retval RTEMS_UNSATISFIED Could not set the pull mode.
> + */
> +extern rtems_status_code rtems_gpio_bsp_set_resistor_mode(
> +  uint32_t bank,
> +  uint32_t pin,
> +  rtems_gpio_pull_mode mode
> +);
> +
> +/**
> + * @brief Reads and returns a vector/bank interrupt event line.
> + *        The bitmask should indicate with a 1 if the corresponding pin
> + *        as a pending interrupt, or 0 if otherwise. The function
> + *        should clear the interrupt event line before returning.
> + *        This must be implemented by each BSP.
> + *
> + * @param[in] vector GPIO vector/bank.
> + *
> + * @retval Bitmask (max 32-bit) representing a GPIO bank, where a bit set
> + *         indicates an active interrupt on that pin.
> + */
> +extern uint32_t rtems_gpio_bsp_interrupt_line(rtems_vector_number vector);
> +
> +/**
> + * @brief Calculates a vector number for a given GPIO bank.
> + *        This must be implemented by each BSP.
> + *
> + * @param[in] bank GPIO bank number.
> + *
> + * @retval The corresponding rtems_vector_number.
> + */
> +extern rtems_vector_number rtems_gpio_bsp_get_vector(uint32_t bank);
> +
> +/**
> + * @brief Enables interrupts to be generated on a given GPIO pin.
> + *        This must be implemented by each BSP.
> + *
> + * @param[in] bank GPIO bank number.
> + * @param[in] pin GPIO pin number within the given bank.
> + * @param[in] interrupt Type of interrupt to enable for the pin.
> + *
> + * @retval RTEMS_SUCCESSFUL Interrupt successfully enabled for this pin.
> + * @retval RTEMS_UNSATISFIED Could not enable the interrupt on the pin.
> + */
> +extern rtems_status_code rtems_bsp_enable_interrupt(
> +  uint32_t bank,
> +  uint32_t pin,
> +  rtems_gpio_interrupt interrupt
> +);
> +
> +/**
> + * @brief Stops interrupts from being generated on a given GPIO pin.
> + *        This must be implemented by each BSP.
> + *
> + * @param[in] bank GPIO bank number.
> + * @param[in] pin GPIO pin number within the given bank.
> + * @param[in] active_interrupt Interrupt type currently active on this
> pin.
> + *
> + * @retval RTEMS_SUCCESSFUL Interrupt successfully disabled for this pin.
> + * @retval RTEMS_UNSATISFIED Could not disable interrupts on this pin.
> + */
> +extern rtems_status_code rtems_bsp_disable_interrupt(
> +  uint32_t bank,
> +  uint32_t pin,
> +  rtems_gpio_interrupt interrupt
> +);
> +
> +/** @} */
> +
> +#ifdef __cplusplus
> +}
> +#endif /* __cplusplus */
> +
> +#endif /* LIBBSP_SHARED_GPIO_H */
> --
> 2.3.6
>
> _______________________________________________
> devel mailing list
> devel at rtems.org
> http://lists.rtems.org/mailman/listinfo/devel
>
-------------- next part --------------
An HTML attachment was scrubbed...
URL: <http://lists.rtems.org/pipermail/devel/attachments/20150813/8150308e/attachment-0001.html>


More information about the devel mailing list