Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/sound/usb/media.c
26378 views
1
// SPDX-License-Identifier: GPL-2.0
2
/*
3
* media.c - Media Controller specific ALSA driver code
4
*
5
* Copyright (c) 2019 Shuah Khan <[email protected]>
6
*
7
*/
8
9
/*
10
* This file adds Media Controller support to the ALSA driver
11
* to use the Media Controller API to share the tuner with DVB
12
* and V4L2 drivers that control the media device.
13
*
14
* The media device is created based on the existing quirks framework.
15
* Using this approach, the media controller API usage can be added for
16
* a specific device.
17
*/
18
19
#include <linux/init.h>
20
#include <linux/list.h>
21
#include <linux/mutex.h>
22
#include <linux/slab.h>
23
#include <linux/usb.h>
24
25
#include <sound/pcm.h>
26
#include <sound/core.h>
27
28
#include "usbaudio.h"
29
#include "card.h"
30
#include "mixer.h"
31
#include "media.h"
32
33
int snd_media_stream_init(struct snd_usb_substream *subs, struct snd_pcm *pcm,
34
int stream)
35
{
36
struct media_device *mdev;
37
struct media_ctl *mctl;
38
struct device *pcm_dev = pcm->streams[stream].dev;
39
u32 intf_type;
40
int ret = 0;
41
u16 mixer_pad;
42
struct media_entity *entity;
43
44
mdev = subs->stream->chip->media_dev;
45
if (!mdev)
46
return 0;
47
48
if (subs->media_ctl)
49
return 0;
50
51
/* allocate media_ctl */
52
mctl = kzalloc(sizeof(*mctl), GFP_KERNEL);
53
if (!mctl)
54
return -ENOMEM;
55
56
mctl->media_dev = mdev;
57
if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
58
intf_type = MEDIA_INTF_T_ALSA_PCM_PLAYBACK;
59
mctl->media_entity.function = MEDIA_ENT_F_AUDIO_PLAYBACK;
60
mctl->media_pad.flags = MEDIA_PAD_FL_SOURCE;
61
mixer_pad = 1;
62
} else {
63
intf_type = MEDIA_INTF_T_ALSA_PCM_CAPTURE;
64
mctl->media_entity.function = MEDIA_ENT_F_AUDIO_CAPTURE;
65
mctl->media_pad.flags = MEDIA_PAD_FL_SINK;
66
mixer_pad = 2;
67
}
68
mctl->media_entity.name = pcm->name;
69
media_entity_pads_init(&mctl->media_entity, 1, &mctl->media_pad);
70
ret = media_device_register_entity(mctl->media_dev,
71
&mctl->media_entity);
72
if (ret)
73
goto free_mctl;
74
75
mctl->intf_devnode = media_devnode_create(mdev, intf_type, 0,
76
MAJOR(pcm_dev->devt),
77
MINOR(pcm_dev->devt));
78
if (!mctl->intf_devnode) {
79
ret = -ENOMEM;
80
goto unregister_entity;
81
}
82
mctl->intf_link = media_create_intf_link(&mctl->media_entity,
83
&mctl->intf_devnode->intf,
84
MEDIA_LNK_FL_ENABLED);
85
if (!mctl->intf_link) {
86
ret = -ENOMEM;
87
goto devnode_remove;
88
}
89
90
/* create link between mixer and audio */
91
media_device_for_each_entity(entity, mdev) {
92
switch (entity->function) {
93
case MEDIA_ENT_F_AUDIO_MIXER:
94
ret = media_create_pad_link(entity, mixer_pad,
95
&mctl->media_entity, 0,
96
MEDIA_LNK_FL_ENABLED);
97
if (ret)
98
goto remove_intf_link;
99
break;
100
}
101
}
102
103
subs->media_ctl = mctl;
104
return 0;
105
106
remove_intf_link:
107
media_remove_intf_link(mctl->intf_link);
108
devnode_remove:
109
media_devnode_remove(mctl->intf_devnode);
110
unregister_entity:
111
media_device_unregister_entity(&mctl->media_entity);
112
free_mctl:
113
kfree(mctl);
114
return ret;
115
}
116
117
void snd_media_stream_delete(struct snd_usb_substream *subs)
118
{
119
struct media_ctl *mctl = subs->media_ctl;
120
121
if (mctl) {
122
struct media_device *mdev;
123
124
mdev = mctl->media_dev;
125
if (mdev && media_devnode_is_registered(mdev->devnode)) {
126
media_devnode_remove(mctl->intf_devnode);
127
media_device_unregister_entity(&mctl->media_entity);
128
media_entity_cleanup(&mctl->media_entity);
129
}
130
kfree(mctl);
131
subs->media_ctl = NULL;
132
}
133
}
134
135
int snd_media_start_pipeline(struct snd_usb_substream *subs)
136
{
137
struct media_ctl *mctl = subs->media_ctl;
138
int ret = 0;
139
140
if (!mctl)
141
return 0;
142
143
mutex_lock(&mctl->media_dev->graph_mutex);
144
if (mctl->media_dev->enable_source)
145
ret = mctl->media_dev->enable_source(&mctl->media_entity,
146
&mctl->media_pipe);
147
mutex_unlock(&mctl->media_dev->graph_mutex);
148
return ret;
149
}
150
151
void snd_media_stop_pipeline(struct snd_usb_substream *subs)
152
{
153
struct media_ctl *mctl = subs->media_ctl;
154
155
if (!mctl)
156
return;
157
158
mutex_lock(&mctl->media_dev->graph_mutex);
159
if (mctl->media_dev->disable_source)
160
mctl->media_dev->disable_source(&mctl->media_entity);
161
mutex_unlock(&mctl->media_dev->graph_mutex);
162
}
163
164
static int snd_media_mixer_init(struct snd_usb_audio *chip)
165
{
166
struct device *ctl_dev = chip->card->ctl_dev;
167
struct media_intf_devnode *ctl_intf;
168
struct usb_mixer_interface *mixer;
169
struct media_device *mdev = chip->media_dev;
170
struct media_mixer_ctl *mctl;
171
u32 intf_type = MEDIA_INTF_T_ALSA_CONTROL;
172
int ret;
173
174
if (!mdev)
175
return -ENODEV;
176
177
ctl_intf = chip->ctl_intf_media_devnode;
178
if (!ctl_intf) {
179
ctl_intf = media_devnode_create(mdev, intf_type, 0,
180
MAJOR(ctl_dev->devt),
181
MINOR(ctl_dev->devt));
182
if (!ctl_intf)
183
return -ENOMEM;
184
chip->ctl_intf_media_devnode = ctl_intf;
185
}
186
187
list_for_each_entry(mixer, &chip->mixer_list, list) {
188
189
if (mixer->media_mixer_ctl)
190
continue;
191
192
/* allocate media_mixer_ctl */
193
mctl = kzalloc(sizeof(*mctl), GFP_KERNEL);
194
if (!mctl)
195
return -ENOMEM;
196
197
mctl->media_dev = mdev;
198
mctl->media_entity.function = MEDIA_ENT_F_AUDIO_MIXER;
199
mctl->media_entity.name = chip->card->mixername;
200
mctl->media_pad[0].flags = MEDIA_PAD_FL_SINK;
201
mctl->media_pad[1].flags = MEDIA_PAD_FL_SOURCE;
202
mctl->media_pad[2].flags = MEDIA_PAD_FL_SOURCE;
203
media_entity_pads_init(&mctl->media_entity, MEDIA_MIXER_PAD_MAX,
204
mctl->media_pad);
205
ret = media_device_register_entity(mctl->media_dev,
206
&mctl->media_entity);
207
if (ret) {
208
kfree(mctl);
209
return ret;
210
}
211
212
mctl->intf_link = media_create_intf_link(&mctl->media_entity,
213
&ctl_intf->intf,
214
MEDIA_LNK_FL_ENABLED);
215
if (!mctl->intf_link) {
216
media_device_unregister_entity(&mctl->media_entity);
217
media_entity_cleanup(&mctl->media_entity);
218
kfree(mctl);
219
return -ENOMEM;
220
}
221
mctl->intf_devnode = ctl_intf;
222
mixer->media_mixer_ctl = mctl;
223
}
224
return 0;
225
}
226
227
static void snd_media_mixer_delete(struct snd_usb_audio *chip)
228
{
229
struct usb_mixer_interface *mixer;
230
struct media_device *mdev = chip->media_dev;
231
232
if (!mdev)
233
return;
234
235
list_for_each_entry(mixer, &chip->mixer_list, list) {
236
struct media_mixer_ctl *mctl;
237
238
mctl = mixer->media_mixer_ctl;
239
if (!mixer->media_mixer_ctl)
240
continue;
241
242
if (media_devnode_is_registered(mdev->devnode)) {
243
media_device_unregister_entity(&mctl->media_entity);
244
media_entity_cleanup(&mctl->media_entity);
245
}
246
kfree(mctl);
247
mixer->media_mixer_ctl = NULL;
248
}
249
if (media_devnode_is_registered(mdev->devnode))
250
media_devnode_remove(chip->ctl_intf_media_devnode);
251
chip->ctl_intf_media_devnode = NULL;
252
}
253
254
int snd_media_device_create(struct snd_usb_audio *chip,
255
struct usb_interface *iface)
256
{
257
struct media_device *mdev;
258
struct usb_device *usbdev = interface_to_usbdev(iface);
259
int ret = 0;
260
261
/* usb-audio driver is probed for each usb interface, and
262
* there are multiple interfaces per device. Avoid calling
263
* media_device_usb_allocate() each time usb_audio_probe()
264
* is called. Do it only once.
265
*/
266
if (chip->media_dev) {
267
mdev = chip->media_dev;
268
goto snd_mixer_init;
269
}
270
271
mdev = media_device_usb_allocate(usbdev, KBUILD_MODNAME, THIS_MODULE);
272
if (IS_ERR(mdev))
273
return -ENOMEM;
274
275
/* save media device - avoid lookups */
276
chip->media_dev = mdev;
277
278
snd_mixer_init:
279
/* Create media entities for mixer and control dev */
280
ret = snd_media_mixer_init(chip);
281
/* media_device might be registered, print error and continue */
282
if (ret)
283
dev_err(&usbdev->dev,
284
"Couldn't create media mixer entities. Error: %d\n",
285
ret);
286
287
if (!media_devnode_is_registered(mdev->devnode)) {
288
/* don't register if snd_media_mixer_init() failed */
289
if (ret)
290
goto create_fail;
291
292
/* register media_device */
293
ret = media_device_register(mdev);
294
create_fail:
295
if (ret) {
296
snd_media_mixer_delete(chip);
297
media_device_delete(mdev, KBUILD_MODNAME, THIS_MODULE);
298
/* clear saved media_dev */
299
chip->media_dev = NULL;
300
dev_err(&usbdev->dev,
301
"Couldn't register media device. Error: %d\n",
302
ret);
303
return ret;
304
}
305
}
306
307
return ret;
308
}
309
310
void snd_media_device_delete(struct snd_usb_audio *chip)
311
{
312
struct media_device *mdev = chip->media_dev;
313
struct snd_usb_stream *stream;
314
315
/* release resources */
316
list_for_each_entry(stream, &chip->pcm_list, list) {
317
snd_media_stream_delete(&stream->substream[0]);
318
snd_media_stream_delete(&stream->substream[1]);
319
}
320
321
snd_media_mixer_delete(chip);
322
323
if (mdev) {
324
media_device_delete(mdev, KBUILD_MODNAME, THIS_MODULE);
325
chip->media_dev = NULL;
326
}
327
}
328
329