1 // SPDX-License-Identifier: GPL-2.0
3 * media.c - Media Controller specific ALSA driver code
5 * Copyright (c) 2019 Shuah Khan <shuah@kernel.org>
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.
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
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>
25 #include <sound/pcm.h>
26 #include <sound/core.h>
33 int snd_media_stream_init(struct snd_usb_substream
*subs
, struct snd_pcm
*pcm
,
36 struct media_device
*mdev
;
37 struct media_ctl
*mctl
;
38 struct device
*pcm_dev
= &pcm
->streams
[stream
].dev
;
42 struct media_entity
*entity
;
44 mdev
= subs
->stream
->chip
->media_dev
;
51 /* allocate media_ctl */
52 mctl
= kzalloc(sizeof(*mctl
), GFP_KERNEL
);
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
;
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
;
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
,
75 mctl
->intf_devnode
= media_devnode_create(mdev
, intf_type
, 0,
77 MINOR(pcm_dev
->devt
));
78 if (!mctl
->intf_devnode
) {
80 goto unregister_entity
;
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
) {
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
);
98 goto remove_intf_link
;
103 subs
->media_ctl
= mctl
;
107 media_remove_intf_link(mctl
->intf_link
);
109 media_devnode_remove(mctl
->intf_devnode
);
111 media_device_unregister_entity(&mctl
->media_entity
);
117 void snd_media_stream_delete(struct snd_usb_substream
*subs
)
119 struct media_ctl
*mctl
= subs
->media_ctl
;
122 struct media_device
*mdev
;
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
);
131 subs
->media_ctl
= NULL
;
135 int snd_media_start_pipeline(struct snd_usb_substream
*subs
)
137 struct media_ctl
*mctl
= subs
->media_ctl
;
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
,
147 mutex_unlock(&mctl
->media_dev
->graph_mutex
);
151 void snd_media_stop_pipeline(struct snd_usb_substream
*subs
)
153 struct media_ctl
*mctl
= subs
->media_ctl
;
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
);
164 static int snd_media_mixer_init(struct snd_usb_audio
*chip
)
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
;
177 ctl_intf
= chip
->ctl_intf_media_devnode
;
179 ctl_intf
= media_devnode_create(mdev
, intf_type
, 0,
180 MAJOR(ctl_dev
->devt
),
181 MINOR(ctl_dev
->devt
));
184 chip
->ctl_intf_media_devnode
= ctl_intf
;
187 list_for_each_entry(mixer
, &chip
->mixer_list
, list
) {
189 if (mixer
->media_mixer_ctl
)
192 /* allocate media_mixer_ctl */
193 mctl
= kzalloc(sizeof(*mctl
), GFP_KERNEL
);
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
,
205 ret
= media_device_register_entity(mctl
->media_dev
,
206 &mctl
->media_entity
);
212 mctl
->intf_link
= media_create_intf_link(&mctl
->media_entity
,
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
);
221 mctl
->intf_devnode
= ctl_intf
;
222 mixer
->media_mixer_ctl
= mctl
;
227 static void snd_media_mixer_delete(struct snd_usb_audio
*chip
)
229 struct usb_mixer_interface
*mixer
;
230 struct media_device
*mdev
= chip
->media_dev
;
235 list_for_each_entry(mixer
, &chip
->mixer_list
, list
) {
236 struct media_mixer_ctl
*mctl
;
238 mctl
= mixer
->media_mixer_ctl
;
239 if (!mixer
->media_mixer_ctl
)
242 if (media_devnode_is_registered(mdev
->devnode
)) {
243 media_device_unregister_entity(&mctl
->media_entity
);
244 media_entity_cleanup(&mctl
->media_entity
);
247 mixer
->media_mixer_ctl
= NULL
;
249 if (media_devnode_is_registered(mdev
->devnode
))
250 media_devnode_remove(chip
->ctl_intf_media_devnode
);
251 chip
->ctl_intf_media_devnode
= NULL
;
254 int snd_media_device_create(struct snd_usb_audio
*chip
,
255 struct usb_interface
*iface
)
257 struct media_device
*mdev
;
258 struct usb_device
*usbdev
= interface_to_usbdev(iface
);
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.
266 if (chip
->media_dev
) {
267 mdev
= chip
->media_dev
;
271 mdev
= media_device_usb_allocate(usbdev
, KBUILD_MODNAME
, THIS_MODULE
);
275 /* save media device - avoid lookups */
276 chip
->media_dev
= mdev
;
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 */
283 dev_err(&usbdev
->dev
,
284 "Couldn't create media mixer entities. Error: %d\n",
287 if (!media_devnode_is_registered(mdev
->devnode
)) {
288 /* dont'register if snd_media_mixer_init() failed */
292 /* register media_device */
293 ret
= media_device_register(mdev
);
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",
310 void snd_media_device_delete(struct snd_usb_audio
*chip
)
312 struct media_device
*mdev
= chip
->media_dev
;
313 struct snd_usb_stream
*stream
;
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]);
321 snd_media_mixer_delete(chip
);
324 media_device_delete(mdev
, KBUILD_MODNAME
, THIS_MODULE
);
325 chip
->media_dev
= NULL
;