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 /* don't 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;