162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only 262306a36Sopenharmony_ci/* 362306a36Sopenharmony_ci * Copyright (c) 2019-2020 Intel Corporation 462306a36Sopenharmony_ci * 562306a36Sopenharmony_ci * Please see Documentation/driver-api/auxiliary_bus.rst for more information. 662306a36Sopenharmony_ci */ 762306a36Sopenharmony_ci 862306a36Sopenharmony_ci#define pr_fmt(fmt) "%s:%s: " fmt, KBUILD_MODNAME, __func__ 962306a36Sopenharmony_ci 1062306a36Sopenharmony_ci#include <linux/device.h> 1162306a36Sopenharmony_ci#include <linux/init.h> 1262306a36Sopenharmony_ci#include <linux/slab.h> 1362306a36Sopenharmony_ci#include <linux/module.h> 1462306a36Sopenharmony_ci#include <linux/pm_domain.h> 1562306a36Sopenharmony_ci#include <linux/pm_runtime.h> 1662306a36Sopenharmony_ci#include <linux/string.h> 1762306a36Sopenharmony_ci#include <linux/auxiliary_bus.h> 1862306a36Sopenharmony_ci#include "base.h" 1962306a36Sopenharmony_ci 2062306a36Sopenharmony_ci/** 2162306a36Sopenharmony_ci * DOC: PURPOSE 2262306a36Sopenharmony_ci * 2362306a36Sopenharmony_ci * In some subsystems, the functionality of the core device (PCI/ACPI/other) is 2462306a36Sopenharmony_ci * too complex for a single device to be managed by a monolithic driver (e.g. 2562306a36Sopenharmony_ci * Sound Open Firmware), multiple devices might implement a common intersection 2662306a36Sopenharmony_ci * of functionality (e.g. NICs + RDMA), or a driver may want to export an 2762306a36Sopenharmony_ci * interface for another subsystem to drive (e.g. SIOV Physical Function export 2862306a36Sopenharmony_ci * Virtual Function management). A split of the functionality into child- 2962306a36Sopenharmony_ci * devices representing sub-domains of functionality makes it possible to 3062306a36Sopenharmony_ci * compartmentalize, layer, and distribute domain-specific concerns via a Linux 3162306a36Sopenharmony_ci * device-driver model. 3262306a36Sopenharmony_ci * 3362306a36Sopenharmony_ci * An example for this kind of requirement is the audio subsystem where a 3462306a36Sopenharmony_ci * single IP is handling multiple entities such as HDMI, Soundwire, local 3562306a36Sopenharmony_ci * devices such as mics/speakers etc. The split for the core's functionality 3662306a36Sopenharmony_ci * can be arbitrary or be defined by the DSP firmware topology and include 3762306a36Sopenharmony_ci * hooks for test/debug. This allows for the audio core device to be minimal 3862306a36Sopenharmony_ci * and focused on hardware-specific control and communication. 3962306a36Sopenharmony_ci * 4062306a36Sopenharmony_ci * Each auxiliary_device represents a part of its parent functionality. The 4162306a36Sopenharmony_ci * generic behavior can be extended and specialized as needed by encapsulating 4262306a36Sopenharmony_ci * an auxiliary_device within other domain-specific structures and the use of 4362306a36Sopenharmony_ci * .ops callbacks. Devices on the auxiliary bus do not share any structures and 4462306a36Sopenharmony_ci * the use of a communication channel with the parent is domain-specific. 4562306a36Sopenharmony_ci * 4662306a36Sopenharmony_ci * Note that ops are intended as a way to augment instance behavior within a 4762306a36Sopenharmony_ci * class of auxiliary devices, it is not the mechanism for exporting common 4862306a36Sopenharmony_ci * infrastructure from the parent. Consider EXPORT_SYMBOL_NS() to convey 4962306a36Sopenharmony_ci * infrastructure from the parent module to the auxiliary module(s). 5062306a36Sopenharmony_ci */ 5162306a36Sopenharmony_ci 5262306a36Sopenharmony_ci/** 5362306a36Sopenharmony_ci * DOC: USAGE 5462306a36Sopenharmony_ci * 5562306a36Sopenharmony_ci * The auxiliary bus is to be used when a driver and one or more kernel 5662306a36Sopenharmony_ci * modules, who share a common header file with the driver, need a mechanism to 5762306a36Sopenharmony_ci * connect and provide access to a shared object allocated by the 5862306a36Sopenharmony_ci * auxiliary_device's registering driver. The registering driver for the 5962306a36Sopenharmony_ci * auxiliary_device(s) and the kernel module(s) registering auxiliary_drivers 6062306a36Sopenharmony_ci * can be from the same subsystem, or from multiple subsystems. 6162306a36Sopenharmony_ci * 6262306a36Sopenharmony_ci * The emphasis here is on a common generic interface that keeps subsystem 6362306a36Sopenharmony_ci * customization out of the bus infrastructure. 6462306a36Sopenharmony_ci * 6562306a36Sopenharmony_ci * One example is a PCI network device that is RDMA-capable and exports a child 6662306a36Sopenharmony_ci * device to be driven by an auxiliary_driver in the RDMA subsystem. The PCI 6762306a36Sopenharmony_ci * driver allocates and registers an auxiliary_device for each physical 6862306a36Sopenharmony_ci * function on the NIC. The RDMA driver registers an auxiliary_driver that 6962306a36Sopenharmony_ci * claims each of these auxiliary_devices. This conveys data/ops published by 7062306a36Sopenharmony_ci * the parent PCI device/driver to the RDMA auxiliary_driver. 7162306a36Sopenharmony_ci * 7262306a36Sopenharmony_ci * Another use case is for the PCI device to be split out into multiple sub 7362306a36Sopenharmony_ci * functions. For each sub function an auxiliary_device is created. A PCI sub 7462306a36Sopenharmony_ci * function driver binds to such devices that creates its own one or more class 7562306a36Sopenharmony_ci * devices. A PCI sub function auxiliary device is likely to be contained in a 7662306a36Sopenharmony_ci * struct with additional attributes such as user defined sub function number 7762306a36Sopenharmony_ci * and optional attributes such as resources and a link to the parent device. 7862306a36Sopenharmony_ci * These attributes could be used by systemd/udev; and hence should be 7962306a36Sopenharmony_ci * initialized before a driver binds to an auxiliary_device. 8062306a36Sopenharmony_ci * 8162306a36Sopenharmony_ci * A key requirement for utilizing the auxiliary bus is that there is no 8262306a36Sopenharmony_ci * dependency on a physical bus, device, register accesses or regmap support. 8362306a36Sopenharmony_ci * These individual devices split from the core cannot live on the platform bus 8462306a36Sopenharmony_ci * as they are not physical devices that are controlled by DT/ACPI. The same 8562306a36Sopenharmony_ci * argument applies for not using MFD in this scenario as MFD relies on 8662306a36Sopenharmony_ci * individual function devices being physical devices. 8762306a36Sopenharmony_ci */ 8862306a36Sopenharmony_ci 8962306a36Sopenharmony_ci/** 9062306a36Sopenharmony_ci * DOC: EXAMPLE 9162306a36Sopenharmony_ci * 9262306a36Sopenharmony_ci * Auxiliary devices are created and registered by a subsystem-level core 9362306a36Sopenharmony_ci * device that needs to break up its functionality into smaller fragments. One 9462306a36Sopenharmony_ci * way to extend the scope of an auxiliary_device is to encapsulate it within a 9562306a36Sopenharmony_ci * domain- pecific structure defined by the parent device. This structure 9662306a36Sopenharmony_ci * contains the auxiliary_device and any associated shared data/callbacks 9762306a36Sopenharmony_ci * needed to establish the connection with the parent. 9862306a36Sopenharmony_ci * 9962306a36Sopenharmony_ci * An example is: 10062306a36Sopenharmony_ci * 10162306a36Sopenharmony_ci * .. code-block:: c 10262306a36Sopenharmony_ci * 10362306a36Sopenharmony_ci * struct foo { 10462306a36Sopenharmony_ci * struct auxiliary_device auxdev; 10562306a36Sopenharmony_ci * void (*connect)(struct auxiliary_device *auxdev); 10662306a36Sopenharmony_ci * void (*disconnect)(struct auxiliary_device *auxdev); 10762306a36Sopenharmony_ci * void *data; 10862306a36Sopenharmony_ci * }; 10962306a36Sopenharmony_ci * 11062306a36Sopenharmony_ci * The parent device then registers the auxiliary_device by calling 11162306a36Sopenharmony_ci * auxiliary_device_init(), and then auxiliary_device_add(), with the pointer 11262306a36Sopenharmony_ci * to the auxdev member of the above structure. The parent provides a name for 11362306a36Sopenharmony_ci * the auxiliary_device that, combined with the parent's KBUILD_MODNAME, 11462306a36Sopenharmony_ci * creates a match_name that is be used for matching and binding with a driver. 11562306a36Sopenharmony_ci * 11662306a36Sopenharmony_ci * Whenever an auxiliary_driver is registered, based on the match_name, the 11762306a36Sopenharmony_ci * auxiliary_driver's probe() is invoked for the matching devices. The 11862306a36Sopenharmony_ci * auxiliary_driver can also be encapsulated inside custom drivers that make 11962306a36Sopenharmony_ci * the core device's functionality extensible by adding additional 12062306a36Sopenharmony_ci * domain-specific ops as follows: 12162306a36Sopenharmony_ci * 12262306a36Sopenharmony_ci * .. code-block:: c 12362306a36Sopenharmony_ci * 12462306a36Sopenharmony_ci * struct my_ops { 12562306a36Sopenharmony_ci * void (*send)(struct auxiliary_device *auxdev); 12662306a36Sopenharmony_ci * void (*receive)(struct auxiliary_device *auxdev); 12762306a36Sopenharmony_ci * }; 12862306a36Sopenharmony_ci * 12962306a36Sopenharmony_ci * 13062306a36Sopenharmony_ci * struct my_driver { 13162306a36Sopenharmony_ci * struct auxiliary_driver auxiliary_drv; 13262306a36Sopenharmony_ci * const struct my_ops ops; 13362306a36Sopenharmony_ci * }; 13462306a36Sopenharmony_ci * 13562306a36Sopenharmony_ci * An example of this type of usage is: 13662306a36Sopenharmony_ci * 13762306a36Sopenharmony_ci * .. code-block:: c 13862306a36Sopenharmony_ci * 13962306a36Sopenharmony_ci * const struct auxiliary_device_id my_auxiliary_id_table[] = { 14062306a36Sopenharmony_ci * { .name = "foo_mod.foo_dev" }, 14162306a36Sopenharmony_ci * { }, 14262306a36Sopenharmony_ci * }; 14362306a36Sopenharmony_ci * 14462306a36Sopenharmony_ci * const struct my_ops my_custom_ops = { 14562306a36Sopenharmony_ci * .send = my_tx, 14662306a36Sopenharmony_ci * .receive = my_rx, 14762306a36Sopenharmony_ci * }; 14862306a36Sopenharmony_ci * 14962306a36Sopenharmony_ci * const struct my_driver my_drv = { 15062306a36Sopenharmony_ci * .auxiliary_drv = { 15162306a36Sopenharmony_ci * .name = "myauxiliarydrv", 15262306a36Sopenharmony_ci * .id_table = my_auxiliary_id_table, 15362306a36Sopenharmony_ci * .probe = my_probe, 15462306a36Sopenharmony_ci * .remove = my_remove, 15562306a36Sopenharmony_ci * .shutdown = my_shutdown, 15662306a36Sopenharmony_ci * }, 15762306a36Sopenharmony_ci * .ops = my_custom_ops, 15862306a36Sopenharmony_ci * }; 15962306a36Sopenharmony_ci */ 16062306a36Sopenharmony_ci 16162306a36Sopenharmony_cistatic const struct auxiliary_device_id *auxiliary_match_id(const struct auxiliary_device_id *id, 16262306a36Sopenharmony_ci const struct auxiliary_device *auxdev) 16362306a36Sopenharmony_ci{ 16462306a36Sopenharmony_ci for (; id->name[0]; id++) { 16562306a36Sopenharmony_ci const char *p = strrchr(dev_name(&auxdev->dev), '.'); 16662306a36Sopenharmony_ci int match_size; 16762306a36Sopenharmony_ci 16862306a36Sopenharmony_ci if (!p) 16962306a36Sopenharmony_ci continue; 17062306a36Sopenharmony_ci match_size = p - dev_name(&auxdev->dev); 17162306a36Sopenharmony_ci 17262306a36Sopenharmony_ci /* use dev_name(&auxdev->dev) prefix before last '.' char to match to */ 17362306a36Sopenharmony_ci if (strlen(id->name) == match_size && 17462306a36Sopenharmony_ci !strncmp(dev_name(&auxdev->dev), id->name, match_size)) 17562306a36Sopenharmony_ci return id; 17662306a36Sopenharmony_ci } 17762306a36Sopenharmony_ci return NULL; 17862306a36Sopenharmony_ci} 17962306a36Sopenharmony_ci 18062306a36Sopenharmony_cistatic int auxiliary_match(struct device *dev, struct device_driver *drv) 18162306a36Sopenharmony_ci{ 18262306a36Sopenharmony_ci struct auxiliary_device *auxdev = to_auxiliary_dev(dev); 18362306a36Sopenharmony_ci struct auxiliary_driver *auxdrv = to_auxiliary_drv(drv); 18462306a36Sopenharmony_ci 18562306a36Sopenharmony_ci return !!auxiliary_match_id(auxdrv->id_table, auxdev); 18662306a36Sopenharmony_ci} 18762306a36Sopenharmony_ci 18862306a36Sopenharmony_cistatic int auxiliary_uevent(const struct device *dev, struct kobj_uevent_env *env) 18962306a36Sopenharmony_ci{ 19062306a36Sopenharmony_ci const char *name, *p; 19162306a36Sopenharmony_ci 19262306a36Sopenharmony_ci name = dev_name(dev); 19362306a36Sopenharmony_ci p = strrchr(name, '.'); 19462306a36Sopenharmony_ci 19562306a36Sopenharmony_ci return add_uevent_var(env, "MODALIAS=%s%.*s", AUXILIARY_MODULE_PREFIX, 19662306a36Sopenharmony_ci (int)(p - name), name); 19762306a36Sopenharmony_ci} 19862306a36Sopenharmony_ci 19962306a36Sopenharmony_cistatic const struct dev_pm_ops auxiliary_dev_pm_ops = { 20062306a36Sopenharmony_ci SET_RUNTIME_PM_OPS(pm_generic_runtime_suspend, pm_generic_runtime_resume, NULL) 20162306a36Sopenharmony_ci SET_SYSTEM_SLEEP_PM_OPS(pm_generic_suspend, pm_generic_resume) 20262306a36Sopenharmony_ci}; 20362306a36Sopenharmony_ci 20462306a36Sopenharmony_cistatic int auxiliary_bus_probe(struct device *dev) 20562306a36Sopenharmony_ci{ 20662306a36Sopenharmony_ci struct auxiliary_driver *auxdrv = to_auxiliary_drv(dev->driver); 20762306a36Sopenharmony_ci struct auxiliary_device *auxdev = to_auxiliary_dev(dev); 20862306a36Sopenharmony_ci int ret; 20962306a36Sopenharmony_ci 21062306a36Sopenharmony_ci ret = dev_pm_domain_attach(dev, true); 21162306a36Sopenharmony_ci if (ret) { 21262306a36Sopenharmony_ci dev_warn(dev, "Failed to attach to PM Domain : %d\n", ret); 21362306a36Sopenharmony_ci return ret; 21462306a36Sopenharmony_ci } 21562306a36Sopenharmony_ci 21662306a36Sopenharmony_ci ret = auxdrv->probe(auxdev, auxiliary_match_id(auxdrv->id_table, auxdev)); 21762306a36Sopenharmony_ci if (ret) 21862306a36Sopenharmony_ci dev_pm_domain_detach(dev, true); 21962306a36Sopenharmony_ci 22062306a36Sopenharmony_ci return ret; 22162306a36Sopenharmony_ci} 22262306a36Sopenharmony_ci 22362306a36Sopenharmony_cistatic void auxiliary_bus_remove(struct device *dev) 22462306a36Sopenharmony_ci{ 22562306a36Sopenharmony_ci struct auxiliary_driver *auxdrv = to_auxiliary_drv(dev->driver); 22662306a36Sopenharmony_ci struct auxiliary_device *auxdev = to_auxiliary_dev(dev); 22762306a36Sopenharmony_ci 22862306a36Sopenharmony_ci if (auxdrv->remove) 22962306a36Sopenharmony_ci auxdrv->remove(auxdev); 23062306a36Sopenharmony_ci dev_pm_domain_detach(dev, true); 23162306a36Sopenharmony_ci} 23262306a36Sopenharmony_ci 23362306a36Sopenharmony_cistatic void auxiliary_bus_shutdown(struct device *dev) 23462306a36Sopenharmony_ci{ 23562306a36Sopenharmony_ci struct auxiliary_driver *auxdrv = NULL; 23662306a36Sopenharmony_ci struct auxiliary_device *auxdev; 23762306a36Sopenharmony_ci 23862306a36Sopenharmony_ci if (dev->driver) { 23962306a36Sopenharmony_ci auxdrv = to_auxiliary_drv(dev->driver); 24062306a36Sopenharmony_ci auxdev = to_auxiliary_dev(dev); 24162306a36Sopenharmony_ci } 24262306a36Sopenharmony_ci 24362306a36Sopenharmony_ci if (auxdrv && auxdrv->shutdown) 24462306a36Sopenharmony_ci auxdrv->shutdown(auxdev); 24562306a36Sopenharmony_ci} 24662306a36Sopenharmony_ci 24762306a36Sopenharmony_cistatic struct bus_type auxiliary_bus_type = { 24862306a36Sopenharmony_ci .name = "auxiliary", 24962306a36Sopenharmony_ci .probe = auxiliary_bus_probe, 25062306a36Sopenharmony_ci .remove = auxiliary_bus_remove, 25162306a36Sopenharmony_ci .shutdown = auxiliary_bus_shutdown, 25262306a36Sopenharmony_ci .match = auxiliary_match, 25362306a36Sopenharmony_ci .uevent = auxiliary_uevent, 25462306a36Sopenharmony_ci .pm = &auxiliary_dev_pm_ops, 25562306a36Sopenharmony_ci}; 25662306a36Sopenharmony_ci 25762306a36Sopenharmony_ci/** 25862306a36Sopenharmony_ci * auxiliary_device_init - check auxiliary_device and initialize 25962306a36Sopenharmony_ci * @auxdev: auxiliary device struct 26062306a36Sopenharmony_ci * 26162306a36Sopenharmony_ci * This is the second step in the three-step process to register an 26262306a36Sopenharmony_ci * auxiliary_device. 26362306a36Sopenharmony_ci * 26462306a36Sopenharmony_ci * When this function returns an error code, then the device_initialize will 26562306a36Sopenharmony_ci * *not* have been performed, and the caller will be responsible to free any 26662306a36Sopenharmony_ci * memory allocated for the auxiliary_device in the error path directly. 26762306a36Sopenharmony_ci * 26862306a36Sopenharmony_ci * It returns 0 on success. On success, the device_initialize has been 26962306a36Sopenharmony_ci * performed. After this point any error unwinding will need to include a call 27062306a36Sopenharmony_ci * to auxiliary_device_uninit(). In this post-initialize error scenario, a call 27162306a36Sopenharmony_ci * to the device's .release callback will be triggered, and all memory clean-up 27262306a36Sopenharmony_ci * is expected to be handled there. 27362306a36Sopenharmony_ci */ 27462306a36Sopenharmony_ciint auxiliary_device_init(struct auxiliary_device *auxdev) 27562306a36Sopenharmony_ci{ 27662306a36Sopenharmony_ci struct device *dev = &auxdev->dev; 27762306a36Sopenharmony_ci 27862306a36Sopenharmony_ci if (!dev->parent) { 27962306a36Sopenharmony_ci pr_err("auxiliary_device has a NULL dev->parent\n"); 28062306a36Sopenharmony_ci return -EINVAL; 28162306a36Sopenharmony_ci } 28262306a36Sopenharmony_ci 28362306a36Sopenharmony_ci if (!auxdev->name) { 28462306a36Sopenharmony_ci pr_err("auxiliary_device has a NULL name\n"); 28562306a36Sopenharmony_ci return -EINVAL; 28662306a36Sopenharmony_ci } 28762306a36Sopenharmony_ci 28862306a36Sopenharmony_ci dev->bus = &auxiliary_bus_type; 28962306a36Sopenharmony_ci device_initialize(&auxdev->dev); 29062306a36Sopenharmony_ci return 0; 29162306a36Sopenharmony_ci} 29262306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(auxiliary_device_init); 29362306a36Sopenharmony_ci 29462306a36Sopenharmony_ci/** 29562306a36Sopenharmony_ci * __auxiliary_device_add - add an auxiliary bus device 29662306a36Sopenharmony_ci * @auxdev: auxiliary bus device to add to the bus 29762306a36Sopenharmony_ci * @modname: name of the parent device's driver module 29862306a36Sopenharmony_ci * 29962306a36Sopenharmony_ci * This is the third step in the three-step process to register an 30062306a36Sopenharmony_ci * auxiliary_device. 30162306a36Sopenharmony_ci * 30262306a36Sopenharmony_ci * This function must be called after a successful call to 30362306a36Sopenharmony_ci * auxiliary_device_init(), which will perform the device_initialize. This 30462306a36Sopenharmony_ci * means that if this returns an error code, then a call to 30562306a36Sopenharmony_ci * auxiliary_device_uninit() must be performed so that the .release callback 30662306a36Sopenharmony_ci * will be triggered to free the memory associated with the auxiliary_device. 30762306a36Sopenharmony_ci * 30862306a36Sopenharmony_ci * The expectation is that users will call the "auxiliary_device_add" macro so 30962306a36Sopenharmony_ci * that the caller's KBUILD_MODNAME is automatically inserted for the modname 31062306a36Sopenharmony_ci * parameter. Only if a user requires a custom name would this version be 31162306a36Sopenharmony_ci * called directly. 31262306a36Sopenharmony_ci */ 31362306a36Sopenharmony_ciint __auxiliary_device_add(struct auxiliary_device *auxdev, const char *modname) 31462306a36Sopenharmony_ci{ 31562306a36Sopenharmony_ci struct device *dev = &auxdev->dev; 31662306a36Sopenharmony_ci int ret; 31762306a36Sopenharmony_ci 31862306a36Sopenharmony_ci if (!modname) { 31962306a36Sopenharmony_ci dev_err(dev, "auxiliary device modname is NULL\n"); 32062306a36Sopenharmony_ci return -EINVAL; 32162306a36Sopenharmony_ci } 32262306a36Sopenharmony_ci 32362306a36Sopenharmony_ci ret = dev_set_name(dev, "%s.%s.%d", modname, auxdev->name, auxdev->id); 32462306a36Sopenharmony_ci if (ret) { 32562306a36Sopenharmony_ci dev_err(dev, "auxiliary device dev_set_name failed: %d\n", ret); 32662306a36Sopenharmony_ci return ret; 32762306a36Sopenharmony_ci } 32862306a36Sopenharmony_ci 32962306a36Sopenharmony_ci ret = device_add(dev); 33062306a36Sopenharmony_ci if (ret) 33162306a36Sopenharmony_ci dev_err(dev, "adding auxiliary device failed!: %d\n", ret); 33262306a36Sopenharmony_ci 33362306a36Sopenharmony_ci return ret; 33462306a36Sopenharmony_ci} 33562306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(__auxiliary_device_add); 33662306a36Sopenharmony_ci 33762306a36Sopenharmony_ci/** 33862306a36Sopenharmony_ci * auxiliary_find_device - auxiliary device iterator for locating a particular device. 33962306a36Sopenharmony_ci * @start: Device to begin with 34062306a36Sopenharmony_ci * @data: Data to pass to match function 34162306a36Sopenharmony_ci * @match: Callback function to check device 34262306a36Sopenharmony_ci * 34362306a36Sopenharmony_ci * This function returns a reference to a device that is 'found' 34462306a36Sopenharmony_ci * for later use, as determined by the @match callback. 34562306a36Sopenharmony_ci * 34662306a36Sopenharmony_ci * The reference returned should be released with put_device(). 34762306a36Sopenharmony_ci * 34862306a36Sopenharmony_ci * The callback should return 0 if the device doesn't match and non-zero 34962306a36Sopenharmony_ci * if it does. If the callback returns non-zero, this function will 35062306a36Sopenharmony_ci * return to the caller and not iterate over any more devices. 35162306a36Sopenharmony_ci */ 35262306a36Sopenharmony_cistruct auxiliary_device *auxiliary_find_device(struct device *start, 35362306a36Sopenharmony_ci const void *data, 35462306a36Sopenharmony_ci int (*match)(struct device *dev, const void *data)) 35562306a36Sopenharmony_ci{ 35662306a36Sopenharmony_ci struct device *dev; 35762306a36Sopenharmony_ci 35862306a36Sopenharmony_ci dev = bus_find_device(&auxiliary_bus_type, start, data, match); 35962306a36Sopenharmony_ci if (!dev) 36062306a36Sopenharmony_ci return NULL; 36162306a36Sopenharmony_ci 36262306a36Sopenharmony_ci return to_auxiliary_dev(dev); 36362306a36Sopenharmony_ci} 36462306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(auxiliary_find_device); 36562306a36Sopenharmony_ci 36662306a36Sopenharmony_ci/** 36762306a36Sopenharmony_ci * __auxiliary_driver_register - register a driver for auxiliary bus devices 36862306a36Sopenharmony_ci * @auxdrv: auxiliary_driver structure 36962306a36Sopenharmony_ci * @owner: owning module/driver 37062306a36Sopenharmony_ci * @modname: KBUILD_MODNAME for parent driver 37162306a36Sopenharmony_ci * 37262306a36Sopenharmony_ci * The expectation is that users will call the "auxiliary_driver_register" 37362306a36Sopenharmony_ci * macro so that the caller's KBUILD_MODNAME is automatically inserted for the 37462306a36Sopenharmony_ci * modname parameter. Only if a user requires a custom name would this version 37562306a36Sopenharmony_ci * be called directly. 37662306a36Sopenharmony_ci */ 37762306a36Sopenharmony_ciint __auxiliary_driver_register(struct auxiliary_driver *auxdrv, 37862306a36Sopenharmony_ci struct module *owner, const char *modname) 37962306a36Sopenharmony_ci{ 38062306a36Sopenharmony_ci int ret; 38162306a36Sopenharmony_ci 38262306a36Sopenharmony_ci if (WARN_ON(!auxdrv->probe) || WARN_ON(!auxdrv->id_table)) 38362306a36Sopenharmony_ci return -EINVAL; 38462306a36Sopenharmony_ci 38562306a36Sopenharmony_ci if (auxdrv->name) 38662306a36Sopenharmony_ci auxdrv->driver.name = kasprintf(GFP_KERNEL, "%s.%s", modname, 38762306a36Sopenharmony_ci auxdrv->name); 38862306a36Sopenharmony_ci else 38962306a36Sopenharmony_ci auxdrv->driver.name = kasprintf(GFP_KERNEL, "%s", modname); 39062306a36Sopenharmony_ci if (!auxdrv->driver.name) 39162306a36Sopenharmony_ci return -ENOMEM; 39262306a36Sopenharmony_ci 39362306a36Sopenharmony_ci auxdrv->driver.owner = owner; 39462306a36Sopenharmony_ci auxdrv->driver.bus = &auxiliary_bus_type; 39562306a36Sopenharmony_ci auxdrv->driver.mod_name = modname; 39662306a36Sopenharmony_ci 39762306a36Sopenharmony_ci ret = driver_register(&auxdrv->driver); 39862306a36Sopenharmony_ci if (ret) 39962306a36Sopenharmony_ci kfree(auxdrv->driver.name); 40062306a36Sopenharmony_ci 40162306a36Sopenharmony_ci return ret; 40262306a36Sopenharmony_ci} 40362306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(__auxiliary_driver_register); 40462306a36Sopenharmony_ci 40562306a36Sopenharmony_ci/** 40662306a36Sopenharmony_ci * auxiliary_driver_unregister - unregister a driver 40762306a36Sopenharmony_ci * @auxdrv: auxiliary_driver structure 40862306a36Sopenharmony_ci */ 40962306a36Sopenharmony_civoid auxiliary_driver_unregister(struct auxiliary_driver *auxdrv) 41062306a36Sopenharmony_ci{ 41162306a36Sopenharmony_ci driver_unregister(&auxdrv->driver); 41262306a36Sopenharmony_ci kfree(auxdrv->driver.name); 41362306a36Sopenharmony_ci} 41462306a36Sopenharmony_ciEXPORT_SYMBOL_GPL(auxiliary_driver_unregister); 41562306a36Sopenharmony_ci 41662306a36Sopenharmony_civoid __init auxiliary_bus_init(void) 41762306a36Sopenharmony_ci{ 41862306a36Sopenharmony_ci WARN_ON(bus_register(&auxiliary_bus_type)); 41962306a36Sopenharmony_ci} 420