diff options
| author | Linus Torvalds <torvalds@linux-foundation.org> | 2010-06-04 12:48:03 -0400 |
|---|---|---|
| committer | Linus Torvalds <torvalds@linux-foundation.org> | 2010-06-04 12:48:03 -0400 |
| commit | bc23416cd4579093acc1e7d819eee747def623da (patch) | |
| tree | 4fab11d6dac818927e5d80c5fddcf903412dd4fc | |
| parent | ad8456361fa19068cf49b50a4f98e41b73c08e76 (diff) | |
| parent | d4376802999d478a103868d7e7b1f473e4a387af (diff) | |
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound-2.6
* 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound-2.6:
ALSA: hda-intel - fix wallclk variable update and condition
ALSA: asihpi - Fix uninitialized variable
ALSA: hda: Use LPIB for ASUS M2V
usb/gadget: Replace the old USB audio FU definitions in f_audio.c
ASoC: MX31ads sound support should depend on MACH_MX31ADS_WM1133_EV1
ASoC: Add missing Kconfig entry for Phytec boards
ALSA: usb-audio: export UAC2 clock selectors as mixer controls
ALSA: usb-audio: clean up find_audio_control_unit()
ALSA: usb-audio: add UAC2 sepecific Feature Unit controls
ALSA: usb-audio: unify constants from specification
ALSA: usb-audio: parse clock topology of UAC2 devices
ALSA: usb-audio: fix selector unit string index accessor
include/linux/usb/audio-v2.h: add more UAC2 details
ALSA: usb-audio: support partially write-protected UAC2 controls
ALSA: usb-audio: UAC2: clean up parsing of bmaControls
ALSA: hda: Use LPIB for another mainboard
ALSA: hda: Use mb31 quirk for an iMac model
ALSA: hda: Use LPIB for an ASUS device
| -rw-r--r-- | drivers/usb/gadget/f_audio.c | 4 | ||||
| -rw-r--r-- | include/linux/usb/audio-v2.h | 31 | ||||
| -rw-r--r-- | include/linux/usb/audio.h | 90 | ||||
| -rw-r--r-- | sound/pci/asihpi/asihpi.c | 3 | ||||
| -rw-r--r-- | sound/pci/hda/hda_intel.c | 7 | ||||
| -rw-r--r-- | sound/pci/hda/patch_realtek.c | 1 | ||||
| -rw-r--r-- | sound/soc/imx/Kconfig | 11 | ||||
| -rw-r--r-- | sound/usb/Makefile | 3 | ||||
| -rw-r--r-- | sound/usb/card.c | 18 | ||||
| -rw-r--r-- | sound/usb/card.h | 1 | ||||
| -rw-r--r-- | sound/usb/clock.c | 311 | ||||
| -rw-r--r-- | sound/usb/clock.h | 12 | ||||
| -rw-r--r-- | sound/usb/endpoint.c | 57 | ||||
| -rw-r--r-- | sound/usb/format.c | 16 | ||||
| -rw-r--r-- | sound/usb/mixer.c | 213 | ||||
| -rw-r--r-- | sound/usb/mixer.h | 2 | ||||
| -rw-r--r-- | sound/usb/mixer_maps.c | 4 | ||||
| -rw-r--r-- | sound/usb/pcm.c | 98 | ||||
| -rw-r--r-- | sound/usb/usbaudio.h | 5 |
19 files changed, 631 insertions, 256 deletions
diff --git a/drivers/usb/gadget/f_audio.c b/drivers/usb/gadget/f_audio.c index 43bf44514c41..b91115f84b13 100644 --- a/drivers/usb/gadget/f_audio.c +++ b/drivers/usb/gadget/f_audio.c | |||
| @@ -101,7 +101,7 @@ static struct uac_feature_unit_descriptor_0 feature_unit_desc = { | |||
| 101 | static struct usb_audio_control mute_control = { | 101 | static struct usb_audio_control mute_control = { |
| 102 | .list = LIST_HEAD_INIT(mute_control.list), | 102 | .list = LIST_HEAD_INIT(mute_control.list), |
| 103 | .name = "Mute Control", | 103 | .name = "Mute Control", |
| 104 | .type = UAC_MUTE_CONTROL, | 104 | .type = UAC_FU_MUTE, |
| 105 | /* Todo: add real Mute control code */ | 105 | /* Todo: add real Mute control code */ |
| 106 | .set = generic_set_cmd, | 106 | .set = generic_set_cmd, |
| 107 | .get = generic_get_cmd, | 107 | .get = generic_get_cmd, |
| @@ -110,7 +110,7 @@ static struct usb_audio_control mute_control = { | |||
| 110 | static struct usb_audio_control volume_control = { | 110 | static struct usb_audio_control volume_control = { |
| 111 | .list = LIST_HEAD_INIT(volume_control.list), | 111 | .list = LIST_HEAD_INIT(volume_control.list), |
| 112 | .name = "Volume Control", | 112 | .name = "Volume Control", |
| 113 | .type = UAC_VOLUME_CONTROL, | 113 | .type = UAC_FU_VOLUME, |
| 114 | /* Todo: add real Volume control code */ | 114 | /* Todo: add real Volume control code */ |
| 115 | .set = generic_set_cmd, | 115 | .set = generic_set_cmd, |
| 116 | .get = generic_get_cmd, | 116 | .get = generic_get_cmd, |
diff --git a/include/linux/usb/audio-v2.h b/include/linux/usb/audio-v2.h index 92f1d99f0f17..383b94ba8c20 100644 --- a/include/linux/usb/audio-v2.h +++ b/include/linux/usb/audio-v2.h | |||
| @@ -18,6 +18,16 @@ | |||
| 18 | /* v1.0 and v2.0 of this standard have many things in common. For the rest | 18 | /* v1.0 and v2.0 of this standard have many things in common. For the rest |
| 19 | * of the definitions, please refer to audio.h */ | 19 | * of the definitions, please refer to audio.h */ |
| 20 | 20 | ||
| 21 | static inline bool uac2_control_is_readable(u32 bmControls, u8 control) | ||
| 22 | { | ||
| 23 | return (bmControls >> (control * 2)) & 0x1; | ||
| 24 | } | ||
| 25 | |||
| 26 | static inline bool uac2_control_is_writeable(u32 bmControls, u8 control) | ||
| 27 | { | ||
| 28 | return (bmControls >> (control * 2)) & 0x2; | ||
| 29 | } | ||
| 30 | |||
| 21 | /* 4.7.2.1 Clock Source Descriptor */ | 31 | /* 4.7.2.1 Clock Source Descriptor */ |
| 22 | 32 | ||
| 23 | struct uac_clock_source_descriptor { | 33 | struct uac_clock_source_descriptor { |
| @@ -31,6 +41,13 @@ struct uac_clock_source_descriptor { | |||
| 31 | __u8 iClockSource; | 41 | __u8 iClockSource; |
| 32 | } __attribute__((packed)); | 42 | } __attribute__((packed)); |
| 33 | 43 | ||
| 44 | /* bmAttribute fields */ | ||
| 45 | #define UAC_CLOCK_SOURCE_TYPE_EXT 0x0 | ||
| 46 | #define UAC_CLOCK_SOURCE_TYPE_INT_FIXED 0x1 | ||
| 47 | #define UAC_CLOCK_SOURCE_TYPE_INT_VAR 0x2 | ||
| 48 | #define UAC_CLOCK_SOURCE_TYPE_INT_PROG 0x3 | ||
| 49 | #define UAC_CLOCK_SOURCE_SYNCED_TO_SOF (1 << 2) | ||
| 50 | |||
| 34 | /* 4.7.2.2 Clock Source Descriptor */ | 51 | /* 4.7.2.2 Clock Source Descriptor */ |
| 35 | 52 | ||
| 36 | struct uac_clock_selector_descriptor { | 53 | struct uac_clock_selector_descriptor { |
| @@ -39,8 +56,20 @@ struct uac_clock_selector_descriptor { | |||
| 39 | __u8 bDescriptorSubtype; | 56 | __u8 bDescriptorSubtype; |
| 40 | __u8 bClockID; | 57 | __u8 bClockID; |
| 41 | __u8 bNrInPins; | 58 | __u8 bNrInPins; |
| 42 | __u8 bmControls; | ||
| 43 | __u8 baCSourceID[]; | 59 | __u8 baCSourceID[]; |
| 60 | /* bmControls, bAssocTerminal and iClockSource omitted */ | ||
| 61 | } __attribute__((packed)); | ||
| 62 | |||
| 63 | /* 4.7.2.3 Clock Multiplier Descriptor */ | ||
| 64 | |||
| 65 | struct uac_clock_multiplier_descriptor { | ||
| 66 | __u8 bLength; | ||
| 67 | __u8 bDescriptorType; | ||
| 68 | __u8 bDescriptorSubtype; | ||
| 69 | __u8 bClockID; | ||
| 70 | __u8 bCSourceID; | ||
| 71 | __u8 bmControls; | ||
| 72 | __u8 iClockMultiplier; | ||
| 44 | } __attribute__((packed)); | 73 | } __attribute__((packed)); |
| 45 | 74 | ||
| 46 | /* 4.7.2.4 Input terminal descriptor */ | 75 | /* 4.7.2.4 Input terminal descriptor */ |
diff --git a/include/linux/usb/audio.h b/include/linux/usb/audio.h index 5d646c388752..c51200c715e5 100644 --- a/include/linux/usb/audio.h +++ b/include/linux/usb/audio.h | |||
| @@ -47,6 +47,15 @@ | |||
| 47 | #define UAC_FORMAT_TYPE 0x02 | 47 | #define UAC_FORMAT_TYPE 0x02 |
| 48 | #define UAC_FORMAT_SPECIFIC 0x03 | 48 | #define UAC_FORMAT_SPECIFIC 0x03 |
| 49 | 49 | ||
| 50 | /* A.7 Processing Unit Process Types */ | ||
| 51 | #define UAC_PROCESS_UNDEFINED 0x00 | ||
| 52 | #define UAC_PROCESS_UP_DOWNMIX 0x01 | ||
| 53 | #define UAC_PROCESS_DOLBY_PROLOGIC 0x02 | ||
| 54 | #define UAC_PROCESS_STEREO_EXTENDER 0x03 | ||
| 55 | #define UAC_PROCESS_REVERB 0x04 | ||
| 56 | #define UAC_PROCESS_CHORUS 0x05 | ||
| 57 | #define UAC_PROCESS_DYN_RANGE_COMP 0x06 | ||
| 58 | |||
| 50 | /* A.8 Audio Class-Specific Endpoint Descriptor Subtypes */ | 59 | /* A.8 Audio Class-Specific Endpoint Descriptor Subtypes */ |
| 51 | #define UAC_EP_GENERAL 0x01 | 60 | #define UAC_EP_GENERAL 0x01 |
| 52 | 61 | ||
| @@ -73,6 +82,60 @@ | |||
| 73 | 82 | ||
| 74 | #define UAC_GET_STAT 0xff | 83 | #define UAC_GET_STAT 0xff |
| 75 | 84 | ||
| 85 | /* A.10 Control Selector Codes */ | ||
| 86 | |||
| 87 | /* A.10.1 Terminal Control Selectors */ | ||
| 88 | #define UAC_TERM_COPY_PROTECT 0x01 | ||
| 89 | |||
| 90 | /* A.10.2 Feature Unit Control Selectors */ | ||
| 91 | #define UAC_FU_MUTE 0x01 | ||
| 92 | #define UAC_FU_VOLUME 0x02 | ||
| 93 | #define UAC_FU_BASS 0x03 | ||
| 94 | #define UAC_FU_MID 0x04 | ||
| 95 | #define UAC_FU_TREBLE 0x05 | ||
| 96 | #define UAC_FU_GRAPHIC_EQUALIZER 0x06 | ||
| 97 | #define UAC_FU_AUTOMATIC_GAIN 0x07 | ||
| 98 | #define UAC_FU_DELAY 0x08 | ||
| 99 | #define UAC_FU_BASS_BOOST 0x09 | ||
| 100 | #define UAC_FU_LOUDNESS 0x0a | ||
| 101 | |||
| 102 | #define UAC_CONTROL_BIT(CS) (1 << ((CS) - 1)) | ||
| 103 | |||
| 104 | /* A.10.3.1 Up/Down-mix Processing Unit Controls Selectors */ | ||
| 105 | #define UAC_UD_ENABLE 0x01 | ||
| 106 | #define UAC_UD_MODE_SELECT 0x02 | ||
| 107 | |||
| 108 | /* A.10.3.2 Dolby Prologic (tm) Processing Unit Controls Selectors */ | ||
| 109 | #define UAC_DP_ENABLE 0x01 | ||
| 110 | #define UAC_DP_MODE_SELECT 0x02 | ||
| 111 | |||
| 112 | /* A.10.3.3 3D Stereo Extender Processing Unit Control Selectors */ | ||
| 113 | #define UAC_3D_ENABLE 0x01 | ||
| 114 | #define UAC_3D_SPACE 0x02 | ||
| 115 | |||
| 116 | /* A.10.3.4 Reverberation Processing Unit Control Selectors */ | ||
| 117 | #define UAC_REVERB_ENABLE 0x01 | ||
| 118 | #define UAC_REVERB_LEVEL 0x02 | ||
| 119 | #define UAC_REVERB_TIME 0x03 | ||
| 120 | #define UAC_REVERB_FEEDBACK 0x04 | ||
| 121 | |||
| 122 | /* A.10.3.5 Chorus Processing Unit Control Selectors */ | ||
| 123 | #define UAC_CHORUS_ENABLE 0x01 | ||
| 124 | #define UAC_CHORUS_LEVEL 0x02 | ||
| 125 | #define UAC_CHORUS_RATE 0x03 | ||
| 126 | #define UAC_CHORUS_DEPTH 0x04 | ||
| 127 | |||
| 128 | /* A.10.3.6 Dynamic Range Compressor Unit Control Selectors */ | ||
| 129 | #define UAC_DCR_ENABLE 0x01 | ||
| 130 | #define UAC_DCR_RATE 0x02 | ||
| 131 | #define UAC_DCR_MAXAMPL 0x03 | ||
| 132 | #define UAC_DCR_THRESHOLD 0x04 | ||
| 133 | #define UAC_DCR_ATTACK_TIME 0x05 | ||
| 134 | #define UAC_DCR_RELEASE_TIME 0x06 | ||
| 135 | |||
| 136 | /* A.10.4 Extension Unit Control Selectors */ | ||
| 137 | #define UAC_XU_ENABLE 0x01 | ||
| 138 | |||
| 76 | /* MIDI - A.1 MS Class-Specific Interface Descriptor Subtypes */ | 139 | /* MIDI - A.1 MS Class-Specific Interface Descriptor Subtypes */ |
| 77 | #define UAC_MS_HEADER 0x01 | 140 | #define UAC_MS_HEADER 0x01 |
| 78 | #define UAC_MIDI_IN_JACK 0x02 | 141 | #define UAC_MIDI_IN_JACK 0x02 |
| @@ -244,7 +307,7 @@ struct uac_selector_unit_descriptor { | |||
| 244 | static inline __u8 uac_selector_unit_iSelector(struct uac_selector_unit_descriptor *desc) | 307 | static inline __u8 uac_selector_unit_iSelector(struct uac_selector_unit_descriptor *desc) |
| 245 | { | 308 | { |
| 246 | __u8 *raw = (__u8 *) desc; | 309 | __u8 *raw = (__u8 *) desc; |
| 247 | return raw[9 + desc->bLength - 1]; | 310 | return raw[desc->bLength - 1]; |
| 248 | } | 311 | } |
| 249 | 312 | ||
| 250 | /* 4.3.2.5 Feature Unit Descriptor */ | 313 | /* 4.3.2.5 Feature Unit Descriptor */ |
| @@ -463,31 +526,6 @@ struct uac_iso_endpoint_descriptor { | |||
| 463 | #define UAC_EP_CS_ATTR_PITCH_CONTROL 0x02 | 526 | #define UAC_EP_CS_ATTR_PITCH_CONTROL 0x02 |
| 464 | #define UAC_EP_CS_ATTR_FILL_MAX 0x80 | 527 | #define UAC_EP_CS_ATTR_FILL_MAX 0x80 |
| 465 | 528 | ||
| 466 | /* A.10.2 Feature Unit Control Selectors */ | ||
| 467 | |||
| 468 | #define UAC_FU_CONTROL_UNDEFINED 0x00 | ||
| 469 | #define UAC_MUTE_CONTROL 0x01 | ||
| 470 | #define UAC_VOLUME_CONTROL 0x02 | ||
| 471 | #define UAC_BASS_CONTROL 0x03 | ||
| 472 | #define UAC_MID_CONTROL 0x04 | ||
| 473 | #define UAC_TREBLE_CONTROL 0x05 | ||
| 474 | #define UAC_GRAPHIC_EQUALIZER_CONTROL 0x06 | ||
| 475 | #define UAC_AUTOMATIC_GAIN_CONTROL 0x07 | ||
| 476 | #define UAC_DELAY_CONTROL 0x08 | ||
| 477 | #define UAC_BASS_BOOST_CONTROL 0x09 | ||
| 478 | #define UAC_LOUDNESS_CONTROL 0x0a | ||
| 479 | |||
| 480 | #define UAC_FU_MUTE (1 << (UAC_MUTE_CONTROL - 1)) | ||
| 481 | #define UAC_FU_VOLUME (1 << (UAC_VOLUME_CONTROL - 1)) | ||
| 482 | #define UAC_FU_BASS (1 << (UAC_BASS_CONTROL - 1)) | ||
| 483 | #define UAC_FU_MID (1 << (UAC_MID_CONTROL - 1)) | ||
| 484 | #define UAC_FU_TREBLE (1 << (UAC_TREBLE_CONTROL - 1)) | ||
| 485 | #define UAC_FU_GRAPHIC_EQ (1 << (UAC_GRAPHIC_EQUALIZER_CONTROL - 1)) | ||
| 486 | #define UAC_FU_AUTO_GAIN (1 << (UAC_AUTOMATIC_GAIN_CONTROL - 1)) | ||
| 487 | #define UAC_FU_DELAY (1 << (UAC_DELAY_CONTROL - 1)) | ||
| 488 | #define UAC_FU_BASS_BOOST (1 << (UAC_BASS_BOOST_CONTROL - 1)) | ||
| 489 | #define UAC_FU_LOUDNESS (1 << (UAC_LOUDNESS_CONTROL - 1)) | ||
| 490 | |||
| 491 | /* status word format (3.7.1.1) */ | 529 | /* status word format (3.7.1.1) */ |
| 492 | 530 | ||
| 493 | #define UAC1_STATUS_TYPE_ORIG_MASK 0x0f | 531 | #define UAC1_STATUS_TYPE_ORIG_MASK 0x0f |
diff --git a/sound/pci/asihpi/asihpi.c b/sound/pci/asihpi/asihpi.c index f74c7372b3d1..1db586af4f9c 100644 --- a/sound/pci/asihpi/asihpi.c +++ b/sound/pci/asihpi/asihpi.c | |||
| @@ -2578,6 +2578,9 @@ static int __devinit snd_card_asihpi_mixer_new(struct snd_card_asihpi *asihpi) | |||
| 2578 | if (err) | 2578 | if (err) |
| 2579 | return -err; | 2579 | return -err; |
| 2580 | 2580 | ||
| 2581 | memset(&prev_ctl, 0, sizeof(prev_ctl)); | ||
| 2582 | prev_ctl.control_type = -1; | ||
| 2583 | |||
| 2581 | for (idx = 0; idx < 2000; idx++) { | 2584 | for (idx = 0; idx < 2000; idx++) { |
| 2582 | err = hpi_mixer_get_control_by_index( | 2585 | err = hpi_mixer_get_control_by_index( |
| 2583 | ss, asihpi->h_mixer, | 2586 | ss, asihpi->h_mixer, |
diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index dc79564fea30..1df25cf5ce38 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c | |||
| @@ -1913,11 +1913,11 @@ static int azx_position_ok(struct azx *chip, struct azx_dev *azx_dev) | |||
| 1913 | if (WARN_ONCE(!azx_dev->period_bytes, | 1913 | if (WARN_ONCE(!azx_dev->period_bytes, |
| 1914 | "hda-intel: zero azx_dev->period_bytes")) | 1914 | "hda-intel: zero azx_dev->period_bytes")) |
| 1915 | return -1; /* this shouldn't happen! */ | 1915 | return -1; /* this shouldn't happen! */ |
| 1916 | if (wallclk <= azx_dev->period_wallclk && | 1916 | if (wallclk < (azx_dev->period_wallclk * 5) / 4 && |
| 1917 | pos % azx_dev->period_bytes > azx_dev->period_bytes / 2) | 1917 | pos % azx_dev->period_bytes > azx_dev->period_bytes / 2) |
| 1918 | /* NG - it's below the first next period boundary */ | 1918 | /* NG - it's below the first next period boundary */ |
| 1919 | return bdl_pos_adj[chip->dev_index] ? 0 : -1; | 1919 | return bdl_pos_adj[chip->dev_index] ? 0 : -1; |
| 1920 | azx_dev->start_wallclk = wallclk; | 1920 | azx_dev->start_wallclk += wallclk; |
| 1921 | return 1; /* OK, it's fine */ | 1921 | return 1; /* OK, it's fine */ |
| 1922 | } | 1922 | } |
| 1923 | 1923 | ||
| @@ -2288,6 +2288,8 @@ static struct snd_pci_quirk position_fix_list[] __devinitdata = { | |||
| 2288 | SND_PCI_QUIRK(0x1028, 0x01f6, "Dell Latitude 131L", POS_FIX_LPIB), | 2288 | SND_PCI_QUIRK(0x1028, 0x01f6, "Dell Latitude 131L", POS_FIX_LPIB), |
| 2289 | SND_PCI_QUIRK(0x103c, 0x306d, "HP dv3", POS_FIX_LPIB), | 2289 | SND_PCI_QUIRK(0x103c, 0x306d, "HP dv3", POS_FIX_LPIB), |
| 2290 | SND_PCI_QUIRK(0x1043, 0x813d, "ASUS P5AD2", POS_FIX_LPIB), | 2290 | SND_PCI_QUIRK(0x1043, 0x813d, "ASUS P5AD2", POS_FIX_LPIB), |
| 2291 | SND_PCI_QUIRK(0x1043, 0x81b3, "ASUS", POS_FIX_LPIB), | ||
| 2292 | SND_PCI_QUIRK(0x1043, 0x81e7, "ASUS M2V", POS_FIX_LPIB), | ||
| 2291 | SND_PCI_QUIRK(0x104d, 0x9069, "Sony VPCS11V9E", POS_FIX_LPIB), | 2293 | SND_PCI_QUIRK(0x104d, 0x9069, "Sony VPCS11V9E", POS_FIX_LPIB), |
| 2292 | SND_PCI_QUIRK(0x1106, 0x3288, "ASUS M2V-MX SE", POS_FIX_LPIB), | 2294 | SND_PCI_QUIRK(0x1106, 0x3288, "ASUS M2V-MX SE", POS_FIX_LPIB), |
| 2293 | SND_PCI_QUIRK(0x1179, 0xff10, "Toshiba A100-259", POS_FIX_LPIB), | 2295 | SND_PCI_QUIRK(0x1179, 0xff10, "Toshiba A100-259", POS_FIX_LPIB), |
| @@ -2296,6 +2298,7 @@ static struct snd_pci_quirk position_fix_list[] __devinitdata = { | |||
| 2296 | SND_PCI_QUIRK(0x1462, 0x1002, "MSI Wind U115", POS_FIX_LPIB), | 2298 | SND_PCI_QUIRK(0x1462, 0x1002, "MSI Wind U115", POS_FIX_LPIB), |
| 2297 | SND_PCI_QUIRK(0x1565, 0x820f, "Biostar Microtech", POS_FIX_LPIB), | 2299 | SND_PCI_QUIRK(0x1565, 0x820f, "Biostar Microtech", POS_FIX_LPIB), |
| 2298 | SND_PCI_QUIRK(0x1565, 0x8218, "Biostar Microtech", POS_FIX_LPIB), | 2300 | SND_PCI_QUIRK(0x1565, 0x8218, "Biostar Microtech", POS_FIX_LPIB), |
| 2301 | SND_PCI_QUIRK(0x1849, 0x0888, "775Dual-VSTA", POS_FIX_LPIB), | ||
| 2299 | SND_PCI_QUIRK(0x8086, 0x2503, "DG965OT AAD63733-203", POS_FIX_LPIB), | 2302 | SND_PCI_QUIRK(0x8086, 0x2503, "DG965OT AAD63733-203", POS_FIX_LPIB), |
| 2300 | SND_PCI_QUIRK(0x8086, 0xd601, "eMachines T5212", POS_FIX_LPIB), | 2303 | SND_PCI_QUIRK(0x8086, 0xd601, "eMachines T5212", POS_FIX_LPIB), |
| 2301 | {} | 2304 | {} |
diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 17d4548cc353..d792cddbf4c2 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c | |||
| @@ -9476,6 +9476,7 @@ static struct snd_pci_quirk alc882_ssid_cfg_tbl[] = { | |||
| 9476 | SND_PCI_QUIRK(0x106b, 0x1000, "iMac 24", ALC885_IMAC24), | 9476 | SND_PCI_QUIRK(0x106b, 0x1000, "iMac 24", ALC885_IMAC24), |
| 9477 | SND_PCI_QUIRK(0x106b, 0x2800, "AppleTV", ALC885_IMAC24), | 9477 | SND_PCI_QUIRK(0x106b, 0x2800, "AppleTV", ALC885_IMAC24), |
| 9478 | SND_PCI_QUIRK(0x106b, 0x2c00, "MacbookPro rev3", ALC885_MBP3), | 9478 | SND_PCI_QUIRK(0x106b, 0x2c00, "MacbookPro rev3", ALC885_MBP3), |
| 9479 | SND_PCI_QUIRK(0x106b, 0x3000, "iMac", ALC889A_MB31), | ||
| 9479 | SND_PCI_QUIRK(0x106b, 0x3600, "Macbook 3,1", ALC889A_MB31), | 9480 | SND_PCI_QUIRK(0x106b, 0x3600, "Macbook 3,1", ALC889A_MB31), |
| 9480 | SND_PCI_QUIRK(0x106b, 0x3800, "MacbookPro 4,1", ALC885_MBP3), | 9481 | SND_PCI_QUIRK(0x106b, 0x3800, "MacbookPro 4,1", ALC885_MBP3), |
| 9481 | SND_PCI_QUIRK(0x106b, 0x3e00, "iMac 24 Aluminum", ALC885_IMAC24), | 9482 | SND_PCI_QUIRK(0x106b, 0x3e00, "iMac 24 Aluminum", ALC885_IMAC24), |
diff --git a/sound/soc/imx/Kconfig b/sound/soc/imx/Kconfig index eba9b9d257a1..252defea93b5 100644 --- a/sound/soc/imx/Kconfig +++ b/sound/soc/imx/Kconfig | |||
| @@ -13,9 +13,18 @@ config SND_MXC_SOC_SSI | |||
| 13 | 13 | ||
| 14 | config SND_MXC_SOC_WM1133_EV1 | 14 | config SND_MXC_SOC_WM1133_EV1 |
| 15 | tristate "Audio on the the i.MX31ADS with WM1133-EV1 fitted" | 15 | tristate "Audio on the the i.MX31ADS with WM1133-EV1 fitted" |
| 16 | depends on SND_IMX_SOC && EXPERIMENTAL | 16 | depends on SND_IMX_SOC && MACH_MX31ADS_WM1133_EV1 && EXPERIMENTAL |
| 17 | select SND_SOC_WM8350 | 17 | select SND_SOC_WM8350 |
| 18 | select SND_MXC_SOC_SSI | 18 | select SND_MXC_SOC_SSI |
| 19 | help | 19 | help |
| 20 | Enable support for audio on the i.MX31ADS with the WM1133-EV1 | 20 | Enable support for audio on the i.MX31ADS with the WM1133-EV1 |
| 21 | PMIC board with WM8835x fitted. | 21 | PMIC board with WM8835x fitted. |
| 22 | |||
| 23 | config SND_SOC_PHYCORE_AC97 | ||
| 24 | tristate "SoC Audio support for Phytec phyCORE (and phyCARD) boards" | ||
| 25 | depends on MACH_PCM043 || MACH_PCA100 | ||
| 26 | select SND_MXC_SOC_SSI | ||
| 27 | select SND_SOC_WM9712 | ||
| 28 | help | ||
| 29 | Say Y if you want to add support for SoC audio on Phytec phyCORE | ||
| 30 | and phyCARD boards in AC97 mode | ||
diff --git a/sound/usb/Makefile b/sound/usb/Makefile index e7ac7f493a8f..1e362bf8834f 100644 --- a/sound/usb/Makefile +++ b/sound/usb/Makefile | |||
| @@ -11,7 +11,8 @@ snd-usb-audio-objs := card.o \ | |||
| 11 | endpoint.o \ | 11 | endpoint.o \ |
| 12 | urb.o \ | 12 | urb.o \ |
| 13 | pcm.o \ | 13 | pcm.o \ |
| 14 | helper.o | 14 | helper.o \ |
| 15 | clock.o | ||
| 15 | 16 | ||
| 16 | snd-usbmidi-lib-objs := midi.o | 17 | snd-usbmidi-lib-objs := midi.o |
| 17 | 18 | ||
diff --git a/sound/usb/card.c b/sound/usb/card.c index da1346bd4856..7a8ac1d81be7 100644 --- a/sound/usb/card.c +++ b/sound/usb/card.c | |||
| @@ -236,7 +236,6 @@ static int snd_usb_create_streams(struct snd_usb_audio *chip, int ctrlif) | |||
| 236 | } | 236 | } |
| 237 | 237 | ||
| 238 | case UAC_VERSION_2: { | 238 | case UAC_VERSION_2: { |
| 239 | struct uac_clock_source_descriptor *cs; | ||
| 240 | struct usb_interface_assoc_descriptor *assoc = | 239 | struct usb_interface_assoc_descriptor *assoc = |
| 241 | usb_ifnum_to_if(dev, ctrlif)->intf_assoc; | 240 | usb_ifnum_to_if(dev, ctrlif)->intf_assoc; |
| 242 | 241 | ||
| @@ -245,21 +244,6 @@ static int snd_usb_create_streams(struct snd_usb_audio *chip, int ctrlif) | |||
| 245 | return -EINVAL; | 244 | return -EINVAL; |
| 246 | } | 245 | } |
| 247 | 246 | ||
| 248 | /* FIXME: for now, we expect there is at least one clock source | ||
| 249 | * descriptor and we always take the first one. | ||
| 250 | * We should properly support devices with multiple clock sources, | ||
| 251 | * clock selectors and sample rate conversion units. */ | ||
| 252 | |||
| 253 | cs = snd_usb_find_csint_desc(host_iface->extra, host_iface->extralen, | ||
| 254 | NULL, UAC2_CLOCK_SOURCE); | ||
| 255 | |||
| 256 | if (!cs) { | ||
| 257 | snd_printk(KERN_ERR "CLOCK_SOURCE descriptor not found\n"); | ||
| 258 | return -EINVAL; | ||
| 259 | } | ||
| 260 | |||
| 261 | chip->clock_id = cs->bClockID; | ||
| 262 | |||
| 263 | for (i = 0; i < assoc->bInterfaceCount; i++) { | 247 | for (i = 0; i < assoc->bInterfaceCount; i++) { |
| 264 | int intf = assoc->bFirstInterface + i; | 248 | int intf = assoc->bFirstInterface + i; |
| 265 | 249 | ||
| @@ -481,6 +465,8 @@ static void *snd_usb_audio_probe(struct usb_device *dev, | |||
| 481 | goto __error; | 465 | goto __error; |
| 482 | } | 466 | } |
| 483 | 467 | ||
| 468 | chip->ctrl_intf = alts; | ||
| 469 | |||
| 484 | if (err > 0) { | 470 | if (err > 0) { |
| 485 | /* create normal USB audio interfaces */ | 471 | /* create normal USB audio interfaces */ |
| 486 | if (snd_usb_create_streams(chip, ifnum) < 0 || | 472 | if (snd_usb_create_streams(chip, ifnum) < 0 || |
diff --git a/sound/usb/card.h b/sound/usb/card.h index ed92420c1095..1febf2f23754 100644 --- a/sound/usb/card.h +++ b/sound/usb/card.h | |||
| @@ -25,6 +25,7 @@ struct audioformat { | |||
| 25 | unsigned int rate_min, rate_max; /* min/max rates */ | 25 | unsigned int rate_min, rate_max; /* min/max rates */ |
| 26 | unsigned int nr_rates; /* number of rate table entries */ | 26 | unsigned int nr_rates; /* number of rate table entries */ |
| 27 | unsigned int *rate_table; /* rate table */ | 27 | unsigned int *rate_table; /* rate table */ |
| 28 | unsigned char clock; /* associated clock */ | ||
| 28 | }; | 29 | }; |
| 29 | 30 | ||
| 30 | struct snd_usb_substream; | 31 | struct snd_usb_substream; |
diff --git a/sound/usb/clock.c b/sound/usb/clock.c new file mode 100644 index 000000000000..b7aadd614c70 --- /dev/null +++ b/sound/usb/clock.c | |||
| @@ -0,0 +1,311 @@ | |||
| 1 | /* | ||
| 2 | * Clock domain and sample rate management functions | ||
| 3 | * | ||
| 4 | * This program is free software; you can redistribute it and/or modify | ||
| 5 | * it under the terms of the GNU General Public License as published by | ||
| 6 | * the Free Software Foundation; either version 2 of the License, or | ||
| 7 | * (at your option) any later version. | ||
| 8 | * | ||
| 9 | * This program is distributed in the hope that it will be useful, | ||
| 10 | * but WITHOUT ANY WARRANTY; without even the implied warranty of | ||
| 11 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | ||
| 12 | * GNU General Public License for more details. | ||
| 13 | * | ||
| 14 | * You should have received a copy of the GNU General Public License | ||
| 15 | * along with this program; if not, write to the Free Software | ||
| 16 | * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA | ||
| 17 | * | ||
| 18 | */ | ||
| 19 | |||
| 20 | #include <linux/bitops.h> | ||
| 21 | #include <linux/init.h> | ||
| 22 | #include <linux/list.h> | ||
| 23 | #include <linux/slab.h> | ||
| 24 | #include <linux/string.h> | ||
| 25 | #include <linux/usb.h> | ||
| 26 | #include <linux/moduleparam.h> | ||
| 27 | #include <linux/mutex.h> | ||
| 28 | #include <linux/usb/audio.h> | ||
| 29 | #include <linux/usb/audio-v2.h> | ||
| 30 | |||
| 31 | #include <sound/core.h> | ||
| 32 | #include <sound/info.h> | ||
| 33 | #include <sound/pcm.h> | ||
| 34 | #include <sound/pcm_params.h> | ||
| 35 | #include <sound/initval.h> | ||
| 36 | |||
| 37 | #include "usbaudio.h" | ||
| 38 | #include "card.h" | ||
| 39 | #include "midi.h" | ||
| 40 | #include "mixer.h" | ||
| 41 | #include "proc.h" | ||
| 42 | #include "quirks.h" | ||
| 43 | #include "endpoint.h" | ||
| 44 | #include "helper.h" | ||
| 45 | #include "debug.h" | ||
| 46 | #include "pcm.h" | ||
| 47 | #include "urb.h" | ||
| 48 | #include "format.h" | ||
| 49 | |||
| 50 | static struct uac_clock_source_descriptor * | ||
| 51 | snd_usb_find_clock_source(struct usb_host_interface *ctrl_iface, | ||
| 52 | int clock_id) | ||
| 53 | { | ||
| 54 | struct uac_clock_source_descriptor *cs = NULL; | ||
| 55 | |||
| 56 | while ((cs = snd_usb_find_csint_desc(ctrl_iface->extra, | ||
| 57 | ctrl_iface->extralen, | ||
| 58 | cs, UAC2_CLOCK_SOURCE))) { | ||
| 59 | if (cs->bClockID == clock_id) | ||
| 60 | return cs; | ||
| 61 | } | ||
| 62 | |||
| 63 | return NULL; | ||
| 64 | } | ||
| 65 | |||
| 66 | static struct uac_clock_selector_descriptor * | ||
| 67 | snd_usb_find_clock_selector(struct usb_host_interface *ctrl_iface, | ||
| 68 | int clock_id) | ||
| 69 | { | ||
| 70 | struct uac_clock_selector_descriptor *cs = NULL; | ||
| 71 | |||
| 72 | while ((cs = snd_usb_find_csint_desc(ctrl_iface->extra, | ||
| 73 | ctrl_iface->extralen, | ||
| 74 | cs, UAC2_CLOCK_SELECTOR))) { | ||
| 75 | if (cs->bClockID == clock_id) | ||
| 76 | return cs; | ||
| 77 | } | ||
| 78 | |||
| 79 | return NULL; | ||
| 80 | } | ||
| 81 | |||
| 82 | static struct uac_clock_multiplier_descriptor * | ||
| 83 | snd_usb_find_clock_multiplier(struct usb_host_interface *ctrl_iface, | ||
| 84 | int clock_id) | ||
| 85 | { | ||
| 86 | struct uac_clock_multiplier_descriptor *cs = NULL; | ||
| 87 | |||
| 88 | while ((cs = snd_usb_find_csint_desc(ctrl_iface->extra, | ||
| 89 | ctrl_iface->extralen, | ||
| 90 | cs, UAC2_CLOCK_MULTIPLIER))) { | ||
| 91 | if (cs->bClockID == clock_id) | ||
| 92 | return cs; | ||
| 93 | } | ||
| 94 | |||
| 95 | return NULL; | ||
| 96 | } | ||
| 97 | |||
| 98 | static int uac_clock_selector_get_val(struct snd_usb_audio *chip, int selector_id) | ||
| 99 | { | ||
| 100 | unsigned char buf; | ||
| 101 | int ret; | ||
| 102 | |||
| 103 | ret = snd_usb_ctl_msg(chip->dev, usb_rcvctrlpipe(chip->dev, 0), | ||
| 104 | UAC2_CS_CUR, | ||
| 105 | USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN, | ||
| 106 | UAC2_CX_CLOCK_SELECTOR << 8, selector_id << 8, | ||
| 107 | &buf, sizeof(buf), 1000); | ||
| 108 | |||
| 109 | if (ret < 0) | ||
| 110 | return ret; | ||
| 111 | |||
| 112 | return buf; | ||
| 113 | } | ||
| 114 | |||
| 115 | static bool uac_clock_source_is_valid(struct snd_usb_audio *chip, int source_id) | ||
| 116 | { | ||
| 117 | int err; | ||
| 118 | unsigned char data; | ||
| 119 | struct usb_device *dev = chip->dev; | ||
| 120 | |||
| 121 | err = snd_usb_ctl_msg(dev, usb_rcvctrlpipe(dev, 0), UAC2_CS_CUR, | ||
| 122 | USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_IN, | ||
| 123 | UAC2_CS_CONTROL_CLOCK_VALID << 8, source_id << 8, | ||
| 124 | &data, sizeof(data), 1000); | ||
| 125 | |||
| 126 | if (err < 0) { | ||
| 127 | snd_printk(KERN_WARNING "%s(): cannot get clock validity for id %d\n", | ||
| 128 | __func__, source_id); | ||
| 129 | return err; | ||
| 130 | } | ||
| 131 | |||
| 132 | return !!data; | ||
| 133 | } | ||
| 134 | |||
| 135 | /* Try to find the clock source ID of a given clock entity */ | ||
| 136 | |||
| 137 | static int __uac_clock_find_source(struct snd_usb_audio *chip, | ||
| 138 | struct usb_host_interface *host_iface, | ||
| 139 | int entity_id, unsigned long *visited) | ||
| 140 | { | ||
| 141 | struct uac_clock_source_descriptor *source; | ||
| 142 | struct uac_clock_selector_descriptor *selector; | ||
| 143 | struct uac_clock_multiplier_descriptor *multiplier; | ||
| 144 | |||
| 145 | entity_id &= 0xff; | ||
| 146 | |||
| 147 | if (test_and_set_bit(entity_id, visited)) { | ||
| 148 | snd_printk(KERN_WARNING | ||
| 149 | "%s(): recursive clock topology detected, id %d.\n", | ||
| 150 | __func__, entity_id); | ||
| 151 | return -EINVAL; | ||
| 152 | } | ||
| 153 | |||
| 154 | /* first, see if the ID we're looking for is a clock source already */ | ||
| 155 | source = snd_usb_find_clock_source(host_iface, entity_id); | ||
| 156 | if (source) | ||
| 157 | return source->bClockID; | ||
| 158 | |||
| 159 | selector = snd_usb_find_clock_selector(host_iface, entity_id); | ||
| 160 | if (selector) { | ||
| 161 | int ret; | ||
| 162 | |||
| 163 | /* the entity ID we are looking for is a selector. | ||
| 164 | * find out what it currently selects */ | ||
| 165 | ret = uac_clock_selector_get_val(chip, selector->bClockID); | ||
| 166 | if (ret < 0) | ||
| 167 | return ret; | ||
| 168 | |||
| 169 | if (ret > selector->bNrInPins || ret < 1) { | ||
| 170 | printk(KERN_ERR | ||
| 171 | "%s(): selector reported illegal value, id %d, ret %d\n", | ||
| 172 | __func__, selector->bClockID, ret); | ||
| 173 | |||
| 174 | return -EINVAL; | ||
| 175 | } | ||
| 176 | |||
| 177 | return __uac_clock_find_source(chip, host_iface, | ||
| 178 | selector->baCSourceID[ret-1], | ||
| 179 | visited); | ||
| 180 | } | ||
| 181 | |||
| 182 | /* FIXME: multipliers only act as pass-thru element for now */ | ||
| 183 | multiplier = snd_usb_find_clock_multiplier(host_iface, entity_id); | ||
| 184 | if (multiplier) | ||
| 185 | return __uac_clock_find_source(chip, host_iface, | ||
| 186 | multiplier->bCSourceID, visited); | ||
| 187 | |||
| 188 | return -EINVAL; | ||
| 189 | } | ||
| 190 | |||
| 191 | int snd_usb_clock_find_source(struct snd_usb_audio *chip, | ||
| 192 | struct usb_host_interface *host_iface, | ||
| 193 | int entity_id) | ||
| 194 | { | ||
| 195 | DECLARE_BITMAP(visited, 256); | ||
| 196 | memset(visited, 0, sizeof(visited)); | ||
| 197 | return __uac_clock_find_source(chip, host_iface, entity_id, visited); | ||
| 198 | } | ||
| 199 | |||
| 200 | static int set_sample_rate_v1(struct snd_usb_audio *chip, int iface, | ||
| 201 | struct usb_host_interface *alts, | ||
| 202 | struct audioformat *fmt, int rate) | ||
| 203 | { | ||
| 204 | struct usb_device *dev = chip->dev; | ||
| 205 | unsigned int ep; | ||
| 206 | unsigned char data[3]; | ||
| 207 | int err, crate; | ||
| 208 | |||
| 209 | ep = get_endpoint(alts, 0)->bEndpointAddress; | ||
| 210 | |||
| 211 | /* if endpoint doesn't have sampling rate control, bail out */ | ||
| 212 | if (!(fmt->attributes & UAC_EP_CS_ATTR_SAMPLE_RATE)) { | ||
| 213 | snd_printk(KERN_WARNING "%d:%d:%d: endpoint lacks sample rate attribute bit, cannot set.\n", | ||
| 214 | dev->devnum, iface, fmt->altsetting); | ||
| 215 | return 0; | ||
| 216 | } | ||
| 217 | |||
| 218 | data[0] = rate; | ||
| 219 | data[1] = rate >> 8; | ||
| 220 | data[2] = rate >> 16; | ||
| 221 | if ((err = snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0), UAC_SET_CUR, | ||
| 222 | USB_TYPE_CLASS | USB_RECIP_ENDPOINT | USB_DIR_OUT, | ||
| 223 | UAC_EP_CS_ATTR_SAMPLE_RATE << 8, ep, | ||
| 224 | data, sizeof(data), 1000)) < 0) { | ||
| 225 | snd_printk(KERN_ERR "%d:%d:%d: cannot set freq %d to ep %#x\n", | ||
| 226 | dev->devnum, iface, fmt->altsetting, rate, ep); | ||
| 227 | return err; | ||
| 228 | } | ||
| 229 | |||
| 230 | if ((err = snd_usb_ctl_msg(dev, usb_rcvctrlpipe(dev, 0), UAC_GET_CUR, | ||
| 231 | USB_TYPE_CLASS | USB_RECIP_ENDPOINT | USB_DIR_IN, | ||
| 232 | UAC_EP_CS_ATTR_SAMPLE_RATE << 8, ep, | ||
| 233 | data, sizeof(data), 1000)) < 0) { | ||
| 234 | snd_printk(KERN_WARNING "%d:%d:%d: cannot get freq at ep %#x\n", | ||
| 235 | dev->devnum, iface, fmt->altsetting, ep); | ||
| 236 | return 0; /* some devices don't support reading */ | ||
| 237 | } | ||
| 238 | |||
| 239 | crate = data[0] | (data[1] << 8) | (data[2] << 16); | ||
| 240 | if (crate != rate) { | ||
| 241 | snd_printd(KERN_WARNING "current rate %d is different from the runtime rate %d\n", crate, rate); | ||
| 242 | // runtime->rate = crate; | ||
| 243 | } | ||
| 244 | |||
| 245 | return 0; | ||
| 246 | } | ||
| 247 | |||
| 248 | static int set_sample_rate_v2(struct snd_usb_audio *chip, int iface, | ||
| 249 | struct usb_host_interface *alts, | ||
| 250 | struct audioformat *fmt, int rate) | ||
| 251 | { | ||
| 252 | struct usb_device *dev = chip->dev; | ||
| 253 | unsigned char data[4]; | ||
| 254 | int err, crate; | ||
| 255 | int clock = snd_usb_clock_find_source(chip, chip->ctrl_intf, fmt->clock); | ||
| 256 | |||
| 257 | if (clock < 0) | ||
| 258 | return clock; | ||
| 259 | |||
| 260 | if (!uac_clock_source_is_valid(chip, clock)) { | ||
| 261 | snd_printk(KERN_ERR "%d:%d:%d: clock source %d is not valid, cannot use\n", | ||
| 262 | dev->devnum, iface, fmt->altsetting, clock); | ||
| 263 | return -ENXIO; | ||
| 264 | } | ||
| 265 | |||
| 266 | data[0] = rate; | ||
| 267 | data[1] = rate >> 8; | ||
| 268 | data[2] = rate >> 16; | ||
| 269 | data[3] = rate >> 24; | ||
| 270 | if ((err = snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0), UAC2_CS_CUR, | ||
| 271 | USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_OUT, | ||
| 272 | UAC2_CS_CONTROL_SAM_FREQ << 8, clock << 8, | ||
| 273 | data, sizeof(data), 1000)) < 0) { | ||
| 274 | snd_printk(KERN_ERR "%d:%d:%d: cannot set freq %d (v2)\n", | ||
| 275 | dev->devnum, iface, fmt->altsetting, rate); | ||
| 276 | return err; | ||
| 277 | } | ||
| 278 | |||
| 279 | if ((err = snd_usb_ctl_msg(dev, usb_rcvctrlpipe(dev, 0), UAC2_CS_CUR, | ||
| 280 | USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_IN, | ||
| 281 | UAC2_CS_CONTROL_SAM_FREQ << 8, clock << 8, | ||
| 282 | data, sizeof(data), 1000)) < 0) { | ||
| 283 | snd_printk(KERN_WARNING "%d:%d:%d: cannot get freq (v2)\n", | ||
| 284 | dev->devnum, iface, fmt->altsetting); | ||
| 285 | return err; | ||
| 286 | } | ||
| 287 | |||
| 288 | crate = data[0] | (data[1] << 8) | (data[2] << 16) | (data[3] << 24); | ||
| 289 | if (crate != rate) | ||
| 290 | snd_printd(KERN_WARNING "current rate %d is different from the runtime rate %d\n", crate, rate); | ||
| 291 | |||
| 292 | return 0; | ||
| 293 | } | ||
| 294 | |||
| 295 | int snd_usb_init_sample_rate(struct snd_usb_audio *chip, int iface, | ||
| 296 | struct usb_host_interface *alts, | ||
| 297 | struct audioformat *fmt, int rate) | ||
| 298 | { | ||
| 299 | struct usb_interface_descriptor *altsd = get_iface_desc(alts); | ||
| 300 | |||
| 301 | switch (altsd->bInterfaceProtocol) { | ||
| 302 | case UAC_VERSION_1: | ||
| 303 | return set_sample_rate_v1(chip, iface, alts, fmt, rate); | ||
| 304 | |||
| 305 | case UAC_VERSION_2: | ||
| 306 | return set_sample_rate_v2(chip, iface, alts, fmt, rate); | ||
| 307 | } | ||
| 308 | |||
| 309 | return -EINVAL; | ||
| 310 | } | ||
| 311 | |||
diff --git a/sound/usb/clock.h b/sound/usb/clock.h new file mode 100644 index 000000000000..beb253684e2d --- /dev/null +++ b/sound/usb/clock.h | |||
| @@ -0,0 +1,12 @@ | |||
| 1 | #ifndef __USBAUDIO_CLOCK_H | ||
| 2 | #define __USBAUDIO_CLOCK_H | ||
| 3 | |||
| 4 | int snd_usb_init_sample_rate(struct snd_usb_audio *chip, int iface, | ||
| 5 | struct usb_host_interface *alts, | ||
| 6 | struct audioformat *fmt, int rate); | ||
| 7 | |||
| 8 | int snd_usb_clock_find_source(struct snd_usb_audio *chip, | ||
| 9 | struct usb_host_interface *host_iface, | ||
| 10 | int entity_id); | ||
| 11 | |||
| 12 | #endif /* __USBAUDIO_CLOCK_H */ | ||
diff --git a/sound/usb/endpoint.c b/sound/usb/endpoint.c index 28ee1ce3971a..9593b91452b9 100644 --- a/sound/usb/endpoint.c +++ b/sound/usb/endpoint.c | |||
| @@ -190,6 +190,38 @@ static int parse_uac_endpoint_attributes(struct snd_usb_audio *chip, | |||
| 190 | return attributes; | 190 | return attributes; |
| 191 | } | 191 | } |
| 192 | 192 | ||
| 193 | static struct uac2_input_terminal_descriptor * | ||
| 194 | snd_usb_find_input_terminal_descriptor(struct usb_host_interface *ctrl_iface, | ||
| 195 | int terminal_id) | ||
| 196 | { | ||
| 197 | struct uac2_input_terminal_descriptor *term = NULL; | ||
| 198 | |||
| 199 | while ((term = snd_usb_find_csint_desc(ctrl_iface->extra, | ||
| 200 | ctrl_iface->extralen, | ||
| 201 | term, UAC_INPUT_TERMINAL))) { | ||
| 202 | if (term->bTerminalID == terminal_id) | ||
| 203 | return term; | ||
| 204 | } | ||
| 205 | |||
| 206 | return NULL; | ||
| 207 | } | ||
| 208 | |||
| 209 | static struct uac2_output_terminal_descriptor * | ||
| 210 | snd_usb_find_output_terminal_descriptor(struct usb_host_interface *ctrl_iface, | ||
| 211 | int terminal_id) | ||
| 212 | { | ||
| 213 | struct uac2_output_terminal_descriptor *term = NULL; | ||
| 214 | |||
| 215 | while ((term = snd_usb_find_csint_desc(ctrl_iface->extra, | ||
| 216 | ctrl_iface->extralen, | ||
| 217 | term, UAC_OUTPUT_TERMINAL))) { | ||
| 218 | if (term->bTerminalID == terminal_id) | ||
| 219 | return term; | ||
| 220 | } | ||
| 221 | |||
| 222 | return NULL; | ||
| 223 | } | ||
| 224 | |||
| 193 | int snd_usb_parse_audio_endpoints(struct snd_usb_audio *chip, int iface_no) | 225 | int snd_usb_parse_audio_endpoints(struct snd_usb_audio *chip, int iface_no) |
| 194 | { | 226 | { |
| 195 | struct usb_device *dev; | 227 | struct usb_device *dev; |
| @@ -199,7 +231,7 @@ int snd_usb_parse_audio_endpoints(struct snd_usb_audio *chip, int iface_no) | |||
| 199 | int i, altno, err, stream; | 231 | int i, altno, err, stream; |
| 200 | int format = 0, num_channels = 0; | 232 | int format = 0, num_channels = 0; |
| 201 | struct audioformat *fp = NULL; | 233 | struct audioformat *fp = NULL; |
| 202 | int num, protocol; | 234 | int num, protocol, clock = 0; |
| 203 | struct uac_format_type_i_continuous_descriptor *fmt; | 235 | struct uac_format_type_i_continuous_descriptor *fmt; |
| 204 | 236 | ||
| 205 | dev = chip->dev; | 237 | dev = chip->dev; |
| @@ -263,6 +295,8 @@ int snd_usb_parse_audio_endpoints(struct snd_usb_audio *chip, int iface_no) | |||
| 263 | } | 295 | } |
| 264 | 296 | ||
| 265 | case UAC_VERSION_2: { | 297 | case UAC_VERSION_2: { |
| 298 | struct uac2_input_terminal_descriptor *input_term; | ||
| 299 | struct uac2_output_terminal_descriptor *output_term; | ||
| 266 | struct uac_as_header_descriptor_v2 *as = | 300 | struct uac_as_header_descriptor_v2 *as = |
| 267 | snd_usb_find_csint_desc(alts->extra, alts->extralen, NULL, UAC_AS_GENERAL); | 301 | snd_usb_find_csint_desc(alts->extra, alts->extralen, NULL, UAC_AS_GENERAL); |
| 268 | 302 | ||
| @@ -281,7 +315,25 @@ int snd_usb_parse_audio_endpoints(struct snd_usb_audio *chip, int iface_no) | |||
| 281 | num_channels = as->bNrChannels; | 315 | num_channels = as->bNrChannels; |
| 282 | format = le32_to_cpu(as->bmFormats); | 316 | format = le32_to_cpu(as->bmFormats); |
| 283 | 317 | ||
| 284 | break; | 318 | /* lookup the terminal associated to this interface |
| 319 | * to extract the clock */ | ||
| 320 | input_term = snd_usb_find_input_terminal_descriptor(chip->ctrl_intf, | ||
| 321 | as->bTerminalLink); | ||
| 322 | if (input_term) { | ||
| 323 | clock = input_term->bCSourceID; | ||
| 324 | break; | ||
| 325 | } | ||
| 326 | |||
| 327 | output_term = snd_usb_find_output_terminal_descriptor(chip->ctrl_intf, | ||
| 328 | as->bTerminalLink); | ||
| 329 | if (output_term) { | ||
| 330 | clock = output_term->bCSourceID; | ||
| 331 | break; | ||
| 332 | } | ||
| 333 | |||
| 334 | snd_printk(KERN_ERR "%d:%u:%d : bogus bTerminalLink %d\n", | ||
| 335 | dev->devnum, iface_no, altno, as->bTerminalLink); | ||
| 336 | continue; | ||
| 285 | } | 337 | } |
| 286 | 338 | ||
| 287 | default: | 339 | default: |
| @@ -338,6 +390,7 @@ int snd_usb_parse_audio_endpoints(struct snd_usb_audio *chip, int iface_no) | |||
| 338 | fp->maxpacksize = (((fp->maxpacksize >> 11) & 3) + 1) | 390 | fp->maxpacksize = (((fp->maxpacksize >> 11) & 3) + 1) |
| 339 | * (fp->maxpacksize & 0x7ff); | 391 | * (fp->maxpacksize & 0x7ff); |
| 340 | fp->attributes = parse_uac_endpoint_attributes(chip, alts, protocol, iface_no); | 392 | fp->attributes = parse_uac_endpoint_attributes(chip, alts, protocol, iface_no); |
| 393 | fp->clock = clock; | ||
| 341 | 394 | ||
| 342 | /* some quirks for attributes here */ | 395 | /* some quirks for attributes here */ |
| 343 | 396 | ||
diff --git a/sound/usb/format.c b/sound/usb/format.c index fe29d61de19b..5367cd1e52d9 100644 --- a/sound/usb/format.c +++ b/sound/usb/format.c | |||
| @@ -29,6 +29,7 @@ | |||
| 29 | #include "quirks.h" | 29 | #include "quirks.h" |
| 30 | #include "helper.h" | 30 | #include "helper.h" |
| 31 | #include "debug.h" | 31 | #include "debug.h" |
| 32 | #include "clock.h" | ||
| 32 | 33 | ||
| 33 | /* | 34 | /* |
| 34 | * parse the audio format type I descriptor | 35 | * parse the audio format type I descriptor |
| @@ -215,15 +216,17 @@ static int parse_audio_format_rates_v2(struct snd_usb_audio *chip, | |||
| 215 | struct usb_device *dev = chip->dev; | 216 | struct usb_device *dev = chip->dev; |
| 216 | unsigned char tmp[2], *data; | 217 | unsigned char tmp[2], *data; |
| 217 | int i, nr_rates, data_size, ret = 0; | 218 | int i, nr_rates, data_size, ret = 0; |
| 219 | int clock = snd_usb_clock_find_source(chip, chip->ctrl_intf, fp->clock); | ||
| 218 | 220 | ||
| 219 | /* get the number of sample rates first by only fetching 2 bytes */ | 221 | /* get the number of sample rates first by only fetching 2 bytes */ |
| 220 | ret = snd_usb_ctl_msg(dev, usb_rcvctrlpipe(dev, 0), UAC2_CS_RANGE, | 222 | ret = snd_usb_ctl_msg(dev, usb_rcvctrlpipe(dev, 0), UAC2_CS_RANGE, |
| 221 | USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_IN, | 223 | USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_IN, |
| 222 | UAC2_CS_CONTROL_SAM_FREQ << 8, chip->clock_id << 8, | 224 | UAC2_CS_CONTROL_SAM_FREQ << 8, clock << 8, |
| 223 | tmp, sizeof(tmp), 1000); | 225 | tmp, sizeof(tmp), 1000); |
| 224 | 226 | ||
| 225 | if (ret < 0) { | 227 | if (ret < 0) { |
| 226 | snd_printk(KERN_ERR "unable to retrieve number of sample rates\n"); | 228 | snd_printk(KERN_ERR "%s(): unable to retrieve number of sample rates (clock %d)\n", |
| 229 | __func__, clock); | ||
| 227 | goto err; | 230 | goto err; |
| 228 | } | 231 | } |
| 229 | 232 | ||
| @@ -237,12 +240,13 @@ static int parse_audio_format_rates_v2(struct snd_usb_audio *chip, | |||
| 237 | 240 | ||
| 238 | /* now get the full information */ | 241 | /* now get the full information */ |
| 239 | ret = snd_usb_ctl_msg(dev, usb_rcvctrlpipe(dev, 0), UAC2_CS_RANGE, | 242 | ret = snd_usb_ctl_msg(dev, usb_rcvctrlpipe(dev, 0), UAC2_CS_RANGE, |
| 240 | USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_IN, | 243 | USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_IN, |
| 241 | UAC2_CS_CONTROL_SAM_FREQ << 8, chip->clock_id << 8, | 244 | UAC2_CS_CONTROL_SAM_FREQ << 8, clock << 8, |
| 242 | data, data_size, 1000); | 245 | data, data_size, 1000); |
| 243 | 246 | ||
| 244 | if (ret < 0) { | 247 | if (ret < 0) { |
| 245 | snd_printk(KERN_ERR "unable to retrieve sample rate range\n"); | 248 | snd_printk(KERN_ERR "%s(): unable to retrieve sample rate range (clock %d)\n", |
| 249 | __func__, clock); | ||
| 246 | ret = -EINVAL; | 250 | ret = -EINVAL; |
| 247 | goto err_free; | 251 | goto err_free; |
| 248 | } | 252 | } |
diff --git a/sound/usb/mixer.c b/sound/usb/mixer.c index 03ce971e0027..a060d005e209 100644 --- a/sound/usb/mixer.c +++ b/sound/usb/mixer.c | |||
| @@ -78,39 +78,6 @@ enum { | |||
| 78 | USB_MIXER_U16, | 78 | USB_MIXER_U16, |
| 79 | }; | 79 | }; |
| 80 | 80 | ||
| 81 | enum { | ||
| 82 | USB_PROC_UPDOWN = 1, | ||
| 83 | USB_PROC_UPDOWN_SWITCH = 1, | ||
| 84 | USB_PROC_UPDOWN_MODE_SEL = 2, | ||
| 85 | |||
| 86 | USB_PROC_PROLOGIC = 2, | ||
| 87 | USB_PROC_PROLOGIC_SWITCH = 1, | ||
| 88 | USB_PROC_PROLOGIC_MODE_SEL = 2, | ||
| 89 | |||
| 90 | USB_PROC_3DENH = 3, | ||
| 91 | USB_PROC_3DENH_SWITCH = 1, | ||
| 92 | USB_PROC_3DENH_SPACE = 2, | ||
| 93 | |||
| 94 | USB_PROC_REVERB = 4, | ||
| 95 | USB_PROC_REVERB_SWITCH = 1, | ||
| 96 | USB_PROC_REVERB_LEVEL = 2, | ||
| 97 | USB_PROC_REVERB_TIME = 3, | ||
| 98 | USB_PROC_REVERB_DELAY = 4, | ||
| 99 | |||
| 100 | USB_PROC_CHORUS = 5, | ||
| 101 | USB_PROC_CHORUS_SWITCH = 1, | ||
| 102 | USB_PROC_CHORUS_LEVEL = 2, | ||
| 103 | USB_PROC_CHORUS_RATE = 3, | ||
| 104 | USB_PROC_CHORUS_DEPTH = 4, | ||
| 105 | |||
| 106 | USB_PROC_DCR = 6, | ||
| 107 | USB_PROC_DCR_SWITCH = 1, | ||
| 108 | USB_PROC_DCR_RATIO = 2, | ||
| 109 | USB_PROC_DCR_MAX_AMP = 3, | ||
| 110 | USB_PROC_DCR_THRESHOLD = 4, | ||
| 111 | USB_PROC_DCR_ATTACK = 5, | ||
| 112 | USB_PROC_DCR_RELEASE = 6, | ||
| 113 | }; | ||
| 114 | 81 | ||
| 115 | /*E-mu 0202(0404) eXtension Unit(XU) control*/ | 82 | /*E-mu 0202(0404) eXtension Unit(XU) control*/ |
| 116 | enum { | 83 | enum { |
| @@ -198,22 +165,24 @@ static int check_mapped_selector_name(struct mixer_build *state, int unitid, | |||
| 198 | 165 | ||
| 199 | /* | 166 | /* |
| 200 | * find an audio control unit with the given unit id | 167 | * find an audio control unit with the given unit id |
| 201 | * this doesn't return any clock related units, so they need to be handled elsewhere | ||
| 202 | */ | 168 | */ |
| 203 | static void *find_audio_control_unit(struct mixer_build *state, unsigned char unit) | 169 | static void *find_audio_control_unit(struct mixer_build *state, unsigned char unit) |
| 204 | { | 170 | { |
| 205 | unsigned char *p; | 171 | /* we just parse the header */ |
| 172 | struct uac_feature_unit_descriptor *hdr = NULL; | ||
| 206 | 173 | ||
| 207 | p = NULL; | 174 | while ((hdr = snd_usb_find_desc(state->buffer, state->buflen, hdr, |
| 208 | while ((p = snd_usb_find_desc(state->buffer, state->buflen, p, | 175 | USB_DT_CS_INTERFACE)) != NULL) { |
| 209 | USB_DT_CS_INTERFACE)) != NULL) { | 176 | if (hdr->bLength >= 4 && |
| 210 | if (p[0] >= 4 && p[2] >= UAC_INPUT_TERMINAL && p[2] <= UAC2_EXTENSION_UNIT_V2 && p[3] == unit) | 177 | hdr->bDescriptorSubtype >= UAC_INPUT_TERMINAL && |
| 211 | return p; | 178 | hdr->bDescriptorSubtype <= UAC2_SAMPLE_RATE_CONVERTER && |
| 179 | hdr->bUnitID == unit) | ||
| 180 | return hdr; | ||
| 212 | } | 181 | } |
| 182 | |||
| 213 | return NULL; | 183 | return NULL; |
| 214 | } | 184 | } |
| 215 | 185 | ||
| 216 | |||
| 217 | /* | 186 | /* |
| 218 | * copy a string with the given id | 187 | * copy a string with the given id |
| 219 | */ | 188 | */ |
| @@ -344,8 +313,8 @@ static int get_ctl_value_v2(struct usb_mixer_elem_info *cval, int request, int v | |||
| 344 | buf, sizeof(buf), 1000); | 313 | buf, sizeof(buf), 1000); |
| 345 | 314 | ||
| 346 | if (ret < 0) { | 315 | if (ret < 0) { |
| 347 | snd_printdd(KERN_ERR "cannot get ctl value: req = %#x, wValue = %#x, wIndex = %#x, type = %d\n", | 316 | snd_printk(KERN_ERR "cannot get ctl value: req = %#x, wValue = %#x, wIndex = %#x, type = %d\n", |
| 348 | request, validx, cval->mixer->ctrlif | (cval->id << 8), cval->val_type); | 317 | request, validx, cval->mixer->ctrlif | (cval->id << 8), cval->val_type); |
| 349 | return ret; | 318 | return ret; |
| 350 | } | 319 | } |
| 351 | 320 | ||
| @@ -462,6 +431,16 @@ static int set_cur_mix_value(struct usb_mixer_elem_info *cval, int channel, | |||
| 462 | int index, int value) | 431 | int index, int value) |
| 463 | { | 432 | { |
| 464 | int err; | 433 | int err; |
| 434 | unsigned int read_only = (channel == 0) ? | ||
| 435 | cval->master_readonly : | ||
| 436 | cval->ch_readonly & (1 << (channel - 1)); | ||
| 437 | |||
| 438 | if (read_only) { | ||
| 439 | snd_printdd(KERN_INFO "%s(): channel %d of control %d is read_only\n", | ||
| 440 | __func__, channel, cval->control); | ||
| 441 | return 0; | ||
| 442 | } | ||
| 443 | |||
| 465 | err = snd_usb_mixer_set_ctl_value(cval, UAC_SET_CUR, (cval->control << 8) | channel, | 444 | err = snd_usb_mixer_set_ctl_value(cval, UAC_SET_CUR, (cval->control << 8) | channel, |
| 466 | value); | 445 | value); |
| 467 | if (err < 0) | 446 | if (err < 0) |
| @@ -631,6 +610,7 @@ static int get_term_name(struct mixer_build *state, struct usb_audio_term *iterm | |||
| 631 | */ | 610 | */ |
| 632 | static int check_input_term(struct mixer_build *state, int id, struct usb_audio_term *term) | 611 | static int check_input_term(struct mixer_build *state, int id, struct usb_audio_term *term) |
| 633 | { | 612 | { |
| 613 | int err; | ||
| 634 | void *p1; | 614 | void *p1; |
| 635 | 615 | ||
| 636 | memset(term, 0, sizeof(*term)); | 616 | memset(term, 0, sizeof(*term)); |
| @@ -651,6 +631,11 @@ static int check_input_term(struct mixer_build *state, int id, struct usb_audio_ | |||
| 651 | term->channels = d->bNrChannels; | 631 | term->channels = d->bNrChannels; |
| 652 | term->chconfig = le32_to_cpu(d->bmChannelConfig); | 632 | term->chconfig = le32_to_cpu(d->bmChannelConfig); |
| 653 | term->name = d->iTerminal; | 633 | term->name = d->iTerminal; |
| 634 | |||
| 635 | /* call recursively to get the clock selectors */ | ||
| 636 | err = check_input_term(state, d->bCSourceID, term); | ||
| 637 | if (err < 0) | ||
| 638 | return err; | ||
| 654 | } | 639 | } |
| 655 | return 0; | 640 | return 0; |
| 656 | case UAC_FEATURE_UNIT: { | 641 | case UAC_FEATURE_UNIT: { |
| @@ -667,7 +652,8 @@ static int check_input_term(struct mixer_build *state, int id, struct usb_audio_ | |||
| 667 | term->name = uac_mixer_unit_iMixer(d); | 652 | term->name = uac_mixer_unit_iMixer(d); |
| 668 | return 0; | 653 | return 0; |
| 669 | } | 654 | } |
| 670 | case UAC_SELECTOR_UNIT: { | 655 | case UAC_SELECTOR_UNIT: |
| 656 | case UAC2_CLOCK_SELECTOR: { | ||
| 671 | struct uac_selector_unit_descriptor *d = p1; | 657 | struct uac_selector_unit_descriptor *d = p1; |
| 672 | /* call recursively to retrieve the channel info */ | 658 | /* call recursively to retrieve the channel info */ |
| 673 | if (check_input_term(state, d->baSourceID[0], term) < 0) | 659 | if (check_input_term(state, d->baSourceID[0], term) < 0) |
| @@ -690,6 +676,13 @@ static int check_input_term(struct mixer_build *state, int id, struct usb_audio_ | |||
| 690 | term->name = uac_processing_unit_iProcessing(d, state->mixer->protocol); | 676 | term->name = uac_processing_unit_iProcessing(d, state->mixer->protocol); |
| 691 | return 0; | 677 | return 0; |
| 692 | } | 678 | } |
| 679 | case UAC2_CLOCK_SOURCE: { | ||
| 680 | struct uac_clock_source_descriptor *d = p1; | ||
| 681 | term->type = d->bDescriptorSubtype << 16; /* virtual type */ | ||
| 682 | term->id = id; | ||
| 683 | term->name = d->iClockSource; | ||
| 684 | return 0; | ||
| 685 | } | ||
| 693 | default: | 686 | default: |
| 694 | return -ENODEV; | 687 | return -ENODEV; |
| 695 | } | 688 | } |
| @@ -709,16 +702,20 @@ struct usb_feature_control_info { | |||
| 709 | }; | 702 | }; |
| 710 | 703 | ||
| 711 | static struct usb_feature_control_info audio_feature_info[] = { | 704 | static struct usb_feature_control_info audio_feature_info[] = { |
| 712 | { "Mute", USB_MIXER_INV_BOOLEAN }, | 705 | { "Mute", USB_MIXER_INV_BOOLEAN }, |
| 713 | { "Volume", USB_MIXER_S16 }, | 706 | { "Volume", USB_MIXER_S16 }, |
| 714 | { "Tone Control - Bass", USB_MIXER_S8 }, | 707 | { "Tone Control - Bass", USB_MIXER_S8 }, |
| 715 | { "Tone Control - Mid", USB_MIXER_S8 }, | 708 | { "Tone Control - Mid", USB_MIXER_S8 }, |
| 716 | { "Tone Control - Treble", USB_MIXER_S8 }, | 709 | { "Tone Control - Treble", USB_MIXER_S8 }, |
| 717 | { "Graphic Equalizer", USB_MIXER_S8 }, /* FIXME: not implemeted yet */ | 710 | { "Graphic Equalizer", USB_MIXER_S8 }, /* FIXME: not implemeted yet */ |
| 718 | { "Auto Gain Control", USB_MIXER_BOOLEAN }, | 711 | { "Auto Gain Control", USB_MIXER_BOOLEAN }, |
| 719 | { "Delay Control", USB_MIXER_U16 }, | 712 | { "Delay Control", USB_MIXER_U16 }, |
| 720 | { "Bass Boost", USB_MIXER_BOOLEAN }, | 713 | { "Bass Boost", USB_MIXER_BOOLEAN }, |
| 721 | { "Loudness", USB_MIXER_BOOLEAN }, | 714 | { "Loudness", USB_MIXER_BOOLEAN }, |
| 715 | /* UAC2 specific */ | ||
| 716 | { "Input Gain Control", USB_MIXER_U16 }, | ||
| 717 | { "Input Gain Pad Control", USB_MIXER_BOOLEAN }, | ||
| 718 | { "Phase Inverter Control", USB_MIXER_BOOLEAN }, | ||
| 722 | }; | 719 | }; |
| 723 | 720 | ||
| 724 | 721 | ||
| @@ -958,7 +955,7 @@ static size_t append_ctl_name(struct snd_kcontrol *kctl, const char *str) | |||
| 958 | static void build_feature_ctl(struct mixer_build *state, void *raw_desc, | 955 | static void build_feature_ctl(struct mixer_build *state, void *raw_desc, |
| 959 | unsigned int ctl_mask, int control, | 956 | unsigned int ctl_mask, int control, |
| 960 | struct usb_audio_term *iterm, int unitid, | 957 | struct usb_audio_term *iterm, int unitid, |
| 961 | int read_only) | 958 | int readonly_mask) |
| 962 | { | 959 | { |
| 963 | struct uac_feature_unit_descriptor *desc = raw_desc; | 960 | struct uac_feature_unit_descriptor *desc = raw_desc; |
| 964 | unsigned int len = 0; | 961 | unsigned int len = 0; |
| @@ -970,7 +967,7 @@ static void build_feature_ctl(struct mixer_build *state, void *raw_desc, | |||
| 970 | 967 | ||
| 971 | control++; /* change from zero-based to 1-based value */ | 968 | control++; /* change from zero-based to 1-based value */ |
| 972 | 969 | ||
| 973 | if (control == UAC_GRAPHIC_EQUALIZER_CONTROL) { | 970 | if (control == UAC_FU_GRAPHIC_EQUALIZER) { |
| 974 | /* FIXME: not supported yet */ | 971 | /* FIXME: not supported yet */ |
| 975 | return; | 972 | return; |
| 976 | } | 973 | } |
| @@ -989,20 +986,25 @@ static void build_feature_ctl(struct mixer_build *state, void *raw_desc, | |||
| 989 | cval->control = control; | 986 | cval->control = control; |
| 990 | cval->cmask = ctl_mask; | 987 | cval->cmask = ctl_mask; |
| 991 | cval->val_type = audio_feature_info[control-1].type; | 988 | cval->val_type = audio_feature_info[control-1].type; |
| 992 | if (ctl_mask == 0) | 989 | if (ctl_mask == 0) { |
| 993 | cval->channels = 1; /* master channel */ | 990 | cval->channels = 1; /* master channel */ |
| 994 | else { | 991 | cval->master_readonly = readonly_mask; |
| 992 | } else { | ||
| 995 | int i, c = 0; | 993 | int i, c = 0; |
| 996 | for (i = 0; i < 16; i++) | 994 | for (i = 0; i < 16; i++) |
| 997 | if (ctl_mask & (1 << i)) | 995 | if (ctl_mask & (1 << i)) |
| 998 | c++; | 996 | c++; |
| 999 | cval->channels = c; | 997 | cval->channels = c; |
| 998 | cval->ch_readonly = readonly_mask; | ||
| 1000 | } | 999 | } |
| 1001 | 1000 | ||
| 1002 | /* get min/max values */ | 1001 | /* get min/max values */ |
| 1003 | get_min_max(cval, 0); | 1002 | get_min_max(cval, 0); |
| 1004 | 1003 | ||
| 1005 | if (read_only) | 1004 | /* if all channels in the mask are marked read-only, make the control |
| 1005 | * read-only. set_cur_mix_value() will check the mask again and won't | ||
| 1006 | * issue write commands to read-only channels. */ | ||
| 1007 | if (cval->channels == readonly_mask) | ||
| 1006 | kctl = snd_ctl_new1(&usb_feature_unit_ctl_ro, cval); | 1008 | kctl = snd_ctl_new1(&usb_feature_unit_ctl_ro, cval); |
| 1007 | else | 1009 | else |
| 1008 | kctl = snd_ctl_new1(&usb_feature_unit_ctl, cval); | 1010 | kctl = snd_ctl_new1(&usb_feature_unit_ctl, cval); |
| @@ -1021,8 +1023,8 @@ static void build_feature_ctl(struct mixer_build *state, void *raw_desc, | |||
| 1021 | kctl->id.name, sizeof(kctl->id.name)); | 1023 | kctl->id.name, sizeof(kctl->id.name)); |
| 1022 | 1024 | ||
| 1023 | switch (control) { | 1025 | switch (control) { |
| 1024 | case UAC_MUTE_CONTROL: | 1026 | case UAC_FU_MUTE: |
| 1025 | case UAC_VOLUME_CONTROL: | 1027 | case UAC_FU_VOLUME: |
| 1026 | /* determine the control name. the rule is: | 1028 | /* determine the control name. the rule is: |
| 1027 | * - if a name id is given in descriptor, use it. | 1029 | * - if a name id is given in descriptor, use it. |
| 1028 | * - if the connected input can be determined, then use the name | 1030 | * - if the connected input can be determined, then use the name |
| @@ -1049,9 +1051,9 @@ static void build_feature_ctl(struct mixer_build *state, void *raw_desc, | |||
| 1049 | len = append_ctl_name(kctl, " Playback"); | 1051 | len = append_ctl_name(kctl, " Playback"); |
| 1050 | } | 1052 | } |
| 1051 | } | 1053 | } |
| 1052 | append_ctl_name(kctl, control == UAC_MUTE_CONTROL ? | 1054 | append_ctl_name(kctl, control == UAC_FU_MUTE ? |
| 1053 | " Switch" : " Volume"); | 1055 | " Switch" : " Volume"); |
| 1054 | if (control == UAC_VOLUME_CONTROL) { | 1056 | if (control == UAC_FU_VOLUME) { |
| 1055 | kctl->tlv.c = mixer_vol_tlv; | 1057 | kctl->tlv.c = mixer_vol_tlv; |
| 1056 | kctl->vd[0].access |= | 1058 | kctl->vd[0].access |= |
| 1057 | SNDRV_CTL_ELEM_ACCESS_TLV_READ | | 1059 | SNDRV_CTL_ELEM_ACCESS_TLV_READ | |
| @@ -1150,7 +1152,7 @@ static int parse_audio_feature_unit(struct mixer_build *state, int unitid, void | |||
| 1150 | snd_printk(KERN_INFO | 1152 | snd_printk(KERN_INFO |
| 1151 | "usbmixer: master volume quirk for PCM2702 chip\n"); | 1153 | "usbmixer: master volume quirk for PCM2702 chip\n"); |
| 1152 | /* disable non-functional volume control */ | 1154 | /* disable non-functional volume control */ |
| 1153 | master_bits &= ~UAC_FU_VOLUME; | 1155 | master_bits &= ~UAC_CONTROL_BIT(UAC_FU_VOLUME); |
| 1154 | break; | 1156 | break; |
| 1155 | } | 1157 | } |
| 1156 | if (channels > 0) | 1158 | if (channels > 0) |
| @@ -1188,19 +1190,22 @@ static int parse_audio_feature_unit(struct mixer_build *state, int unitid, void | |||
| 1188 | 1190 | ||
| 1189 | for (j = 0; j < channels; j++) { | 1191 | for (j = 0; j < channels; j++) { |
| 1190 | unsigned int mask = snd_usb_combine_bytes(bmaControls + csize * (j+1), csize); | 1192 | unsigned int mask = snd_usb_combine_bytes(bmaControls + csize * (j+1), csize); |
| 1191 | if (mask & (1 << (i * 2))) { | 1193 | if (uac2_control_is_readable(mask, i)) { |
| 1192 | ch_bits |= (1 << j); | 1194 | ch_bits |= (1 << j); |
| 1193 | if (~mask & (1 << ((i * 2) + 1))) | 1195 | if (!uac2_control_is_writeable(mask, i)) |
| 1194 | ch_read_only |= (1 << j); | 1196 | ch_read_only |= (1 << j); |
| 1195 | } | 1197 | } |
| 1196 | } | 1198 | } |
| 1197 | 1199 | ||
| 1198 | /* FIXME: the whole unit is read-only if any of the channels is marked read-only */ | 1200 | /* NOTE: build_feature_ctl() will mark the control read-only if all channels |
| 1201 | * are marked read-only in the descriptors. Otherwise, the control will be | ||
| 1202 | * reported as writeable, but the driver will not actually issue a write | ||
| 1203 | * command for read-only channels */ | ||
| 1199 | if (ch_bits & 1) /* the first channel must be set (for ease of programming) */ | 1204 | if (ch_bits & 1) /* the first channel must be set (for ease of programming) */ |
| 1200 | build_feature_ctl(state, _ftr, ch_bits, i, &iterm, unitid, !!ch_read_only); | 1205 | build_feature_ctl(state, _ftr, ch_bits, i, &iterm, unitid, ch_read_only); |
| 1201 | if (master_bits & (1 << i * 2)) | 1206 | if (uac2_control_is_readable(master_bits, i)) |
| 1202 | build_feature_ctl(state, _ftr, 0, i, &iterm, unitid, | 1207 | build_feature_ctl(state, _ftr, 0, i, &iterm, unitid, |
| 1203 | ~master_bits & (1 << ((i * 2) + 1))); | 1208 | !uac2_control_is_writeable(master_bits, i)); |
| 1204 | } | 1209 | } |
| 1205 | } | 1210 | } |
| 1206 | 1211 | ||
| @@ -1392,51 +1397,51 @@ struct procunit_info { | |||
| 1392 | }; | 1397 | }; |
| 1393 | 1398 | ||
| 1394 | static struct procunit_value_info updown_proc_info[] = { | 1399 | static struct procunit_value_info updown_proc_info[] = { |
| 1395 | { USB_PROC_UPDOWN_SWITCH, "Switch", USB_MIXER_BOOLEAN }, | 1400 | { UAC_UD_ENABLE, "Switch", USB_MIXER_BOOLEAN }, |
| 1396 | { USB_PROC_UPDOWN_MODE_SEL, "Mode Select", USB_MIXER_U8, 1 }, | 1401 | { UAC_UD_MODE_SELECT, "Mode Select", USB_MIXER_U8, 1 }, |
| 1397 | { 0 } | 1402 | { 0 } |
| 1398 | }; | 1403 | }; |
| 1399 | static struct procunit_value_info prologic_proc_info[] = { | 1404 | static struct procunit_value_info prologic_proc_info[] = { |
| 1400 | { USB_PROC_PROLOGIC_SWITCH, "Switch", USB_MIXER_BOOLEAN }, | 1405 | { UAC_DP_ENABLE, "Switch", USB_MIXER_BOOLEAN }, |
| 1401 | { USB_PROC_PROLOGIC_MODE_SEL, "Mode Select", USB_MIXER_U8, 1 }, | 1406 | { UAC_DP_MODE_SELECT, "Mode Select", USB_MIXER_U8, 1 }, |
| 1402 | { 0 } | 1407 | { 0 } |
| 1403 | }; | 1408 | }; |
| 1404 | static struct procunit_value_info threed_enh_proc_info[] = { | 1409 | static struct procunit_value_info threed_enh_proc_info[] = { |
| 1405 | { USB_PROC_3DENH_SWITCH, "Switch", USB_MIXER_BOOLEAN }, | 1410 | { UAC_3D_ENABLE, "Switch", USB_MIXER_BOOLEAN }, |
| 1406 | { USB_PROC_3DENH_SPACE, "Spaciousness", USB_MIXER_U8 }, | 1411 | { UAC_3D_SPACE, "Spaciousness", USB_MIXER_U8 }, |
| 1407 | { 0 } | 1412 | { 0 } |
| 1408 | }; | 1413 | }; |
| 1409 | static struct procunit_value_info reverb_proc_info[] = { | 1414 | static struct procunit_value_info reverb_proc_info[] = { |
| 1410 | { USB_PROC_REVERB_SWITCH, "Switch", USB_MIXER_BOOLEAN }, | 1415 | { UAC_REVERB_ENABLE, "Switch", USB_MIXER_BOOLEAN }, |
| 1411 | { USB_PROC_REVERB_LEVEL, "Level", USB_MIXER_U8 }, | 1416 | { UAC_REVERB_LEVEL, "Level", USB_MIXER_U8 }, |
| 1412 | { USB_PROC_REVERB_TIME, "Time", USB_MIXER_U16 }, | 1417 | { UAC_REVERB_TIME, "Time", USB_MIXER_U16 }, |
| 1413 | { USB_PROC_REVERB_DELAY, "Delay", USB_MIXER_U8 }, | 1418 | { UAC_REVERB_FEEDBACK, "Feedback", USB_MIXER_U8 }, |
| 1414 | { 0 } | 1419 | { 0 } |
| 1415 | }; | 1420 | }; |
| 1416 | static struct procunit_value_info chorus_proc_info[] = { | 1421 | static struct procunit_value_info chorus_proc_info[] = { |
| 1417 | { USB_PROC_CHORUS_SWITCH, "Switch", USB_MIXER_BOOLEAN }, | 1422 | { UAC_CHORUS_ENABLE, "Switch", USB_MIXER_BOOLEAN }, |
| 1418 | { USB_PROC_CHORUS_LEVEL, "Level", USB_MIXER_U8 }, | 1423 | { UAC_CHORUS_LEVEL, "Level", USB_MIXER_U8 }, |
| 1419 | { USB_PROC_CHORUS_RATE, "Rate", USB_MIXER_U16 }, | 1424 | { UAC_CHORUS_RATE, "Rate", USB_MIXER_U16 }, |
| 1420 | { USB_PROC_CHORUS_DEPTH, "Depth", USB_MIXER_U16 }, | 1425 | { UAC_CHORUS_DEPTH, "Depth", USB_MIXER_U16 }, |
| 1421 | { 0 } | 1426 | { 0 } |
| 1422 | }; | 1427 | }; |
| 1423 | static struct procunit_value_info dcr_proc_info[] = { | 1428 | static struct procunit_value_info dcr_proc_info[] = { |
| 1424 | { USB_PROC_DCR_SWITCH, "Switch", USB_MIXER_BOOLEAN }, | 1429 | { UAC_DCR_ENABLE, "Switch", USB_MIXER_BOOLEAN }, |
| 1425 | { USB_PROC_DCR_RATIO, "Ratio", USB_MIXER_U16 }, | 1430 | { UAC_DCR_RATE, "Ratio", USB_MIXER_U16 }, |
| 1426 | { USB_PROC_DCR_MAX_AMP, "Max Amp", USB_MIXER_S16 }, | 1431 | { UAC_DCR_MAXAMPL, "Max Amp", USB_MIXER_S16 }, |
| 1427 | { USB_PROC_DCR_THRESHOLD, "Threshold", USB_MIXER_S16 }, | 1432 | { UAC_DCR_THRESHOLD, "Threshold", USB_MIXER_S16 }, |
| 1428 | { USB_PROC_DCR_ATTACK, "Attack Time", USB_MIXER_U16 }, | 1433 | { UAC_DCR_ATTACK_TIME, "Attack Time", USB_MIXER_U16 }, |
| 1429 | { USB_PROC_DCR_RELEASE, "Release Time", USB_MIXER_U16 }, | 1434 | { UAC_DCR_RELEASE_TIME, "Release Time", USB_MIXER_U16 }, |
| 1430 | { 0 } | 1435 | { 0 } |
| 1431 | }; | 1436 | }; |
| 1432 | 1437 | ||
| 1433 | static struct procunit_info procunits[] = { | 1438 | static struct procunit_info procunits[] = { |
| 1434 | { USB_PROC_UPDOWN, "Up Down", updown_proc_info }, | 1439 | { UAC_PROCESS_UP_DOWNMIX, "Up Down", updown_proc_info }, |
| 1435 | { USB_PROC_PROLOGIC, "Dolby Prologic", prologic_proc_info }, | 1440 | { UAC_PROCESS_DOLBY_PROLOGIC, "Dolby Prologic", prologic_proc_info }, |
| 1436 | { USB_PROC_3DENH, "3D Stereo Extender", threed_enh_proc_info }, | 1441 | { UAC_PROCESS_STEREO_EXTENDER, "3D Stereo Extender", threed_enh_proc_info }, |
| 1437 | { USB_PROC_REVERB, "Reverb", reverb_proc_info }, | 1442 | { UAC_PROCESS_REVERB, "Reverb", reverb_proc_info }, |
| 1438 | { USB_PROC_CHORUS, "Chorus", chorus_proc_info }, | 1443 | { UAC_PROCESS_CHORUS, "Chorus", chorus_proc_info }, |
| 1439 | { USB_PROC_DCR, "DCR", dcr_proc_info }, | 1444 | { UAC_PROCESS_DYN_RANGE_COMP, "DCR", dcr_proc_info }, |
| 1440 | { 0 }, | 1445 | { 0 }, |
| 1441 | }; | 1446 | }; |
| 1442 | /* | 1447 | /* |
| @@ -1524,7 +1529,7 @@ static int build_audio_procunit(struct mixer_build *state, int unitid, void *raw | |||
| 1524 | cval->channels = 1; | 1529 | cval->channels = 1; |
| 1525 | 1530 | ||
| 1526 | /* get min/max values */ | 1531 | /* get min/max values */ |
| 1527 | if (type == USB_PROC_UPDOWN && cval->control == USB_PROC_UPDOWN_MODE_SEL) { | 1532 | if (type == UAC_PROCESS_UP_DOWNMIX && cval->control == UAC_UD_MODE_SELECT) { |
| 1528 | __u8 *control_spec = uac_processing_unit_specific(desc, state->mixer->protocol); | 1533 | __u8 *control_spec = uac_processing_unit_specific(desc, state->mixer->protocol); |
| 1529 | /* FIXME: hard-coded */ | 1534 | /* FIXME: hard-coded */ |
| 1530 | cval->min = 1; | 1535 | cval->min = 1; |
| @@ -1619,7 +1624,7 @@ static int mixer_ctl_selector_get(struct snd_kcontrol *kcontrol, struct snd_ctl_ | |||
| 1619 | struct usb_mixer_elem_info *cval = kcontrol->private_data; | 1624 | struct usb_mixer_elem_info *cval = kcontrol->private_data; |
| 1620 | int val, err; | 1625 | int val, err; |
| 1621 | 1626 | ||
| 1622 | err = get_cur_ctl_value(cval, 0, &val); | 1627 | err = get_cur_ctl_value(cval, cval->control << 8, &val); |
| 1623 | if (err < 0) { | 1628 | if (err < 0) { |
| 1624 | if (cval->mixer->ignore_ctl_error) { | 1629 | if (cval->mixer->ignore_ctl_error) { |
| 1625 | ucontrol->value.enumerated.item[0] = 0; | 1630 | ucontrol->value.enumerated.item[0] = 0; |
| @@ -1638,7 +1643,7 @@ static int mixer_ctl_selector_put(struct snd_kcontrol *kcontrol, struct snd_ctl_ | |||
| 1638 | struct usb_mixer_elem_info *cval = kcontrol->private_data; | 1643 | struct usb_mixer_elem_info *cval = kcontrol->private_data; |
| 1639 | int val, oval, err; | 1644 | int val, oval, err; |
| 1640 | 1645 | ||
| 1641 | err = get_cur_ctl_value(cval, 0, &oval); | 1646 | err = get_cur_ctl_value(cval, cval->control << 8, &oval); |
| 1642 | if (err < 0) { | 1647 | if (err < 0) { |
| 1643 | if (cval->mixer->ignore_ctl_error) | 1648 | if (cval->mixer->ignore_ctl_error) |
| 1644 | return 0; | 1649 | return 0; |
| @@ -1647,7 +1652,7 @@ static int mixer_ctl_selector_put(struct snd_kcontrol *kcontrol, struct snd_ctl_ | |||
| 1647 | val = ucontrol->value.enumerated.item[0]; | 1652 | val = ucontrol->value.enumerated.item[0]; |
| 1648 | val = get_abs_value(cval, val); | 1653 | val = get_abs_value(cval, val); |
| 1649 | if (val != oval) { | 1654 | if (val != oval) { |
| 1650 | set_cur_ctl_value(cval, 0, val); | 1655 | set_cur_ctl_value(cval, cval->control << 8, val); |
| 1651 | return 1; | 1656 | return 1; |
| 1652 | } | 1657 | } |
| 1653 | return 0; | 1658 | return 0; |
| @@ -1729,6 +1734,11 @@ static int parse_audio_selector_unit(struct mixer_build *state, int unitid, void | |||
| 1729 | cval->res = 1; | 1734 | cval->res = 1; |
| 1730 | cval->initialized = 1; | 1735 | cval->initialized = 1; |
| 1731 | 1736 | ||
| 1737 | if (desc->bDescriptorSubtype == UAC2_CLOCK_SELECTOR) | ||
| 1738 | cval->control = UAC2_CX_CLOCK_SELECTOR; | ||
| 1739 | else | ||
| 1740 | cval->control = 0; | ||
| 1741 | |||
| 1732 | namelist = kmalloc(sizeof(char *) * desc->bNrInPins, GFP_KERNEL); | 1742 | namelist = kmalloc(sizeof(char *) * desc->bNrInPins, GFP_KERNEL); |
| 1733 | if (! namelist) { | 1743 | if (! namelist) { |
| 1734 | snd_printk(KERN_ERR "cannot malloc\n"); | 1744 | snd_printk(KERN_ERR "cannot malloc\n"); |
| @@ -1778,7 +1788,9 @@ static int parse_audio_selector_unit(struct mixer_build *state, int unitid, void | |||
| 1778 | if (! len) | 1788 | if (! len) |
| 1779 | strlcpy(kctl->id.name, "USB", sizeof(kctl->id.name)); | 1789 | strlcpy(kctl->id.name, "USB", sizeof(kctl->id.name)); |
| 1780 | 1790 | ||
| 1781 | if ((state->oterm.type & 0xff00) == 0x0100) | 1791 | if (desc->bDescriptorSubtype == UAC2_CLOCK_SELECTOR) |
| 1792 | append_ctl_name(kctl, " Clock Source"); | ||
| 1793 | else if ((state->oterm.type & 0xff00) == 0x0100) | ||
| 1782 | append_ctl_name(kctl, " Capture Source"); | 1794 | append_ctl_name(kctl, " Capture Source"); |
| 1783 | else | 1795 | else |
| 1784 | append_ctl_name(kctl, " Playback Source"); | 1796 | append_ctl_name(kctl, " Playback Source"); |
| @@ -1812,10 +1824,12 @@ static int parse_audio_unit(struct mixer_build *state, int unitid) | |||
| 1812 | 1824 | ||
| 1813 | switch (p1[2]) { | 1825 | switch (p1[2]) { |
| 1814 | case UAC_INPUT_TERMINAL: | 1826 | case UAC_INPUT_TERMINAL: |
| 1827 | case UAC2_CLOCK_SOURCE: | ||
| 1815 | return 0; /* NOP */ | 1828 | return 0; /* NOP */ |
| 1816 | case UAC_MIXER_UNIT: | 1829 | case UAC_MIXER_UNIT: |
| 1817 | return parse_audio_mixer_unit(state, unitid, p1); | 1830 | return parse_audio_mixer_unit(state, unitid, p1); |
| 1818 | case UAC_SELECTOR_UNIT: | 1831 | case UAC_SELECTOR_UNIT: |
| 1832 | case UAC2_CLOCK_SELECTOR: | ||
| 1819 | return parse_audio_selector_unit(state, unitid, p1); | 1833 | return parse_audio_selector_unit(state, unitid, p1); |
| 1820 | case UAC_FEATURE_UNIT: | 1834 | case UAC_FEATURE_UNIT: |
| 1821 | return parse_audio_feature_unit(state, unitid, p1); | 1835 | return parse_audio_feature_unit(state, unitid, p1); |
| @@ -1912,6 +1926,11 @@ static int snd_usb_mixer_controls(struct usb_mixer_interface *mixer) | |||
| 1912 | err = parse_audio_unit(&state, desc->bSourceID); | 1926 | err = parse_audio_unit(&state, desc->bSourceID); |
| 1913 | if (err < 0) | 1927 | if (err < 0) |
| 1914 | return err; | 1928 | return err; |
| 1929 | |||
| 1930 | /* for UAC2, use the same approach to also add the clock selectors */ | ||
| 1931 | err = parse_audio_unit(&state, desc->bCSourceID); | ||
| 1932 | if (err < 0) | ||
| 1933 | return err; | ||
| 1915 | } | 1934 | } |
| 1916 | } | 1935 | } |
| 1917 | 1936 | ||
diff --git a/sound/usb/mixer.h b/sound/usb/mixer.h index 130123854a6c..a7cf1007fbb0 100644 --- a/sound/usb/mixer.h +++ b/sound/usb/mixer.h | |||
| @@ -34,6 +34,8 @@ struct usb_mixer_elem_info { | |||
| 34 | unsigned int id; | 34 | unsigned int id; |
| 35 | unsigned int control; /* CS or ICN (high byte) */ | 35 | unsigned int control; /* CS or ICN (high byte) */ |
| 36 | unsigned int cmask; /* channel mask bitmap: 0 = master */ | 36 | unsigned int cmask; /* channel mask bitmap: 0 = master */ |
| 37 | unsigned int ch_readonly; | ||
| 38 | unsigned int master_readonly; | ||
| 37 | int channels; | 39 | int channels; |
| 38 | int val_type; | 40 | int val_type; |
| 39 | int min, max, res; | 41 | int min, max, res; |
diff --git a/sound/usb/mixer_maps.c b/sound/usb/mixer_maps.c index d93fc89beba8..f1324c423835 100644 --- a/sound/usb/mixer_maps.c +++ b/sound/usb/mixer_maps.c | |||
| @@ -85,8 +85,8 @@ static struct usbmix_name_map extigy_map[] = { | |||
| 85 | /* 16: MU (w/o controls) */ | 85 | /* 16: MU (w/o controls) */ |
| 86 | { 17, NULL, 1 }, /* DISABLED: PU-switch (any effect?) */ | 86 | { 17, NULL, 1 }, /* DISABLED: PU-switch (any effect?) */ |
| 87 | { 17, "Channel Routing", 2 }, /* PU: mode select */ | 87 | { 17, "Channel Routing", 2 }, /* PU: mode select */ |
| 88 | { 18, "Tone Control - Bass", UAC_BASS_CONTROL }, /* FU */ | 88 | { 18, "Tone Control - Bass", UAC_FU_BASS }, /* FU */ |
| 89 | { 18, "Tone Control - Treble", UAC_TREBLE_CONTROL }, /* FU */ | 89 | { 18, "Tone Control - Treble", UAC_FU_TREBLE }, /* FU */ |
| 90 | { 18, "Master Playback" }, /* FU; others */ | 90 | { 18, "Master Playback" }, /* FU; others */ |
| 91 | /* 19: OT speaker */ | 91 | /* 19: OT speaker */ |
| 92 | /* 20: OT headphone */ | 92 | /* 20: OT headphone */ |
diff --git a/sound/usb/pcm.c b/sound/usb/pcm.c index 056587de7be4..456829882f40 100644 --- a/sound/usb/pcm.c +++ b/sound/usb/pcm.c | |||
| @@ -31,6 +31,7 @@ | |||
| 31 | #include "urb.h" | 31 | #include "urb.h" |
| 32 | #include "helper.h" | 32 | #include "helper.h" |
| 33 | #include "pcm.h" | 33 | #include "pcm.h" |
| 34 | #include "clock.h" | ||
| 34 | 35 | ||
| 35 | /* | 36 | /* |
| 36 | * return the current pcm pointer. just based on the hwptr_done value. | 37 | * return the current pcm pointer. just based on the hwptr_done value. |
| @@ -181,103 +182,6 @@ int snd_usb_init_pitch(struct snd_usb_audio *chip, int iface, | |||
| 181 | return -EINVAL; | 182 | return -EINVAL; |
| 182 | } | 183 | } |
| 183 | 184 | ||
| 184 | static int set_sample_rate_v1(struct snd_usb_audio *chip, int iface, | ||
| 185 | struct usb_host_interface *alts, | ||
| 186 | struct audioformat *fmt, int rate) | ||
| 187 | { | ||
| 188 | struct usb_device *dev = chip->dev; | ||
| 189 | unsigned int ep; | ||
| 190 | unsigned char data[3]; | ||
| 191 | int err, crate; | ||
| 192 | |||
| 193 | ep = get_endpoint(alts, 0)->bEndpointAddress; | ||
| 194 | /* if endpoint doesn't have sampling rate control, bail out */ | ||
| 195 | if (!(fmt->attributes & UAC_EP_CS_ATTR_SAMPLE_RATE)) { | ||
| 196 | snd_printk(KERN_WARNING "%d:%d:%d: endpoint lacks sample rate attribute bit, cannot set.\n", | ||
| 197 | dev->devnum, iface, fmt->altsetting); | ||
| 198 | return 0; | ||
| 199 | } | ||
| 200 | |||
| 201 | data[0] = rate; | ||
| 202 | data[1] = rate >> 8; | ||
| 203 | data[2] = rate >> 16; | ||
| 204 | if ((err = snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0), UAC_SET_CUR, | ||
| 205 | USB_TYPE_CLASS|USB_RECIP_ENDPOINT|USB_DIR_OUT, | ||
| 206 | UAC_EP_CS_ATTR_SAMPLE_RATE << 8, ep, | ||
| 207 | data, sizeof(data), 1000)) < 0) { | ||
| 208 | snd_printk(KERN_ERR "%d:%d:%d: cannot set freq %d to ep %#x\n", | ||
| 209 | dev->devnum, iface, fmt->altsetting, rate, ep); | ||
| 210 | return err; | ||
| 211 | } | ||
| 212 | if ((err = snd_usb_ctl_msg(dev, usb_rcvctrlpipe(dev, 0), UAC_GET_CUR, | ||
| 213 | USB_TYPE_CLASS|USB_RECIP_ENDPOINT|USB_DIR_IN, | ||
| 214 | UAC_EP_CS_ATTR_SAMPLE_RATE << 8, ep, | ||
| 215 | data, sizeof(data), 1000)) < 0) { | ||
| 216 | snd_printk(KERN_WARNING "%d:%d:%d: cannot get freq at ep %#x\n", | ||
| 217 | dev->devnum, iface, fmt->altsetting, ep); | ||
| 218 | return 0; /* some devices don't support reading */ | ||
| 219 | } | ||
| 220 | crate = data[0] | (data[1] << 8) | (data[2] << 16); | ||
| 221 | if (crate != rate) { | ||
| 222 | snd_printd(KERN_WARNING "current rate %d is different from the runtime rate %d\n", crate, rate); | ||
| 223 | // runtime->rate = crate; | ||
| 224 | } | ||
| 225 | |||
| 226 | return 0; | ||
| 227 | } | ||
| 228 | |||
| 229 | static int set_sample_rate_v2(struct snd_usb_audio *chip, int iface, | ||
| 230 | struct usb_host_interface *alts, | ||
| 231 | struct audioformat *fmt, int rate) | ||
| 232 | { | ||
| 233 | struct usb_device *dev = chip->dev; | ||
| 234 | unsigned char data[4]; | ||
| 235 | int err, crate; | ||
| 236 | |||
| 237 | data[0] = rate; | ||
| 238 | data[1] = rate >> 8; | ||
| 239 | data[2] = rate >> 16; | ||
| 240 | data[3] = rate >> 24; | ||
| 241 | if ((err = snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0), UAC2_CS_CUR, | ||
| 242 | USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_OUT, | ||
| 243 | UAC2_CS_CONTROL_SAM_FREQ << 8, chip->clock_id << 8, | ||
| 244 | data, sizeof(data), 1000)) < 0) { | ||
| 245 | snd_printk(KERN_ERR "%d:%d:%d: cannot set freq %d (v2)\n", | ||
| 246 | dev->devnum, iface, fmt->altsetting, rate); | ||
| 247 | return err; | ||
| 248 | } | ||
| 249 | if ((err = snd_usb_ctl_msg(dev, usb_rcvctrlpipe(dev, 0), UAC2_CS_CUR, | ||
| 250 | USB_TYPE_CLASS | USB_RECIP_INTERFACE | USB_DIR_IN, | ||
| 251 | UAC2_CS_CONTROL_SAM_FREQ << 8, chip->clock_id << 8, | ||
| 252 | data, sizeof(data), 1000)) < 0) { | ||
| 253 | snd_printk(KERN_WARNING "%d:%d:%d: cannot get freq (v2)\n", | ||
| 254 | dev->devnum, iface, fmt->altsetting); | ||
| 255 | return err; | ||
| 256 | } | ||
| 257 | crate = data[0] | (data[1] << 8) | (data[2] << 16) | (data[3] << 24); | ||
| 258 | if (crate != rate) | ||
| 259 | snd_printd(KERN_WARNING "current rate %d is different from the runtime rate %d\n", crate, rate); | ||
| 260 | |||
| 261 | return 0; | ||
| 262 | } | ||
| 263 | |||
| 264 | int snd_usb_init_sample_rate(struct snd_usb_audio *chip, int iface, | ||
| 265 | struct usb_host_interface *alts, | ||
| 266 | struct audioformat *fmt, int rate) | ||
| 267 | { | ||
| 268 | struct usb_interface_descriptor *altsd = get_iface_desc(alts); | ||
| 269 | |||
| 270 | switch (altsd->bInterfaceProtocol) { | ||
| 271 | case UAC_VERSION_1: | ||
| 272 | return set_sample_rate_v1(chip, iface, alts, fmt, rate); | ||
| 273 | |||
| 274 | case UAC_VERSION_2: | ||
| 275 | return set_sample_rate_v2(chip, iface, alts, fmt, rate); | ||
| 276 | } | ||
| 277 | |||
| 278 | return -EINVAL; | ||
| 279 | } | ||
| 280 | |||
| 281 | /* | 185 | /* |
| 282 | * find a matching format and set up the interface | 186 | * find a matching format and set up the interface |
| 283 | */ | 187 | */ |
diff --git a/sound/usb/usbaudio.h b/sound/usb/usbaudio.h index 06ebf24d3a4d..24d3319cc34d 100644 --- a/sound/usb/usbaudio.h +++ b/sound/usb/usbaudio.h | |||
| @@ -40,9 +40,6 @@ struct snd_usb_audio { | |||
| 40 | int num_interfaces; | 40 | int num_interfaces; |
| 41 | int num_suspended_intf; | 41 | int num_suspended_intf; |
| 42 | 42 | ||
| 43 | /* for audio class v2 */ | ||
| 44 | int clock_id; | ||
| 45 | |||
| 46 | struct list_head pcm_list; /* list of pcm streams */ | 43 | struct list_head pcm_list; /* list of pcm streams */ |
| 47 | int pcm_devs; | 44 | int pcm_devs; |
| 48 | 45 | ||
| @@ -53,6 +50,8 @@ struct snd_usb_audio { | |||
| 53 | int setup; /* from the 'device_setup' module param */ | 50 | int setup; /* from the 'device_setup' module param */ |
| 54 | int nrpacks; /* from the 'nrpacks' module param */ | 51 | int nrpacks; /* from the 'nrpacks' module param */ |
| 55 | int async_unlink; /* from the 'async_unlink' module param */ | 52 | int async_unlink; /* from the 'async_unlink' module param */ |
| 53 | |||
| 54 | struct usb_host_interface *ctrl_intf; /* the audio control interface */ | ||
| 56 | }; | 55 | }; |
| 57 | 56 | ||
| 58 | /* | 57 | /* |
