linux/drivers/base/component.c

// SPDX-License-Identifier: GPL-2.0
/*
 * Componentized device handling.
 */
#include <linux/component.h>
#include <linux/device.h>
#include <linux/list.h>
#include <linux/mutex.h>
#include <linux/of.h>
#include <linux/slab.h>
#include <linux/debugfs.h>

/**
 * DOC: overview
 *
 * The component helper allows drivers to collect a pile of sub-devices,
 * including their bound drivers, into an aggregate driver. Various subsystems
 * already provide functions to get hold of such components, e.g.
 * of_clk_get_by_name(). The component helper can be used when such a
 * subsystem-specific way to find a device is not available: The component
 * helper fills the niche of aggregate drivers for specific hardware, where
 * further standardization into a subsystem would not be practical. The common
 * example is when a logical device (e.g. a DRM display driver) is spread around
 * the SoC on various components (scanout engines, blending blocks, transcoders
 * for various outputs and so on).
 *
 * The component helper also doesn't solve runtime dependencies, e.g. for system
 * suspend and resume operations. See also :ref:`device links<device_link>`.
 *
 * Components are registered using component_add() and unregistered with
 * component_del(), usually from the driver's probe and disconnect functions.
 *
 * Aggregate drivers first assemble a component match list of what they need
 * using component_match_add(). This is then registered as an aggregate driver
 * using component_master_add_with_match(), and unregistered using
 * component_master_del().
 */

struct component;

struct component_match_array {};

struct component_match {};

struct aggregate_device {};

struct component {};

static DEFINE_MUTEX(component_mutex);
static LIST_HEAD(component_list);
static LIST_HEAD(aggregate_devices);

#ifdef CONFIG_DEBUG_FS

static struct dentry *component_debugfs_dir;

static int component_devices_show(struct seq_file *s, void *data)
{}

DEFINE_SHOW_ATTRIBUTE();

static int __init component_debug_init(void)
{}

core_initcall(component_debug_init);

static void component_debugfs_add(struct aggregate_device *m)
{}

static void component_debugfs_del(struct aggregate_device *m)
{}

#else

static void component_debugfs_add(struct aggregate_device *m)
{ }

static void component_debugfs_del(struct aggregate_device *m)
{ }

#endif

static struct aggregate_device *__aggregate_find(struct device *parent,
	const struct component_master_ops *ops)
{}

static struct component *find_component(struct aggregate_device *adev,
	struct component_match_array *mc)
{}

static int find_components(struct aggregate_device *adev)
{}

/* Detach component from associated aggregate_device */
static void remove_component(struct aggregate_device *adev, struct component *c)
{}

/*
 * Try to bring up an aggregate device.  If component is NULL, we're interested
 * in this aggregate device, otherwise it's a component which must be present
 * to try and bring up the aggregate device.
 *
 * Returns 1 for successful bringup, 0 if not ready, or -ve errno.
 */
static int try_to_bring_up_aggregate_device(struct aggregate_device *adev,
	struct component *component)
{}

static int try_to_bring_up_masters(struct component *component)
{}

static void take_down_aggregate_device(struct aggregate_device *adev)
{}

/**
 * component_compare_of - A common component compare function for of_node
 * @dev: component device
 * @data: @compare_data from component_match_add_release()
 *
 * A common compare function when compare_data is device of_node. e.g.
 * component_match_add_release(masterdev, &match, component_release_of,
 * component_compare_of, component_dev_of_node)
 */
int component_compare_of(struct device *dev, void *data)
{}
EXPORT_SYMBOL_GPL();

/**
 * component_release_of - A common component release function for of_node
 * @dev: component device
 * @data: @compare_data from component_match_add_release()
 *
 * About the example, Please see component_compare_of().
 */
void component_release_of(struct device *dev, void *data)
{}
EXPORT_SYMBOL_GPL();

/**
 * component_compare_dev - A common component compare function for dev
 * @dev: component device
 * @data: @compare_data from component_match_add_release()
 *
 * A common compare function when compare_data is struce device. e.g.
 * component_match_add(masterdev, &match, component_compare_dev, component_dev)
 */
int component_compare_dev(struct device *dev, void *data)
{}
EXPORT_SYMBOL_GPL();

/**
 * component_compare_dev_name - A common component compare function for device name
 * @dev: component device
 * @data: @compare_data from component_match_add_release()
 *
 * A common compare function when compare_data is device name string. e.g.
 * component_match_add(masterdev, &match, component_compare_dev_name,
 * "component_dev_name")
 */
int component_compare_dev_name(struct device *dev, void *data)
{}
EXPORT_SYMBOL_GPL();

static void devm_component_match_release(struct device *parent, void *res)
{}

static int component_match_realloc(struct component_match *match, size_t num)
{}

static void __component_match_add(struct device *parent,
	struct component_match **matchptr,
	void (*release)(struct device *, void *),
	int (*compare)(struct device *, void *),
	int (*compare_typed)(struct device *, int, void *),
	void *compare_data)
{}

/**
 * component_match_add_release - add a component match entry with release callback
 * @parent: parent device of the aggregate driver
 * @matchptr: pointer to the list of component matches
 * @release: release function for @compare_data
 * @compare: compare function to match against all components
 * @compare_data: opaque pointer passed to the @compare function
 *
 * Adds a new component match to the list stored in @matchptr, which the
 * aggregate driver needs to function. The list of component matches pointed to
 * by @matchptr must be initialized to NULL before adding the first match. This
 * only matches against components added with component_add().
 *
 * The allocated match list in @matchptr is automatically released using devm
 * actions, where upon @release will be called to free any references held by
 * @compare_data, e.g. when @compare_data is a &device_node that must be
 * released with of_node_put().
 *
 * See also component_match_add() and component_match_add_typed().
 */
void component_match_add_release(struct device *parent,
	struct component_match **matchptr,
	void (*release)(struct device *, void *),
	int (*compare)(struct device *, void *), void *compare_data)
{}
EXPORT_SYMBOL();

/**
 * component_match_add_typed - add a component match entry for a typed component
 * @parent: parent device of the aggregate driver
 * @matchptr: pointer to the list of component matches
 * @compare_typed: compare function to match against all typed components
 * @compare_data: opaque pointer passed to the @compare function
 *
 * Adds a new component match to the list stored in @matchptr, which the
 * aggregate driver needs to function. The list of component matches pointed to
 * by @matchptr must be initialized to NULL before adding the first match. This
 * only matches against components added with component_add_typed().
 *
 * The allocated match list in @matchptr is automatically released using devm
 * actions.
 *
 * See also component_match_add_release() and component_match_add_typed().
 */
void component_match_add_typed(struct device *parent,
	struct component_match **matchptr,
	int (*compare_typed)(struct device *, int, void *), void *compare_data)
{}
EXPORT_SYMBOL();

static void free_aggregate_device(struct aggregate_device *adev)
{}

/**
 * component_master_add_with_match - register an aggregate driver
 * @parent: parent device of the aggregate driver
 * @ops: callbacks for the aggregate driver
 * @match: component match list for the aggregate driver
 *
 * Registers a new aggregate driver consisting of the components added to @match
 * by calling one of the component_match_add() functions. Once all components in
 * @match are available, it will be assembled by calling
 * &component_master_ops.bind from @ops. Must be unregistered by calling
 * component_master_del().
 */
int component_master_add_with_match(struct device *parent,
	const struct component_master_ops *ops,
	struct component_match *match)
{}
EXPORT_SYMBOL_GPL();

/**
 * component_master_del - unregister an aggregate driver
 * @parent: parent device of the aggregate driver
 * @ops: callbacks for the aggregate driver
 *
 * Unregisters an aggregate driver registered with
 * component_master_add_with_match(). If necessary the aggregate driver is first
 * disassembled by calling &component_master_ops.unbind from @ops.
 */
void component_master_del(struct device *parent,
	const struct component_master_ops *ops)
{}
EXPORT_SYMBOL_GPL();

static void component_unbind(struct component *component,
	struct aggregate_device *adev, void *data)
{}

/**
 * component_unbind_all - unbind all components of an aggregate driver
 * @parent: parent device of the aggregate driver
 * @data: opaque pointer, passed to all components
 *
 * Unbinds all components of the aggregate device by passing @data to their
 * &component_ops.unbind functions. Should be called from
 * &component_master_ops.unbind.
 */
void component_unbind_all(struct device *parent, void *data)
{}
EXPORT_SYMBOL_GPL();

static int component_bind(struct component *component, struct aggregate_device *adev,
	void *data)
{}

/**
 * component_bind_all - bind all components of an aggregate driver
 * @parent: parent device of the aggregate driver
 * @data: opaque pointer, passed to all components
 *
 * Binds all components of the aggregate @dev by passing @data to their
 * &component_ops.bind functions. Should be called from
 * &component_master_ops.bind.
 */
int component_bind_all(struct device *parent, void *data)
{}
EXPORT_SYMBOL_GPL();

static int __component_add(struct device *dev, const struct component_ops *ops,
	int subcomponent)
{}

/**
 * component_add_typed - register a component
 * @dev: component device
 * @ops: component callbacks
 * @subcomponent: nonzero identifier for subcomponents
 *
 * Register a new component for @dev. Functions in @ops will be call when the
 * aggregate driver is ready to bind the overall driver by calling
 * component_bind_all(). See also &struct component_ops.
 *
 * @subcomponent must be nonzero and is used to differentiate between multiple
 * components registered on the same device @dev. These components are match
 * using component_match_add_typed().
 *
 * The component needs to be unregistered at driver unload/disconnect by
 * calling component_del().
 *
 * See also component_add().
 */
int component_add_typed(struct device *dev, const struct component_ops *ops,
	int subcomponent)
{}
EXPORT_SYMBOL_GPL();

/**
 * component_add - register a component
 * @dev: component device
 * @ops: component callbacks
 *
 * Register a new component for @dev. Functions in @ops will be called when the
 * aggregate driver is ready to bind the overall driver by calling
 * component_bind_all(). See also &struct component_ops.
 *
 * The component needs to be unregistered at driver unload/disconnect by
 * calling component_del().
 *
 * See also component_add_typed() for a variant that allows multiple different
 * components on the same device.
 */
int component_add(struct device *dev, const struct component_ops *ops)
{}
EXPORT_SYMBOL_GPL();

/**
 * component_del - unregister a component
 * @dev: component device
 * @ops: component callbacks
 *
 * Unregister a component added with component_add(). If the component is bound
 * into an aggregate driver, this will force the entire aggregate driver, including
 * all its components, to be unbound.
 */
void component_del(struct device *dev, const struct component_ops *ops)
{}
EXPORT_SYMBOL_GPL();