Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  * Componentized device handling.
0004  */
0005 #include <linux/component.h>
0006 #include <linux/device.h>
0007 #include <linux/list.h>
0008 #include <linux/mutex.h>
0009 #include <linux/of.h>
0010 #include <linux/slab.h>
0011 #include <linux/debugfs.h>
0012 
0013 /**
0014  * DOC: overview
0015  *
0016  * The component helper allows drivers to collect a pile of sub-devices,
0017  * including their bound drivers, into an aggregate driver. Various subsystems
0018  * already provide functions to get hold of such components, e.g.
0019  * of_clk_get_by_name(). The component helper can be used when such a
0020  * subsystem-specific way to find a device is not available: The component
0021  * helper fills the niche of aggregate drivers for specific hardware, where
0022  * further standardization into a subsystem would not be practical. The common
0023  * example is when a logical device (e.g. a DRM display driver) is spread around
0024  * the SoC on various components (scanout engines, blending blocks, transcoders
0025  * for various outputs and so on).
0026  *
0027  * The component helper also doesn't solve runtime dependencies, e.g. for system
0028  * suspend and resume operations. See also :ref:`device links<device_link>`.
0029  *
0030  * Components are registered using component_add() and unregistered with
0031  * component_del(), usually from the driver's probe and disconnect functions.
0032  *
0033  * Aggregate drivers first assemble a component match list of what they need
0034  * using component_match_add(). This is then registered as an aggregate driver
0035  * using component_master_add_with_match(), and unregistered using
0036  * component_master_del().
0037  */
0038 
0039 struct component;
0040 
0041 struct component_match_array {
0042     void *data;
0043     int (*compare)(struct device *, void *);
0044     int (*compare_typed)(struct device *, int, void *);
0045     void (*release)(struct device *, void *);
0046     struct component *component;
0047     bool duplicate;
0048 };
0049 
0050 struct component_match {
0051     size_t alloc;
0052     size_t num;
0053     struct component_match_array *compare;
0054 };
0055 
0056 struct aggregate_device {
0057     struct list_head node;
0058     bool bound;
0059 
0060     const struct component_master_ops *ops;
0061     struct device *parent;
0062     struct component_match *match;
0063 };
0064 
0065 struct component {
0066     struct list_head node;
0067     struct aggregate_device *adev;
0068     bool bound;
0069 
0070     const struct component_ops *ops;
0071     int subcomponent;
0072     struct device *dev;
0073 };
0074 
0075 static DEFINE_MUTEX(component_mutex);
0076 static LIST_HEAD(component_list);
0077 static LIST_HEAD(aggregate_devices);
0078 
0079 #ifdef CONFIG_DEBUG_FS
0080 
0081 static struct dentry *component_debugfs_dir;
0082 
0083 static int component_devices_show(struct seq_file *s, void *data)
0084 {
0085     struct aggregate_device *m = s->private;
0086     struct component_match *match = m->match;
0087     size_t i;
0088 
0089     mutex_lock(&component_mutex);
0090     seq_printf(s, "%-40s %20s\n", "aggregate_device name", "status");
0091     seq_puts(s, "-------------------------------------------------------------\n");
0092     seq_printf(s, "%-40s %20s\n\n",
0093            dev_name(m->parent), m->bound ? "bound" : "not bound");
0094 
0095     seq_printf(s, "%-40s %20s\n", "device name", "status");
0096     seq_puts(s, "-------------------------------------------------------------\n");
0097     for (i = 0; i < match->num; i++) {
0098         struct component *component = match->compare[i].component;
0099 
0100         seq_printf(s, "%-40s %20s\n",
0101                component ? dev_name(component->dev) : "(unknown)",
0102                component ? (component->bound ? "bound" : "not bound") : "not registered");
0103     }
0104     mutex_unlock(&component_mutex);
0105 
0106     return 0;
0107 }
0108 
0109 DEFINE_SHOW_ATTRIBUTE(component_devices);
0110 
0111 static int __init component_debug_init(void)
0112 {
0113     component_debugfs_dir = debugfs_create_dir("device_component", NULL);
0114 
0115     return 0;
0116 }
0117 
0118 core_initcall(component_debug_init);
0119 
0120 static void component_debugfs_add(struct aggregate_device *m)
0121 {
0122     debugfs_create_file(dev_name(m->parent), 0444, component_debugfs_dir, m,
0123                 &component_devices_fops);
0124 }
0125 
0126 static void component_debugfs_del(struct aggregate_device *m)
0127 {
0128     debugfs_remove(debugfs_lookup(dev_name(m->parent), component_debugfs_dir));
0129 }
0130 
0131 #else
0132 
0133 static void component_debugfs_add(struct aggregate_device *m)
0134 { }
0135 
0136 static void component_debugfs_del(struct aggregate_device *m)
0137 { }
0138 
0139 #endif
0140 
0141 static struct aggregate_device *__aggregate_find(struct device *parent,
0142     const struct component_master_ops *ops)
0143 {
0144     struct aggregate_device *m;
0145 
0146     list_for_each_entry(m, &aggregate_devices, node)
0147         if (m->parent == parent && (!ops || m->ops == ops))
0148             return m;
0149 
0150     return NULL;
0151 }
0152 
0153 static struct component *find_component(struct aggregate_device *adev,
0154     struct component_match_array *mc)
0155 {
0156     struct component *c;
0157 
0158     list_for_each_entry(c, &component_list, node) {
0159         if (c->adev && c->adev != adev)
0160             continue;
0161 
0162         if (mc->compare && mc->compare(c->dev, mc->data))
0163             return c;
0164 
0165         if (mc->compare_typed &&
0166             mc->compare_typed(c->dev, c->subcomponent, mc->data))
0167             return c;
0168     }
0169 
0170     return NULL;
0171 }
0172 
0173 static int find_components(struct aggregate_device *adev)
0174 {
0175     struct component_match *match = adev->match;
0176     size_t i;
0177     int ret = 0;
0178 
0179     /*
0180      * Scan the array of match functions and attach
0181      * any components which are found to this adev.
0182      */
0183     for (i = 0; i < match->num; i++) {
0184         struct component_match_array *mc = &match->compare[i];
0185         struct component *c;
0186 
0187         dev_dbg(adev->parent, "Looking for component %zu\n", i);
0188 
0189         if (match->compare[i].component)
0190             continue;
0191 
0192         c = find_component(adev, mc);
0193         if (!c) {
0194             ret = -ENXIO;
0195             break;
0196         }
0197 
0198         dev_dbg(adev->parent, "found component %s, duplicate %u\n",
0199             dev_name(c->dev), !!c->adev);
0200 
0201         /* Attach this component to the adev */
0202         match->compare[i].duplicate = !!c->adev;
0203         match->compare[i].component = c;
0204         c->adev = adev;
0205     }
0206     return ret;
0207 }
0208 
0209 /* Detach component from associated aggregate_device */
0210 static void remove_component(struct aggregate_device *adev, struct component *c)
0211 {
0212     size_t i;
0213 
0214     /* Detach the component from this adev. */
0215     for (i = 0; i < adev->match->num; i++)
0216         if (adev->match->compare[i].component == c)
0217             adev->match->compare[i].component = NULL;
0218 }
0219 
0220 /*
0221  * Try to bring up an aggregate device.  If component is NULL, we're interested
0222  * in this aggregate device, otherwise it's a component which must be present
0223  * to try and bring up the aggregate device.
0224  *
0225  * Returns 1 for successful bringup, 0 if not ready, or -ve errno.
0226  */
0227 static int try_to_bring_up_aggregate_device(struct aggregate_device *adev,
0228     struct component *component)
0229 {
0230     int ret;
0231 
0232     dev_dbg(adev->parent, "trying to bring up adev\n");
0233 
0234     if (find_components(adev)) {
0235         dev_dbg(adev->parent, "master has incomplete components\n");
0236         return 0;
0237     }
0238 
0239     if (component && component->adev != adev) {
0240         dev_dbg(adev->parent, "master is not for this component (%s)\n",
0241             dev_name(component->dev));
0242         return 0;
0243     }
0244 
0245     if (!devres_open_group(adev->parent, adev, GFP_KERNEL))
0246         return -ENOMEM;
0247 
0248     /* Found all components */
0249     ret = adev->ops->bind(adev->parent);
0250     if (ret < 0) {
0251         devres_release_group(adev->parent, NULL);
0252         if (ret != -EPROBE_DEFER)
0253             dev_info(adev->parent, "adev bind failed: %d\n", ret);
0254         return ret;
0255     }
0256 
0257     devres_close_group(adev->parent, NULL);
0258     adev->bound = true;
0259     return 1;
0260 }
0261 
0262 static int try_to_bring_up_masters(struct component *component)
0263 {
0264     struct aggregate_device *adev;
0265     int ret = 0;
0266 
0267     list_for_each_entry(adev, &aggregate_devices, node) {
0268         if (!adev->bound) {
0269             ret = try_to_bring_up_aggregate_device(adev, component);
0270             if (ret != 0)
0271                 break;
0272         }
0273     }
0274 
0275     return ret;
0276 }
0277 
0278 static void take_down_aggregate_device(struct aggregate_device *adev)
0279 {
0280     if (adev->bound) {
0281         adev->ops->unbind(adev->parent);
0282         devres_release_group(adev->parent, adev);
0283         adev->bound = false;
0284     }
0285 }
0286 
0287 /**
0288  * component_compare_of - A common component compare function for of_node
0289  * @dev: component device
0290  * @data: @compare_data from component_match_add_release()
0291  *
0292  * A common compare function when compare_data is device of_node. e.g.
0293  * component_match_add_release(masterdev, &match, component_release_of,
0294  * component_compare_of, component_dev_of_node)
0295  */
0296 int component_compare_of(struct device *dev, void *data)
0297 {
0298     return device_match_of_node(dev, data);
0299 }
0300 EXPORT_SYMBOL_GPL(component_compare_of);
0301 
0302 /**
0303  * component_release_of - A common component release function for of_node
0304  * @dev: component device
0305  * @data: @compare_data from component_match_add_release()
0306  *
0307  * About the example, Please see component_compare_of().
0308  */
0309 void component_release_of(struct device *dev, void *data)
0310 {
0311     of_node_put(data);
0312 }
0313 EXPORT_SYMBOL_GPL(component_release_of);
0314 
0315 /**
0316  * component_compare_dev - A common component compare function for dev
0317  * @dev: component device
0318  * @data: @compare_data from component_match_add_release()
0319  *
0320  * A common compare function when compare_data is struce device. e.g.
0321  * component_match_add(masterdev, &match, component_compare_dev, component_dev)
0322  */
0323 int component_compare_dev(struct device *dev, void *data)
0324 {
0325     return dev == data;
0326 }
0327 EXPORT_SYMBOL_GPL(component_compare_dev);
0328 
0329 /**
0330  * component_compare_dev_name - A common component compare function for device name
0331  * @dev: component device
0332  * @data: @compare_data from component_match_add_release()
0333  *
0334  * A common compare function when compare_data is device name string. e.g.
0335  * component_match_add(masterdev, &match, component_compare_dev_name,
0336  * "component_dev_name")
0337  */
0338 int component_compare_dev_name(struct device *dev, void *data)
0339 {
0340     return device_match_name(dev, data);
0341 }
0342 EXPORT_SYMBOL_GPL(component_compare_dev_name);
0343 
0344 static void devm_component_match_release(struct device *parent, void *res)
0345 {
0346     struct component_match *match = res;
0347     unsigned int i;
0348 
0349     for (i = 0; i < match->num; i++) {
0350         struct component_match_array *mc = &match->compare[i];
0351 
0352         if (mc->release)
0353             mc->release(parent, mc->data);
0354     }
0355 
0356     kfree(match->compare);
0357 }
0358 
0359 static int component_match_realloc(struct component_match *match, size_t num)
0360 {
0361     struct component_match_array *new;
0362 
0363     if (match->alloc == num)
0364         return 0;
0365 
0366     new = kmalloc_array(num, sizeof(*new), GFP_KERNEL);
0367     if (!new)
0368         return -ENOMEM;
0369 
0370     if (match->compare) {
0371         memcpy(new, match->compare, sizeof(*new) *
0372                         min(match->num, num));
0373         kfree(match->compare);
0374     }
0375     match->compare = new;
0376     match->alloc = num;
0377 
0378     return 0;
0379 }
0380 
0381 static void __component_match_add(struct device *parent,
0382     struct component_match **matchptr,
0383     void (*release)(struct device *, void *),
0384     int (*compare)(struct device *, void *),
0385     int (*compare_typed)(struct device *, int, void *),
0386     void *compare_data)
0387 {
0388     struct component_match *match = *matchptr;
0389 
0390     if (IS_ERR(match))
0391         return;
0392 
0393     if (!match) {
0394         match = devres_alloc(devm_component_match_release,
0395                      sizeof(*match), GFP_KERNEL);
0396         if (!match) {
0397             *matchptr = ERR_PTR(-ENOMEM);
0398             return;
0399         }
0400 
0401         devres_add(parent, match);
0402 
0403         *matchptr = match;
0404     }
0405 
0406     if (match->num == match->alloc) {
0407         size_t new_size = match->alloc + 16;
0408         int ret;
0409 
0410         ret = component_match_realloc(match, new_size);
0411         if (ret) {
0412             *matchptr = ERR_PTR(ret);
0413             return;
0414         }
0415     }
0416 
0417     match->compare[match->num].compare = compare;
0418     match->compare[match->num].compare_typed = compare_typed;
0419     match->compare[match->num].release = release;
0420     match->compare[match->num].data = compare_data;
0421     match->compare[match->num].component = NULL;
0422     match->num++;
0423 }
0424 
0425 /**
0426  * component_match_add_release - add a component match entry with release callback
0427  * @parent: parent device of the aggregate driver
0428  * @matchptr: pointer to the list of component matches
0429  * @release: release function for @compare_data
0430  * @compare: compare function to match against all components
0431  * @compare_data: opaque pointer passed to the @compare function
0432  *
0433  * Adds a new component match to the list stored in @matchptr, which the
0434  * aggregate driver needs to function. The list of component matches pointed to
0435  * by @matchptr must be initialized to NULL before adding the first match. This
0436  * only matches against components added with component_add().
0437  *
0438  * The allocated match list in @matchptr is automatically released using devm
0439  * actions, where upon @release will be called to free any references held by
0440  * @compare_data, e.g. when @compare_data is a &device_node that must be
0441  * released with of_node_put().
0442  *
0443  * See also component_match_add() and component_match_add_typed().
0444  */
0445 void component_match_add_release(struct device *parent,
0446     struct component_match **matchptr,
0447     void (*release)(struct device *, void *),
0448     int (*compare)(struct device *, void *), void *compare_data)
0449 {
0450     __component_match_add(parent, matchptr, release, compare, NULL,
0451                   compare_data);
0452 }
0453 EXPORT_SYMBOL(component_match_add_release);
0454 
0455 /**
0456  * component_match_add_typed - add a component match entry for a typed component
0457  * @parent: parent device of the aggregate driver
0458  * @matchptr: pointer to the list of component matches
0459  * @compare_typed: compare function to match against all typed components
0460  * @compare_data: opaque pointer passed to the @compare function
0461  *
0462  * Adds a new component match to the list stored in @matchptr, which the
0463  * aggregate driver needs to function. The list of component matches pointed to
0464  * by @matchptr must be initialized to NULL before adding the first match. This
0465  * only matches against components added with component_add_typed().
0466  *
0467  * The allocated match list in @matchptr is automatically released using devm
0468  * actions.
0469  *
0470  * See also component_match_add_release() and component_match_add_typed().
0471  */
0472 void component_match_add_typed(struct device *parent,
0473     struct component_match **matchptr,
0474     int (*compare_typed)(struct device *, int, void *), void *compare_data)
0475 {
0476     __component_match_add(parent, matchptr, NULL, NULL, compare_typed,
0477                   compare_data);
0478 }
0479 EXPORT_SYMBOL(component_match_add_typed);
0480 
0481 static void free_aggregate_device(struct aggregate_device *adev)
0482 {
0483     struct component_match *match = adev->match;
0484     int i;
0485 
0486     component_debugfs_del(adev);
0487     list_del(&adev->node);
0488 
0489     if (match) {
0490         for (i = 0; i < match->num; i++) {
0491             struct component *c = match->compare[i].component;
0492             if (c)
0493                 c->adev = NULL;
0494         }
0495     }
0496 
0497     kfree(adev);
0498 }
0499 
0500 /**
0501  * component_master_add_with_match - register an aggregate driver
0502  * @parent: parent device of the aggregate driver
0503  * @ops: callbacks for the aggregate driver
0504  * @match: component match list for the aggregate driver
0505  *
0506  * Registers a new aggregate driver consisting of the components added to @match
0507  * by calling one of the component_match_add() functions. Once all components in
0508  * @match are available, it will be assembled by calling
0509  * &component_master_ops.bind from @ops. Must be unregistered by calling
0510  * component_master_del().
0511  */
0512 int component_master_add_with_match(struct device *parent,
0513     const struct component_master_ops *ops,
0514     struct component_match *match)
0515 {
0516     struct aggregate_device *adev;
0517     int ret;
0518 
0519     /* Reallocate the match array for its true size */
0520     ret = component_match_realloc(match, match->num);
0521     if (ret)
0522         return ret;
0523 
0524     adev = kzalloc(sizeof(*adev), GFP_KERNEL);
0525     if (!adev)
0526         return -ENOMEM;
0527 
0528     adev->parent = parent;
0529     adev->ops = ops;
0530     adev->match = match;
0531 
0532     component_debugfs_add(adev);
0533     /* Add to the list of available aggregate devices. */
0534     mutex_lock(&component_mutex);
0535     list_add(&adev->node, &aggregate_devices);
0536 
0537     ret = try_to_bring_up_aggregate_device(adev, NULL);
0538 
0539     if (ret < 0)
0540         free_aggregate_device(adev);
0541 
0542     mutex_unlock(&component_mutex);
0543 
0544     return ret < 0 ? ret : 0;
0545 }
0546 EXPORT_SYMBOL_GPL(component_master_add_with_match);
0547 
0548 /**
0549  * component_master_del - unregister an aggregate driver
0550  * @parent: parent device of the aggregate driver
0551  * @ops: callbacks for the aggregate driver
0552  *
0553  * Unregisters an aggregate driver registered with
0554  * component_master_add_with_match(). If necessary the aggregate driver is first
0555  * disassembled by calling &component_master_ops.unbind from @ops.
0556  */
0557 void component_master_del(struct device *parent,
0558     const struct component_master_ops *ops)
0559 {
0560     struct aggregate_device *adev;
0561 
0562     mutex_lock(&component_mutex);
0563     adev = __aggregate_find(parent, ops);
0564     if (adev) {
0565         take_down_aggregate_device(adev);
0566         free_aggregate_device(adev);
0567     }
0568     mutex_unlock(&component_mutex);
0569 }
0570 EXPORT_SYMBOL_GPL(component_master_del);
0571 
0572 static void component_unbind(struct component *component,
0573     struct aggregate_device *adev, void *data)
0574 {
0575     WARN_ON(!component->bound);
0576 
0577     if (component->ops && component->ops->unbind)
0578         component->ops->unbind(component->dev, adev->parent, data);
0579     component->bound = false;
0580 
0581     /* Release all resources claimed in the binding of this component */
0582     devres_release_group(component->dev, component);
0583 }
0584 
0585 /**
0586  * component_unbind_all - unbind all components of an aggregate driver
0587  * @parent: parent device of the aggregate driver
0588  * @data: opaque pointer, passed to all components
0589  *
0590  * Unbinds all components of the aggregate device by passing @data to their
0591  * &component_ops.unbind functions. Should be called from
0592  * &component_master_ops.unbind.
0593  */
0594 void component_unbind_all(struct device *parent, void *data)
0595 {
0596     struct aggregate_device *adev;
0597     struct component *c;
0598     size_t i;
0599 
0600     WARN_ON(!mutex_is_locked(&component_mutex));
0601 
0602     adev = __aggregate_find(parent, NULL);
0603     if (!adev)
0604         return;
0605 
0606     /* Unbind components in reverse order */
0607     for (i = adev->match->num; i--; )
0608         if (!adev->match->compare[i].duplicate) {
0609             c = adev->match->compare[i].component;
0610             component_unbind(c, adev, data);
0611         }
0612 }
0613 EXPORT_SYMBOL_GPL(component_unbind_all);
0614 
0615 static int component_bind(struct component *component, struct aggregate_device *adev,
0616     void *data)
0617 {
0618     int ret;
0619 
0620     /*
0621      * Each component initialises inside its own devres group.
0622      * This allows us to roll-back a failed component without
0623      * affecting anything else.
0624      */
0625     if (!devres_open_group(adev->parent, NULL, GFP_KERNEL))
0626         return -ENOMEM;
0627 
0628     /*
0629      * Also open a group for the device itself: this allows us
0630      * to release the resources claimed against the sub-device
0631      * at the appropriate moment.
0632      */
0633     if (!devres_open_group(component->dev, component, GFP_KERNEL)) {
0634         devres_release_group(adev->parent, NULL);
0635         return -ENOMEM;
0636     }
0637 
0638     dev_dbg(adev->parent, "binding %s (ops %ps)\n",
0639         dev_name(component->dev), component->ops);
0640 
0641     ret = component->ops->bind(component->dev, adev->parent, data);
0642     if (!ret) {
0643         component->bound = true;
0644 
0645         /*
0646          * Close the component device's group so that resources
0647          * allocated in the binding are encapsulated for removal
0648          * at unbind.  Remove the group on the DRM device as we
0649          * can clean those resources up independently.
0650          */
0651         devres_close_group(component->dev, NULL);
0652         devres_remove_group(adev->parent, NULL);
0653 
0654         dev_info(adev->parent, "bound %s (ops %ps)\n",
0655              dev_name(component->dev), component->ops);
0656     } else {
0657         devres_release_group(component->dev, NULL);
0658         devres_release_group(adev->parent, NULL);
0659 
0660         if (ret != -EPROBE_DEFER)
0661             dev_err(adev->parent, "failed to bind %s (ops %ps): %d\n",
0662                 dev_name(component->dev), component->ops, ret);
0663     }
0664 
0665     return ret;
0666 }
0667 
0668 /**
0669  * component_bind_all - bind all components of an aggregate driver
0670  * @parent: parent device of the aggregate driver
0671  * @data: opaque pointer, passed to all components
0672  *
0673  * Binds all components of the aggregate @dev by passing @data to their
0674  * &component_ops.bind functions. Should be called from
0675  * &component_master_ops.bind.
0676  */
0677 int component_bind_all(struct device *parent, void *data)
0678 {
0679     struct aggregate_device *adev;
0680     struct component *c;
0681     size_t i;
0682     int ret = 0;
0683 
0684     WARN_ON(!mutex_is_locked(&component_mutex));
0685 
0686     adev = __aggregate_find(parent, NULL);
0687     if (!adev)
0688         return -EINVAL;
0689 
0690     /* Bind components in match order */
0691     for (i = 0; i < adev->match->num; i++)
0692         if (!adev->match->compare[i].duplicate) {
0693             c = adev->match->compare[i].component;
0694             ret = component_bind(c, adev, data);
0695             if (ret)
0696                 break;
0697         }
0698 
0699     if (ret != 0) {
0700         for (; i > 0; i--)
0701             if (!adev->match->compare[i - 1].duplicate) {
0702                 c = adev->match->compare[i - 1].component;
0703                 component_unbind(c, adev, data);
0704             }
0705     }
0706 
0707     return ret;
0708 }
0709 EXPORT_SYMBOL_GPL(component_bind_all);
0710 
0711 static int __component_add(struct device *dev, const struct component_ops *ops,
0712     int subcomponent)
0713 {
0714     struct component *component;
0715     int ret;
0716 
0717     component = kzalloc(sizeof(*component), GFP_KERNEL);
0718     if (!component)
0719         return -ENOMEM;
0720 
0721     component->ops = ops;
0722     component->dev = dev;
0723     component->subcomponent = subcomponent;
0724 
0725     dev_dbg(dev, "adding component (ops %ps)\n", ops);
0726 
0727     mutex_lock(&component_mutex);
0728     list_add_tail(&component->node, &component_list);
0729 
0730     ret = try_to_bring_up_masters(component);
0731     if (ret < 0) {
0732         if (component->adev)
0733             remove_component(component->adev, component);
0734         list_del(&component->node);
0735 
0736         kfree(component);
0737     }
0738     mutex_unlock(&component_mutex);
0739 
0740     return ret < 0 ? ret : 0;
0741 }
0742 
0743 /**
0744  * component_add_typed - register a component
0745  * @dev: component device
0746  * @ops: component callbacks
0747  * @subcomponent: nonzero identifier for subcomponents
0748  *
0749  * Register a new component for @dev. Functions in @ops will be call when the
0750  * aggregate driver is ready to bind the overall driver by calling
0751  * component_bind_all(). See also &struct component_ops.
0752  *
0753  * @subcomponent must be nonzero and is used to differentiate between multiple
0754  * components registerd on the same device @dev. These components are match
0755  * using component_match_add_typed().
0756  *
0757  * The component needs to be unregistered at driver unload/disconnect by
0758  * calling component_del().
0759  *
0760  * See also component_add().
0761  */
0762 int component_add_typed(struct device *dev, const struct component_ops *ops,
0763     int subcomponent)
0764 {
0765     if (WARN_ON(subcomponent == 0))
0766         return -EINVAL;
0767 
0768     return __component_add(dev, ops, subcomponent);
0769 }
0770 EXPORT_SYMBOL_GPL(component_add_typed);
0771 
0772 /**
0773  * component_add - register a component
0774  * @dev: component device
0775  * @ops: component callbacks
0776  *
0777  * Register a new component for @dev. Functions in @ops will be called when the
0778  * aggregate driver is ready to bind the overall driver by calling
0779  * component_bind_all(). See also &struct component_ops.
0780  *
0781  * The component needs to be unregistered at driver unload/disconnect by
0782  * calling component_del().
0783  *
0784  * See also component_add_typed() for a variant that allows multipled different
0785  * components on the same device.
0786  */
0787 int component_add(struct device *dev, const struct component_ops *ops)
0788 {
0789     return __component_add(dev, ops, 0);
0790 }
0791 EXPORT_SYMBOL_GPL(component_add);
0792 
0793 /**
0794  * component_del - unregister a component
0795  * @dev: component device
0796  * @ops: component callbacks
0797  *
0798  * Unregister a component added with component_add(). If the component is bound
0799  * into an aggregate driver, this will force the entire aggregate driver, including
0800  * all its components, to be unbound.
0801  */
0802 void component_del(struct device *dev, const struct component_ops *ops)
0803 {
0804     struct component *c, *component = NULL;
0805 
0806     mutex_lock(&component_mutex);
0807     list_for_each_entry(c, &component_list, node)
0808         if (c->dev == dev && c->ops == ops) {
0809             list_del(&c->node);
0810             component = c;
0811             break;
0812         }
0813 
0814     if (component && component->adev) {
0815         take_down_aggregate_device(component->adev);
0816         remove_component(component->adev, component);
0817     }
0818 
0819     mutex_unlock(&component_mutex);
0820 
0821     WARN_ON(!component);
0822     kfree(component);
0823 }
0824 EXPORT_SYMBOL_GPL(component_del);