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