linux/sound/aoa/soundbus/core.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0-only
   2/*
   3 * soundbus
   4 *
   5 * Copyright 2006 Johannes Berg <johannes@sipsolutions.net>
   6 */
   7
   8#include <linux/module.h>
   9#include "soundbus.h"
  10
  11MODULE_AUTHOR("Johannes Berg <johannes@sipsolutions.net>");
  12MODULE_LICENSE("GPL");
  13MODULE_DESCRIPTION("Apple Soundbus");
  14
  15struct soundbus_dev *soundbus_dev_get(struct soundbus_dev *dev)
  16{
  17        struct device *tmp;
  18
  19        if (!dev)
  20                return NULL;
  21        tmp = get_device(&dev->ofdev.dev);
  22        if (tmp)
  23                return to_soundbus_device(tmp);
  24        else
  25                return NULL;
  26}
  27EXPORT_SYMBOL_GPL(soundbus_dev_get);
  28
  29void soundbus_dev_put(struct soundbus_dev *dev)
  30{
  31        if (dev)
  32                put_device(&dev->ofdev.dev);
  33}
  34EXPORT_SYMBOL_GPL(soundbus_dev_put);
  35
  36static int soundbus_probe(struct device *dev)
  37{
  38        int error = -ENODEV;
  39        struct soundbus_driver *drv;
  40        struct soundbus_dev *soundbus_dev;
  41
  42        drv = to_soundbus_driver(dev->driver);
  43        soundbus_dev = to_soundbus_device(dev);
  44
  45        if (!drv->probe)
  46                return error;
  47
  48        soundbus_dev_get(soundbus_dev);
  49
  50        error = drv->probe(soundbus_dev);
  51        if (error)
  52                soundbus_dev_put(soundbus_dev);
  53
  54        return error;
  55}
  56
  57
  58static int soundbus_uevent(struct device *dev, struct kobj_uevent_env *env)
  59{
  60        struct soundbus_dev * soundbus_dev;
  61        struct platform_device * of;
  62        const char *compat;
  63        int retval = 0;
  64        int cplen, seen = 0;
  65
  66        if (!dev)
  67                return -ENODEV;
  68
  69        soundbus_dev = to_soundbus_device(dev);
  70        if (!soundbus_dev)
  71                return -ENODEV;
  72
  73        of = &soundbus_dev->ofdev;
  74
  75        /* stuff we want to pass to /sbin/hotplug */
  76        retval = add_uevent_var(env, "OF_NAME=%pOFn", of->dev.of_node);
  77        if (retval)
  78                return retval;
  79
  80        retval = add_uevent_var(env, "OF_TYPE=%s", of_node_get_device_type(of->dev.of_node));
  81        if (retval)
  82                return retval;
  83
  84        /* Since the compatible field can contain pretty much anything
  85         * it's not really legal to split it out with commas. We split it
  86         * up using a number of environment variables instead. */
  87
  88        compat = of_get_property(of->dev.of_node, "compatible", &cplen);
  89        while (compat && cplen > 0) {
  90                int tmp = env->buflen;
  91                retval = add_uevent_var(env, "OF_COMPATIBLE_%d=%s", seen, compat);
  92                if (retval)
  93                        return retval;
  94                compat += env->buflen - tmp;
  95                cplen -= env->buflen - tmp;
  96                seen += 1;
  97        }
  98
  99        retval = add_uevent_var(env, "OF_COMPATIBLE_N=%d", seen);
 100        if (retval)
 101                return retval;
 102        retval = add_uevent_var(env, "MODALIAS=%s", soundbus_dev->modalias);
 103
 104        return retval;
 105}
 106
 107static void soundbus_device_remove(struct device *dev)
 108{
 109        struct soundbus_dev * soundbus_dev = to_soundbus_device(dev);
 110        struct soundbus_driver * drv = to_soundbus_driver(dev->driver);
 111
 112        if (dev->driver && drv->remove)
 113                drv->remove(soundbus_dev);
 114        soundbus_dev_put(soundbus_dev);
 115}
 116
 117static void soundbus_device_shutdown(struct device *dev)
 118{
 119        struct soundbus_dev * soundbus_dev = to_soundbus_device(dev);
 120        struct soundbus_driver * drv = to_soundbus_driver(dev->driver);
 121
 122        if (dev->driver && drv->shutdown)
 123                drv->shutdown(soundbus_dev);
 124}
 125
 126/* soundbus_dev_attrs is declared in sysfs.c */
 127ATTRIBUTE_GROUPS(soundbus_dev);
 128static struct bus_type soundbus_bus_type = {
 129        .name           = "aoa-soundbus",
 130        .probe          = soundbus_probe,
 131        .uevent         = soundbus_uevent,
 132        .remove         = soundbus_device_remove,
 133        .shutdown       = soundbus_device_shutdown,
 134        .dev_groups     = soundbus_dev_groups,
 135};
 136
 137int soundbus_add_one(struct soundbus_dev *dev)
 138{
 139        static int devcount;
 140
 141        /* sanity checks */
 142        if (!dev->attach_codec ||
 143            !dev->ofdev.dev.of_node ||
 144            dev->pcmname ||
 145            dev->pcmid != -1) {
 146                printk(KERN_ERR "soundbus: adding device failed sanity check!\n");
 147                return -EINVAL;
 148        }
 149
 150        dev_set_name(&dev->ofdev.dev, "soundbus:%x", ++devcount);
 151        dev->ofdev.dev.bus = &soundbus_bus_type;
 152        return of_device_register(&dev->ofdev);
 153}
 154EXPORT_SYMBOL_GPL(soundbus_add_one);
 155
 156void soundbus_remove_one(struct soundbus_dev *dev)
 157{
 158        of_device_unregister(&dev->ofdev);
 159}
 160EXPORT_SYMBOL_GPL(soundbus_remove_one);
 161
 162int soundbus_register_driver(struct soundbus_driver *drv)
 163{
 164        /* initialize common driver fields */
 165        drv->driver.name = drv->name;
 166        drv->driver.bus = &soundbus_bus_type;
 167
 168        /* register with core */
 169        return driver_register(&drv->driver);
 170}
 171EXPORT_SYMBOL_GPL(soundbus_register_driver);
 172
 173void soundbus_unregister_driver(struct soundbus_driver *drv)
 174{
 175        driver_unregister(&drv->driver);
 176}
 177EXPORT_SYMBOL_GPL(soundbus_unregister_driver);
 178
 179static int __init soundbus_init(void)
 180{
 181        return bus_register(&soundbus_bus_type);
 182}
 183
 184static void __exit soundbus_exit(void)
 185{
 186        bus_unregister(&soundbus_bus_type);
 187}
 188
 189subsys_initcall(soundbus_init);
 190module_exit(soundbus_exit);
 191