diff --git a/CMakeLists.txt b/CMakeLists.txt index c786770bee4f2..82407c7284c4e 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -494,6 +494,7 @@ endif() set(syscall_list_h ${CMAKE_CURRENT_BINARY_DIR}/include/generated/syscall_list.h) set(syscalls_json ${CMAKE_CURRENT_BINARY_DIR}/misc/generated/syscalls.json) +set(subsys_json ${CMAKE_CURRENT_BINARY_DIR}/misc/generated/subsystems.json) # The syscalls subdirs txt file is constructed by python containing a list of folders to use for # dependency handling, including empty folders. @@ -585,12 +586,14 @@ endforeach() add_custom_command( OUTPUT ${syscalls_json} + ${subsys_json} COMMAND ${PYTHON_EXECUTABLE} ${ZEPHYR_BASE}/scripts/parse_syscalls.py --include ${ZEPHYR_BASE}/include # Read files from this dir ${parse_syscalls_include_args} # Read files from these dirs also - --json-file ${syscalls_json} # Write this file + --json-file ${syscalls_json} # Write this file + --subsystem-file ${subsys_json} # Write subsystem list to this file DEPENDS ${syscalls_subdirs_trigger} ${PARSE_SYSCALLS_HEADER_DEPENDS} ) @@ -617,6 +620,9 @@ add_custom_command(OUTPUT include/generated/syscall_dispatch.c ${syscall_list_h} DEPENDS ${syscalls_json} ) +# This is passed into all calls to the gen_kobject_list.py script. +set(gen_kobject_list_include_args --include ${subsys_json}) + set(DRV_VALIDATION ${PROJECT_BINARY_DIR}/include/generated/driver-validation.h) add_custom_command( OUTPUT ${DRV_VALIDATION} @@ -624,8 +630,11 @@ add_custom_command( ${PYTHON_EXECUTABLE} ${ZEPHYR_BASE}/scripts/gen_kobject_list.py --validation-output ${DRV_VALIDATION} + ${gen_kobject_list_include_args} $<$:--verbose> - DEPENDS ${ZEPHYR_BASE}/scripts/gen_kobject_list.py + DEPENDS + ${ZEPHYR_BASE}/scripts/gen_kobject_list.py + ${subsys_json} WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} ) add_custom_target(${DRIVER_VALIDATION_H_TARGET} DEPENDS ${DRV_VALIDATION}) @@ -941,8 +950,11 @@ if(CONFIG_USERSPACE) ${GEN_KOBJ_LIST} --kernel $ --gperf-output ${OBJ_LIST} + ${gen_kobject_list_include_args} $<$:--verbose> - DEPENDS ${ZEPHYR_PREBUILT_EXECUTABLE} + DEPENDS + ${ZEPHYR_PREBUILT_EXECUTABLE} + ${subsys_json} WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} ) add_custom_target(obj_list DEPENDS ${CMAKE_CURRENT_BINARY_DIR}/${OBJ_LIST}) diff --git a/cmake/kobj.cmake b/cmake/kobj.cmake index bd16d3538d9f0..f54e148a60d83 100644 --- a/cmake/kobj.cmake +++ b/cmake/kobj.cmake @@ -21,8 +21,11 @@ function(gen_kobj gen_dir_out) --kobj-types-output ${KOBJ_TYPES} --kobj-otype-output ${KOBJ_OTYPE} --kobj-size-output ${KOBJ_SIZE} + ${gen_kobject_list_include_args} $<$:--verbose> - DEPENDS $ENV{ZEPHYR_BASE}/scripts/gen_kobject_list.py + DEPENDS + $ENV{ZEPHYR_BASE}/scripts/gen_kobject_list.py + ${subsys_json} WORKING_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR} ) add_custom_target(${KOBJ_TYPES_H_TARGET} DEPENDS ${KOBJ_TYPES} ${KOBJ_OTYPE}) diff --git a/include/crypto/cipher.h b/include/crypto/cipher.h index bec6f74bebb08..7d5790a713429 100644 --- a/include/crypto/cipher.h +++ b/include/crypto/cipher.h @@ -24,7 +24,7 @@ #include "cipher_structs.h" /* The API a crypto driver should implement */ -struct crypto_driver_api { +__subsystem struct crypto_driver_api { int (*query_hw_caps)(struct device *dev); /* Setup a crypto session */ diff --git a/include/drivers/adc.h b/include/drivers/adc.h index ab99917cdf04d..a80cf6c2c825e 100644 --- a/include/drivers/adc.h +++ b/include/drivers/adc.h @@ -353,7 +353,7 @@ typedef int (*adc_api_read_async)(struct device *dev, * * This is the mandatory API any ADC driver needs to expose. */ -struct adc_driver_api { +__subsystem struct adc_driver_api { adc_api_channel_setup channel_setup; adc_api_read read; #ifdef CONFIG_ADC_ASYNC diff --git a/include/drivers/can.h b/include/drivers/can.h index 80de9a41f7206..c1010e2f597a0 100644 --- a/include/drivers/can.h +++ b/include/drivers/can.h @@ -312,7 +312,7 @@ struct zcan_work { void *cb_arg; }; -struct can_driver_api { +__subsystem struct can_driver_api { can_configure_t configure; can_send_t send; can_attach_isr_t attach_isr; diff --git a/include/drivers/counter.h b/include/drivers/counter.h index 3e96e12d80d93..71772ad817ac8 100644 --- a/include/drivers/counter.h +++ b/include/drivers/counter.h @@ -184,7 +184,7 @@ typedef u32_t (*counter_api_get_guard_period)(struct device *dev, u32_t flags); typedef int (*counter_api_set_guard_period)(struct device *dev, u32_t ticks, u32_t flags); -struct counter_driver_api { +__subsystem struct counter_driver_api { counter_api_start start; counter_api_stop stop; counter_api_get_value get_value; diff --git a/include/drivers/dma.h b/include/drivers/dma.h index 1b90c9390abe0..11c0bd0a3db0b 100644 --- a/include/drivers/dma.h +++ b/include/drivers/dma.h @@ -189,7 +189,7 @@ typedef int (*dma_api_stop)(struct device *dev, u32_t channel); typedef int (*dma_api_get_status)(struct device *dev, u32_t channel, struct dma_status *status); -struct dma_driver_api { +__subsystem struct dma_driver_api { dma_api_config config; dma_api_reload reload; dma_api_start start; diff --git a/include/drivers/eeprom.h b/include/drivers/eeprom.h index d3a8c8d39a034..cabab9cdf23a2 100644 --- a/include/drivers/eeprom.h +++ b/include/drivers/eeprom.h @@ -38,7 +38,7 @@ typedef int (*eeprom_api_write)(struct device *dev, off_t offset, const void *data, size_t len); typedef size_t (*eeprom_api_size)(struct device *dev); -struct eeprom_driver_api { +__subsystem struct eeprom_driver_api { eeprom_api_read read; eeprom_api_write write; eeprom_api_size size; diff --git a/include/drivers/entropy.h b/include/drivers/entropy.h index 5722ec246546e..0891ecebf94e9 100644 --- a/include/drivers/entropy.h +++ b/include/drivers/entropy.h @@ -46,7 +46,7 @@ typedef int (*entropy_get_entropy_isr_t)(struct device *dev, u8_t *buffer, u16_t length, u32_t flags); -struct entropy_driver_api { +__subsystem struct entropy_driver_api { entropy_get_entropy_t get_entropy; entropy_get_entropy_isr_t get_entropy_isr; }; diff --git a/include/drivers/espi.h b/include/drivers/espi.h index 500206cd718f0..bc059fb3cd9db 100644 --- a/include/drivers/espi.h +++ b/include/drivers/espi.h @@ -357,7 +357,7 @@ typedef int (*espi_api_manage_callback)(struct device *dev, struct espi_callback *callback, bool set); -struct espi_driver_api { +__subsystem struct espi_driver_api { espi_api_config config; espi_api_get_channel_status get_channel_status; espi_api_read_request read_request; diff --git a/include/drivers/flash.h b/include/drivers/flash.h index 20deff034948b..04d83b0c5897f 100644 --- a/include/drivers/flash.h +++ b/include/drivers/flash.h @@ -70,7 +70,7 @@ typedef void (*flash_api_pages_layout)(struct device *dev, size_t *layout_size); #endif /* CONFIG_FLASH_PAGE_LAYOUT */ -struct flash_driver_api { +__subsystem struct flash_driver_api { flash_api_read read; flash_api_write write; flash_api_erase erase; diff --git a/include/drivers/gpio.h b/include/drivers/gpio.h index 89005120e322c..93628fd9d4beb 100644 --- a/include/drivers/gpio.h +++ b/include/drivers/gpio.h @@ -545,7 +545,7 @@ enum gpio_int_trig { GPIO_INT_TRIG_BOTH = GPIO_INT_LOW_0 | GPIO_INT_HIGH_1, }; -struct gpio_driver_api { +__subsystem struct gpio_driver_api { int (*pin_configure)(struct device *port, gpio_pin_t pin, gpio_flags_t flags); int (*port_get_raw)(struct device *port, gpio_port_value_t *value); int (*port_set_masked_raw)(struct device *port, gpio_port_pins_t mask, diff --git a/include/drivers/i2c.h b/include/drivers/i2c.h index 7143d2d758dc3..8c51f12a75e50 100644 --- a/include/drivers/i2c.h +++ b/include/drivers/i2c.h @@ -174,7 +174,7 @@ typedef int (*i2c_api_slave_register_t)(struct device *dev, typedef int (*i2c_api_slave_unregister_t)(struct device *dev, struct i2c_slave_config *cfg); -struct i2c_driver_api { +__subsystem struct i2c_driver_api { i2c_api_configure_t configure; i2c_api_full_io_t transfer; i2c_api_slave_register_t slave_register; diff --git a/include/drivers/i2s.h b/include/drivers/i2s.h index 451bf96d8c3d6..dbbb18aa1bb14 100644 --- a/include/drivers/i2s.h +++ b/include/drivers/i2s.h @@ -313,7 +313,7 @@ struct i2s_config { * * For internal use only, skip these in public documentation. */ -struct i2s_driver_api { +__subsystem struct i2s_driver_api { int (*configure)(struct device *dev, enum i2s_dir dir, struct i2s_config *cfg); struct i2s_config *(*config_get)(struct device *dev, diff --git a/include/drivers/ipm.h b/include/drivers/ipm.h index 9a7deb0791f8e..2ef49563295ac 100644 --- a/include/drivers/ipm.h +++ b/include/drivers/ipm.h @@ -85,7 +85,7 @@ typedef void (*ipm_register_callback_t)(struct device *port, ipm_callback_t cb, */ typedef int (*ipm_set_enabled_t)(struct device *ipmdev, int enable); -struct ipm_driver_api { +__subsystem struct ipm_driver_api { ipm_send_t send; ipm_register_callback_t register_callback; ipm_max_data_size_get_t max_data_size_get; diff --git a/include/drivers/kscan.h b/include/drivers/kscan.h index 6caa5bfdd61bb..5b9203546697f 100644 --- a/include/drivers/kscan.h +++ b/include/drivers/kscan.h @@ -56,7 +56,7 @@ typedef int (*kscan_config_t)(struct device *dev, typedef int (*kscan_disable_callback_t)(struct device *dev); typedef int (*kscan_enable_callback_t)(struct device *dev); -struct kscan_driver_api { +__subsystem struct kscan_driver_api { kscan_config_t config; kscan_disable_callback_t disable_callback; kscan_enable_callback_t enable_callback; diff --git a/include/drivers/led.h b/include/drivers/led.h index 3a5f06442c900..3cfc7ce7a661b 100644 --- a/include/drivers/led.h +++ b/include/drivers/led.h @@ -53,7 +53,7 @@ typedef int (*led_api_off)(struct device *dev, u32_t led); * * This is the mandatory API any LED driver needs to expose. */ -struct led_driver_api { +__subsystem struct led_driver_api { led_api_blink blink; led_api_set_brightness set_brightness; led_api_on on; diff --git a/include/drivers/pinmux.h b/include/drivers/pinmux.h index 67aeb646ee6d8..4cb85a5e01da6 100644 --- a/include/drivers/pinmux.h +++ b/include/drivers/pinmux.h @@ -66,7 +66,7 @@ typedef int (*pmux_pullup)(struct device *dev, u32_t pin, u8_t func); */ typedef int (*pmux_input)(struct device *dev, u32_t pin, u8_t func); -struct pinmux_driver_api { +__subsystem struct pinmux_driver_api { pmux_set set; pmux_get get; pmux_pullup pullup; diff --git a/include/drivers/ps2.h b/include/drivers/ps2.h index 573eb200dae32..e7eec94b558cf 100644 --- a/include/drivers/ps2.h +++ b/include/drivers/ps2.h @@ -50,7 +50,7 @@ typedef int (*ps2_write_t)(struct device *dev, u8_t value); typedef int (*ps2_disable_callback_t)(struct device *dev); typedef int (*ps2_enable_callback_t)(struct device *dev); -struct ps2_driver_api { +__subsystem struct ps2_driver_api { ps2_config_t config; ps2_read_t read; ps2_write_t write; diff --git a/include/drivers/pwm.h b/include/drivers/pwm.h index 8846f5c442dfc..4b7c7ec4556c6 100644 --- a/include/drivers/pwm.h +++ b/include/drivers/pwm.h @@ -52,7 +52,7 @@ typedef int (*pwm_get_cycles_per_sec_t)(struct device *dev, u32_t pwm, u64_t *cycles); /** @brief PWM driver API definition. */ -struct pwm_driver_api { +__subsystem struct pwm_driver_api { pwm_pin_set_t pin_set; pwm_get_cycles_per_sec_t get_cycles_per_sec; }; diff --git a/include/drivers/sensor.h b/include/drivers/sensor.h index 2e6f8586adae0..cfb70d410fc69 100644 --- a/include/drivers/sensor.h +++ b/include/drivers/sensor.h @@ -316,7 +316,7 @@ typedef int (*sensor_channel_get_t)(struct device *dev, enum sensor_channel chan, struct sensor_value *val); -struct sensor_driver_api { +__subsystem struct sensor_driver_api { sensor_attr_set_t attr_set; sensor_trigger_set_t trigger_set; sensor_sample_fetch_t sample_fetch; diff --git a/include/drivers/spi.h b/include/drivers/spi.h index 23e8450703d5d..18fb98c4a3726 100644 --- a/include/drivers/spi.h +++ b/include/drivers/spi.h @@ -223,7 +223,7 @@ typedef int (*spi_api_release)(struct device *dev, * @brief SPI driver API * This is the mandatory API any SPI driver needs to expose. */ -struct spi_driver_api { +__subsystem struct spi_driver_api { spi_api_io transceive; #ifdef CONFIG_SPI_ASYNC spi_api_io_async transceive_async; diff --git a/include/drivers/uart.h b/include/drivers/uart.h index 4de313e670584..06715d0c726ea 100644 --- a/include/drivers/uart.h +++ b/include/drivers/uart.h @@ -342,7 +342,7 @@ struct uart_device_config { }; /** @brief Driver API structure. */ -struct uart_driver_api { +__subsystem struct uart_driver_api { #ifdef CONFIG_UART_ASYNC_API diff --git a/include/drivers/watchdog.h b/include/drivers/watchdog.h index 8fdfe72c5d2d3..90ca1cc5d34e4 100644 --- a/include/drivers/watchdog.h +++ b/include/drivers/watchdog.h @@ -135,7 +135,7 @@ typedef int (*wdt_api_install_timeout)(struct device *dev, typedef int (*wdt_api_feed)(struct device *dev, int channel_id); /** @cond INTERNAL_HIDDEN */ -struct wdt_driver_api { +__subsystem struct wdt_driver_api { wdt_api_setup setup; wdt_api_disable disable; wdt_api_install_timeout install_timeout; diff --git a/include/ptp_clock.h b/include/ptp_clock.h index 05be598c19719..803912870d81b 100644 --- a/include/ptp_clock.h +++ b/include/ptp_clock.h @@ -22,7 +22,7 @@ extern "C" { #define PTP_CLOCK_NAME "PTP_CLOCK" #endif -struct ptp_clock_driver_api { +__subsystem struct ptp_clock_driver_api { int (*set)(struct device *dev, struct net_ptp_time *tm); int (*get)(struct device *dev, struct net_ptp_time *tm); int (*adjust)(struct device *dev, int increment); diff --git a/include/toolchain/common.h b/include/toolchain/common.h index 6f48245fa7ab4..331ed433be059 100644 --- a/include/toolchain/common.h +++ b/include/toolchain/common.h @@ -132,6 +132,11 @@ #define __syscall #endif /* #ifndef ZTEST_UNITTEST */ +/* Used as a sentinel by parse_syscalls.py to identify what API structs + * define driver subsystems. + */ +#define __subsystem + #ifndef BUILD_ASSERT /* compile-time assertion that makes the build fail */ #define BUILD_ASSERT(EXPR) \ diff --git a/samples/userspace/prod_consumer/src/sample_driver.h b/samples/userspace/prod_consumer/src/sample_driver.h index 4f0e52a477d27..ec7ae867568a1 100644 --- a/samples/userspace/prod_consumer/src/sample_driver.h +++ b/samples/userspace/prod_consumer/src/sample_driver.h @@ -23,7 +23,7 @@ typedef int (*sample_driver_set_callback_t)(struct device *dev, typedef int (*sample_driver_state_set_t)(struct device *dev, bool active); -struct sample_driver_api { +__subsystem struct sample_driver_api { sample_driver_write_t write; sample_driver_set_callback_t set_callback; sample_driver_state_set_t state_set; diff --git a/scripts/gen_kobject_list.py b/scripts/gen_kobject_list.py index 596102627c71e..e565835844a8b 100755 --- a/scripts/gen_kobject_list.py +++ b/scripts/gen_kobject_list.py @@ -56,6 +56,7 @@ import math import os import struct +import json from elf_helper import ElfHelper, kobject_to_enum from collections import OrderedDict @@ -90,33 +91,13 @@ ("k_futex", (None, True)) ]) - - subsystems = [ - "adc_driver_api", - "aio_cmp_driver_api", - "counter_driver_api", - "crypto_driver_api", - "dma_driver_api", - "flash_driver_api", - "gpio_driver_api", - "i2c_driver_api", - "i2s_driver_api", - "ipm_driver_api", - "led_driver_api", - "pinmux_driver_api", - "pwm_driver_api", - "entropy_driver_api", - "sensor_driver_api", - "spi_driver_api", - "uart_driver_api", - "can_driver_api", - "ptp_clock_driver_api", - "eeprom_driver_api", - "wdt_driver_api", - - # Fake 'sample driver' subsystem, used by tests/samples - "sample_driver_api" + # Editing the list is deprecated, add the __subsystem sentinal to your driver + # api declaration instead. e.x. + # + # __subsystem struct my_driver_api { + # .... + #}; ] header = """%compare-lengths @@ -331,6 +312,11 @@ def write_kobj_size_output(fp): fp.write("#endif\n") +def parse_subsystems_list_file(path): + with open(path, "r") as fp: + subsys_list = json.load(fp) + subsystems.extend(subsys_list) + def parse_args(): global args @@ -355,6 +341,11 @@ def parse_args(): parser.add_argument( "-Z", "--kobj-size-output", required=False, help="Output case statements for obj_size_get()") + parser.add_argument("-i", "--include-subsystem-list", required=False, action='append', + help='''Specifies a file with a JSON encoded list of subsystem names to append to + the driver subsystems list. Can be specified multiple times: + -i file1 -i file2 ...''') + parser.add_argument("-v", "--verbose", action="store_true", help="Print extra debugging information") args = parser.parse_args() @@ -365,6 +356,10 @@ def parse_args(): def main(): parse_args() + if args.include_subsystem_list is not None: + for list_file in args.include_subsystem_list: + parse_subsystems_list_file(list_file) + if args.gperf_output: assert args.kernel, "--kernel ELF required for --gperf-output" eh = ElfHelper(args.kernel, args.verbose, kobjects, subsystems) diff --git a/scripts/parse_syscalls.py b/scripts/parse_syscalls.py index 2d79b535b0776..25c56223da84e 100644 --- a/scripts/parse_syscalls.py +++ b/scripts/parse_syscalls.py @@ -5,7 +5,7 @@ # SPDX-License-Identifier: Apache-2.0 """ -Script to scan Zephyr include directories and emit system call metadata +Script to scan Zephyr include directories and emit system call and subsystem metadata System calls require a great deal of boilerplate code in order to implement completely. This script is the first step in the build system's process of @@ -26,7 +26,7 @@ import os import json -api_regex = re.compile(r''' +syscall_regex = re.compile(r''' __syscall\s+ # __syscall attribute, must be first ([^(]+) # type and name of system call (split later) [(] # Function opening parenthesis @@ -34,9 +34,16 @@ [)] # Closing parenthesis ''', re.MULTILINE | re.VERBOSE) +subsys_regex = re.compile(r''' +__subsystem\s+ # __subsystem attribute, must be first +struct\s+ # struct keyword is next +([^{]+) # name of subsystem +[{] # Open curly bracket +''', re.MULTILINE | re.VERBOSE) def analyze_headers(multiple_directories): - ret = [] + syscall_ret = [] + subsys_ret = [] for base_path in multiple_directories: for root, dirs, files in os.walk(base_path, topdown=True): @@ -44,23 +51,41 @@ def analyze_headers(multiple_directories): files.sort() for fn in files: - # toolchain/common.h has the definition of __syscall which we + # toolchain/common.h has the definitions of __syscall and __subsystem which we # don't want to trip over path = os.path.join(root, fn) if not fn.endswith(".h") or path.endswith(os.path.join(os.sep, 'toolchain', 'common.h')): continue with open(path, "r", encoding="utf-8") as fp: - try: - result = [(mo.groups(), fn) - for mo in api_regex.finditer(fp.read())] - except Exception: - sys.stderr.write("While parsing %s\n" % fn) - raise + contents = fp.read() + + try: + syscall_result = [(mo.groups(), fn) + for mo in syscall_regex.finditer(contents)] + subsys_result = [mo.groups()[0].strip() + for mo in subsys_regex.finditer(contents)] + except Exception: + sys.stderr.write("While parsing %s\n" % fn) + raise - ret.extend(result) + syscall_ret.extend(syscall_result) + subsys_ret.extend(subsys_result) - return ret + return syscall_ret, subsys_ret + + +def update_file_if_changed(path, new): + if os.path.exists(path): + with open(path, 'r') as fp: + old = fp.read() + + if new != old: + with open(path, 'w') as fp: + fp.write(new) + else: + with open(path, 'w') as fp: + fp.write(new) def parse_args(): @@ -76,34 +101,33 @@ def parse_args(): parser.add_argument( "-j", "--json-file", required=True, help="Write system call prototype information as json to file") + parser.add_argument( + "-s", "--subsystem-file", required=True, + help="Write subsystem name information as json to file") args = parser.parse_args() def main(): parse_args() - syscalls = analyze_headers(args.include) + syscalls, subsys = analyze_headers(args.include) + + # Only write json files if they don't exist or have changes since + # they will force and incremental rebuild. syscalls_in_json = json.dumps( syscalls, indent=4, sort_keys=True ) + update_file_if_changed(args.json_file, syscalls_in_json) - # Check if the file already exists, and if there are no changes, - # don't touch it since that will force an incremental rebuild - path = args.json_file - new = syscalls_in_json - if os.path.exists(path): - with open(path, 'r') as fp: - old = fp.read() - - if new != old: - with open(path, 'w') as fp: - fp.write(new) - else: - with open(path, 'w') as fp: - fp.write(new) + subsys_in_json = json.dumps( + subsys, + indent=4, + sort_keys=True + ) + update_file_if_changed(args.subsystem_file, subsys_in_json) if __name__ == "__main__":