ifndef VERBOSE .SILENT: endif # Never run this makefile in parallel, as it could screw things up # It won't affect the submakes, so you still get the speedup from specifying -jx .NOTPARALLEL: # Allow the silent with lower caps to work the same way as upper caps ifdef silent SILENT = $(silent) endif ifdef SILENT SUB_IS_SILENT := $(SILENT) endif # We need to make sure that silent is always turned off at the top level # Otherwise the [OK], [ERROR] and [WARN] messages won't be displayed correctly override SILENT := false ifndef SUB_IS_SILENT QMK_VERSION := $(shell git describe --abbrev=0 --tags 2>/dev/null) ifneq ($(QMK_VERSION),) $(info QMK Firmware $(QMK_VERSION)) endif endif ON_ERROR := error_occurred=1 BREAK_ON_ERRORS = no STARTING_MAKEFILE := $(firstword $(MAKEFILE_LIST)) ROOT_MAKEFILE := $(lastword $(MAKEFILE_LIST)) ROOT_DIR := $(dir $(ROOT_MAKEFILE)) ifeq ($(ROOT_DIR),) ROOT_DIR := . endif ABS_STARTING_MAKEFILE := $(abspath $(STARTING_MAKEFILE)) ABS_ROOT_MAKEFILE := $(abspath $(ROOT_MAKEFILE)) ABS_STARTING_DIR := $(dir $(ABS_STARTING_MAKEFILE)) ABS_ROOT_DIR := $(dir $(ABS_ROOT_MAKEFILE)) STARTING_DIR := $(subst $(ABS_ROOT_DIR),,$(ABS_STARTING_DIR)) BUILD_DIR := $(ROOT_DIR)/.build TEST_DIR := $(BUILD_DIR)/test ERROR_FILE := $(BUILD_DIR)/error_occurred MAKEFILE_INCLUDED=yes # Helper function to process the newt element of a space separated path # It works a bit like the traditional functional head tail # so the CURRENT_PATH_ELEMENT will become the new head # and the PATH_ELEMENTS are the rest that are still unprocessed define NEXT_PATH_ELEMENT $$(eval CURRENT_PATH_ELEMENT := $$(firstword $$(PATH_ELEMENTS))) $$(eval PATH_ELEMENTS := $$(wordlist 2,9999,$$(PATH_ELEMENTS))) endef # We change the / to spaces so that we more easily can work with the elements # separately PATH_ELEMENTS := $(subst /, ,$(STARTING_DIR)) # Initialize the path elements list for further processing $(eval $(call NEXT_PATH_ELEMENT)) # This function sets the KEYBOARD; KEYMAP and SUBPROJECT to the correct # variables depending on which directory you stand in. # It's really a very simple if else chain, if you squint enough, # but the makefile syntax makes it very verbose. # If we are in a subfolder of keyboards # # *** No longer needed ** # # ifeq ($(CURRENT_PATH_ELEMENT),keyboards) # $(eval $(call NEXT_PATH_ELEMENT)) # KEYBOARD := $(CURRENT_PATH_ELEMENT) # $(eval $(call NEXT_PATH_ELEMENT)) # # If we are in a subfolder of keymaps, or in other words in a keymap # # folder # ifeq ($(CURRENT_PATH_ELEMENT),keymaps) # $(eval $(call NEXT_PATH_ELEMENT)) # KEYMAP := $(CURRENT_PATH_ELEMENT) # # else if we are not in the keyboard folder itself # else ifneq ($(CURRENT_PATH_ELEMENT),) # # the we can assume it's a subproject, as no other folders # # should have make files in them # SUBPROJECT := $(CURRENT_PATH_ELEMENT) # $(eval $(call NEXT_PATH_ELEMENT)) # # if we are inside a keymap folder of a subproject # ifeq ($(CURRENT_PATH_ELEMENT),keymaps) # $(eval $(call NEXT_PATH_ELEMENT)) # KEYMAP := $(CURRENT_PATH_ELEMENT) # endif # endif # endif define GET_KEYBOARDS All_RULES_MK := $$(patsubst $(ROOT_DIR)/keyboards/%/rules.mk,%,$$(wildcard $(ROOT_DIR)/keyboards/*/rules.mk)) All_RULES_MK += $$(patsubst $(ROOT_DIR)/keyboards/%/rules.mk,%,$$(wildcard $(ROOT_DIR)/keyboards/*/*/rules.mk)) All_RULES_MK += $$(patsubst $(ROOT_DIR)/keyboards/%/rules.mk,%,$$(wildcard $(ROOT_DIR)/keyboards/*/*/*/rules.mk)) All_RULES_MK += $$(patsubst $(ROOT_DIR)/keyboards/%/rules.mk,%,$$(wildcard $(ROOT_DIR)/keyboards/*/*/*/*/rules.mk)) KEYMAPS_MK := $$(patsubst $(ROOT_DIR)/keyboards/%/rules.mk,%,$$(wildcard $(ROOT_DIR)/keyboards/*/keymaps/*/rules.mk)) KEYMAPS_MK += $$(patsubst $(ROOT_DIR)/keyboards/%/rules.mk,%,$$(wildcard $(ROOT_DIR)/keyboards/*/*/keymaps/*/rules.mk)) KEYMAPS_MK += $$(patsubst $(ROOT_DIR)/keyboards/%/rules.mk,%,$$(wildcard $(ROOT_DIR)/keyboards/*/*/*/keymaps/*/rules.mk)) KEYMAPS_MK += $$(patsubst $(ROOT_DIR)/keyboards/%/rules.mk,%,$$(wildcard $(ROOT_DIR)/keyboards/*/*/*/*/keymaps/*/rules.mk)) KEYBOARDS := $$(sort $$(filter-out $$(KEYMAPS_MK), $$(All_RULES_MK))) endef $(eval $(call GET_KEYBOARDS)) # Only consider folders with makefiles, to prevent errors in case there are extra folders #KEYBOARDS += $(patsubst $(ROOD_DIR)/keyboards/%/rules.mk,%,$(wildcard $(ROOT_DIR)/keyboards/*/*/rules.mk)) list-keyboards: echo $(KEYBOARDS) exit 0 define PRINT_KEYBOARD $(info $(PRINTING_KEYBOARD)) endef generate-keyboards-file: $(foreach PRINTING_KEYBOARD,$(KEYBOARDS),$(eval $(call PRINT_KEYBOARD))) exit 0 #Compatibility with the old make variables, anything you specify directly on the command line # always overrides the detected folders ifdef keyboard KEYBOARD := $(keyboard) endif ifdef keymap KEYMAP := $(keymap) endif # Uncomment these for debugging # $(info Keyboard: $(KEYBOARD)) # $(info Keymap: $(KEYMAP)) # $(info Subproject: $(SUBPROJECT)) # $(info Keyboards: $(KEYBOARDS)) # Set the default goal depending on where we are running make from # this handles the case where you run make without any arguments .DEFAULT_GOAL := all:all ifneq ($(KEYMAP),) .DEFAULT_GOAL := $(KEYBOARD):$(KEYMAP) else ifneq ($(KEYBOARD),) # Inside a keyboard folder, build all keymaps for all subprojects # Note that this is different from the old behaviour, which would # build only the default keymap of the default keyboard .DEFAULT_GOAL := $(KEYBOARD):all endif # Compare the start of the RULE variable with the first argument($1) # If the rules equals $1 or starts with $1:, RULE_FOUND is set to true # and $1 is removed from the RULE variable # Otherwise the RULE_FOUND variable is set to false, and RULE left as it was # The function is a bit tricky, since there's no built in $(startswith) function define COMPARE_AND_REMOVE_FROM_RULE_HELPER ifeq ($1,$$(RULE)) RULE:= RULE_FOUND := true else STARTCOLON_REMOVED=$$(subst START$1:,,START$$(RULE)) ifneq ($$(STARTCOLON_REMOVED),START$$(RULE)) RULE_FOUND := true RULE := $$(STARTCOLON_REMOVED) else RULE_FOUND := false endif endif endef # This makes it easier to call COMPARE_AND_REMOVE_FROM_RULE, since it makes it behave like # a function that returns the value COMPARE_AND_REMOVE_FROM_RULE = $(eval $(call COMPARE_AND_REMOVE_FROM_RULE_HELPER,$1))$(RULE_FOUND) # Recursively try to find a match for the start of the rule to be checked # $1 The list to be checked # If a match is found, then RULE_FOUND is set to true # and MATCHED_ITEM to the item that was matched define TRY_TO_MATCH_RULE_FROM_LIST_HELPER3 ifneq ($1,) ifeq ($$(call COMPARE_AND_REMOVE_FROM_RULE,$$(firstword $1)),true) MATCHED_ITEM := $$(firstword $1) else
/*
    ChibiOS/RT - Copyright (C) 2006,2007,2008,2009,2010 Giovanni Di Sirio.

    This file is part of ChibiOS/RT.

    ChibiOS/RT is free software; you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation; either version 3 of the License, or
    (at your option) any later version.

    ChibiOS/RT is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

/**
 * @file    pal.c
 * @brief   I/O Ports Abstraction Layer code.
 *
 * @addtogroup PAL
 * @{
 */

#include "ch.h"
#include "hal.h"

#if HAL_USE_PAL || defined(__DOXYGEN__)

/*===========================================================================*/
/* Driver exported variables.                                                */
/*===========================================================================*/

/*===========================================================================*/
/* Driver local variables.                                                   */
/*===========================================================================*/

/*===========================================================================*/
/* Driver local functions.                                                   */
/*===========================================================================*/

/*===========================================================================*/
/* Driver exported functions.                                                */
/*===========================================================================*/

/**
 * @brief   Read from an I/O bus.
 * @note    The operation is not guaranteed to be atomic on all the
 *          architectures, for atomicity and/or portability reasons you may
 *          need to enclose port I/O operations between @p chSysLock() and
 *          @p chSysUnlock().
 * @note    The function internally uses the @p palReadGroup() macro. The use
 *          of this function is preferred when you value code size, readability
 *          and error checking over speed.
 *
 * @param[in] bus       the I/O bus, pointer to a @p IOBus structure
 * @return              The bus logical states.
 *
 * @api
 */
ioportmask_t palReadBus(IOBus *bus) {

  chDbgCheck((bus != NULL) &&
             (bus->bus_offset > PAL_IOPORTS_WIDTH), "palReadBus");

  return palReadGroup(bus->bus_portid, bus->bus_mask, bus->bus_offset);
}

/**
 * @brief   Write to an I/O bus.
 * @note    The operation is not guaranteed to be atomic on all the
 *          architectures, for atomicity and/or portability reasons you may
 *          need to enclose port I/O operations between @p chSysLock() and
 *          @p chSysUnlock().
 * @note    The default implementation is non atomic and not necessarily
 *          optimal. Low level drivers may  optimize the function by using
 *          specific hardware or coding.
 *
 * @param[in] bus       the I/O bus, pointer to a @p IOBus structure
 * @param[in] bits      the bits to be written on the I/O bus. Values exceeding
 *                      the bus width are masked so most significant bits are
 *                      lost.
 *
 * @api
 */
void palWriteBus(IOBus *bus, ioportmask_t bits) {

  chDbgCheck((bus != NULL) &&
             (bus->bus_offset > PAL_IOPORTS_WIDTH), "palWriteBus");

  palWriteGroup(bus->bus_portid, bus->bus_mask, bus->bus_offset, bits);
}

/**
 * @brief   Programs a bus with the specified mode.
 * @note    The operation is not guaranteed to be atomic on all the
 *          architectures, for atomicity and/or portability reasons you may
 *          need to enclose port I/O operations between @p chSysLock() and
 *          @p chSysUnlock().
 * @note    The default implementation is non atomic and not necessarily
 *          optimal. Low level drivers may  optimize the function by using
 *          specific hardware or coding.
 *
 * @param[in] bus       the I/O bus, pointer to a @p IOBus structure
 * @param[in] mode      the mode
 *
 * @api
 */
void palSetBusMode(IOBus *bus, uint_fast8_t mode) {

  chDbgCheck((bus != NULL) &&
             (bus->bus_offset > PAL_IOPORTS_WIDTH), "palSetBusMode");

  palSetGroupMode(bus->bus_portid, bus->bus_mask, mode);
}

#endif /* HAL_USE_PAL */

/** @} */
ways --tags 2>/dev/null || date +"%Y-%m-%d-%H:%M:%S") else GIT_VERSION := NA endif ifndef SKIP_VERSION BUILD_DATE := $(shell date +"%Y-%m-%d-%H:%M:%S") $(shell echo '#define QMK_VERSION "$(GIT_VERSION)"' > $(ROOT_DIR)/quantum/version.h) $(shell echo '#define QMK_BUILDDATE "$(BUILD_DATE)"' >> $(ROOT_DIR)/quantum/version.h) else BUILD_DATE := NA endif include $(ROOT_DIR)/testlist.mk