diff options
author | Linus Torvalds <torvalds@linux-foundation.org> | 2012-10-08 18:07:14 -0400 |
---|---|---|
committer | Linus Torvalds <torvalds@linux-foundation.org> | 2012-10-08 18:07:14 -0400 |
commit | f5a246eab9a268f51ba8189ea5b098a1bfff200e (patch) | |
tree | a6ff7169e0bcaca498d9aec8b0624de1b74eaecb /sound/usb | |
parent | d5bbd43d5f450c3fca058f5b85f3dfb4e8cc88c9 (diff) | |
parent | 7ff34ad80b7080fafaac8efa9ef0061708eddd51 (diff) |
Merge tag 'sound-3.7' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound
Pull sound updates from Takashi Iwai:
"This contains pretty many small commits covering fairly large range of
files in sound/ directory. Partly because of additional API support
and partly because of constantly developed ASoC and ARM stuff.
Some highlights:
- Introduced the helper function and documentation for exposing the
channel map via control API, as discussed in Plumbers; most of PCI
drivers are covered, will follow more drivers later
- Most of drivers have been replaced with the new PM callbacks (if
the bus is supported)
- HD-audio controller got the support of runtime PM and the support
of D3 clock-stop. Also changing the power_save option in sysfs
kicks off immediately to enable / disable the power-save mode.
- Another significant code change in HD-audio is the rewrite of
firmware loading code. Other than that, most of changes in
HD-audio are continued cleanups and standardization for the generic
auto parser and bug fixes (HBR, device-specific fixups), in
addition to the support of channel-map API.
- Addition of ASoC bindings for the compressed API, used by the
mid-x86 drivers.
- Lots of cleanups and API refreshes for ASoC codec drivers and
DaVinci.
- Conversion of OMAP to dmaengine.
- New machine driver for Wolfson Microelectronics Bells.
- New CODEC driver for Wolfson Microelectronics WM0010.
- Enhancements to the ux500 and wm2000 drivers
- A new driver for DA9055 and the support for regulator bypass mode."
Fix up various arm soc header file reorg conflicts.
* tag 'sound-3.7' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound: (339 commits)
ALSA: hda - Add new codec ALC283 ALC290 support
ALSA: hda - avoid unneccesary indices on "Headphone Jack" controls
ALSA: hda - fix indices on boost volume on Conexant
ALSA: aloop - add locking to timer access
ALSA: hda - Fix hang caused by race during suspend.
sound: Remove unnecessary semicolon
ALSA: hda/realtek - Fix detection of ALC271X codec
ALSA: hda - Add inverted internal mic quirk for Lenovo IdeaPad U310
ALSA: hda - make Realtek/Sigmatel/Conexant use the generic unsol event
ALSA: hda - make a generic unsol event handler
ASoC: codecs: Add DA9055 codec driver
ASoC: eukrea-tlv320: Convert it to platform driver
ALSA: ASoC: add DT bindings for CS4271
ASoC: wm_hubs: Ensure volume updates are handled during class W startup
ASoC: wm5110: Adding missing volume update bits
ASoC: wm5110: Add OUT3R support
ASoC: wm5110: Add AEC loopback support
ASoC: wm5110: Rename EPOUT to HPOUT3
ASoC: arizona: Add more clock rates
ASoC: arizona: Add more DSP options for mixer input muxes
...
Diffstat (limited to 'sound/usb')
-rw-r--r-- | sound/usb/6fire/firmware.c | 5 | ||||
-rw-r--r-- | sound/usb/card.c | 2 | ||||
-rw-r--r-- | sound/usb/card.h | 7 | ||||
-rw-r--r-- | sound/usb/endpoint.c | 39 | ||||
-rw-r--r-- | sound/usb/endpoint.h | 5 | ||||
-rw-r--r-- | sound/usb/helper.c | 5 | ||||
-rw-r--r-- | sound/usb/mixer.c | 7 | ||||
-rw-r--r-- | sound/usb/pcm.c | 126 | ||||
-rw-r--r-- | sound/usb/quirks-table.h | 53 | ||||
-rw-r--r-- | sound/usb/quirks.c | 24 | ||||
-rw-r--r-- | sound/usb/quirks.h | 10 |
11 files changed, 216 insertions, 67 deletions
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) | |||
346 | if (!memcmp(version, known_fw_versions + i, 4)) | 346 | if (!memcmp(version, known_fw_versions + i, 4)) |
347 | return 0; | 347 | return 0; |
348 | 348 | ||
349 | snd_printk(KERN_ERR PREFIX "invalid fimware version in device: " | 349 | snd_printk(KERN_ERR PREFIX "invalid fimware version in device: %*ph. " |
350 | "%02x %02x %02x %02x. " | ||
351 | "please reconnect to power. if this failure " | 350 | "please reconnect to power. if this failure " |
352 | "still happens, check your firmware installation.", | 351 | "still happens, check your firmware installation.", |
353 | version[0], version[1], version[2], version[3]); | 352 | 4, version); |
354 | return -EINVAL; | 353 | return -EINVAL; |
355 | } | 354 | } |
356 | 355 | ||
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) | |||
646 | list_for_each(p, &chip->pcm_list) { | 646 | list_for_each(p, &chip->pcm_list) { |
647 | as = list_entry(p, struct snd_usb_stream, list); | 647 | as = list_entry(p, struct snd_usb_stream, list); |
648 | snd_pcm_suspend_all(as->pcm); | 648 | snd_pcm_suspend_all(as->pcm); |
649 | as->substream[0].need_setup_ep = | ||
650 | as->substream[1].need_setup_ep = true; | ||
649 | } | 651 | } |
650 | } | 652 | } |
651 | } else { | 653 | } else { |
diff --git a/sound/usb/card.h b/sound/usb/card.h index 2b9fffff23b6..afa4f9e9b27a 100644 --- a/sound/usb/card.h +++ b/sound/usb/card.h | |||
@@ -92,6 +92,8 @@ struct snd_usb_endpoint { | |||
92 | unsigned char silence_value; | 92 | unsigned char silence_value; |
93 | unsigned int stride; | 93 | unsigned int stride; |
94 | int iface, alt_idx; | 94 | int iface, alt_idx; |
95 | int skip_packets; /* quirks for devices to ignore the first n packets | ||
96 | in a stream */ | ||
95 | 97 | ||
96 | spinlock_t lock; | 98 | spinlock_t lock; |
97 | struct list_head list; | 99 | struct list_head list; |
@@ -105,6 +107,8 @@ struct snd_usb_substream { | |||
105 | int interface; /* current interface */ | 107 | int interface; /* current interface */ |
106 | int endpoint; /* assigned endpoint */ | 108 | int endpoint; /* assigned endpoint */ |
107 | struct audioformat *cur_audiofmt; /* current audioformat pointer (for hw_params callback) */ | 109 | struct audioformat *cur_audiofmt; /* current audioformat pointer (for hw_params callback) */ |
110 | snd_pcm_format_t pcm_format; /* current audio format (for hw_params callback) */ | ||
111 | unsigned int channels; /* current number of channels (for hw_params callback) */ | ||
108 | unsigned int cur_rate; /* current rate (for hw_params callback) */ | 112 | unsigned int cur_rate; /* current rate (for hw_params callback) */ |
109 | unsigned int period_bytes; /* current period bytes (for hw_params callback) */ | 113 | unsigned int period_bytes; /* current period bytes (for hw_params callback) */ |
110 | unsigned int altset_idx; /* USB data format: index of alternate setting */ | 114 | unsigned int altset_idx; /* USB data format: index of alternate setting */ |
@@ -115,14 +119,13 @@ struct snd_usb_substream { | |||
115 | 119 | ||
116 | unsigned int hwptr_done; /* processed byte position in the buffer */ | 120 | unsigned int hwptr_done; /* processed byte position in the buffer */ |
117 | unsigned int transfer_done; /* processed frames since last period update */ | 121 | unsigned int transfer_done; /* processed frames since last period update */ |
118 | unsigned long active_mask; /* bitmask of active urbs */ | ||
119 | unsigned long unlink_mask; /* bitmask of unlinked urbs */ | ||
120 | 122 | ||
121 | /* data and sync endpoints for this stream */ | 123 | /* data and sync endpoints for this stream */ |
122 | unsigned int ep_num; /* the endpoint number */ | 124 | unsigned int ep_num; /* the endpoint number */ |
123 | struct snd_usb_endpoint *data_endpoint; | 125 | struct snd_usb_endpoint *data_endpoint; |
124 | struct snd_usb_endpoint *sync_endpoint; | 126 | struct snd_usb_endpoint *sync_endpoint; |
125 | unsigned long flags; | 127 | unsigned long flags; |
128 | bool need_setup_ep; /* (re)configure EP at prepare? */ | ||
126 | 129 | ||
127 | u64 formats; /* format bitmasks (all or'ed) */ | 130 | u64 formats; /* format bitmasks (all or'ed) */ |
128 | unsigned int num_formats; /* number of supported audio formats (list) */ | 131 | unsigned int num_formats; /* number of supported audio formats (list) */ |
diff --git a/sound/usb/endpoint.c b/sound/usb/endpoint.c index 060dccb9ec75..7f78c6d782b0 100644 --- a/sound/usb/endpoint.c +++ b/sound/usb/endpoint.c | |||
@@ -31,6 +31,7 @@ | |||
31 | #include "card.h" | 31 | #include "card.h" |
32 | #include "endpoint.h" | 32 | #include "endpoint.h" |
33 | #include "pcm.h" | 33 | #include "pcm.h" |
34 | #include "quirks.h" | ||
34 | 35 | ||
35 | #define EP_FLAG_ACTIVATED 0 | 36 | #define EP_FLAG_ACTIVATED 0 |
36 | #define EP_FLAG_RUNNING 1 | 37 | #define EP_FLAG_RUNNING 1 |
@@ -170,6 +171,11 @@ static void retire_inbound_urb(struct snd_usb_endpoint *ep, | |||
170 | { | 171 | { |
171 | struct urb *urb = urb_ctx->urb; | 172 | struct urb *urb = urb_ctx->urb; |
172 | 173 | ||
174 | if (unlikely(ep->skip_packets > 0)) { | ||
175 | ep->skip_packets--; | ||
176 | return; | ||
177 | } | ||
178 | |||
173 | if (ep->sync_slave) | 179 | if (ep->sync_slave) |
174 | snd_usb_handle_sync_urb(ep->sync_slave, ep, urb); | 180 | snd_usb_handle_sync_urb(ep->sync_slave, ep, urb); |
175 | 181 | ||
@@ -567,20 +573,19 @@ static void release_urbs(struct snd_usb_endpoint *ep, int force) | |||
567 | * configure a data endpoint | 573 | * configure a data endpoint |
568 | */ | 574 | */ |
569 | static int data_ep_set_params(struct snd_usb_endpoint *ep, | 575 | static int data_ep_set_params(struct snd_usb_endpoint *ep, |
570 | struct snd_pcm_hw_params *hw_params, | 576 | snd_pcm_format_t pcm_format, |
577 | unsigned int channels, | ||
578 | unsigned int period_bytes, | ||
571 | struct audioformat *fmt, | 579 | struct audioformat *fmt, |
572 | struct snd_usb_endpoint *sync_ep) | 580 | struct snd_usb_endpoint *sync_ep) |
573 | { | 581 | { |
574 | unsigned int maxsize, i, urb_packs, total_packs, packs_per_ms; | 582 | unsigned int maxsize, i, urb_packs, total_packs, packs_per_ms; |
575 | int period_bytes = params_period_bytes(hw_params); | ||
576 | int format = params_format(hw_params); | ||
577 | int is_playback = usb_pipeout(ep->pipe); | 583 | int is_playback = usb_pipeout(ep->pipe); |
578 | int frame_bits = snd_pcm_format_physical_width(params_format(hw_params)) * | 584 | int frame_bits = snd_pcm_format_physical_width(pcm_format) * channels; |
579 | params_channels(hw_params); | ||
580 | 585 | ||
581 | ep->datainterval = fmt->datainterval; | 586 | ep->datainterval = fmt->datainterval; |
582 | ep->stride = frame_bits >> 3; | 587 | ep->stride = frame_bits >> 3; |
583 | ep->silence_value = format == SNDRV_PCM_FORMAT_U8 ? 0x80 : 0; | 588 | ep->silence_value = pcm_format == SNDRV_PCM_FORMAT_U8 ? 0x80 : 0; |
584 | 589 | ||
585 | /* calculate max. frequency */ | 590 | /* calculate max. frequency */ |
586 | if (ep->maxpacksize) { | 591 | if (ep->maxpacksize) { |
@@ -693,7 +698,6 @@ out_of_memory: | |||
693 | * configure a sync endpoint | 698 | * configure a sync endpoint |
694 | */ | 699 | */ |
695 | static int sync_ep_set_params(struct snd_usb_endpoint *ep, | 700 | static int sync_ep_set_params(struct snd_usb_endpoint *ep, |
696 | struct snd_pcm_hw_params *hw_params, | ||
697 | struct audioformat *fmt) | 701 | struct audioformat *fmt) |
698 | { | 702 | { |
699 | int i; | 703 | int i; |
@@ -736,7 +740,10 @@ out_of_memory: | |||
736 | * snd_usb_endpoint_set_params: configure an snd_usb_endpoint | 740 | * snd_usb_endpoint_set_params: configure an snd_usb_endpoint |
737 | * | 741 | * |
738 | * @ep: the snd_usb_endpoint to configure | 742 | * @ep: the snd_usb_endpoint to configure |
739 | * @hw_params: the hardware parameters | 743 | * @pcm_format: the audio fomat. |
744 | * @channels: the number of audio channels. | ||
745 | * @period_bytes: the number of bytes in one alsa period. | ||
746 | * @rate: the frame rate. | ||
740 | * @fmt: the USB audio format information | 747 | * @fmt: the USB audio format information |
741 | * @sync_ep: the sync endpoint to use, if any | 748 | * @sync_ep: the sync endpoint to use, if any |
742 | * | 749 | * |
@@ -745,7 +752,10 @@ out_of_memory: | |||
745 | * An endpoint that is already running can not be reconfigured. | 752 | * An endpoint that is already running can not be reconfigured. |
746 | */ | 753 | */ |
747 | int snd_usb_endpoint_set_params(struct snd_usb_endpoint *ep, | 754 | int snd_usb_endpoint_set_params(struct snd_usb_endpoint *ep, |
748 | struct snd_pcm_hw_params *hw_params, | 755 | snd_pcm_format_t pcm_format, |
756 | unsigned int channels, | ||
757 | unsigned int period_bytes, | ||
758 | unsigned int rate, | ||
749 | struct audioformat *fmt, | 759 | struct audioformat *fmt, |
750 | struct snd_usb_endpoint *sync_ep) | 760 | struct snd_usb_endpoint *sync_ep) |
751 | { | 761 | { |
@@ -765,9 +775,9 @@ int snd_usb_endpoint_set_params(struct snd_usb_endpoint *ep, | |||
765 | ep->fill_max = !!(fmt->attributes & UAC_EP_CS_ATTR_FILL_MAX); | 775 | ep->fill_max = !!(fmt->attributes & UAC_EP_CS_ATTR_FILL_MAX); |
766 | 776 | ||
767 | if (snd_usb_get_speed(ep->chip->dev) == USB_SPEED_FULL) | 777 | if (snd_usb_get_speed(ep->chip->dev) == USB_SPEED_FULL) |
768 | ep->freqn = get_usb_full_speed_rate(params_rate(hw_params)); | 778 | ep->freqn = get_usb_full_speed_rate(rate); |
769 | else | 779 | else |
770 | ep->freqn = get_usb_high_speed_rate(params_rate(hw_params)); | 780 | ep->freqn = get_usb_high_speed_rate(rate); |
771 | 781 | ||
772 | /* calculate the frequency in 16.16 format */ | 782 | /* calculate the frequency in 16.16 format */ |
773 | ep->freqm = ep->freqn; | 783 | ep->freqm = ep->freqn; |
@@ -777,10 +787,11 @@ int snd_usb_endpoint_set_params(struct snd_usb_endpoint *ep, | |||
777 | 787 | ||
778 | switch (ep->type) { | 788 | switch (ep->type) { |
779 | case SND_USB_ENDPOINT_TYPE_DATA: | 789 | case SND_USB_ENDPOINT_TYPE_DATA: |
780 | err = data_ep_set_params(ep, hw_params, fmt, sync_ep); | 790 | err = data_ep_set_params(ep, pcm_format, channels, |
791 | period_bytes, fmt, sync_ep); | ||
781 | break; | 792 | break; |
782 | case SND_USB_ENDPOINT_TYPE_SYNC: | 793 | case SND_USB_ENDPOINT_TYPE_SYNC: |
783 | err = sync_ep_set_params(ep, hw_params, fmt); | 794 | err = sync_ep_set_params(ep, fmt); |
784 | break; | 795 | break; |
785 | default: | 796 | default: |
786 | err = -EINVAL; | 797 | err = -EINVAL; |
@@ -828,6 +839,8 @@ int snd_usb_endpoint_start(struct snd_usb_endpoint *ep, int can_sleep) | |||
828 | ep->unlink_mask = 0; | 839 | ep->unlink_mask = 0; |
829 | ep->phase = 0; | 840 | ep->phase = 0; |
830 | 841 | ||
842 | snd_usb_endpoint_start_quirk(ep); | ||
843 | |||
831 | /* | 844 | /* |
832 | * If this endpoint has a data endpoint as implicit feedback source, | 845 | * If this endpoint has a data endpoint as implicit feedback source, |
833 | * don't start the urbs here. Instead, mark them all as available, | 846 | * don't start the urbs here. Instead, mark them all as available, |
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, | |||
9 | int ep_num, int direction, int type); | 9 | int ep_num, int direction, int type); |
10 | 10 | ||
11 | int snd_usb_endpoint_set_params(struct snd_usb_endpoint *ep, | 11 | int snd_usb_endpoint_set_params(struct snd_usb_endpoint *ep, |
12 | struct snd_pcm_hw_params *hw_params, | 12 | snd_pcm_format_t pcm_format, |
13 | unsigned int channels, | ||
14 | unsigned int period_bytes, | ||
15 | unsigned int rate, | ||
13 | struct audioformat *fmt, | 16 | struct audioformat *fmt, |
14 | struct snd_usb_endpoint *sync_ep); | 17 | struct snd_usb_endpoint *sync_ep); |
15 | 18 | ||
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 @@ | |||
21 | 21 | ||
22 | #include "usbaudio.h" | 22 | #include "usbaudio.h" |
23 | #include "helper.h" | 23 | #include "helper.h" |
24 | #include "quirks.h" | ||
24 | 25 | ||
25 | /* | 26 | /* |
26 | * combine bytes and get an integer value | 27 | * 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, | |||
97 | memcpy(data, buf, size); | 98 | memcpy(data, buf, size); |
98 | kfree(buf); | 99 | kfree(buf); |
99 | } | 100 | } |
101 | |||
102 | snd_usb_ctl_msg_quirk(dev, pipe, request, requesttype, | ||
103 | value, index, data, size); | ||
104 | |||
100 | return err; | 105 | return err; |
101 | } | 106 | } |
102 | 107 | ||
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 | |||
1267 | /* disable non-functional volume control */ | 1267 | /* disable non-functional volume control */ |
1268 | master_bits &= ~UAC_CONTROL_BIT(UAC_FU_VOLUME); | 1268 | master_bits &= ~UAC_CONTROL_BIT(UAC_FU_VOLUME); |
1269 | break; | 1269 | break; |
1270 | case USB_ID(0x1130, 0xf211): | ||
1271 | snd_printk(KERN_INFO | ||
1272 | "usbmixer: volume control quirk for Tenx TP6911 Audio Headset\n"); | ||
1273 | /* disable non-functional volume control */ | ||
1274 | channels = 0; | ||
1275 | break; | ||
1276 | |||
1270 | } | 1277 | } |
1271 | if (channels > 0) | 1278 | if (channels > 0) |
1272 | first_ch_bits = snd_usb_combine_bytes(bmaControls + csize, csize); | 1279 | first_ch_bits = snd_usb_combine_bytes(bmaControls + csize, csize); |
diff --git a/sound/usb/pcm.c b/sound/usb/pcm.c index f782ce19bf5a..55e19e1b80ec 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 | |||
82 | /* | 82 | /* |
83 | * find a matching audio format | 83 | * find a matching audio format |
84 | */ | 84 | */ |
85 | static struct audioformat *find_format(struct snd_usb_substream *subs, unsigned int format, | 85 | static struct audioformat *find_format(struct snd_usb_substream *subs) |
86 | unsigned int rate, unsigned int channels) | ||
87 | { | 86 | { |
88 | struct list_head *p; | 87 | struct list_head *p; |
89 | struct audioformat *found = NULL; | 88 | struct audioformat *found = NULL; |
@@ -92,16 +91,17 @@ static struct audioformat *find_format(struct snd_usb_substream *subs, unsigned | |||
92 | list_for_each(p, &subs->fmt_list) { | 91 | list_for_each(p, &subs->fmt_list) { |
93 | struct audioformat *fp; | 92 | struct audioformat *fp; |
94 | fp = list_entry(p, struct audioformat, list); | 93 | fp = list_entry(p, struct audioformat, list); |
95 | if (!(fp->formats & (1uLL << format))) | 94 | if (!(fp->formats & (1uLL << subs->pcm_format))) |
96 | continue; | 95 | continue; |
97 | if (fp->channels != channels) | 96 | if (fp->channels != subs->channels) |
98 | continue; | 97 | continue; |
99 | if (rate < fp->rate_min || rate > fp->rate_max) | 98 | if (subs->cur_rate < fp->rate_min || |
99 | subs->cur_rate > fp->rate_max) | ||
100 | continue; | 100 | continue; |
101 | if (! (fp->rates & SNDRV_PCM_RATE_CONTINUOUS)) { | 101 | if (! (fp->rates & SNDRV_PCM_RATE_CONTINUOUS)) { |
102 | unsigned int i; | 102 | unsigned int i; |
103 | for (i = 0; i < fp->nr_rates; i++) | 103 | for (i = 0; i < fp->nr_rates; i++) |
104 | if (fp->rate_table[i] == rate) | 104 | if (fp->rate_table[i] == subs->cur_rate) |
105 | break; | 105 | break; |
106 | if (i >= fp->nr_rates) | 106 | if (i >= fp->nr_rates) |
107 | continue; | 107 | continue; |
@@ -436,6 +436,42 @@ add_sync_ep: | |||
436 | } | 436 | } |
437 | 437 | ||
438 | /* | 438 | /* |
439 | * configure endpoint params | ||
440 | * | ||
441 | * called during initial setup and upon resume | ||
442 | */ | ||
443 | static int configure_endpoint(struct snd_usb_substream *subs) | ||
444 | { | ||
445 | int ret; | ||
446 | |||
447 | mutex_lock(&subs->stream->chip->shutdown_mutex); | ||
448 | /* format changed */ | ||
449 | stop_endpoints(subs, 0, 0, 0); | ||
450 | ret = snd_usb_endpoint_set_params(subs->data_endpoint, | ||
451 | subs->pcm_format, | ||
452 | subs->channels, | ||
453 | subs->period_bytes, | ||
454 | subs->cur_rate, | ||
455 | subs->cur_audiofmt, | ||
456 | subs->sync_endpoint); | ||
457 | if (ret < 0) | ||
458 | goto unlock; | ||
459 | |||
460 | if (subs->sync_endpoint) | ||
461 | ret = snd_usb_endpoint_set_params(subs->data_endpoint, | ||
462 | subs->pcm_format, | ||
463 | subs->channels, | ||
464 | subs->period_bytes, | ||
465 | subs->cur_rate, | ||
466 | subs->cur_audiofmt, | ||
467 | NULL); | ||
468 | |||
469 | unlock: | ||
470 | mutex_unlock(&subs->stream->chip->shutdown_mutex); | ||
471 | return ret; | ||
472 | } | ||
473 | |||
474 | /* | ||
439 | * hw_params callback | 475 | * hw_params callback |
440 | * | 476 | * |
441 | * allocate a buffer and set the given audio format. | 477 | * allocate a buffer and set the given audio format. |
@@ -450,63 +486,33 @@ static int snd_usb_hw_params(struct snd_pcm_substream *substream, | |||
450 | { | 486 | { |
451 | struct snd_usb_substream *subs = substream->runtime->private_data; | 487 | struct snd_usb_substream *subs = substream->runtime->private_data; |
452 | struct audioformat *fmt; | 488 | struct audioformat *fmt; |
453 | unsigned int channels, rate, format; | 489 | int ret; |
454 | int ret, changed; | ||
455 | 490 | ||
456 | ret = snd_pcm_lib_alloc_vmalloc_buffer(substream, | 491 | ret = snd_pcm_lib_alloc_vmalloc_buffer(substream, |
457 | params_buffer_bytes(hw_params)); | 492 | params_buffer_bytes(hw_params)); |
458 | if (ret < 0) | 493 | if (ret < 0) |
459 | return ret; | 494 | return ret; |
460 | 495 | ||
461 | format = params_format(hw_params); | 496 | subs->pcm_format = params_format(hw_params); |
462 | rate = params_rate(hw_params); | 497 | subs->period_bytes = params_period_bytes(hw_params); |
463 | channels = params_channels(hw_params); | 498 | subs->channels = params_channels(hw_params); |
464 | fmt = find_format(subs, format, rate, channels); | 499 | subs->cur_rate = params_rate(hw_params); |
500 | |||
501 | fmt = find_format(subs); | ||
465 | if (!fmt) { | 502 | if (!fmt) { |
466 | snd_printd(KERN_DEBUG "cannot set format: format = %#x, rate = %d, channels = %d\n", | 503 | snd_printd(KERN_DEBUG "cannot set format: format = %#x, rate = %d, channels = %d\n", |
467 | format, rate, channels); | 504 | subs->pcm_format, subs->cur_rate, subs->channels); |
468 | return -EINVAL; | 505 | return -EINVAL; |
469 | } | 506 | } |
470 | 507 | ||
471 | changed = subs->cur_audiofmt != fmt || | ||
472 | subs->period_bytes != params_period_bytes(hw_params) || | ||
473 | subs->cur_rate != rate; | ||
474 | if ((ret = set_format(subs, fmt)) < 0) | 508 | if ((ret = set_format(subs, fmt)) < 0) |
475 | return ret; | 509 | return ret; |
476 | 510 | ||
477 | if (subs->cur_rate != rate) { | 511 | subs->interface = fmt->iface; |
478 | struct usb_host_interface *alts; | 512 | subs->altset_idx = fmt->altset_idx; |
479 | struct usb_interface *iface; | 513 | subs->need_setup_ep = true; |
480 | iface = usb_ifnum_to_if(subs->dev, fmt->iface); | ||
481 | alts = &iface->altsetting[fmt->altset_idx]; | ||
482 | ret = snd_usb_init_sample_rate(subs->stream->chip, fmt->iface, alts, fmt, rate); | ||
483 | if (ret < 0) | ||
484 | return ret; | ||
485 | subs->cur_rate = rate; | ||
486 | } | ||
487 | |||
488 | if (changed) { | ||
489 | mutex_lock(&subs->stream->chip->shutdown_mutex); | ||
490 | /* format changed */ | ||
491 | stop_endpoints(subs, 0, 0, 0); | ||
492 | ret = snd_usb_endpoint_set_params(subs->data_endpoint, hw_params, fmt, | ||
493 | subs->sync_endpoint); | ||
494 | if (ret < 0) | ||
495 | goto unlock; | ||
496 | 514 | ||
497 | if (subs->sync_endpoint) | 515 | return 0; |
498 | ret = snd_usb_endpoint_set_params(subs->sync_endpoint, | ||
499 | hw_params, fmt, NULL); | ||
500 | unlock: | ||
501 | mutex_unlock(&subs->stream->chip->shutdown_mutex); | ||
502 | } | ||
503 | |||
504 | if (ret == 0) { | ||
505 | subs->interface = fmt->iface; | ||
506 | subs->altset_idx = fmt->altset_idx; | ||
507 | } | ||
508 | |||
509 | return ret; | ||
510 | } | 516 | } |
511 | 517 | ||
512 | /* | 518 | /* |
@@ -537,6 +543,9 @@ static int snd_usb_pcm_prepare(struct snd_pcm_substream *substream) | |||
537 | { | 543 | { |
538 | struct snd_pcm_runtime *runtime = substream->runtime; | 544 | struct snd_pcm_runtime *runtime = substream->runtime; |
539 | struct snd_usb_substream *subs = runtime->private_data; | 545 | struct snd_usb_substream *subs = runtime->private_data; |
546 | struct usb_host_interface *alts; | ||
547 | struct usb_interface *iface; | ||
548 | int ret; | ||
540 | 549 | ||
541 | if (! subs->cur_audiofmt) { | 550 | if (! subs->cur_audiofmt) { |
542 | snd_printk(KERN_ERR "usbaudio: no format is specified!\n"); | 551 | snd_printk(KERN_ERR "usbaudio: no format is specified!\n"); |
@@ -546,6 +555,27 @@ static int snd_usb_pcm_prepare(struct snd_pcm_substream *substream) | |||
546 | if (snd_BUG_ON(!subs->data_endpoint)) | 555 | if (snd_BUG_ON(!subs->data_endpoint)) |
547 | return -EIO; | 556 | return -EIO; |
548 | 557 | ||
558 | ret = set_format(subs, subs->cur_audiofmt); | ||
559 | if (ret < 0) | ||
560 | return ret; | ||
561 | |||
562 | iface = usb_ifnum_to_if(subs->dev, subs->cur_audiofmt->iface); | ||
563 | alts = &iface->altsetting[subs->cur_audiofmt->altset_idx]; | ||
564 | ret = snd_usb_init_sample_rate(subs->stream->chip, | ||
565 | subs->cur_audiofmt->iface, | ||
566 | alts, | ||
567 | subs->cur_audiofmt, | ||
568 | subs->cur_rate); | ||
569 | if (ret < 0) | ||
570 | return ret; | ||
571 | |||
572 | if (subs->need_setup_ep) { | ||
573 | ret = configure_endpoint(subs); | ||
574 | if (ret < 0) | ||
575 | return ret; | ||
576 | subs->need_setup_ep = false; | ||
577 | } | ||
578 | |||
549 | /* some unit conversions in runtime */ | 579 | /* some unit conversions in runtime */ |
550 | subs->data_endpoint->maxframesize = | 580 | subs->data_endpoint->maxframesize = |
551 | bytes_to_frames(runtime, subs->data_endpoint->maxpacksize); | 581 | bytes_to_frames(runtime, subs->data_endpoint->maxpacksize); |
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"), | |||
2781 | } | 2781 | } |
2782 | }, | 2782 | }, |
2783 | 2783 | ||
2784 | /* Microsoft XboxLive Headset/Xbox Communicator */ | ||
2785 | { | ||
2786 | USB_DEVICE(0x045e, 0x0283), | ||
2787 | .bInterfaceClass = USB_CLASS_PER_INTERFACE, | ||
2788 | .driver_info = (unsigned long) &(const struct snd_usb_audio_quirk) { | ||
2789 | .vendor_name = "Microsoft", | ||
2790 | .product_name = "XboxLive Headset/Xbox Communicator", | ||
2791 | .ifnum = QUIRK_ANY_INTERFACE, | ||
2792 | .type = QUIRK_COMPOSITE, | ||
2793 | .data = &(const struct snd_usb_audio_quirk[]) { | ||
2794 | { | ||
2795 | /* playback */ | ||
2796 | .ifnum = 0, | ||
2797 | .type = QUIRK_AUDIO_FIXED_ENDPOINT, | ||
2798 | .data = &(const struct audioformat) { | ||
2799 | .formats = SNDRV_PCM_FMTBIT_S16_LE, | ||
2800 | .channels = 1, | ||
2801 | .iface = 0, | ||
2802 | .altsetting = 0, | ||
2803 | .altset_idx = 0, | ||
2804 | .attributes = 0, | ||
2805 | .endpoint = 0x04, | ||
2806 | .ep_attr = 0x05, | ||
2807 | .rates = SNDRV_PCM_RATE_CONTINUOUS, | ||
2808 | .rate_min = 22050, | ||
2809 | .rate_max = 22050 | ||
2810 | } | ||
2811 | }, | ||
2812 | { | ||
2813 | /* capture */ | ||
2814 | .ifnum = 1, | ||
2815 | .type = QUIRK_AUDIO_FIXED_ENDPOINT, | ||
2816 | .data = &(const struct audioformat) { | ||
2817 | .formats = SNDRV_PCM_FMTBIT_S16_LE, | ||
2818 | .channels = 1, | ||
2819 | .iface = 1, | ||
2820 | .altsetting = 0, | ||
2821 | .altset_idx = 0, | ||
2822 | .attributes = 0, | ||
2823 | .endpoint = 0x85, | ||
2824 | .ep_attr = 0x05, | ||
2825 | .rates = SNDRV_PCM_RATE_CONTINUOUS, | ||
2826 | .rate_min = 16000, | ||
2827 | .rate_max = 16000 | ||
2828 | } | ||
2829 | }, | ||
2830 | { | ||
2831 | .ifnum = -1 | ||
2832 | } | ||
2833 | } | ||
2834 | } | ||
2835 | }, | ||
2836 | |||
2784 | { | 2837 | { |
2785 | /* | 2838 | /* |
2786 | * Some USB MIDI devices don't have an audio control interface, | 2839 | * Some USB MIDI devices don't have an audio control interface, |
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, | |||
761 | } | 761 | } |
762 | } | 762 | } |
763 | 763 | ||
764 | void snd_usb_endpoint_start_quirk(struct snd_usb_endpoint *ep) | ||
765 | { | ||
766 | /* | ||
767 | * "Playback Design" products send bogus feedback data at the start | ||
768 | * of the stream. Ignore them. | ||
769 | */ | ||
770 | if ((le16_to_cpu(ep->chip->dev->descriptor.idVendor) == 0x23ba) && | ||
771 | ep->type == SND_USB_ENDPOINT_TYPE_SYNC) | ||
772 | ep->skip_packets = 4; | ||
773 | } | ||
774 | |||
775 | void snd_usb_ctl_msg_quirk(struct usb_device *dev, unsigned int pipe, | ||
776 | __u8 request, __u8 requesttype, __u16 value, | ||
777 | __u16 index, void *data, __u16 size) | ||
778 | { | ||
779 | /* | ||
780 | * "Playback Design" products need a 20ms delay after each | ||
781 | * class compliant request | ||
782 | */ | ||
783 | if ((le16_to_cpu(dev->descriptor.idVendor) == 0x23ba) && | ||
784 | (requesttype & USB_TYPE_MASK) == USB_TYPE_CLASS) | ||
785 | mdelay(20); | ||
786 | } | ||
787 | |||
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 @@ | |||
1 | #ifndef __USBAUDIO_QUIRKS_H | 1 | #ifndef __USBAUDIO_QUIRKS_H |
2 | #define __USBAUDIO_QUIRKS_H | 2 | #define __USBAUDIO_QUIRKS_H |
3 | 3 | ||
4 | struct audioformat; | ||
5 | struct snd_usb_endpoint; | ||
6 | struct snd_usb_substream; | ||
7 | |||
4 | int snd_usb_create_quirk(struct snd_usb_audio *chip, | 8 | int snd_usb_create_quirk(struct snd_usb_audio *chip, |
5 | struct usb_interface *iface, | 9 | struct usb_interface *iface, |
6 | struct usb_driver *driver, | 10 | struct usb_driver *driver, |
@@ -20,4 +24,10 @@ void snd_usb_set_format_quirk(struct snd_usb_substream *subs, | |||
20 | int snd_usb_is_big_endian_format(struct snd_usb_audio *chip, | 24 | int snd_usb_is_big_endian_format(struct snd_usb_audio *chip, |
21 | struct audioformat *fp); | 25 | struct audioformat *fp); |
22 | 26 | ||
27 | void snd_usb_endpoint_start_quirk(struct snd_usb_endpoint *ep); | ||
28 | |||
29 | void snd_usb_ctl_msg_quirk(struct usb_device *dev, unsigned int pipe, | ||
30 | __u8 request, __u8 requesttype, __u16 value, | ||
31 | __u16 index, void *data, __u16 size); | ||
32 | |||
23 | #endif /* __USBAUDIO_QUIRKS_H */ | 33 | #endif /* __USBAUDIO_QUIRKS_H */ |