#include <drm/drm_atomic.h>
#include <drm/drm_drv.h>
#include <drm/drm_kunit_helpers.h>
#include <drm/drm_managed.h>
#include <kunit/resource.h>
#include <linux/device.h>
#include <linux/platform_device.h>
#define KUNIT_DEVICE_NAME "drm-kunit-mock-device"
static const struct drm_mode_config_funcs drm_mode_config_funcs = {
};
static int fake_probe(struct platform_device *pdev)
{
return 0;
}
static struct platform_driver fake_platform_driver = {
.probe = fake_probe,
.driver = {
.name = KUNIT_DEVICE_NAME,
},
};
static void kunit_action_platform_driver_unregister(void *ptr)
{
struct platform_driver *drv = ptr;
platform_driver_unregister(drv);
}
static void kunit_action_platform_device_put(void *ptr)
{
struct platform_device *pdev = ptr;
platform_device_put(pdev);
}
static void kunit_action_platform_device_del(void *ptr)
{
struct platform_device *pdev = ptr;
platform_device_del(pdev);
}
struct device *drm_kunit_helper_alloc_device(struct kunit *test)
{
struct platform_device *pdev;
int ret;
ret = platform_driver_register(&fake_platform_driver);
KUNIT_ASSERT_EQ(test, ret, 0);
ret = kunit_add_action_or_reset(test,
kunit_action_platform_driver_unregister,
&fake_platform_driver);
KUNIT_ASSERT_EQ(test, ret, 0);
pdev = platform_device_alloc(KUNIT_DEVICE_NAME, PLATFORM_DEVID_NONE);
KUNIT_ASSERT_NOT_ERR_OR_NULL(test, pdev);
ret = kunit_add_action_or_reset(test,
kunit_action_platform_device_put,
pdev);
KUNIT_ASSERT_EQ(test, ret, 0);
ret = platform_device_add(pdev);
KUNIT_ASSERT_EQ(test, ret, 0);
ret = kunit_add_action_or_reset(test,
kunit_action_platform_device_del,
pdev);
KUNIT_ASSERT_EQ(test, ret, 0);
return &pdev->dev;
}
EXPORT_SYMBOL_GPL(drm_kunit_helper_alloc_device);
void drm_kunit_helper_free_device(struct kunit *test, struct device *dev)
{
struct platform_device *pdev = to_platform_device(dev);
kunit_release_action(test,
kunit_action_platform_device_del,
pdev);
kunit_release_action(test,
kunit_action_platform_device_put,
pdev);
kunit_release_action(test,
kunit_action_platform_driver_unregister,
&fake_platform_driver);
}
EXPORT_SYMBOL_GPL(drm_kunit_helper_free_device);
struct drm_device *
__drm_kunit_helper_alloc_drm_device_with_driver(struct kunit *test,
struct device *dev,
size_t size, size_t offset,
const struct drm_driver *driver)
{
struct drm_device *drm;
void *container;
int ret;
container = __devm_drm_dev_alloc(dev, driver, size, offset);
if (IS_ERR(container))
return ERR_CAST(container);
drm = container + offset;
drm->mode_config.funcs = &drm_mode_config_funcs;
ret = drmm_mode_config_init(drm);
if (ret)
return ERR_PTR(ret);
return drm;
}
EXPORT_SYMBOL_GPL(__drm_kunit_helper_alloc_drm_device_with_driver);
static void action_drm_release_context(void *ptr)
{
struct drm_modeset_acquire_ctx *ctx = ptr;
drm_modeset_drop_locks(ctx);
drm_modeset_acquire_fini(ctx);
}
struct drm_modeset_acquire_ctx *
drm_kunit_helper_acquire_ctx_alloc(struct kunit *test)
{
struct drm_modeset_acquire_ctx *ctx;
int ret;
ctx = kunit_kzalloc(test, sizeof(*ctx), GFP_KERNEL);
KUNIT_ASSERT_NOT_NULL(test, ctx);
drm_modeset_acquire_init(ctx, 0);
ret = kunit_add_action_or_reset(test,
action_drm_release_context,
ctx);
if (ret)
return ERR_PTR(ret);
return ctx;
}
EXPORT_SYMBOL_GPL(drm_kunit_helper_acquire_ctx_alloc);
static void kunit_action_drm_atomic_state_put(void *ptr)
{
struct drm_atomic_state *state = ptr;
drm_atomic_state_put(state);
}
struct drm_atomic_state *
drm_kunit_helper_atomic_state_alloc(struct kunit *test,
struct drm_device *drm,
struct drm_modeset_acquire_ctx *ctx)
{
struct drm_atomic_state *state;
int ret;
state = drm_atomic_state_alloc(drm);
if (!state)
return ERR_PTR(-ENOMEM);
ret = kunit_add_action_or_reset(test,
kunit_action_drm_atomic_state_put,
state);
if (ret)
return ERR_PTR(ret);
state->acquire_ctx = ctx;
return state;
}
EXPORT_SYMBOL_GPL(drm_kunit_helper_atomic_state_alloc);
MODULE_AUTHOR("Maxime Ripard <maxime@cerno.tech>");
MODULE_LICENSE("GPL"