diff --git a/doc/kernel/drivers/index.rst b/doc/kernel/drivers/index.rst index 96574e08995380..c1571edff32e3f 100644 --- a/doc/kernel/drivers/index.rst +++ b/doc/kernel/drivers/index.rst @@ -68,21 +68,24 @@ The following APIs for device drivers are provided by :file:`device.h`. The APIs are intended for use in device drivers only and should not be used in applications. -:c:func:`DEVICE_DEFINE()` +:c:macro:`DEVICE_DEFINE()` Create device object and related data structures including setting it up for boot-time initialization. -:c:func:`DEVICE_NAME_GET()` +:c:macro:`DEVICE_NAME_GET()` Converts a device identifier to the global identifier for a device object. -:c:func:`DEVICE_GET()` +:c:macro:`DEVICE_GET()` Obtain a pointer to a device object by name. -:c:func:`DEVICE_DECLARE()` +:c:macro:`DEVICE_DECLARE()` Declare a device object. Use this when you need a forward reference to a device that has not yet been defined. +:c:macro:`DEVICE_API()` + Wrap a driver API declaration to assign it to its respective linker section. + .. _device_struct: Driver Data Structures @@ -97,8 +100,8 @@ split into read-only and runtime-mutable parts. At a high level we have: struct device { const char *name; const void *config; - const void *api; - void * const data; + const void *api; + void * const data; }; The ``config`` member is for read-only configuration data set at build time. For @@ -122,6 +125,9 @@ Most drivers will be implementing a device-independent subsystem API. Applications can simply program to that generic API, and application code is not specific to any particular driver implementation. +If all driver API instances are assigned to their respective API linker section +use :c:macro:`DEVICE_API_IS()` to verify the API's type. + A subsystem API definition typically looks like this: .. code-block:: C @@ -129,29 +135,28 @@ A subsystem API definition typically looks like this: typedef int (*subsystem_do_this_t)(const struct device *dev, int foo, int bar); typedef void (*subsystem_do_that_t)(const struct device *dev, void *baz); - struct subsystem_api { + __subsystem struct subsystem_driver_api { subsystem_do_this_t do_this; subsystem_do_that_t do_that; }; static inline int subsystem_do_this(const struct device *dev, int foo, int bar) { - struct subsystem_api *api; + __ASSERT_NO_MSG(DEVICE_API_IS(subsystem, dev)); - api = (struct subsystem_api *)dev->api; - return api->do_this(dev, foo, bar); + return DEVICE_API_GET(subsystem, dev)->do_this(dev, foo, bar); } static inline void subsystem_do_that(const struct device *dev, void *baz) { - struct subsystem_api *api; + __ASSERT_NO_MSG(DEVICE_API_IS(subsystem, dev)); - api = (struct subsystem_api *)dev->api; - api->do_that(dev, baz); + DEVICE_API_GET(subsystem, dev)->do_that(dev, baz); } A driver implementing a particular subsystem will define the real implementation -of these APIs, and populate an instance of subsystem_api structure: +of these APIs, and populate an instance of subsystem_driver_api structure using +the :c:macro:`DEVICE_API()` wrapper: .. code-block:: C @@ -165,9 +170,9 @@ of these APIs, and populate an instance of subsystem_api structure: ... } - static struct subsystem_api my_driver_api_funcs = { + static DEVICE_API(subsystem, my_driver_api_funcs) = { .do_this = my_driver_do_this, - .do_that = my_driver_do_that + .do_that = my_driver_do_that, }; The driver would then pass ``my_driver_api_funcs`` as the ``api`` argument to