[alsa-devel] [RFC PATCH 0/2] Add support for audio cards with multiple endpoints on the one interface
Devices of company Focusrite (Novation) contain multiple endpoints on a single interface. In particular (1235:0010) "Novation Saffire 6 USB" on one interface have endpoints for playback and capture. Functions "set_format" and "pcm_close" are generated when new stream is creating and when it is closing respectively. They contain a function call "usb_set_interface" which resets interface and endpoints on it. Thus it is imposible to capture and playback a sound at the same time. To avoid this, suggest to monitor the status of the interface and endpoint on it. Status of endpoints can be monitored by the field "enabled" of the structure "usb_host_endpoint". This approach should not affect for the audio cards with one endpoint on the interface.
Please correct me if I'm wrong.
Signed-off-by: Eduard Gilmutdinov edgilmutdinov@gmail.com --- sound/usb/pcm.c | 47 +++++++++++++++++++++++++++++++++++++---------- 1 file changed, 37 insertions(+), 10 deletions(-)
diff --git a/sound/usb/pcm.c b/sound/usb/pcm.c index c62a165..e6edfaf 100644 --- a/sound/usb/pcm.c +++ b/sound/usb/pcm.c @@ -453,7 +453,7 @@ static int set_format(struct snd_usb_substream *subs, struct audioformat *fmt) struct usb_host_interface *alts; struct usb_interface_descriptor *altsd; struct usb_interface *iface; - int err; + int err, need_init, i;
iface = usb_ifnum_to_if(dev, fmt->iface); if (WARN_ON(!iface)) @@ -482,15 +482,28 @@ static int set_format(struct snd_usb_substream *subs, struct audioformat *fmt) /* set interface */ if (subs->interface != fmt->iface || subs->altset_idx != fmt->altset_idx) { - err = usb_set_interface(dev, fmt->iface, fmt->altsetting); - if (err < 0) { - dev_err(&dev->dev, - "%d:%d: usb_set_interface failed (%d)\n", - fmt->iface, fmt->altsetting, err); - return -EIO; + + need_init = iface->cur_altsetting != alts; + + if (need_init) { + err = usb_set_interface(dev, fmt->iface, fmt->altsetting); + if (err < 0) { + dev_err(&dev->dev, + "%d:%d: usb_set_interface failed (%d)\n", + fmt->iface, fmt->altsetting, err); + return -EIO; + } + dev_dbg(&dev->dev, "setting usb interface %d:%d\n", + fmt->iface, fmt->altsetting); + } + + for (i = 0; i < alts->desc.bNumEndpoints; ++i) { + if (alts->endpoint[i].desc.bEndpointAddress == fmt->endpoint) + alts->endpoint[i].enabled = 1; + else if (need_init) + alts->endpoint[i].enabled = 0; } - dev_dbg(&dev->dev, "setting usb interface %d:%d\n", - fmt->iface, fmt->altsetting); + subs->interface = fmt->iface; subs->altset_idx = fmt->altset_idx;
@@ -1210,11 +1223,25 @@ static int snd_usb_pcm_close(struct snd_pcm_substream *substream, int direction) { struct snd_usb_stream *as = snd_pcm_substream_chip(substream); struct snd_usb_substream *subs = &as->substream[direction]; + struct usb_interface *iface; + struct usb_host_interface *cur_alts; + int i, ep_active = 0;
stop_endpoints(subs, true);
if (!as->chip->shutdown && subs->interface >= 0) { - usb_set_interface(subs->dev, subs->interface, 0); + iface = usb_ifnum_to_if(subs->dev, subs->interface); + cur_alts = iface->cur_altsetting; + for (i = 0; i < cur_alts->desc.bNumEndpoints; ++i) { + if (cur_alts->endpoint[i].desc.bEndpointAddress == subs->ep_num) + cur_alts->endpoint[i].enabled = 0; + + ep_active += cur_alts->endpoint[i].enabled; + } + + if (!ep_active) + usb_set_interface(subs->dev, subs->interface, 0); + subs->interface = -1; }
Signed-off-by: Eduard Gilmutdinov edgilmutdinov@gmail.com --- sound/usb/quirks-table.h | 24 ++++++++++++++++++++++++ 1 file changed, 24 insertions(+)
diff --git a/sound/usb/quirks-table.h b/sound/usb/quirks-table.h index f652b10..a61e57d 100644 --- a/sound/usb/quirks-table.h +++ b/sound/usb/quirks-table.h @@ -2539,6 +2539,30 @@ YAMAHA_DEVICE(0x7010, "UB99"), .attributes = UAC_EP_CS_ATTR_SAMPLE_RATE, .endpoint = 0x01, .ep_attr = USB_ENDPOINT_XFER_ISOC, + .maxpacksize = 0x024c, + .rates = SNDRV_PCM_RATE_44100 | + SNDRV_PCM_RATE_48000, + .rate_min = 44100, + .rate_max = 48000, + .nr_rates = 2, + .rate_table = (unsigned int[]) { + 44100, 48000 + } + } + }, + { + .ifnum = 0, + .type = QUIRK_AUDIO_FIXED_ENDPOINT, + .data = &(const struct audioformat) { + .formats = SNDRV_PCM_FMTBIT_S24_3LE, + .channels = 2, + .iface = 0, + .altsetting = 1, + .altset_idx = 1, + .attributes = UAC_EP_CS_ATTR_SAMPLE_RATE, + .endpoint = 0x82, + .ep_attr = USB_ENDPOINT_XFER_ISOC, + .maxpacksize = 0x0126, .rates = SNDRV_PCM_RATE_44100 | SNDRV_PCM_RATE_48000, .rate_min = 44100,
participants (1)
-
Eduard Gilmutdinov