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

André Marques andre.lousa.marques at gmail.com
Mon Jun 22 22:49:04 UTC 2015


Hello Gedare,

first of all thanks for the review. Answers bellow.

On 22-06-2015 16:05, Gedare Bloom wrote:
> (
>
>
> On Mon, Jun 22, 2015 at 8:01 AM, Andre Marques
> <andre.lousa.marques at gmail.com> wrote:
>> ---
>>   c/src/lib/libbsp/Makefile.am           |    3 +-
>>   c/src/lib/libbsp/preinstall.am         |    4 +
>>   c/src/lib/libbsp/shared/gpio.c         | 1083 ++++++++++++++++++++++++++++++++
>>   c/src/lib/libbsp/shared/include/gpio.h |  610 ++++++++++++++++++
>>   4 files changed, 1699 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..12cdb29
>> --- /dev/null
>> +++ b/c/src/lib/libbsp/shared/gpio.c
>> @@ -0,0 +1,1083 @@
>> +/**
>> + * @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/status-checks.h>
>> +#include <bsp/irq-generic.h>
>> +#include <bsp/gpio.h>
>> +
>> +#include <assert.h>
>> +#include <stdlib.h>
>> +
>> +/**
>> + * @brief GPIO API mutex atributes.
> spelling: attributes
>
>> + */
>> +#define MUTEX_ATRIBUTES                         \
> here too.
>
>> +  ( RTEMS_LOCAL                                 \
>> +    | RTEMS_PRIORITY                            \
>> +    | RTEMS_BINARY_SEMAPHORE                    \
>> +    | RTEMS_INHERIT_PRIORITY                    \
>> +    | RTEMS_NO_PRIORITY_CEILING                 \
>> +    )
>> +
>> +#define AQUIRE_LOCK(m) assert( rtems_semaphore_obtain(m,                \
> spelling: ACQUIRE
>
>> +                                                      RTEMS_WAIT,       \
>> +                                                      RTEMS_NO_TIMEOUT  \
>> +                                                      ) == RTEMS_SUCCESSFUL )
>> +
>> +#define RELEASE_LOCK(m) assert( rtems_semaphore_release(m) == RTEMS_SUCCESSFUL )
>> +
>> +/*Encapsulates relevant data for a GPIO interrupt handler. */
> Add Doxygen for all of these structs
>
>> +typedef struct _gpio_handler_list
>> +{
>> +  struct _gpio_handler_list *next_isr;
> Consider using an RTEMS chain (doubly-linked list) here. It would save
> on some list-manipulation code, and force you to use readable
> functions that already exist in the rtems namespace. If you want one
> list per pin, you can embed an rtems_chain_control in each gpio_pin.

Yes that makes sense. Will check that.

>> +
>> +  /* User-defined ISR routine. */
>> +  rtems_gpio_irq_state (*handler) (void *arg);
>> +
>> +  /* User-defined arguments for the ISR routine. */
>> +  void *arg;
>> +} gpio_handler_list;
>> +
>> +/* Encapsulates relevant data about a GPIO pin. */
>> +typedef struct
>> +{
>> +  uint32_t bank_number;
>> +  uint32_t pin_number;
>> +
>> +  rtems_gpio_function pin_function;
>> +
>> +  /* Type of event which will trigger an interrupt. */
>> +  rtems_gpio_interrupt enabled_interrupt;
> enabled_interrupt brings to mind isr enable/disable, if this field is
> more than a bool, then a more descriptive name should be used.

Yes this field can have several values, as it reflects the currently 
active interrupt (defined on the rtems_gpio_interrupt enum) on a pin. 
Maybe it can become current_active_interrupt or cur_active_interrupt.

>> +
>> +  /* Id of the task that will be calling the user-defined ISR handlers
>> +   * for this pin. */
>> +  rtems_id task_id;
> perhaps 'handler_task_id' can help readability

agreed.

>> +
>> +  /* ISR shared flag. */
>> +  rtems_gpio_handler_flag handler_flag;
>> +
>> +  /* Linked list of interrupt handlers. */
>> +  gpio_handler_list *handler_list;
>> +
>> +  /* GPIO input (pull resistor) pin mode. */
>> +  rtems_gpio_pull_mode resistor_mode;
>> +
>> +  /* If true inverts digital in/out logic. */
>> +  int logic_invert;
> bool instead of int?

oops.

>> +
>> +  /* Switch-deboucing information. */
>> +  int debouncing_tick_count;
>> +  rtems_interval last_isr_tick;
>> +} gpio_pin;
>> +
>> +static gpio_pin** gpio_pin_state;
>> +static Atomic_Flag init_flag = ATOMIC_INITIALIZER_FLAG;
>> +static uint32_t gpio_count;
>> +static uint32_t bank_count;
>> +static uint32_t pins_per_bank;
>> +static uint32_t odd_bank_pins;
>> +static uint32_t* interrupt_counter;
>> +static rtems_id* bank_lock;
> This many global (file-scope) variables indicates poor modularity in the source.
>
>> +
>> +#define BANK_NUMBER(pin_number) pin_number / pins_per_bank
>> +#define PIN_NUMBER(pin_number) pin_number % pins_per_bank
>> +
>> +static int debounce_switch(gpio_pin* gpio)
>> +{
>> +  rtems_interval time;
>> +
>> +  time = rtems_clock_get_ticks_since_boot();
>> +
>> +  /* If not enough time has elapsed since last interrupt. */
>> +  if ( (time - gpio->last_isr_tick) < gpio->debouncing_tick_count ) {
>> +    return -1;
>> +  }
>> +
>> +  gpio->last_isr_tick = time;
>> +
>> +  return 0;
>> +}
>> +
>> +static rtems_task generic_handler_task(rtems_task_argument arg)
>> +{
>> +  gpio_handler_list *handler_list;
>> +  rtems_event_set out;
>> +  gpio_pin* gpio;
> put the * next to gpio.

Ok, will apply to all pointers then.
>
>> +  uint32_t bank;
>> +  int handled_count;
>> +  int rv;
>> +
>> +  gpio = (gpio_pin*) arg;
>> +
>> +  bank = gpio->bank_number;
> Validate args for errors.

These tasks are only created by the rtems_gpio_enable_interrupt() 
function, and all parameters are validated before creating/starting the 
task. Should they be validated again here?

>> +
>> +  while ( true ) {
>> +    handled_count = 0;
>> +
>> +    /* Wait for interrupt event. This is sent by the bank's generic_isr handler. */
>> +    rtems_event_receive(RTEMS_EVENT_1, RTEMS_EVENT_ALL | RTEMS_WAIT,
>> +                        RTEMS_NO_TIMEOUT,
>> +                        &out);
> When you split across multiple lines, put one argument per line and no
> args on first/last line, e.g.
> rtems_event_receive(
>      RTEMS_EVENT_1,
>      RTEMS_EVENT_ALL | RTEMS_WAIT,
>      RTEMS_NO_TIMEOUT,
>      &out
> );

Noted.

>> +
>> +    AQUIRE_LOCK(bank_lock[bank]);
> What is the lock protecting?

Since the rtems_gpio_disable_interrupt() kills this task when the 
interrupt is disabled, having the lock here (which 
rtems_gpio_disable_interrupt() must also acquire before doing anything) 
ensures that any interrupt disable call occurring during an interrupt 
process will have to wait while the on-going interrupt is processed. 
Otherwise the handler could leave the system on an inconsistent state. I 
shall make this clear with a comment.

>
>> +
>> +    /* If this pin has the debouncing function attached, call it. */
>> +    if ( gpio->debouncing_tick_count > 0 ) {
>> +      rv = debounce_switch(gpio);
>> +
>> +      /* If the handler call was caused by a switch bounce, ignores and move on. */
>> +      if ( rv < 0 ) {
>> +        RELEASE_LOCK(bank_lock[bank]);
>> +
>> +        continue;
>> +      }
>> +
>> +      /* Record the current clock tick. */
>> +      gpio->last_isr_tick = rtems_clock_get_ticks_since_boot();
> debounce_switch() already did this?

You are right, debounce_switch() does update the last_isr_tick field. 
Will remove it from here.

>> +    }
>> +
>> +    handler_list = gpio->handler_list;
>> +
>> +    /* Iterate the ISR list. */
>> +    while ( handler_list != NULL ) {
>> +      if ( (handler_list->handler)(handler_list->arg) == IRQ_HANDLED ) {
>> +        ++handled_count;
>> +      }
>> +
>> +      handler_list = handler_list->next_isr;
>> +    }
>> +
>> +    /* If no handler assumed the interrupt, treat it as a spurious interrupt. */
> Wrong word, "assumed". Not sure what you mean to say though. Maybe
> "consumed"? Anyway, you can say "handled".

By assumed I wanted to say that no device assumed the interrupt (since 
each handler should be bound to a different device on the shared IRQ 
line). It may become "If the interrupt was not handled, ..."

>> +    if ( handled_count == 0 ) {
>> +      bsp_interrupt_handler_default(rtems_bsp_gpio_get_vector(bank));
>> +    }
>> +
>> +    RELEASE_LOCK(bank_lock[bank]);
>> +  }
>> +}
>> +
>> +static void generic_isr(void* arg)
>> +{
>> +  rtems_vector_number vector;
>> +  uint32_t event_status;
>> +  uint32_t bank_pin_count;
>> +  gpio_pin *gpio;
>> +  uint32_t bank_number;
>> +  int i;
>> +
>> +  gpio = (gpio_pin *) arg;
>> +
>> +  /* Get the bank/vector number of a pin (e.g.: 0) from this bank. */
>> +  bank_number = gpio[0].bank_number;
>> +
> Again, validate args. Why is it gpio[0] here? And not above?

As with generic_handler_task, these ISRs are only created by 
rtems_gpio_enable_interrupt() and rtems_gpio_disable_interrupt(), which 
validate the arguments sent here. Should they be re-validated here?

As for the gpio[0], the gpio pointer points to a whole gpio bank, so 
gpio[0] is the first pin of this bank. Since all pins in this bank have 
the same bank number, I can use any pin from it to obtain the bank 
number that this ISR is listening. Maybe gpio should be renamed to 
gpio_bank.

>
>> +  vector = rtems_bsp_gpio_get_vector(bank_number);
>> +
>> +  /* If the current bank is an odd last bank (i.e.: not completely filled). */
>> +  if ( odd_bank_pins > 0 &&  bank_number == bank_count - 1 ) {
>> +    bank_pin_count = odd_bank_pins;
>> +  }
>> +  else {
>> +    bank_pin_count = pins_per_bank;
>> +  }
> This can be simplified by
> if (bank_number == bank_count - 1)
>    bank_pin_count = last_bank_pins; /* or odd_bank_pins */
> else
>    bank_pin_count - pins_per_bank;
>
> I prefer "last_bank_pins" myself. odd_bank_pins is strange to me, is
> it a standard term?

Not that I am aware :). "last_bank_pins" do seem better.
>
> Is it the case that only the last bank is ever going to have a number
> of pins different from the others? Or should there instead just be an
> array of pins_per_bank[bank_count]?

The "last_bank_pins" is here to account for potentially weird platforms 
(or a desired GPIO layout) with an uneven number of GPIO pins, such that 
it is impossible to have the same number of pins on all banks. In that 
case those "odd" pins would end up on a special last bank that has less 
pins than the rest. i.e.: a platform with 54 GPIOs (such as the PI), 
since each bank is set to have 32 pins, the last one cannot be filled.

>> +
>> +  /* Prevents more interrupts from being generated on GPIO. */
>> +  bsp_interrupt_vector_disable(vector);
>> +
>> +  /* Ensure that interrupts are disabled in this vector, before checking
>> +   * the interrupt line. */
>> +  RTEMS_COMPILER_MEMORY_BARRIER();
> Manually inserting memory barriers is hackish. If we need this after
> bsp_interrupt_vector_disable(), then you might consider proposing we
> add it directly there.

This function seems to be bsp defined also (from irq-generic), so it is 
a matter of doing it there. From a quick check the BB does it at the end 
of bsp_interrupt_vector_disable(), the Pi does not. So not sure if that 
is enforced or it is just the Pi implementation that forgot it. Will 
move it out from here.

>> +
>> +  /* Obtains a 32-bit bitmask, with the pins currently reporting interrupts
>> +   * signaled with 1. */
>> +  event_status = rtems_bsp_gpio_interrupt_line(vector);
>> +
> Is it ever the case there are more than 32 pins in a bank? (If not,
> this should be assert()ed somewhere in the code.)

There may be bigger (up to 64?). But yes it would help to define a max 
pin number for a single bank, and have that asserted. Would it be best 
to set a max pin number per bank of 64 pins, and change this to a 64-bit 
bitmask to account for any number in-between? The reasoning behind the 
pin bitmask is that most platforms should be able to directly (or after 
some bitwise operations) write it to the registers.

>> +  /* Iterates through the bitmask and calls the corresponding handler
>> +   * for active interrupts. */
>> +  for ( i = 0; i < bank_pin_count; ++i ) {
>> +    /* If active, wake the corresponding pin's ISR task. */
>> +    if ( event_status & (1 << i) ) {
>> +      rtems_event_send(gpio[i].task_id, RTEMS_EVENT_1);
> It may improve readability to #define something as RTEMS_EVENT_1. like
> #define GPIO_INTERRUPT_ACTIVE RTEMS_EVENT_1.

maybe GPIO_INTERRUPT_EVENT?

>
>> +    }
>> +  }
>> +
>> +  /* Clear all active events. */
>> +  rtems_bsp_gpio_clear_interrupt_line(vector, event_status);
>> +
>> +  /* Ensure that the interrupt line is cleared before re-activating
>> +   * the interrupts on this vector. */
>> +  RTEMS_COMPILER_MEMORY_BARRIER();
> Again, this should be done in bsp_interrupt_vector_enable?
>
>> +
>> +  bsp_interrupt_vector_enable(vector);
>> +}
>> +
>> +static uint32_t get_pin_bitmask(uint32_t count, va_list args, uint32_t* bank_number, rtems_status_code* sc)
> Line length > 80 chars
>
> It is probably better (more common in RTEMS) to return the status code
> directly and the pin_bitmask through an argument side-effect.
> Especially since this function already returns bank_number through the
> side effect, this makes a little more sense.

Agreed.

>
> You might consider splitting this function into two different ones:
> get_bank_number()
> get_pin_bitmask()
> Splitting it will reduce the complexity.
>
> Please document any use of variadic arguments. A function with both va
> args and multiple return values is already complex to understand
> without even reading its code...
>
> Is it better to pass a va_list here, or an array of integer pin
> numbers? (When all variadic arguments have the same type, the question
> is worth asking.)

An integer array could be used (that is how it was before), the 
reasoning behind the variadic was an attempt to ease the application 
code, namely on a possible interactive usage (i.e.: direct shell 
command). But I am realising that maybe the array option is generally 
better (also a shell command could do a variadic wrapper around this).

>> +{
>> +  uint32_t bank;
>> +  uint32_t pin;
>> +  uint32_t bitmask;
>> +  uint32_t pin_number;
>> +  int i;
>> +
>> +  if ( count < 1 ) {
> equivalent: count == 0.
>
>> +    *sc = RTEMS_UNSATISFIED;
>> +
>> +    return 0;
> And then you can just return RTEMS_UNSATISFIED without touching the bitmask.
>
>> +  }
>> +
>> +  bitmask = 0;
>> +
>> +  for ( i = 0; i < count; ++i ) {
>> +    pin_number = va_arg(args, uint32_t);
>> +
>> +    if ( pin_number < 0 || pin_number >= gpio_count ) {
>> +      *sc = RTEMS_INVALID_ID;
>> +
>> +      return 0;
>> +    }
>> +
>> +    bank = BANK_NUMBER(pin_number);
> If you already know the bank_number, you can replace this with
> if(BANK_NUMBER(pin_number) != bank_number) return RTEMS_UNSATISFIED;

I never know the bank number until the first iteration ( the i == 0 case 
bellow).

>> +    pin = PIN_NUMBER(pin_number);
>> +
>> +    if ( i == 0 ) {
>> +      *bank_number = bank;
>> +
>> +      AQUIRE_LOCK(bank_lock[bank]);
>> +    }
>> +    else if ( bank != *bank_number ) {
>> +      *sc = RTEMS_UNSATISFIED;
>> +
>> +      RELEASE_LOCK(bank_lock[*bank_number]);
>> +
>> +      return 0;
>> +    }
>> +
>> +    if ( gpio_pin_state[bank][pin].pin_function != DIGITAL_OUTPUT ) {
>> +      *sc = RTEMS_NOT_CONFIGURED;
>> +
>> +      RELEASE_LOCK(bank_lock[bank]);
>> +
>> +      return 0;
>> +    }
>> +
>> +    bitmask |= (1 << PIN_NUMBER(pin_number));
> pin variable already stores PIN_NUMBER(pin_number).

indeed.

>> +  }
>> +
>> +  *sc = RTEMS_SUCCESSFUL;
>> +
>> +  RELEASE_LOCK(bank_lock[bank]);
>> +
>> +  return bitmask;
>> +}
>> +
>> +rtems_status_code rtems_gpio_initialize(void)
>> +{
>> +  rtems_status_code sc;
>> +  rtems_gpio_layout layout;
>> +  int bank_pins;
>> +  int pin;
>> +  int bank;
>> +  int i;
>> +
>> +  if ( _Atomic_Flag_test_and_set(&init_flag, ATOMIC_ORDER_RELAXED) == true ) {
> Note: More motivation for a public-facing API for our atomic ops:
> https://devel.rtems.org/ticket/2366
>
>> +    return RTEMS_SUCCESSFUL;
>> +  }
>> +
>> +  layout = rtems_bsp_gpio_initialize();
>> +
> Validate return values.
>
>> +  gpio_count = layout.pin_count;
>> +  pins_per_bank = layout.pins_per_bank;
>> +
>> +  bank_count = gpio_count / pins_per_bank;
>> +
>> +  /* Account for remaining pins after filling the last bank. */
>> +  odd_bank_pins = gpio_count % pins_per_bank;
>> +
>> +  if ( odd_bank_pins > 0 ) {
>> +    ++bank_count;
>> +  }
>> +
>> +  /* Create GPIO bank mutexes. */
>> +  bank_lock = (rtems_id*) malloc(bank_count * sizeof(rtems_id));
> Is there any way to get the max bank count at compile-time from the
> BSP? If so we can statically create some of these structures, locks,
> variables, etc. This dynamic memory allocation is troublesome.

It can be done through BSP_OPTs. That would also remove the need for 
rtems_bsp_gpio_initialize().

>> +
>> +  for ( i = 0; i < bank_count; ++i ) {
>> +    sc = rtems_semaphore_create(rtems_build_name('G', 'I', 'N', 'T'), 1, MUTEX_ATRIBUTES, 0, &bank_lock[i]);
> These semaphores need to be accounted for in confdefs.h, but this
> means we need an accurate number for bank_count.
>
>> +
>> +    if ( sc != RTEMS_SUCCESSFUL ) {
>> +      return sc;
>> +    }
>> +  }
>> +
>> +  /* Create GPIO pin state matrix. */
>> +  gpio_pin_state = (gpio_pin**) malloc(bank_count * sizeof(gpio_pin*));
>> +
>> +  for ( i = 0; i < bank_count; ++i ) {
>> +    if ( i == bank_count - 1 ) {
>> +      bank_pins = odd_bank_pins;
>> +    }
>> +    else {
>> +      bank_pins = pins_per_bank;
>> +    }
>> +
>> +    gpio_pin_state[i] = (gpio_pin*) malloc(bank_pins * sizeof(gpio_pin));
>> +  }
>> +
>> +  /* Creates an interrupt counter per pin bank. */
>> +  interrupt_counter = (uint32_t*) calloc(bank_count, sizeof(uint32_t));
>> +
>> +  for ( i = 0; i < gpio_count; ++i ) {
>> +    bank = BANK_NUMBER(i);
>> +    pin = PIN_NUMBER(i);
>> +
>> +    gpio_pin_state[bank][pin].bank_number = bank;
>> +    gpio_pin_state[bank][pin].pin_number = pin;
>> +    gpio_pin_state[bank][pin].pin_function = NOT_USED;
>> +    gpio_pin_state[bank][pin].enabled_interrupt = NONE;
>> +    gpio_pin_state[bank][pin].task_id = RTEMS_ID_NONE;
>> +    gpio_pin_state[bank][pin].handler_list = NULL;
>> +    gpio_pin_state[bank][pin].debouncing_tick_count = 0;
>> +    gpio_pin_state[bank][pin].last_isr_tick = 0;
>> +  }
>> +
>> +  return RTEMS_SUCCESSFUL;
>> +}
>> +
>> +rtems_status_code rtems_gpio_request_conf(rtems_gpio_pin_conf* conf)
>> +{
>> +  rtems_gpio_interrupt_conf* interrupt_conf;
>> +  rtems_status_code sc;
>> +  bool new_request;
>> +  uint32_t bank;
>> +  uint32_t pin;
>> +
>> +  new_request = false;
>> +
>> +  sc = rtems_gpio_request_pin(conf->pin_number, conf->function, conf->output_enabled, conf->logic_invert, conf->bsp_specific);
> line lengths
>
>> +
>> +  if ( sc == RTEMS_SUCCESSFUL ) {
>> +    new_request = true;
>> +  }
>> +  /* If the pin is being used, then this function call is an update call.
>> +   * If not, an error occurred. */
>> +  else if ( sc != RTEMS_RESOURCE_IN_USE ) {
>> +    RTEMS_SYSLOG_ERROR("rtems_gpio_request_pin failed with status code %d\n", sc);
> I don't think this SYSLOG_ERROR is much used, so I recommend avoiding
> it in favor of just returning the error value, and maybe using a debug
> printk if you like.

Yes these are intended as debug prints that add to the return code.

>> +
>> +    return RTEMS_UNSATISFIED;
>> +  }
>> +
>> +  sc = rtems_gpio_resistor_mode(conf->pin_number, conf->pull_mode);
>> +
>> +  if ( sc != RTEMS_SUCCESSFUL ) {
>> +    RTEMS_SYSLOG_ERROR("rtems_gpio_resistor_mode failed with status code %d\n", sc);
>> +
>> +    return RTEMS_UNSATISFIED;
>> +  }
>> +
>> +  interrupt_conf = (rtems_gpio_interrupt_conf*) conf->interrupt;
>> +
>> +  if ( interrupt_conf != NULL ) {
>> +    bank = BANK_NUMBER(conf->pin_number);
>> +    pin = PIN_NUMBER(conf->pin_number);
> Why doesn't the conf store these, anyway?

The API calculates the pin and bank numbers from the "global" pin number 
as a protection mechanism against a change in the GPIO layout. On a 
second thougth, I do not actually see a reason for it to change, unless 
there is an application where I would like to work with banks instead of 
individual pins, and would change the GPIO layout accordingly. But even 
in that case I could just create a separate conf file with those 
specific requirements (and maybe it can allow to define multiple pins 
with the same conf, to form a group that is to be treated as a single 
entity, if that can be a thing?).

One issue that arises with storing the bank and pin numbers directly is 
that it becomes more hardcoded. With a global pin number a bsp can 
define a pin with

#define GPIO_40 40

and use that to refer to that pin. By having to explicitly use the bank 
and pin numbers, I would have two numbers that would be hardcoded (and 
the separate conf file would apply here).

So yes, probably the bank and pin numbers can be directly stored. The 
other API calls can also receive the two numbers, or at least the 
rtems_gpio_request_pin could. If this function (and 
rtems_gpio_request_conf) would return a gpio_pin_id var/struct with the 
bank and pin number combination, the following calls would only use this 
gpio_pin_id, and could even avoid the bank/pin check if this type is opaque.

>
>> +
>> +    AQUIRE_LOCK(bank_lock[bank]);
> And also store its own lock field?

The lock field is per bank. Each conf struct only refer to an individual 
pin.

>
>> +
>> +    if ( interrupt_conf->enabled_interrupt != gpio_pin_state[bank][pin].enabled_interrupt ) {
>> +      if ( new_request == false ) {
>> +        sc = rtems_gpio_disable_interrupt(conf->pin_number);
>> +
>> +        if ( sc != RTEMS_SUCCESSFUL ) {
>> +          RELEASE_LOCK(bank_lock[bank]);
>> +
>> +          RTEMS_SYSLOG_ERROR("rtems_gpio_disable_interrupt failed with status code %d\n", sc);
>> +
>> +          return RTEMS_UNSATISFIED;
>> +        }
>> +      }
>> +
>> +      sc = rtems_gpio_enable_interrupt(conf->pin_number,
>> +                                       interrupt_conf->enabled_interrupt,
>> +                                       interrupt_conf->handler_flag,
>> +                                       interrupt_conf->handler,
>> +                                       interrupt_conf->arg);
> Fix first/last lines.
>
>> +
>> +      if ( sc != RTEMS_SUCCESSFUL ) {
>> +        RELEASE_LOCK(bank_lock[bank]);
>> +
>> +        RTEMS_SYSLOG_ERROR("rtems_gpio_enable_interrupt failed with status code %d\n", sc);
>> +
>> +        return RTEMS_UNSATISFIED;
>> +      }
>> +
>> +    }
>> +
>> +    if ( interrupt_conf->clock_tick_interval != gpio_pin_state[bank][pin].debouncing_tick_count ) {
>> +      gpio_pin_state[bank][pin].debouncing_tick_count = interrupt_conf->clock_tick_interval;
>> +      gpio_pin_state[bank][pin].last_isr_tick = 0;
>> +    }
>> +
>> +    RELEASE_LOCK(bank_lock[bank]);
>> +  }
>> +
>> +  return RTEMS_SUCCESSFUL;
>> +}
>> +
>> +rtems_status_code rtems_gpio_multi_set(uint32_t count, ...)
>> +{
>> +  rtems_status_code sc;
>> +  uint32_t bank;
>> +  uint32_t bitmask;
>> +  va_list ap;
>> +
>> +  va_start(ap, count);
>> +
>> +  bitmask = get_pin_bitmask(count, ap, &bank, &sc);
>> +
>> +  if ( sc != RTEMS_SUCCESSFUL ) {
>> +    RTEMS_SYSLOG_ERROR("error parsing function arguments\n");
>> +
>> +    return sc;
>> +  }
>> +
>> +  va_end(ap);
>> +
>> +  AQUIRE_LOCK(bank_lock[bank]);
>> +
>> +  sc = rtems_bsp_gpio_multi_set(bank, bitmask);
>> +
>> +  RELEASE_LOCK(bank_lock[bank]);
>> +
>> +  return sc;
>> +}
>> +
>> +rtems_status_code rtems_gpio_multi_clear(uint32_t count, ...)
>> +{
>> +  rtems_status_code sc;
>> +  uint32_t bank;
>> +  uint32_t bitmask;
>> +  va_list ap;
>> +
>> +  va_start(ap, count);
>> +
>> +  bitmask = get_pin_bitmask(count, ap, &bank, &sc);
>> +
>> +  if ( sc != RTEMS_SUCCESSFUL ) {
>> +    RTEMS_SYSLOG_ERROR("error parsing function arguments\n");
>> +
>> +    return sc;
>> +  }
>> +
>> +  va_end(ap);
>> +
>> +  AQUIRE_LOCK(bank_lock[bank]);
>> +
>> +  sc = rtems_bsp_gpio_multi_clear(bank, bitmask);
>> +
>> +  RELEASE_LOCK(bank_lock[bank]);
>> +
>> +  return sc;
>> +}
>> +
>> +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 >= gpio_count ) {
>> +    return RTEMS_INVALID_ID;
>> +  }
>> +
>> +  bank = BANK_NUMBER(pin_number);
>> +  pin = PIN_NUMBER(pin_number);
>> +
>> +  AQUIRE_LOCK(bank_lock[bank]);
>> +
>> +  if ( gpio_pin_state[bank][pin].pin_function != DIGITAL_OUTPUT ) {
>> +    RELEASE_LOCK(bank_lock[bank]);
>> +
>> +    RTEMS_SYSLOG_ERROR("Can only set digital output pins\n");
>> +
>> +    return RTEMS_NOT_CONFIGURED;
>> +  }
>> +
>> +  if ( gpio_pin_state[bank][pin].logic_invert ) {
>> +    sc = rtems_bsp_gpio_clear(bank, pin);
>> +  }
>> +  else {
>> +    sc = rtems_bsp_gpio_set(bank, pin);
>> +  }
>> +
>> +  RELEASE_LOCK(bank_lock[bank]);
>> +
>> +  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 >= gpio_count ) {
>> +    return RTEMS_INVALID_ID;
>> +  }
>> +
>> +  bank = BANK_NUMBER(pin_number);
>> +  pin = PIN_NUMBER(pin_number);
>> +
>> +  AQUIRE_LOCK(bank_lock[bank]);
>> +
>> +  if ( gpio_pin_state[bank][pin].pin_function != DIGITAL_OUTPUT ) {
>> +    RELEASE_LOCK(bank_lock[bank]);
>> +
>> +    RTEMS_SYSLOG_ERROR("Can only clear digital output pins\n");
>> +
>> +    return RTEMS_NOT_CONFIGURED;
>> +  }
>> +
>> +  if ( gpio_pin_state[bank][pin].logic_invert ) {
>> +    sc = rtems_bsp_gpio_set(bank, pin);
>> +  }
>> +  else {
>> +    sc = rtems_bsp_gpio_clear(bank, pin);
>> +  }
>> +
>> +  RELEASE_LOCK(bank_lock[bank]);
>> +
>> +  return sc;
>> +}
>> +
>> +int rtems_gpio_get_value(uint32_t pin_number)
>> +{
>> +  uint32_t bank;
>> +  uint32_t pin;
>> +  int rv;
>> +
>> +  if ( pin_number < 0 || pin_number >= gpio_count ) {
>> +    return -1;
>> +  }
>> +
>> +  bank = BANK_NUMBER(pin_number);
>> +  pin = PIN_NUMBER(pin_number);
>> +
>> +  AQUIRE_LOCK(bank_lock[bank]);
>> +
>> +  if ( gpio_pin_state[bank][pin].pin_function != DIGITAL_INPUT) {
>> +    RELEASE_LOCK(bank_lock[bank]);
>> +
>> +    RTEMS_SYSLOG_ERROR("Can only read digital input pins\n");
>> +
>> +    return -1;
>> +  }
>> +
>> +  rv = rtems_bsp_gpio_get_value(bank, pin);
>> +
>> +  if ( gpio_pin_state[bank][pin].logic_invert && rv > 0 ) {
> why rv > 0?

The rtems_bsp_gpio_get_value can return -1 if for some reason it failed 
to get a value. With the rv > 0 condition that would be sent to an 
application through the last return.

>> +    RELEASE_LOCK(bank_lock[bank]);
>> +
>> +    return !rv;
>> +  }
>> +
>> +  RELEASE_LOCK(bank_lock[bank]);
>> +
>> +  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 >= gpio_count ) {
>> +    return RTEMS_INVALID_ID;
>> +  }
>> +
>> +  bank = BANK_NUMBER(pin_number);
>> +  pin = PIN_NUMBER(pin_number);
>> +
>> +  AQUIRE_LOCK(bank_lock[bank]);
>> +
>> +  /* If the pin is already being used returns with an error. */
>> +  if ( gpio_pin_state[bank][pin].pin_function != NOT_USED ) {
>> +    RELEASE_LOCK(bank_lock[bank]);
>> +
>> +    return RTEMS_RESOURCE_IN_USE;
>> +  }
>> +
>> +  switch ( function ) {
>> +    case DIGITAL_INPUT:
>> +      sc = rtems_bsp_gpio_select_input(bank, pin, bsp_specific);
>> +      break;
>> +    case DIGITAL_OUTPUT:
>> +      sc = rtems_bsp_gpio_select_output(bank, pin, bsp_specific);
>> +      break;
>> +    case BSP_SPECIFIC:
>> +      bsp_data = (rtems_gpio_specific_data*) bsp_specific;
>> +
>> +      if ( bsp_data == NULL ) {
>> +        RELEASE_LOCK(bank_lock[bank]);
>> +
>> +        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(bank_lock[bank]);
>> +
>> +      return RTEMS_NOT_DEFINED;
>> +  }
>> +
>> +  if ( sc != RTEMS_SUCCESSFUL ) {
>> +    RELEASE_LOCK(bank_lock[bank]);
>> +
>> +    return sc;
>> +  }
>> +
>> +  /* If the function was successfuly assigned to the pin,
>> +   * record that information on the gpio_pin_state structure. */
>> +  gpio_pin_state[bank][pin].pin_function = function;
>> +  gpio_pin_state[bank][pin].logic_invert = logic_invert;
>> +
>> +  if ( function == DIGITAL_OUTPUT ) {
>> +    if ( output_enabled == true ) {
>> +      sc = rtems_bsp_gpio_set(bank, pin);
> Shouldn't this also check logic_invert?

If the application indicates that this pin is to be enabled upon 
request, it should be enabled (set) regardless of the behavior of the 
next set/clears on that pin (which may be inverted, depending on the 
logic_invert flag). That is how I see it.

>> +    }
>> +    else {
>> +      sc = rtems_bsp_gpio_clear(bank, pin);
>> +    }
>> +  }
>> +
>> +  RELEASE_LOCK(bank_lock[bank]);
>> +
>> +  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 >= gpio_count ) {
>> +    return RTEMS_INVALID_ID;
>> +  }
>> +
>> +  bank = BANK_NUMBER(pin_number);
>> +  pin = PIN_NUMBER(pin_number);
>> +
>> +  AQUIRE_LOCK(bank_lock[bank]);
>> +
>> +  /* 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[bank][pin].resistor_mode == mode  && mode != NO_PULL_RESISTOR ) {
>> +    RELEASE_LOCK(bank_lock[bank]);
>> +
>> +    return RTEMS_SUCCESSFUL;
>> +  }
>> +
>> +  sc = rtems_bsp_gpio_set_resistor_mode(bank, pin, mode);
>> +
>> +  if ( sc != RTEMS_SUCCESSFUL ) {
>> +    RELEASE_LOCK(bank_lock[bank]);
>> +
>> +    return sc;
>> +  }
>> +
>> +  gpio_pin_state[bank][pin].resistor_mode = mode;
>> +
>> +  RELEASE_LOCK(bank_lock[bank]);
>> +
>> +  return RTEMS_SUCCESSFUL;
>> +}
>> +
>> +rtems_status_code rtems_gpio_release_pin(uint32_t pin_number)
>> +{
>> +  rtems_status_code sc;
>> +  gpio_pin* gpio;
>> +  uint32_t bank;
>> +  uint32_t pin;
>> +
>> +  if ( pin_number < 0 || pin_number >= gpio_count ) {
>> +    return RTEMS_INVALID_ID;
>> +  }
>> +
>> +  bank = BANK_NUMBER(pin_number);
>> +  pin = PIN_NUMBER(pin_number);
>> +
>> +  AQUIRE_LOCK(bank_lock[bank]);
>> +
>> +  gpio = &gpio_pin_state[bank][pin];
>> +
>> +  /* If the pin has an enabled interrupt then remove the handler(s),
>> +   * and disable the interrupts on that pin. */
>> +  if ( gpio->enabled_interrupt != NONE ) {
>> +    sc = rtems_gpio_disable_interrupt(pin_number);
>> +
>> +    if ( sc != RTEMS_SUCCESSFUL ) {
>> +      RELEASE_LOCK(bank_lock[bank]);
>> +
>> +      return sc;
>> +    }
>> +  }
>> +
>> +  gpio->pin_function = NOT_USED;
>> +  gpio->task_id = RTEMS_ID_NONE;
>> +  gpio->debouncing_tick_count = 0;
>> +  gpio->last_isr_tick = 0;
>> +
>> +  RELEASE_LOCK(bank_lock[bank]);
>> +
>> +  return RTEMS_SUCCESSFUL;
>> +}
>> +
>> +rtems_status_code rtems_gpio_debounce_switch(uint32_t pin_number, int ticks)
>> +{
>> +  uint32_t bank;
>> +  uint32_t pin;
>> +
>> +  if ( pin_number < 0 || pin_number >= gpio_count ) {
>> +    return RTEMS_INVALID_ID;
>> +  }
>> +
>> +  bank = BANK_NUMBER(pin_number);
>> +  pin = PIN_NUMBER(pin_number);
>> +
>> +  AQUIRE_LOCK(bank_lock[bank]);
>> +
>> +  if ( gpio_pin_state[bank][pin].pin_function != DIGITAL_INPUT ) {
>> +    RELEASE_LOCK(bank_lock[bank]);
>> +
>> +    return RTEMS_NOT_CONFIGURED;
>> +  }
>> +
>> +  gpio_pin_state[bank][pin].debouncing_tick_count = ticks;
>> +  gpio_pin_state[bank][pin].last_isr_tick = rtems_clock_get_ticks_per_second();
> Why setting last_isr_tick? If anything set it to 0, or to the ticks
> since boot, but not to ticks_per_second...

Yes it should be 0.

>> +
>> +  RELEASE_LOCK(bank_lock[bank]);
>> +
>> +  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_handler_list *isr_node;
>> +  gpio_pin* gpio;
>> +  uint32_t bank;
>> +  uint32_t pin;
>> +
>> +  if ( pin_number < 0 || pin_number >= gpio_count ) {
>> +    return RTEMS_INVALID_ID;
>> +  }
>> +
>> +  bank = BANK_NUMBER(pin_number);
>> +  pin = PIN_NUMBER(pin_number);
>> +
>> +  AQUIRE_LOCK(bank_lock[bank]);
>> +
>> +  gpio = &gpio_pin_state[bank][pin];
>> +
>> +  /* If the current pin has no interrupt enabled
>> +   * then it does not need an handler. */
>> +  if ( gpio->enabled_interrupt == NONE ) {
>> +    RELEASE_LOCK(bank_lock[bank]);
>> +
>> +    return RTEMS_NOT_CONFIGURED;
>> +  }
>> +  /* If the pin already has an enabled interrupt but the installed handler
>> +   * is set as unique. */
>> +  else if ( gpio->handler_flag == UNIQUE_HANDLER && gpio->handler_list != NULL ) {
>> +    RELEASE_LOCK(bank_lock[bank]);
>> +
>> +    return RTEMS_RESOURCE_IN_USE;
>> +  }
>> +
>> +  /* Update the pin's ISR list. */
>> +  isr_node = (gpio_handler_list *) malloc(sizeof(gpio_handler_list));
>> +
>> +  if ( isr_node == NULL ) {
>> +    RELEASE_LOCK(bank_lock[bank]);
>> +
>> +    return RTEMS_NO_MEMORY;
>> +  }
>> +
>> +  isr_node->handler = handler;
>> +  isr_node->arg = arg;
>> +
>> +  if ( gpio->handler_flag == SHARED_HANDLER ) {
>> +    isr_node->next_isr = gpio->handler_list;
>> +  }
>> +  else {
>> +    isr_node->next_isr = NULL;
> Isn't this the same thing as gpio->handler_list in case of !SHARED_HANDLER?

Indeed the gpio->handler_list is always NULL if empty, so yes this if 
block can be replaced with

isr_node->next_isr = gpio->handler_list;

Not sure if that would be more readable.

>> +  }
>> +
>> +  gpio->handler_list = isr_node;
>> +
>> +  RELEASE_LOCK(bank_lock[bank]);
>> +
>> +  return RTEMS_SUCCESSFUL;
>> +}
>> +
>> +rtems_status_code rtems_gpio_enable_interrupt(
>> +uint32_t pin_number,
>> +rtems_gpio_interrupt interrupt,
>> +rtems_gpio_handler_flag flag,
>> +rtems_gpio_irq_state (*handler) (void *arg),
>> +void *arg
>> +)
>> +{
>> +  rtems_vector_number vector;
>> +  rtems_status_code sc;
>> +  gpio_pin* gpio;
>> +  uint32_t bank;
>> +  uint32_t pin;
>> +
>> +  if ( pin_number < 0 || pin_number >= gpio_count ) {
>> +    return RTEMS_INVALID_ID;
>> +  }
>> +
>> +  bank = BANK_NUMBER(pin_number);
>> +  pin = PIN_NUMBER(pin_number);
>> +
>> +  vector = rtems_bsp_gpio_get_vector(bank);
>> +
>> +  AQUIRE_LOCK(bank_lock[bank]);
>> +
>> +  gpio = &gpio_pin_state[bank][pin];
>> +
>> +  if ( gpio->pin_function != DIGITAL_INPUT ) {
>> +    RELEASE_LOCK(bank_lock[bank]);
>> +
>> +    return RTEMS_NOT_CONFIGURED;
>> +  }
>> +
>> +  /* If trying to enable the same type of interrupt on the same pin, or if the pin
>> +   * already has an enabled interrupt. */
>> +  if ( interrupt == gpio->enabled_interrupt || gpio->enabled_interrupt != NONE ) {
>> +    RELEASE_LOCK(bank_lock[bank]);
>> +
>> +    return RTEMS_RESOURCE_IN_USE;
>> +  }
>> +
>> +  /* Creates and starts a new task which will call the corresponding
>> +   * user-defined handlers for this pin. */
>> +  sc = rtems_task_create(rtems_build_name('G', 'P', 'I', 'O'),
>> +                         5,
>> +                         RTEMS_MINIMUM_STACK_SIZE * 2,
>> +                         RTEMS_NO_TIMESLICE,
>> +                         RTEMS_DEFAULT_ATTRIBUTES,
>> +                         &gpio->task_id);
>> +
>> +  if ( sc != RTEMS_SUCCESSFUL ) {
>> +    RELEASE_LOCK(bank_lock[bank]);
>> +
>> +    return RTEMS_UNSATISFIED;
>> +  }
>> +
>> +  sc = rtems_task_start(gpio->task_id, generic_handler_task, (rtems_task_argument) gpio);
>> +
>> +  if ( sc != RTEMS_SUCCESSFUL ) {
>> +    RELEASE_LOCK(bank_lock[bank]);
>> +
>> +    sc = rtems_task_delete(gpio->task_id);
>> +
>> +    assert( sc == RTEMS_SUCCESSFUL );
>> +
>> +    return RTEMS_UNSATISFIED;
>> +  }
>> +
>> +  gpio->enabled_interrupt = interrupt;
>> +  gpio->handler_flag = flag;
>> +
>> +  /* Installs the interrupt handler. */
>> +  sc = rtems_gpio_interrupt_handler_install(pin_number, handler, arg);
>> +
>> +  if ( sc != RTEMS_SUCCESSFUL ) {
>> +    RELEASE_LOCK(bank_lock[bank]);
>> +
>> +    sc = rtems_task_delete(gpio->task_id);
>> +
>> +    assert( sc == RTEMS_SUCCESSFUL );
>> +
>> +    return RTEMS_UNSATISFIED;
>> +  }
>> +
>> +  /* If the generic ISR has not been yet installed for this bank, installs it.
>> +   * This ISR will be responsible for calling the handler tasks,
>> +   * which in turn will call the user-defined interrupt handlers.*/
>> +  if ( interrupt_counter[bank] == 0 ) {
>> +    sc = rtems_interrupt_handler_install(vector,
>> +                                         "GPIO_HANDLER",
>> +                                         RTEMS_INTERRUPT_UNIQUE,
>> +                                         (rtems_interrupt_handler) generic_isr,
>> +                                         gpio_pin_state[bank]);
>> +
>> +    if ( sc != RTEMS_SUCCESSFUL ) {
>> +      RELEASE_LOCK(bank_lock[bank]);
>> +
>> +      return RTEMS_UNSATISFIED;
>> +    }
>> +  }
>> +
>> +  sc = rtems_bsp_enable_interrupt(bank, pin, interrupt);
>> +
>> +  if ( sc != RTEMS_SUCCESSFUL ) {
>> +    RELEASE_LOCK(bank_lock[bank]);
>> +
>> +    return RTEMS_UNSATISFIED;
>> +  }
>> +
>> +  ++interrupt_counter[bank];
>> +
>> +  RELEASE_LOCK(bank_lock[bank]);
>> +
>> +  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_handler_list *isr_node, *next_node;
>> +  gpio_pin* gpio;
>> +  uint32_t bank;
>> +  uint32_t pin;
>> +
>> +  if ( pin_number < 0 || pin_number >= gpio_count ) {
>> +    return RTEMS_INVALID_ID;
>> +  }
>> +
>> +  bank = BANK_NUMBER(pin_number);
>> +  pin = PIN_NUMBER(pin_number);
>> +
>> +  AQUIRE_LOCK(bank_lock[bank]);
>> +
>> +  gpio = &gpio_pin_state[bank][pin];
>> +
>> +  isr_node = gpio->handler_list;
>> +
>> +  if ( isr_node != NULL ) {
>> +    if ( isr_node->handler == handler && isr_node->arg == arg ) {
>> +      gpio->handler_list = isr_node->next_isr;
>> +
>> +      free(isr_node);
>> +    }
>> +    else {
>> +      while ( isr_node->next_isr != NULL ) {
>> +        if ( (isr_node->next_isr)->handler == handler && (isr_node->next_isr)->arg == arg ) {
>> +          next_node = (isr_node->next_isr)->next_isr;
>> +
>> +          free(isr_node->next_isr);
>> +
>> +          isr_node->next_isr = next_node;
>> +        }
>> +      }
>> +    }
>> +  }
>> +
>> +  /* If the removed handler was the last for this pin, disables further
>> +   * interrupts on this pin. */
>> +  if ( gpio->handler_list == NULL ) {
>> +    RELEASE_LOCK(bank_lock[bank]);
>> +
>> +    return rtems_gpio_disable_interrupt(pin_number);
>> +  }
>> +
>> +  RELEASE_LOCK(bank_lock[bank]);
>> +
>> +  return RTEMS_SUCCESSFUL;
>> +}
>> +
>> +rtems_status_code rtems_gpio_disable_interrupt(uint32_t pin_number)
>> +{
>> +  gpio_handler_list *isr_node;
>> +  rtems_vector_number vector;
>> +  rtems_status_code sc;
>> +  gpio_pin* gpio;
>> +  uint32_t bank;
>> +  uint32_t pin;
>> +
>> +  if ( pin_number < 0 || pin_number >= gpio_count ) {
>> +    return RTEMS_INVALID_ID;
>> +  }
>> +
>> +  bank = BANK_NUMBER(pin_number);
>> +  pin = PIN_NUMBER(pin_number);
>> +
>> +  vector = rtems_bsp_gpio_get_vector(bank);
>> +
>> +  AQUIRE_LOCK(bank_lock[bank]);
>> +
>> +  gpio = &gpio_pin_state[bank][pin];
>> +
>> +  if ( interrupt_counter[bank] == 0 || gpio->enabled_interrupt == NONE ) {
>> +    RELEASE_LOCK(bank_lock[bank]);
>> +
>> +    return RTEMS_SUCCESSFUL;
>> +  }
>> +
>> +  sc = rtems_bsp_disable_interrupt(bank, pin, gpio->enabled_interrupt);
>> +
>> +  if ( sc != RTEMS_SUCCESSFUL ) {
>> +    RELEASE_LOCK(bank_lock[bank]);
>> +
>> +    return RTEMS_UNSATISFIED;
>> +  }
>> +
>> +  gpio->enabled_interrupt = NONE;
>> +
>> +  while ( gpio->handler_list != NULL ) {
>> +    isr_node = gpio->handler_list;
>> +
>> +    gpio->handler_list = isr_node->next_isr;
>> +
>> +    free(isr_node);
>> +  }
>> +
>> +  sc = rtems_task_delete(gpio->task_id);
> So the handler task cannot be shared by more than one pin? Is this
> requirement explicit somewhere? Is this the intent?

The handler task is to handle the (possible) many handlers an individual 
pin can have, if it acts as a shared IRQ line. What is shared across 
multiple pins is the generic_isr, which is as actual ISR routine (shared 
with all pins of a given bank).

>> +
>> +  assert( sc == RTEMS_SUCCESSFUL );
>> +
>> +  --interrupt_counter[bank];
>> +
>> +  /* If no GPIO interrupts are left in this bank, removes the handler. */
>> +  if ( interrupt_counter[bank] == 0 ) {
>> +    sc = rtems_interrupt_handler_remove(vector,
>> +                                        (rtems_interrupt_handler) generic_isr,
>> +                                        gpio_pin_state[bank]);
>> +
>> +    if ( sc != RTEMS_SUCCESSFUL ) {
>> +      RELEASE_LOCK(bank_lock[bank]);
>> +
>> +      return RTEMS_UNSATISFIED;
>> +    }
>> +  }
>> +
>> +  RELEASE_LOCK(bank_lock[bank]);
>> +
>> +  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..6a84747
>> --- /dev/null
>> +++ b/c/src/lib/libbsp/shared/include/gpio.h
>> @@ -0,0 +1,610 @@
>> +/**
>> + * @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
> why two underscores?

oops.

>> +
>> +#include <rtems.h>
>> +
>> +#ifdef __cplusplus
>> +extern "C" {
>> +#endif /* __cplusplus */
>> +
>> +/**
>> + * @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 configuratons
>> + * 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;
> This could also be bool.
>

Agreed.

>> +
>> +/**
>> + * @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 relevant information about a BSP's GPIO layout.
>> + */
>> +typedef struct
>> +{
>> +  /* Total number of GPIO pins. */
>> +  uint32_t pin_count;
>> +
>> +  /* Number of pins per bank. The last bank may be smaller,
>> +   * depending on the total number of pins. */
>> +  uint32_t pins_per_bank;
> Maybe use an array instead. This can also reduce the need for all the
> arithmetic computing bank and pin from pin_number.. if you can just
> index directly into a struct containing all that information? What
> would be the expected cost in size to do it like this?

You mean to replace the rtems_gpio_layout with an array of structs 
statically filled with the bank/pin combinations by each BSP? That does 
not seem very clean, specially since each all banks have the same number 
of pins (the last is the only possible exception), and the layout 
calculation is pretty easy/cheap.

One way to improve the bank/pin situation would, maybe, be as follows:

Replace the gpio_pin **gpio_pin_state matrix with an uni-dimensional 
array, such that (suposing pins_per_bank = 32) from the index 0 to 31 it 
would refer to pins in the first bank, from index 32 to 63 to pins from 
the second bank, and so on. This would allow to fetch the right GPIO pin 
using the pin_number directly.

For the cases where I need to send a whole bank of pins, I could simply 
send a pointer to the index of the first pin of that bank. Then since I 
know how many pins each bank has I always know where the bank ends.

>> +} rtems_gpio_layout;
>> +
>> +/**
>> + * @brief Object containing configuration information
>> + *        regarding interrupts.
>> + */
>> +typedef struct
>> +{
>> +  rtems_gpio_interrupt enabled_interrupt;
>> +
>> +  rtems_gpio_handler_flag handler_flag;
>> +
>> +  /* 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 clock_tick_interval;
> perhaps put debounce in the name to make it more clear in the code.

Agreed.

>> +} rtems_gpio_interrupt_conf;
> spell out configuration
>
>> +
>> +/**
>> + * @brief Object containing configuration information
>> + *        to request/update a GPIO pin.
>> + */
>> +typedef struct
>> +{
>> +  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;
>> +  bool logic_invert;
>> +
>> +  /* Pin interrupt configuration. Should be NULL if not used. */
>> +  rtems_gpio_interrupt_conf* interrupt;
> We normally put the * with the variable name.

Yes I missed that on the coding conventions document.

>> +
>> +  /* Struct 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 struct.
>> +   *
>> +   * 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;
>> +
>> +/** @} */
>> +
>> +/**
>> + * @name gpio Usage
>> + *
>> + * @{
>> + */
>> +
>> +/**
>> + * @brief Initializes the GPIO API.
>> + *
>> + * @retval RTEMS_SUCCESSFUL API successfully initialized.
>> + * @retval * For other error code see @rtems_semaphore_create().
>> + */
>> +extern rtems_status_code rtems_gpio_initialize(void);
>> +
>> +/**
>> + * @brief Requests a GPIO pin configuration from the API.
> remove "from the API".
>
>> + *        It may be used either to request a new pin, or to update the
>> + *        configuration/functions of a pin currently in use.
>> + *
>> + * @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 request/update the pin's configuration.
>> + */
>> +extern rtems_status_code rtems_gpio_request_conf(rtems_gpio_pin_conf* conf);
>> +
>> +/**
>> + * @brief Sets multiple output GPIO pins with the logical high.
>> + *
>> + * @param[in] count Number of GPIO pins to set.
>> + * @param[in] ... Comma-separated list of GPIO pin numbers.
>> + *
>> + * @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 count, ...);
>> +
>> +/**
>> + * @brief Sets multiple output GPIO pins with the logical low.
>> + *
>> + * @param[in] count Number of GPIO pins to clear.
>> + * @param[in] ... Comma-separated list of GPIO pin numbers.
>> + *
>> + * @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 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 int rtems_gpio_get_value(uint32_t pin_number);
>> +
>> +/**
>> + * @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 not handled by the API.
>> + *
>> + * @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 from the API, making it available to be used
> ditto.
>
>> + *        again.
>> + *
>> + * @param[in] pin_number GPIO pin number.
>> + *
>> + * @retval RTEMS_SUCCESSFUL Pin successfully disabled on the API.
> delete "on the API"
>
>> + * @retval RTEMS_INVALID_ID Pin number is invalid.
>> + * @retval * Could not disable an ative interrupt on this pin,
> typo: active
>
>> + *           @see rtems_gpio_disable_interrupt().
>> + */
>> +extern rtems_status_code rtems_gpio_release_pin(uint32_t pin_number);
>> +
>> +/**
>> + * @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 De-bounce 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.
>> + */
>> +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_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] 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_RESOURCE_IN_USE The pin already has an enabled interrupt.
>> + */
>> +extern rtems_status_code rtems_gpio_enable_interrupt(
>> +uint32_t pin_number,
>> +rtems_gpio_interrupt interrupt,
>> +rtems_gpio_handler_flag flag,
>> +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 * @see rtems_gpio_disable_interrupt()
>> + */
>> +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_UNSATISFIED Could not remove the current interrupt handler,
>> + *                           could not recognise 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 Defines the GPIO pin layout. This must be implemented by each BSP.
>> + */
>> +extern rtems_gpio_layout rtems_bsp_gpio_initialize(void);
>> +
> This should perhaps return a status, and have layout filled in as a
> side-effect, passing it as a pointer rather than getting a struct
> returned.
>
>> +/**
>> + * @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_bsp_gpio_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_bsp_gpio_multi_clear(uint32_t bank, uint32_t bitmask);
>> +
>> +/**
>> + * @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_bsp_gpio_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_bsp_gpio_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 int rtems_bsp_gpio_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 asssigned successfully.
>> + * @retval RTEMS_UNSATISFIED Could not assign the function to the pin.
>> + */
>> +extern rtems_status_code rtems_bsp_gpio_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 asssigned successfully.
>> + * @retval RTEMS_UNSATISFIED Could not assign the function to the pin.
>> + */
>> +extern rtems_status_code rtems_bsp_gpio_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 asssigned 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_bsp_gpio_set_resistor_mode(uint32_t bank, uint32_t pin, rtems_gpio_pull_mode mode);
>> +
>> +/**
>> + * @brief Reads and returns a vector/bank interrupt event line.
>> + *        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_bsp_gpio_interrupt_line(rtems_vector_number vector);
>> +
>> +/**
>> + * @brief Clears a vector/bank interrupt event line.
>> + *        This must be implemented by each BSP.
>> + *
>> + * @param[in] vector GPIO vector/bank.
>> + * @param[in] event_status Bitmask with the processed interrupts on the given
>> + *                         vector. This bitmask is the same as calculated in
>> + *                         @see rtems_bsp_gpio_interrupt_line().
>> + */
>> +extern void rtems_bsp_gpio_clear_interrupt_line(rtems_vector_number vector, uint32_t event_status);
>> +
>> +/**
>> + * @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_bsp_gpio_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 Disables interrupt on hardware. This must be implemented by each BSP.
>> + */
>> +
>> +/**
>> + * @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] enabled_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 enabled_interrupt);
>> +
>> +/** @} */
>> +
>> +#ifdef __cplusplus
>> +}
>> +#endif /* __cplusplus */
>> +
>> +#endif /* LIBBSP_SHARED__GPIO_H */
>> --
>> 2.0.5
>>
>> _______________________________________________
>> devel mailing list
>> devel at rtems.org
>> http://lists.rtems.org/mailman/listinfo/devel




More information about the devel mailing list