Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

Add auxiliary bus support

Add support for the Auxiliary Bus, auxiliary_device and auxiliary_driver.
It enables drivers to create an auxiliary_device and bind an
auxiliary_driver to it.

The bus supports probe/remove shutdown and suspend/resume callbacks.
Each auxiliary_device has a unique string based id; driver binds to
an auxiliary_device based on this id through the bus.

Co-developed-by: Kiran Patil <kiran.patil@intel.com>
Co-developed-by: Ranjani Sridharan <ranjani.sridharan@linux.intel.com>
Co-developed-by: Fred Oh <fred.oh@linux.intel.com>
Co-developed-by: Leon Romanovsky <leonro@nvidia.com>
Signed-off-by: Kiran Patil <kiran.patil@intel.com>
Signed-off-by: Ranjani Sridharan <ranjani.sridharan@linux.intel.com>
Signed-off-by: Fred Oh <fred.oh@linux.intel.com>
Signed-off-by: Leon Romanovsky <leonro@nvidia.com>
Signed-off-by: Dave Ertman <david.m.ertman@intel.com>
Reviewed-by: Pierre-Louis Bossart <pierre-louis.bossart@linux.intel.com>
Reviewed-by: Shiraz Saleem <shiraz.saleem@intel.com>
Reviewed-by: Parav Pandit <parav@mellanox.com>
Reviewed-by: Dan Williams <dan.j.williams@intel.com>
Reviewed-by: Martin Habets <mhabets@solarflare.com>
Link: https://lore.kernel.org/r/20201113161859.1775473-2-david.m.ertman@intel.com
Signed-off-by: Dan Williams <dan.j.williams@intel.com>
Link: https://lore.kernel.org/r/160695681289.505290.8978295443574440604.stgit@dwillia2-desk3.amr.corp.intel.com
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>

authored by

Dave Ertman and committed by
Greg Kroah-Hartman
7de3697e f8394f23

+604
+234
Documentation/driver-api/auxiliary_bus.rst
··· 1 + .. SPDX-License-Identifier: GPL-2.0-only 2 + 3 + ============= 4 + Auxiliary Bus 5 + ============= 6 + 7 + In some subsystems, the functionality of the core device (PCI/ACPI/other) is 8 + too complex for a single device to be managed by a monolithic driver 9 + (e.g. Sound Open Firmware), multiple devices might implement a common 10 + intersection of functionality (e.g. NICs + RDMA), or a driver may want to 11 + export an interface for another subsystem to drive (e.g. SIOV Physical Function 12 + export Virtual Function management). A split of the functinoality into child- 13 + devices representing sub-domains of functionality makes it possible to 14 + compartmentalize, layer, and distribute domain-specific concerns via a Linux 15 + device-driver model. 16 + 17 + An example for this kind of requirement is the audio subsystem where a single 18 + IP is handling multiple entities such as HDMI, Soundwire, local devices such as 19 + mics/speakers etc. The split for the core's functionality can be arbitrary or 20 + be defined by the DSP firmware topology and include hooks for test/debug. This 21 + allows for the audio core device to be minimal and focused on hardware-specific 22 + control and communication. 23 + 24 + Each auxiliary_device represents a part of its parent functionality. The 25 + generic behavior can be extended and specialized as needed by encapsulating an 26 + auxiliary_device within other domain-specific structures and the use of .ops 27 + callbacks. Devices on the auxiliary bus do not share any structures and the use 28 + of a communication channel with the parent is domain-specific. 29 + 30 + Note that ops are intended as a way to augment instance behavior within a class 31 + of auxiliary devices, it is not the mechanism for exporting common 32 + infrastructure from the parent. Consider EXPORT_SYMBOL_NS() to convey 33 + infrastructure from the parent module to the auxiliary module(s). 34 + 35 + 36 + When Should the Auxiliary Bus Be Used 37 + ===================================== 38 + 39 + The auxiliary bus is to be used when a driver and one or more kernel modules, 40 + who share a common header file with the driver, need a mechanism to connect and 41 + provide access to a shared object allocated by the auxiliary_device's 42 + registering driver. The registering driver for the auxiliary_device(s) and the 43 + kernel module(s) registering auxiliary_drivers can be from the same subsystem, 44 + or from multiple subsystems. 45 + 46 + The emphasis here is on a common generic interface that keeps subsystem 47 + customization out of the bus infrastructure. 48 + 49 + One example is a PCI network device that is RDMA-capable and exports a child 50 + device to be driven by an auxiliary_driver in the RDMA subsystem. The PCI 51 + driver allocates and registers an auxiliary_device for each physical 52 + function on the NIC. The RDMA driver registers an auxiliary_driver that claims 53 + each of these auxiliary_devices. This conveys data/ops published by the parent 54 + PCI device/driver to the RDMA auxiliary_driver. 55 + 56 + Another use case is for the PCI device to be split out into multiple sub 57 + functions. For each sub function an auxiliary_device is created. A PCI sub 58 + function driver binds to such devices that creates its own one or more class 59 + devices. A PCI sub function auxiliary device is likely to be contained in a 60 + struct with additional attributes such as user defined sub function number and 61 + optional attributes such as resources and a link to the parent device. These 62 + attributes could be used by systemd/udev; and hence should be initialized 63 + before a driver binds to an auxiliary_device. 64 + 65 + A key requirement for utilizing the auxiliary bus is that there is no 66 + dependency on a physical bus, device, register accesses or regmap support. 67 + These individual devices split from the core cannot live on the platform bus as 68 + they are not physical devices that are controlled by DT/ACPI. The same 69 + argument applies for not using MFD in this scenario as MFD relies on individual 70 + function devices being physical devices. 71 + 72 + Auxiliary Device 73 + ================ 74 + 75 + An auxiliary_device represents a part of its parent device's functionality. It 76 + is given a name that, combined with the registering drivers KBUILD_MODNAME, 77 + creates a match_name that is used for driver binding, and an id that combined 78 + with the match_name provide a unique name to register with the bus subsystem. 79 + 80 + Registering an auxiliary_device is a two-step process. First call 81 + auxiliary_device_init(), which checks several aspects of the auxiliary_device 82 + struct and performs a device_initialize(). After this step completes, any 83 + error state must have a call to auxiliary_device_uninit() in its resolution path. 84 + The second step in registering an auxiliary_device is to perform a call to 85 + auxiliary_device_add(), which sets the name of the device and add the device to 86 + the bus. 87 + 88 + Unregistering an auxiliary_device is also a two-step process to mirror the 89 + register process. First call auxiliary_device_delete(), then call 90 + auxiliary_device_uninit(). 91 + 92 + .. code-block:: c 93 + 94 + struct auxiliary_device { 95 + struct device dev; 96 + const char *name; 97 + u32 id; 98 + }; 99 + 100 + If two auxiliary_devices both with a match_name "mod.foo" are registered onto 101 + the bus, they must have unique id values (e.g. "x" and "y") so that the 102 + registered devices names are "mod.foo.x" and "mod.foo.y". If match_name + id 103 + are not unique, then the device_add fails and generates an error message. 104 + 105 + The auxiliary_device.dev.type.release or auxiliary_device.dev.release must be 106 + populated with a non-NULL pointer to successfully register the auxiliary_device. 107 + 108 + The auxiliary_device.dev.parent must also be populated. 109 + 110 + Auxiliary Device Memory Model and Lifespan 111 + ------------------------------------------ 112 + 113 + The registering driver is the entity that allocates memory for the 114 + auxiliary_device and register it on the auxiliary bus. It is important to note 115 + that, as opposed to the platform bus, the registering driver is wholly 116 + responsible for the management for the memory used for the driver object. 117 + 118 + A parent object, defined in the shared header file, contains the 119 + auxiliary_device. It also contains a pointer to the shared object(s), which 120 + also is defined in the shared header. Both the parent object and the shared 121 + object(s) are allocated by the registering driver. This layout allows the 122 + auxiliary_driver's registering module to perform a container_of() call to go 123 + from the pointer to the auxiliary_device, that is passed during the call to the 124 + auxiliary_driver's probe function, up to the parent object, and then have 125 + access to the shared object(s). 126 + 127 + The memory for the auxiliary_device is freed only in its release() callback 128 + flow as defined by its registering driver. 129 + 130 + The memory for the shared object(s) must have a lifespan equal to, or greater 131 + than, the lifespan of the memory for the auxiliary_device. The auxiliary_driver 132 + should only consider that this shared object is valid as long as the 133 + auxiliary_device is still registered on the auxiliary bus. It is up to the 134 + registering driver to manage (e.g. free or keep available) the memory for the 135 + shared object beyond the life of the auxiliary_device. 136 + 137 + The registering driver must unregister all auxiliary devices before its own 138 + driver.remove() is completed. 139 + 140 + Auxiliary Drivers 141 + ================= 142 + 143 + Auxiliary drivers follow the standard driver model convention, where 144 + discovery/enumeration is handled by the core, and drivers 145 + provide probe() and remove() methods. They support power management 146 + and shutdown notifications using the standard conventions. 147 + 148 + .. code-block:: c 149 + 150 + struct auxiliary_driver { 151 + int (*probe)(struct auxiliary_device *, 152 + const struct auxiliary_device_id *id); 153 + int (*remove)(struct auxiliary_device *); 154 + void (*shutdown)(struct auxiliary_device *); 155 + int (*suspend)(struct auxiliary_device *, pm_message_t); 156 + int (*resume)(struct auxiliary_device *); 157 + struct device_driver driver; 158 + const struct auxiliary_device_id *id_table; 159 + }; 160 + 161 + Auxiliary drivers register themselves with the bus by calling 162 + auxiliary_driver_register(). The id_table contains the match_names of auxiliary 163 + devices that a driver can bind with. 164 + 165 + Example Usage 166 + ============= 167 + 168 + Auxiliary devices are created and registered by a subsystem-level core device 169 + that needs to break up its functionality into smaller fragments. One way to 170 + extend the scope of an auxiliary_device is to encapsulate it within a domain- 171 + pecific structure defined by the parent device. This structure contains the 172 + auxiliary_device and any associated shared data/callbacks needed to establish 173 + the connection with the parent. 174 + 175 + An example is: 176 + 177 + .. code-block:: c 178 + 179 + struct foo { 180 + struct auxiliary_device auxdev; 181 + void (*connect)(struct auxiliary_device *auxdev); 182 + void (*disconnect)(struct auxiliary_device *auxdev); 183 + void *data; 184 + }; 185 + 186 + The parent device then registers the auxiliary_device by calling 187 + auxiliary_device_init(), and then auxiliary_device_add(), with the pointer to 188 + the auxdev member of the above structure. The parent provides a name for the 189 + auxiliary_device that, combined with the parent's KBUILD_MODNAME, creates a 190 + match_name that is be used for matching and binding with a driver. 191 + 192 + Whenever an auxiliary_driver is registered, based on the match_name, the 193 + auxiliary_driver's probe() is invoked for the matching devices. The 194 + auxiliary_driver can also be encapsulated inside custom drivers that make the 195 + core device's functionality extensible by adding additional domain-specific ops 196 + as follows: 197 + 198 + .. code-block:: c 199 + 200 + struct my_ops { 201 + void (*send)(struct auxiliary_device *auxdev); 202 + void (*receive)(struct auxiliary_device *auxdev); 203 + }; 204 + 205 + 206 + struct my_driver { 207 + struct auxiliary_driver auxiliary_drv; 208 + const struct my_ops ops; 209 + }; 210 + 211 + An example of this type of usage is: 212 + 213 + .. code-block:: c 214 + 215 + const struct auxiliary_device_id my_auxiliary_id_table[] = { 216 + { .name = "foo_mod.foo_dev" }, 217 + { }, 218 + }; 219 + 220 + const struct my_ops my_custom_ops = { 221 + .send = my_tx, 222 + .receive = my_rx, 223 + }; 224 + 225 + const struct my_driver my_drv = { 226 + .auxiliary_drv = { 227 + .name = "myauxiliarydrv", 228 + .id_table = my_auxiliary_id_table, 229 + .probe = my_probe, 230 + .remove = my_remove, 231 + .shutdown = my_shutdown, 232 + }, 233 + .ops = my_custom_ops, 234 + };
+1
Documentation/driver-api/index.rst
··· 72 72 thermal/index 73 73 fpga/index 74 74 acpi/index 75 + auxiliary_bus 75 76 backlight/lp855x-driver.rst 76 77 connector 77 78 console
+3
drivers/base/Kconfig
··· 1 1 # SPDX-License-Identifier: GPL-2.0 2 2 menu "Generic Driver Options" 3 3 4 + config AUXILIARY_BUS 5 + bool 6 + 4 7 config UEVENT_HELPER 5 8 bool "Support for uevent helper" 6 9 help
+1
drivers/base/Makefile
··· 7 7 attribute_container.o transport_class.o \ 8 8 topology.o container.o property.o cacheinfo.o \ 9 9 swnode.o 10 + obj-$(CONFIG_AUXILIARY_BUS) += auxiliary.o 10 11 obj-$(CONFIG_DEVTMPFS) += devtmpfs.o 11 12 obj-y += power/ 12 13 obj-$(CONFIG_ISA_BUS_API) += isa.o
+268
drivers/base/auxiliary.c
··· 1 + // SPDX-License-Identifier: GPL-2.0-only 2 + /* 3 + * Copyright (c) 2019-2020 Intel Corporation 4 + * 5 + * Please see Documentation/driver-api/auxiliary_bus.rst for more information. 6 + */ 7 + 8 + #define pr_fmt(fmt) "%s:%s: " fmt, KBUILD_MODNAME, __func__ 9 + 10 + #include <linux/device.h> 11 + #include <linux/init.h> 12 + #include <linux/module.h> 13 + #include <linux/pm_domain.h> 14 + #include <linux/pm_runtime.h> 15 + #include <linux/string.h> 16 + #include <linux/auxiliary_bus.h> 17 + 18 + static const struct auxiliary_device_id *auxiliary_match_id(const struct auxiliary_device_id *id, 19 + const struct auxiliary_device *auxdev) 20 + { 21 + for (; id->name[0]; id++) { 22 + const char *p = strrchr(dev_name(&auxdev->dev), '.'); 23 + int match_size; 24 + 25 + if (!p) 26 + continue; 27 + match_size = p - dev_name(&auxdev->dev); 28 + 29 + /* use dev_name(&auxdev->dev) prefix before last '.' char to match to */ 30 + if (strlen(id->name) == match_size && 31 + !strncmp(dev_name(&auxdev->dev), id->name, match_size)) 32 + return id; 33 + } 34 + return NULL; 35 + } 36 + 37 + static int auxiliary_match(struct device *dev, struct device_driver *drv) 38 + { 39 + struct auxiliary_device *auxdev = to_auxiliary_dev(dev); 40 + struct auxiliary_driver *auxdrv = to_auxiliary_drv(drv); 41 + 42 + return !!auxiliary_match_id(auxdrv->id_table, auxdev); 43 + } 44 + 45 + static int auxiliary_uevent(struct device *dev, struct kobj_uevent_env *env) 46 + { 47 + const char *name, *p; 48 + 49 + name = dev_name(dev); 50 + p = strrchr(name, '.'); 51 + 52 + return add_uevent_var(env, "MODALIAS=%s%.*s", AUXILIARY_MODULE_PREFIX, (int)(p - name), 53 + name); 54 + } 55 + 56 + static const struct dev_pm_ops auxiliary_dev_pm_ops = { 57 + SET_RUNTIME_PM_OPS(pm_generic_runtime_suspend, pm_generic_runtime_resume, NULL) 58 + SET_SYSTEM_SLEEP_PM_OPS(pm_generic_suspend, pm_generic_resume) 59 + }; 60 + 61 + static int auxiliary_bus_probe(struct device *dev) 62 + { 63 + struct auxiliary_driver *auxdrv = to_auxiliary_drv(dev->driver); 64 + struct auxiliary_device *auxdev = to_auxiliary_dev(dev); 65 + int ret; 66 + 67 + ret = dev_pm_domain_attach(dev, true); 68 + if (ret) { 69 + dev_warn(dev, "Failed to attach to PM Domain : %d\n", ret); 70 + return ret; 71 + } 72 + 73 + ret = auxdrv->probe(auxdev, auxiliary_match_id(auxdrv->id_table, auxdev)); 74 + if (ret) 75 + dev_pm_domain_detach(dev, true); 76 + 77 + return ret; 78 + } 79 + 80 + static int auxiliary_bus_remove(struct device *dev) 81 + { 82 + struct auxiliary_driver *auxdrv = to_auxiliary_drv(dev->driver); 83 + struct auxiliary_device *auxdev = to_auxiliary_dev(dev); 84 + int ret = 0; 85 + 86 + if (auxdrv->remove) 87 + ret = auxdrv->remove(auxdev); 88 + dev_pm_domain_detach(dev, true); 89 + 90 + return ret; 91 + } 92 + 93 + static void auxiliary_bus_shutdown(struct device *dev) 94 + { 95 + struct auxiliary_driver *auxdrv = to_auxiliary_drv(dev->driver); 96 + struct auxiliary_device *auxdev = to_auxiliary_dev(dev); 97 + 98 + if (auxdrv->shutdown) 99 + auxdrv->shutdown(auxdev); 100 + } 101 + 102 + static struct bus_type auxiliary_bus_type = { 103 + .name = "auxiliary", 104 + .probe = auxiliary_bus_probe, 105 + .remove = auxiliary_bus_remove, 106 + .shutdown = auxiliary_bus_shutdown, 107 + .match = auxiliary_match, 108 + .uevent = auxiliary_uevent, 109 + .pm = &auxiliary_dev_pm_ops, 110 + }; 111 + 112 + /** 113 + * auxiliary_device_init - check auxiliary_device and initialize 114 + * @auxdev: auxiliary device struct 115 + * 116 + * This is the first step in the two-step process to register an auxiliary_device. 117 + * 118 + * When this function returns an error code, then the device_initialize will *not* have 119 + * been performed, and the caller will be responsible to free any memory allocated for the 120 + * auxiliary_device in the error path directly. 121 + * 122 + * It returns 0 on success. On success, the device_initialize has been performed. After this 123 + * point any error unwinding will need to include a call to auxiliary_device_uninit(). 124 + * In this post-initialize error scenario, a call to the device's .release callback will be 125 + * triggered, and all memory clean-up is expected to be handled there. 126 + */ 127 + int auxiliary_device_init(struct auxiliary_device *auxdev) 128 + { 129 + struct device *dev = &auxdev->dev; 130 + 131 + if (!dev->parent) { 132 + pr_err("auxiliary_device has a NULL dev->parent\n"); 133 + return -EINVAL; 134 + } 135 + 136 + if (!auxdev->name) { 137 + pr_err("auxiliary_device has a NULL name\n"); 138 + return -EINVAL; 139 + } 140 + 141 + dev->bus = &auxiliary_bus_type; 142 + device_initialize(&auxdev->dev); 143 + return 0; 144 + } 145 + EXPORT_SYMBOL_GPL(auxiliary_device_init); 146 + 147 + /** 148 + * __auxiliary_device_add - add an auxiliary bus device 149 + * @auxdev: auxiliary bus device to add to the bus 150 + * @modname: name of the parent device's driver module 151 + * 152 + * This is the second step in the two-step process to register an auxiliary_device. 153 + * 154 + * This function must be called after a successful call to auxiliary_device_init(), which 155 + * will perform the device_initialize. This means that if this returns an error code, then a 156 + * call to auxiliary_device_uninit() must be performed so that the .release callback will 157 + * be triggered to free the memory associated with the auxiliary_device. 158 + * 159 + * The expectation is that users will call the "auxiliary_device_add" macro so that the caller's 160 + * KBUILD_MODNAME is automatically inserted for the modname parameter. Only if a user requires 161 + * a custom name would this version be called directly. 162 + */ 163 + int __auxiliary_device_add(struct auxiliary_device *auxdev, const char *modname) 164 + { 165 + struct device *dev = &auxdev->dev; 166 + int ret; 167 + 168 + if (!modname) { 169 + pr_err("auxiliary device modname is NULL\n"); 170 + return -EINVAL; 171 + } 172 + 173 + ret = dev_set_name(dev, "%s.%s.%d", modname, auxdev->name, auxdev->id); 174 + if (ret) { 175 + pr_err("auxiliary device dev_set_name failed: %d\n", ret); 176 + return ret; 177 + } 178 + 179 + ret = device_add(dev); 180 + if (ret) 181 + dev_err(dev, "adding auxiliary device failed!: %d\n", ret); 182 + 183 + return ret; 184 + } 185 + EXPORT_SYMBOL_GPL(__auxiliary_device_add); 186 + 187 + /** 188 + * auxiliary_find_device - auxiliary device iterator for locating a particular device. 189 + * @start: Device to begin with 190 + * @data: Data to pass to match function 191 + * @match: Callback function to check device 192 + * 193 + * This function returns a reference to a device that is 'found' 194 + * for later use, as determined by the @match callback. 195 + * 196 + * The callback should return 0 if the device doesn't match and non-zero 197 + * if it does. If the callback returns non-zero, this function will 198 + * return to the caller and not iterate over any more devices. 199 + */ 200 + struct auxiliary_device * 201 + auxiliary_find_device(struct device *start, const void *data, 202 + int (*match)(struct device *dev, const void *data)) 203 + { 204 + struct device *dev; 205 + 206 + dev = bus_find_device(&auxiliary_bus_type, start, data, match); 207 + if (!dev) 208 + return NULL; 209 + 210 + return to_auxiliary_dev(dev); 211 + } 212 + EXPORT_SYMBOL_GPL(auxiliary_find_device); 213 + 214 + /** 215 + * __auxiliary_driver_register - register a driver for auxiliary bus devices 216 + * @auxdrv: auxiliary_driver structure 217 + * @owner: owning module/driver 218 + * @modname: KBUILD_MODNAME for parent driver 219 + */ 220 + int __auxiliary_driver_register(struct auxiliary_driver *auxdrv, struct module *owner, 221 + const char *modname) 222 + { 223 + if (WARN_ON(!auxdrv->probe) || WARN_ON(!auxdrv->id_table)) 224 + return -EINVAL; 225 + 226 + if (auxdrv->name) 227 + auxdrv->driver.name = kasprintf(GFP_KERNEL, "%s.%s", modname, auxdrv->name); 228 + else 229 + auxdrv->driver.name = kasprintf(GFP_KERNEL, "%s", modname); 230 + if (!auxdrv->driver.name) 231 + return -ENOMEM; 232 + 233 + auxdrv->driver.owner = owner; 234 + auxdrv->driver.bus = &auxiliary_bus_type; 235 + auxdrv->driver.mod_name = modname; 236 + 237 + return driver_register(&auxdrv->driver); 238 + } 239 + EXPORT_SYMBOL_GPL(__auxiliary_driver_register); 240 + 241 + /** 242 + * auxiliary_driver_unregister - unregister a driver 243 + * @auxdrv: auxiliary_driver structure 244 + */ 245 + void auxiliary_driver_unregister(struct auxiliary_driver *auxdrv) 246 + { 247 + driver_unregister(&auxdrv->driver); 248 + kfree(auxdrv->driver.name); 249 + } 250 + EXPORT_SYMBOL_GPL(auxiliary_driver_unregister); 251 + 252 + static int __init auxiliary_bus_init(void) 253 + { 254 + return bus_register(&auxiliary_bus_type); 255 + } 256 + 257 + static void __exit auxiliary_bus_exit(void) 258 + { 259 + bus_unregister(&auxiliary_bus_type); 260 + } 261 + 262 + module_init(auxiliary_bus_init); 263 + module_exit(auxiliary_bus_exit); 264 + 265 + MODULE_LICENSE("GPL v2"); 266 + MODULE_DESCRIPTION("Auxiliary Bus"); 267 + MODULE_AUTHOR("David Ertman <david.m.ertman@intel.com>"); 268 + MODULE_AUTHOR("Kiran Patil <kiran.patil@intel.com>");
+78
include/linux/auxiliary_bus.h
··· 1 + /* SPDX-License-Identifier: GPL-2.0-only */ 2 + /* 3 + * Copyright (c) 2019-2020 Intel Corporation 4 + * 5 + * Please see Documentation/driver-api/auxiliary_bus.rst for more information. 6 + */ 7 + 8 + #ifndef _AUXILIARY_BUS_H_ 9 + #define _AUXILIARY_BUS_H_ 10 + 11 + #include <linux/device.h> 12 + #include <linux/mod_devicetable.h> 13 + #include <linux/slab.h> 14 + 15 + struct auxiliary_device { 16 + struct device dev; 17 + const char *name; 18 + u32 id; 19 + }; 20 + 21 + struct auxiliary_driver { 22 + int (*probe)(struct auxiliary_device *auxdev, const struct auxiliary_device_id *id); 23 + int (*remove)(struct auxiliary_device *auxdev); 24 + void (*shutdown)(struct auxiliary_device *auxdev); 25 + int (*suspend)(struct auxiliary_device *auxdev, pm_message_t state); 26 + int (*resume)(struct auxiliary_device *auxdev); 27 + const char *name; 28 + struct device_driver driver; 29 + const struct auxiliary_device_id *id_table; 30 + }; 31 + 32 + static inline struct auxiliary_device *to_auxiliary_dev(struct device *dev) 33 + { 34 + return container_of(dev, struct auxiliary_device, dev); 35 + } 36 + 37 + static inline struct auxiliary_driver *to_auxiliary_drv(struct device_driver *drv) 38 + { 39 + return container_of(drv, struct auxiliary_driver, driver); 40 + } 41 + 42 + int auxiliary_device_init(struct auxiliary_device *auxdev); 43 + int __auxiliary_device_add(struct auxiliary_device *auxdev, const char *modname); 44 + #define auxiliary_device_add(auxdev) __auxiliary_device_add(auxdev, KBUILD_MODNAME) 45 + 46 + static inline void auxiliary_device_uninit(struct auxiliary_device *auxdev) 47 + { 48 + put_device(&auxdev->dev); 49 + } 50 + 51 + static inline void auxiliary_device_delete(struct auxiliary_device *auxdev) 52 + { 53 + device_del(&auxdev->dev); 54 + } 55 + 56 + int __auxiliary_driver_register(struct auxiliary_driver *auxdrv, struct module *owner, 57 + const char *modname); 58 + #define auxiliary_driver_register(auxdrv) \ 59 + __auxiliary_driver_register(auxdrv, THIS_MODULE, KBUILD_MODNAME) 60 + 61 + void auxiliary_driver_unregister(struct auxiliary_driver *auxdrv); 62 + 63 + /** 64 + * module_auxiliary_driver() - Helper macro for registering an auxiliary driver 65 + * @__auxiliary_driver: auxiliary driver struct 66 + * 67 + * Helper macro for auxiliary drivers which do not do anything special in 68 + * module init/exit. This eliminates a lot of boilerplate. Each module may only 69 + * use this macro once, and calling it replaces module_init() and module_exit() 70 + */ 71 + #define module_auxiliary_driver(__auxiliary_driver) \ 72 + module_driver(__auxiliary_driver, auxiliary_driver_register, auxiliary_driver_unregister) 73 + 74 + struct auxiliary_device * 75 + auxiliary_find_device(struct device *start, const void *data, 76 + int (*match)(struct device *dev, const void *data)); 77 + 78 + #endif /* _AUXILIARY_BUS_H_ */
+8
include/linux/mod_devicetable.h
··· 838 838 kernel_ulong_t driver_data; 839 839 }; 840 840 841 + #define AUXILIARY_NAME_SIZE 32 842 + #define AUXILIARY_MODULE_PREFIX "auxiliary:" 843 + 844 + struct auxiliary_device_id { 845 + char name[AUXILIARY_NAME_SIZE]; 846 + kernel_ulong_t driver_data; 847 + }; 848 + 841 849 #endif /* LINUX_MOD_DEVICETABLE_H */
+3
scripts/mod/devicetable-offsets.c
··· 243 243 DEVID(mhi_device_id); 244 244 DEVID_FIELD(mhi_device_id, chan); 245 245 246 + DEVID(auxiliary_device_id); 247 + DEVID_FIELD(auxiliary_device_id, name); 248 + 246 249 return 0; 247 250 }
+8
scripts/mod/file2alias.c
··· 1364 1364 { 1365 1365 DEF_FIELD_ADDR(symval, mhi_device_id, chan); 1366 1366 sprintf(alias, MHI_DEVICE_MODALIAS_FMT, *chan); 1367 + return 1; 1368 + } 1369 + 1370 + static int do_auxiliary_entry(const char *filename, void *symval, char *alias) 1371 + { 1372 + DEF_FIELD_ADDR(symval, auxiliary_device_id, name); 1373 + sprintf(alias, AUXILIARY_MODULE_PREFIX "%s", *name); 1367 1374 1368 1375 return 1; 1369 1376 } ··· 1449 1442 {"tee", SIZE_tee_client_device_id, do_tee_entry}, 1450 1443 {"wmi", SIZE_wmi_device_id, do_wmi_entry}, 1451 1444 {"mhi", SIZE_mhi_device_id, do_mhi_entry}, 1445 + {"auxiliary", SIZE_auxiliary_device_id, do_auxiliary_entry}, 1452 1446 }; 1453 1447 1454 1448 /* Create MODULE_ALIAS() statements.