xref: /openbmc/linux/sound/usb/media.c (revision a59511d1)
1 /*
2  * media.c - Media Controller specific ALSA driver code
3  *
4  * Copyright (c) 2016 Shuah Khan <shuahkh@osg.samsung.com>
5  * Copyright (c) 2016 Samsung Electronics Co., Ltd.
6  *
7  * This file is released under the GPLv2.
8  */
9 
10 /*
11  * This file adds Media Controller support to ALSA driver
12  * to use the Media Controller API to share tuner with DVB
13  * and V4L2 drivers that control media device. Media device
14  * is created based on existing quirks framework. Using this
15  * 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 static int media_snd_enable_source(struct media_ctl *mctl)
34 {
35 	if (mctl && mctl->media_dev->enable_source)
36 		return mctl->media_dev->enable_source(&mctl->media_entity,
37 						      &mctl->media_pipe);
38 	return 0;
39 }
40 
41 static void media_snd_disable_source(struct media_ctl *mctl)
42 {
43 	if (mctl && mctl->media_dev->disable_source)
44 		mctl->media_dev->disable_source(&mctl->media_entity);
45 }
46 
47 int media_snd_stream_init(struct snd_usb_substream *subs, struct snd_pcm *pcm,
48 			int stream)
49 {
50 	struct media_device *mdev;
51 	struct media_ctl *mctl;
52 	struct device *pcm_dev = &pcm->streams[stream].dev;
53 	u32 intf_type;
54 	int ret = 0;
55 	u16 mixer_pad;
56 	struct media_entity *entity;
57 
58 	mdev = subs->stream->chip->media_dev;
59 	if (!mdev)
60 		return -ENODEV;
61 
62 	if (subs->media_ctl)
63 		return 0;
64 
65 	/* allocate media_ctl */
66 	mctl = kzalloc(sizeof(*mctl), GFP_KERNEL);
67 	if (!mctl)
68 		return -ENOMEM;
69 
70 	mctl->media_dev = mdev;
71 	if (stream == SNDRV_PCM_STREAM_PLAYBACK) {
72 		intf_type = MEDIA_INTF_T_ALSA_PCM_PLAYBACK;
73 		mctl->media_entity.function = MEDIA_ENT_F_AUDIO_PLAYBACK;
74 		mctl->media_pad.flags = MEDIA_PAD_FL_SOURCE;
75 		mixer_pad = 1;
76 	} else {
77 		intf_type = MEDIA_INTF_T_ALSA_PCM_CAPTURE;
78 		mctl->media_entity.function = MEDIA_ENT_F_AUDIO_CAPTURE;
79 		mctl->media_pad.flags = MEDIA_PAD_FL_SINK;
80 		mixer_pad = 2;
81 	}
82 	mctl->media_entity.name = pcm->name;
83 	media_entity_pads_init(&mctl->media_entity, 1, &mctl->media_pad);
84 	ret =  media_device_register_entity(mctl->media_dev,
85 					    &mctl->media_entity);
86 	if (ret)
87 		goto free_mctl;
88 
89 	mctl->intf_devnode = media_devnode_create(mdev, intf_type, 0,
90 						  MAJOR(pcm_dev->devt),
91 						  MINOR(pcm_dev->devt));
92 	if (!mctl->intf_devnode) {
93 		ret = -ENOMEM;
94 		goto unregister_entity;
95 	}
96 	mctl->intf_link = media_create_intf_link(&mctl->media_entity,
97 						 &mctl->intf_devnode->intf,
98 						 MEDIA_LNK_FL_ENABLED);
99 	if (!mctl->intf_link) {
100 		ret = -ENOMEM;
101 		goto devnode_remove;
102 	}
103 
104 	/* create link between mixer and audio */
105 	media_device_for_each_entity(entity, mdev) {
106 		switch (entity->function) {
107 		case MEDIA_ENT_F_AUDIO_MIXER:
108 			ret = media_create_pad_link(entity, mixer_pad,
109 						    &mctl->media_entity, 0,
110 						    MEDIA_LNK_FL_ENABLED);
111 			if (ret)
112 				goto remove_intf_link;
113 			break;
114 		}
115 	}
116 
117 	subs->media_ctl = mctl;
118 	return 0;
119 
120 remove_intf_link:
121 	media_remove_intf_link(mctl->intf_link);
122 devnode_remove:
123 	media_devnode_remove(mctl->intf_devnode);
124 unregister_entity:
125 	media_device_unregister_entity(&mctl->media_entity);
126 free_mctl:
127 	kfree(mctl);
128 	return ret;
129 }
130 
131 void media_snd_stream_delete(struct snd_usb_substream *subs)
132 {
133 	struct media_ctl *mctl = subs->media_ctl;
134 
135 	if (mctl && mctl->media_dev) {
136 		struct media_device *mdev;
137 
138 		mdev = subs->stream->chip->media_dev;
139 		if (mdev && media_devnode_is_registered(&mdev->devnode)) {
140 			media_devnode_remove(mctl->intf_devnode);
141 			media_device_unregister_entity(&mctl->media_entity);
142 			media_entity_cleanup(&mctl->media_entity);
143 		}
144 		kfree(mctl);
145 		subs->media_ctl = NULL;
146 	}
147 }
148 
149 int media_snd_start_pipeline(struct snd_usb_substream *subs)
150 {
151 	struct media_ctl *mctl = subs->media_ctl;
152 
153 	if (mctl)
154 		return media_snd_enable_source(mctl);
155 	return 0;
156 }
157 
158 void media_snd_stop_pipeline(struct snd_usb_substream *subs)
159 {
160 	struct media_ctl *mctl = subs->media_ctl;
161 
162 	if (mctl)
163 		media_snd_disable_source(mctl);
164 }
165 
166 int media_snd_mixer_init(struct snd_usb_audio *chip)
167 {
168 	struct device *ctl_dev = &chip->card->ctl_dev;
169 	struct media_intf_devnode *ctl_intf;
170 	struct usb_mixer_interface *mixer;
171 	struct media_device *mdev = chip->media_dev;
172 	struct media_mixer_ctl *mctl;
173 	u32 intf_type = MEDIA_INTF_T_ALSA_CONTROL;
174 	int ret;
175 
176 	if (!mdev)
177 		return -ENODEV;
178 
179 	ctl_intf = chip->ctl_intf_media_devnode;
180 	if (!ctl_intf) {
181 		ctl_intf = media_devnode_create(mdev, intf_type, 0,
182 						MAJOR(ctl_dev->devt),
183 						MINOR(ctl_dev->devt));
184 		if (!ctl_intf)
185 			return -ENOMEM;
186 		chip->ctl_intf_media_devnode = ctl_intf;
187 	}
188 
189 	list_for_each_entry(mixer, &chip->mixer_list, list) {
190 
191 		if (mixer->media_mixer_ctl)
192 			continue;
193 
194 		/* allocate media_mixer_ctl */
195 		mctl = kzalloc(sizeof(*mctl), GFP_KERNEL);
196 		if (!mctl)
197 			return -ENOMEM;
198 
199 		mctl->media_dev = mdev;
200 		mctl->media_entity.function = MEDIA_ENT_F_AUDIO_MIXER;
201 		mctl->media_entity.name = chip->card->mixername;
202 		mctl->media_pad[0].flags = MEDIA_PAD_FL_SINK;
203 		mctl->media_pad[1].flags = MEDIA_PAD_FL_SOURCE;
204 		mctl->media_pad[2].flags = MEDIA_PAD_FL_SOURCE;
205 		media_entity_pads_init(&mctl->media_entity, MEDIA_MIXER_PAD_MAX,
206 				  mctl->media_pad);
207 		ret =  media_device_register_entity(mctl->media_dev,
208 						    &mctl->media_entity);
209 		if (ret) {
210 			kfree(mctl);
211 			return ret;
212 		}
213 
214 		mctl->intf_link = media_create_intf_link(&mctl->media_entity,
215 							 &ctl_intf->intf,
216 							 MEDIA_LNK_FL_ENABLED);
217 		if (!mctl->intf_link) {
218 			media_device_unregister_entity(&mctl->media_entity);
219 			media_entity_cleanup(&mctl->media_entity);
220 			kfree(mctl);
221 			return -ENOMEM;
222 		}
223 		mctl->intf_devnode = ctl_intf;
224 		mixer->media_mixer_ctl = mctl;
225 	}
226 	return 0;
227 }
228 
229 static void media_snd_mixer_delete(struct snd_usb_audio *chip)
230 {
231 	struct usb_mixer_interface *mixer;
232 	struct media_device *mdev = chip->media_dev;
233 
234 	if (!mdev)
235 		return;
236 
237 	list_for_each_entry(mixer, &chip->mixer_list, list) {
238 		struct media_mixer_ctl *mctl;
239 
240 		mctl = mixer->media_mixer_ctl;
241 		if (!mixer->media_mixer_ctl)
242 			continue;
243 
244 		if (media_devnode_is_registered(&mdev->devnode)) {
245 			media_device_unregister_entity(&mctl->media_entity);
246 			media_entity_cleanup(&mctl->media_entity);
247 		}
248 		kfree(mctl);
249 		mixer->media_mixer_ctl = NULL;
250 	}
251 	if (media_devnode_is_registered(&mdev->devnode))
252 		media_devnode_remove(chip->ctl_intf_media_devnode);
253 	chip->ctl_intf_media_devnode = NULL;
254 }
255 
256 int media_snd_device_create(struct snd_usb_audio *chip,
257 			struct usb_interface *iface)
258 {
259 	struct media_device *mdev;
260 	struct usb_device *usbdev = interface_to_usbdev(iface);
261 	int ret;
262 
263 	mdev = media_device_get_devres(&usbdev->dev);
264 	if (!mdev)
265 		return -ENOMEM;
266 	if (!mdev->dev) {
267 		/* register media device */
268 		mdev->dev = &usbdev->dev;
269 		if (usbdev->product)
270 			strlcpy(mdev->model, usbdev->product,
271 				sizeof(mdev->model));
272 		if (usbdev->serial)
273 			strlcpy(mdev->serial, usbdev->serial,
274 				sizeof(mdev->serial));
275 		strcpy(mdev->bus_info, usbdev->devpath);
276 		mdev->hw_revision = le16_to_cpu(usbdev->descriptor.bcdDevice);
277 		media_device_init(mdev);
278 	}
279 	if (!media_devnode_is_registered(&mdev->devnode)) {
280 		ret = media_device_register(mdev);
281 		if (ret) {
282 			dev_err(&usbdev->dev,
283 				"Couldn't register media device. Error: %d\n",
284 				ret);
285 			return ret;
286 		}
287 	}
288 
289 	/* save media device - avoid lookups */
290 	chip->media_dev = mdev;
291 
292 	/* Create media entities for mixer and control dev */
293 	ret = media_snd_mixer_init(chip);
294 	if (ret) {
295 		dev_err(&usbdev->dev,
296 			"Couldn't create media mixer entities. Error: %d\n",
297 			ret);
298 
299 		/* clear saved media_dev */
300 		chip->media_dev = NULL;
301 
302 		return ret;
303 	}
304 	return 0;
305 }
306 
307 void media_snd_device_delete(struct snd_usb_audio *chip)
308 {
309 	struct media_device *mdev = chip->media_dev;
310 
311 	media_snd_mixer_delete(chip);
312 
313 	if (mdev) {
314 		if (media_devnode_is_registered(&mdev->devnode))
315 			media_device_unregister(mdev);
316 		chip->media_dev = NULL;
317 	}
318 }
319