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
;