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 */
/** @} */