source: rtems/c/src/lib/libbsp/shared/gpio.c @ 87f8b01

5
Last change on this file since 87f8b01 was 87f8b01, checked in by Andre Marques <andre.lousa.marques@…>, on 07/27/15 at 16:01:43

RTEMS GPIO API definition and implementation.

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).
  • Property mode set to 100644
File size: 47.4 KB
Line 
1/**
2 * @file gpio.c
3 *
4 * @ingroup rtems_gpio
5 *
6 * @brief RTEMS GPIO API implementation.
7 */
8
9/*
10 *  Copyright (c) 2014-2015 Andre Marques <andre.lousa.marques at gmail.com>
11 *
12 *  The license and distribution terms for this file may be
13 *  found in the file LICENSE in this distribution or at
14 *  http://www.rtems.org/license/LICENSE.
15 */
16
17#include <rtems/score/atomic.h>
18#include <rtems/chain.h>
19#include <bsp/irq-generic.h>
20#include <bsp/gpio.h>
21#include <assert.h>
22#include <stdlib.h>
23
24/**
25 * @brief GPIO API mutex attributes.
26 */
27#define MUTEX_ATTRIBUTES (     \
28  RTEMS_LOCAL                  \
29  | RTEMS_PRIORITY             \
30  | RTEMS_BINARY_SEMAPHORE     \
31  | RTEMS_INHERIT_PRIORITY     \
32  | RTEMS_NO_PRIORITY_CEILING  \
33)
34
35#define CREATE_LOCK(name, lock_id) rtems_semaphore_create(   \
36  name,                                                      \
37  1,                                                         \
38  MUTEX_ATTRIBUTES,                                          \
39  0,                                                         \
40  lock_id                                                    \
41)
42
43#define ACQUIRE_LOCK(m) assert ( rtems_semaphore_obtain(m,               \
44                                                        RTEMS_WAIT,      \
45                                                        RTEMS_NO_TIMEOUT \
46                                                        ) == RTEMS_SUCCESSFUL )
47
48#define RELEASE_LOCK(m) assert ( rtems_semaphore_release(m) == RTEMS_SUCCESSFUL )
49
50/**
51 * @brief Object containing relevant information about a GPIO group.
52 *
53 * Encapsulates relevant data for a GPIO pin group.
54 */
55struct rtems_gpio_group
56{
57  rtems_chain_node node;
58
59  uint32_t *digital_inputs;
60  uint32_t digital_input_bank;
61  uint32_t input_count;
62
63  uint32_t *digital_outputs;
64  uint32_t digital_output_bank;
65  uint32_t output_count;
66
67  uint32_t *bsp_speficifc_pins;
68  uint32_t bsp_specific_bank;
69  uint32_t bsp_specific_pin_count;
70
71  rtems_id group_lock;
72};
73
74/**
75 * @brief Object containing relevant information to a list of user-defined
76 *        interrupt handlers.
77 *
78 * Encapsulates relevant data for a GPIO interrupt handler.
79 */
80typedef struct
81{
82  rtems_chain_node node;
83
84  /* User-defined ISR routine. */
85  rtems_gpio_irq_state (*handler) (void *arg);
86
87  /* User-defined arguments for the ISR routine. */
88  void *arg;
89} gpio_handler_node;
90
91/**
92 * @brief Object containing relevant information of a pin's interrupt
93 *        configuration/state.
94 *
95 * Encapsulates relevant data of a GPIO pin interrupt state.
96 */
97typedef struct
98{
99  /* Currently active interrupt. */
100  rtems_gpio_interrupt active_interrupt;
101
102  /* ISR shared flag. */
103  rtems_gpio_handler_flag handler_flag;
104
105  /* Linked list of interrupt handlers. */
106  rtems_chain_control handler_chain;
107
108  /* Switch-deboucing information. */
109  uint32_t debouncing_tick_count;
110  rtems_interval last_isr_tick;
111} gpio_pin_interrupt_state;
112
113/**
114 * @brief Object containing information on a GPIO pin.
115 *
116 * Encapsulates relevant data about a GPIO pin.
117 */
118typedef struct
119{
120  rtems_gpio_function pin_function;
121
122  /* GPIO pull resistor configuration. */
123  rtems_gpio_pull_mode resistor_mode;
124
125  /* If true inverts digital in/out applicational logic. */
126  bool logic_invert;
127
128  /* True if the pin is on a group. */
129  bool on_group;
130
131  /* Interrupt data for a pin. This field is NULL if no interrupt is enabled
132   * on the pin. */
133  gpio_pin_interrupt_state *interrupt_state;
134} gpio_pin;
135
136/**
137 * @brief Object containing relevant information regarding a GPIO bank state.
138 *
139 * Encapsulates relevant data for a GPIO bank.
140 */
141typedef struct
142{
143  uint32_t bank_number;
144  uint32_t interrupt_counter;
145  rtems_id lock;
146
147  /* If TRUE the interrupts on the bank will be called
148   * by a rtems interrupt server, otherwise they will be handled
149   * in the normal ISR context. */
150  bool threaded_interrupts;
151} gpio_bank;
152
153static gpio_pin gpio_pin_state[BSP_GPIO_PIN_COUNT];
154static Atomic_Flag init_flag = ATOMIC_INITIALIZER_FLAG;
155static gpio_bank gpio_bank_state[GPIO_BANK_COUNT];
156static Atomic_Uint threaded_interrupt_counter = ATOMIC_INITIALIZER_UINT(0);
157static rtems_chain_control gpio_group;
158
159#define BANK_NUMBER(pin_number) pin_number / BSP_GPIO_PINS_PER_BANK
160#define PIN_NUMBER(pin_number) pin_number % BSP_GPIO_PINS_PER_BANK
161
162static int debounce_switch(gpio_pin_interrupt_state *interrupt_state)
163{
164  rtems_interval time;
165
166  time = rtems_clock_get_ticks_since_boot();
167
168  /* If not enough time has elapsed since last interrupt. */
169  if (
170      (time - interrupt_state->last_isr_tick) <
171      interrupt_state->debouncing_tick_count
172  ) {
173    return -1;
174  }
175
176  interrupt_state->last_isr_tick = time;
177
178  return 0;
179}
180
181/* Returns the amount of pins in a bank. */
182static uint32_t get_bank_pin_count(uint32_t bank)
183{
184  /* If the current bank is the last bank, which may not be completely filled. */
185  if ( bank == GPIO_BANK_COUNT - 1 ) {
186    return GPIO_LAST_BANK_PINS;
187  }
188
189  return BSP_GPIO_PINS_PER_BANK;
190}
191
192/* GPIO generic bank ISR. This may be called directly as response to an
193 * interrupt, or by the rtems interrupt server task if the GPIO bank
194 * uses threading interrupt handling. */
195static void generic_bank_isr(void *arg)
196{
197  gpio_pin_interrupt_state *interrupt_state;
198  rtems_chain_control *handler_list;
199  rtems_chain_node *node;
200  rtems_chain_node *next_node;
201  gpio_handler_node *isr_node;
202  rtems_vector_number vector;
203  uint32_t event_status;
204  uint32_t bank_number;
205  uint32_t bank_start_pin;
206  uint8_t handled_count;
207  uint8_t rv;
208  uint8_t i;
209
210  bank_number = *((uint32_t*) arg);
211
212  assert ( bank_number >= 0 && bank_number < GPIO_BANK_COUNT );
213
214  /* Calculate bank start address in the pin_state array. */
215  bank_start_pin = bank_number * BSP_GPIO_PINS_PER_BANK;
216
217  vector = rtems_gpio_bsp_get_vector(bank_number);
218
219  /* If this bank does not use threaded interrupts we have to
220   * disable the vector. Otherwise the interrupt server does it. */
221  if ( gpio_bank_state[bank_number].threaded_interrupts == false ) {
222    /* Prevents more interrupts from being generated on GPIO. */
223    bsp_interrupt_vector_disable(vector);
224  }
225
226  /* Obtains a 32-bit bitmask, with the pins currently reporting interrupts
227   * signaled with 1. */
228  event_status = rtems_gpio_bsp_interrupt_line(vector);
229
230  /* Iterates through the bitmask and calls the corresponding handler
231   * for active interrupts. */
232  for ( i = 0; i < get_bank_pin_count(bank_number); ++i ) {
233    /* If active, wake the corresponding pin's ISR task. */
234    if ( event_status & (1 << i) ) {
235      interrupt_state = gpio_pin_state[bank_start_pin + i].interrupt_state;
236
237      assert ( interrupt_state != NULL );
238
239      handled_count = 0;
240
241      if ( gpio_bank_state[bank_number].threaded_interrupts ) {
242        ACQUIRE_LOCK(gpio_bank_state[bank_number].lock);
243      }
244
245      /* If this pin has the debouncing function attached, call it. */
246      if ( interrupt_state->debouncing_tick_count > 0 ) {
247        rv = debounce_switch(interrupt_state);
248
249        /* If the handler call was caused by a switch bounce,
250         * ignores and move on. */
251        if ( rv < 0 ) {
252          if ( gpio_bank_state[bank_number].threaded_interrupts ) {
253            RELEASE_LOCK(gpio_bank_state[bank_number].lock);
254          }
255
256          continue;
257        }
258      }
259
260      handler_list = &interrupt_state->handler_chain;
261
262      node = rtems_chain_first(handler_list);
263
264      /* Iterate the ISR list. */
265      while ( !rtems_chain_is_tail(handler_list, node) ) {
266        isr_node = (gpio_handler_node *) node;
267
268        next_node = node->next;
269
270        if ( (isr_node->handler)(isr_node->arg) == IRQ_HANDLED ) {
271          ++handled_count;
272        }
273
274        node = next_node;
275      }
276
277      /* If no handler assumed the interrupt,
278       * treat it as a spurious interrupt. */
279      if ( handled_count == 0 ) {
280        bsp_interrupt_handler_default(rtems_gpio_bsp_get_vector(bank_number));
281      }
282
283      if ( gpio_bank_state[bank_number].threaded_interrupts ) {
284        RELEASE_LOCK(gpio_bank_state[bank_number].lock);
285      }
286    }
287  }
288
289  if ( gpio_bank_state[bank_number].threaded_interrupts == false ) {
290    bsp_interrupt_vector_enable(vector);
291  }
292}
293
294/* Verifies if all pins in the received pin array are from the same bank and
295 * have the defined GPIO function. Produces bitmask of the received pins. */
296static rtems_status_code get_pin_bitmask(
297  uint32_t *pins,
298  uint32_t pin_count,
299  uint32_t *bank_number,
300  uint32_t *bitmask,
301  rtems_gpio_function function
302) {
303  uint32_t pin_number;
304  uint32_t bank;
305  uint8_t i;
306
307  if ( pin_count < 1 ) {
308    return RTEMS_UNSATISFIED;
309  }
310
311  *bitmask = 0;
312
313  for ( i = 0; i < pin_count; ++i ) {
314    pin_number = pins[i];
315
316    if ( pin_number < 0 || pin_number >= BSP_GPIO_PIN_COUNT ) {
317      return RTEMS_INVALID_ID;
318    }
319
320    bank = BANK_NUMBER(pin_number);
321
322    if ( i == 0 ) {
323      *bank_number = bank;
324
325      ACQUIRE_LOCK(gpio_bank_state[bank].lock);
326    }
327    else if ( bank != *bank_number ) {
328      RELEASE_LOCK(gpio_bank_state[*bank_number].lock);
329
330      return RTEMS_UNSATISFIED;
331    }
332
333    if (
334        gpio_pin_state[pin_number].pin_function != function ||
335        gpio_pin_state[pin_number].on_group
336    ) {
337      RELEASE_LOCK(gpio_bank_state[bank].lock);
338
339      return RTEMS_NOT_CONFIGURED;
340    }
341
342    *bitmask |= (1 << PIN_NUMBER(pin_number));
343  }
344
345  RELEASE_LOCK(gpio_bank_state[bank].lock);
346
347  return RTEMS_SUCCESSFUL;
348}
349
350static rtems_status_code check_same_bank_and_availability(
351  const rtems_gpio_pin_conf *pin_confs,
352  uint32_t pin_count,
353  uint32_t *bank_number,
354  uint32_t *pins
355) {
356  uint32_t pin_number;
357  uint32_t bank;
358  uint8_t i;
359
360  for ( i = 0; i < pin_count; ++i ) {
361    pin_number = pin_confs[i].pin_number;
362
363    bank = BANK_NUMBER(pin_number);
364
365    if ( i == 0 ) {
366      *bank_number = bank;
367
368      ACQUIRE_LOCK(gpio_bank_state[bank].lock);
369    }
370    else if ( bank != *bank_number ) {
371      RELEASE_LOCK(gpio_bank_state[*bank_number].lock);
372
373      return RTEMS_UNSATISFIED;
374    }
375
376    if ( gpio_pin_state[pin_number].pin_function != NOT_USED ) {
377      RELEASE_LOCK(gpio_bank_state[bank].lock);
378
379      return RTEMS_RESOURCE_IN_USE;
380    }
381
382    pins[i] = PIN_NUMBER(pin_number);
383  }
384
385  RELEASE_LOCK(gpio_bank_state[*bank_number].lock);
386
387  return RTEMS_SUCCESSFUL;
388}
389
390static rtems_status_code setup_resistor_and_interrupt_configuration(
391  uint32_t pin_number,
392  rtems_gpio_pull_mode pull_mode,
393  rtems_gpio_interrupt_configuration *interrupt_conf
394) {
395  gpio_pin_interrupt_state *interrupt_state;
396  rtems_status_code sc;
397  uint32_t bank;
398
399  sc = rtems_gpio_resistor_mode(pin_number, pull_mode);
400
401  if ( sc != RTEMS_SUCCESSFUL ) {
402#if defined(DEBUG)
403    printk("rtems_gpio_resistor_mode failed with status code %d\n", sc);
404#endif
405
406    return RTEMS_UNSATISFIED;
407  }
408
409  if ( interrupt_conf != NULL ) {
410    bank = BANK_NUMBER(pin_number);
411
412    ACQUIRE_LOCK(gpio_bank_state[bank].lock);
413
414    sc = rtems_gpio_enable_interrupt(
415           pin_number,
416           interrupt_conf->active_interrupt,
417           interrupt_conf->handler_flag,
418           interrupt_conf->threaded_interrupts,
419           interrupt_conf->handler,
420           interrupt_conf->arg
421         );
422
423    if ( sc != RTEMS_SUCCESSFUL ) {
424      RELEASE_LOCK(gpio_bank_state[bank].lock);
425
426#if defined(DEBUG)
427      printk(
428        "rtems_gpio_enable_interrupt failed with status code %d\n",
429        sc
430      );
431#endif
432
433      return RTEMS_UNSATISFIED;
434    }
435
436    interrupt_state = gpio_pin_state[pin_number].interrupt_state;
437
438    interrupt_state->debouncing_tick_count =
439      interrupt_conf->debounce_clock_tick_interval;
440
441    interrupt_state->last_isr_tick = 0;
442
443    RELEASE_LOCK(gpio_bank_state[bank].lock);
444  }
445
446  return RTEMS_SUCCESSFUL;
447}
448
449static rtems_status_code gpio_multi_select(
450  const rtems_gpio_pin_conf *pins,
451  uint8_t pin_count,
452  bool on_group
453) {
454  rtems_status_code sc;
455  uint32_t pin_number;
456  uint32_t bank;
457  uint8_t i;
458
459  /* If the BSP has multi select capabilities. */
460#ifdef BSP_GPIO_PINS_PER_SELECT_BANK
461  rtems_gpio_multiple_pin_select
462    pin_data[GPIO_SELECT_BANK_COUNT][BSP_GPIO_PINS_PER_SELECT_BANK];
463  rtems_gpio_specific_data *bsp_data;
464
465  /* Since each platform may have more than two functions to assign to a pin,
466   * each pin requires more than one bit in the selection register to
467   * properly assign a function to it.
468   * Therefore a selection bank (pin selection register) will support fewer pins
469   * than a regular bank, meaning that there will be more selection banks than
470   * regular banks, which have to be handled separately.
471   *
472   * This field records the select bank number relative to the GPIO bank. */
473  uint32_t select_bank;
474  uint32_t bank_number;
475  uint32_t select_bank_counter[GPIO_SELECT_BANK_COUNT];
476  uint32_t select_count;
477  uint32_t pin;
478
479  if ( pin_count == 0 ) {
480    return RTEMS_SUCCESSFUL;
481  }
482
483  for ( i = 0; i < GPIO_SELECT_BANK_COUNT; ++i ) {
484    select_bank_counter[i] = 0;
485  }
486
487  for ( i = 0; i < pin_count; ++i ) {
488    pin_number = pins[i].pin_number;
489
490    if ( pin_number < 0 || pin_number >= BSP_GPIO_PIN_COUNT ) {
491      return RTEMS_INVALID_ID;
492    }
493
494    bank = BANK_NUMBER(pin_number);
495    pin = PIN_NUMBER(pin_number);
496
497    if ( i == 0 ) {
498      bank_number = bank;
499
500      ACQUIRE_LOCK(gpio_bank_state[bank].lock);
501    }
502    else if ( bank != bank_number ) {
503      RELEASE_LOCK(gpio_bank_state[bank_number].lock);
504
505      return RTEMS_UNSATISFIED;
506    }
507
508    /* If the pin is already being used returns with an error. */
509    if ( gpio_pin_state[pin_number].pin_function != NOT_USED ) {
510      RELEASE_LOCK(gpio_bank_state[bank_number].lock);
511
512      return RTEMS_RESOURCE_IN_USE;
513    }
514
515    select_bank = (pin_number / BSP_GPIO_PINS_PER_SELECT_BANK) -
516                  (bank * GPIO_SELECT_BANK_COUNT);
517
518    select_count = select_bank_counter[select_bank];
519
520    pin_data[select_bank][select_count].pin_number = pin_number;
521    pin_data[select_bank][select_count].function = pins[i].function;
522
523    if ( pins[i].function == BSP_SPECIFIC ) {
524      bsp_data = (rtems_gpio_specific_data *) pins[i].bsp_specific;
525
526      if ( bsp_data == NULL ) {
527        RELEASE_LOCK(gpio_bank_state[bank_number].lock);
528
529        return RTEMS_UNSATISFIED;
530      }
531
532      pin_data[select_bank][select_count].io_function = bsp_data->io_function;
533      pin_data[select_bank][select_count].bsp_specific = bsp_data->pin_data;
534    }
535    else {
536      /* io_function takes a dummy value, as it will not be used. */
537      pin_data[select_bank][select_count].io_function = 0;
538      pin_data[select_bank][select_count].bsp_specific = pins[i].bsp_specific;
539    }
540
541    ++select_bank_counter[select_bank];
542  }
543
544  for ( i = 0; i < GPIO_SELECT_BANK_COUNT; ++i ) {
545    if ( select_bank_counter[i] == 0 ) {
546      continue;
547    }
548
549    sc = rtems_gpio_bsp_multi_select(
550           pin_data[i], select_bank_counter[i], i +
551           (bank_number * GPIO_SELECT_BANK_COUNT)
552         );
553
554    if ( sc != RTEMS_SUCCESSFUL ) {
555      RELEASE_LOCK(gpio_bank_state[bank_number].lock);
556
557      return sc;
558    }
559  }
560
561  for ( i = 0; i < pin_count; ++i ) {
562    pin_number = pins[i].pin_number;
563
564    /* Fill other pin state information. */
565    gpio_pin_state[pin_number].pin_function = pins[i].function;
566    gpio_pin_state[pin_number].logic_invert = pins[i].logic_invert;
567    gpio_pin_state[pin_number].on_group = on_group;
568
569    sc = setup_resistor_and_interrupt_configuration(
570           pin_number,
571           pins[i].pull_mode,
572           pins[i].interrupt
573         );
574
575    if ( sc != RTEMS_SUCCESSFUL ) {
576      RELEASE_LOCK(gpio_bank_state[bank_number].lock);
577
578      return sc;
579    }
580
581    bank = BANK_NUMBER(pin_number);
582    pin = PIN_NUMBER(pin_number);
583
584    if ( pins[i].function == DIGITAL_OUTPUT ) {
585      if ( pins[i].output_enabled == true ) {
586        sc = rtems_gpio_bsp_set(bank, pin);
587      }
588      else {
589        sc = rtems_gpio_bsp_clear(bank, pin);
590      }
591
592      if ( sc != RTEMS_SUCCESSFUL ) {
593        RELEASE_LOCK(gpio_bank_state[bank_number].lock);
594
595        return sc;
596      }
597    }
598  }
599
600  RELEASE_LOCK(gpio_bank_state[bank_number].lock);
601
602  return sc;
603
604  /* If the BSP does not provide pin multi-selection,
605   * configures each pin sequentially. */
606#else
607  for ( i = 0; i < pin_count; ++i ) {
608    pin_number = pins[i].pin_number;
609
610    if ( pin_number < 0 || pin_number >= BSP_GPIO_PIN_COUNT ) {
611      return RTEMS_INVALID_ID;
612    }
613
614    bank = BANK_NUMBER(pin_number);
615
616    ACQUIRE_LOCK(gpio_bank_state[bank].lock);
617
618    /* If the pin is already being used returns with an error. */
619    if ( gpio_pin_state[pin_number].pin_function != NOT_USED ) {
620      RELEASE_LOCK(gpio_bank_state[bank].lock);
621
622      return RTEMS_RESOURCE_IN_USE;
623    }
624  }
625
626  for ( i = 0; i < pin_count; ++i ) {
627    sc = rtems_gpio_request_configuration(&pins[i]);
628
629    if ( sc != RTEMS_SUCCESSFUL ) {
630      return sc;
631    }
632
633    gpio_pin_state[pins[i].pin_number].on_group = on_group;
634  }
635
636  return RTEMS_SUCCESSFUL;
637#endif
638}
639
640rtems_status_code rtems_gpio_initialize(void)
641{
642  rtems_status_code sc;
643  uint32_t i;
644
645  if ( _Atomic_Flag_test_and_set(&init_flag, ATOMIC_ORDER_RELAXED) == true ) {
646    return RTEMS_SUCCESSFUL;
647  }
648
649  for ( i = 0; i < GPIO_BANK_COUNT; ++i ) {
650    sc = CREATE_LOCK(
651           rtems_build_name('G', 'I', 'N', 'T'),
652           &gpio_bank_state[i].lock
653         );
654
655    if ( sc != RTEMS_SUCCESSFUL ) {
656      return sc;
657    }
658
659    gpio_bank_state[i].bank_number = i;
660    gpio_bank_state[i].interrupt_counter = 0;
661
662    /* The threaded_interrupts field is initialized during
663     * rtems_gpio_enable_interrupt(), as its value is never used before. */
664  }
665
666  for ( i = 0; i < BSP_GPIO_PIN_COUNT; ++i ) {
667    gpio_pin_state[i].pin_function = NOT_USED;
668    gpio_pin_state[i].resistor_mode = NO_PULL_RESISTOR;
669    gpio_pin_state[i].logic_invert = false;
670    gpio_pin_state[i].on_group = false;
671    gpio_pin_state[i].interrupt_state = NULL;
672  }
673
674  /* Initialize GPIO groups chain. */
675  rtems_chain_initialize_empty(&gpio_group);
676
677  return RTEMS_SUCCESSFUL;
678}
679
680rtems_gpio_group *rtems_gpio_create_pin_group(void)
681{
682  struct rtems_gpio_group *group;
683
684  group = (struct rtems_gpio_group *) malloc(sizeof(struct rtems_gpio_group));
685
686  return group;
687}
688
689rtems_status_code rtems_gpio_define_pin_group(
690  const rtems_gpio_group_definition *group_definition,
691  rtems_gpio_group *group
692) {
693  rtems_status_code sc;
694
695  if ( group_definition == NULL || group == NULL ) {
696    return RTEMS_UNSATISFIED;
697  }
698
699  if (
700      group_definition->input_count == 0 &&
701      group_definition->output_count == 0 &&
702      group_definition->bsp_specific_pin_count == 0
703  ) {
704    return RTEMS_UNSATISFIED;
705  }
706
707  group->input_count = group_definition->input_count;
708
709  if ( group->input_count > 0 ) {
710    group->digital_inputs =
711      (uint32_t *) malloc(group->input_count * sizeof(uint32_t));
712
713    /* Evaluate if the pins that will constitute the group are available and
714     * that pins with the same function within the group all belong
715     * to the same pin group. */
716    sc = check_same_bank_and_availability(
717           group_definition->digital_inputs,
718           group->input_count,
719           &group->digital_input_bank,
720           group->digital_inputs
721         );
722
723    if ( sc != RTEMS_SUCCESSFUL ) {
724      return sc;
725    }
726  }
727  else {
728    group->digital_inputs = NULL;
729  }
730
731  group->output_count = group_definition->output_count;
732
733  if ( group->output_count > 0 ) {
734    group->digital_outputs =
735      (uint32_t *) malloc(group->output_count * sizeof(uint32_t));
736
737    sc = check_same_bank_and_availability(
738           group_definition->digital_outputs,
739           group->output_count,
740           &group->digital_output_bank,
741           group->digital_outputs
742         );
743
744    if ( sc != RTEMS_SUCCESSFUL ) {
745      return sc;
746    }
747  }
748  else {
749    group->digital_outputs = NULL;
750  }
751
752  group->bsp_specific_pin_count = group_definition->bsp_specific_pin_count;
753
754  if ( group->bsp_specific_pin_count > 0 ) {
755    group->bsp_speficifc_pins =
756      (uint32_t *) malloc(
757                     group->bsp_specific_pin_count *
758                     sizeof(uint32_t)
759                   );
760
761    sc = check_same_bank_and_availability(
762           group_definition->bsp_specifics,
763           group->bsp_specific_pin_count,
764           &group->bsp_specific_bank,
765           group->bsp_speficifc_pins
766         );
767
768    if ( sc != RTEMS_SUCCESSFUL ) {
769      return sc;
770    }
771  }
772  else {
773    group->bsp_speficifc_pins = NULL;
774  }
775
776  /* Request the pins. */
777  sc = gpio_multi_select(
778         group_definition->digital_inputs,
779         group_definition->input_count,
780         true
781       );
782
783  if ( sc != RTEMS_SUCCESSFUL ) {
784    return RTEMS_UNSATISFIED;
785  }
786
787  sc = gpio_multi_select(
788         group_definition->digital_outputs,
789         group_definition->output_count,
790         true
791       );
792
793  if ( sc != RTEMS_SUCCESSFUL ) {
794    sc = rtems_gpio_release_multiple_pins(
795           group_definition->digital_inputs,
796           group_definition->input_count
797         );
798
799    assert ( sc == RTEMS_SUCCESSFUL );
800
801    return RTEMS_UNSATISFIED;
802  }
803
804  sc = gpio_multi_select(
805         group_definition->bsp_specifics,
806         group_definition->bsp_specific_pin_count,
807         true
808       );
809
810  if ( sc != RTEMS_SUCCESSFUL ) {
811    sc = rtems_gpio_release_multiple_pins(
812           group_definition->digital_inputs,
813           group_definition->input_count
814         );
815
816    assert ( sc == RTEMS_SUCCESSFUL );
817
818    sc = rtems_gpio_release_multiple_pins(
819           group_definition->digital_outputs,
820           group_definition->output_count
821         );
822
823    assert ( sc == RTEMS_SUCCESSFUL );
824
825    return RTEMS_UNSATISFIED;
826  }
827
828  /* Create group lock. */
829  sc = CREATE_LOCK(rtems_build_name('G', 'R', 'P', 'L'), &group->group_lock);
830
831  if ( sc != RTEMS_SUCCESSFUL ) {
832    return sc;
833  }
834
835  rtems_chain_append(&gpio_group, &group->node);
836
837  return RTEMS_SUCCESSFUL;
838}
839
840rtems_status_code rtems_gpio_write_group(uint32_t data, rtems_gpio_group *group)
841{
842  rtems_status_code sc = RTEMS_SUCCESSFUL;
843  uint32_t set_bitmask;
844  uint32_t clear_bitmask;
845  uint32_t bank;
846  uint32_t pin;
847  uint8_t i;
848
849  if ( group->output_count == 0 ) {
850    return RTEMS_NOT_DEFINED;
851  }
852
853  bank = group->digital_output_bank;
854
855  /* Acquire bank lock for the digital output pins. */
856  ACQUIRE_LOCK(gpio_bank_state[bank].lock);
857
858  /* Acquire group lock. */
859  ACQUIRE_LOCK(group->group_lock);
860
861  set_bitmask = 0;
862  clear_bitmask = 0;
863
864  for ( i = 0; i < group->output_count; ++i ) {
865    pin = group->digital_outputs[i];
866
867    if ( (data & (1 << i)) == 0 ) {
868      clear_bitmask |= (1 << pin);
869    }
870    else {
871      set_bitmask |= (1 << pin);
872    }
873  }
874
875  /* Set the logical highs. */
876  if ( set_bitmask > 0 ) {
877    sc = rtems_gpio_bsp_multi_set(bank, set_bitmask);
878
879    if ( sc != RTEMS_SUCCESSFUL ) {
880      RELEASE_LOCK(group->group_lock);
881      RELEASE_LOCK(gpio_bank_state[bank].lock);
882
883      return sc;
884    }
885  }
886
887  /* Set the logical lows. */
888  if ( clear_bitmask > 0 ) {
889    sc = rtems_gpio_bsp_multi_clear(bank, clear_bitmask);
890
891    if ( sc != RTEMS_SUCCESSFUL ) {
892      RELEASE_LOCK(group->group_lock);
893      RELEASE_LOCK(gpio_bank_state[bank].lock);
894
895      return sc;
896    }
897  }
898
899  RELEASE_LOCK(group->group_lock);
900  RELEASE_LOCK(gpio_bank_state[bank].lock);
901
902  return RTEMS_SUCCESSFUL;
903}
904
905uint32_t rtems_gpio_read_group(rtems_gpio_group *group)
906{
907  uint32_t read_bitmask;
908  uint32_t bank;
909  uint32_t pin;
910  uint32_t rv;
911  uint8_t i;
912
913  if ( group->input_count == 0 ) {
914    return 0xDEADBEEF;
915  }
916
917  bank = group->digital_input_bank;
918
919  /* Acquire bank lock for the digital input pins. */
920  ACQUIRE_LOCK(gpio_bank_state[bank].lock);
921
922  /* Acquire group lock. */
923  ACQUIRE_LOCK(group->group_lock);
924
925  read_bitmask = 0;
926
927  for ( i = 0; i < group->input_count; ++i ) {
928    pin = group->digital_inputs[i];
929
930    read_bitmask |= (1 << pin);
931  }
932
933  rv = rtems_gpio_bsp_multi_read(bank, read_bitmask);
934
935  RELEASE_LOCK(gpio_bank_state[bank].lock);
936  RELEASE_LOCK(group->group_lock);
937
938  return rv;
939}
940
941rtems_status_code rtems_gpio_group_bsp_specific_operation(
942  rtems_gpio_group *group,
943  void *arg
944) {
945  rtems_status_code sc;
946  uint32_t bank;
947
948  if ( group->bsp_specific_pin_count == 0 ) {
949    return RTEMS_NOT_DEFINED;
950  }
951
952  bank = group->bsp_specific_bank;
953
954  /* Acquire bank lock for the BSP specific function pins. */
955  ACQUIRE_LOCK(gpio_bank_state[bank].lock);
956
957  /* Acquire group lock. */
958  ACQUIRE_LOCK(group->group_lock);
959
960  sc = rtems_gpio_bsp_specific_group_operation(
961         bank,
962         group->bsp_speficifc_pins,
963         group->bsp_specific_pin_count,
964         arg
965       );
966
967  RELEASE_LOCK(gpio_bank_state[bank].lock);
968  RELEASE_LOCK(group->group_lock);
969
970  return sc;
971}
972
973rtems_status_code rtems_gpio_multi_select(
974  const rtems_gpio_pin_conf *pins,
975  uint8_t pin_count
976) {
977  return gpio_multi_select(pins, pin_count, false);
978}
979
980rtems_status_code rtems_gpio_request_configuration(
981  const rtems_gpio_pin_conf *conf
982) {
983  rtems_status_code sc;
984
985  sc = rtems_gpio_request_pin(
986         conf->pin_number,
987         conf->function,
988         conf->output_enabled,
989         conf->logic_invert,
990         conf->bsp_specific
991       );
992
993  if ( sc != RTEMS_SUCCESSFUL ) {
994#if defined(DEBUG)
995    printk("rtems_gpio_request_pin failed with status code %d\n",sc);
996#endif
997
998    return RTEMS_UNSATISFIED;
999  }
1000
1001  return setup_resistor_and_interrupt_configuration(
1002           conf->pin_number,
1003           conf->pull_mode,
1004           conf->interrupt
1005         );
1006}
1007
1008rtems_status_code rtems_gpio_update_configuration(
1009  const rtems_gpio_pin_conf *conf
1010) {
1011  rtems_gpio_interrupt_configuration *interrupt_conf;
1012  gpio_pin_interrupt_state *interrupt_state;
1013  rtems_status_code sc;
1014  uint32_t bank;
1015
1016  if ( conf->pin_number < 0 || conf->pin_number >= BSP_GPIO_PIN_COUNT ) {
1017    return RTEMS_INVALID_ID;
1018  }
1019
1020  bank = BANK_NUMBER(conf->pin_number);
1021
1022  ACQUIRE_LOCK(gpio_bank_state[bank].lock);
1023
1024  /* If the pin is not being used returns with an error. */
1025  if ( gpio_pin_state[conf->pin_number].pin_function == NOT_USED ) {
1026    RELEASE_LOCK(gpio_bank_state[bank].lock);
1027
1028    return RTEMS_NOT_CONFIGURED;
1029  }
1030
1031  sc = rtems_gpio_resistor_mode(conf->pin_number, conf->pull_mode);
1032
1033  if ( sc != RTEMS_SUCCESSFUL ) {
1034#if defined(DEBUG)
1035    printk("rtems_gpio_resistor_mode failed with status code %d\n", sc);
1036#endif
1037
1038    return RTEMS_UNSATISFIED;
1039  }
1040
1041  interrupt_conf = (rtems_gpio_interrupt_configuration *) conf->interrupt;
1042
1043  interrupt_state = gpio_pin_state[conf->pin_number].interrupt_state;
1044
1045  if ( interrupt_state != NULL ) {
1046    sc = rtems_gpio_disable_interrupt(conf->pin_number);
1047
1048    if ( sc != RTEMS_SUCCESSFUL ) {
1049      RELEASE_LOCK(gpio_bank_state[bank].lock);
1050
1051#if defined(DEBUG)
1052      printk(
1053        "rtems_gpio_disable_interrupt failed with status code %d\n",
1054        sc
1055      );
1056#endif
1057
1058      return RTEMS_UNSATISFIED;
1059    }
1060  }
1061
1062  if ( interrupt_conf != NULL ) {
1063    sc = rtems_gpio_enable_interrupt(
1064           conf->pin_number,
1065           interrupt_conf->active_interrupt,
1066           interrupt_conf->handler_flag,
1067           interrupt_conf->threaded_interrupts,
1068           interrupt_conf->handler,
1069           interrupt_conf->arg
1070         );
1071
1072    if ( sc != RTEMS_SUCCESSFUL ) {
1073      RELEASE_LOCK(gpio_bank_state[bank].lock);
1074
1075#if defined(DEBUG)
1076      printk(
1077        "rtems_gpio_enable_interrupt failed with status code %d\n",
1078        sc
1079      );
1080#endif
1081
1082      return RTEMS_UNSATISFIED;
1083    }
1084  }
1085
1086  if ( interrupt_conf != NULL && interrupt_state != NULL ) {
1087    if (
1088        interrupt_conf->debounce_clock_tick_interval !=
1089        interrupt_state->debouncing_tick_count
1090    ) {
1091      interrupt_state->debouncing_tick_count =
1092        interrupt_conf->debounce_clock_tick_interval;
1093
1094      interrupt_state->last_isr_tick = 0;
1095    }
1096  }
1097
1098  RELEASE_LOCK(gpio_bank_state[bank].lock);
1099
1100  return RTEMS_SUCCESSFUL;
1101}
1102
1103rtems_status_code rtems_gpio_multi_set(
1104 uint32_t *pin_numbers,
1105 uint32_t pin_count
1106) {
1107  rtems_status_code sc;
1108  uint32_t bitmask;
1109  uint32_t bank;
1110
1111  sc = get_pin_bitmask(pin_numbers, pin_count, &bank, &bitmask, DIGITAL_OUTPUT);
1112
1113  if ( sc != RTEMS_SUCCESSFUL ) {
1114    return sc;
1115  }
1116
1117  ACQUIRE_LOCK(gpio_bank_state[bank].lock);
1118
1119  sc = rtems_gpio_bsp_multi_set(bank, bitmask);
1120
1121  RELEASE_LOCK(gpio_bank_state[bank].lock);
1122
1123  return sc;
1124}
1125
1126rtems_status_code rtems_gpio_multi_clear(
1127  uint32_t *pin_numbers,
1128  uint32_t pin_count
1129) {
1130  rtems_status_code sc;
1131  uint32_t bitmask;
1132  uint32_t bank;
1133
1134  sc = get_pin_bitmask(pin_numbers, pin_count, &bank, &bitmask, DIGITAL_OUTPUT);
1135
1136  if ( sc != RTEMS_SUCCESSFUL ) {
1137    return sc;
1138  }
1139
1140  ACQUIRE_LOCK(gpio_bank_state[bank].lock);
1141
1142  sc = rtems_gpio_bsp_multi_clear(bank, bitmask);
1143
1144  RELEASE_LOCK(gpio_bank_state[bank].lock);
1145
1146  return sc;
1147}
1148
1149uint32_t rtems_gpio_multi_read(
1150  uint32_t *pin_numbers,
1151  uint32_t pin_count
1152) {
1153  rtems_status_code sc;
1154  uint32_t bitmask;
1155  uint32_t bank;
1156  uint32_t rv;
1157
1158  sc = get_pin_bitmask(pin_numbers, pin_count, &bank, &bitmask, DIGITAL_INPUT);
1159
1160  if ( sc != RTEMS_SUCCESSFUL ) {
1161    return 0xDEADBEEF;
1162  }
1163
1164  ACQUIRE_LOCK(gpio_bank_state[bank].lock);
1165
1166  rv = rtems_gpio_bsp_multi_read(bank, bitmask);
1167
1168  RELEASE_LOCK(gpio_bank_state[bank].lock);
1169
1170  return rv;
1171}
1172
1173rtems_status_code rtems_gpio_set(uint32_t pin_number)
1174{
1175  rtems_status_code sc;
1176  uint32_t bank;
1177  uint32_t pin;
1178
1179  if ( pin_number < 0 || pin_number >= BSP_GPIO_PIN_COUNT ) {
1180    return RTEMS_INVALID_ID;
1181  }
1182
1183  bank = BANK_NUMBER(pin_number);
1184  pin = PIN_NUMBER(pin_number);
1185
1186  ACQUIRE_LOCK(gpio_bank_state[bank].lock);
1187
1188  if (
1189      gpio_pin_state[pin_number].pin_function != DIGITAL_OUTPUT ||
1190      gpio_pin_state[pin_number].on_group
1191  ) {
1192    RELEASE_LOCK(gpio_bank_state[bank].lock);
1193
1194#if defined(DEBUG)
1195    printk("Can only set digital output pins\n");
1196#endif
1197
1198    return RTEMS_NOT_CONFIGURED;
1199  }
1200
1201  if ( gpio_pin_state[pin_number].logic_invert ) {
1202    sc = rtems_gpio_bsp_clear(bank, pin);
1203  }
1204  else {
1205    sc = rtems_gpio_bsp_set(bank, pin);
1206  }
1207
1208  RELEASE_LOCK(gpio_bank_state[bank].lock);
1209
1210  return sc;
1211}
1212
1213rtems_status_code rtems_gpio_clear(uint32_t pin_number)
1214{
1215  rtems_status_code sc;
1216  uint32_t bank;
1217  uint32_t pin;
1218
1219  if ( pin_number < 0 || pin_number >= BSP_GPIO_PIN_COUNT ) {
1220    return RTEMS_INVALID_ID;
1221  }
1222
1223  bank = BANK_NUMBER(pin_number);
1224  pin = PIN_NUMBER(pin_number);
1225
1226  ACQUIRE_LOCK(gpio_bank_state[bank].lock);
1227
1228  if (
1229      gpio_pin_state[pin_number].pin_function != DIGITAL_OUTPUT ||
1230      gpio_pin_state[pin_number].on_group
1231  ) {
1232    RELEASE_LOCK(gpio_bank_state[bank].lock);
1233
1234#if defined(DEBUG)
1235    printk("Can only clear digital output pins\n");
1236#endif
1237
1238    return RTEMS_NOT_CONFIGURED;
1239  }
1240
1241  if ( gpio_pin_state[pin_number].logic_invert ) {
1242    sc = rtems_gpio_bsp_set(bank, pin);
1243  }
1244  else {
1245    sc = rtems_gpio_bsp_clear(bank, pin);
1246  }
1247
1248  RELEASE_LOCK(gpio_bank_state[bank].lock);
1249
1250  return sc;
1251}
1252
1253uint8_t rtems_gpio_get_value(uint32_t pin_number)
1254{
1255  uint32_t bank;
1256  uint32_t pin;
1257  int rv;
1258
1259  if ( pin_number < 0 || pin_number >= BSP_GPIO_PIN_COUNT ) {
1260    return -1;
1261  }
1262
1263  bank = BANK_NUMBER(pin_number);
1264  pin = PIN_NUMBER(pin_number);
1265
1266  ACQUIRE_LOCK(gpio_bank_state[bank].lock);
1267
1268  if (
1269      gpio_pin_state[pin_number].pin_function != DIGITAL_INPUT ||
1270      gpio_pin_state[pin_number].on_group
1271  ) {
1272    RELEASE_LOCK(gpio_bank_state[bank].lock);
1273
1274#if defined(DEBUG)
1275    printk("Can only read digital input pins\n");
1276#endif
1277
1278    return -1;
1279  }
1280
1281  rv = rtems_gpio_bsp_get_value(bank, pin);
1282
1283  if ( gpio_pin_state[pin_number].logic_invert && rv > 0 ) {
1284    RELEASE_LOCK(gpio_bank_state[bank].lock);
1285
1286    return !rv;
1287  }
1288
1289  RELEASE_LOCK(gpio_bank_state[bank].lock);
1290
1291  return ( rv > 0 ) ? 1 : rv;
1292}
1293
1294rtems_status_code rtems_gpio_request_pin(
1295  uint32_t pin_number,
1296  rtems_gpio_function function,
1297  bool output_enabled,
1298  bool logic_invert,
1299  void *bsp_specific
1300) {
1301  rtems_gpio_specific_data *bsp_data;
1302  rtems_status_code sc = RTEMS_SUCCESSFUL;
1303  uint32_t bank;
1304  uint32_t pin;
1305
1306  if ( pin_number < 0 || pin_number >= BSP_GPIO_PIN_COUNT ) {
1307    return RTEMS_INVALID_ID;
1308  }
1309
1310  bank = BANK_NUMBER(pin_number);
1311  pin = PIN_NUMBER(pin_number);
1312
1313  ACQUIRE_LOCK(gpio_bank_state[bank].lock);
1314
1315  /* If the pin is already being used returns with an error. */
1316  if ( gpio_pin_state[pin_number].pin_function != NOT_USED ) {
1317    RELEASE_LOCK(gpio_bank_state[bank].lock);
1318
1319    return RTEMS_RESOURCE_IN_USE;
1320  }
1321
1322  switch ( function ) {
1323    case DIGITAL_INPUT:
1324      sc = rtems_gpio_bsp_select_input(bank, pin, bsp_specific);
1325      break;
1326    case DIGITAL_OUTPUT:
1327      sc = rtems_gpio_bsp_select_output(bank, pin, bsp_specific);
1328      break;
1329    case BSP_SPECIFIC:
1330      bsp_data = (rtems_gpio_specific_data *) bsp_specific;
1331
1332      if ( bsp_data == NULL ) {
1333        RELEASE_LOCK(gpio_bank_state[bank].lock);
1334
1335        return RTEMS_UNSATISFIED;
1336      }
1337
1338      sc = rtems_bsp_select_specific_io(
1339             bank,
1340             pin,
1341             bsp_data->io_function,
1342             bsp_data->pin_data
1343           );
1344      break;
1345    case NOT_USED:
1346    default:
1347      RELEASE_LOCK(gpio_bank_state[bank].lock);
1348
1349      return RTEMS_NOT_DEFINED;
1350  }
1351
1352  if ( sc != RTEMS_SUCCESSFUL ) {
1353    RELEASE_LOCK(gpio_bank_state[bank].lock);
1354
1355    return sc;
1356  }
1357
1358  /* If the function was successfully assigned to the pin,
1359   * record that information on the gpio_pin_state structure. */
1360  gpio_pin_state[pin_number].pin_function = function;
1361  gpio_pin_state[pin_number].logic_invert = logic_invert;
1362
1363  if ( function == DIGITAL_OUTPUT ) {
1364    if ( output_enabled == true ) {
1365      sc = rtems_gpio_bsp_set(bank, pin);
1366    }
1367    else {
1368      sc = rtems_gpio_bsp_clear(bank, pin);
1369    }
1370  }
1371
1372  RELEASE_LOCK(gpio_bank_state[bank].lock);
1373
1374  return sc;
1375}
1376
1377rtems_status_code rtems_gpio_resistor_mode(
1378  uint32_t pin_number,
1379  rtems_gpio_pull_mode mode
1380) {
1381  rtems_status_code sc;
1382  uint32_t bank;
1383  uint32_t pin;
1384
1385  if ( pin_number < 0 || pin_number >= BSP_GPIO_PIN_COUNT ) {
1386    return RTEMS_INVALID_ID;
1387  }
1388
1389  bank = BANK_NUMBER(pin_number);
1390  pin = PIN_NUMBER(pin_number);
1391
1392  ACQUIRE_LOCK(gpio_bank_state[bank].lock);
1393
1394  /* If the desired actuation mode is already set, silently exits.
1395   * The NO_PULL_RESISTOR is a special case, as some platforms have
1396   * pull-up resistors enabled on startup, so this state may have to
1397   * be reinforced in the hardware. */
1398  if (
1399      gpio_pin_state[pin_number].resistor_mode == mode &&
1400      mode != NO_PULL_RESISTOR
1401  ) {
1402    RELEASE_LOCK(gpio_bank_state[bank].lock);
1403
1404    return RTEMS_SUCCESSFUL;
1405  }
1406
1407  sc = rtems_gpio_bsp_set_resistor_mode(bank, pin, mode);
1408
1409  if ( sc != RTEMS_SUCCESSFUL ) {
1410    RELEASE_LOCK(gpio_bank_state[bank].lock);
1411
1412    return sc;
1413  }
1414
1415  gpio_pin_state[pin_number].resistor_mode = mode;
1416
1417  RELEASE_LOCK(gpio_bank_state[bank].lock);
1418
1419  return RTEMS_SUCCESSFUL;
1420}
1421
1422rtems_status_code rtems_gpio_release_pin(uint32_t pin_number)
1423{
1424  gpio_pin_interrupt_state *interrupt_state;
1425  rtems_status_code sc;
1426  uint32_t bank;
1427
1428  if ( pin_number < 0 || pin_number >= BSP_GPIO_PIN_COUNT ) {
1429    return RTEMS_INVALID_ID;
1430  }
1431
1432  bank = BANK_NUMBER(pin_number);
1433
1434  ACQUIRE_LOCK(gpio_bank_state[bank].lock);
1435
1436  interrupt_state = gpio_pin_state[pin_number].interrupt_state;
1437
1438  /* If the pin has an enabled interrupt then remove the handler(s)
1439   * and disable interrupts on that pin. */
1440  if ( interrupt_state != NULL ) {
1441    sc = rtems_gpio_disable_interrupt(pin_number);
1442
1443    if ( sc != RTEMS_SUCCESSFUL ) {
1444      RELEASE_LOCK(gpio_bank_state[bank].lock);
1445
1446      return sc;
1447    }
1448  }
1449
1450  gpio_pin_state[pin_number].pin_function = NOT_USED;
1451  gpio_pin_state[pin_number].resistor_mode = NO_PULL_RESISTOR;
1452  gpio_pin_state[pin_number].logic_invert = false;
1453  gpio_pin_state[pin_number].on_group = false;
1454
1455  RELEASE_LOCK(gpio_bank_state[bank].lock);
1456
1457  return RTEMS_SUCCESSFUL;
1458}
1459
1460rtems_status_code rtems_gpio_release_configuration(
1461  const rtems_gpio_pin_conf *conf
1462) {
1463  if ( conf == NULL ) {
1464    return RTEMS_UNSATISFIED;
1465  }
1466
1467  return rtems_gpio_release_pin(conf->pin_number);
1468}
1469
1470rtems_status_code rtems_gpio_release_multiple_pins(
1471  const rtems_gpio_pin_conf *pins,
1472  uint32_t pin_count
1473) {
1474  rtems_status_code sc;
1475  uint32_t i;
1476
1477  if ( pins == NULL ) {
1478    return RTEMS_UNSATISFIED;
1479  }
1480
1481  for ( i = 0; i < pin_count; ++i ) {
1482    sc = rtems_gpio_release_pin(pins[i].pin_number);
1483
1484    if ( sc != RTEMS_SUCCESSFUL ) {
1485      return sc;
1486    }
1487  }
1488
1489  return RTEMS_SUCCESSFUL;
1490}
1491
1492rtems_status_code rtems_gpio_release_pin_group(
1493  rtems_gpio_group *group
1494) {
1495  rtems_status_code sc;
1496  uint8_t i;
1497
1498  ACQUIRE_LOCK(group->group_lock);
1499
1500  sc = rtems_semaphore_flush(group->group_lock);
1501
1502  if ( sc != RTEMS_SUCCESSFUL ) {
1503    RELEASE_LOCK(group->group_lock);
1504
1505    return sc;
1506  }
1507
1508  RELEASE_LOCK(group->group_lock);
1509
1510  /* Deletes the group lock. */
1511  sc = rtems_semaphore_delete(group->group_lock);
1512
1513  if ( sc != RTEMS_SUCCESSFUL ) {
1514    return sc;
1515  }
1516
1517  /* Pin releasing. */
1518  for ( i = 0; i < group->input_count; ++i ) {
1519    sc = rtems_gpio_release_pin(group->digital_inputs[i]);
1520
1521    if ( sc != RTEMS_SUCCESSFUL ) {
1522      return sc;
1523    }
1524  }
1525
1526  if ( group->input_count > 0 ) {
1527    free(group->digital_inputs);
1528  }
1529
1530  for ( i = 0; i < group->output_count; ++i ) {
1531    sc = rtems_gpio_release_pin(group->digital_outputs[i]);
1532
1533    if ( sc != RTEMS_SUCCESSFUL ) {
1534      return sc;
1535    }
1536  }
1537
1538  if ( group->output_count > 0 ) {
1539    free(group->digital_outputs);
1540  }
1541
1542  for ( i = 0; i < group->bsp_specific_pin_count; ++i ) {
1543    sc = rtems_gpio_release_pin(group->bsp_speficifc_pins[i]);
1544
1545    if ( sc != RTEMS_SUCCESSFUL ) {
1546      return sc;
1547    }
1548  }
1549
1550  if ( group->bsp_specific_pin_count > 0 ) {
1551    free(group->bsp_speficifc_pins);
1552  }
1553
1554  rtems_chain_extract(&group->node);
1555
1556  free(group);
1557
1558  return RTEMS_SUCCESSFUL;
1559}
1560
1561rtems_status_code rtems_gpio_debounce_switch(uint32_t pin_number, int ticks)
1562{
1563  gpio_pin_interrupt_state *interrupt_state;
1564  uint32_t bank;
1565
1566  if ( pin_number < 0 || pin_number >= BSP_GPIO_PIN_COUNT ) {
1567    return RTEMS_INVALID_ID;
1568  }
1569
1570  bank = BANK_NUMBER(pin_number);
1571
1572  ACQUIRE_LOCK(gpio_bank_state[bank].lock);
1573
1574  interrupt_state = gpio_pin_state[pin_number].interrupt_state;
1575
1576  /* If no interrupt configuration is set for this pin, or if the pin is
1577   * not set as a digital input, or the pin in on a group. */
1578  if (
1579      interrupt_state == NULL ||
1580      gpio_pin_state[pin_number].pin_function != DIGITAL_INPUT ||
1581      gpio_pin_state[pin_number].on_group
1582  ) {
1583    RELEASE_LOCK(gpio_bank_state[bank].lock);
1584
1585    return RTEMS_NOT_CONFIGURED;
1586  }
1587
1588  interrupt_state->debouncing_tick_count = ticks;
1589  interrupt_state->last_isr_tick = 0;
1590
1591  RELEASE_LOCK(gpio_bank_state[bank].lock);
1592
1593  return RTEMS_SUCCESSFUL;
1594}
1595
1596rtems_status_code rtems_gpio_interrupt_handler_install(
1597  uint32_t pin_number,
1598  rtems_gpio_irq_state (*handler) (void *arg),
1599  void *arg
1600) {
1601  gpio_pin_interrupt_state *interrupt_state;
1602  gpio_handler_node *isr_node;
1603  uint32_t bank;
1604
1605  if ( pin_number < 0 || pin_number >= BSP_GPIO_PIN_COUNT ) {
1606    return RTEMS_INVALID_ID;
1607  }
1608
1609  bank = BANK_NUMBER(pin_number);
1610
1611  ACQUIRE_LOCK(gpio_bank_state[bank].lock);
1612
1613  interrupt_state = gpio_pin_state[pin_number].interrupt_state;
1614
1615  /* If no interrupt configuration is set for this pin. */
1616   if ( interrupt_state == NULL ) {
1617    RELEASE_LOCK(gpio_bank_state[bank].lock);
1618
1619    return RTEMS_NOT_CONFIGURED;
1620  }
1621
1622  /* If the current pin has no interrupt enabled
1623   * then it does not need an handler. */
1624  if ( interrupt_state->active_interrupt == NONE ) {
1625    RELEASE_LOCK(gpio_bank_state[bank].lock);
1626
1627    return RTEMS_NOT_CONFIGURED;
1628  }
1629  /* If the pin already has an enabled interrupt but the installed handler
1630   * is set as unique. */
1631  else if (
1632           interrupt_state->handler_flag == UNIQUE_HANDLER &&
1633           !rtems_chain_is_empty(&interrupt_state->handler_chain)
1634  ) {
1635    RELEASE_LOCK(gpio_bank_state[bank].lock);
1636
1637    return RTEMS_TOO_MANY;
1638  }
1639
1640  /* Update the pin's ISR list. */
1641  isr_node = (gpio_handler_node *) malloc(sizeof(gpio_handler_node));
1642
1643  if ( isr_node == NULL ) {
1644    RELEASE_LOCK(gpio_bank_state[bank].lock);
1645
1646    return RTEMS_NO_MEMORY;
1647  }
1648
1649  isr_node->handler = handler;
1650  isr_node->arg = arg;
1651
1652  rtems_chain_append(&interrupt_state->handler_chain, &isr_node->node);
1653
1654  RELEASE_LOCK(gpio_bank_state[bank].lock);
1655
1656  return RTEMS_SUCCESSFUL;
1657}
1658
1659rtems_status_code rtems_gpio_enable_interrupt(
1660  uint32_t pin_number,
1661  rtems_gpio_interrupt interrupt,
1662  rtems_gpio_handler_flag flag,
1663  bool threaded_handling,
1664  rtems_gpio_irq_state (*handler) (void *arg),
1665  void *arg
1666) {
1667  gpio_pin_interrupt_state *interrupt_state;
1668  rtems_vector_number vector;
1669  rtems_status_code sc;
1670  uint32_t bank;
1671  uint32_t pin;
1672
1673  if ( pin_number < 0 || pin_number >= BSP_GPIO_PIN_COUNT ) {
1674    return RTEMS_INVALID_ID;
1675  }
1676
1677  bank = BANK_NUMBER(pin_number);
1678  pin = PIN_NUMBER(pin_number);
1679
1680  vector = rtems_gpio_bsp_get_vector(bank);
1681
1682  ACQUIRE_LOCK(gpio_bank_state[bank].lock);
1683
1684  if (
1685      gpio_pin_state[pin_number].pin_function != DIGITAL_INPUT ||
1686      gpio_pin_state[pin_number].on_group
1687  ) {
1688    RELEASE_LOCK(gpio_bank_state[bank].lock);
1689
1690    return RTEMS_NOT_CONFIGURED;
1691  }
1692
1693  /* If the bank already has at least one interrupt enabled on a pin,
1694   * then new interrupts on this bank must follow the current
1695   * threading policy. */
1696  if (
1697      gpio_bank_state[bank].interrupt_counter > 0 &&
1698      gpio_bank_state[bank].threaded_interrupts != threaded_handling
1699  ) {
1700    RELEASE_LOCK(gpio_bank_state[bank].lock);
1701
1702    return RTEMS_RESOURCE_IN_USE;
1703  }
1704
1705  interrupt_state = gpio_pin_state[pin_number].interrupt_state;
1706
1707  /* If an interrupt configuration is already in place for this pin. */
1708  if ( interrupt_state != NULL ) {
1709    RELEASE_LOCK(gpio_bank_state[bank].lock);
1710
1711    return RTEMS_RESOURCE_IN_USE;
1712  }
1713
1714  gpio_pin_state[pin_number].interrupt_state =
1715    (gpio_pin_interrupt_state *) malloc(sizeof(gpio_pin_interrupt_state));
1716
1717  if ( gpio_pin_state[pin_number].interrupt_state == NULL ) {
1718    return RTEMS_NO_MEMORY;
1719  }
1720
1721  gpio_pin_state[pin_number].interrupt_state->active_interrupt = NONE;
1722  gpio_pin_state[pin_number].interrupt_state->debouncing_tick_count = 0;
1723  gpio_pin_state[pin_number].interrupt_state->last_isr_tick = 0;
1724
1725  rtems_chain_initialize_empty(
1726    &gpio_pin_state[pin_number].interrupt_state->handler_chain
1727  );
1728
1729  interrupt_state = gpio_pin_state[pin_number].interrupt_state;
1730
1731  interrupt_state->active_interrupt = interrupt;
1732  interrupt_state->handler_flag = flag;
1733
1734  /* Installs the interrupt handler on the GPIO pin
1735   * tracking structure. */
1736  sc = rtems_gpio_interrupt_handler_install(pin_number, handler, arg);
1737
1738  if ( sc != RTEMS_SUCCESSFUL ) {
1739    RELEASE_LOCK(gpio_bank_state[bank].lock);
1740
1741    return RTEMS_UNSATISFIED;
1742  }
1743
1744  if ( threaded_handling ) {
1745    if (
1746        _Atomic_Load_uint(&threaded_interrupt_counter, ATOMIC_ORDER_RELAXED) == 0
1747    ) {
1748      sc = rtems_interrupt_server_initialize(
1749             INTERRUPT_SERVER_PRIORITY,
1750             INTERRUPT_SERVER_STACK_SIZE,
1751             INTERRUPT_SERVER_MODES,
1752             INTERRUPT_SERVER_ATTRIBUTES,
1753             NULL
1754           );
1755
1756      if ( sc != RTEMS_SUCCESSFUL ) {
1757        RELEASE_LOCK(gpio_bank_state[bank].lock);
1758
1759        return RTEMS_UNSATISFIED;
1760      }
1761    }
1762
1763    if ( gpio_bank_state[bank].interrupt_counter == 0 ) {
1764      sc = rtems_interrupt_server_handler_install(
1765             RTEMS_ID_NONE,
1766             vector,
1767             "GPIO_HANDLER",
1768             RTEMS_INTERRUPT_UNIQUE,
1769             (rtems_interrupt_handler) generic_bank_isr,
1770             &gpio_bank_state[bank].bank_number
1771           );
1772
1773      if ( sc != RTEMS_SUCCESSFUL ) {
1774        RELEASE_LOCK(gpio_bank_state[bank].lock);
1775
1776        return RTEMS_UNSATISFIED;
1777      }
1778
1779      _Atomic_Fetch_add_uint(
1780        &threaded_interrupt_counter,
1781        1,
1782        ATOMIC_ORDER_RELAXED
1783      );
1784    }
1785  }
1786  else if ( gpio_bank_state[bank].interrupt_counter == 0 ) {
1787    sc = rtems_interrupt_handler_install(
1788           vector,
1789           "GPIO_HANDLER",
1790           RTEMS_INTERRUPT_UNIQUE,
1791           (rtems_interrupt_handler) generic_bank_isr,
1792           &gpio_bank_state[bank].bank_number
1793         );
1794
1795    if ( sc != RTEMS_SUCCESSFUL ) {
1796      RELEASE_LOCK(gpio_bank_state[bank].lock);
1797
1798      return RTEMS_UNSATISFIED;
1799    }
1800  }
1801
1802  sc = rtems_bsp_enable_interrupt(bank, pin, interrupt);
1803
1804  if ( sc != RTEMS_SUCCESSFUL ) {
1805    RELEASE_LOCK(gpio_bank_state[bank].lock);
1806
1807    return RTEMS_UNSATISFIED;
1808  }
1809
1810  /* If this was the first interrupt enabled on this GPIO bank,
1811   * record the threading policy. */
1812  if ( gpio_bank_state[bank].interrupt_counter == 0 ) {
1813    gpio_bank_state[bank].threaded_interrupts = threaded_handling;
1814  }
1815
1816  ++gpio_bank_state[bank].interrupt_counter;
1817
1818  RELEASE_LOCK(gpio_bank_state[bank].lock);
1819
1820  return RTEMS_SUCCESSFUL;
1821}
1822
1823rtems_status_code rtems_gpio_interrupt_handler_remove(
1824  uint32_t pin_number,
1825  rtems_gpio_irq_state (*handler) (void *arg),
1826  void *arg
1827) {
1828  gpio_pin_interrupt_state *interrupt_state;
1829  rtems_chain_control *handler_list;
1830  rtems_chain_node *node;
1831  rtems_chain_node *next_node;
1832  gpio_handler_node *isr_node;
1833  uint32_t bank;
1834
1835  if ( pin_number < 0 || pin_number >= BSP_GPIO_PIN_COUNT ) {
1836    return RTEMS_INVALID_ID;
1837  }
1838
1839  bank = BANK_NUMBER(pin_number);
1840
1841  ACQUIRE_LOCK(gpio_bank_state[bank].lock);
1842
1843  interrupt_state = gpio_pin_state[pin_number].interrupt_state;
1844
1845  /* If no interrupt configuration is set for this pin. */
1846  if ( interrupt_state == NULL ) {
1847    RELEASE_LOCK(gpio_bank_state[bank].lock);
1848
1849    return RTEMS_NOT_CONFIGURED;
1850  }
1851
1852  handler_list = &interrupt_state->handler_chain;
1853
1854  node = rtems_chain_first(handler_list);
1855
1856  /* If the first node is also the last handler for this pin, disables
1857   * interrupts on this pin as there will be no handler to handle it.
1858   * This also removes the remaining handler. */
1859  if ( rtems_chain_is_last(node) ) {
1860    RELEASE_LOCK(gpio_bank_state[bank].lock);
1861
1862    return rtems_gpio_disable_interrupt(pin_number);
1863  }
1864
1865  /* Iterate the ISR list. */
1866  while ( !rtems_chain_is_tail(handler_list, node) ) {
1867    isr_node = (gpio_handler_node *) node;
1868
1869    next_node = node->next;
1870
1871    if ( isr_node->handler == handler && isr_node->arg == arg ) {
1872      rtems_chain_extract(node);
1873
1874      break;
1875    }
1876
1877    node = next_node;
1878  }
1879
1880  RELEASE_LOCK(gpio_bank_state[bank].lock);
1881
1882  return RTEMS_SUCCESSFUL;
1883}
1884
1885rtems_status_code rtems_gpio_disable_interrupt(uint32_t pin_number)
1886{
1887  gpio_pin_interrupt_state *interrupt_state;
1888  rtems_chain_control *handler_list;
1889  rtems_chain_node *node;
1890  rtems_chain_node *next_node;
1891  rtems_vector_number vector;
1892  rtems_status_code sc;
1893  uint32_t bank;
1894  uint32_t pin;
1895
1896  if ( pin_number < 0 || pin_number >= BSP_GPIO_PIN_COUNT ) {
1897    return RTEMS_INVALID_ID;
1898  }
1899
1900  bank = BANK_NUMBER(pin_number);
1901  pin = PIN_NUMBER(pin_number);
1902
1903  vector = rtems_gpio_bsp_get_vector(bank);
1904
1905  ACQUIRE_LOCK(gpio_bank_state[bank].lock);
1906
1907  interrupt_state = gpio_pin_state[pin_number].interrupt_state;
1908
1909  /* If no interrupt configuration is set for this pin. */
1910  if ( interrupt_state == NULL ) {
1911    RELEASE_LOCK(gpio_bank_state[bank].lock);
1912
1913    return RTEMS_NOT_CONFIGURED;
1914  }
1915
1916  sc = rtems_bsp_disable_interrupt(bank, pin, interrupt_state->active_interrupt);
1917
1918  if ( sc != RTEMS_SUCCESSFUL ) {
1919    RELEASE_LOCK(gpio_bank_state[bank].lock);
1920
1921    return RTEMS_UNSATISFIED;
1922  }
1923
1924  interrupt_state->active_interrupt = NONE;
1925
1926  handler_list = &interrupt_state->handler_chain;
1927
1928  node = rtems_chain_first(handler_list);
1929
1930  /* Iterate the ISR list. */
1931  while ( !rtems_chain_is_tail(handler_list, node) ) {
1932    next_node = node->next;
1933
1934    rtems_chain_extract(node);
1935
1936    node = next_node;
1937  }
1938
1939  /* If this is the last GPIO interrupt are left in this bank,
1940   * removes the handler. */
1941  if ( gpio_bank_state[bank].interrupt_counter == 1 ) {
1942    if ( gpio_bank_state[bank].threaded_interrupts ) {
1943      sc = rtems_interrupt_server_handler_remove(
1944             RTEMS_ID_NONE,
1945             vector,
1946             (rtems_interrupt_handler) generic_bank_isr,
1947             &gpio_bank_state[bank].bank_number
1948           );
1949    }
1950    else {
1951      sc = rtems_interrupt_handler_remove(
1952             vector,
1953             (rtems_interrupt_handler) generic_bank_isr,
1954             &gpio_bank_state[bank].bank_number
1955           );
1956    }
1957
1958    if ( sc != RTEMS_SUCCESSFUL ) {
1959      RELEASE_LOCK(gpio_bank_state[bank].lock);
1960
1961      return RTEMS_UNSATISFIED;
1962    }
1963  }
1964
1965  /* Free the pin's interrupt state structure. */
1966  free(interrupt_state);
1967
1968  --gpio_bank_state[bank].interrupt_counter;
1969
1970  if ( gpio_bank_state[bank].threaded_interrupts ) {
1971    _Atomic_Fetch_sub_uint(&threaded_interrupt_counter, 1, ATOMIC_ORDER_RELAXED);
1972  }
1973
1974  RELEASE_LOCK(gpio_bank_state[bank].lock);
1975
1976  return RTEMS_SUCCESSFUL;
1977}
Note: See TracBrowser for help on using the repository browser.