source: rtems/c/src/lib/libbsp/shared/gpio.c @ 5c337d7e

5
Last change on this file since 5c337d7e was 5c337d7e, checked in by Sudarshan Rajagopalan <sudarshan.rajagopalan@…>, on 10/21/15 at 15:33:44

Fixes GPIO APIs Naming Convention and Comments

Closes #2435.

  • Property mode set to 100644
File size: 47.5 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 GPIO_INPUT_ERROR;
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 GPIO_INPUT_ERROR;
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
1253int rtems_gpio_get_value(uint32_t pin_number)
1254{
1255  uint32_t bank;
1256  uint32_t pin;
1257  uint32_t 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 ( rv == GPIO_INPUT_ERROR ) {
1284    RELEASE_LOCK(gpio_bank_state[bank].lock);
1285
1286    return -1;
1287  }
1288
1289  if ( gpio_pin_state[pin_number].logic_invert ) {
1290    RELEASE_LOCK(gpio_bank_state[bank].lock);
1291
1292    return !rv;
1293  }
1294
1295  RELEASE_LOCK(gpio_bank_state[bank].lock);
1296
1297  return rv > 0;
1298}
1299
1300rtems_status_code rtems_gpio_request_pin(
1301  uint32_t pin_number,
1302  rtems_gpio_function function,
1303  bool output_enabled,
1304  bool logic_invert,
1305  void *bsp_specific
1306) {
1307  rtems_gpio_specific_data *bsp_data;
1308  rtems_status_code sc = RTEMS_SUCCESSFUL;
1309  uint32_t bank;
1310  uint32_t pin;
1311
1312  if ( pin_number < 0 || pin_number >= BSP_GPIO_PIN_COUNT ) {
1313    return RTEMS_INVALID_ID;
1314  }
1315
1316  bank = BANK_NUMBER(pin_number);
1317  pin = PIN_NUMBER(pin_number);
1318
1319  ACQUIRE_LOCK(gpio_bank_state[bank].lock);
1320
1321  /* If the pin is already being used returns with an error. */
1322  if ( gpio_pin_state[pin_number].pin_function != NOT_USED ) {
1323    RELEASE_LOCK(gpio_bank_state[bank].lock);
1324
1325    return RTEMS_RESOURCE_IN_USE;
1326  }
1327
1328  switch ( function ) {
1329    case DIGITAL_INPUT:
1330      sc = rtems_gpio_bsp_select_input(bank, pin, bsp_specific);
1331      break;
1332    case DIGITAL_OUTPUT:
1333      sc = rtems_gpio_bsp_select_output(bank, pin, bsp_specific);
1334      break;
1335    case BSP_SPECIFIC:
1336      bsp_data = (rtems_gpio_specific_data *) bsp_specific;
1337
1338      if ( bsp_data == NULL ) {
1339        RELEASE_LOCK(gpio_bank_state[bank].lock);
1340
1341        return RTEMS_UNSATISFIED;
1342      }
1343
1344      sc = rtems_gpio_bsp_select_specific_io(
1345             bank,
1346             pin,
1347             bsp_data->io_function,
1348             bsp_data->pin_data
1349           );
1350      break;
1351    case NOT_USED:
1352    default:
1353      RELEASE_LOCK(gpio_bank_state[bank].lock);
1354
1355      return RTEMS_NOT_DEFINED;
1356  }
1357
1358  if ( sc != RTEMS_SUCCESSFUL ) {
1359    RELEASE_LOCK(gpio_bank_state[bank].lock);
1360
1361    return sc;
1362  }
1363
1364  /* If the function was successfully assigned to the pin,
1365   * record that information on the gpio_pin_state structure. */
1366  gpio_pin_state[pin_number].pin_function = function;
1367  gpio_pin_state[pin_number].logic_invert = logic_invert;
1368
1369  if ( function == DIGITAL_OUTPUT ) {
1370    if ( output_enabled == true ) {
1371      sc = rtems_gpio_bsp_set(bank, pin);
1372    }
1373    else {
1374      sc = rtems_gpio_bsp_clear(bank, pin);
1375    }
1376  }
1377
1378  RELEASE_LOCK(gpio_bank_state[bank].lock);
1379
1380  return sc;
1381}
1382
1383rtems_status_code rtems_gpio_resistor_mode(
1384  uint32_t pin_number,
1385  rtems_gpio_pull_mode mode
1386) {
1387  rtems_status_code sc;
1388  uint32_t bank;
1389  uint32_t pin;
1390
1391  if ( pin_number < 0 || pin_number >= BSP_GPIO_PIN_COUNT ) {
1392    return RTEMS_INVALID_ID;
1393  }
1394
1395  bank = BANK_NUMBER(pin_number);
1396  pin = PIN_NUMBER(pin_number);
1397
1398  ACQUIRE_LOCK(gpio_bank_state[bank].lock);
1399
1400  /* If the desired actuation mode is already set, silently exits.
1401   * The NO_PULL_RESISTOR is a special case, as some platforms have
1402   * pull-up resistors enabled on startup, so this state may have to
1403   * be reinforced in the hardware. */
1404  if (
1405      gpio_pin_state[pin_number].resistor_mode == mode &&
1406      mode != NO_PULL_RESISTOR
1407  ) {
1408    RELEASE_LOCK(gpio_bank_state[bank].lock);
1409
1410    return RTEMS_SUCCESSFUL;
1411  }
1412
1413  sc = rtems_gpio_bsp_set_resistor_mode(bank, pin, mode);
1414
1415  if ( sc != RTEMS_SUCCESSFUL ) {
1416    RELEASE_LOCK(gpio_bank_state[bank].lock);
1417
1418    return sc;
1419  }
1420
1421  gpio_pin_state[pin_number].resistor_mode = mode;
1422
1423  RELEASE_LOCK(gpio_bank_state[bank].lock);
1424
1425  return RTEMS_SUCCESSFUL;
1426}
1427
1428rtems_status_code rtems_gpio_release_pin(uint32_t pin_number)
1429{
1430  gpio_pin_interrupt_state *interrupt_state;
1431  rtems_status_code sc;
1432  uint32_t bank;
1433
1434  if ( pin_number < 0 || pin_number >= BSP_GPIO_PIN_COUNT ) {
1435    return RTEMS_INVALID_ID;
1436  }
1437
1438  bank = BANK_NUMBER(pin_number);
1439
1440  ACQUIRE_LOCK(gpio_bank_state[bank].lock);
1441
1442  interrupt_state = gpio_pin_state[pin_number].interrupt_state;
1443
1444  /* If the pin has an enabled interrupt then remove the handler(s)
1445   * and disable interrupts on that pin. */
1446  if ( interrupt_state != NULL ) {
1447    sc = rtems_gpio_disable_interrupt(pin_number);
1448
1449    if ( sc != RTEMS_SUCCESSFUL ) {
1450      RELEASE_LOCK(gpio_bank_state[bank].lock);
1451
1452      return sc;
1453    }
1454  }
1455
1456  gpio_pin_state[pin_number].pin_function = NOT_USED;
1457  gpio_pin_state[pin_number].resistor_mode = NO_PULL_RESISTOR;
1458  gpio_pin_state[pin_number].logic_invert = false;
1459  gpio_pin_state[pin_number].on_group = false;
1460
1461  RELEASE_LOCK(gpio_bank_state[bank].lock);
1462
1463  return RTEMS_SUCCESSFUL;
1464}
1465
1466rtems_status_code rtems_gpio_release_configuration(
1467  const rtems_gpio_pin_conf *conf
1468) {
1469  if ( conf == NULL ) {
1470    return RTEMS_UNSATISFIED;
1471  }
1472
1473  return rtems_gpio_release_pin(conf->pin_number);
1474}
1475
1476rtems_status_code rtems_gpio_release_multiple_pins(
1477  const rtems_gpio_pin_conf *pins,
1478  uint32_t pin_count
1479) {
1480  rtems_status_code sc;
1481  uint32_t i;
1482
1483  if ( pins == NULL ) {
1484    return RTEMS_UNSATISFIED;
1485  }
1486
1487  for ( i = 0; i < pin_count; ++i ) {
1488    sc = rtems_gpio_release_pin(pins[i].pin_number);
1489
1490    if ( sc != RTEMS_SUCCESSFUL ) {
1491      return sc;
1492    }
1493  }
1494
1495  return RTEMS_SUCCESSFUL;
1496}
1497
1498rtems_status_code rtems_gpio_release_pin_group(
1499  rtems_gpio_group *group
1500) {
1501  rtems_status_code sc;
1502  uint8_t i;
1503
1504  ACQUIRE_LOCK(group->group_lock);
1505
1506  sc = rtems_semaphore_flush(group->group_lock);
1507
1508  if ( sc != RTEMS_SUCCESSFUL ) {
1509    RELEASE_LOCK(group->group_lock);
1510
1511    return sc;
1512  }
1513
1514  RELEASE_LOCK(group->group_lock);
1515
1516  /* Deletes the group lock. */
1517  sc = rtems_semaphore_delete(group->group_lock);
1518
1519  if ( sc != RTEMS_SUCCESSFUL ) {
1520    return sc;
1521  }
1522
1523  /* Pin releasing. */
1524  for ( i = 0; i < group->input_count; ++i ) {
1525    sc = rtems_gpio_release_pin(group->digital_inputs[i]);
1526
1527    if ( sc != RTEMS_SUCCESSFUL ) {
1528      return sc;
1529    }
1530  }
1531
1532  if ( group->input_count > 0 ) {
1533    free(group->digital_inputs);
1534  }
1535
1536  for ( i = 0; i < group->output_count; ++i ) {
1537    sc = rtems_gpio_release_pin(group->digital_outputs[i]);
1538
1539    if ( sc != RTEMS_SUCCESSFUL ) {
1540      return sc;
1541    }
1542  }
1543
1544  if ( group->output_count > 0 ) {
1545    free(group->digital_outputs);
1546  }
1547
1548  for ( i = 0; i < group->bsp_specific_pin_count; ++i ) {
1549    sc = rtems_gpio_release_pin(group->bsp_speficifc_pins[i]);
1550
1551    if ( sc != RTEMS_SUCCESSFUL ) {
1552      return sc;
1553    }
1554  }
1555
1556  if ( group->bsp_specific_pin_count > 0 ) {
1557    free(group->bsp_speficifc_pins);
1558  }
1559
1560  rtems_chain_extract(&group->node);
1561
1562  free(group);
1563
1564  return RTEMS_SUCCESSFUL;
1565}
1566
1567rtems_status_code rtems_gpio_debounce_switch(uint32_t pin_number, int ticks)
1568{
1569  gpio_pin_interrupt_state *interrupt_state;
1570  uint32_t bank;
1571
1572  if ( pin_number < 0 || pin_number >= BSP_GPIO_PIN_COUNT ) {
1573    return RTEMS_INVALID_ID;
1574  }
1575
1576  bank = BANK_NUMBER(pin_number);
1577
1578  ACQUIRE_LOCK(gpio_bank_state[bank].lock);
1579
1580  interrupt_state = gpio_pin_state[pin_number].interrupt_state;
1581
1582  /* If no interrupt configuration is set for this pin, or if the pin is
1583   * not set as a digital input, or the pin in on a group. */
1584  if (
1585      interrupt_state == NULL ||
1586      gpio_pin_state[pin_number].pin_function != DIGITAL_INPUT ||
1587      gpio_pin_state[pin_number].on_group
1588  ) {
1589    RELEASE_LOCK(gpio_bank_state[bank].lock);
1590
1591    return RTEMS_NOT_CONFIGURED;
1592  }
1593
1594  interrupt_state->debouncing_tick_count = ticks;
1595  interrupt_state->last_isr_tick = 0;
1596
1597  RELEASE_LOCK(gpio_bank_state[bank].lock);
1598
1599  return RTEMS_SUCCESSFUL;
1600}
1601
1602rtems_status_code rtems_gpio_interrupt_handler_install(
1603  uint32_t pin_number,
1604  rtems_gpio_irq_state (*handler) (void *arg),
1605  void *arg
1606) {
1607  gpio_pin_interrupt_state *interrupt_state;
1608  gpio_handler_node *isr_node;
1609  uint32_t bank;
1610
1611  if ( pin_number < 0 || pin_number >= BSP_GPIO_PIN_COUNT ) {
1612    return RTEMS_INVALID_ID;
1613  }
1614
1615  bank = BANK_NUMBER(pin_number);
1616
1617  ACQUIRE_LOCK(gpio_bank_state[bank].lock);
1618
1619  interrupt_state = gpio_pin_state[pin_number].interrupt_state;
1620
1621  /* If no interrupt configuration is set for this pin. */
1622   if ( interrupt_state == NULL ) {
1623    RELEASE_LOCK(gpio_bank_state[bank].lock);
1624
1625    return RTEMS_NOT_CONFIGURED;
1626  }
1627
1628  /* If the current pin has no interrupt enabled
1629   * then it does not need an handler. */
1630  if ( interrupt_state->active_interrupt == NONE ) {
1631    RELEASE_LOCK(gpio_bank_state[bank].lock);
1632
1633    return RTEMS_NOT_CONFIGURED;
1634  }
1635  /* If the pin already has an enabled interrupt but the installed handler
1636   * is set as unique. */
1637  else if (
1638           interrupt_state->handler_flag == UNIQUE_HANDLER &&
1639           !rtems_chain_is_empty(&interrupt_state->handler_chain)
1640  ) {
1641    RELEASE_LOCK(gpio_bank_state[bank].lock);
1642
1643    return RTEMS_TOO_MANY;
1644  }
1645
1646  /* Update the pin's ISR list. */
1647  isr_node = (gpio_handler_node *) malloc(sizeof(gpio_handler_node));
1648
1649  if ( isr_node == NULL ) {
1650    RELEASE_LOCK(gpio_bank_state[bank].lock);
1651
1652    return RTEMS_NO_MEMORY;
1653  }
1654
1655  isr_node->handler = handler;
1656  isr_node->arg = arg;
1657
1658  rtems_chain_append(&interrupt_state->handler_chain, &isr_node->node);
1659
1660  RELEASE_LOCK(gpio_bank_state[bank].lock);
1661
1662  return RTEMS_SUCCESSFUL;
1663}
1664
1665rtems_status_code rtems_gpio_enable_interrupt(
1666  uint32_t pin_number,
1667  rtems_gpio_interrupt interrupt,
1668  rtems_gpio_handler_flag flag,
1669  bool threaded_handling,
1670  rtems_gpio_irq_state (*handler) (void *arg),
1671  void *arg
1672) {
1673  gpio_pin_interrupt_state *interrupt_state;
1674  rtems_vector_number vector;
1675  rtems_status_code sc;
1676  uint32_t bank;
1677  uint32_t pin;
1678
1679  if ( pin_number < 0 || pin_number >= BSP_GPIO_PIN_COUNT ) {
1680    return RTEMS_INVALID_ID;
1681  }
1682
1683  bank = BANK_NUMBER(pin_number);
1684  pin = PIN_NUMBER(pin_number);
1685
1686  vector = rtems_gpio_bsp_get_vector(bank);
1687
1688  ACQUIRE_LOCK(gpio_bank_state[bank].lock);
1689
1690  if (
1691      gpio_pin_state[pin_number].pin_function != DIGITAL_INPUT ||
1692      gpio_pin_state[pin_number].on_group
1693  ) {
1694    RELEASE_LOCK(gpio_bank_state[bank].lock);
1695
1696    return RTEMS_NOT_CONFIGURED;
1697  }
1698
1699  /* If the bank already has at least one interrupt enabled on a pin,
1700   * then new interrupts on this bank must follow the current
1701   * threading policy. */
1702  if (
1703      gpio_bank_state[bank].interrupt_counter > 0 &&
1704      gpio_bank_state[bank].threaded_interrupts != threaded_handling
1705  ) {
1706    RELEASE_LOCK(gpio_bank_state[bank].lock);
1707
1708    return RTEMS_RESOURCE_IN_USE;
1709  }
1710
1711  interrupt_state = gpio_pin_state[pin_number].interrupt_state;
1712
1713  /* If an interrupt configuration is already in place for this pin. */
1714  if ( interrupt_state != NULL ) {
1715    RELEASE_LOCK(gpio_bank_state[bank].lock);
1716
1717    return RTEMS_RESOURCE_IN_USE;
1718  }
1719
1720  gpio_pin_state[pin_number].interrupt_state =
1721    (gpio_pin_interrupt_state *) malloc(sizeof(gpio_pin_interrupt_state));
1722
1723  if ( gpio_pin_state[pin_number].interrupt_state == NULL ) {
1724    return RTEMS_NO_MEMORY;
1725  }
1726
1727  gpio_pin_state[pin_number].interrupt_state->active_interrupt = NONE;
1728  gpio_pin_state[pin_number].interrupt_state->debouncing_tick_count = 0;
1729  gpio_pin_state[pin_number].interrupt_state->last_isr_tick = 0;
1730
1731  rtems_chain_initialize_empty(
1732    &gpio_pin_state[pin_number].interrupt_state->handler_chain
1733  );
1734
1735  interrupt_state = gpio_pin_state[pin_number].interrupt_state;
1736
1737  interrupt_state->active_interrupt = interrupt;
1738  interrupt_state->handler_flag = flag;
1739
1740  /* Installs the interrupt handler on the GPIO pin
1741   * tracking structure. */
1742  sc = rtems_gpio_interrupt_handler_install(pin_number, handler, arg);
1743
1744  if ( sc != RTEMS_SUCCESSFUL ) {
1745    RELEASE_LOCK(gpio_bank_state[bank].lock);
1746
1747    return RTEMS_UNSATISFIED;
1748  }
1749
1750  if ( threaded_handling ) {
1751    if (
1752        _Atomic_Load_uint(&threaded_interrupt_counter, ATOMIC_ORDER_RELAXED) == 0
1753    ) {
1754      sc = rtems_interrupt_server_initialize(
1755             INTERRUPT_SERVER_PRIORITY,
1756             INTERRUPT_SERVER_STACK_SIZE,
1757             INTERRUPT_SERVER_MODES,
1758             INTERRUPT_SERVER_ATTRIBUTES,
1759             NULL
1760           );
1761
1762      if ( sc != RTEMS_SUCCESSFUL ) {
1763        RELEASE_LOCK(gpio_bank_state[bank].lock);
1764
1765        return RTEMS_UNSATISFIED;
1766      }
1767    }
1768
1769    if ( gpio_bank_state[bank].interrupt_counter == 0 ) {
1770      sc = rtems_interrupt_server_handler_install(
1771             RTEMS_ID_NONE,
1772             vector,
1773             "GPIO_HANDLER",
1774             RTEMS_INTERRUPT_UNIQUE,
1775             (rtems_interrupt_handler) generic_bank_isr,
1776             &gpio_bank_state[bank].bank_number
1777           );
1778
1779      if ( sc != RTEMS_SUCCESSFUL ) {
1780        RELEASE_LOCK(gpio_bank_state[bank].lock);
1781
1782        return RTEMS_UNSATISFIED;
1783      }
1784
1785      _Atomic_Fetch_add_uint(
1786        &threaded_interrupt_counter,
1787        1,
1788        ATOMIC_ORDER_RELAXED
1789      );
1790    }
1791  }
1792  else if ( gpio_bank_state[bank].interrupt_counter == 0 ) {
1793    sc = rtems_interrupt_handler_install(
1794           vector,
1795           "GPIO_HANDLER",
1796           RTEMS_INTERRUPT_UNIQUE,
1797           (rtems_interrupt_handler) generic_bank_isr,
1798           &gpio_bank_state[bank].bank_number
1799         );
1800
1801    if ( sc != RTEMS_SUCCESSFUL ) {
1802      RELEASE_LOCK(gpio_bank_state[bank].lock);
1803
1804      return RTEMS_UNSATISFIED;
1805    }
1806  }
1807
1808  sc = rtems_gpio_bsp_enable_interrupt(bank, pin, interrupt);
1809
1810  if ( sc != RTEMS_SUCCESSFUL ) {
1811    RELEASE_LOCK(gpio_bank_state[bank].lock);
1812
1813    return RTEMS_UNSATISFIED;
1814  }
1815
1816  /* If this was the first interrupt enabled on this GPIO bank,
1817   * record the threading policy. */
1818  if ( gpio_bank_state[bank].interrupt_counter == 0 ) {
1819    gpio_bank_state[bank].threaded_interrupts = threaded_handling;
1820  }
1821
1822  ++gpio_bank_state[bank].interrupt_counter;
1823
1824  RELEASE_LOCK(gpio_bank_state[bank].lock);
1825
1826  return RTEMS_SUCCESSFUL;
1827}
1828
1829rtems_status_code rtems_gpio_interrupt_handler_remove(
1830  uint32_t pin_number,
1831  rtems_gpio_irq_state (*handler) (void *arg),
1832  void *arg
1833) {
1834  gpio_pin_interrupt_state *interrupt_state;
1835  rtems_chain_control *handler_list;
1836  rtems_chain_node *node;
1837  rtems_chain_node *next_node;
1838  gpio_handler_node *isr_node;
1839  uint32_t bank;
1840
1841  if ( pin_number < 0 || pin_number >= BSP_GPIO_PIN_COUNT ) {
1842    return RTEMS_INVALID_ID;
1843  }
1844
1845  bank = BANK_NUMBER(pin_number);
1846
1847  ACQUIRE_LOCK(gpio_bank_state[bank].lock);
1848
1849  interrupt_state = gpio_pin_state[pin_number].interrupt_state;
1850
1851  /* If no interrupt configuration is set for this pin. */
1852  if ( interrupt_state == NULL ) {
1853    RELEASE_LOCK(gpio_bank_state[bank].lock);
1854
1855    return RTEMS_NOT_CONFIGURED;
1856  }
1857
1858  handler_list = &interrupt_state->handler_chain;
1859
1860  node = rtems_chain_first(handler_list);
1861
1862  /* If the first node is also the last handler for this pin, disables
1863   * interrupts on this pin as there will be no handler to handle it.
1864   * This also removes the remaining handler. */
1865  if ( rtems_chain_is_last(node) ) {
1866    RELEASE_LOCK(gpio_bank_state[bank].lock);
1867
1868    return rtems_gpio_disable_interrupt(pin_number);
1869  }
1870
1871  /* Iterate the ISR list. */
1872  while ( !rtems_chain_is_tail(handler_list, node) ) {
1873    isr_node = (gpio_handler_node *) node;
1874
1875    next_node = node->next;
1876
1877    if ( isr_node->handler == handler && isr_node->arg == arg ) {
1878      rtems_chain_extract(node);
1879
1880      break;
1881    }
1882
1883    node = next_node;
1884  }
1885
1886  RELEASE_LOCK(gpio_bank_state[bank].lock);
1887
1888  return RTEMS_SUCCESSFUL;
1889}
1890
1891rtems_status_code rtems_gpio_disable_interrupt(uint32_t pin_number)
1892{
1893  gpio_pin_interrupt_state *interrupt_state;
1894  rtems_chain_control *handler_list;
1895  rtems_chain_node *node;
1896  rtems_chain_node *next_node;
1897  rtems_vector_number vector;
1898  rtems_status_code sc;
1899  uint32_t bank;
1900  uint32_t pin;
1901
1902  if ( pin_number < 0 || pin_number >= BSP_GPIO_PIN_COUNT ) {
1903    return RTEMS_INVALID_ID;
1904  }
1905
1906  bank = BANK_NUMBER(pin_number);
1907  pin = PIN_NUMBER(pin_number);
1908
1909  vector = rtems_gpio_bsp_get_vector(bank);
1910
1911  ACQUIRE_LOCK(gpio_bank_state[bank].lock);
1912
1913  interrupt_state = gpio_pin_state[pin_number].interrupt_state;
1914
1915  /* If no interrupt configuration is set for this pin. */
1916  if ( interrupt_state == NULL ) {
1917    RELEASE_LOCK(gpio_bank_state[bank].lock);
1918
1919    return RTEMS_NOT_CONFIGURED;
1920  }
1921
1922  sc = rtems_gpio_bsp_disable_interrupt(bank, pin, interrupt_state->active_interrupt);
1923
1924  if ( sc != RTEMS_SUCCESSFUL ) {
1925    RELEASE_LOCK(gpio_bank_state[bank].lock);
1926
1927    return RTEMS_UNSATISFIED;
1928  }
1929
1930  interrupt_state->active_interrupt = NONE;
1931
1932  handler_list = &interrupt_state->handler_chain;
1933
1934  node = rtems_chain_first(handler_list);
1935
1936  /* Iterate the ISR list. */
1937  while ( !rtems_chain_is_tail(handler_list, node) ) {
1938    next_node = node->next;
1939
1940    rtems_chain_extract(node);
1941
1942    node = next_node;
1943  }
1944
1945  /* If this is the last GPIO interrupt are left in this bank,
1946   * removes the handler. */
1947  if ( gpio_bank_state[bank].interrupt_counter == 1 ) {
1948    if ( gpio_bank_state[bank].threaded_interrupts ) {
1949      sc = rtems_interrupt_server_handler_remove(
1950             RTEMS_ID_NONE,
1951             vector,
1952             (rtems_interrupt_handler) generic_bank_isr,
1953             &gpio_bank_state[bank].bank_number
1954           );
1955    }
1956    else {
1957      sc = rtems_interrupt_handler_remove(
1958             vector,
1959             (rtems_interrupt_handler) generic_bank_isr,
1960             &gpio_bank_state[bank].bank_number
1961           );
1962    }
1963
1964    if ( sc != RTEMS_SUCCESSFUL ) {
1965      RELEASE_LOCK(gpio_bank_state[bank].lock);
1966
1967      return RTEMS_UNSATISFIED;
1968    }
1969  }
1970
1971  /* Free the pin's interrupt state structure. */
1972  free(interrupt_state);
1973
1974  --gpio_bank_state[bank].interrupt_counter;
1975
1976  if ( gpio_bank_state[bank].threaded_interrupts ) {
1977    _Atomic_Fetch_sub_uint(&threaded_interrupt_counter, 1, ATOMIC_ORDER_RELAXED);
1978  }
1979
1980  RELEASE_LOCK(gpio_bank_state[bank].lock);
1981
1982  return RTEMS_SUCCESSFUL;
1983}
Note: See TracBrowser for help on using the repository browser.