1/*
2 * Copyright 2020, Data61
3 * Commonwealth Scientific and Industrial Research Organisation (CSIRO)
4 * ABN 41 687 119 230.
5 *
6 * This software may be distributed and modified according to the terms of
7 * the BSD 2-Clause license. Note that NO WARRANTY is provided.
8 * See "LICENSE_BSD2.txt" for details.
9 *
10 * @TAG(DATA61_BSD)
11 */
12
13#pragma once
14
15#include <utils/util.h>
16#include <platsupport/io.h>
17
18/*
19 * These macros are used to check if compat_list or init_func
20 * passed to PS_DRIVER_MODULE_DEFINE are not NULL or 0
21 */
22#define PS_INVALID_ADDR_0 0,
23#define PS_INVALID_ADDR_NULL 0,
24#define __third_arg(_, __, val, ...) val
25#define IS_NULL(compat_list, init_func) \
26    __IS_NULL(PS_INVALID_##compat_list, PS_INVALID_##init_func)
27// arg1 and arg2 will expand to real argument only when the pointers are NULL or 0
28// thus selecting the thrid arg will tell us whether one of them is NULL
29#define __IS_NULL(arg1, arg2) __third_arg(arg1 arg2 INVALID, INVALID, VALID)
30
31#define PS_DRIVER_MODULE_DEFINE(name, compat_list, init_func)                   \
32    __PS_DRIVER_MODULE_DEFINE(IS_NULL(ADDR_##compat_list, ADDR_##init_func),    \
33            name, compat_list, init_func)
34#define __PS_DRIVER_MODULE_DEFINE(null, name, compat_list, init_func)           \
35    ____PS_DRIVER_MODULE_DEFINE(null, name, compat_list, init_func)
36#define ____PS_DRIVER_MODULE_DEFINE(null, name, compat_list, init_func)         \
37    PS_DRIVER_MODULE_DEFINE_##null(name, compat_list, init_func)
38#define PS_DRIVER_MODULE_DEFINE_INVALID(name, compat_list, init_func)           \
39    "compat_list and init_func must not be NULL"
40#define PS_DRIVER_MODULE_DEFINE_VALID(name, compat_list, init_func)             \
41    static ps_driver_module_t name = {                                          \
42        .compatible_list = compat_list,                                         \
43        .init = init_func                                                       \
44    };                                                                          \
45    USED SECTION("_driver_modules") ps_driver_module_t *name##_ptr = &name;
46
47#define PS_DRIVER_INIT_SUCCESS 0
48#define PS_DRIVER_INIT_DEFER 1
49
50/*
51 * Returns:
52 *  - negative on error
53 *  - PS_DRIVER_INIT_SUCCESS on success
54 *  - PS_DRIVER_INIT_DEFER when you want to defer this initialisation function until later
55 */
56typedef int (*ps_driver_init_fn_t)(ps_io_ops_t *io_ops, const char *device_path);
57
58typedef struct {
59    const char **compatible_list;
60    ps_driver_init_fn_t init;
61} ps_driver_module_t;
62