2 * media.c - Media Controller specific ALSA driver code
4 * Copyright (c) 2016 Shuah Khan <shuahkh@osg.samsung.com>
5 * Copyright (c) 2016 Samsung Electronics Co., Ltd.
7 * This file is released under the GPLv2.
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
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 static int media_snd_enable_source(struct media_ctl *mctl)
35 if (mctl && mctl->media_dev->enable_source)
36 return mctl->media_dev->enable_source(&mctl->media_entity,
41 static void media_snd_disable_source(struct media_ctl *mctl)
43 if (mctl && mctl->media_dev->disable_source)
44 mctl->media_dev->disable_source(&mctl->media_entity);
47 int media_snd_stream_init(struct snd_usb_substream *subs, struct snd_pcm *pcm,
50 struct media_device *mdev;
51 struct media_ctl *mctl;
52 struct device *pcm_dev = &pcm->streams[stream].dev;
56 struct media_entity *entity;
58 mdev = subs->stream->chip->media_dev;
65 /* allocate media_ctl */
66 mctl = kzalloc(sizeof(*mctl), GFP_KERNEL);
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;
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;
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,
89 mctl->intf_devnode = media_devnode_create(mdev, intf_type, 0,
91 MINOR(pcm_dev->devt));
92 if (!mctl->intf_devnode) {
94 goto unregister_entity;
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) {
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);
112 goto remove_intf_link;
117 subs->media_ctl = mctl;
121 media_remove_intf_link(mctl->intf_link);
123 media_devnode_remove(mctl->intf_devnode);
125 media_device_unregister_entity(&mctl->media_entity);
131 void media_snd_stream_delete(struct snd_usb_substream *subs)
133 struct media_ctl *mctl = subs->media_ctl;
135 if (mctl && mctl->media_dev) {
136 struct media_device *mdev;
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);
145 subs->media_ctl = NULL;
149 int media_snd_start_pipeline(struct snd_usb_substream *subs)
151 struct media_ctl *mctl = subs->media_ctl;
154 return media_snd_enable_source(mctl);
158 void media_snd_stop_pipeline(struct snd_usb_substream *subs)
160 struct media_ctl *mctl = subs->media_ctl;
163 media_snd_disable_source(mctl);
166 int media_snd_mixer_init(struct snd_usb_audio *chip)
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;
179 ctl_intf = chip->ctl_intf_media_devnode;
181 ctl_intf = media_devnode_create(mdev, intf_type, 0,
182 MAJOR(ctl_dev->devt),
183 MINOR(ctl_dev->devt));
186 chip->ctl_intf_media_devnode = ctl_intf;
189 list_for_each_entry(mixer, &chip->mixer_list, list) {
191 if (mixer->media_mixer_ctl)
194 /* allocate media_mixer_ctl */
195 mctl = kzalloc(sizeof(*mctl), GFP_KERNEL);
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,
207 ret = media_device_register_entity(mctl->media_dev,
208 &mctl->media_entity);
214 mctl->intf_link = media_create_intf_link(&mctl->media_entity,
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);
223 mctl->intf_devnode = ctl_intf;
224 mixer->media_mixer_ctl = mctl;
229 static void media_snd_mixer_delete(struct snd_usb_audio *chip)
231 struct usb_mixer_interface *mixer;
232 struct media_device *mdev = chip->media_dev;
237 list_for_each_entry(mixer, &chip->mixer_list, list) {
238 struct media_mixer_ctl *mctl;
240 mctl = mixer->media_mixer_ctl;
241 if (!mixer->media_mixer_ctl)
244 if (media_devnode_is_registered(&mdev->devnode)) {
245 media_device_unregister_entity(&mctl->media_entity);
246 media_entity_cleanup(&mctl->media_entity);
249 mixer->media_mixer_ctl = NULL;
251 if (media_devnode_is_registered(&mdev->devnode))
252 media_devnode_remove(chip->ctl_intf_media_devnode);
253 chip->ctl_intf_media_devnode = NULL;
256 int media_snd_device_create(struct snd_usb_audio *chip,
257 struct usb_interface *iface)
259 struct media_device *mdev;
260 struct usb_device *usbdev = interface_to_usbdev(iface);
263 mdev = media_device_get_devres(&usbdev->dev);
267 /* register media device */
268 mdev->dev = &usbdev->dev;
270 strlcpy(mdev->model, usbdev->product,
271 sizeof(mdev->model));
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);
279 if (!media_devnode_is_registered(&mdev->devnode)) {
280 ret = media_device_register(mdev);
282 dev_err(&usbdev->dev,
283 "Couldn't register media device. Error: %d\n",
289 /* save media device - avoid lookups */
290 chip->media_dev = mdev;
292 /* Create media entities for mixer and control dev */
293 ret = media_snd_mixer_init(chip);
295 dev_err(&usbdev->dev,
296 "Couldn't create media mixer entities. Error: %d\n",
299 /* clear saved media_dev */
300 chip->media_dev = NULL;
307 void media_snd_device_delete(struct snd_usb_audio *chip)
309 struct media_device *mdev = chip->media_dev;
311 media_snd_mixer_delete(chip);
314 if (media_devnode_is_registered(&mdev->devnode))
315 media_device_unregister(mdev);
316 chip->media_dev = NULL;