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