From 793ea49c476ebacfefabf78af9ea88a19da6ecdb Mon Sep 17 00:00:00 2001 From: Andy Shevchenko Date: Thu, 2 Aug 2012 16:52:41 +0300 Subject: ALSA: print small buffers via %*ph[C] Signed-off-by: Andy Shevchenko Signed-off-by: Takashi Iwai --- sound/usb/6fire/firmware.c | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) (limited to 'sound/usb') diff --git a/sound/usb/6fire/firmware.c b/sound/usb/6fire/firmware.c index 56ad923bf6b5..a1d9b0792a1e 100644 --- a/sound/usb/6fire/firmware.c +++ b/sound/usb/6fire/firmware.c @@ -346,11 +346,10 @@ static int usb6fire_fw_check(u8 *version) if (!memcmp(version, known_fw_versions + i, 4)) return 0; - snd_printk(KERN_ERR PREFIX "invalid fimware version in device: " - "%02x %02x %02x %02x. " + snd_printk(KERN_ERR PREFIX "invalid fimware version in device: %*ph. " "please reconnect to power. if this failure " "still happens, check your firmware installation.", - version[0], version[1], version[2], version[3]); + 4, version); return -EINVAL; } -- cgit v1.2.3 From 48ee7cb8b4867093c75eb5102f2359c9799b3341 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 28 Aug 2012 16:27:26 -0700 Subject: ALSA: usb-audio: Remove obsoleted fields in struct snd_usb_substream The two entries are duplicated in struct snd_usb_endpoint. Seems forgotten in the last clean-up. Signed-off-by: Takashi Iwai --- sound/usb/card.h | 2 -- 1 file changed, 2 deletions(-) (limited to 'sound/usb') diff --git a/sound/usb/card.h b/sound/usb/card.h index 2b9fffff23b6..bcb5267a02e8 100644 --- a/sound/usb/card.h +++ b/sound/usb/card.h @@ -115,8 +115,6 @@ struct snd_usb_substream { unsigned int hwptr_done; /* processed byte position in the buffer */ unsigned int transfer_done; /* processed frames since last period update */ - unsigned long active_mask; /* bitmask of active urbs */ - unsigned long unlink_mask; /* bitmask of unlinked urbs */ /* data and sync endpoints for this stream */ unsigned int ep_num; /* the endpoint number */ -- cgit v1.2.3 From c05fce586d4da2dfe0309bef3795a8586e967bc3 Mon Sep 17 00:00:00 2001 From: Marko Friedemann Date: Mon, 3 Sep 2012 10:12:40 +0200 Subject: ALSA: USB: Support for (original) Xbox Communicator Added support for Xbox Communicator to USB quirks. Signed-off-by: Marko Friedemann Signed-off-by: Takashi Iwai --- sound/usb/quirks-table.h | 53 ++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 53 insertions(+) (limited to 'sound/usb') diff --git a/sound/usb/quirks-table.h b/sound/usb/quirks-table.h index 79780fa57a43..d73ac9bc4272 100644 --- a/sound/usb/quirks-table.h +++ b/sound/usb/quirks-table.h @@ -2781,6 +2781,59 @@ YAMAHA_DEVICE(0x7010, "UB99"), } }, +/* Microsoft XboxLive Headset/Xbox Communicator */ +{ + USB_DEVICE(0x045e, 0x0283), + .bInterfaceClass = USB_CLASS_PER_INTERFACE, + .driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) { + .vendor_name = "Microsoft", + .product_name = "XboxLive Headset/Xbox Communicator", + .ifnum = QUIRK_ANY_INTERFACE, + .type = QUIRK_COMPOSITE, + .data = &(const struct snd_usb_audio_quirk[]) { + { + /* playback */ + .ifnum = 0, + .type = QUIRK_AUDIO_FIXED_ENDPOINT, + .data = &(const struct audioformat) { + .formats = SNDRV_PCM_FMTBIT_S16_LE, + .channels = 1, + .iface = 0, + .altsetting = 0, + .altset_idx = 0, + .attributes = 0, + .endpoint = 0x04, + .ep_attr = 0x05, + .rates = SNDRV_PCM_RATE_CONTINUOUS, + .rate_min = 22050, + .rate_max = 22050 + } + }, + { + /* capture */ + .ifnum = 1, + .type = QUIRK_AUDIO_FIXED_ENDPOINT, + .data = &(const struct audioformat) { + .formats = SNDRV_PCM_FMTBIT_S16_LE, + .channels = 1, + .iface = 1, + .altsetting = 0, + .altset_idx = 0, + .attributes = 0, + .endpoint = 0x85, + .ep_attr = 0x05, + .rates = SNDRV_PCM_RATE_CONTINUOUS, + .rate_min = 16000, + .rate_max = 16000 + } + }, + { + .ifnum = -1 + } + } + } +}, + { /* * Some USB MIDI devices don't have an audio control interface, -- cgit v1.2.3 From 2b58fd5b3193fd3af3d15114d95706087d25a7fe Mon Sep 17 00:00:00 2001 From: Daniel Mack Date: Tue, 4 Sep 2012 10:23:07 +0200 Subject: ALSA: snd-usb: Add quirks for Playback Designs devices Playback Designs' USB devices have some hardware limitations on their USB interface. In particular: - They need a 20ms delay after each class compliant request as the hardware ACKs the USB packets before the device is actually ready for the next command. Sending data immediately will result in buffer overflows in the hardware. - The devices send bogus feedback data at the start of each stream which confuse the feedback format auto-detection. This patch introduces a new quirks hook that is called after each control packet and which adds a delay for all devices that match Playback Designs' USB VID for now. In addition, it adds a counter to snd_usb_endpoint to drop received packets on the floor. Another new quirks function that is called once an endpoint is started initializes that counter for these devices on their sync endpoint. Signed-off-by: Daniel Mack Reported-and-tested-by: Andreas Koch Supported-by: Demian Martin Signed-off-by: Takashi Iwai --- sound/usb/card.h | 2 ++ sound/usb/endpoint.c | 8 ++++++++ sound/usb/helper.c | 5 +++++ sound/usb/quirks.c | 24 ++++++++++++++++++++++++ sound/usb/quirks.h | 10 ++++++++++ 5 files changed, 49 insertions(+) (limited to 'sound/usb') diff --git a/sound/usb/card.h b/sound/usb/card.h index bcb5267a02e8..23b6f23bd36a 100644 --- a/sound/usb/card.h +++ b/sound/usb/card.h @@ -92,6 +92,8 @@ struct snd_usb_endpoint { unsigned char silence_value; unsigned int stride; int iface, alt_idx; + int skip_packets; /* quirks for devices to ignore the first n packets + in a stream */ spinlock_t lock; struct list_head list; diff --git a/sound/usb/endpoint.c b/sound/usb/endpoint.c index c41181202688..94b08a6087a3 100644 --- a/sound/usb/endpoint.c +++ b/sound/usb/endpoint.c @@ -31,6 +31,7 @@ #include "card.h" #include "endpoint.h" #include "pcm.h" +#include "quirks.h" #define EP_FLAG_ACTIVATED 0 #define EP_FLAG_RUNNING 1 @@ -170,6 +171,11 @@ static void retire_inbound_urb(struct snd_usb_endpoint *ep, { struct urb *urb = urb_ctx->urb; + if (unlikely(ep->skip_packets > 0)) { + ep->skip_packets--; + return; + } + if (ep->sync_slave) snd_usb_handle_sync_urb(ep->sync_slave, ep, urb); @@ -825,6 +831,8 @@ int snd_usb_endpoint_start(struct snd_usb_endpoint *ep) ep->unlink_mask = 0; ep->phase = 0; + snd_usb_endpoint_start_quirk(ep); + /* * If this endpoint has a data endpoint as implicit feedback source, * don't start the urbs here. Instead, mark them all as available, diff --git a/sound/usb/helper.c b/sound/usb/helper.c index 9eed8f40b179..c1db28f874c2 100644 --- a/sound/usb/helper.c +++ b/sound/usb/helper.c @@ -21,6 +21,7 @@ #include "usbaudio.h" #include "helper.h" +#include "quirks.h" /* * combine bytes and get an integer value @@ -97,6 +98,10 @@ int snd_usb_ctl_msg(struct usb_device *dev, unsigned int pipe, __u8 request, memcpy(data, buf, size); kfree(buf); } + + snd_usb_ctl_msg_quirk(dev, pipe, request, requesttype, + value, index, data, size); + return err; } diff --git a/sound/usb/quirks.c b/sound/usb/quirks.c index 27817266867a..0f58b4b6d702 100644 --- a/sound/usb/quirks.c +++ b/sound/usb/quirks.c @@ -761,3 +761,27 @@ void snd_usb_set_format_quirk(struct snd_usb_substream *subs, } } +void snd_usb_endpoint_start_quirk(struct snd_usb_endpoint *ep) +{ + /* + * "Playback Design" products send bogus feedback data at the start + * of the stream. Ignore them. + */ + if ((le16_to_cpu(ep->chip->dev->descriptor.idVendor) == 0x23ba) && + ep->type == SND_USB_ENDPOINT_TYPE_SYNC) + ep->skip_packets = 4; +} + +void snd_usb_ctl_msg_quirk(struct usb_device *dev, unsigned int pipe, + __u8 request, __u8 requesttype, __u16 value, + __u16 index, void *data, __u16 size) +{ + /* + * "Playback Design" products need a 20ms delay after each + * class compliant request + */ + if ((le16_to_cpu(dev->descriptor.idVendor) == 0x23ba) && + (requesttype & USB_TYPE_MASK) == USB_TYPE_CLASS) + mdelay(20); +} + diff --git a/sound/usb/quirks.h b/sound/usb/quirks.h index 03e5e94098cd..0ca9e91067a6 100644 --- a/sound/usb/quirks.h +++ b/sound/usb/quirks.h @@ -1,6 +1,10 @@ #ifndef __USBAUDIO_QUIRKS_H #define __USBAUDIO_QUIRKS_H +struct audioformat; +struct snd_usb_endpoint; +struct snd_usb_substream; + int snd_usb_create_quirk(struct snd_usb_audio *chip, struct usb_interface *iface, struct usb_driver *driver, @@ -20,4 +24,10 @@ void snd_usb_set_format_quirk(struct snd_usb_substream *subs, int snd_usb_is_big_endian_format(struct snd_usb_audio *chip, struct audioformat *fp); +void snd_usb_endpoint_start_quirk(struct snd_usb_endpoint *ep); + +void snd_usb_ctl_msg_quirk(struct usb_device *dev, unsigned int pipe, + __u8 request, __u8 requesttype, __u16 value, + __u16 index, void *data, __u16 size); + #endif /* __USBAUDIO_QUIRKS_H */ -- cgit v1.2.3 From 715a170563843a1f55ae4c8484bc4732d69d2288 Mon Sep 17 00:00:00 2001 From: Dylan Reid Date: Tue, 18 Sep 2012 09:49:46 -0700 Subject: ALSA: usb-audio: set period_bytes in substream. Set the peiod_bytes member of snd_usb_substream. It was no longer being set, but will be needed to resume properly in a future commit. Signed-off-by: Dylan Reid Signed-off-by: Takashi Iwai --- sound/usb/pcm.c | 2 ++ 1 file changed, 2 insertions(+) (limited to 'sound/usb') diff --git a/sound/usb/pcm.c b/sound/usb/pcm.c index f782ce19bf5a..786f7a05e9a6 100644 --- a/sound/usb/pcm.c +++ b/sound/usb/pcm.c @@ -486,6 +486,8 @@ static int snd_usb_hw_params(struct snd_pcm_substream *substream, } if (changed) { + subs->period_bytes = params_period_bytes(hw_params); + mutex_lock(&subs->stream->chip->shutdown_mutex); /* format changed */ stop_endpoints(subs, 0, 0, 0); -- cgit v1.2.3 From 35ec7aa29833de350f51922736aefe22ebf76c4d Mon Sep 17 00:00:00 2001 From: Dylan Reid Date: Tue, 18 Sep 2012 09:49:47 -0700 Subject: ALSA: usb-audio: Don't require hw_params in endpoint. Change the interface to configure an endpoint so that it doesn't require a hw_params struct. This will allow it to be called from prepare instead of hw_params, configuring it after system resume. Signed-off-by: Dylan Reid Signed-off-by: Takashi Iwai --- sound/usb/endpoint.c | 31 ++++++++++++++++++------------- sound/usb/endpoint.h | 5 ++++- sound/usb/pcm.c | 16 +++++++++++++--- 3 files changed, 35 insertions(+), 17 deletions(-) (limited to 'sound/usb') diff --git a/sound/usb/endpoint.c b/sound/usb/endpoint.c index a83a18dbac25..152bfd48a311 100644 --- a/sound/usb/endpoint.c +++ b/sound/usb/endpoint.c @@ -567,20 +567,19 @@ static void release_urbs(struct snd_usb_endpoint *ep, int force) * configure a data endpoint */ static int data_ep_set_params(struct snd_usb_endpoint *ep, - struct snd_pcm_hw_params *hw_params, + snd_pcm_format_t pcm_format, + unsigned int channels, + unsigned int period_bytes, struct audioformat *fmt, struct snd_usb_endpoint *sync_ep) { unsigned int maxsize, i, urb_packs, total_packs, packs_per_ms; - int period_bytes = params_period_bytes(hw_params); - int format = params_format(hw_params); int is_playback = usb_pipeout(ep->pipe); - int frame_bits = snd_pcm_format_physical_width(params_format(hw_params)) * - params_channels(hw_params); + int frame_bits = snd_pcm_format_physical_width(pcm_format) * channels; ep->datainterval = fmt->datainterval; ep->stride = frame_bits >> 3; - ep->silence_value = format == SNDRV_PCM_FORMAT_U8 ? 0x80 : 0; + ep->silence_value = pcm_format == SNDRV_PCM_FORMAT_U8 ? 0x80 : 0; /* calculate max. frequency */ if (ep->maxpacksize) { @@ -693,7 +692,6 @@ out_of_memory: * configure a sync endpoint */ static int sync_ep_set_params(struct snd_usb_endpoint *ep, - struct snd_pcm_hw_params *hw_params, struct audioformat *fmt) { int i; @@ -736,7 +734,10 @@ out_of_memory: * snd_usb_endpoint_set_params: configure an snd_usb_endpoint * * @ep: the snd_usb_endpoint to configure - * @hw_params: the hardware parameters + * @pcm_format: the audio fomat. + * @channels: the number of audio channels. + * @period_bytes: the number of bytes in one alsa period. + * @rate: the frame rate. * @fmt: the USB audio format information * @sync_ep: the sync endpoint to use, if any * @@ -745,7 +746,10 @@ out_of_memory: * An endpoint that is already running can not be reconfigured. */ int snd_usb_endpoint_set_params(struct snd_usb_endpoint *ep, - struct snd_pcm_hw_params *hw_params, + snd_pcm_format_t pcm_format, + unsigned int channels, + unsigned int period_bytes, + unsigned int rate, struct audioformat *fmt, struct snd_usb_endpoint *sync_ep) { @@ -765,9 +769,9 @@ int snd_usb_endpoint_set_params(struct snd_usb_endpoint *ep, ep->fill_max = !!(fmt->attributes & UAC_EP_CS_ATTR_FILL_MAX); if (snd_usb_get_speed(ep->chip->dev) == USB_SPEED_FULL) - ep->freqn = get_usb_full_speed_rate(params_rate(hw_params)); + ep->freqn = get_usb_full_speed_rate(rate); else - ep->freqn = get_usb_high_speed_rate(params_rate(hw_params)); + ep->freqn = get_usb_high_speed_rate(rate); /* calculate the frequency in 16.16 format */ ep->freqm = ep->freqn; @@ -777,10 +781,11 @@ int snd_usb_endpoint_set_params(struct snd_usb_endpoint *ep, switch (ep->type) { case SND_USB_ENDPOINT_TYPE_DATA: - err = data_ep_set_params(ep, hw_params, fmt, sync_ep); + err = data_ep_set_params(ep, pcm_format, channels, + period_bytes, fmt, sync_ep); break; case SND_USB_ENDPOINT_TYPE_SYNC: - err = sync_ep_set_params(ep, hw_params, fmt); + err = sync_ep_set_params(ep, fmt); break; default: err = -EINVAL; diff --git a/sound/usb/endpoint.h b/sound/usb/endpoint.h index cbbbdf226d66..6376ccf10fd4 100644 --- a/sound/usb/endpoint.h +++ b/sound/usb/endpoint.h @@ -9,7 +9,10 @@ struct snd_usb_endpoint *snd_usb_add_endpoint(struct snd_usb_audio *chip, int ep_num, int direction, int type); int snd_usb_endpoint_set_params(struct snd_usb_endpoint *ep, - struct snd_pcm_hw_params *hw_params, + snd_pcm_format_t pcm_format, + unsigned int channels, + unsigned int period_bytes, + unsigned int rate, struct audioformat *fmt, struct snd_usb_endpoint *sync_ep); diff --git a/sound/usb/pcm.c b/sound/usb/pcm.c index 786f7a05e9a6..62ab4fd5880a 100644 --- a/sound/usb/pcm.c +++ b/sound/usb/pcm.c @@ -491,14 +491,24 @@ static int snd_usb_hw_params(struct snd_pcm_substream *substream, mutex_lock(&subs->stream->chip->shutdown_mutex); /* format changed */ stop_endpoints(subs, 0, 0, 0); - ret = snd_usb_endpoint_set_params(subs->data_endpoint, hw_params, fmt, + ret = snd_usb_endpoint_set_params(subs->data_endpoint, + format, + channels, + subs->period_bytes, + rate, + fmt, subs->sync_endpoint); if (ret < 0) goto unlock; if (subs->sync_endpoint) - ret = snd_usb_endpoint_set_params(subs->sync_endpoint, - hw_params, fmt, NULL); + ret = snd_usb_endpoint_set_params(subs->data_endpoint, + format, + channels, + subs->period_bytes, + rate, + fmt, + NULL); unlock: mutex_unlock(&subs->stream->chip->shutdown_mutex); } -- cgit v1.2.3 From 61a709504b079110cd5b12ea9a4590ffea687a5c Mon Sep 17 00:00:00 2001 From: Dylan Reid Date: Tue, 18 Sep 2012 09:49:48 -0700 Subject: ALSA: usb-audio: Move configuration to prepare. Move interface and endpoint configuration from hw_params to prepare callback. During system suspend/resume when the USB device power isn't cycled the interface and endpoint configuration need to be set before audio playback can continue. Resume involves another call to prepare but not to hw_params, moving it here allows a playing stream to continue after resume. Signed-off-by: Dylan Reid Signed-off-by: Takashi Iwai --- sound/usb/card.h | 2 + sound/usb/pcm.c | 134 ++++++++++++++++++++++++++++++------------------------- 2 files changed, 76 insertions(+), 60 deletions(-) (limited to 'sound/usb') diff --git a/sound/usb/card.h b/sound/usb/card.h index 23b6f23bd36a..6cc883c3567d 100644 --- a/sound/usb/card.h +++ b/sound/usb/card.h @@ -107,6 +107,8 @@ struct snd_usb_substream { int interface; /* current interface */ int endpoint; /* assigned endpoint */ struct audioformat *cur_audiofmt; /* current audioformat pointer (for hw_params callback) */ + snd_pcm_format_t pcm_format; /* current audio format (for hw_params callback) */ + unsigned int channels; /* current number of channels (for hw_params callback) */ unsigned int cur_rate; /* current rate (for hw_params callback) */ unsigned int period_bytes; /* current period bytes (for hw_params callback) */ unsigned int altset_idx; /* USB data format: index of alternate setting */ diff --git a/sound/usb/pcm.c b/sound/usb/pcm.c index 62ab4fd5880a..ae783d40f55a 100644 --- a/sound/usb/pcm.c +++ b/sound/usb/pcm.c @@ -82,8 +82,7 @@ static snd_pcm_uframes_t snd_usb_pcm_pointer(struct snd_pcm_substream *substream /* * find a matching audio format */ -static struct audioformat *find_format(struct snd_usb_substream *subs, unsigned int format, - unsigned int rate, unsigned int channels) +static struct audioformat *find_format(struct snd_usb_substream *subs) { struct list_head *p; struct audioformat *found = NULL; @@ -92,16 +91,17 @@ static struct audioformat *find_format(struct snd_usb_substream *subs, unsigned list_for_each(p, &subs->fmt_list) { struct audioformat *fp; fp = list_entry(p, struct audioformat, list); - if (!(fp->formats & (1uLL << format))) + if (!(fp->formats & (1uLL << subs->pcm_format))) continue; - if (fp->channels != channels) + if (fp->channels != subs->channels) continue; - if (rate < fp->rate_min || rate > fp->rate_max) + if (subs->cur_rate < fp->rate_min || + subs->cur_rate > fp->rate_max) continue; if (! (fp->rates & SNDRV_PCM_RATE_CONTINUOUS)) { unsigned int i; for (i = 0; i < fp->nr_rates; i++) - if (fp->rate_table[i] == rate) + if (fp->rate_table[i] == subs->cur_rate) break; if (i >= fp->nr_rates) continue; @@ -435,6 +435,42 @@ add_sync_ep: return 0; } +/* + * configure endpoint params + * + * called during initial setup and upon resume + */ +static int configure_endpoint(struct snd_usb_substream *subs) +{ + int ret; + + mutex_lock(&subs->stream->chip->shutdown_mutex); + /* format changed */ + stop_endpoints(subs, 0, 0, 0); + ret = snd_usb_endpoint_set_params(subs->data_endpoint, + subs->pcm_format, + subs->channels, + subs->period_bytes, + subs->cur_rate, + subs->cur_audiofmt, + subs->sync_endpoint); + if (ret < 0) + goto unlock; + + if (subs->sync_endpoint) + ret = snd_usb_endpoint_set_params(subs->data_endpoint, + subs->pcm_format, + subs->channels, + subs->period_bytes, + subs->cur_rate, + subs->cur_audiofmt, + NULL); + +unlock: + mutex_unlock(&subs->stream->chip->shutdown_mutex); + return ret; +} + /* * hw_params callback * @@ -450,75 +486,32 @@ static int snd_usb_hw_params(struct snd_pcm_substream *substream, { struct snd_usb_substream *subs = substream->runtime->private_data; struct audioformat *fmt; - unsigned int channels, rate, format; - int ret, changed; + int ret; ret = snd_pcm_lib_alloc_vmalloc_buffer(substream, params_buffer_bytes(hw_params)); if (ret < 0) return ret; - format = params_format(hw_params); - rate = params_rate(hw_params); - channels = params_channels(hw_params); - fmt = find_format(subs, format, rate, channels); + subs->pcm_format = params_format(hw_params); + subs->period_bytes = params_period_bytes(hw_params); + subs->channels = params_channels(hw_params); + subs->cur_rate = params_rate(hw_params); + + fmt = find_format(subs); if (!fmt) { snd_printd(KERN_DEBUG "cannot set format: format = %#x, rate = %d, channels = %d\n", - format, rate, channels); + subs->pcm_format, subs->cur_rate, subs->channels); return -EINVAL; } - changed = subs->cur_audiofmt != fmt || - subs->period_bytes != params_period_bytes(hw_params) || - subs->cur_rate != rate; if ((ret = set_format(subs, fmt)) < 0) return ret; - if (subs->cur_rate != rate) { - struct usb_host_interface *alts; - struct usb_interface *iface; - iface = usb_ifnum_to_if(subs->dev, fmt->iface); - alts = &iface->altsetting[fmt->altset_idx]; - ret = snd_usb_init_sample_rate(subs->stream->chip, fmt->iface, alts, fmt, rate); - if (ret < 0) - return ret; - subs->cur_rate = rate; - } - - if (changed) { - subs->period_bytes = params_period_bytes(hw_params); + subs->interface = fmt->iface; + subs->altset_idx = fmt->altset_idx; - mutex_lock(&subs->stream->chip->shutdown_mutex); - /* format changed */ - stop_endpoints(subs, 0, 0, 0); - ret = snd_usb_endpoint_set_params(subs->data_endpoint, - format, - channels, - subs->period_bytes, - rate, - fmt, - subs->sync_endpoint); - if (ret < 0) - goto unlock; - - if (subs->sync_endpoint) - ret = snd_usb_endpoint_set_params(subs->data_endpoint, - format, - channels, - subs->period_bytes, - rate, - fmt, - NULL); -unlock: - mutex_unlock(&subs->stream->chip->shutdown_mutex); - } - - if (ret == 0) { - subs->interface = fmt->iface; - subs->altset_idx = fmt->altset_idx; - } - - return ret; + return 0; } /* @@ -549,6 +542,9 @@ static int snd_usb_pcm_prepare(struct snd_pcm_substream *substream) { struct snd_pcm_runtime *runtime = substream->runtime; struct snd_usb_substream *subs = runtime->private_data; + struct usb_host_interface *alts; + struct usb_interface *iface; + int ret; if (! subs->cur_audiofmt) { snd_printk(KERN_ERR "usbaudio: no format is specified!\n"); @@ -558,6 +554,24 @@ static int snd_usb_pcm_prepare(struct snd_pcm_substream *substream) if (snd_BUG_ON(!subs->data_endpoint)) return -EIO; + ret = set_format(subs, subs->cur_audiofmt); + if (ret < 0) + return ret; + + iface = usb_ifnum_to_if(subs->dev, subs->cur_audiofmt->iface); + alts = &iface->altsetting[subs->cur_audiofmt->altset_idx]; + ret = snd_usb_init_sample_rate(subs->stream->chip, + subs->cur_audiofmt->iface, + alts, + subs->cur_audiofmt, + subs->cur_rate); + if (ret < 0) + return ret; + + ret = configure_endpoint(subs); + if (ret < 0) + return ret; + /* some unit conversions in runtime */ subs->data_endpoint->maxframesize = bytes_to_frames(runtime, subs->data_endpoint->maxpacksize); -- cgit v1.2.3 From 384dc085c32285e6548511bf80c5d5a5b246ed24 Mon Sep 17 00:00:00 2001 From: Takashi Iwai Date: Tue, 18 Sep 2012 14:49:31 +0200 Subject: ALSA: usb-audio: Avoid unnecessary EP setups in prepare The recent fix for USB suspend breakage moved the code to set up EP from hw_params to prepare, but it means also the EP setup might be called multiple times unnecessarily because the prepare callback can be called multiple times without starting the stream (e.g. OSS emulation). This patch adds a new flag to struct snd_usb_substream indicating whether the setup of EP is required, and do it only when necessary, i.e. right after hw_params or suspend. Signed-off-by: Takashi Iwai --- sound/usb/card.c | 2 ++ sound/usb/card.h | 1 + sound/usb/pcm.c | 10 +++++++--- 3 files changed, 10 insertions(+), 3 deletions(-) (limited to 'sound/usb') diff --git a/sound/usb/card.c b/sound/usb/card.c index 4a469f0cb6d4..561bb74fd364 100644 --- a/sound/usb/card.c +++ b/sound/usb/card.c @@ -646,6 +646,8 @@ static int usb_audio_suspend(struct usb_interface *intf, pm_message_t message) list_for_each(p, &chip->pcm_list) { as = list_entry(p, struct snd_usb_stream, list); snd_pcm_suspend_all(as->pcm); + as->substream[0].need_setup_ep = + as->substream[1].need_setup_ep = true; } } } else { diff --git a/sound/usb/card.h b/sound/usb/card.h index 6cc883c3567d..afa4f9e9b27a 100644 --- a/sound/usb/card.h +++ b/sound/usb/card.h @@ -125,6 +125,7 @@ struct snd_usb_substream { struct snd_usb_endpoint *data_endpoint; struct snd_usb_endpoint *sync_endpoint; unsigned long flags; + bool need_setup_ep; /* (re)configure EP at prepare? */ u64 formats; /* format bitmasks (all or'ed) */ unsigned int num_formats; /* number of supported audio formats (list) */ diff --git a/sound/usb/pcm.c b/sound/usb/pcm.c index ae783d40f55a..55e19e1b80ec 100644 --- a/sound/usb/pcm.c +++ b/sound/usb/pcm.c @@ -510,6 +510,7 @@ static int snd_usb_hw_params(struct snd_pcm_substream *substream, subs->interface = fmt->iface; subs->altset_idx = fmt->altset_idx; + subs->need_setup_ep = true; return 0; } @@ -568,9 +569,12 @@ static int snd_usb_pcm_prepare(struct snd_pcm_substream *substream) if (ret < 0) return ret; - ret = configure_endpoint(subs); - if (ret < 0) - return ret; + if (subs->need_setup_ep) { + ret = configure_endpoint(subs); + if (ret < 0) + return ret; + subs->need_setup_ep = false; + } /* some unit conversions in runtime */ subs->data_endpoint->maxframesize = -- cgit v1.2.3 From c10514394ef9e8de93a4ad8c8904d71dcd82c122 Mon Sep 17 00:00:00 2001 From: David Henningsson Date: Thu, 20 Sep 2012 10:20:41 +0200 Subject: ALSA: usb - disable broken hw volume for Tenx TP6911 While going through Ubuntu bugs, I discovered this patch being posted and a confirmation that the patch works as expected. Finding out how the hw volume really works would be preferrable to just disabling the broken one, but this would be better than nothing. Credit: sndfnsdfin (qawsnews) BugLink: https://bugs.launchpad.net/bugs/559939 Signed-off-by: David Henningsson Signed-off-by: Takashi Iwai --- sound/usb/mixer.c | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'sound/usb') diff --git a/sound/usb/mixer.c b/sound/usb/mixer.c index 4f40ba823163..fe56c9da38e9 100644 --- a/sound/usb/mixer.c +++ b/sound/usb/mixer.c @@ -1267,6 +1267,13 @@ static int parse_audio_feature_unit(struct mixer_build *state, int unitid, void /* disable non-functional volume control */ master_bits &= ~UAC_CONTROL_BIT(UAC_FU_VOLUME); break; + case USB_ID(0x1130, 0xf211): + snd_printk(KERN_INFO + "usbmixer: volume control quirk for Tenx TP6911 Audio Headset\n"); + /* disable non-functional volume control */ + channels = 0; + break; + } if (channels > 0) first_ch_bits = snd_usb_combine_bytes(bmaControls + csize, csize); -- cgit v1.2.3