1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22#include <linux/slab.h>
23#include <linux/time.h>
24#include <linux/export.h>
25#include <linux/errno.h>
26#include <sound/core.h>
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44int snd_device_new(struct snd_card *card, enum snd_device_type type,
45 void *device_data, struct snd_device_ops *ops)
46{
47 struct snd_device *dev;
48 struct list_head *p;
49
50 if (snd_BUG_ON(!card || !device_data || !ops))
51 return -ENXIO;
52 dev = kzalloc(sizeof(*dev), GFP_KERNEL);
53 if (!dev)
54 return -ENOMEM;
55 INIT_LIST_HEAD(&dev->list);
56 dev->card = card;
57 dev->type = type;
58 dev->state = SNDRV_DEV_BUILD;
59 dev->device_data = device_data;
60 dev->ops = ops;
61
62
63 list_for_each_prev(p, &card->devices) {
64 struct snd_device *pdev = list_entry(p, struct snd_device, list);
65 if ((unsigned int)pdev->type <= (unsigned int)type)
66 break;
67 }
68
69 list_add(&dev->list, p);
70 return 0;
71}
72EXPORT_SYMBOL(snd_device_new);
73
74static void __snd_device_disconnect(struct snd_device *dev)
75{
76 if (dev->state == SNDRV_DEV_REGISTERED) {
77 if (dev->ops->dev_disconnect &&
78 dev->ops->dev_disconnect(dev))
79 dev_err(dev->card->dev, "device disconnect failure\n");
80 dev->state = SNDRV_DEV_DISCONNECTED;
81 }
82}
83
84static void __snd_device_free(struct snd_device *dev)
85{
86
87 list_del(&dev->list);
88
89 __snd_device_disconnect(dev);
90 if (dev->ops->dev_free) {
91 if (dev->ops->dev_free(dev))
92 dev_err(dev->card->dev, "device free failure\n");
93 }
94 kfree(dev);
95}
96
97static struct snd_device *look_for_dev(struct snd_card *card, void *device_data)
98{
99 struct snd_device *dev;
100
101 list_for_each_entry(dev, &card->devices, list)
102 if (dev->device_data == device_data)
103 return dev;
104
105 return NULL;
106}
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121void snd_device_disconnect(struct snd_card *card, void *device_data)
122{
123 struct snd_device *dev;
124
125 if (snd_BUG_ON(!card || !device_data))
126 return;
127 dev = look_for_dev(card, device_data);
128 if (dev)
129 __snd_device_disconnect(dev);
130 else
131 dev_dbg(card->dev, "device disconnect %p (from %pF), not found\n",
132 device_data, __builtin_return_address(0));
133}
134EXPORT_SYMBOL_GPL(snd_device_disconnect);
135
136
137
138
139
140
141
142
143
144
145void snd_device_free(struct snd_card *card, void *device_data)
146{
147 struct snd_device *dev;
148
149 if (snd_BUG_ON(!card || !device_data))
150 return;
151 dev = look_for_dev(card, device_data);
152 if (dev)
153 __snd_device_free(dev);
154 else
155 dev_dbg(card->dev, "device free %p (from %pF), not found\n",
156 device_data, __builtin_return_address(0));
157}
158EXPORT_SYMBOL(snd_device_free);
159
160static int __snd_device_register(struct snd_device *dev)
161{
162 if (dev->state == SNDRV_DEV_BUILD) {
163 if (dev->ops->dev_register) {
164 int err = dev->ops->dev_register(dev);
165 if (err < 0)
166 return err;
167 }
168 dev->state = SNDRV_DEV_REGISTERED;
169 }
170 return 0;
171}
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186int snd_device_register(struct snd_card *card, void *device_data)
187{
188 struct snd_device *dev;
189
190 if (snd_BUG_ON(!card || !device_data))
191 return -ENXIO;
192 dev = look_for_dev(card, device_data);
193 if (dev)
194 return __snd_device_register(dev);
195 snd_BUG();
196 return -ENXIO;
197}
198EXPORT_SYMBOL(snd_device_register);
199
200
201
202
203
204int snd_device_register_all(struct snd_card *card)
205{
206 struct snd_device *dev;
207 int err;
208
209 if (snd_BUG_ON(!card))
210 return -ENXIO;
211 list_for_each_entry(dev, &card->devices, list) {
212 err = __snd_device_register(dev);
213 if (err < 0)
214 return err;
215 }
216 return 0;
217}
218
219
220
221
222
223void snd_device_disconnect_all(struct snd_card *card)
224{
225 struct snd_device *dev;
226
227 if (snd_BUG_ON(!card))
228 return;
229 list_for_each_entry_reverse(dev, &card->devices, list)
230 __snd_device_disconnect(dev);
231}
232
233
234
235
236
237void snd_device_free_all(struct snd_card *card)
238{
239 struct snd_device *dev, *next;
240
241 if (snd_BUG_ON(!card))
242 return;
243 list_for_each_entry_safe_reverse(dev, next, &card->devices, list)
244 __snd_device_free(dev);
245}
246