1// SPDX-License-Identifier: GPL-2.0
2/*
3 * media.c - Media Controller specific ALSA driver code
4 *
5 * Copyright (c) 2019 Shuah Khan <shuah@kernel.org>
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
33int 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
106remove_intf_link:
107	media_remove_intf_link(mctl->intf_link);
108devnode_remove:
109	media_devnode_remove(mctl->intf_devnode);
110unregister_entity:
111	media_device_unregister_entity(&mctl->media_entity);
112free_mctl:
113	kfree(mctl);
114	return ret;
115}
116
117void 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
135int 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
151void 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
164static 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
227static 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
254int 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
278snd_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);
294create_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
310void 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