aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRussell King <rmk+kernel@arm.linux.org.uk>2014-04-19 06:18:01 -0400
committerRussell King <rmk+kernel@arm.linux.org.uk>2014-07-03 06:32:43 -0400
commit6955b58254c2bcee8a7b55ce06468a645dc98ec5 (patch)
tree2efc0f481be4070cf6e2916b037fa28ac0fcf092
parentfcbcebce7159c928692dc6a5e88869f6e44438b9 (diff)
component: add support for component match array
Add support for generating a set of component matches at master probe time, and submitting them to the component layer. This allows the component layer to perform the matches internally without needing to call into the master driver, and allows for further restructuring of the component helper. Acked-by: Laurent Pinchart <laurent.pinchart@ideasonboard.com> Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
-rw-r--r--drivers/base/component.c120
-rw-r--r--include/linux/component.h7
2 files changed, 124 insertions, 3 deletions
diff --git a/drivers/base/component.c b/drivers/base/component.c
index 55813e91bf0d..b4236daed4fa 100644
--- a/drivers/base/component.c
+++ b/drivers/base/component.c
@@ -18,6 +18,15 @@
18#include <linux/mutex.h> 18#include <linux/mutex.h>
19#include <linux/slab.h> 19#include <linux/slab.h>
20 20
21struct component_match {
22 size_t alloc;
23 size_t num;
24 struct {
25 void *data;
26 int (*fn)(struct device *, void *);
27 } compare[0];
28};
29
21struct master { 30struct master {
22 struct list_head node; 31 struct list_head node;
23 struct list_head components; 32 struct list_head components;
@@ -25,6 +34,7 @@ struct master {
25 34
26 const struct component_master_ops *ops; 35 const struct component_master_ops *ops;
27 struct device *dev; 36 struct device *dev;
37 struct component_match *match;
28}; 38};
29 39
30struct component { 40struct component {
@@ -96,6 +106,34 @@ int component_master_add_child(struct master *master,
96} 106}
97EXPORT_SYMBOL_GPL(component_master_add_child); 107EXPORT_SYMBOL_GPL(component_master_add_child);
98 108
109static int find_components(struct master *master)
110{
111 struct component_match *match = master->match;
112 size_t i;
113 int ret = 0;
114
115 if (!match) {
116 /*
117 * Search the list of components, looking for components that
118 * belong to this master, and attach them to the master.
119 */
120 return master->ops->add_components(master->dev, master);
121 }
122
123 /*
124 * Scan the array of match functions and attach
125 * any components which are found to this master.
126 */
127 for (i = 0; i < match->num; i++) {
128 ret = component_master_add_child(master,
129 match->compare[i].fn,
130 match->compare[i].data);
131 if (ret)
132 break;
133 }
134 return ret;
135}
136
99/* Detach all attached components from this master */ 137/* Detach all attached components from this master */
100static void master_remove_components(struct master *master) 138static void master_remove_components(struct master *master)
101{ 139{
@@ -128,7 +166,7 @@ static int try_to_bring_up_master(struct master *master,
128 * Search the list of components, looking for components that 166 * Search the list of components, looking for components that
129 * belong to this master, and attach them to the master. 167 * belong to this master, and attach them to the master.
130 */ 168 */
131 if (master->ops->add_components(master->dev, master)) { 169 if (find_components(master)) {
132 /* Failed to find all components */ 170 /* Failed to find all components */
133 ret = 0; 171 ret = 0;
134 goto out; 172 goto out;
@@ -186,18 +224,87 @@ static void take_down_master(struct master *master)
186 master_remove_components(master); 224 master_remove_components(master);
187} 225}
188 226
189int component_master_add(struct device *dev, 227static size_t component_match_size(size_t num)
190 const struct component_master_ops *ops) 228{
229 return offsetof(struct component_match, compare[num]);
230}
231
232static struct component_match *component_match_realloc(struct device *dev,
233 struct component_match *match, size_t num)
234{
235 struct component_match *new;
236
237 if (match && match->alloc == num)
238 return match;
239
240 new = devm_kmalloc(dev, component_match_size(num), GFP_KERNEL);
241 if (!new)
242 return ERR_PTR(-ENOMEM);
243
244 if (match) {
245 memcpy(new, match, component_match_size(min(match->num, num)));
246 devm_kfree(dev, match);
247 } else {
248 new->num = 0;
249 }
250
251 new->alloc = num;
252
253 return new;
254}
255
256/*
257 * Add a component to be matched.
258 *
259 * The match array is first created or extended if necessary.
260 */
261void component_match_add(struct device *dev, struct component_match **matchptr,
262 int (*compare)(struct device *, void *), void *compare_data)
263{
264 struct component_match *match = *matchptr;
265
266 if (IS_ERR(match))
267 return;
268
269 if (!match || match->num == match->alloc) {
270 size_t new_size = match ? match->alloc + 16 : 15;
271
272 match = component_match_realloc(dev, match, new_size);
273
274 *matchptr = match;
275
276 if (IS_ERR(match))
277 return;
278 }
279
280 match->compare[match->num].fn = compare;
281 match->compare[match->num].data = compare_data;
282 match->num++;
283}
284EXPORT_SYMBOL(component_match_add);
285
286int component_master_add_with_match(struct device *dev,
287 const struct component_master_ops *ops,
288 struct component_match *match)
191{ 289{
192 struct master *master; 290 struct master *master;
193 int ret; 291 int ret;
194 292
293 if (ops->add_components && match)
294 return -EINVAL;
295
296 /* Reallocate the match array for its true size */
297 match = component_match_realloc(dev, match, match->num);
298 if (IS_ERR(match))
299 return PTR_ERR(match);
300
195 master = kzalloc(sizeof(*master), GFP_KERNEL); 301 master = kzalloc(sizeof(*master), GFP_KERNEL);
196 if (!master) 302 if (!master)
197 return -ENOMEM; 303 return -ENOMEM;
198 304
199 master->dev = dev; 305 master->dev = dev;
200 master->ops = ops; 306 master->ops = ops;
307 master->match = match;
201 INIT_LIST_HEAD(&master->components); 308 INIT_LIST_HEAD(&master->components);
202 309
203 /* Add to the list of available masters. */ 310 /* Add to the list of available masters. */
@@ -215,6 +322,13 @@ int component_master_add(struct device *dev,
215 322
216 return ret < 0 ? ret : 0; 323 return ret < 0 ? ret : 0;
217} 324}
325EXPORT_SYMBOL_GPL(component_master_add_with_match);
326
327int component_master_add(struct device *dev,
328 const struct component_master_ops *ops)
329{
330 return component_master_add_with_match(dev, ops, NULL);
331}
218EXPORT_SYMBOL_GPL(component_master_add); 332EXPORT_SYMBOL_GPL(component_master_add);
219 333
220void component_master_del(struct device *dev, 334void component_master_del(struct device *dev,
diff --git a/include/linux/component.h b/include/linux/component.h
index 68870182ca1e..c00dcc302611 100644
--- a/include/linux/component.h
+++ b/include/linux/component.h
@@ -29,4 +29,11 @@ void component_master_del(struct device *,
29int component_master_add_child(struct master *master, 29int component_master_add_child(struct master *master,
30 int (*compare)(struct device *, void *), void *compare_data); 30 int (*compare)(struct device *, void *), void *compare_data);
31 31
32struct component_match;
33
34int component_master_add_with_match(struct device *,
35 const struct component_master_ops *, struct component_match *);
36void component_match_add(struct device *, struct component_match **,
37 int (*compare)(struct device *, void *), void *compare_data);
38
32#endif 39#endif