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