Device initialization may require use of generic services such as starting up power rails, some of which may be controlled by GPIOs on an external controller that can't be used until full kernel services are available. Generic services can check k_is_in_isr() and mediate their behavior that way, but currently have no way to determine that the kernel is not available. Provide a function that indicates whether initialization is still in pre-kernel stages where no kernel services are available. Signed-off-by: Peter A. Bigot <pab@pabigot.com>
260 lines
5.8 KiB
C
260 lines
5.8 KiB
C
/*
|
|
* Copyright (c) 2018 Intel Corporation
|
|
*
|
|
* SPDX-License-Identifier: Apache-2.0
|
|
*/
|
|
|
|
#include <zephyr.h>
|
|
#include <device.h>
|
|
#include <init.h>
|
|
#include <ztest.h>
|
|
#include <sys/printk.h>
|
|
|
|
|
|
#define DUMMY_PORT_1 "dummy"
|
|
#define DUMMY_PORT_2 "dummy_driver"
|
|
#define BAD_DRIVER "bad_driver"
|
|
|
|
/**
|
|
* @brief Test cases to verify device objects
|
|
*
|
|
* Verify zephyr device driver apis with different device types
|
|
*
|
|
* @defgroup kernel_device_tests Device
|
|
*
|
|
* @ingroup all_tests
|
|
*
|
|
* @{
|
|
*/
|
|
|
|
/**
|
|
* @brief Test device object binding
|
|
*
|
|
* Validates device binding for an existing and a non-existing device object.
|
|
* It creates a dummy_driver device object with basic init and configuration
|
|
* information and validates its binding.
|
|
*
|
|
* @see device_get_binding(), device_busy_set(), device_busy_clear(),
|
|
* DEVICE_AND_API_INIT()
|
|
*/
|
|
void test_dummy_device(void)
|
|
{
|
|
struct device *dev;
|
|
|
|
dev = device_get_binding(DUMMY_PORT_1);
|
|
zassert_equal(dev, NULL, NULL);
|
|
dev = device_get_binding(DUMMY_PORT_2);
|
|
zassert_false((dev == NULL), NULL);
|
|
|
|
device_busy_set(dev);
|
|
device_busy_clear(dev);
|
|
|
|
/* device_get_binding() returns false for device object
|
|
* with failed init.
|
|
*/
|
|
dev = device_get_binding(BAD_DRIVER);
|
|
zassert_true((dev == NULL), NULL);
|
|
}
|
|
|
|
/**
|
|
* @brief Test device binding for existing device
|
|
*
|
|
* Validates device binding for an existing device object.
|
|
*
|
|
* @see device_get_binding(), DEVICE_AND_API_INIT()
|
|
*/
|
|
static void test_dynamic_name(void)
|
|
{
|
|
struct device *mux;
|
|
char name[sizeof(DUMMY_PORT_2)];
|
|
|
|
snprintk(name, sizeof(name), "%s", DUMMY_PORT_2);
|
|
mux = device_get_binding(name);
|
|
zassert_true(mux != NULL, NULL);
|
|
}
|
|
|
|
/**
|
|
* @brief Test device binding for non-existing device
|
|
*
|
|
* Validates binding of a random device driver(non-defined driver) named
|
|
* "ANOTHER_BOGUS_NAME".
|
|
*
|
|
* @see device_get_binding(), DEVICE_AND_API_INIT()
|
|
*/
|
|
static void test_bogus_dynamic_name(void)
|
|
{
|
|
struct device *mux;
|
|
char name[64];
|
|
|
|
snprintk(name, sizeof(name), "ANOTHER_BOGUS_NAME");
|
|
mux = device_get_binding(name);
|
|
zassert_true(mux == NULL, NULL);
|
|
}
|
|
|
|
static struct init_record {
|
|
bool pre_kernel;
|
|
bool is_in_isr;
|
|
bool is_pre_kernel;
|
|
} init_records[4];
|
|
|
|
static struct init_record *rp = init_records;
|
|
|
|
static int add_init_record(bool pre_kernel)
|
|
{
|
|
rp->pre_kernel = pre_kernel;
|
|
rp->is_pre_kernel = k_is_pre_kernel();
|
|
rp->is_in_isr = k_is_in_isr();
|
|
++rp;
|
|
return 0;
|
|
}
|
|
|
|
static int pre1_fn(struct device *dev)
|
|
{
|
|
return add_init_record(true);
|
|
}
|
|
|
|
static int pre2_fn(struct device *dev)
|
|
{
|
|
return add_init_record(true);
|
|
}
|
|
|
|
static int post_fn(struct device *dev)
|
|
{
|
|
return add_init_record(false);
|
|
}
|
|
|
|
static int app_fn(struct device *dev)
|
|
{
|
|
return add_init_record(false);
|
|
}
|
|
|
|
SYS_INIT(pre1_fn, PRE_KERNEL_1, 0);
|
|
SYS_INIT(pre2_fn, PRE_KERNEL_2, 0);
|
|
SYS_INIT(post_fn, POST_KERNEL, 0);
|
|
SYS_INIT(app_fn, APPLICATION, 0);
|
|
|
|
/**
|
|
* @brief Test detection of initialization before kernel services available.
|
|
*
|
|
* Confirms check is correct.
|
|
*
|
|
* @see k_is_pre_kernel()
|
|
*/
|
|
void test_pre_kernel_detection(void)
|
|
{
|
|
struct init_record *rpe = rp;
|
|
|
|
zassert_equal(rp - init_records, 4U,
|
|
"bad record count");
|
|
rp = init_records;
|
|
while ((rp < rpe) && rp->pre_kernel) {
|
|
zassert_equal(rp->is_in_isr, false,
|
|
"rec %zu isr", rp - init_records);
|
|
zassert_equal(rp->is_pre_kernel, true,
|
|
"rec %zu pre-kernel", rp - init_records);
|
|
++rp;
|
|
}
|
|
zassert_equal(rp - init_records, 2U,
|
|
"bad pre-kernel count");
|
|
|
|
while (rp < rpe) {
|
|
zassert_equal(rp->is_in_isr, false,
|
|
"rec %zu isr", rp - init_records);
|
|
zassert_equal(rp->is_pre_kernel, false,
|
|
"rec %zu post-kernel", rp - init_records);
|
|
++rp;
|
|
}
|
|
}
|
|
|
|
#ifdef CONFIG_DEVICE_POWER_MANAGEMENT
|
|
/**
|
|
* @brief Test system device list query API with PM enabled.
|
|
*
|
|
* It queries the list of devices in the system, used to suspend or
|
|
* resume the devices in PM applications.
|
|
*
|
|
* @see device_list_get()
|
|
*/
|
|
static void build_suspend_device_list(void)
|
|
{
|
|
int devcount;
|
|
struct device *devices;
|
|
|
|
device_list_get(&devices, &devcount);
|
|
zassert_false((devcount == 0), NULL);
|
|
}
|
|
|
|
/**
|
|
* @brief Test device binding for existing device with PM enabled.
|
|
*
|
|
* Validates device binding for an existing device object with Power management
|
|
* enabled. It also checks if the device is in the middle of a transaction,
|
|
* sets/clears busy status and validates status again.
|
|
*
|
|
* @see device_get_binding(), device_busy_set(), device_busy_clear(),
|
|
* device_busy_check(), device_any_busy_check(),
|
|
* device_list_get(), device_set_power_state()
|
|
*/
|
|
void test_dummy_device_pm(void)
|
|
{
|
|
struct device *dev;
|
|
int busy, ret;
|
|
|
|
dev = device_get_binding(DUMMY_PORT_2);
|
|
zassert_false((dev == NULL), NULL);
|
|
|
|
busy = device_any_busy_check();
|
|
zassert_true((busy == 0), NULL);
|
|
|
|
/* Set device state to DEVICE_PM_ACTIVE_STATE */
|
|
ret = device_set_power_state(dev, DEVICE_PM_ACTIVE_STATE, NULL, NULL);
|
|
zassert_true((ret == 0), "Unable to set active state to device");
|
|
|
|
device_busy_set(dev);
|
|
|
|
busy = device_any_busy_check();
|
|
zassert_false((busy == 0), NULL);
|
|
|
|
busy = device_busy_check(dev);
|
|
zassert_false((busy == 0), NULL);
|
|
|
|
device_busy_clear(dev);
|
|
|
|
busy = device_busy_check(dev);
|
|
zassert_true((busy == 0), NULL);
|
|
|
|
/* Set device state to DEVICE_PM_FORCE_SUSPEND_STATE */
|
|
ret = device_set_power_state(dev,
|
|
DEVICE_PM_FORCE_SUSPEND_STATE, NULL, NULL);
|
|
zassert_true((ret == 0), "Unable to force suspend device");
|
|
|
|
build_suspend_device_list();
|
|
}
|
|
#else
|
|
static void build_suspend_device_list(void)
|
|
{
|
|
ztest_test_skip();
|
|
}
|
|
|
|
void test_dummy_device_pm(void)
|
|
{
|
|
ztest_test_skip();
|
|
}
|
|
#endif
|
|
|
|
/**
|
|
* @}
|
|
*/
|
|
|
|
void test_main(void)
|
|
{
|
|
ztest_test_suite(device,
|
|
ztest_unit_test(test_dummy_device_pm),
|
|
ztest_unit_test(build_suspend_device_list),
|
|
ztest_unit_test(test_dummy_device),
|
|
ztest_unit_test(test_pre_kernel_detection),
|
|
ztest_user_unit_test(test_bogus_dynamic_name),
|
|
ztest_user_unit_test(test_dynamic_name));
|
|
ztest_run_test_suite(device);
|
|
}
|