aboutsummaryrefslogtreecommitdiffstats
path: root/sound/usb
diff options
context:
space:
mode:
Diffstat (limited to 'sound/usb')
-rw-r--r--sound/usb/6fire/comm.c3
-rw-r--r--sound/usb/Kconfig2
-rw-r--r--sound/usb/card.c7
-rw-r--r--sound/usb/endpoint.c44
-rw-r--r--sound/usb/endpoint.h5
-rw-r--r--sound/usb/format.c10
-rw-r--r--sound/usb/pcm.c33
-rw-r--r--sound/usb/quirks-table.h127
-rw-r--r--sound/usb/usbaudio.h1
9 files changed, 167 insertions, 65 deletions
diff --git a/sound/usb/6fire/comm.c b/sound/usb/6fire/comm.c
index 6c3d531a250e..1a75c36932d8 100644
--- a/sound/usb/6fire/comm.c
+++ b/sound/usb/6fire/comm.c
@@ -129,12 +129,13 @@ int __devinit usb6fire_comm_init(struct sfire_chip *chip)
{
struct comm_runtime *rt = kzalloc(sizeof(struct comm_runtime),
GFP_KERNEL);
- struct urb *urb = &rt->receiver;
+ struct urb *urb;
int ret;
if (!rt)
return -ENOMEM;
+ urb = &rt->receiver;
rt->serial = 1;
rt->chip = chip;
usb_init_urb(urb);
diff --git a/sound/usb/Kconfig b/sound/usb/Kconfig
index ff77b28f3da1..225dfd737265 100644
--- a/sound/usb/Kconfig
+++ b/sound/usb/Kconfig
@@ -90,7 +90,7 @@ config SND_USB_CAIAQ_INPUT
config SND_USB_US122L
tristate "Tascam US-122L USB driver"
- depends on X86 && EXPERIMENTAL
+ depends on X86
select SND_HWDEP
select SND_RAWMIDI
help
diff --git a/sound/usb/card.c b/sound/usb/card.c
index dbf7999d18b4..ccf95cfe186f 100644
--- a/sound/usb/card.c
+++ b/sound/usb/card.c
@@ -25,9 +25,6 @@
*
* NOTES:
*
- * - async unlink should be used for avoiding the sleep inside lock.
- * 2.4.22 usb-uhci seems buggy for async unlinking and results in
- * oops. in such a cse, pass async_unlink=0 option.
* - the linked URBs would be preferred but not used so far because of
* the instability of unlinking.
* - type II is not supported properly. there is no device which supports
@@ -83,7 +80,6 @@ static bool enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP;/* Enable this card *
static int vid[SNDRV_CARDS] = { [0 ... (SNDRV_CARDS-1)] = -1 };
static int pid[SNDRV_CARDS] = { [0 ... (SNDRV_CARDS-1)] = -1 };
static int nrpacks = 8; /* max. number of packets per urb */
-static bool async_unlink = 1;
static int device_setup[SNDRV_CARDS]; /* device parameter for this card */
static bool ignore_ctl_error;
@@ -99,8 +95,6 @@ module_param_array(pid, int, NULL, 0444);
MODULE_PARM_DESC(pid, "Product ID for the USB audio device.");
module_param(nrpacks, int, 0644);
MODULE_PARM_DESC(nrpacks, "Max. number of packets per URB.");
-module_param(async_unlink, bool, 0444);
-MODULE_PARM_DESC(async_unlink, "Use async unlink mode.");
module_param_array(device_setup, int, NULL, 0444);
MODULE_PARM_DESC(device_setup, "Specific device setup (if needed).");
module_param(ignore_ctl_error, bool, 0444);
@@ -345,7 +339,6 @@ static int snd_usb_audio_create(struct usb_device *dev, int idx,
chip->card = card;
chip->setup = device_setup[idx];
chip->nrpacks = nrpacks;
- chip->async_unlink = async_unlink;
chip->probing = 1;
chip->usb_id = USB_ID(le16_to_cpu(dev->descriptor.idVendor),
diff --git a/sound/usb/endpoint.c b/sound/usb/endpoint.c
index 34de6f2faf61..f487d26f8d40 100644
--- a/sound/usb/endpoint.c
+++ b/sound/usb/endpoint.c
@@ -485,15 +485,10 @@ __exit_unlock:
static int wait_clear_urbs(struct snd_usb_endpoint *ep)
{
unsigned long end_time = jiffies + msecs_to_jiffies(1000);
- unsigned int i;
int alive;
do {
- alive = 0;
- for (i = 0; i < ep->nurbs; i++)
- if (test_bit(i, &ep->active_mask))
- alive++;
-
+ alive = bitmap_weight(&ep->active_mask, ep->nurbs);
if (!alive)
break;
@@ -520,33 +515,24 @@ void snd_usb_endpoint_sync_pending_stop(struct snd_usb_endpoint *ep)
/*
* unlink active urbs.
*/
-static int deactivate_urbs(struct snd_usb_endpoint *ep, int force, int can_sleep)
+static int deactivate_urbs(struct snd_usb_endpoint *ep, bool force)
{
unsigned int i;
- int async;
if (!force && ep->chip->shutdown) /* to be sure... */
return -EBADFD;
- async = !can_sleep && ep->chip->async_unlink;
-
clear_bit(EP_FLAG_RUNNING, &ep->flags);
INIT_LIST_HEAD(&ep->ready_playback_urbs);
ep->next_packet_read_pos = 0;
ep->next_packet_write_pos = 0;
- if (!async && in_interrupt())
- return 0;
-
for (i = 0; i < ep->nurbs; i++) {
if (test_bit(i, &ep->active_mask)) {
if (!test_and_set_bit(i, &ep->unlink_mask)) {
struct urb *u = ep->urb[i].urb;
- if (async)
- usb_unlink_urb(u);
- else
- usb_kill_urb(u);
+ usb_unlink_urb(u);
}
}
}
@@ -566,7 +552,7 @@ static void release_urbs(struct snd_usb_endpoint *ep, int force)
ep->prepare_data_urb = NULL;
/* stop urbs */
- deactivate_urbs(ep, force, 1);
+ deactivate_urbs(ep, force);
wait_clear_urbs(ep);
for (i = 0; i < ep->nurbs; i++)
@@ -829,7 +815,7 @@ int snd_usb_endpoint_set_params(struct snd_usb_endpoint *ep,
*
* Returns an error if the URB submission failed, 0 in all other cases.
*/
-int snd_usb_endpoint_start(struct snd_usb_endpoint *ep, int can_sleep)
+int snd_usb_endpoint_start(struct snd_usb_endpoint *ep, bool can_sleep)
{
int err;
unsigned int i;
@@ -842,7 +828,7 @@ int snd_usb_endpoint_start(struct snd_usb_endpoint *ep, int can_sleep)
return 0;
/* just to be sure */
- deactivate_urbs(ep, 0, can_sleep);
+ deactivate_urbs(ep, false);
if (can_sleep)
wait_clear_urbs(ep);
@@ -896,7 +882,7 @@ int snd_usb_endpoint_start(struct snd_usb_endpoint *ep, int can_sleep)
__error:
clear_bit(EP_FLAG_RUNNING, &ep->flags);
ep->use_count--;
- deactivate_urbs(ep, 0, 0);
+ deactivate_urbs(ep, false);
return -EPIPE;
}
@@ -910,9 +896,11 @@ __error:
* actually be deactivated.
*
* Must be balanced to calls of snd_usb_endpoint_start().
+ *
+ * The caller needs to synchronize the pending stop operation via
+ * snd_usb_endpoint_sync_pending_stop().
*/
-void snd_usb_endpoint_stop(struct snd_usb_endpoint *ep,
- int force, int can_sleep, int wait)
+void snd_usb_endpoint_stop(struct snd_usb_endpoint *ep)
{
if (!ep)
return;
@@ -921,16 +909,12 @@ void snd_usb_endpoint_stop(struct snd_usb_endpoint *ep,
return;
if (--ep->use_count == 0) {
- deactivate_urbs(ep, force, can_sleep);
+ deactivate_urbs(ep, false);
ep->data_subs = NULL;
ep->sync_slave = NULL;
ep->retire_data_urb = NULL;
ep->prepare_data_urb = NULL;
-
- if (wait)
- wait_clear_urbs(ep);
- else
- set_bit(EP_FLAG_STOPPING, &ep->flags);
+ set_bit(EP_FLAG_STOPPING, &ep->flags);
}
}
@@ -952,7 +936,7 @@ int snd_usb_endpoint_deactivate(struct snd_usb_endpoint *ep)
if (!ep)
return -EINVAL;
- deactivate_urbs(ep, 1, 1);
+ deactivate_urbs(ep, true);
wait_clear_urbs(ep);
if (ep->use_count != 0)
diff --git a/sound/usb/endpoint.h b/sound/usb/endpoint.h
index 3d4c9705041f..447902dd8a4a 100644
--- a/sound/usb/endpoint.h
+++ b/sound/usb/endpoint.h
@@ -16,9 +16,8 @@ int snd_usb_endpoint_set_params(struct snd_usb_endpoint *ep,
struct audioformat *fmt,
struct snd_usb_endpoint *sync_ep);
-int snd_usb_endpoint_start(struct snd_usb_endpoint *ep, int can_sleep);
-void snd_usb_endpoint_stop(struct snd_usb_endpoint *ep,
- int force, int can_sleep, int wait);
+int snd_usb_endpoint_start(struct snd_usb_endpoint *ep, bool can_sleep);
+void snd_usb_endpoint_stop(struct snd_usb_endpoint *ep);
void snd_usb_endpoint_sync_pending_stop(struct snd_usb_endpoint *ep);
int snd_usb_endpoint_activate(struct snd_usb_endpoint *ep);
int snd_usb_endpoint_deactivate(struct snd_usb_endpoint *ep);
diff --git a/sound/usb/format.c b/sound/usb/format.c
index ddfef57c4c9f..e831ee4238bb 100644
--- a/sound/usb/format.c
+++ b/sound/usb/format.c
@@ -155,7 +155,7 @@ static int parse_audio_format_rates_v1(struct snd_usb_audio *chip, struct audiof
if (fmt[0] < offset + 1 + 3 * (nr_rates ? nr_rates : 2)) {
snd_printk(KERN_ERR "%d:%u:%d : invalid UAC_FORMAT_TYPE desc\n",
chip->dev->devnum, fp->iface, fp->altsetting);
- return -1;
+ return -EINVAL;
}
if (nr_rates) {
@@ -167,7 +167,7 @@ static int parse_audio_format_rates_v1(struct snd_usb_audio *chip, struct audiof
fp->rate_table = kmalloc(sizeof(int) * nr_rates, GFP_KERNEL);
if (fp->rate_table == NULL) {
snd_printk(KERN_ERR "cannot malloc\n");
- return -1;
+ return -ENOMEM;
}
fp->nr_rates = 0;
@@ -198,7 +198,7 @@ static int parse_audio_format_rates_v1(struct snd_usb_audio *chip, struct audiof
}
if (!fp->nr_rates) {
hwc_debug("All rates were zero. Skipping format!\n");
- return -1;
+ return -EINVAL;
}
} else {
/* continuous rates */
@@ -383,7 +383,7 @@ static int parse_audio_format_i(struct snd_usb_audio *chip,
fp->formats = parse_audio_format_i_type(chip, fp, format,
fmt, protocol);
if (!fp->formats)
- return -1;
+ return -EINVAL;
}
/* gather possible sample rates */
@@ -409,7 +409,7 @@ static int parse_audio_format_i(struct snd_usb_audio *chip,
if (fp->channels < 1) {
snd_printk(KERN_ERR "%d:%u:%d : invalid channels %d\n",
chip->dev->devnum, fp->iface, fp->altsetting, fp->channels);
- return -1;
+ return -EINVAL;
}
return ret;
diff --git a/sound/usb/pcm.c b/sound/usb/pcm.c
index ef6fa24fc473..e919c2e40fa0 100644
--- a/sound/usb/pcm.c
+++ b/sound/usb/pcm.c
@@ -173,11 +173,8 @@ static int init_pitch_v2(struct snd_usb_audio *chip, int iface,
{
struct usb_device *dev = chip->dev;
unsigned char data[1];
- unsigned int ep;
int err;
- ep = get_endpoint(alts, 0)->bEndpointAddress;
-
data[0] = 1;
if ((err = snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0), UAC2_CS_CUR,
USB_TYPE_CLASS | USB_RECIP_ENDPOINT | USB_DIR_OUT,
@@ -214,7 +211,7 @@ int snd_usb_init_pitch(struct snd_usb_audio *chip, int iface,
}
}
-static int start_endpoints(struct snd_usb_substream *subs, int can_sleep)
+static int start_endpoints(struct snd_usb_substream *subs, bool can_sleep)
{
int err;
@@ -266,16 +263,18 @@ static int start_endpoints(struct snd_usb_substream *subs, int can_sleep)
return 0;
}
-static void stop_endpoints(struct snd_usb_substream *subs,
- int force, int can_sleep, int wait)
+static void stop_endpoints(struct snd_usb_substream *subs, bool wait)
{
if (test_and_clear_bit(SUBSTREAM_FLAG_SYNC_EP_STARTED, &subs->flags))
- snd_usb_endpoint_stop(subs->sync_endpoint,
- force, can_sleep, wait);
+ snd_usb_endpoint_stop(subs->sync_endpoint);
if (test_and_clear_bit(SUBSTREAM_FLAG_DATA_EP_STARTED, &subs->flags))
- snd_usb_endpoint_stop(subs->data_endpoint,
- force, can_sleep, wait);
+ snd_usb_endpoint_stop(subs->data_endpoint);
+
+ if (wait) {
+ snd_usb_endpoint_sync_pending_stop(subs->sync_endpoint);
+ snd_usb_endpoint_sync_pending_stop(subs->data_endpoint);
+ }
}
static int deactivate_endpoints(struct snd_usb_substream *subs)
@@ -447,7 +446,7 @@ static int configure_endpoint(struct snd_usb_substream *subs)
int ret;
/* format changed */
- stop_endpoints(subs, 0, 0, 0);
+ stop_endpoints(subs, true);
ret = snd_usb_endpoint_set_params(subs->data_endpoint,
subs->pcm_format,
subs->channels,
@@ -533,7 +532,7 @@ static int snd_usb_hw_free(struct snd_pcm_substream *substream)
subs->period_bytes = 0;
down_read(&subs->stream->chip->shutdown_rwsem);
if (!subs->stream->chip->shutdown) {
- stop_endpoints(subs, 0, 1, 1);
+ stop_endpoints(subs, true);
deactivate_endpoints(subs);
}
up_read(&subs->stream->chip->shutdown_rwsem);
@@ -608,7 +607,7 @@ static int snd_usb_pcm_prepare(struct snd_pcm_substream *substream)
/* for playback, submit the URBs now; otherwise, the first hwptr_done
* updates for all URBs would happen at the same time when starting */
if (subs->direction == SNDRV_PCM_STREAM_PLAYBACK)
- ret = start_endpoints(subs, 1);
+ ret = start_endpoints(subs, true);
unlock:
up_read(&subs->stream->chip->shutdown_rwsem);
@@ -1013,7 +1012,7 @@ 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];
- stop_endpoints(subs, 0, 0, 0);
+ stop_endpoints(subs, true);
if (!as->chip->shutdown && subs->interface >= 0) {
usb_set_interface(subs->dev, subs->interface, 0);
@@ -1248,7 +1247,7 @@ static int snd_usb_substream_playback_trigger(struct snd_pcm_substream *substrea
subs->running = 1;
return 0;
case SNDRV_PCM_TRIGGER_STOP:
- stop_endpoints(subs, 0, 0, 0);
+ stop_endpoints(subs, false);
subs->running = 0;
return 0;
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
@@ -1269,7 +1268,7 @@ static int snd_usb_substream_capture_trigger(struct snd_pcm_substream *substream
switch (cmd) {
case SNDRV_PCM_TRIGGER_START:
- err = start_endpoints(subs, 0);
+ err = start_endpoints(subs, false);
if (err < 0)
return err;
@@ -1277,7 +1276,7 @@ static int snd_usb_substream_capture_trigger(struct snd_pcm_substream *substream
subs->running = 1;
return 0;
case SNDRV_PCM_TRIGGER_STOP:
- stop_endpoints(subs, 0, 0, 0);
+ stop_endpoints(subs, false);
subs->running = 0;
return 0;
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
diff --git a/sound/usb/quirks-table.h b/sound/usb/quirks-table.h
index 88d8cebbb244..898e16c70b0c 100644
--- a/sound/usb/quirks-table.h
+++ b/sound/usb/quirks-table.h
@@ -1457,6 +1457,40 @@ YAMAHA_DEVICE(0x7010, "UB99"),
}
},
{
+ /* Advanced mode of the Roland VG-99, with MIDI and 24-bit PCM at 44.1
+ * kHz. In standard mode, the device has ID 0582:00b3, and offers
+ * 16-bit PCM at 44.1 kHz with no MIDI.
+ */
+ USB_DEVICE(0x0582, 0x00b2),
+ .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
+ .vendor_name = "Roland",
+ .product_name = "VG-99",
+ .ifnum = QUIRK_ANY_INTERFACE,
+ .type = QUIRK_COMPOSITE,
+ .data = (const struct snd_usb_audio_quirk[]) {
+ {
+ .ifnum = 0,
+ .type = QUIRK_AUDIO_STANDARD_INTERFACE
+ },
+ {
+ .ifnum = 1,
+ .type = QUIRK_AUDIO_STANDARD_INTERFACE
+ },
+ {
+ .ifnum = 2,
+ .type = QUIRK_MIDI_FIXED_ENDPOINT,
+ .data = & (const struct snd_usb_midi_endpoint_info) {
+ .out_cables = 0x0003,
+ .in_cables = 0x0003
+ }
+ },
+ {
+ .ifnum = -1
+ }
+ }
+ }
+},
+{
/* Roland SonicCell */
USB_DEVICE(0x0582, 0x00c2),
.driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
@@ -2880,6 +2914,99 @@ YAMAHA_DEVICE(0x7010, "UB99"),
}
},
+/* Reloop Play */
+{
+ USB_DEVICE(0x200c, 0x100b),
+ .bInterfaceClass = USB_CLASS_PER_INTERFACE,
+ .driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) {
+ .ifnum = QUIRK_ANY_INTERFACE,
+ .type = QUIRK_COMPOSITE,
+ .data = &(const struct snd_usb_audio_quirk[]) {
+ {
+ .ifnum = 0,
+ .type = QUIRK_AUDIO_STANDARD_MIXER,
+ },
+ {
+ .ifnum = 1,
+ .type = QUIRK_AUDIO_FIXED_ENDPOINT,
+ .data = &(const struct audioformat) {
+ .formats = SNDRV_PCM_FMTBIT_S24_3LE,
+ .channels = 4,
+ .iface = 1,
+ .altsetting = 1,
+ .altset_idx = 1,
+ .attributes = UAC_EP_CS_ATTR_SAMPLE_RATE,
+ .endpoint = 0x01,
+ .ep_attr = USB_ENDPOINT_SYNC_ADAPTIVE,
+ .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 = -1
+ }
+ }
+ }
+},
+
+{
+ /*
+ * Focusrite Scarlett 18i6
+ *
+ * Avoid mixer creation, which otherwise fails because some of
+ * the interface descriptor subtypes for interface 0 are
+ * unknown. That should be fixed or worked-around but this at
+ * least allows the device to be used successfully with a DAW
+ * and an external mixer. See comments below about other
+ * ignored interfaces.
+ */
+ USB_DEVICE(0x1235, 0x8004),
+ .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) {
+ .vendor_name = "Focusrite",
+ .product_name = "Scarlett 18i6",
+ .ifnum = QUIRK_ANY_INTERFACE,
+ .type = QUIRK_COMPOSITE,
+ .data = & (const struct snd_usb_audio_quirk[]) {
+ {
+ /* InterfaceSubClass 1 (Control Device) */
+ .ifnum = 0,
+ .type = QUIRK_IGNORE_INTERFACE
+ },
+ {
+ .ifnum = 1,
+ .type = QUIRK_AUDIO_STANDARD_INTERFACE
+ },
+ {
+ .ifnum = 2,
+ .type = QUIRK_AUDIO_STANDARD_INTERFACE
+ },
+ {
+ /* InterfaceSubClass 1 (Control Device) */
+ .ifnum = 3,
+ .type = QUIRK_IGNORE_INTERFACE
+ },
+ {
+ .ifnum = 4,
+ .type = QUIRK_MIDI_STANDARD_INTERFACE
+ },
+ {
+ /* InterfaceSubClass 1 (Device Firmware Update) */
+ .ifnum = 5,
+ .type = QUIRK_IGNORE_INTERFACE
+ },
+ {
+ .ifnum = -1
+ }
+ }
+ }
+},
+
{
/*
* Some USB MIDI devices don't have an audio control interface,
diff --git a/sound/usb/usbaudio.h b/sound/usb/usbaudio.h
index ef42797f56fb..1ac3fd9cc5a6 100644
--- a/sound/usb/usbaudio.h
+++ b/sound/usb/usbaudio.h
@@ -56,7 +56,6 @@ struct snd_usb_audio {
int setup; /* from the 'device_setup' module param */
int nrpacks; /* from the 'nrpacks' module param */
- int async_unlink; /* from the 'async_unlink' module param */
struct usb_host_interface *ctrl_intf; /* the audio control interface */
};