RDMA/nes: don't leak skb if carrier down
[deliverable/linux.git] / sound / usb / media.c
CommitLineData
aebb2b89
SK
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
33static 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
41static 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
47int 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)
c0fd9cdf 87 goto free_mctl;
aebb2b89
SK
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;
c0fd9cdf 94 goto unregister_entity;
aebb2b89
SK
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;
c0fd9cdf 101 goto devnode_remove;
aebb2b89
SK
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)
c0fd9cdf 112 goto remove_intf_link;
aebb2b89
SK
113 break;
114 }
115 }
116
117 subs->media_ctl = mctl;
118 return 0;
119
c0fd9cdf 120remove_intf_link:
aebb2b89 121 media_remove_intf_link(mctl->intf_link);
c0fd9cdf 122devnode_remove:
aebb2b89 123 media_devnode_remove(mctl->intf_devnode);
c0fd9cdf 124unregister_entity:
aebb2b89 125 media_device_unregister_entity(&mctl->media_entity);
c0fd9cdf 126free_mctl:
aebb2b89
SK
127 kfree(mctl);
128 return ret;
129}
130
131void 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
149int 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
158void 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
166int 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
229static 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
256int 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
307void 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}
This page took 0.048975 seconds and 5 git commands to generate.