[alsa-devel] Better support for Focusrite saffire pro 6 usb 1
Juho Jokelainen
juho_jokelainen at hotmail.com
Wed Jan 4 10:17:48 CET 2017
After getting said device, I was bummed it didn't work well in linux (or windows for that matter).
Fortunately I fould an earlier post about it.
http://alsa-devel.alsa-project.narkive.com/pr5aHEeM/rfc-patch-0-2-add-support-for-audio-cards-with-multiple-endpoints-on-the-one-interface
For whatever reason, that patch has not made it into kernel. I can vouch that this patch
(with a few line change to support kernel changes in the last 3 years) does work and my
device now supports both audio input and output.
Unfortunately I have no experience in kernel development nor do I really understand the
alsa system. Since the code has been kept out of kernel, I suspect there is something
fishy about it. If in any way possible I would still like to see code that effectively does the
same thing as this patch upstreamed.
The slightly modified patch (for kernel 4.8):
---
sound/usb/pcm.c | 44 ++++++++++++++++++++++++++++++++++++--------
sound/usb/quirks-table.h | 24 ++++++++++++++++++++++++
2 files changed, 60 insertions(+), 8 deletions(-)
diff --git a/sound/usb/pcm.c b/sound/usb/pcm.c
index 44d178e..19e319d 100644
--- a/sound/usb/pcm.c
+++ b/sound/usb/pcm.c
@@ -483,7 +483,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))
@@ -498,12 +498,26 @@ static int set_format(struct snd_usb_substream *subs, struct audioformat *fmt)
/* close the old interface */
if (subs->interface >= 0 && subs->interface != fmt->iface) {
- err = usb_set_interface(subs->dev, subs->interface, 0);
- if (err < 0) {
- dev_err(&dev->dev,
- "%d:%d: return to setting 0 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;
}
subs->interface = -1;
subs->altset_idx = 0;
@@ -1241,12 +1255,26 @@ 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 (subs->interface >= 0 &&
!snd_usb_lock_shutdown(subs->stream->chip)) {
- 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;
snd_usb_unlock_shutdown(subs->stream->chip);
}
diff --git a/sound/usb/quirks-table.h b/sound/usb/quirks-table.h
index c60a776..2670498 100644
--- a/sound/usb/quirks-table.h
+++ b/sound/usb/quirks-table.h
@@ -2701,6 +2701,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,
--
2.10.2
my asoundrc for testing purposes:
pcm.frontroute {
type route
slave.pcm "dmix:USB"
ttable.0.0 1
ttable.1.1 1
}
pcm.frontusb {
type plug
slave.pcm "frontroute"
hint {
show on
description "USB front channels"
}
}
pcm.rearroute {
type route
slave.pcm "dmix:USB"
ttable.0.2 1
ttable.1.3 1
}
pcm.rearusb {
type plug
slave.pcm "rearroute"
hint {
show on
description "USB rear channels"
}
}
pcm.micaroute {
type route
slave.pcm "dsnoop:USB"
ttable.0.0 1
}
pcm.mica {
type plug
slave.pcm "micaroute"
hint {
show on
description "Focusrite Saffire Input 1"
}
}
pcm.micbroute {
type route
slave.pcm "dsnoop:USB"
ttable.0.1 1
}
pcm.micb {
type plug
slave.pcm "micbroute"
hint {
show on
description "Focusrite Saffire Input 2"
}
}
pcm.!default {
type plug
slave {
pcm "hw:1,0"
}
}
ctl.!default {
type hw
card 1
}
<https://gist.github.com/shiona/def87540b87466fff315c4ac805c6766>
More information about the Alsa-devel
mailing list