summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorShuah Khan <shuahkh@osg.samsung.com>2016-03-02 11:50:31 -0500
committerMauro Carvalho Chehab <mchehab@osg.samsung.com>2016-03-03 13:01:13 -0500
commitaebb2b89bff0fdeb4e7ddd73dcbccde1a0f27554 (patch)
treeaad7f1862beb01250032ac02d46d1dac11ccaa18
parent6ede20f9683c55dac8281b63d80b5cc669640252 (diff)
[media] sound/usb: Use Media Controller API to share media resources
Change ALSA driver to use Media Controller API to share media resources with DVB and V4L2 drivers on a AU0828 media device. Media Controller specific initialization is done after sound card is registered. ALSA creates Media interface and entity function graph nodes for Control, Mixer, PCM Playback, and PCM Capture devices. snd_usb_hw_params() will call Media Controller enable source handler interface to request the media resource. If resource request is granted, it will release it from snd_usb_hw_free(). If resource is busy, -EBUSY is returned. Media specific cleanup is done in usb_audio_disconnect(). Signed-off-by: Shuah Khan <shuahkh@osg.samsung.com> Acked-by: Takashi Iwai <tiwai@suse.de> Signed-off-by: Mauro Carvalho Chehab <mchehab@osg.samsung.com>
-rw-r--r--sound/usb/Kconfig4
-rw-r--r--sound/usb/Makefile2
-rw-r--r--sound/usb/card.c14
-rw-r--r--sound/usb/card.h3
-rw-r--r--sound/usb/media.c318
-rw-r--r--sound/usb/media.h72
-rw-r--r--sound/usb/mixer.h3
-rw-r--r--sound/usb/pcm.c28
-rw-r--r--sound/usb/quirks-table.h1
-rw-r--r--sound/usb/stream.c2
-rw-r--r--sound/usb/usbaudio.h6
11 files changed, 448 insertions, 5 deletions
diff --git a/sound/usb/Kconfig b/sound/usb/Kconfig
index a452ad7cec40..d14bf411515b 100644
--- a/sound/usb/Kconfig
+++ b/sound/usb/Kconfig
@@ -15,6 +15,7 @@ config SND_USB_AUDIO
15 select SND_RAWMIDI 15 select SND_RAWMIDI
16 select SND_PCM 16 select SND_PCM
17 select BITREVERSE 17 select BITREVERSE
18 select SND_USB_AUDIO_USE_MEDIA_CONTROLLER if MEDIA_CONTROLLER && (MEDIA_SUPPORT=y || MEDIA_SUPPORT=SND_USB_AUDIO)
18 help 19 help
19 Say Y here to include support for USB audio and USB MIDI 20 Say Y here to include support for USB audio and USB MIDI
20 devices. 21 devices.
@@ -22,6 +23,9 @@ config SND_USB_AUDIO
22 To compile this driver as a module, choose M here: the module 23 To compile this driver as a module, choose M here: the module
23 will be called snd-usb-audio. 24 will be called snd-usb-audio.
24 25
26config SND_USB_AUDIO_USE_MEDIA_CONTROLLER
27 bool
28
25config SND_USB_UA101 29config SND_USB_UA101
26 tristate "Edirol UA-101/UA-1000 driver" 30 tristate "Edirol UA-101/UA-1000 driver"
27 select SND_PCM 31 select SND_PCM
diff --git a/sound/usb/Makefile b/sound/usb/Makefile
index 2d2d122b069f..8dca3c407f5a 100644
--- a/sound/usb/Makefile
+++ b/sound/usb/Makefile
@@ -15,6 +15,8 @@ snd-usb-audio-objs := card.o \
15 quirks.o \ 15 quirks.o \
16 stream.o 16 stream.o
17 17
18snd-usb-audio-$(CONFIG_SND_USB_AUDIO_USE_MEDIA_CONTROLLER) += media.o
19
18snd-usbmidi-lib-objs := midi.o 20snd-usbmidi-lib-objs := midi.o
19 21
20# Toplevel Module Dependency 22# Toplevel Module Dependency
diff --git a/sound/usb/card.c b/sound/usb/card.c
index 1f09d9591276..258cf7015ce2 100644
--- a/sound/usb/card.c
+++ b/sound/usb/card.c
@@ -66,6 +66,7 @@
66#include "format.h" 66#include "format.h"
67#include "power.h" 67#include "power.h"
68#include "stream.h" 68#include "stream.h"
69#include "media.h"
69 70
70MODULE_AUTHOR("Takashi Iwai <tiwai@suse.de>"); 71MODULE_AUTHOR("Takashi Iwai <tiwai@suse.de>");
71MODULE_DESCRIPTION("USB Audio"); 72MODULE_DESCRIPTION("USB Audio");
@@ -561,6 +562,11 @@ static int usb_audio_probe(struct usb_interface *intf,
561 if (err < 0) 562 if (err < 0)
562 goto __error; 563 goto __error;
563 564
565 if (quirk->media_device) {
566 /* don't want to fail when media_snd_device_create() fails */
567 media_snd_device_create(chip, intf);
568 }
569
564 usb_chip[chip->index] = chip; 570 usb_chip[chip->index] = chip;
565 chip->num_interfaces++; 571 chip->num_interfaces++;
566 usb_set_intfdata(intf, chip); 572 usb_set_intfdata(intf, chip);
@@ -617,6 +623,14 @@ static void usb_audio_disconnect(struct usb_interface *intf)
617 list_for_each(p, &chip->midi_list) { 623 list_for_each(p, &chip->midi_list) {
618 snd_usbmidi_disconnect(p); 624 snd_usbmidi_disconnect(p);
619 } 625 }
626 /*
627 * Nice to check quirk && quirk->media_device
628 * need some special handlings. Doesn't look like
629 * we have access to quirk here
630 * Acceses mixer_list
631 */
632 media_snd_device_delete(chip);
633
620 /* release mixer resources */ 634 /* release mixer resources */
621 list_for_each_entry(mixer, &chip->mixer_list, list) { 635 list_for_each_entry(mixer, &chip->mixer_list, list) {
622 snd_usb_mixer_disconnect(mixer); 636 snd_usb_mixer_disconnect(mixer);
diff --git a/sound/usb/card.h b/sound/usb/card.h
index 71778ca4b26a..34a0898e2238 100644
--- a/sound/usb/card.h
+++ b/sound/usb/card.h
@@ -105,6 +105,8 @@ struct snd_usb_endpoint {
105 struct list_head list; 105 struct list_head list;
106}; 106};
107 107
108struct media_ctl;
109
108struct snd_usb_substream { 110struct snd_usb_substream {
109 struct snd_usb_stream *stream; 111 struct snd_usb_stream *stream;
110 struct usb_device *dev; 112 struct usb_device *dev;
@@ -156,6 +158,7 @@ struct snd_usb_substream {
156 } dsd_dop; 158 } dsd_dop;
157 159
158 bool trigger_tstamp_pending_update; /* trigger timestamp being updated from initial estimate */ 160 bool trigger_tstamp_pending_update; /* trigger timestamp being updated from initial estimate */
161 struct media_ctl *media_ctl;
159}; 162};
160 163
161struct snd_usb_stream { 164struct snd_usb_stream {
diff --git a/sound/usb/media.c b/sound/usb/media.c
new file mode 100644
index 000000000000..6c0dfd825097
--- /dev/null
+++ b/sound/usb/media.c
@@ -0,0 +1,318 @@
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)
87 goto err1;
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 err2;
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 err3;
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 err4;
113 break;
114 }
115 }
116
117 subs->media_ctl = mctl;
118 return 0;
119
120err4:
121 media_remove_intf_link(mctl->intf_link);
122err3:
123 media_devnode_remove(mctl->intf_devnode);
124err2:
125 media_device_unregister_entity(&mctl->media_entity);
126err1:
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}
diff --git a/sound/usb/media.h b/sound/usb/media.h
new file mode 100644
index 000000000000..1dcdcdc5f7aa
--- /dev/null
+++ b/sound/usb/media.h
@@ -0,0 +1,72 @@
1/*
2 * media.h - 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#ifndef __MEDIA_H
19
20#ifdef CONFIG_SND_USB_AUDIO_USE_MEDIA_CONTROLLER
21
22#include <media/media-device.h>
23#include <media/media-entity.h>
24#include <sound/asound.h>
25
26struct media_ctl {
27 struct media_device *media_dev;
28 struct media_entity media_entity;
29 struct media_intf_devnode *intf_devnode;
30 struct media_link *intf_link;
31 struct media_pad media_pad;
32 struct media_pipeline media_pipe;
33};
34
35/*
36 * One source pad each for SNDRV_PCM_STREAM_CAPTURE and
37 * SNDRV_PCM_STREAM_PLAYBACK. One for sink pad to link
38 * to AUDIO Source
39*/
40#define MEDIA_MIXER_PAD_MAX (SNDRV_PCM_STREAM_LAST + 2)
41
42struct media_mixer_ctl {
43 struct media_device *media_dev;
44 struct media_entity media_entity;
45 struct media_intf_devnode *intf_devnode;
46 struct media_link *intf_link;
47 struct media_pad media_pad[MEDIA_MIXER_PAD_MAX];
48 struct media_pipeline media_pipe;
49};
50
51int media_snd_device_create(struct snd_usb_audio *chip,
52 struct usb_interface *iface);
53void media_snd_device_delete(struct snd_usb_audio *chip);
54int media_snd_stream_init(struct snd_usb_substream *subs, struct snd_pcm *pcm,
55 int stream);
56void media_snd_stream_delete(struct snd_usb_substream *subs);
57int media_snd_start_pipeline(struct snd_usb_substream *subs);
58void media_snd_stop_pipeline(struct snd_usb_substream *subs);
59#else
60static inline int media_snd_device_create(struct snd_usb_audio *chip,
61 struct usb_interface *iface)
62 { return 0; }
63static inline void media_snd_device_delete(struct snd_usb_audio *chip) { }
64static inline int media_snd_stream_init(struct snd_usb_substream *subs,
65 struct snd_pcm *pcm, int stream)
66 { return 0; }
67static inline void media_snd_stream_delete(struct snd_usb_substream *subs) { }
68static inline int media_snd_start_pipeline(struct snd_usb_substream *subs)
69 { return 0; }
70static inline void media_snd_stop_pipeline(struct snd_usb_substream *subs) { }
71#endif
72#endif /* __MEDIA_H */
diff --git a/sound/usb/mixer.h b/sound/usb/mixer.h
index 3417ef347e40..f3789446ab9c 100644
--- a/sound/usb/mixer.h
+++ b/sound/usb/mixer.h
@@ -3,6 +3,8 @@
3 3
4#include <sound/info.h> 4#include <sound/info.h>
5 5
6struct media_mixer_ctl;
7
6struct usb_mixer_interface { 8struct usb_mixer_interface {
7 struct snd_usb_audio *chip; 9 struct snd_usb_audio *chip;
8 struct usb_host_interface *hostif; 10 struct usb_host_interface *hostif;
@@ -22,6 +24,7 @@ struct usb_mixer_interface {
22 struct urb *rc_urb; 24 struct urb *rc_urb;
23 struct usb_ctrlrequest *rc_setup_packet; 25 struct usb_ctrlrequest *rc_setup_packet;
24 u8 rc_buffer[6]; 26 u8 rc_buffer[6];
27 struct media_mixer_ctl *media_mixer_ctl;
25}; 28};
26 29
27#define MAX_CHANNELS 16 /* max logical channels */ 30#define MAX_CHANNELS 16 /* max logical channels */
diff --git a/sound/usb/pcm.c b/sound/usb/pcm.c
index 9245f52d43bd..b0370d5f33f8 100644
--- a/sound/usb/pcm.c
+++ b/sound/usb/pcm.c
@@ -35,6 +35,7 @@
35#include "pcm.h" 35#include "pcm.h"
36#include "clock.h" 36#include "clock.h"
37#include "power.h" 37#include "power.h"
38#include "media.h"
38 39
39#define SUBSTREAM_FLAG_DATA_EP_STARTED 0 40#define SUBSTREAM_FLAG_DATA_EP_STARTED 0
40#define SUBSTREAM_FLAG_SYNC_EP_STARTED 1 41#define SUBSTREAM_FLAG_SYNC_EP_STARTED 1
@@ -715,10 +716,14 @@ static int snd_usb_hw_params(struct snd_pcm_substream *substream,
715 struct audioformat *fmt; 716 struct audioformat *fmt;
716 int ret; 717 int ret;
717 718
719 ret = media_snd_start_pipeline(subs);
720 if (ret)
721 return ret;
722
718 ret = snd_pcm_lib_alloc_vmalloc_buffer(substream, 723 ret = snd_pcm_lib_alloc_vmalloc_buffer(substream,
719 params_buffer_bytes(hw_params)); 724 params_buffer_bytes(hw_params));
720 if (ret < 0) 725 if (ret < 0)
721 return ret; 726 goto err_ret;
722 727
723 subs->pcm_format = params_format(hw_params); 728 subs->pcm_format = params_format(hw_params);
724 subs->period_bytes = params_period_bytes(hw_params); 729 subs->period_bytes = params_period_bytes(hw_params);
@@ -732,22 +737,27 @@ static int snd_usb_hw_params(struct snd_pcm_substream *substream,
732 dev_dbg(&subs->dev->dev, 737 dev_dbg(&subs->dev->dev,
733 "cannot set format: format = %#x, rate = %d, channels = %d\n", 738 "cannot set format: format = %#x, rate = %d, channels = %d\n",
734 subs->pcm_format, subs->cur_rate, subs->channels); 739 subs->pcm_format, subs->cur_rate, subs->channels);
735 return -EINVAL; 740 ret = -EINVAL;
741 goto err_ret;
736 } 742 }
737 743
738 ret = snd_usb_lock_shutdown(subs->stream->chip); 744 ret = snd_usb_lock_shutdown(subs->stream->chip);
739 if (ret < 0) 745 if (ret < 0)
740 return ret; 746 goto err_ret;
741 ret = set_format(subs, fmt); 747 ret = set_format(subs, fmt);
742 snd_usb_unlock_shutdown(subs->stream->chip); 748 snd_usb_unlock_shutdown(subs->stream->chip);
743 if (ret < 0) 749 if (ret < 0)
744 return ret; 750 goto err_ret;
745 751
746 subs->interface = fmt->iface; 752 subs->interface = fmt->iface;
747 subs->altset_idx = fmt->altset_idx; 753 subs->altset_idx = fmt->altset_idx;
748 subs->need_setup_ep = true; 754 subs->need_setup_ep = true;
749 755
750 return 0; 756 return 0;
757
758err_ret:
759 media_snd_stop_pipeline(subs);
760 return ret;
751} 761}
752 762
753/* 763/*
@@ -759,6 +769,7 @@ static int snd_usb_hw_free(struct snd_pcm_substream *substream)
759{ 769{
760 struct snd_usb_substream *subs = substream->runtime->private_data; 770 struct snd_usb_substream *subs = substream->runtime->private_data;
761 771
772 media_snd_stop_pipeline(subs);
762 subs->cur_audiofmt = NULL; 773 subs->cur_audiofmt = NULL;
763 subs->cur_rate = 0; 774 subs->cur_rate = 0;
764 subs->period_bytes = 0; 775 subs->period_bytes = 0;
@@ -1219,6 +1230,7 @@ static int snd_usb_pcm_open(struct snd_pcm_substream *substream, int direction)
1219 struct snd_usb_stream *as = snd_pcm_substream_chip(substream); 1230 struct snd_usb_stream *as = snd_pcm_substream_chip(substream);
1220 struct snd_pcm_runtime *runtime = substream->runtime; 1231 struct snd_pcm_runtime *runtime = substream->runtime;
1221 struct snd_usb_substream *subs = &as->substream[direction]; 1232 struct snd_usb_substream *subs = &as->substream[direction];
1233 int ret;
1222 1234
1223 subs->interface = -1; 1235 subs->interface = -1;
1224 subs->altset_idx = 0; 1236 subs->altset_idx = 0;
@@ -1232,7 +1244,12 @@ static int snd_usb_pcm_open(struct snd_pcm_substream *substream, int direction)
1232 subs->dsd_dop.channel = 0; 1244 subs->dsd_dop.channel = 0;
1233 subs->dsd_dop.marker = 1; 1245 subs->dsd_dop.marker = 1;
1234 1246
1235 return setup_hw_info(runtime, subs); 1247 ret = setup_hw_info(runtime, subs);
1248 if (ret == 0)
1249 ret = media_snd_stream_init(subs, as->pcm, direction);
1250 if (ret)
1251 snd_usb_autosuspend(subs->stream->chip);
1252 return ret;
1236} 1253}
1237 1254
1238static int snd_usb_pcm_close(struct snd_pcm_substream *substream, int direction) 1255static int snd_usb_pcm_close(struct snd_pcm_substream *substream, int direction)
@@ -1241,6 +1258,7 @@ static int snd_usb_pcm_close(struct snd_pcm_substream *substream, int direction)
1241 struct snd_usb_substream *subs = &as->substream[direction]; 1258 struct snd_usb_substream *subs = &as->substream[direction];
1242 1259
1243 stop_endpoints(subs, true); 1260 stop_endpoints(subs, true);
1261 media_snd_stop_pipeline(subs);
1244 1262
1245 if (subs->interface >= 0 && 1263 if (subs->interface >= 0 &&
1246 !snd_usb_lock_shutdown(subs->stream->chip)) { 1264 !snd_usb_lock_shutdown(subs->stream->chip)) {
diff --git a/sound/usb/quirks-table.h b/sound/usb/quirks-table.h
index c60a776e815d..9d087b19c70c 100644
--- a/sound/usb/quirks-table.h
+++ b/sound/usb/quirks-table.h
@@ -2886,6 +2886,7 @@ YAMAHA_DEVICE(0x7010, "UB99"),
2886 .product_name = pname, \ 2886 .product_name = pname, \
2887 .ifnum = QUIRK_ANY_INTERFACE, \ 2887 .ifnum = QUIRK_ANY_INTERFACE, \
2888 .type = QUIRK_AUDIO_ALIGN_TRANSFER, \ 2888 .type = QUIRK_AUDIO_ALIGN_TRANSFER, \
2889 .media_device = 1, \
2889 } \ 2890 } \
2890} 2891}
2891 2892
diff --git a/sound/usb/stream.c b/sound/usb/stream.c
index c4dc577ab1bd..51258a15f653 100644
--- a/sound/usb/stream.c
+++ b/sound/usb/stream.c
@@ -36,6 +36,7 @@
36#include "format.h" 36#include "format.h"
37#include "clock.h" 37#include "clock.h"
38#include "stream.h" 38#include "stream.h"
39#include "media.h"
39 40
40/* 41/*
41 * free a substream 42 * free a substream
@@ -52,6 +53,7 @@ static void free_substream(struct snd_usb_substream *subs)
52 kfree(fp); 53 kfree(fp);
53 } 54 }
54 kfree(subs->rate_list.list); 55 kfree(subs->rate_list.list);
56 media_snd_stream_delete(subs);
55} 57}
56 58
57 59
diff --git a/sound/usb/usbaudio.h b/sound/usb/usbaudio.h
index b665d85555cb..a161c7c1b126 100644
--- a/sound/usb/usbaudio.h
+++ b/sound/usb/usbaudio.h
@@ -30,6 +30,9 @@
30 * 30 *
31 */ 31 */
32 32
33struct media_device;
34struct media_intf_devnode;
35
33struct snd_usb_audio { 36struct snd_usb_audio {
34 int index; 37 int index;
35 struct usb_device *dev; 38 struct usb_device *dev;
@@ -60,6 +63,8 @@ struct snd_usb_audio {
60 bool autoclock; /* from the 'autoclock' module param */ 63 bool autoclock; /* from the 'autoclock' module param */
61 64
62 struct usb_host_interface *ctrl_intf; /* the audio control interface */ 65 struct usb_host_interface *ctrl_intf; /* the audio control interface */
66 struct media_device *media_dev;
67 struct media_intf_devnode *ctl_intf_media_devnode;
63}; 68};
64 69
65#define usb_audio_err(chip, fmt, args...) \ 70#define usb_audio_err(chip, fmt, args...) \
@@ -110,6 +115,7 @@ struct snd_usb_audio_quirk {
110 const char *product_name; 115 const char *product_name;
111 int16_t ifnum; 116 int16_t ifnum;
112 uint16_t type; 117 uint16_t type;
118 bool media_device;
113 const void *data; 119 const void *data;
114}; 120};
115 121