From ce2e4ebdf1087f060ce20b745f4ed74ebc86e7f7 Mon Sep 17 00:00:00 2001 From: Daniel Leung Date: Thu, 14 Apr 2016 09:28:33 -0700 Subject: [PATCH] device: add macro to assign driver_api at compile time This adds the DEVICE_AND_API_INIT() macro to take in a parameter to assign to device->driver_api. This eliminates the need to assign to driver_api during runtime device initialization. This provides an alternative way to declare devices. This should save a few bytes in ROM for those devices that will never fail initialization (in other words, never need to manipulate driver_api pointer at all). Also clean up the documentation a bit to remove duplicated block of information. Change-Id: I6abed1abe75db2e8babfcf1ecf590491132a5543 Signed-off-by: Daniel Leung --- doc/drivers/drivers.rst | 5 ++ include/device.h | 135 ++++++++++++++++++++++------------------ 2 files changed, 78 insertions(+), 62 deletions(-) diff --git a/doc/drivers/drivers.rst b/doc/drivers/drivers.rst index 1947e69c3b5..241d0e3e64c 100644 --- a/doc/drivers/drivers.rst +++ b/doc/drivers/drivers.rst @@ -28,6 +28,11 @@ applications. :c:func:`DEVICE_INIT()` create device object and set it up for boot time initialization. +:c:func:`DEVICE_AND_API_INIT()` + Create device object and set it up for boot time initialization. + This also takes a pointer to driver API struct for link time + pointer assignment. + :c:func:`DEVICE_NAME_GET()` Expands to the full name of a global device object. diff --git a/include/device.h b/include/device.h index a784c78fbd0..3ae69530676 100644 --- a/include/device.h +++ b/include/device.h @@ -38,7 +38,7 @@ extern "C" { /** * @def DEVICE_INIT * - * @brief create device object and set it up for boot time initialization + * @brief Create device object and set it up for boot time initialization. * * @details This macro defines a device object that is automatically * configured by the kernel during system initialization. @@ -58,23 +58,23 @@ extern "C" { * @param level The initialization level at which configuration occurs. * Must be one of the following symbols, which are listed in the order * they are performed by the kernel: - * - * PRIMARY: Used for devices that have no dependencies, such as those + * \n + * \li PRIMARY: Used for devices that have no dependencies, such as those * that rely solely on hardware present in the processor/SOC. These devices * cannot use any kernel services during configuration, since they are not * yet available. - * - * SECONDARY: Used for devices that rely on the initialization of devices + * \n + * \li SECONDARY: Used for devices that rely on the initialization of devices * initialized as part of the PRIMARY level. These devices cannot use any * kernel services during configuration, since they are not yet available. - * - * NANOKERNEL: Used for devices that require nanokernel services during + * \n + * \li NANOKERNEL: Used for devices that require nanokernel services during * configuration. - * - * MICROKERNEL: Used for devices that require microkernel services during + * \n + * \li MICROKERNEL: Used for devices that require microkernel services during * configuration. - * - * APPLICATION: Used for application components (i.e. non-kernel components) + * \n + * \li APPLICATION: Used for application components (i.e. non-kernel components) * that need automatic configuration. These devices can use all services * provided by the kernel during configuration. * @@ -87,8 +87,25 @@ extern "C" { * (e.g. CONFIG_KERNEL_INIT_PRIORITY_DEFAULT + 5). */ +/** + * @def DEVICE_AND_API_INIT + * + * @brief Create device object and set it up for boot time initialization, + * with the option to set driver_api. + * + * @details This macro defines a device object that is automatically + * configured by the kernel during system initialization. The driver_api + * is also be set here, eliminating the need to do that during initialization. + * + * \see DEVICE_INIT() for description on other parameters. + * + * @param api Provides an initial pointer to the API function struct + * used by the driver. Can be NULL. + */ + #ifndef CONFIG_DEVICE_POWER_MANAGEMENT -#define DEVICE_INIT(dev_name, drv_name, init_fn, data, cfg_info, level, prio) \ +#define DEVICE_AND_API_INIT(dev_name, drv_name, init_fn, data, cfg_info, \ + level, prio, api) \ \ static struct device_config __config_##dev_name __used \ __attribute__((__section__(".devconfig.init"))) = { \ @@ -99,65 +116,32 @@ extern "C" { static struct device (__device_##dev_name) __used \ __attribute__((__section__(".init_" #level STRINGIFY(prio)))) = { \ .config = &(__config_##dev_name), \ + .driver_api = api, \ .driver_data = data \ } + +#define DEVICE_INIT(dev_name, drv_name, init_fn, data, cfg_info, level, prio) \ + DEVICE_AND_API_INIT(dev_name, drv_name, init_fn, data, cfg_info, \ + level, prio, NULL) + #else /** - * @def DEVICE_INIT_PM + * @def DEVICE_AND_API_INIT_PM * - * @brief create device object and set it up for boot time initialization + * @brief Create device object and set it up for boot time initialization, + * with the options to set driver_api and device_pm_ops. * * @details This macro defines a device object that is automatically - * configured by the kernel during system initialization. - * - * @param dev_name Device name. - * - * @param drv_name The name this instance of the driver exposes to - * the system. - * - * @param init_fn Address to the init function of the driver. + * configured by the kernel during system initialization. This driver_api + * and device_pm_ops are also be set here. * * @param device_pm_ops Address to the device_pm_ops structure of the driver. * - * @param data Pointer to the device's configuration data. - * - * @param cfg_info The address to the structure containing the - * configuration information for this instance of the driver. - * - * @param level The initialization level at which configuration occurs. - * Must be one of the following symbols, which are listed in the order - * they are performed by the kernel: - * - * PRIMARY: Used for devices that have no dependencies, such as those - * that rely solely on hardware present in the processor/SOC. These devices - * cannot use any kernel services during configuration, since they are not - * yet available. - * - * SECONDARY: Used for devices that rely on the initialization of devices - * initialized as part of the PRIMARY level. These devices cannot use any - * kernel services during configuration, since they are not yet available. - * - * NANOKERNEL: Used for devices that require nanokernel services during - * configuration. - * - * MICROKERNEL: Used for devices that require microkernel services during - * configuration. - * - * APPLICATION: Used for application components (i.e. non-kernel components) - * that need automatic configuration. These devices can use all services - * provided by the kernel during configuration. - * - * @param prio The initialization priority of the device, relative to - * other devices of the same initialization level. Specified as an integer - * value in the range 0 to 99; lower values indicate earlier initialization. - * Must be a decimal integer literal without leading zeroes or sign (e.g. 32), - * or an equivalent symbolic name (e.g. \#define MY_INIT_PRIO 32); symbolic - * expressions are *not* permitted - * (e.g. CONFIG_KERNEL_INIT_PRIORITY_DEFAULT + 5). + * \see DEVICE_AND_API_INIT() for description on other parameters. */ -#define DEVICE_INIT_PM(dev_name, drv_name, init_fn, device_pm_ops, \ - data, cfg_info, level, prio) \ +#define DEVICE_AND_API_INIT_PM(dev_name, drv_name, init_fn, device_pm_ops, \ + data, cfg_info, level, prio, api) \ \ static struct device_config __config_##dev_name __used \ __attribute__((__section__(".devconfig.init"))) = { \ @@ -169,19 +153,46 @@ extern "C" { static struct device (__device_##dev_name) __used \ __attribute__((__section__(".init_" #level STRINGIFY(prio)))) = { \ .config = &(__config_##dev_name), \ + .driver_api = api, \ .driver_data = data \ } +/** + * @def DEVICE_INIT_PM + * + * @brief Create device object and set it up for boot time initialization, + * with the options to device_pm_ops. + * + * @details This macro defines a device object that is automatically + * configured by the kernel during system initialization. This device_pm_ops + * is also be set here. + * + * @param device_pm_ops Address to the device_pm_ops structure of the driver. + * + * \see DEVICE_INIT() for description on other parameters. + */ + +#define DEVICE_INIT_PM(dev_name, drv_name, init_fn, device_pm_ops, \ + data, cfg_info, level, prio) \ + DEVICE_AND_API_INIT_PM(dev_name, drv_name, init_fn, device_pm_ops, \ + data, cfg_info, level, prio, NULL) + /* * Create a default device_pm_ops for devices that do not call the * DEVICE_INIT_PM macro so that caller of hook functions * need not check dev_pm_ops != NULL. */ extern struct device_pm_ops device_pm_ops_nop; +#define DEVICE_AND_API_INIT(dev_name, drv_name, init_fn, data, cfg_info, \ + level, prio, api) \ + DEVICE_AND_API_INIT_PM(dev_name, drv_name, init_fn, \ + &device_pm_ops_nop, data, cfg_info, \ + level, prio, api) + #define DEVICE_INIT(dev_name, drv_name, init_fn, data, cfg_info, level, prio) \ - DEVICE_INIT_PM(dev_name, drv_name, init_fn, \ - &device_pm_ops_nop, data, cfg_info, \ - level, prio) + DEVICE_AND_API_INIT(dev_name, drv_name, init_fn, data, cfg_info, \ + level, prio, NULL) + #endif /**