Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
awilliam
GitHub Repository: awilliam/linux-vfio
Path: blob/master/sound/core/device.c
10814 views
1
/*
2
* Device management routines
3
* Copyright (c) by Jaroslav Kysela <[email protected]>
4
*
5
*
6
* This program is free software; you can redistribute it and/or modify
7
* it under the terms of the GNU General Public License as published by
8
* the Free Software Foundation; either version 2 of the License, or
9
* (at your option) any later version.
10
*
11
* This program is distributed in the hope that it will be useful,
12
* but WITHOUT ANY WARRANTY; without even the implied warranty of
13
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
* GNU General Public License for more details.
15
*
16
* You should have received a copy of the GNU General Public License
17
* along with this program; if not, write to the Free Software
18
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
19
*
20
*/
21
22
#include <linux/slab.h>
23
#include <linux/time.h>
24
#include <linux/errno.h>
25
#include <sound/core.h>
26
27
/**
28
* snd_device_new - create an ALSA device component
29
* @card: the card instance
30
* @type: the device type, SNDRV_DEV_XXX
31
* @device_data: the data pointer of this device
32
* @ops: the operator table
33
*
34
* Creates a new device component for the given data pointer.
35
* The device will be assigned to the card and managed together
36
* by the card.
37
*
38
* The data pointer plays a role as the identifier, too, so the
39
* pointer address must be unique and unchanged.
40
*
41
* Returns zero if successful, or a negative error code on failure.
42
*/
43
int snd_device_new(struct snd_card *card, snd_device_type_t type,
44
void *device_data, struct snd_device_ops *ops)
45
{
46
struct snd_device *dev;
47
48
if (snd_BUG_ON(!card || !device_data || !ops))
49
return -ENXIO;
50
dev = kzalloc(sizeof(*dev), GFP_KERNEL);
51
if (dev == NULL) {
52
snd_printk(KERN_ERR "Cannot allocate device\n");
53
return -ENOMEM;
54
}
55
dev->card = card;
56
dev->type = type;
57
dev->state = SNDRV_DEV_BUILD;
58
dev->device_data = device_data;
59
dev->ops = ops;
60
list_add(&dev->list, &card->devices); /* add to the head of list */
61
return 0;
62
}
63
64
EXPORT_SYMBOL(snd_device_new);
65
66
/**
67
* snd_device_free - release the device from the card
68
* @card: the card instance
69
* @device_data: the data pointer to release
70
*
71
* Removes the device from the list on the card and invokes the
72
* callbacks, dev_disconnect and dev_free, corresponding to the state.
73
* Then release the device.
74
*
75
* Returns zero if successful, or a negative error code on failure or if the
76
* device not found.
77
*/
78
int snd_device_free(struct snd_card *card, void *device_data)
79
{
80
struct snd_device *dev;
81
82
if (snd_BUG_ON(!card || !device_data))
83
return -ENXIO;
84
list_for_each_entry(dev, &card->devices, list) {
85
if (dev->device_data != device_data)
86
continue;
87
/* unlink */
88
list_del(&dev->list);
89
if (dev->state == SNDRV_DEV_REGISTERED &&
90
dev->ops->dev_disconnect)
91
if (dev->ops->dev_disconnect(dev))
92
snd_printk(KERN_ERR
93
"device disconnect failure\n");
94
if (dev->ops->dev_free) {
95
if (dev->ops->dev_free(dev))
96
snd_printk(KERN_ERR "device free failure\n");
97
}
98
kfree(dev);
99
return 0;
100
}
101
snd_printd("device free %p (from %pF), not found\n", device_data,
102
__builtin_return_address(0));
103
return -ENXIO;
104
}
105
106
EXPORT_SYMBOL(snd_device_free);
107
108
/**
109
* snd_device_disconnect - disconnect the device
110
* @card: the card instance
111
* @device_data: the data pointer to disconnect
112
*
113
* Turns the device into the disconnection state, invoking
114
* dev_disconnect callback, if the device was already registered.
115
*
116
* Usually called from snd_card_disconnect().
117
*
118
* Returns zero if successful, or a negative error code on failure or if the
119
* device not found.
120
*/
121
int 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 -ENXIO;
127
list_for_each_entry(dev, &card->devices, list) {
128
if (dev->device_data != device_data)
129
continue;
130
if (dev->state == SNDRV_DEV_REGISTERED &&
131
dev->ops->dev_disconnect) {
132
if (dev->ops->dev_disconnect(dev))
133
snd_printk(KERN_ERR "device disconnect failure\n");
134
dev->state = SNDRV_DEV_DISCONNECTED;
135
}
136
return 0;
137
}
138
snd_printd("device disconnect %p (from %pF), not found\n", device_data,
139
__builtin_return_address(0));
140
return -ENXIO;
141
}
142
143
/**
144
* snd_device_register - register the device
145
* @card: the card instance
146
* @device_data: the data pointer to register
147
*
148
* Registers the device which was already created via
149
* snd_device_new(). Usually this is called from snd_card_register(),
150
* but it can be called later if any new devices are created after
151
* invocation of snd_card_register().
152
*
153
* Returns zero if successful, or a negative error code on failure or if the
154
* device not found.
155
*/
156
int snd_device_register(struct snd_card *card, void *device_data)
157
{
158
struct snd_device *dev;
159
int err;
160
161
if (snd_BUG_ON(!card || !device_data))
162
return -ENXIO;
163
list_for_each_entry(dev, &card->devices, list) {
164
if (dev->device_data != device_data)
165
continue;
166
if (dev->state == SNDRV_DEV_BUILD && dev->ops->dev_register) {
167
if ((err = dev->ops->dev_register(dev)) < 0)
168
return err;
169
dev->state = SNDRV_DEV_REGISTERED;
170
return 0;
171
}
172
snd_printd("snd_device_register busy\n");
173
return -EBUSY;
174
}
175
snd_BUG();
176
return -ENXIO;
177
}
178
179
EXPORT_SYMBOL(snd_device_register);
180
181
/*
182
* register all the devices on the card.
183
* called from init.c
184
*/
185
int snd_device_register_all(struct snd_card *card)
186
{
187
struct snd_device *dev;
188
int err;
189
190
if (snd_BUG_ON(!card))
191
return -ENXIO;
192
list_for_each_entry(dev, &card->devices, list) {
193
if (dev->state == SNDRV_DEV_BUILD && dev->ops->dev_register) {
194
if ((err = dev->ops->dev_register(dev)) < 0)
195
return err;
196
dev->state = SNDRV_DEV_REGISTERED;
197
}
198
}
199
return 0;
200
}
201
202
/*
203
* disconnect all the devices on the card.
204
* called from init.c
205
*/
206
int snd_device_disconnect_all(struct snd_card *card)
207
{
208
struct snd_device *dev;
209
int err = 0;
210
211
if (snd_BUG_ON(!card))
212
return -ENXIO;
213
list_for_each_entry(dev, &card->devices, list) {
214
if (snd_device_disconnect(card, dev->device_data) < 0)
215
err = -ENXIO;
216
}
217
return err;
218
}
219
220
/*
221
* release all the devices on the card.
222
* called from init.c
223
*/
224
int snd_device_free_all(struct snd_card *card, snd_device_cmd_t cmd)
225
{
226
struct snd_device *dev;
227
int err;
228
unsigned int range_low, range_high, type;
229
230
if (snd_BUG_ON(!card))
231
return -ENXIO;
232
range_low = (__force unsigned int)cmd * SNDRV_DEV_TYPE_RANGE_SIZE;
233
range_high = range_low + SNDRV_DEV_TYPE_RANGE_SIZE - 1;
234
__again:
235
list_for_each_entry(dev, &card->devices, list) {
236
type = (__force unsigned int)dev->type;
237
if (type >= range_low && type <= range_high) {
238
if ((err = snd_device_free(card, dev->device_data)) < 0)
239
return err;
240
goto __again;
241
}
242
}
243
return 0;
244
}
245
246