forked from kofal.net/zmk
feat(endpoints): add "no endpoint" value This adds ZMK_TRANSPORT_NONE, which can be set as the preferred endpoint transport if you wish to prevent the keyboard from sending any output. More usefully, it also is used to indicate that the preferred endpoint is not available and it could not fall back to an available one. To go along with this, many endpoint functions are renamed for consistency, and a few new functions are added: - zmk_endpoint_get_preferred_transport() returns the value that was set with zmk_endpoint_set_preferred_transport(). - zmk_endpoint_get_preferred() returns the endpoint that will be used if it is available. This endpoint always has the same transport as zmk_endpoint_get_preferred_transport(). - zmk_endpoint_is_connected() is a shortcut to check if the keyboard is actually connected to an endpoint. This change is based on #2572 but without the option to disable endpoint fallback. It does refactor code to allow adding that feature later. fix(endpoints): Add endpoint setting upgrade Adding ZMK_TRANSPORT_NONE at the start of enum zmk_transport results in the preferred transport setting no longer representing the same values when it is saved with earlier firmware and loaded with newer firmware. To fix this, the "endpoints/preferred" setting is now deprecated and replaced by "endpoints/preferred2". If the old setting is present, it is interpreted as the old enum type, upgraded to the new type, and saved immediately to the new setting. The old setting is then deleted. To avoid this happening again in the future, enum zmk_transport now has explicit values assigned to identifier, and a comment is also added to explain that existing values must not be changed. fix: Set default transport according to enabled transports The default value for preferred_transport is now set to USB only if CONFIG_ZMK_USB is enabled. If not, it falls back to BLE if CONFIG_ZMK_BLE is enabled, then to "none" if nothing is enabled.
137 lines
4.1 KiB
C
137 lines
4.1 KiB
C
/*
|
|
* Copyright (c) 2023 The ZMK Contributors
|
|
*
|
|
* SPDX-License-Identifier: MIT
|
|
*/
|
|
|
|
#include <zephyr/drivers/gpio.h>
|
|
#include <zephyr/devicetree.h>
|
|
#include <zephyr/init.h>
|
|
#include <zephyr/pm/device.h>
|
|
#include <zephyr/pm/device_runtime.h>
|
|
#include <zephyr/pm/pm.h>
|
|
#include <zephyr/sys/poweroff.h>
|
|
|
|
#include <zephyr/logging/log.h>
|
|
LOG_MODULE_DECLARE(zmk, CONFIG_ZMK_LOG_LEVEL);
|
|
|
|
#include <zmk/endpoints.h>
|
|
|
|
// Reimplement some of the device work from Zephyr PM to work with the new `sys_poweroff` API.
|
|
// TODO: Tweak this to smarter runtime PM of subsystems on sleep.
|
|
|
|
#ifdef CONFIG_ZMK_PM_DEVICE_SUSPEND_RESUME
|
|
TYPE_SECTION_START_EXTERN(const struct device *, pm_device_slots);
|
|
|
|
#if defined(CONFIG_PM_DEVICE_SYSTEM_MANAGED)
|
|
/* Number of devices successfully suspended. */
|
|
static size_t zmk_num_susp;
|
|
|
|
int zmk_pm_suspend_devices(void) {
|
|
const struct device *devs;
|
|
size_t devc;
|
|
|
|
devc = z_device_get_all_static(&devs);
|
|
|
|
zmk_num_susp = 0;
|
|
|
|
for (const struct device *dev = devs + devc - 1; dev >= devs; dev--) {
|
|
int ret;
|
|
|
|
/*
|
|
* Ignore uninitialized devices, busy devices, wake up sources, and
|
|
* devices with runtime PM enabled.
|
|
*/
|
|
if (!device_is_ready(dev) || pm_device_is_busy(dev) || pm_device_wakeup_is_enabled(dev) ||
|
|
pm_device_runtime_is_enabled(dev)) {
|
|
continue;
|
|
}
|
|
|
|
ret = pm_device_action_run(dev, PM_DEVICE_ACTION_SUSPEND);
|
|
/* ignore devices not supporting or already at the given state */
|
|
if ((ret == -ENOSYS) || (ret == -ENOTSUP) || (ret == -EALREADY)) {
|
|
continue;
|
|
} else if (ret < 0) {
|
|
LOG_ERR("Device %s did not enter %s state (%d)", dev->name,
|
|
pm_device_state_str(PM_DEVICE_STATE_SUSPENDED), ret);
|
|
return ret;
|
|
}
|
|
|
|
TYPE_SECTION_START(pm_device_slots)[zmk_num_susp] = dev;
|
|
zmk_num_susp++;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
void zmk_pm_resume_devices(void) {
|
|
for (int i = (zmk_num_susp - 1); i >= 0; i--) {
|
|
pm_device_action_run(TYPE_SECTION_START(pm_device_slots)[i], PM_DEVICE_ACTION_RESUME);
|
|
}
|
|
|
|
zmk_num_susp = 0;
|
|
}
|
|
#endif /* !CONFIG_PM_DEVICE_RUNTIME_EXCLUSIVE */
|
|
#endif /* CONFIG_ZMK_PM_DEVICE_SUSPEND_RESUME */
|
|
|
|
#if IS_ENABLED(CONFIG_ZMK_PM_SOFT_OFF)
|
|
|
|
#define HAS_WAKERS DT_HAS_COMPAT_STATUS_OKAY(zmk_soft_off_wakeup_sources)
|
|
|
|
#if HAS_WAKERS
|
|
|
|
#define DEVICE_WITH_SEP(node_id, prop, idx) DEVICE_DT_GET(DT_PROP_BY_IDX(node_id, prop, idx)),
|
|
|
|
const struct device *soft_off_wakeup_sources[] = {
|
|
DT_FOREACH_PROP_ELEM(DT_INST(0, zmk_soft_off_wakeup_sources), wakeup_sources, DEVICE_WITH_SEP)};
|
|
|
|
#endif
|
|
|
|
int zmk_pm_soft_off(void) {
|
|
#if IS_ENABLED(CONFIG_PM_DEVICE)
|
|
size_t device_count;
|
|
const struct device *devs;
|
|
|
|
#if !IS_ENABLED(CONFIG_ZMK_SPLIT) || IS_ENABLED(CONFIG_ZMK_SPLIT_ROLE_CENTRAL)
|
|
zmk_endpoint_clear_reports();
|
|
// Need to sleep to give any other threads a chance so submit endpoint data.
|
|
k_sleep(K_MSEC(100));
|
|
#endif
|
|
|
|
device_count = z_device_get_all_static(&devs);
|
|
|
|
// There may be some matrix/direct kscan devices that would be used for wakeup
|
|
// from normal "inactive goes to sleep" behavior, so disable them as wakeup devices
|
|
// and then suspend them so we're ready to take over setting up our system
|
|
// and then putting it into an off state.
|
|
LOG_DBG("soft-on-off pressed cb: suspend devices");
|
|
for (int i = 0; i < device_count; i++) {
|
|
const struct device *dev = &devs[i];
|
|
|
|
if (pm_device_wakeup_is_enabled(dev)) {
|
|
pm_device_wakeup_enable(dev, false);
|
|
}
|
|
pm_device_action_run(dev, PM_DEVICE_ACTION_SUSPEND);
|
|
}
|
|
#endif // IS_ENABLED(CONFIG_PM_DEVICE)
|
|
|
|
#if HAS_WAKERS
|
|
for (int i = 0; i < ARRAY_SIZE(soft_off_wakeup_sources); i++) {
|
|
const struct device *dev = soft_off_wakeup_sources[i];
|
|
pm_device_wakeup_enable(dev, true);
|
|
pm_device_action_run(dev, PM_DEVICE_ACTION_RESUME);
|
|
}
|
|
#endif // HAS_WAKERS
|
|
|
|
int err = zmk_pm_suspend_devices();
|
|
if (err < 0) {
|
|
zmk_pm_resume_devices();
|
|
return err;
|
|
}
|
|
|
|
LOG_DBG("soft-off: go to sleep");
|
|
sys_poweroff();
|
|
return 0;
|
|
}
|
|
|
|
#endif // IS_ENABLED(CONFIG_ZMK_PM_SOFT_OFF)
|