/* * Copyright (c) 2020 The ZMK Contributors * * SPDX-License-Identifier: MIT */ #pragma once #include #include #include #include #include #include #include #include /** * @cond INTERNAL_HIDDEN * * Behavior driver API definition and system call entry points. * * (Internal use only.) */ struct behavior_parameter_value_metadata { char *display_name; union { uint32_t value; struct { int32_t min; int32_t max; } range; }; enum { BEHAVIOR_PARAMETER_VALUE_TYPE_NIL = 0, BEHAVIOR_PARAMETER_VALUE_TYPE_VALUE = 1, BEHAVIOR_PARAMETER_VALUE_TYPE_RANGE = 2, BEHAVIOR_PARAMETER_VALUE_TYPE_HID_USAGE = 3, BEHAVIOR_PARAMETER_VALUE_TYPE_LAYER_ID = 4, } type; }; struct behavior_parameter_metadata_set { size_t param1_values_len; const struct behavior_parameter_value_metadata *param1_values; size_t param2_values_len; const struct behavior_parameter_value_metadata *param2_values; }; struct behavior_parameter_metadata { size_t sets_len; const struct behavior_parameter_metadata_set *sets; }; enum behavior_sensor_binding_process_mode { BEHAVIOR_SENSOR_BINDING_PROCESS_MODE_TRIGGER, BEHAVIOR_SENSOR_BINDING_PROCESS_MODE_DISCARD, }; typedef int (*behavior_keymap_binding_callback_t)(struct zmk_behavior_binding *binding, struct zmk_behavior_binding_event event); typedef int (*behavior_sensor_keymap_binding_process_callback_t)( struct zmk_behavior_binding *binding, struct zmk_behavior_binding_event event, enum behavior_sensor_binding_process_mode mode); typedef int (*behavior_sensor_keymap_binding_accept_data_callback_t)( struct zmk_behavior_binding *binding, struct zmk_behavior_binding_event event, const struct zmk_sensor_config *sensor_config, size_t channel_data_size, const struct zmk_sensor_channel_data channel_data[channel_data_size]); #if IS_ENABLED(CONFIG_ZMK_BEHAVIOR_METADATA) typedef int (*behavior_get_parameter_metadata_t)( const struct device *behavior, struct behavior_parameter_metadata *param_metadata); #endif // IS_ENABLED(CONFIG_ZMK_BEHAVIOR_METADATA) enum behavior_locality { BEHAVIOR_LOCALITY_CENTRAL, BEHAVIOR_LOCALITY_EVENT_SOURCE, BEHAVIOR_LOCALITY_GLOBAL }; __subsystem struct behavior_driver_api { enum behavior_locality locality; behavior_keymap_binding_callback_t binding_convert_central_state_dependent_params; behavior_keymap_binding_callback_t binding_pressed; behavior_keymap_binding_callback_t binding_released; behavior_sensor_keymap_binding_accept_data_callback_t sensor_binding_accept_data; behavior_sensor_keymap_binding_process_callback_t sensor_binding_process; #if IS_ENABLED(CONFIG_ZMK_BEHAVIOR_METADATA) behavior_get_parameter_metadata_t get_parameter_metadata; const struct behavior_parameter_metadata *parameter_metadata; #endif // IS_ENABLED(CONFIG_ZMK_BEHAVIOR_METADATA) }; /** * @endcond */ struct zmk_behavior_metadata { #if IS_ENABLED(CONFIG_ZMK_BEHAVIOR_METADATA) const char *display_name; #endif // IS_ENABLED(CONFIG_ZMK_BEHAVIOR_METADATA) }; struct zmk_behavior_ref { const struct device *device; const struct zmk_behavior_metadata metadata; }; #if IS_ENABLED(CONFIG_ZMK_BEHAVIOR_LOCAL_IDS) struct zmk_behavior_local_id_map { const struct device *device; zmk_behavior_local_id_t local_id; }; #endif // IS_ENABLED(CONFIG_ZMK_BEHAVIOR_LOCAL_IDS) #define ZMK_BEHAVIOR_REF_DT_NAME(node_id) _CONCAT(zmk_behavior_, DEVICE_DT_NAME_GET(node_id)) #if IS_ENABLED(CONFIG_ZMK_BEHAVIOR_METADATA) #define ZMK_BEHAVIOR_METADATA_INITIALIZER(node_id) \ { .display_name = DT_PROP_OR(node_id, display_name, DEVICE_DT_NAME(node_id)), } #else #define ZMK_BEHAVIOR_METADATA_INITIALIZER(node_id) \ {} #endif // IS_ENABLED(CONFIG_ZMK_BEHAVIOR_METADATA) #define ZMK_BEHAVIOR_REF_INITIALIZER(node_id, _dev) \ { .device = _dev, .metadata = ZMK_BEHAVIOR_METADATA_INITIALIZER(node_id), } #define ZMK_BEHAVIOR_LOCAL_ID_MAP_INITIALIZER(node_id, _dev) \ { .device = _dev, } #define ZMK_BEHAVIOR_REF_DEFINE(name, node_id, _dev) \ static const STRUCT_SECTION_ITERABLE(zmk_behavior_ref, name) = \ ZMK_BEHAVIOR_REF_INITIALIZER(node_id, _dev); \ COND_CODE_1(IS_ENABLED(CONFIG_ZMK_BEHAVIOR_LOCAL_IDS), \ (static const STRUCT_SECTION_ITERABLE(zmk_behavior_local_id_map, \ _CONCAT(_zmk_behavior_local_id_map, name)) = \ ZMK_BEHAVIOR_LOCAL_ID_MAP_INITIALIZER(node_id, _dev)), \ ()); #define ZMK_BEHAVIOR_REF_DT_DEFINE(node_id) \ ZMK_BEHAVIOR_REF_DEFINE(ZMK_BEHAVIOR_REF_DT_NAME(node_id), node_id, DEVICE_DT_GET(node_id)) /** * Registers @p node_id as a behavior. */ #define BEHAVIOR_DEFINE(node_id) ZMK_BEHAVIOR_REF_DT_DEFINE(node_id) /** * @brief Like DEVICE_DT_DEFINE(), but also registers the device as a behavior. * * @param node_id The devicetree node identifier. * @param ... Other parameters as expected by DEVICE_DT_DEFINE. */ #define BEHAVIOR_DT_DEFINE(node_id, ...) \ DEVICE_DT_DEFINE(node_id, __VA_ARGS__); \ BEHAVIOR_DEFINE(node_id) /** * @brief Like DEVICE_DT_INST_DEFINE(), but also registers the device as a behavior. * * @param inst Instance number. * @param ... Other parameters as expected by DEVICE_DT_DEFINE. */ #define BEHAVIOR_DT_INST_DEFINE(inst, ...) \ DEVICE_DT_INST_DEFINE(inst, __VA_ARGS__); \ BEHAVIOR_DEFINE(DT_DRV_INST(inst)) /** * @brief Validate a given behavior binding is valid, including parameter validation * if the metadata feature is enablued. * * @param binding The behavior binding to validate. * * @retval 0 if the passed in binding is valid. * @retval -ENODEV if the binding references a non-existant behavior. * @retval -EINVAL if parameters are not valid for the behavior metadata. */ int zmk_behavior_validate_binding(const struct zmk_behavior_binding *binding); #if IS_ENABLED(CONFIG_ZMK_BEHAVIOR_METADATA) int zmk_behavior_get_empty_param_metadata(const struct device *dev, struct behavior_parameter_metadata *metadata); /** * @brief Validate a given behavior parameters match the behavior metadata. * * @param metadata The behavior metadata to validate against * @param param1 The first parameter value * @param param2 The second parameter value * * @retval 0 if the passed in parameters are valid. * @retval -ENODEV if metadata is NULL. * @retval -EINVAL if parameters are not valid for the metadata. */ int zmk_behavior_check_params_match_metadata(const struct behavior_parameter_metadata *metadata, uint32_t param1, uint32_t param2); /** * @brief Validate a given behavior parameter matches the behavior metadata parameter values. * * @param values The values to validate against * @param values_len How many values to check * @param param The value to check. * * @retval 0 if the passed in parameter is valid. * @retval -ENODEV if values is NULL. * @retval -EINVAL if parameter is not valid for the value metadata. */ int zmk_behavior_validate_param_values(const struct behavior_parameter_value_metadata *values, size_t values_len, uint32_t param); #endif // IS_ENABLED(CONFIG_ZMK_BEHAVIOR_METADATA) /** * Syscall wrapper for zmk_behavior_get_binding(). * * Use zmk_behavior_get_binding() in application code instead. */ __syscall const struct device *behavior_get_binding(const char *name); /** * @brief Handle the keymap binding which needs to be converted from relative "toggle" to absolute * "turn on" * @param binding Pointer to the details so of the binding * @param event The event that triggered use of the binding * * @retval 0 If successful. * @retval Negative errno code if failure. */ __syscall int behavior_keymap_binding_convert_central_state_dependent_params( struct zmk_behavior_binding *binding, struct zmk_behavior_binding_event event); static inline int z_impl_behavior_keymap_binding_convert_central_state_dependent_params( struct zmk_behavior_binding *binding, struct zmk_behavior_binding_event event) { const struct device *dev = zmk_behavior_get_binding(binding->behavior_dev); const struct behavior_driver_api *api = (const struct behavior_driver_api *)dev->api; if (api->binding_convert_central_state_dependent_params == NULL) { return 0; } return api->binding_convert_central_state_dependent_params(binding, event); } #if IS_ENABLED(CONFIG_ZMK_BEHAVIOR_METADATA) /** * @brief Determine where the behavior should be run * @param behavior Pointer to the device structure for the driver instance. * * @retval Zero if successful. * @retval Negative errno code if failure. */ __syscall int behavior_get_parameter_metadata(const struct device *behavior, struct behavior_parameter_metadata *param_metadata); static inline int z_impl_behavior_get_parameter_metadata(const struct device *behavior, struct behavior_parameter_metadata *param_metadata) { if (behavior == NULL || param_metadata == NULL) { return -EINVAL; } const struct behavior_driver_api *api = (const struct behavior_driver_api *)behavior->api; if (api->get_parameter_metadata) { return api->get_parameter_metadata(behavior, param_metadata); } else if (api->parameter_metadata) { *param_metadata = *api->parameter_metadata; } else { return -ENODEV; } return 0; } #endif // IS_ENABLED(CONFIG_ZMK_BEHAVIOR_METADATA) /** * @brief Determine where the behavior should be run * @param behavior Pointer to the device structure for the driver instance. * * @retval Zero if successful. * @retval Negative errno code if failure. */ __syscall int behavior_get_locality(const struct device *behavior, enum behavior_locality *locality); static inline int z_impl_behavior_get_locality(const struct device *behavior, enum behavior_locality *locality) { if (behavior == NULL) { return -EINVAL; } const struct behavior_driver_api *api = (const struct behavior_driver_api *)behavior->api; *locality = api->locality; return 0; } /** * @brief Handle the keymap binding being pressed * @param dev Pointer to the device structure for the driver instance. * @param param1 User parameter specified at time of behavior binding. * @param param2 User parameter specified at time of behavior binding. * * @retval 0 If successful. * @retval Negative errno code if failure. */ __syscall int behavior_keymap_binding_pressed(struct zmk_behavior_binding *binding, struct zmk_behavior_binding_event event); static inline int z_impl_behavior_keymap_binding_pressed(struct zmk_behavior_binding *binding, struct zmk_behavior_binding_event event) { const struct device *dev = zmk_behavior_get_binding(binding->behavior_dev); if (dev == NULL) { return -EINVAL; } const struct behavior_driver_api *api = (const struct behavior_driver_api *)dev->api; if (api->binding_pressed == NULL) { return -ENOTSUP; } return api->binding_pressed(binding, event); } /** * @brief Handle the assigned position being pressed * @param dev Pointer to the device structure for the driver instance. * @param param1 User parameter specified at time of behavior assignment. * * @retval 0 If successful. * @retval Negative errno code if failure. */ __syscall int behavior_keymap_binding_released(struct zmk_behavior_binding *binding, struct zmk_behavior_binding_event event); static inline int z_impl_behavior_keymap_binding_released(struct zmk_behavior_binding *binding, struct zmk_behavior_binding_event event) { const struct device *dev = zmk_behavior_get_binding(binding->behavior_dev); if (dev == NULL) { return -EINVAL; } const struct behavior_driver_api *api = (const struct behavior_driver_api *)dev->api; if (api->binding_released == NULL) { return -ENOTSUP; } return api->binding_released(binding, event); } /** * @brief Handle the a sensor keymap binding processing any incoming data from the sensor * @param binding Sensor keymap binding which was triggered. * @param sensor Pointer to the sensor device structure for the sensor driver instance. * @param virtual_key_position ZMK_KEYMAP_LEN + sensor number * @param timestamp Time at which the binding was triggered. * * @retval 0 If successful. * @retval Negative errno code if failure. */ __syscall int behavior_sensor_keymap_binding_accept_data( struct zmk_behavior_binding *binding, struct zmk_behavior_binding_event event, const struct zmk_sensor_config *sensor_config, size_t channel_data_size, const struct zmk_sensor_channel_data *channel_data); static inline int z_impl_behavior_sensor_keymap_binding_accept_data( struct zmk_behavior_binding *binding, struct zmk_behavior_binding_event event, const struct zmk_sensor_config *sensor_config, size_t channel_data_size, const struct zmk_sensor_channel_data *channel_data) { const struct device *dev = zmk_behavior_get_binding(binding->behavior_dev); if (dev == NULL) { return -EINVAL; } const struct behavior_driver_api *api = (const struct behavior_driver_api *)dev->api; if (api->sensor_binding_accept_data == NULL) { return -ENOTSUP; } return api->sensor_binding_accept_data(binding, event, sensor_config, channel_data_size, channel_data); } /** * @brief Handle the keymap sensor binding being triggered after updating any local data * @param dev Pointer to the device structure for the driver instance. * @param param1 User parameter specified at time of behavior binding. * @param param2 User parameter specified at time of behavior binding. * * @retval 0 If successful. * @retval Negative errno code if failure. */ // clang-format off __syscall int behavior_sensor_keymap_binding_process( struct zmk_behavior_binding *binding, struct zmk_behavior_binding_event event, enum behavior_sensor_binding_process_mode mode); // clang-format on static inline int z_impl_behavior_sensor_keymap_binding_process(struct zmk_behavior_binding *binding, struct zmk_behavior_binding_event event, enum behavior_sensor_binding_process_mode mode) { const struct device *dev = zmk_behavior_get_binding(binding->behavior_dev); if (dev == NULL) { return -EINVAL; } const struct behavior_driver_api *api = (const struct behavior_driver_api *)dev->api; if (api->sensor_binding_process == NULL) { return -ENOTSUP; } return api->sensor_binding_process(binding, event, mode); } /** * @} */ #include