Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * soundbus
0004  *
0005  * Copyright 2006 Johannes Berg <johannes@sipsolutions.net>
0006  */
0007 
0008 #include <linux/module.h>
0009 #include "soundbus.h"
0010 
0011 MODULE_AUTHOR("Johannes Berg <johannes@sipsolutions.net>");
0012 MODULE_LICENSE("GPL");
0013 MODULE_DESCRIPTION("Apple Soundbus");
0014 
0015 struct soundbus_dev *soundbus_dev_get(struct soundbus_dev *dev)
0016 {
0017     struct device *tmp;
0018 
0019     if (!dev)
0020         return NULL;
0021     tmp = get_device(&dev->ofdev.dev);
0022     if (tmp)
0023         return to_soundbus_device(tmp);
0024     else
0025         return NULL;
0026 }
0027 EXPORT_SYMBOL_GPL(soundbus_dev_get);
0028 
0029 void soundbus_dev_put(struct soundbus_dev *dev)
0030 {
0031     if (dev)
0032         put_device(&dev->ofdev.dev);
0033 }
0034 EXPORT_SYMBOL_GPL(soundbus_dev_put);
0035 
0036 static int soundbus_probe(struct device *dev)
0037 {
0038     int error = -ENODEV;
0039     struct soundbus_driver *drv;
0040     struct soundbus_dev *soundbus_dev;
0041 
0042     drv = to_soundbus_driver(dev->driver);
0043     soundbus_dev = to_soundbus_device(dev);
0044 
0045     if (!drv->probe)
0046         return error;
0047 
0048     soundbus_dev_get(soundbus_dev);
0049 
0050     error = drv->probe(soundbus_dev);
0051     if (error)
0052         soundbus_dev_put(soundbus_dev);
0053 
0054     return error;
0055 }
0056 
0057 
0058 static int soundbus_uevent(struct device *dev, struct kobj_uevent_env *env)
0059 {
0060     struct soundbus_dev * soundbus_dev;
0061     struct platform_device * of;
0062     const char *compat;
0063     int retval = 0;
0064     int cplen, seen = 0;
0065 
0066     if (!dev)
0067         return -ENODEV;
0068 
0069     soundbus_dev = to_soundbus_device(dev);
0070     if (!soundbus_dev)
0071         return -ENODEV;
0072 
0073     of = &soundbus_dev->ofdev;
0074 
0075     /* stuff we want to pass to /sbin/hotplug */
0076     retval = add_uevent_var(env, "OF_NAME=%pOFn", of->dev.of_node);
0077     if (retval)
0078         return retval;
0079 
0080     retval = add_uevent_var(env, "OF_TYPE=%s", of_node_get_device_type(of->dev.of_node));
0081     if (retval)
0082         return retval;
0083 
0084     /* Since the compatible field can contain pretty much anything
0085      * it's not really legal to split it out with commas. We split it
0086      * up using a number of environment variables instead. */
0087 
0088     compat = of_get_property(of->dev.of_node, "compatible", &cplen);
0089     while (compat && cplen > 0) {
0090         int tmp = env->buflen;
0091         retval = add_uevent_var(env, "OF_COMPATIBLE_%d=%s", seen, compat);
0092         if (retval)
0093             return retval;
0094         compat += env->buflen - tmp;
0095         cplen -= env->buflen - tmp;
0096         seen += 1;
0097     }
0098 
0099     retval = add_uevent_var(env, "OF_COMPATIBLE_N=%d", seen);
0100     if (retval)
0101         return retval;
0102     retval = add_uevent_var(env, "MODALIAS=%s", soundbus_dev->modalias);
0103 
0104     return retval;
0105 }
0106 
0107 static void soundbus_device_remove(struct device *dev)
0108 {
0109     struct soundbus_dev * soundbus_dev = to_soundbus_device(dev);
0110     struct soundbus_driver * drv = to_soundbus_driver(dev->driver);
0111 
0112     if (dev->driver && drv->remove)
0113         drv->remove(soundbus_dev);
0114     soundbus_dev_put(soundbus_dev);
0115 }
0116 
0117 static void soundbus_device_shutdown(struct device *dev)
0118 {
0119     struct soundbus_dev * soundbus_dev = to_soundbus_device(dev);
0120     struct soundbus_driver * drv = to_soundbus_driver(dev->driver);
0121 
0122     if (dev->driver && drv->shutdown)
0123         drv->shutdown(soundbus_dev);
0124 }
0125 
0126 /* soundbus_dev_attrs is declared in sysfs.c */
0127 ATTRIBUTE_GROUPS(soundbus_dev);
0128 static struct bus_type soundbus_bus_type = {
0129     .name       = "aoa-soundbus",
0130     .probe      = soundbus_probe,
0131     .uevent     = soundbus_uevent,
0132     .remove     = soundbus_device_remove,
0133     .shutdown   = soundbus_device_shutdown,
0134     .dev_groups = soundbus_dev_groups,
0135 };
0136 
0137 int soundbus_add_one(struct soundbus_dev *dev)
0138 {
0139     static int devcount;
0140 
0141     /* sanity checks */
0142     if (!dev->attach_codec ||
0143         !dev->ofdev.dev.of_node ||
0144         dev->pcmname ||
0145         dev->pcmid != -1) {
0146         printk(KERN_ERR "soundbus: adding device failed sanity check!\n");
0147         return -EINVAL;
0148     }
0149 
0150     dev_set_name(&dev->ofdev.dev, "soundbus:%x", ++devcount);
0151     dev->ofdev.dev.bus = &soundbus_bus_type;
0152     return of_device_register(&dev->ofdev);
0153 }
0154 EXPORT_SYMBOL_GPL(soundbus_add_one);
0155 
0156 void soundbus_remove_one(struct soundbus_dev *dev)
0157 {
0158     of_device_unregister(&dev->ofdev);
0159 }
0160 EXPORT_SYMBOL_GPL(soundbus_remove_one);
0161 
0162 int soundbus_register_driver(struct soundbus_driver *drv)
0163 {
0164     /* initialize common driver fields */
0165     drv->driver.name = drv->name;
0166     drv->driver.bus = &soundbus_bus_type;
0167 
0168     /* register with core */
0169     return driver_register(&drv->driver);
0170 }
0171 EXPORT_SYMBOL_GPL(soundbus_register_driver);
0172 
0173 void soundbus_unregister_driver(struct soundbus_driver *drv)
0174 {
0175     driver_unregister(&drv->driver);
0176 }
0177 EXPORT_SYMBOL_GPL(soundbus_unregister_driver);
0178 
0179 static int __init soundbus_init(void)
0180 {
0181     return bus_register(&soundbus_bus_type);
0182 }
0183 
0184 static void __exit soundbus_exit(void)
0185 {
0186     bus_unregister(&soundbus_bus_type);
0187 }
0188 
0189 subsys_initcall(soundbus_init);
0190 module_exit(soundbus_exit);