@@ -68,21 +68,24 @@ The following APIs for device drivers are provided by :file:`device.h`. The APIs
68
68
are intended for use in device drivers only and should not be used in
69
69
applications.
70
70
71
- :c:func : `DEVICE_DEFINE() `
71
+ :c:macro : `DEVICE_DEFINE() `
72
72
Create device object and related data structures including setting it
73
73
up for boot-time initialization.
74
74
75
- :c:func : `DEVICE_NAME_GET() `
75
+ :c:macro : `DEVICE_NAME_GET() `
76
76
Converts a device identifier to the global identifier for a device
77
77
object.
78
78
79
- :c:func : `DEVICE_GET() `
79
+ :c:macro : `DEVICE_GET() `
80
80
Obtain a pointer to a device object by name.
81
81
82
- :c:func : `DEVICE_DECLARE() `
82
+ :c:macro : `DEVICE_DECLARE() `
83
83
Declare a device object. Use this when you need a forward reference
84
84
to a device that has not yet been defined.
85
85
86
+ :c:macro: `DEVICE_API() `
87
+ Wrap a driver API declaration to assign it to its respective linker section.
88
+
86
89
.. _device_struct :
87
90
88
91
Driver Data Structures
@@ -97,8 +100,8 @@ split into read-only and runtime-mutable parts. At a high level we have:
97
100
struct device {
98
101
const char *name;
99
102
const void *config;
100
- const void *api;
101
- void * const data;
103
+ const void *api;
104
+ void * const data;
102
105
};
103
106
104
107
The ``config `` member is for read-only configuration data set at build time. For
@@ -122,36 +125,38 @@ Most drivers will be implementing a device-independent subsystem API.
122
125
Applications can simply program to that generic API, and application
123
126
code is not specific to any particular driver implementation.
124
127
128
+ If all driver API instances are assigned to their respective API linker section
129
+ use :c:macro: `DEVICE_API_IS() ` to verify the API's type.
130
+
125
131
A subsystem API definition typically looks like this:
126
132
127
133
.. code-block :: C
128
134
129
135
typedef int (*subsystem_do_this_t)(const struct device *dev, int foo, int bar);
130
136
typedef void (*subsystem_do_that_t)(const struct device *dev, void *baz);
131
137
132
- struct subsystem_api {
138
+ __subsystem struct subsystem_driver_api {
133
139
subsystem_do_this_t do_this;
134
140
subsystem_do_that_t do_that;
135
141
};
136
142
137
143
static inline int subsystem_do_this(const struct device *dev, int foo, int bar)
138
144
{
139
- struct subsystem_api *api ;
145
+ __ASSERT_NO_MSG(DEVICE_API_IS(subsystem, dev)) ;
140
146
141
- api = (struct subsystem_api *)dev->api;
142
- return api->do_this(dev, foo, bar);
147
+ return DEVICE_API_GET(subsystem, dev)->do_this(dev, foo, bar);
143
148
}
144
149
145
150
static inline void subsystem_do_that(const struct device *dev, void *baz)
146
151
{
147
- struct subsystem_api *api ;
152
+ __ASSERT_NO_MSG(DEVICE_API_IS(subsystem, dev)) ;
148
153
149
- api = (struct subsystem_api *)dev->api;
150
- api->do_that(dev, baz);
154
+ DEVICE_API_GET(subsystem, dev)->do_that(dev, baz);
151
155
}
152
156
153
157
A driver implementing a particular subsystem will define the real implementation
154
- of these APIs, and populate an instance of subsystem_api structure:
158
+ of these APIs, and populate an instance of subsystem_driver_api structure using
159
+ the :c:macro: `DEVICE_API() ` wrapper:
155
160
156
161
.. code-block :: C
157
162
@@ -165,9 +170,9 @@ of these APIs, and populate an instance of subsystem_api structure:
165
170
...
166
171
}
167
172
168
- static struct subsystem_api my_driver_api_funcs = {
173
+ static DEVICE_API(subsystem, my_driver_api_funcs) = {
169
174
.do_this = my_driver_do_this,
170
- .do_that = my_driver_do_that
175
+ .do_that = my_driver_do_that,
171
176
};
172
177
173
178
The driver would then pass ``my_driver_api_funcs `` as the ``api `` argument to
0 commit comments