diff options
author | Takashi Iwai <tiwai@suse.de> | 2018-06-04 05:41:48 -0400 |
---|---|---|
committer | Takashi Iwai <tiwai@suse.de> | 2018-06-04 05:42:27 -0400 |
commit | cdbc653a04ee692a7105a96e8dd6055d9971d45c (patch) | |
tree | c1282680b3115edfd693a27bc6758208534ac557 | |
parent | 009f8c90f571d87855914dbc20e6c0ea2a3b19ae (diff) | |
parent | ceec4684085a9e4dc60439d84ab47ce260444804 (diff) |
Merge branch 'for-next' into for-linus
4.18-rc1 merge material.
Signed-off-by: Takashi Iwai <tiwai@suse.de>
129 files changed, 8705 insertions, 1431 deletions
diff --git a/Documentation/sound/alsa-configuration.rst b/Documentation/sound/alsa-configuration.rst index aed6b4fb8e46..b1052e18292d 100644 --- a/Documentation/sound/alsa-configuration.rst +++ b/Documentation/sound/alsa-configuration.rst | |||
@@ -2224,6 +2224,13 @@ quirk_alias | |||
2224 | Quirk alias list, pass strings like ``0123abcd:5678beef``, which | 2224 | Quirk alias list, pass strings like ``0123abcd:5678beef``, which |
2225 | applies the existing quirk for the device 5678:beef to a new | 2225 | applies the existing quirk for the device 5678:beef to a new |
2226 | device 0123:abcd. | 2226 | device 0123:abcd. |
2227 | use_vmalloc | ||
2228 | Use vmalloc() for allocations of the PCM buffers (default: yes). | ||
2229 | For architectures with non-coherent memory like ARM or MIPS, the | ||
2230 | mmap access may give inconsistent results with vmalloc'ed | ||
2231 | buffers. If mmap is used on such architectures, turn off this | ||
2232 | option, so that the DMA-coherent buffers are allocated and used | ||
2233 | instead. | ||
2227 | 2234 | ||
2228 | This module supports multiple devices, autoprobe and hotplugging. | 2235 | This module supports multiple devices, autoprobe and hotplugging. |
2229 | 2236 | ||
diff --git a/Documentation/sound/hd-audio/models.rst b/Documentation/sound/hd-audio/models.rst index 1fee5a4f6660..7c2d37571af0 100644 --- a/Documentation/sound/hd-audio/models.rst +++ b/Documentation/sound/hd-audio/models.rst | |||
@@ -263,6 +263,8 @@ hp-dock | |||
263 | HP dock support | 263 | HP dock support |
264 | mute-led-gpio | 264 | mute-led-gpio |
265 | Mute LED control via GPIO | 265 | Mute LED control via GPIO |
266 | hp-mic-fix | ||
267 | Fix for headset mic pin on HP boxes | ||
266 | 268 | ||
267 | STAC9200 | 269 | STAC9200 |
268 | ======== | 270 | ======== |
diff --git a/MAINTAINERS b/MAINTAINERS index 92be777d060a..bd214e061359 100644 --- a/MAINTAINERS +++ b/MAINTAINERS | |||
@@ -15494,6 +15494,13 @@ S: Supported | |||
15494 | F: arch/x86/xen/*swiotlb* | 15494 | F: arch/x86/xen/*swiotlb* |
15495 | F: drivers/xen/*swiotlb* | 15495 | F: drivers/xen/*swiotlb* |
15496 | 15496 | ||
15497 | XEN SOUND FRONTEND DRIVER | ||
15498 | M: Oleksandr Andrushchenko <oleksandr_andrushchenko@epam.com> | ||
15499 | L: xen-devel@lists.xenproject.org (moderated for non-subscribers) | ||
15500 | L: alsa-devel@alsa-project.org (moderated for non-subscribers) | ||
15501 | S: Supported | ||
15502 | F: sound/xen/* | ||
15503 | |||
15497 | XFS FILESYSTEM | 15504 | XFS FILESYSTEM |
15498 | M: Darrick J. Wong <darrick.wong@oracle.com> | 15505 | M: Darrick J. Wong <darrick.wong@oracle.com> |
15499 | M: linux-xfs@vger.kernel.org | 15506 | M: linux-xfs@vger.kernel.org |
diff --git a/include/linux/usb/audio-v2.h b/include/linux/usb/audio-v2.h index aaafecf073ff..a96ed2ce3254 100644 --- a/include/linux/usb/audio-v2.h +++ b/include/linux/usb/audio-v2.h | |||
@@ -189,6 +189,13 @@ struct uac2_iso_endpoint_descriptor { | |||
189 | #define UAC2_CONTROL_DATA_OVERRUN (3 << 2) | 189 | #define UAC2_CONTROL_DATA_OVERRUN (3 << 2) |
190 | #define UAC2_CONTROL_DATA_UNDERRUN (3 << 4) | 190 | #define UAC2_CONTROL_DATA_UNDERRUN (3 << 4) |
191 | 191 | ||
192 | /* 5.2.5.4.2 Connector Control Parameter Block */ | ||
193 | struct uac2_connectors_ctl_blk { | ||
194 | __u8 bNrChannels; | ||
195 | __le32 bmChannelConfig; | ||
196 | __u8 iChannelNames; | ||
197 | } __attribute__((packed)); | ||
198 | |||
192 | /* 6.1 Interrupt Data Message */ | 199 | /* 6.1 Interrupt Data Message */ |
193 | 200 | ||
194 | #define UAC2_INTERRUPT_DATA_MSG_VENDOR (1 << 0) | 201 | #define UAC2_INTERRUPT_DATA_MSG_VENDOR (1 << 0) |
diff --git a/include/linux/usb/audio-v3.h b/include/linux/usb/audio-v3.h index a8959aaba0ae..a710e28b5215 100644 --- a/include/linux/usb/audio-v3.h +++ b/include/linux/usb/audio-v3.h | |||
@@ -221,6 +221,12 @@ struct uac3_iso_endpoint_descriptor { | |||
221 | __le16 wLockDelay; | 221 | __le16 wLockDelay; |
222 | } __attribute__((packed)); | 222 | } __attribute__((packed)); |
223 | 223 | ||
224 | /* 5.2.1.6.1 INSERTION CONTROL PARAMETER BLOCK */ | ||
225 | struct uac3_insertion_ctl_blk { | ||
226 | __u8 bSize; | ||
227 | __u8 bmConInserted; | ||
228 | } __attribute__ ((packed)); | ||
229 | |||
224 | /* 6.1 INTERRUPT DATA MESSAGE */ | 230 | /* 6.1 INTERRUPT DATA MESSAGE */ |
225 | struct uac3_interrupt_data_msg { | 231 | struct uac3_interrupt_data_msg { |
226 | __u8 bInfo; | 232 | __u8 bInfo; |
@@ -392,4 +398,38 @@ struct uac3_interrupt_data_msg { | |||
392 | #define UAC3_AC_ACTIVE_INTERFACE_CONTROL 0x01 | 398 | #define UAC3_AC_ACTIVE_INTERFACE_CONTROL 0x01 |
393 | #define UAC3_AC_POWER_DOMAIN_CONTROL 0x02 | 399 | #define UAC3_AC_POWER_DOMAIN_CONTROL 0x02 |
394 | 400 | ||
401 | /* A.23.5 TERMINAL CONTROL SELECTORS */ | ||
402 | #define UAC3_TE_UNDEFINED 0x00 | ||
403 | #define UAC3_TE_INSERTION 0x01 | ||
404 | #define UAC3_TE_OVERLOAD 0x02 | ||
405 | #define UAC3_TE_UNDERFLOW 0x03 | ||
406 | #define UAC3_TE_OVERFLOW 0x04 | ||
407 | #define UAC3_TE_LATENCY 0x05 | ||
408 | |||
409 | /* BADD predefined Unit/Terminal values */ | ||
410 | #define UAC3_BADD_IT_ID1 1 /* Input Terminal ID1: bTerminalID = 1 */ | ||
411 | #define UAC3_BADD_FU_ID2 2 /* Feature Unit ID2: bUnitID = 2 */ | ||
412 | #define UAC3_BADD_OT_ID3 3 /* Output Terminal ID3: bTerminalID = 3 */ | ||
413 | #define UAC3_BADD_IT_ID4 4 /* Input Terminal ID4: bTerminalID = 4 */ | ||
414 | #define UAC3_BADD_FU_ID5 5 /* Feature Unit ID5: bUnitID = 5 */ | ||
415 | #define UAC3_BADD_OT_ID6 6 /* Output Terminal ID6: bTerminalID = 6 */ | ||
416 | #define UAC3_BADD_FU_ID7 7 /* Feature Unit ID7: bUnitID = 7 */ | ||
417 | #define UAC3_BADD_MU_ID8 8 /* Mixer Unit ID8: bUnitID = 8 */ | ||
418 | #define UAC3_BADD_CS_ID9 9 /* Clock Source Entity ID9: bClockID = 9 */ | ||
419 | #define UAC3_BADD_PD_ID10 10 /* Power Domain ID10: bPowerDomainID = 10 */ | ||
420 | #define UAC3_BADD_PD_ID11 11 /* Power Domain ID11: bPowerDomainID = 11 */ | ||
421 | |||
422 | /* BADD wMaxPacketSize of AS endpoints */ | ||
423 | #define UAC3_BADD_EP_MAXPSIZE_SYNC_MONO_16 0x0060 | ||
424 | #define UAC3_BADD_EP_MAXPSIZE_ASYNC_MONO_16 0x0062 | ||
425 | #define UAC3_BADD_EP_MAXPSIZE_SYNC_MONO_24 0x0090 | ||
426 | #define UAC3_BADD_EP_MAXPSIZE_ASYNC_MONO_24 0x0093 | ||
427 | #define UAC3_BADD_EP_MAXPSIZE_SYNC_STEREO_16 0x00C0 | ||
428 | #define UAC3_BADD_EP_MAXPSIZE_ASYNC_STEREO_16 0x00C4 | ||
429 | #define UAC3_BADD_EP_MAXPSIZE_SYNC_STEREO_24 0x0120 | ||
430 | #define UAC3_BADD_EP_MAXPSIZE_ASYNC_STEREO_24 0x0126 | ||
431 | |||
432 | /* BADD sample rate is always fixed to 48kHz */ | ||
433 | #define UAC3_BADD_SAMPLING_RATE 48000 | ||
434 | |||
395 | #endif /* __LINUX_USB_AUDIO_V3_H */ | 435 | #endif /* __LINUX_USB_AUDIO_V3_H */ |
diff --git a/include/sound/core.h b/include/sound/core.h index 5f181b875c2f..36a5934cf4b1 100644 --- a/include/sound/core.h +++ b/include/sound/core.h | |||
@@ -51,7 +51,6 @@ struct completion; | |||
51 | */ | 51 | */ |
52 | enum snd_device_type { | 52 | enum snd_device_type { |
53 | SNDRV_DEV_LOWLEVEL, | 53 | SNDRV_DEV_LOWLEVEL, |
54 | SNDRV_DEV_CONTROL, | ||
55 | SNDRV_DEV_INFO, | 54 | SNDRV_DEV_INFO, |
56 | SNDRV_DEV_BUS, | 55 | SNDRV_DEV_BUS, |
57 | SNDRV_DEV_CODEC, | 56 | SNDRV_DEV_CODEC, |
@@ -62,6 +61,7 @@ enum snd_device_type { | |||
62 | SNDRV_DEV_SEQUENCER, | 61 | SNDRV_DEV_SEQUENCER, |
63 | SNDRV_DEV_HWDEP, | 62 | SNDRV_DEV_HWDEP, |
64 | SNDRV_DEV_JACK, | 63 | SNDRV_DEV_JACK, |
64 | SNDRV_DEV_CONTROL, /* NOTE: this must be the last one */ | ||
65 | }; | 65 | }; |
66 | 66 | ||
67 | enum snd_device_state { | 67 | enum snd_device_state { |
diff --git a/include/sound/emu10k1.h b/include/sound/emu10k1.h index 5ebcc51c0a6a..8c1572de44c5 100644 --- a/include/sound/emu10k1.h +++ b/include/sound/emu10k1.h | |||
@@ -1610,7 +1610,7 @@ struct snd_emu10k1_fx8010_pcm { | |||
1610 | struct snd_pcm_indirect pcm_rec; | 1610 | struct snd_pcm_indirect pcm_rec; |
1611 | unsigned int tram_pos; | 1611 | unsigned int tram_pos; |
1612 | unsigned int tram_shift; | 1612 | unsigned int tram_shift; |
1613 | struct snd_emu10k1_fx8010_irq *irq; | 1613 | struct snd_emu10k1_fx8010_irq irq; |
1614 | }; | 1614 | }; |
1615 | 1615 | ||
1616 | struct snd_emu10k1_fx8010 { | 1616 | struct snd_emu10k1_fx8010 { |
@@ -1902,7 +1902,7 @@ int snd_emu10k1_fx8010_register_irq_handler(struct snd_emu10k1 *emu, | |||
1902 | snd_fx8010_irq_handler_t *handler, | 1902 | snd_fx8010_irq_handler_t *handler, |
1903 | unsigned char gpr_running, | 1903 | unsigned char gpr_running, |
1904 | void *private_data, | 1904 | void *private_data, |
1905 | struct snd_emu10k1_fx8010_irq **r_irq); | 1905 | struct snd_emu10k1_fx8010_irq *irq); |
1906 | int snd_emu10k1_fx8010_unregister_irq_handler(struct snd_emu10k1 *emu, | 1906 | int snd_emu10k1_fx8010_unregister_irq_handler(struct snd_emu10k1 *emu, |
1907 | struct snd_emu10k1_fx8010_irq *irq); | 1907 | struct snd_emu10k1_fx8010_irq *irq); |
1908 | 1908 | ||
diff --git a/include/sound/hdaudio.h b/include/sound/hdaudio.h index 06536e01ed94..c052afc27547 100644 --- a/include/sound/hdaudio.h +++ b/include/sound/hdaudio.h | |||
@@ -571,4 +571,9 @@ static inline unsigned int snd_array_index(struct snd_array *array, void *ptr) | |||
571 | return (unsigned long)(ptr - array->list) / array->elem_size; | 571 | return (unsigned long)(ptr - array->list) / array->elem_size; |
572 | } | 572 | } |
573 | 573 | ||
574 | /* a helper macro to iterate for each snd_array element */ | ||
575 | #define snd_array_for_each(array, idx, ptr) \ | ||
576 | for ((idx) = 0, (ptr) = (array)->list; (idx) < (array)->used; \ | ||
577 | (ptr) = snd_array_elem(array, ++(idx))) | ||
578 | |||
574 | #endif /* __SOUND_HDAUDIO_H */ | 579 | #endif /* __SOUND_HDAUDIO_H */ |
diff --git a/include/sound/memalloc.h b/include/sound/memalloc.h index 782d1df34208..9c3db3dce32b 100644 --- a/include/sound/memalloc.h +++ b/include/sound/memalloc.h | |||
@@ -34,11 +34,9 @@ struct snd_dma_device { | |||
34 | struct device *dev; /* generic device */ | 34 | struct device *dev; /* generic device */ |
35 | }; | 35 | }; |
36 | 36 | ||
37 | #ifndef snd_dma_pci_data | ||
38 | #define snd_dma_pci_data(pci) (&(pci)->dev) | 37 | #define snd_dma_pci_data(pci) (&(pci)->dev) |
39 | #define snd_dma_isa_data() NULL | 38 | #define snd_dma_isa_data() NULL |
40 | #define snd_dma_continuous_data(x) ((struct device *)(__force unsigned long)(x)) | 39 | #define snd_dma_continuous_data(x) ((struct device *)(__force unsigned long)(x)) |
41 | #endif | ||
42 | 40 | ||
43 | 41 | ||
44 | /* | 42 | /* |
diff --git a/include/uapi/linux/usb/audio.h b/include/uapi/linux/usb/audio.h index 3a78e7145689..13d98e6e0db1 100644 --- a/include/uapi/linux/usb/audio.h +++ b/include/uapi/linux/usb/audio.h | |||
@@ -285,9 +285,22 @@ static inline __u8 uac_mixer_unit_iChannelNames(struct uac_mixer_unit_descriptor | |||
285 | static inline __u8 *uac_mixer_unit_bmControls(struct uac_mixer_unit_descriptor *desc, | 285 | static inline __u8 *uac_mixer_unit_bmControls(struct uac_mixer_unit_descriptor *desc, |
286 | int protocol) | 286 | int protocol) |
287 | { | 287 | { |
288 | return (protocol == UAC_VERSION_1) ? | 288 | switch (protocol) { |
289 | &desc->baSourceID[desc->bNrInPins + 4] : | 289 | case UAC_VERSION_1: |
290 | &desc->baSourceID[desc->bNrInPins + 6]; | 290 | return &desc->baSourceID[desc->bNrInPins + 4]; |
291 | case UAC_VERSION_2: | ||
292 | return &desc->baSourceID[desc->bNrInPins + 6]; | ||
293 | case UAC_VERSION_3: | ||
294 | return &desc->baSourceID[desc->bNrInPins + 2]; | ||
295 | default: | ||
296 | return NULL; | ||
297 | } | ||
298 | } | ||
299 | |||
300 | static inline __u16 uac3_mixer_unit_wClusterDescrID(struct uac_mixer_unit_descriptor *desc) | ||
301 | { | ||
302 | return (desc->baSourceID[desc->bNrInPins + 1] << 8) | | ||
303 | desc->baSourceID[desc->bNrInPins]; | ||
291 | } | 304 | } |
292 | 305 | ||
293 | static inline __u8 uac_mixer_unit_iMixer(struct uac_mixer_unit_descriptor *desc) | 306 | static inline __u8 uac_mixer_unit_iMixer(struct uac_mixer_unit_descriptor *desc) |
diff --git a/include/uapi/sound/tlv.h b/include/uapi/sound/tlv.h index be5371f09a62..7d6d65f60a42 100644 --- a/include/uapi/sound/tlv.h +++ b/include/uapi/sound/tlv.h | |||
@@ -42,6 +42,10 @@ | |||
42 | #define SNDRV_CTL_TLVD_LENGTH(...) \ | 42 | #define SNDRV_CTL_TLVD_LENGTH(...) \ |
43 | ((unsigned int)sizeof((const unsigned int[]) { __VA_ARGS__ })) | 43 | ((unsigned int)sizeof((const unsigned int[]) { __VA_ARGS__ })) |
44 | 44 | ||
45 | /* Accessor offsets for TLV data items */ | ||
46 | #define SNDRV_CTL_TLVO_TYPE 0 | ||
47 | #define SNDRV_CTL_TLVO_LEN 1 | ||
48 | |||
45 | #define SNDRV_CTL_TLVD_CONTAINER_ITEM(...) \ | 49 | #define SNDRV_CTL_TLVD_CONTAINER_ITEM(...) \ |
46 | SNDRV_CTL_TLVD_ITEM(SNDRV_CTL_TLVT_CONTAINER, __VA_ARGS__) | 50 | SNDRV_CTL_TLVD_ITEM(SNDRV_CTL_TLVT_CONTAINER, __VA_ARGS__) |
47 | #define SNDRV_CTL_TLVD_DECLARE_CONTAINER(name, ...) \ | 51 | #define SNDRV_CTL_TLVD_DECLARE_CONTAINER(name, ...) \ |
@@ -61,6 +65,10 @@ | |||
61 | SNDRV_CTL_TLVD_DB_SCALE_ITEM(min, step, mute) \ | 65 | SNDRV_CTL_TLVD_DB_SCALE_ITEM(min, step, mute) \ |
62 | } | 66 | } |
63 | 67 | ||
68 | /* Accessor offsets for min, mute and step items in dB scale type TLV */ | ||
69 | #define SNDRV_CTL_TLVO_DB_SCALE_MIN 2 | ||
70 | #define SNDRV_CTL_TLVO_DB_SCALE_MUTE_AND_STEP 3 | ||
71 | |||
64 | /* dB scale specified with min/max values instead of step */ | 72 | /* dB scale specified with min/max values instead of step */ |
65 | #define SNDRV_CTL_TLVD_DB_MINMAX_ITEM(min_dB, max_dB) \ | 73 | #define SNDRV_CTL_TLVD_DB_MINMAX_ITEM(min_dB, max_dB) \ |
66 | SNDRV_CTL_TLVD_ITEM(SNDRV_CTL_TLVT_DB_MINMAX, (min_dB), (max_dB)) | 74 | SNDRV_CTL_TLVD_ITEM(SNDRV_CTL_TLVT_DB_MINMAX, (min_dB), (max_dB)) |
@@ -75,6 +83,10 @@ | |||
75 | SNDRV_CTL_TLVD_DB_MINMAX_MUTE_ITEM(min_dB, max_dB) \ | 83 | SNDRV_CTL_TLVD_DB_MINMAX_MUTE_ITEM(min_dB, max_dB) \ |
76 | } | 84 | } |
77 | 85 | ||
86 | /* Accessor offsets for min, max items in db-minmax types of TLV. */ | ||
87 | #define SNDRV_CTL_TLVO_DB_MINMAX_MIN 2 | ||
88 | #define SNDRV_CTL_TLVO_DB_MINMAX_MAX 3 | ||
89 | |||
78 | /* linear volume between min_dB and max_dB (.01dB unit) */ | 90 | /* linear volume between min_dB and max_dB (.01dB unit) */ |
79 | #define SNDRV_CTL_TLVD_DB_LINEAR_ITEM(min_dB, max_dB) \ | 91 | #define SNDRV_CTL_TLVD_DB_LINEAR_ITEM(min_dB, max_dB) \ |
80 | SNDRV_CTL_TLVD_ITEM(SNDRV_CTL_TLVT_DB_LINEAR, (min_dB), (max_dB)) | 92 | SNDRV_CTL_TLVD_ITEM(SNDRV_CTL_TLVT_DB_LINEAR, (min_dB), (max_dB)) |
@@ -83,6 +95,10 @@ | |||
83 | SNDRV_CTL_TLVD_DB_LINEAR_ITEM(min_dB, max_dB) \ | 95 | SNDRV_CTL_TLVD_DB_LINEAR_ITEM(min_dB, max_dB) \ |
84 | } | 96 | } |
85 | 97 | ||
98 | /* Accessor offsets for min, max items in db-linear type of TLV. */ | ||
99 | #define SNDRV_CTL_TLVO_DB_LINEAR_MIN 2 | ||
100 | #define SNDRV_CTL_TLVO_DB_LINEAR_MAX 3 | ||
101 | |||
86 | /* dB range container: | 102 | /* dB range container: |
87 | * Items in dB range container must be ordered by their values and by their | 103 | * Items in dB range container must be ordered by their values and by their |
88 | * dB values. This implies that larger values must correspond with larger | 104 | * dB values. This implies that larger values must correspond with larger |
diff --git a/sound/Kconfig b/sound/Kconfig index 6833db9002ec..1140e9988fc5 100644 --- a/sound/Kconfig +++ b/sound/Kconfig | |||
@@ -96,6 +96,8 @@ source "sound/x86/Kconfig" | |||
96 | 96 | ||
97 | source "sound/synth/Kconfig" | 97 | source "sound/synth/Kconfig" |
98 | 98 | ||
99 | source "sound/xen/Kconfig" | ||
100 | |||
99 | endif # SND | 101 | endif # SND |
100 | 102 | ||
101 | endif # !UML | 103 | endif # !UML |
diff --git a/sound/Makefile b/sound/Makefile index 99d8c31262c8..797ecdcd35e2 100644 --- a/sound/Makefile +++ b/sound/Makefile | |||
@@ -5,7 +5,7 @@ | |||
5 | obj-$(CONFIG_SOUND) += soundcore.o | 5 | obj-$(CONFIG_SOUND) += soundcore.o |
6 | obj-$(CONFIG_DMASOUND) += oss/dmasound/ | 6 | obj-$(CONFIG_DMASOUND) += oss/dmasound/ |
7 | obj-$(CONFIG_SND) += core/ i2c/ drivers/ isa/ pci/ ppc/ arm/ sh/ synth/ usb/ \ | 7 | obj-$(CONFIG_SND) += core/ i2c/ drivers/ isa/ pci/ ppc/ arm/ sh/ synth/ usb/ \ |
8 | firewire/ sparc/ spi/ parisc/ pcmcia/ mips/ soc/ atmel/ hda/ x86/ | 8 | firewire/ sparc/ spi/ parisc/ pcmcia/ mips/ soc/ atmel/ hda/ x86/ xen/ |
9 | obj-$(CONFIG_SND_AOA) += aoa/ | 9 | obj-$(CONFIG_SND_AOA) += aoa/ |
10 | 10 | ||
11 | # This one must be compilable even if sound is configured out | 11 | # This one must be compilable even if sound is configured out |
diff --git a/sound/core/compress_offload.c b/sound/core/compress_offload.c index 4563432badba..4b01a37c836e 100644 --- a/sound/core/compress_offload.c +++ b/sound/core/compress_offload.c | |||
@@ -1001,7 +1001,7 @@ static int snd_compress_proc_init(struct snd_compr *compr) | |||
1001 | compr->card->proc_root); | 1001 | compr->card->proc_root); |
1002 | if (!entry) | 1002 | if (!entry) |
1003 | return -ENOMEM; | 1003 | return -ENOMEM; |
1004 | entry->mode = S_IFDIR | S_IRUGO | S_IXUGO; | 1004 | entry->mode = S_IFDIR | 0555; |
1005 | if (snd_info_register(entry) < 0) { | 1005 | if (snd_info_register(entry) < 0) { |
1006 | snd_info_free_entry(entry); | 1006 | snd_info_free_entry(entry); |
1007 | return -ENOMEM; | 1007 | return -ENOMEM; |
diff --git a/sound/core/device.c b/sound/core/device.c index cb0e46f66cc9..535102d564e3 100644 --- a/sound/core/device.c +++ b/sound/core/device.c | |||
@@ -240,6 +240,15 @@ void snd_device_free_all(struct snd_card *card) | |||
240 | 240 | ||
241 | if (snd_BUG_ON(!card)) | 241 | if (snd_BUG_ON(!card)) |
242 | return; | 242 | return; |
243 | list_for_each_entry_safe_reverse(dev, next, &card->devices, list) { | ||
244 | /* exception: free ctl and lowlevel stuff later */ | ||
245 | if (dev->type == SNDRV_DEV_CONTROL || | ||
246 | dev->type == SNDRV_DEV_LOWLEVEL) | ||
247 | continue; | ||
248 | __snd_device_free(dev); | ||
249 | } | ||
250 | |||
251 | /* free all */ | ||
243 | list_for_each_entry_safe_reverse(dev, next, &card->devices, list) | 252 | list_for_each_entry_safe_reverse(dev, next, &card->devices, list) |
244 | __snd_device_free(dev); | 253 | __snd_device_free(dev); |
245 | } | 254 | } |
diff --git a/sound/core/info.c b/sound/core/info.c index 4b36767af9e1..fe502bc5e6d2 100644 --- a/sound/core/info.c +++ b/sound/core/info.c | |||
@@ -454,7 +454,7 @@ static struct snd_info_entry *create_subdir(struct module *mod, | |||
454 | entry = snd_info_create_module_entry(mod, name, NULL); | 454 | entry = snd_info_create_module_entry(mod, name, NULL); |
455 | if (!entry) | 455 | if (!entry) |
456 | return NULL; | 456 | return NULL; |
457 | entry->mode = S_IFDIR | S_IRUGO | S_IXUGO; | 457 | entry->mode = S_IFDIR | 0555; |
458 | if (snd_info_register(entry) < 0) { | 458 | if (snd_info_register(entry) < 0) { |
459 | snd_info_free_entry(entry); | 459 | snd_info_free_entry(entry); |
460 | return NULL; | 460 | return NULL; |
@@ -470,7 +470,7 @@ int __init snd_info_init(void) | |||
470 | snd_proc_root = snd_info_create_entry("asound", NULL); | 470 | snd_proc_root = snd_info_create_entry("asound", NULL); |
471 | if (!snd_proc_root) | 471 | if (!snd_proc_root) |
472 | return -ENOMEM; | 472 | return -ENOMEM; |
473 | snd_proc_root->mode = S_IFDIR | S_IRUGO | S_IXUGO; | 473 | snd_proc_root->mode = S_IFDIR | 0555; |
474 | snd_proc_root->p = proc_mkdir("asound", NULL); | 474 | snd_proc_root->p = proc_mkdir("asound", NULL); |
475 | if (!snd_proc_root->p) | 475 | if (!snd_proc_root->p) |
476 | goto error; | 476 | goto error; |
@@ -716,7 +716,7 @@ snd_info_create_entry(const char *name, struct snd_info_entry *parent) | |||
716 | kfree(entry); | 716 | kfree(entry); |
717 | return NULL; | 717 | return NULL; |
718 | } | 718 | } |
719 | entry->mode = S_IFREG | S_IRUGO; | 719 | entry->mode = S_IFREG | 0444; |
720 | entry->content = SNDRV_INFO_CONTENT_TEXT; | 720 | entry->content = SNDRV_INFO_CONTENT_TEXT; |
721 | mutex_init(&entry->access); | 721 | mutex_init(&entry->access); |
722 | INIT_LIST_HEAD(&entry->children); | 722 | INIT_LIST_HEAD(&entry->children); |
diff --git a/sound/core/init.c b/sound/core/init.c index 79b4df1c1dc7..4849c611c0fe 100644 --- a/sound/core/init.c +++ b/sound/core/init.c | |||
@@ -703,7 +703,7 @@ card_id_store_attr(struct device *dev, struct device_attribute *attr, | |||
703 | return count; | 703 | return count; |
704 | } | 704 | } |
705 | 705 | ||
706 | static DEVICE_ATTR(id, S_IRUGO | S_IWUSR, card_id_show_attr, card_id_store_attr); | 706 | static DEVICE_ATTR(id, 0644, card_id_show_attr, card_id_store_attr); |
707 | 707 | ||
708 | static ssize_t | 708 | static ssize_t |
709 | card_number_show_attr(struct device *dev, | 709 | card_number_show_attr(struct device *dev, |
@@ -713,7 +713,7 @@ card_number_show_attr(struct device *dev, | |||
713 | return scnprintf(buf, PAGE_SIZE, "%i\n", card->number); | 713 | return scnprintf(buf, PAGE_SIZE, "%i\n", card->number); |
714 | } | 714 | } |
715 | 715 | ||
716 | static DEVICE_ATTR(number, S_IRUGO, card_number_show_attr, NULL); | 716 | static DEVICE_ATTR(number, 0444, card_number_show_attr, NULL); |
717 | 717 | ||
718 | static struct attribute *card_dev_attrs[] = { | 718 | static struct attribute *card_dev_attrs[] = { |
719 | &dev_attr_id.attr, | 719 | &dev_attr_id.attr, |
diff --git a/sound/core/oss/mixer_oss.c b/sound/core/oss/mixer_oss.c index 379bf486ccc7..64d904bee8bb 100644 --- a/sound/core/oss/mixer_oss.c +++ b/sound/core/oss/mixer_oss.c | |||
@@ -1247,7 +1247,7 @@ static void snd_mixer_oss_proc_init(struct snd_mixer_oss *mixer) | |||
1247 | if (! entry) | 1247 | if (! entry) |
1248 | return; | 1248 | return; |
1249 | entry->content = SNDRV_INFO_CONTENT_TEXT; | 1249 | entry->content = SNDRV_INFO_CONTENT_TEXT; |
1250 | entry->mode = S_IFREG | S_IRUGO | S_IWUSR; | 1250 | entry->mode = S_IFREG | 0644; |
1251 | entry->c.text.read = snd_mixer_oss_proc_read; | 1251 | entry->c.text.read = snd_mixer_oss_proc_read; |
1252 | entry->c.text.write = snd_mixer_oss_proc_write; | 1252 | entry->c.text.write = snd_mixer_oss_proc_write; |
1253 | entry->private_data = mixer; | 1253 | entry->private_data = mixer; |
diff --git a/sound/core/oss/pcm_oss.c b/sound/core/oss/pcm_oss.c index 1980f68246cb..905a53c1cde5 100644 --- a/sound/core/oss/pcm_oss.c +++ b/sound/core/oss/pcm_oss.c | |||
@@ -3045,7 +3045,7 @@ static void snd_pcm_oss_proc_init(struct snd_pcm *pcm) | |||
3045 | continue; | 3045 | continue; |
3046 | if ((entry = snd_info_create_card_entry(pcm->card, "oss", pstr->proc_root)) != NULL) { | 3046 | if ((entry = snd_info_create_card_entry(pcm->card, "oss", pstr->proc_root)) != NULL) { |
3047 | entry->content = SNDRV_INFO_CONTENT_TEXT; | 3047 | entry->content = SNDRV_INFO_CONTENT_TEXT; |
3048 | entry->mode = S_IFREG | S_IRUGO | S_IWUSR; | 3048 | entry->mode = S_IFREG | 0644; |
3049 | entry->c.text.read = snd_pcm_oss_proc_read; | 3049 | entry->c.text.read = snd_pcm_oss_proc_read; |
3050 | entry->c.text.write = snd_pcm_oss_proc_write; | 3050 | entry->c.text.write = snd_pcm_oss_proc_write; |
3051 | entry->private_data = pstr; | 3051 | entry->private_data = pstr; |
diff --git a/sound/core/pcm.c b/sound/core/pcm.c index 66ac89aad681..c352bfb973cc 100644 --- a/sound/core/pcm.c +++ b/sound/core/pcm.c | |||
@@ -530,7 +530,7 @@ static int snd_pcm_stream_proc_init(struct snd_pcm_str *pstr) | |||
530 | pcm->card->proc_root); | 530 | pcm->card->proc_root); |
531 | if (!entry) | 531 | if (!entry) |
532 | return -ENOMEM; | 532 | return -ENOMEM; |
533 | entry->mode = S_IFDIR | S_IRUGO | S_IXUGO; | 533 | entry->mode = S_IFDIR | 0555; |
534 | if (snd_info_register(entry) < 0) { | 534 | if (snd_info_register(entry) < 0) { |
535 | snd_info_free_entry(entry); | 535 | snd_info_free_entry(entry); |
536 | return -ENOMEM; | 536 | return -ENOMEM; |
@@ -552,7 +552,7 @@ static int snd_pcm_stream_proc_init(struct snd_pcm_str *pstr) | |||
552 | if (entry) { | 552 | if (entry) { |
553 | entry->c.text.read = snd_pcm_xrun_debug_read; | 553 | entry->c.text.read = snd_pcm_xrun_debug_read; |
554 | entry->c.text.write = snd_pcm_xrun_debug_write; | 554 | entry->c.text.write = snd_pcm_xrun_debug_write; |
555 | entry->mode |= S_IWUSR; | 555 | entry->mode |= 0200; |
556 | entry->private_data = pstr; | 556 | entry->private_data = pstr; |
557 | if (snd_info_register(entry) < 0) { | 557 | if (snd_info_register(entry) < 0) { |
558 | snd_info_free_entry(entry); | 558 | snd_info_free_entry(entry); |
@@ -590,7 +590,7 @@ static int snd_pcm_substream_proc_init(struct snd_pcm_substream *substream) | |||
590 | substream->pstr->proc_root); | 590 | substream->pstr->proc_root); |
591 | if (!entry) | 591 | if (!entry) |
592 | return -ENOMEM; | 592 | return -ENOMEM; |
593 | entry->mode = S_IFDIR | S_IRUGO | S_IXUGO; | 593 | entry->mode = S_IFDIR | 0555; |
594 | if (snd_info_register(entry) < 0) { | 594 | if (snd_info_register(entry) < 0) { |
595 | snd_info_free_entry(entry); | 595 | snd_info_free_entry(entry); |
596 | return -ENOMEM; | 596 | return -ENOMEM; |
@@ -647,7 +647,7 @@ static int snd_pcm_substream_proc_init(struct snd_pcm_substream *substream) | |||
647 | entry->private_data = substream; | 647 | entry->private_data = substream; |
648 | entry->c.text.read = NULL; | 648 | entry->c.text.read = NULL; |
649 | entry->c.text.write = snd_pcm_xrun_injection_write; | 649 | entry->c.text.write = snd_pcm_xrun_injection_write; |
650 | entry->mode = S_IFREG | S_IWUSR; | 650 | entry->mode = S_IFREG | 0200; |
651 | if (snd_info_register(entry) < 0) { | 651 | if (snd_info_register(entry) < 0) { |
652 | snd_info_free_entry(entry); | 652 | snd_info_free_entry(entry); |
653 | entry = NULL; | 653 | entry = NULL; |
@@ -1087,7 +1087,7 @@ static ssize_t show_pcm_class(struct device *dev, | |||
1087 | return snprintf(buf, PAGE_SIZE, "%s\n", str); | 1087 | return snprintf(buf, PAGE_SIZE, "%s\n", str); |
1088 | } | 1088 | } |
1089 | 1089 | ||
1090 | static DEVICE_ATTR(pcm_class, S_IRUGO, show_pcm_class, NULL); | 1090 | static DEVICE_ATTR(pcm_class, 0444, show_pcm_class, NULL); |
1091 | static struct attribute *pcm_dev_attrs[] = { | 1091 | static struct attribute *pcm_dev_attrs[] = { |
1092 | &dev_attr_pcm_class.attr, | 1092 | &dev_attr_pcm_class.attr, |
1093 | NULL | 1093 | NULL |
diff --git a/sound/core/pcm_compat.c b/sound/core/pcm_compat.c index 6491afbb5fd5..39d853bfa5ac 100644 --- a/sound/core/pcm_compat.c +++ b/sound/core/pcm_compat.c | |||
@@ -45,10 +45,7 @@ static int snd_pcm_ioctl_rewind_compat(struct snd_pcm_substream *substream, | |||
45 | 45 | ||
46 | if (get_user(frames, src)) | 46 | if (get_user(frames, src)) |
47 | return -EFAULT; | 47 | return -EFAULT; |
48 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) | 48 | err = snd_pcm_rewind(substream, frames); |
49 | err = snd_pcm_playback_rewind(substream, frames); | ||
50 | else | ||
51 | err = snd_pcm_capture_rewind(substream, frames); | ||
52 | if (put_user(err, src)) | 49 | if (put_user(err, src)) |
53 | return -EFAULT; | 50 | return -EFAULT; |
54 | return err < 0 ? err : 0; | 51 | return err < 0 ? err : 0; |
@@ -62,10 +59,7 @@ static int snd_pcm_ioctl_forward_compat(struct snd_pcm_substream *substream, | |||
62 | 59 | ||
63 | if (get_user(frames, src)) | 60 | if (get_user(frames, src)) |
64 | return -EFAULT; | 61 | return -EFAULT; |
65 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) | 62 | err = snd_pcm_forward(substream, frames); |
66 | err = snd_pcm_playback_forward(substream, frames); | ||
67 | else | ||
68 | err = snd_pcm_capture_forward(substream, frames); | ||
69 | if (put_user(err, src)) | 63 | if (put_user(err, src)) |
70 | return -EFAULT; | 64 | return -EFAULT; |
71 | return err < 0 ? err : 0; | 65 | return err < 0 ? err : 0; |
diff --git a/sound/core/pcm_lib.c b/sound/core/pcm_lib.c index f4a19509cccf..44b5ae833082 100644 --- a/sound/core/pcm_lib.c +++ b/sound/core/pcm_lib.c | |||
@@ -191,10 +191,7 @@ int snd_pcm_update_state(struct snd_pcm_substream *substream, | |||
191 | { | 191 | { |
192 | snd_pcm_uframes_t avail; | 192 | snd_pcm_uframes_t avail; |
193 | 193 | ||
194 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) | 194 | avail = snd_pcm_avail(substream); |
195 | avail = snd_pcm_playback_avail(runtime); | ||
196 | else | ||
197 | avail = snd_pcm_capture_avail(runtime); | ||
198 | if (avail > runtime->avail_max) | 195 | if (avail > runtime->avail_max) |
199 | runtime->avail_max = avail; | 196 | runtime->avail_max = avail; |
200 | if (runtime->status->state == SNDRV_PCM_STATE_DRAINING) { | 197 | if (runtime->status->state == SNDRV_PCM_STATE_DRAINING) { |
@@ -1856,10 +1853,7 @@ static int wait_for_avail(struct snd_pcm_substream *substream, | |||
1856 | * This check must happen after been added to the waitqueue | 1853 | * This check must happen after been added to the waitqueue |
1857 | * and having current state be INTERRUPTIBLE. | 1854 | * and having current state be INTERRUPTIBLE. |
1858 | */ | 1855 | */ |
1859 | if (is_playback) | 1856 | avail = snd_pcm_avail(substream); |
1860 | avail = snd_pcm_playback_avail(runtime); | ||
1861 | else | ||
1862 | avail = snd_pcm_capture_avail(runtime); | ||
1863 | if (avail >= runtime->twake) | 1857 | if (avail >= runtime->twake) |
1864 | break; | 1858 | break; |
1865 | snd_pcm_stream_unlock_irq(substream); | 1859 | snd_pcm_stream_unlock_irq(substream); |
@@ -2175,10 +2169,7 @@ snd_pcm_sframes_t __snd_pcm_lib_xfer(struct snd_pcm_substream *substream, | |||
2175 | runtime->twake = runtime->control->avail_min ? : 1; | 2169 | runtime->twake = runtime->control->avail_min ? : 1; |
2176 | if (runtime->status->state == SNDRV_PCM_STATE_RUNNING) | 2170 | if (runtime->status->state == SNDRV_PCM_STATE_RUNNING) |
2177 | snd_pcm_update_hw_ptr(substream); | 2171 | snd_pcm_update_hw_ptr(substream); |
2178 | if (is_playback) | 2172 | avail = snd_pcm_avail(substream); |
2179 | avail = snd_pcm_playback_avail(runtime); | ||
2180 | else | ||
2181 | avail = snd_pcm_capture_avail(runtime); | ||
2182 | while (size > 0) { | 2173 | while (size > 0) { |
2183 | snd_pcm_uframes_t frames, appl_ptr, appl_ofs; | 2174 | snd_pcm_uframes_t frames, appl_ptr, appl_ofs; |
2184 | snd_pcm_uframes_t cont; | 2175 | snd_pcm_uframes_t cont; |
diff --git a/sound/core/pcm_local.h b/sound/core/pcm_local.h index 16f254732b2a..7a499d02df6c 100644 --- a/sound/core/pcm_local.h +++ b/sound/core/pcm_local.h | |||
@@ -36,6 +36,24 @@ int snd_pcm_update_hw_ptr(struct snd_pcm_substream *substream); | |||
36 | void snd_pcm_playback_silence(struct snd_pcm_substream *substream, | 36 | void snd_pcm_playback_silence(struct snd_pcm_substream *substream, |
37 | snd_pcm_uframes_t new_hw_ptr); | 37 | snd_pcm_uframes_t new_hw_ptr); |
38 | 38 | ||
39 | static inline snd_pcm_uframes_t | ||
40 | snd_pcm_avail(struct snd_pcm_substream *substream) | ||
41 | { | ||
42 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) | ||
43 | return snd_pcm_playback_avail(substream->runtime); | ||
44 | else | ||
45 | return snd_pcm_capture_avail(substream->runtime); | ||
46 | } | ||
47 | |||
48 | static inline snd_pcm_uframes_t | ||
49 | snd_pcm_hw_avail(struct snd_pcm_substream *substream) | ||
50 | { | ||
51 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) | ||
52 | return snd_pcm_playback_hw_avail(substream->runtime); | ||
53 | else | ||
54 | return snd_pcm_capture_hw_avail(substream->runtime); | ||
55 | } | ||
56 | |||
39 | #ifdef CONFIG_SND_PCM_TIMER | 57 | #ifdef CONFIG_SND_PCM_TIMER |
40 | void snd_pcm_timer_resolution_change(struct snd_pcm_substream *substream); | 58 | void snd_pcm_timer_resolution_change(struct snd_pcm_substream *substream); |
41 | void snd_pcm_timer_init(struct snd_pcm_substream *substream); | 59 | void snd_pcm_timer_init(struct snd_pcm_substream *substream); |
diff --git a/sound/core/pcm_memory.c b/sound/core/pcm_memory.c index ae33e456708c..4b5356a10315 100644 --- a/sound/core/pcm_memory.c +++ b/sound/core/pcm_memory.c | |||
@@ -201,7 +201,7 @@ static inline void preallocate_info_init(struct snd_pcm_substream *substream) | |||
201 | if ((entry = snd_info_create_card_entry(substream->pcm->card, "prealloc", substream->proc_root)) != NULL) { | 201 | if ((entry = snd_info_create_card_entry(substream->pcm->card, "prealloc", substream->proc_root)) != NULL) { |
202 | entry->c.text.read = snd_pcm_lib_preallocate_proc_read; | 202 | entry->c.text.read = snd_pcm_lib_preallocate_proc_read; |
203 | entry->c.text.write = snd_pcm_lib_preallocate_proc_write; | 203 | entry->c.text.write = snd_pcm_lib_preallocate_proc_write; |
204 | entry->mode |= S_IWUSR; | 204 | entry->mode |= 0200; |
205 | entry->private_data = substream; | 205 | entry->private_data = substream; |
206 | if (snd_info_register(entry) < 0) { | 206 | if (snd_info_register(entry) < 0) { |
207 | snd_info_free_entry(entry); | 207 | snd_info_free_entry(entry); |
diff --git a/sound/core/pcm_native.c b/sound/core/pcm_native.c index 0e875d5a9e86..04c6301394d0 100644 --- a/sound/core/pcm_native.c +++ b/sound/core/pcm_native.c | |||
@@ -99,6 +99,57 @@ static inline void down_write_nonblock(struct rw_semaphore *lock) | |||
99 | cond_resched(); | 99 | cond_resched(); |
100 | } | 100 | } |
101 | 101 | ||
102 | #define PCM_LOCK_DEFAULT 0 | ||
103 | #define PCM_LOCK_IRQ 1 | ||
104 | #define PCM_LOCK_IRQSAVE 2 | ||
105 | |||
106 | static unsigned long __snd_pcm_stream_lock_mode(struct snd_pcm_substream *substream, | ||
107 | unsigned int mode) | ||
108 | { | ||
109 | unsigned long flags = 0; | ||
110 | if (substream->pcm->nonatomic) { | ||
111 | down_read_nested(&snd_pcm_link_rwsem, SINGLE_DEPTH_NESTING); | ||
112 | mutex_lock(&substream->self_group.mutex); | ||
113 | } else { | ||
114 | switch (mode) { | ||
115 | case PCM_LOCK_DEFAULT: | ||
116 | read_lock(&snd_pcm_link_rwlock); | ||
117 | break; | ||
118 | case PCM_LOCK_IRQ: | ||
119 | read_lock_irq(&snd_pcm_link_rwlock); | ||
120 | break; | ||
121 | case PCM_LOCK_IRQSAVE: | ||
122 | read_lock_irqsave(&snd_pcm_link_rwlock, flags); | ||
123 | break; | ||
124 | } | ||
125 | spin_lock(&substream->self_group.lock); | ||
126 | } | ||
127 | return flags; | ||
128 | } | ||
129 | |||
130 | static void __snd_pcm_stream_unlock_mode(struct snd_pcm_substream *substream, | ||
131 | unsigned int mode, unsigned long flags) | ||
132 | { | ||
133 | if (substream->pcm->nonatomic) { | ||
134 | mutex_unlock(&substream->self_group.mutex); | ||
135 | up_read(&snd_pcm_link_rwsem); | ||
136 | } else { | ||
137 | spin_unlock(&substream->self_group.lock); | ||
138 | |||
139 | switch (mode) { | ||
140 | case PCM_LOCK_DEFAULT: | ||
141 | read_unlock(&snd_pcm_link_rwlock); | ||
142 | break; | ||
143 | case PCM_LOCK_IRQ: | ||
144 | read_unlock_irq(&snd_pcm_link_rwlock); | ||
145 | break; | ||
146 | case PCM_LOCK_IRQSAVE: | ||
147 | read_unlock_irqrestore(&snd_pcm_link_rwlock, flags); | ||
148 | break; | ||
149 | } | ||
150 | } | ||
151 | } | ||
152 | |||
102 | /** | 153 | /** |
103 | * snd_pcm_stream_lock - Lock the PCM stream | 154 | * snd_pcm_stream_lock - Lock the PCM stream |
104 | * @substream: PCM substream | 155 | * @substream: PCM substream |
@@ -109,13 +160,7 @@ static inline void down_write_nonblock(struct rw_semaphore *lock) | |||
109 | */ | 160 | */ |
110 | void snd_pcm_stream_lock(struct snd_pcm_substream *substream) | 161 | void snd_pcm_stream_lock(struct snd_pcm_substream *substream) |
111 | { | 162 | { |
112 | if (substream->pcm->nonatomic) { | 163 | __snd_pcm_stream_lock_mode(substream, PCM_LOCK_DEFAULT); |
113 | down_read_nested(&snd_pcm_link_rwsem, SINGLE_DEPTH_NESTING); | ||
114 | mutex_lock(&substream->self_group.mutex); | ||
115 | } else { | ||
116 | read_lock(&snd_pcm_link_rwlock); | ||
117 | spin_lock(&substream->self_group.lock); | ||
118 | } | ||
119 | } | 164 | } |
120 | EXPORT_SYMBOL_GPL(snd_pcm_stream_lock); | 165 | EXPORT_SYMBOL_GPL(snd_pcm_stream_lock); |
121 | 166 | ||
@@ -127,13 +172,7 @@ EXPORT_SYMBOL_GPL(snd_pcm_stream_lock); | |||
127 | */ | 172 | */ |
128 | void snd_pcm_stream_unlock(struct snd_pcm_substream *substream) | 173 | void snd_pcm_stream_unlock(struct snd_pcm_substream *substream) |
129 | { | 174 | { |
130 | if (substream->pcm->nonatomic) { | 175 | __snd_pcm_stream_unlock_mode(substream, PCM_LOCK_DEFAULT, 0); |
131 | mutex_unlock(&substream->self_group.mutex); | ||
132 | up_read(&snd_pcm_link_rwsem); | ||
133 | } else { | ||
134 | spin_unlock(&substream->self_group.lock); | ||
135 | read_unlock(&snd_pcm_link_rwlock); | ||
136 | } | ||
137 | } | 176 | } |
138 | EXPORT_SYMBOL_GPL(snd_pcm_stream_unlock); | 177 | EXPORT_SYMBOL_GPL(snd_pcm_stream_unlock); |
139 | 178 | ||
@@ -147,9 +186,7 @@ EXPORT_SYMBOL_GPL(snd_pcm_stream_unlock); | |||
147 | */ | 186 | */ |
148 | void snd_pcm_stream_lock_irq(struct snd_pcm_substream *substream) | 187 | void snd_pcm_stream_lock_irq(struct snd_pcm_substream *substream) |
149 | { | 188 | { |
150 | if (!substream->pcm->nonatomic) | 189 | __snd_pcm_stream_lock_mode(substream, PCM_LOCK_IRQ); |
151 | local_irq_disable(); | ||
152 | snd_pcm_stream_lock(substream); | ||
153 | } | 190 | } |
154 | EXPORT_SYMBOL_GPL(snd_pcm_stream_lock_irq); | 191 | EXPORT_SYMBOL_GPL(snd_pcm_stream_lock_irq); |
155 | 192 | ||
@@ -161,19 +198,13 @@ EXPORT_SYMBOL_GPL(snd_pcm_stream_lock_irq); | |||
161 | */ | 198 | */ |
162 | void snd_pcm_stream_unlock_irq(struct snd_pcm_substream *substream) | 199 | void snd_pcm_stream_unlock_irq(struct snd_pcm_substream *substream) |
163 | { | 200 | { |
164 | snd_pcm_stream_unlock(substream); | 201 | __snd_pcm_stream_unlock_mode(substream, PCM_LOCK_IRQ, 0); |
165 | if (!substream->pcm->nonatomic) | ||
166 | local_irq_enable(); | ||
167 | } | 202 | } |
168 | EXPORT_SYMBOL_GPL(snd_pcm_stream_unlock_irq); | 203 | EXPORT_SYMBOL_GPL(snd_pcm_stream_unlock_irq); |
169 | 204 | ||
170 | unsigned long _snd_pcm_stream_lock_irqsave(struct snd_pcm_substream *substream) | 205 | unsigned long _snd_pcm_stream_lock_irqsave(struct snd_pcm_substream *substream) |
171 | { | 206 | { |
172 | unsigned long flags = 0; | 207 | return __snd_pcm_stream_lock_mode(substream, PCM_LOCK_IRQSAVE); |
173 | if (!substream->pcm->nonatomic) | ||
174 | local_irq_save(flags); | ||
175 | snd_pcm_stream_lock(substream); | ||
176 | return flags; | ||
177 | } | 208 | } |
178 | EXPORT_SYMBOL_GPL(_snd_pcm_stream_lock_irqsave); | 209 | EXPORT_SYMBOL_GPL(_snd_pcm_stream_lock_irqsave); |
179 | 210 | ||
@@ -187,9 +218,7 @@ EXPORT_SYMBOL_GPL(_snd_pcm_stream_lock_irqsave); | |||
187 | void snd_pcm_stream_unlock_irqrestore(struct snd_pcm_substream *substream, | 218 | void snd_pcm_stream_unlock_irqrestore(struct snd_pcm_substream *substream, |
188 | unsigned long flags) | 219 | unsigned long flags) |
189 | { | 220 | { |
190 | snd_pcm_stream_unlock(substream); | 221 | __snd_pcm_stream_unlock_mode(substream, PCM_LOCK_IRQSAVE, flags); |
191 | if (!substream->pcm->nonatomic) | ||
192 | local_irq_restore(flags); | ||
193 | } | 222 | } |
194 | EXPORT_SYMBOL_GPL(snd_pcm_stream_unlock_irqrestore); | 223 | EXPORT_SYMBOL_GPL(snd_pcm_stream_unlock_irqrestore); |
195 | 224 | ||
@@ -857,6 +886,18 @@ static int snd_pcm_sw_params_user(struct snd_pcm_substream *substream, | |||
857 | return err; | 886 | return err; |
858 | } | 887 | } |
859 | 888 | ||
889 | static inline snd_pcm_uframes_t | ||
890 | snd_pcm_calc_delay(struct snd_pcm_substream *substream) | ||
891 | { | ||
892 | snd_pcm_uframes_t delay; | ||
893 | |||
894 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) | ||
895 | delay = snd_pcm_playback_hw_avail(substream->runtime); | ||
896 | else | ||
897 | delay = snd_pcm_capture_avail(substream->runtime); | ||
898 | return delay + substream->runtime->delay; | ||
899 | } | ||
900 | |||
860 | int snd_pcm_status(struct snd_pcm_substream *substream, | 901 | int snd_pcm_status(struct snd_pcm_substream *substream, |
861 | struct snd_pcm_status *status) | 902 | struct snd_pcm_status *status) |
862 | { | 903 | { |
@@ -908,21 +949,9 @@ int snd_pcm_status(struct snd_pcm_substream *substream, | |||
908 | _tstamp_end: | 949 | _tstamp_end: |
909 | status->appl_ptr = runtime->control->appl_ptr; | 950 | status->appl_ptr = runtime->control->appl_ptr; |
910 | status->hw_ptr = runtime->status->hw_ptr; | 951 | status->hw_ptr = runtime->status->hw_ptr; |
911 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) { | 952 | status->avail = snd_pcm_avail(substream); |
912 | status->avail = snd_pcm_playback_avail(runtime); | 953 | status->delay = snd_pcm_running(substream) ? |
913 | if (runtime->status->state == SNDRV_PCM_STATE_RUNNING || | 954 | snd_pcm_calc_delay(substream) : 0; |
914 | runtime->status->state == SNDRV_PCM_STATE_DRAINING) { | ||
915 | status->delay = runtime->buffer_size - status->avail; | ||
916 | status->delay += runtime->delay; | ||
917 | } else | ||
918 | status->delay = 0; | ||
919 | } else { | ||
920 | status->avail = snd_pcm_capture_avail(runtime); | ||
921 | if (runtime->status->state == SNDRV_PCM_STATE_RUNNING) | ||
922 | status->delay = status->avail + runtime->delay; | ||
923 | else | ||
924 | status->delay = 0; | ||
925 | } | ||
926 | status->avail_max = runtime->avail_max; | 955 | status->avail_max = runtime->avail_max; |
927 | status->overrange = runtime->overrange; | 956 | status->overrange = runtime->overrange; |
928 | runtime->avail_max = 0; | 957 | runtime->avail_max = 0; |
@@ -2610,10 +2639,9 @@ static snd_pcm_sframes_t rewind_appl_ptr(struct snd_pcm_substream *substream, | |||
2610 | return ret < 0 ? 0 : frames; | 2639 | return ret < 0 ? 0 : frames; |
2611 | } | 2640 | } |
2612 | 2641 | ||
2613 | static snd_pcm_sframes_t snd_pcm_playback_rewind(struct snd_pcm_substream *substream, | 2642 | static snd_pcm_sframes_t snd_pcm_rewind(struct snd_pcm_substream *substream, |
2614 | snd_pcm_uframes_t frames) | 2643 | snd_pcm_uframes_t frames) |
2615 | { | 2644 | { |
2616 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
2617 | snd_pcm_sframes_t ret; | 2645 | snd_pcm_sframes_t ret; |
2618 | 2646 | ||
2619 | if (frames == 0) | 2647 | if (frames == 0) |
@@ -2623,33 +2651,14 @@ static snd_pcm_sframes_t snd_pcm_playback_rewind(struct snd_pcm_substream *subst | |||
2623 | ret = do_pcm_hwsync(substream); | 2651 | ret = do_pcm_hwsync(substream); |
2624 | if (!ret) | 2652 | if (!ret) |
2625 | ret = rewind_appl_ptr(substream, frames, | 2653 | ret = rewind_appl_ptr(substream, frames, |
2626 | snd_pcm_playback_hw_avail(runtime)); | 2654 | snd_pcm_hw_avail(substream)); |
2627 | snd_pcm_stream_unlock_irq(substream); | 2655 | snd_pcm_stream_unlock_irq(substream); |
2628 | return ret; | 2656 | return ret; |
2629 | } | 2657 | } |
2630 | 2658 | ||
2631 | static snd_pcm_sframes_t snd_pcm_capture_rewind(struct snd_pcm_substream *substream, | 2659 | static snd_pcm_sframes_t snd_pcm_forward(struct snd_pcm_substream *substream, |
2632 | snd_pcm_uframes_t frames) | 2660 | snd_pcm_uframes_t frames) |
2633 | { | 2661 | { |
2634 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
2635 | snd_pcm_sframes_t ret; | ||
2636 | |||
2637 | if (frames == 0) | ||
2638 | return 0; | ||
2639 | |||
2640 | snd_pcm_stream_lock_irq(substream); | ||
2641 | ret = do_pcm_hwsync(substream); | ||
2642 | if (!ret) | ||
2643 | ret = rewind_appl_ptr(substream, frames, | ||
2644 | snd_pcm_capture_hw_avail(runtime)); | ||
2645 | snd_pcm_stream_unlock_irq(substream); | ||
2646 | return ret; | ||
2647 | } | ||
2648 | |||
2649 | static snd_pcm_sframes_t snd_pcm_playback_forward(struct snd_pcm_substream *substream, | ||
2650 | snd_pcm_uframes_t frames) | ||
2651 | { | ||
2652 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
2653 | snd_pcm_sframes_t ret; | 2662 | snd_pcm_sframes_t ret; |
2654 | 2663 | ||
2655 | if (frames == 0) | 2664 | if (frames == 0) |
@@ -2659,25 +2668,7 @@ static snd_pcm_sframes_t snd_pcm_playback_forward(struct snd_pcm_substream *subs | |||
2659 | ret = do_pcm_hwsync(substream); | 2668 | ret = do_pcm_hwsync(substream); |
2660 | if (!ret) | 2669 | if (!ret) |
2661 | ret = forward_appl_ptr(substream, frames, | 2670 | ret = forward_appl_ptr(substream, frames, |
2662 | snd_pcm_playback_avail(runtime)); | 2671 | snd_pcm_avail(substream)); |
2663 | snd_pcm_stream_unlock_irq(substream); | ||
2664 | return ret; | ||
2665 | } | ||
2666 | |||
2667 | static snd_pcm_sframes_t snd_pcm_capture_forward(struct snd_pcm_substream *substream, | ||
2668 | snd_pcm_uframes_t frames) | ||
2669 | { | ||
2670 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
2671 | snd_pcm_sframes_t ret; | ||
2672 | |||
2673 | if (frames == 0) | ||
2674 | return 0; | ||
2675 | |||
2676 | snd_pcm_stream_lock_irq(substream); | ||
2677 | ret = do_pcm_hwsync(substream); | ||
2678 | if (!ret) | ||
2679 | ret = forward_appl_ptr(substream, frames, | ||
2680 | snd_pcm_capture_avail(runtime)); | ||
2681 | snd_pcm_stream_unlock_irq(substream); | 2672 | snd_pcm_stream_unlock_irq(substream); |
2682 | return ret; | 2673 | return ret; |
2683 | } | 2674 | } |
@@ -2695,19 +2686,13 @@ static int snd_pcm_hwsync(struct snd_pcm_substream *substream) | |||
2695 | static int snd_pcm_delay(struct snd_pcm_substream *substream, | 2686 | static int snd_pcm_delay(struct snd_pcm_substream *substream, |
2696 | snd_pcm_sframes_t *delay) | 2687 | snd_pcm_sframes_t *delay) |
2697 | { | 2688 | { |
2698 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
2699 | int err; | 2689 | int err; |
2700 | snd_pcm_sframes_t n = 0; | 2690 | snd_pcm_sframes_t n = 0; |
2701 | 2691 | ||
2702 | snd_pcm_stream_lock_irq(substream); | 2692 | snd_pcm_stream_lock_irq(substream); |
2703 | err = do_pcm_hwsync(substream); | 2693 | err = do_pcm_hwsync(substream); |
2704 | if (!err) { | 2694 | if (!err) |
2705 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) | 2695 | n = snd_pcm_calc_delay(substream); |
2706 | n = snd_pcm_playback_hw_avail(runtime); | ||
2707 | else | ||
2708 | n = snd_pcm_capture_avail(runtime); | ||
2709 | n += runtime->delay; | ||
2710 | } | ||
2711 | snd_pcm_stream_unlock_irq(substream); | 2696 | snd_pcm_stream_unlock_irq(substream); |
2712 | if (!err) | 2697 | if (!err) |
2713 | *delay = n; | 2698 | *delay = n; |
@@ -2834,10 +2819,7 @@ static int snd_pcm_rewind_ioctl(struct snd_pcm_substream *substream, | |||
2834 | return -EFAULT; | 2819 | return -EFAULT; |
2835 | if (put_user(0, _frames)) | 2820 | if (put_user(0, _frames)) |
2836 | return -EFAULT; | 2821 | return -EFAULT; |
2837 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) | 2822 | result = snd_pcm_rewind(substream, frames); |
2838 | result = snd_pcm_playback_rewind(substream, frames); | ||
2839 | else | ||
2840 | result = snd_pcm_capture_rewind(substream, frames); | ||
2841 | __put_user(result, _frames); | 2823 | __put_user(result, _frames); |
2842 | return result < 0 ? result : 0; | 2824 | return result < 0 ? result : 0; |
2843 | } | 2825 | } |
@@ -2852,10 +2834,7 @@ static int snd_pcm_forward_ioctl(struct snd_pcm_substream *substream, | |||
2852 | return -EFAULT; | 2834 | return -EFAULT; |
2853 | if (put_user(0, _frames)) | 2835 | if (put_user(0, _frames)) |
2854 | return -EFAULT; | 2836 | return -EFAULT; |
2855 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) | 2837 | result = snd_pcm_forward(substream, frames); |
2856 | result = snd_pcm_playback_forward(substream, frames); | ||
2857 | else | ||
2858 | result = snd_pcm_capture_forward(substream, frames); | ||
2859 | __put_user(result, _frames); | 2838 | __put_user(result, _frames); |
2860 | return result < 0 ? result : 0; | 2839 | return result < 0 ? result : 0; |
2861 | } | 2840 | } |
@@ -2998,7 +2977,7 @@ int snd_pcm_kernel_ioctl(struct snd_pcm_substream *substream, | |||
2998 | /* provided only for OSS; capture-only and no value returned */ | 2977 | /* provided only for OSS; capture-only and no value returned */ |
2999 | if (substream->stream != SNDRV_PCM_STREAM_CAPTURE) | 2978 | if (substream->stream != SNDRV_PCM_STREAM_CAPTURE) |
3000 | return -EINVAL; | 2979 | return -EINVAL; |
3001 | result = snd_pcm_capture_forward(substream, *frames); | 2980 | result = snd_pcm_forward(substream, *frames); |
3002 | return result < 0 ? result : 0; | 2981 | return result < 0 ? result : 0; |
3003 | } | 2982 | } |
3004 | case SNDRV_PCM_IOCTL_HW_PARAMS: | 2983 | case SNDRV_PCM_IOCTL_HW_PARAMS: |
@@ -3140,82 +3119,46 @@ static ssize_t snd_pcm_writev(struct kiocb *iocb, struct iov_iter *from) | |||
3140 | return result; | 3119 | return result; |
3141 | } | 3120 | } |
3142 | 3121 | ||
3143 | static __poll_t snd_pcm_playback_poll(struct file *file, poll_table * wait) | 3122 | static __poll_t snd_pcm_poll(struct file *file, poll_table *wait) |
3144 | { | 3123 | { |
3145 | struct snd_pcm_file *pcm_file; | 3124 | struct snd_pcm_file *pcm_file; |
3146 | struct snd_pcm_substream *substream; | 3125 | struct snd_pcm_substream *substream; |
3147 | struct snd_pcm_runtime *runtime; | 3126 | struct snd_pcm_runtime *runtime; |
3148 | __poll_t mask; | 3127 | __poll_t mask, ok; |
3149 | snd_pcm_uframes_t avail; | 3128 | snd_pcm_uframes_t avail; |
3150 | 3129 | ||
3151 | pcm_file = file->private_data; | 3130 | pcm_file = file->private_data; |
3152 | 3131 | ||
3153 | substream = pcm_file->substream; | 3132 | substream = pcm_file->substream; |
3133 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) | ||
3134 | ok = EPOLLOUT | EPOLLWRNORM; | ||
3135 | else | ||
3136 | ok = EPOLLIN | EPOLLRDNORM; | ||
3154 | if (PCM_RUNTIME_CHECK(substream)) | 3137 | if (PCM_RUNTIME_CHECK(substream)) |
3155 | return EPOLLOUT | EPOLLWRNORM | EPOLLERR; | 3138 | return ok | EPOLLERR; |
3156 | runtime = substream->runtime; | ||
3157 | |||
3158 | poll_wait(file, &runtime->sleep, wait); | ||
3159 | 3139 | ||
3160 | snd_pcm_stream_lock_irq(substream); | ||
3161 | avail = snd_pcm_playback_avail(runtime); | ||
3162 | switch (runtime->status->state) { | ||
3163 | case SNDRV_PCM_STATE_RUNNING: | ||
3164 | case SNDRV_PCM_STATE_PREPARED: | ||
3165 | case SNDRV_PCM_STATE_PAUSED: | ||
3166 | if (avail >= runtime->control->avail_min) { | ||
3167 | mask = EPOLLOUT | EPOLLWRNORM; | ||
3168 | break; | ||
3169 | } | ||
3170 | /* Fall through */ | ||
3171 | case SNDRV_PCM_STATE_DRAINING: | ||
3172 | mask = 0; | ||
3173 | break; | ||
3174 | default: | ||
3175 | mask = EPOLLOUT | EPOLLWRNORM | EPOLLERR; | ||
3176 | break; | ||
3177 | } | ||
3178 | snd_pcm_stream_unlock_irq(substream); | ||
3179 | return mask; | ||
3180 | } | ||
3181 | |||
3182 | static __poll_t snd_pcm_capture_poll(struct file *file, poll_table * wait) | ||
3183 | { | ||
3184 | struct snd_pcm_file *pcm_file; | ||
3185 | struct snd_pcm_substream *substream; | ||
3186 | struct snd_pcm_runtime *runtime; | ||
3187 | __poll_t mask; | ||
3188 | snd_pcm_uframes_t avail; | ||
3189 | |||
3190 | pcm_file = file->private_data; | ||
3191 | |||
3192 | substream = pcm_file->substream; | ||
3193 | if (PCM_RUNTIME_CHECK(substream)) | ||
3194 | return EPOLLIN | EPOLLRDNORM | EPOLLERR; | ||
3195 | runtime = substream->runtime; | 3140 | runtime = substream->runtime; |
3196 | |||
3197 | poll_wait(file, &runtime->sleep, wait); | 3141 | poll_wait(file, &runtime->sleep, wait); |
3198 | 3142 | ||
3143 | mask = 0; | ||
3199 | snd_pcm_stream_lock_irq(substream); | 3144 | snd_pcm_stream_lock_irq(substream); |
3200 | avail = snd_pcm_capture_avail(runtime); | 3145 | avail = snd_pcm_avail(substream); |
3201 | switch (runtime->status->state) { | 3146 | switch (runtime->status->state) { |
3202 | case SNDRV_PCM_STATE_RUNNING: | 3147 | case SNDRV_PCM_STATE_RUNNING: |
3203 | case SNDRV_PCM_STATE_PREPARED: | 3148 | case SNDRV_PCM_STATE_PREPARED: |
3204 | case SNDRV_PCM_STATE_PAUSED: | 3149 | case SNDRV_PCM_STATE_PAUSED: |
3205 | if (avail >= runtime->control->avail_min) { | 3150 | if (avail >= runtime->control->avail_min) |
3206 | mask = EPOLLIN | EPOLLRDNORM; | 3151 | mask = ok; |
3207 | break; | ||
3208 | } | ||
3209 | mask = 0; | ||
3210 | break; | 3152 | break; |
3211 | case SNDRV_PCM_STATE_DRAINING: | 3153 | case SNDRV_PCM_STATE_DRAINING: |
3212 | if (avail > 0) { | 3154 | if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) { |
3213 | mask = EPOLLIN | EPOLLRDNORM; | 3155 | mask = ok; |
3214 | break; | 3156 | if (!avail) |
3157 | mask |= EPOLLERR; | ||
3215 | } | 3158 | } |
3216 | /* Fall through */ | 3159 | break; |
3217 | default: | 3160 | default: |
3218 | mask = EPOLLIN | EPOLLRDNORM | EPOLLERR; | 3161 | mask = ok | EPOLLERR; |
3219 | break; | 3162 | break; |
3220 | } | 3163 | } |
3221 | snd_pcm_stream_unlock_irq(substream); | 3164 | snd_pcm_stream_unlock_irq(substream); |
@@ -3707,7 +3650,7 @@ const struct file_operations snd_pcm_f_ops[2] = { | |||
3707 | .open = snd_pcm_playback_open, | 3650 | .open = snd_pcm_playback_open, |
3708 | .release = snd_pcm_release, | 3651 | .release = snd_pcm_release, |
3709 | .llseek = no_llseek, | 3652 | .llseek = no_llseek, |
3710 | .poll = snd_pcm_playback_poll, | 3653 | .poll = snd_pcm_poll, |
3711 | .unlocked_ioctl = snd_pcm_ioctl, | 3654 | .unlocked_ioctl = snd_pcm_ioctl, |
3712 | .compat_ioctl = snd_pcm_ioctl_compat, | 3655 | .compat_ioctl = snd_pcm_ioctl_compat, |
3713 | .mmap = snd_pcm_mmap, | 3656 | .mmap = snd_pcm_mmap, |
@@ -3721,7 +3664,7 @@ const struct file_operations snd_pcm_f_ops[2] = { | |||
3721 | .open = snd_pcm_capture_open, | 3664 | .open = snd_pcm_capture_open, |
3722 | .release = snd_pcm_release, | 3665 | .release = snd_pcm_release, |
3723 | .llseek = no_llseek, | 3666 | .llseek = no_llseek, |
3724 | .poll = snd_pcm_capture_poll, | 3667 | .poll = snd_pcm_poll, |
3725 | .unlocked_ioctl = snd_pcm_ioctl, | 3668 | .unlocked_ioctl = snd_pcm_ioctl, |
3726 | .compat_ioctl = snd_pcm_ioctl_compat, | 3669 | .compat_ioctl = snd_pcm_ioctl_compat, |
3727 | .mmap = snd_pcm_mmap, | 3670 | .mmap = snd_pcm_mmap, |
diff --git a/sound/core/seq/seq_ports.c b/sound/core/seq/seq_ports.c index d21ece9f8d73..24d90abfc64d 100644 --- a/sound/core/seq/seq_ports.c +++ b/sound/core/seq/seq_ports.c | |||
@@ -669,7 +669,7 @@ int snd_seq_event_port_attach(int client, | |||
669 | /* Set up the port */ | 669 | /* Set up the port */ |
670 | memset(&portinfo, 0, sizeof(portinfo)); | 670 | memset(&portinfo, 0, sizeof(portinfo)); |
671 | portinfo.addr.client = client; | 671 | portinfo.addr.client = client; |
672 | strlcpy(portinfo.name, portname ? portname : "Unamed port", | 672 | strlcpy(portinfo.name, portname ? portname : "Unnamed port", |
673 | sizeof(portinfo.name)); | 673 | sizeof(portinfo.name)); |
674 | 674 | ||
675 | portinfo.capability = cap; | 675 | portinfo.capability = cap; |
diff --git a/sound/core/seq/seq_timer.c b/sound/core/seq/seq_timer.c index 23167578231f..f587d0e27476 100644 --- a/sound/core/seq/seq_timer.c +++ b/sound/core/seq/seq_timer.c | |||
@@ -371,9 +371,7 @@ static int initialize_timer(struct snd_seq_timer *tmr) | |||
371 | 371 | ||
372 | tmr->ticks = 1; | 372 | tmr->ticks = 1; |
373 | if (!(t->hw.flags & SNDRV_TIMER_HW_SLAVE)) { | 373 | if (!(t->hw.flags & SNDRV_TIMER_HW_SLAVE)) { |
374 | unsigned long r = t->hw.resolution; | 374 | unsigned long r = snd_timer_resolution(tmr->timeri); |
375 | if (! r && t->hw.c_resolution) | ||
376 | r = t->hw.c_resolution(t); | ||
377 | if (r) { | 375 | if (r) { |
378 | tmr->ticks = (unsigned int)(1000000000uL / (r * freq)); | 376 | tmr->ticks = (unsigned int)(1000000000uL / (r * freq)); |
379 | if (! tmr->ticks) | 377 | if (! tmr->ticks) |
diff --git a/sound/core/timer.c b/sound/core/timer.c index 0ddcae495838..665089c45560 100644 --- a/sound/core/timer.c +++ b/sound/core/timer.c | |||
@@ -427,25 +427,35 @@ int snd_timer_close(struct snd_timer_instance *timeri) | |||
427 | } | 427 | } |
428 | EXPORT_SYMBOL(snd_timer_close); | 428 | EXPORT_SYMBOL(snd_timer_close); |
429 | 429 | ||
430 | static unsigned long snd_timer_hw_resolution(struct snd_timer *timer) | ||
431 | { | ||
432 | if (timer->hw.c_resolution) | ||
433 | return timer->hw.c_resolution(timer); | ||
434 | else | ||
435 | return timer->hw.resolution; | ||
436 | } | ||
437 | |||
430 | unsigned long snd_timer_resolution(struct snd_timer_instance *timeri) | 438 | unsigned long snd_timer_resolution(struct snd_timer_instance *timeri) |
431 | { | 439 | { |
432 | struct snd_timer * timer; | 440 | struct snd_timer * timer; |
441 | unsigned long ret = 0; | ||
442 | unsigned long flags; | ||
433 | 443 | ||
434 | if (timeri == NULL) | 444 | if (timeri == NULL) |
435 | return 0; | 445 | return 0; |
436 | timer = timeri->timer; | 446 | timer = timeri->timer; |
437 | if (timer) { | 447 | if (timer) { |
438 | if (timer->hw.c_resolution) | 448 | spin_lock_irqsave(&timer->lock, flags); |
439 | return timer->hw.c_resolution(timer); | 449 | ret = snd_timer_hw_resolution(timer); |
440 | return timer->hw.resolution; | 450 | spin_unlock_irqrestore(&timer->lock, flags); |
441 | } | 451 | } |
442 | return 0; | 452 | return ret; |
443 | } | 453 | } |
444 | EXPORT_SYMBOL(snd_timer_resolution); | 454 | EXPORT_SYMBOL(snd_timer_resolution); |
445 | 455 | ||
446 | static void snd_timer_notify1(struct snd_timer_instance *ti, int event) | 456 | static void snd_timer_notify1(struct snd_timer_instance *ti, int event) |
447 | { | 457 | { |
448 | struct snd_timer *timer; | 458 | struct snd_timer *timer = ti->timer; |
449 | unsigned long resolution = 0; | 459 | unsigned long resolution = 0; |
450 | struct snd_timer_instance *ts; | 460 | struct snd_timer_instance *ts; |
451 | struct timespec tstamp; | 461 | struct timespec tstamp; |
@@ -457,14 +467,14 @@ static void snd_timer_notify1(struct snd_timer_instance *ti, int event) | |||
457 | if (snd_BUG_ON(event < SNDRV_TIMER_EVENT_START || | 467 | if (snd_BUG_ON(event < SNDRV_TIMER_EVENT_START || |
458 | event > SNDRV_TIMER_EVENT_PAUSE)) | 468 | event > SNDRV_TIMER_EVENT_PAUSE)) |
459 | return; | 469 | return; |
460 | if (event == SNDRV_TIMER_EVENT_START || | 470 | if (timer && |
461 | event == SNDRV_TIMER_EVENT_CONTINUE) | 471 | (event == SNDRV_TIMER_EVENT_START || |
462 | resolution = snd_timer_resolution(ti); | 472 | event == SNDRV_TIMER_EVENT_CONTINUE)) |
473 | resolution = snd_timer_hw_resolution(timer); | ||
463 | if (ti->ccallback) | 474 | if (ti->ccallback) |
464 | ti->ccallback(ti, event, &tstamp, resolution); | 475 | ti->ccallback(ti, event, &tstamp, resolution); |
465 | if (ti->flags & SNDRV_TIMER_IFLG_SLAVE) | 476 | if (ti->flags & SNDRV_TIMER_IFLG_SLAVE) |
466 | return; | 477 | return; |
467 | timer = ti->timer; | ||
468 | if (timer == NULL) | 478 | if (timer == NULL) |
469 | return; | 479 | return; |
470 | if (timer->hw.flags & SNDRV_TIMER_HW_SLAVE) | 480 | if (timer->hw.flags & SNDRV_TIMER_HW_SLAVE) |
@@ -771,10 +781,7 @@ void snd_timer_interrupt(struct snd_timer * timer, unsigned long ticks_left) | |||
771 | spin_lock_irqsave(&timer->lock, flags); | 781 | spin_lock_irqsave(&timer->lock, flags); |
772 | 782 | ||
773 | /* remember the current resolution */ | 783 | /* remember the current resolution */ |
774 | if (timer->hw.c_resolution) | 784 | resolution = snd_timer_hw_resolution(timer); |
775 | resolution = timer->hw.c_resolution(timer); | ||
776 | else | ||
777 | resolution = timer->hw.resolution; | ||
778 | 785 | ||
779 | /* loop for all active instances | 786 | /* loop for all active instances |
780 | * Here we cannot use list_for_each_entry because the active_list of a | 787 | * Here we cannot use list_for_each_entry because the active_list of a |
@@ -1014,12 +1021,8 @@ void snd_timer_notify(struct snd_timer *timer, int event, struct timespec *tstam | |||
1014 | spin_lock_irqsave(&timer->lock, flags); | 1021 | spin_lock_irqsave(&timer->lock, flags); |
1015 | if (event == SNDRV_TIMER_EVENT_MSTART || | 1022 | if (event == SNDRV_TIMER_EVENT_MSTART || |
1016 | event == SNDRV_TIMER_EVENT_MCONTINUE || | 1023 | event == SNDRV_TIMER_EVENT_MCONTINUE || |
1017 | event == SNDRV_TIMER_EVENT_MRESUME) { | 1024 | event == SNDRV_TIMER_EVENT_MRESUME) |
1018 | if (timer->hw.c_resolution) | 1025 | resolution = snd_timer_hw_resolution(timer); |
1019 | resolution = timer->hw.c_resolution(timer); | ||
1020 | else | ||
1021 | resolution = timer->hw.resolution; | ||
1022 | } | ||
1023 | list_for_each_entry(ti, &timer->active_list_head, active_list) { | 1026 | list_for_each_entry(ti, &timer->active_list_head, active_list) { |
1024 | if (ti->ccallback) | 1027 | if (ti->ccallback) |
1025 | ti->ccallback(ti, event, tstamp, resolution); | 1028 | ti->ccallback(ti, event, tstamp, resolution); |
@@ -1656,10 +1659,8 @@ static int snd_timer_user_gstatus(struct file *file, | |||
1656 | mutex_lock(®ister_mutex); | 1659 | mutex_lock(®ister_mutex); |
1657 | t = snd_timer_find(&tid); | 1660 | t = snd_timer_find(&tid); |
1658 | if (t != NULL) { | 1661 | if (t != NULL) { |
1659 | if (t->hw.c_resolution) | 1662 | spin_lock_irq(&t->lock); |
1660 | gstatus.resolution = t->hw.c_resolution(t); | 1663 | gstatus.resolution = snd_timer_hw_resolution(t); |
1661 | else | ||
1662 | gstatus.resolution = t->hw.resolution; | ||
1663 | if (t->hw.precise_resolution) { | 1664 | if (t->hw.precise_resolution) { |
1664 | t->hw.precise_resolution(t, &gstatus.resolution_num, | 1665 | t->hw.precise_resolution(t, &gstatus.resolution_num, |
1665 | &gstatus.resolution_den); | 1666 | &gstatus.resolution_den); |
@@ -1667,6 +1668,7 @@ static int snd_timer_user_gstatus(struct file *file, | |||
1667 | gstatus.resolution_num = gstatus.resolution; | 1668 | gstatus.resolution_num = gstatus.resolution; |
1668 | gstatus.resolution_den = 1000000000uL; | 1669 | gstatus.resolution_den = 1000000000uL; |
1669 | } | 1670 | } |
1671 | spin_unlock_irq(&t->lock); | ||
1670 | } else { | 1672 | } else { |
1671 | err = -ENODEV; | 1673 | err = -ENODEV; |
1672 | } | 1674 | } |
diff --git a/sound/core/vmaster.c b/sound/core/vmaster.c index 9e96186742d0..58fa3f94722a 100644 --- a/sound/core/vmaster.c +++ b/sound/core/vmaster.c | |||
@@ -421,13 +421,15 @@ struct snd_kcontrol *snd_ctl_make_virtual_master(char *name, | |||
421 | kctl->private_free = master_free; | 421 | kctl->private_free = master_free; |
422 | 422 | ||
423 | /* additional (constant) TLV read */ | 423 | /* additional (constant) TLV read */ |
424 | if (tlv && | 424 | if (tlv) { |
425 | (tlv[0] == SNDRV_CTL_TLVT_DB_SCALE || | 425 | unsigned int type = tlv[SNDRV_CTL_TLVO_TYPE]; |
426 | tlv[0] == SNDRV_CTL_TLVT_DB_MINMAX || | 426 | if (type == SNDRV_CTL_TLVT_DB_SCALE || |
427 | tlv[0] == SNDRV_CTL_TLVT_DB_MINMAX_MUTE)) { | 427 | type == SNDRV_CTL_TLVT_DB_MINMAX || |
428 | kctl->vd[0].access |= SNDRV_CTL_ELEM_ACCESS_TLV_READ; | 428 | type == SNDRV_CTL_TLVT_DB_MINMAX_MUTE) { |
429 | memcpy(master->tlv, tlv, sizeof(master->tlv)); | 429 | kctl->vd[0].access |= SNDRV_CTL_ELEM_ACCESS_TLV_READ; |
430 | kctl->tlv.p = master->tlv; | 430 | memcpy(master->tlv, tlv, sizeof(master->tlv)); |
431 | kctl->tlv.p = master->tlv; | ||
432 | } | ||
431 | } | 433 | } |
432 | 434 | ||
433 | return kctl; | 435 | return kctl; |
diff --git a/sound/drivers/aloop.c b/sound/drivers/aloop.c index eab7f594ebe7..78a2fdc38531 100644 --- a/sound/drivers/aloop.c +++ b/sound/drivers/aloop.c | |||
@@ -768,20 +768,7 @@ static int loopback_close(struct snd_pcm_substream *substream) | |||
768 | return 0; | 768 | return 0; |
769 | } | 769 | } |
770 | 770 | ||
771 | static const struct snd_pcm_ops loopback_playback_ops = { | 771 | static const struct snd_pcm_ops loopback_pcm_ops = { |
772 | .open = loopback_open, | ||
773 | .close = loopback_close, | ||
774 | .ioctl = snd_pcm_lib_ioctl, | ||
775 | .hw_params = loopback_hw_params, | ||
776 | .hw_free = loopback_hw_free, | ||
777 | .prepare = loopback_prepare, | ||
778 | .trigger = loopback_trigger, | ||
779 | .pointer = loopback_pointer, | ||
780 | .page = snd_pcm_lib_get_vmalloc_page, | ||
781 | .mmap = snd_pcm_lib_mmap_vmalloc, | ||
782 | }; | ||
783 | |||
784 | static const struct snd_pcm_ops loopback_capture_ops = { | ||
785 | .open = loopback_open, | 772 | .open = loopback_open, |
786 | .close = loopback_close, | 773 | .close = loopback_close, |
787 | .ioctl = snd_pcm_lib_ioctl, | 774 | .ioctl = snd_pcm_lib_ioctl, |
@@ -804,8 +791,8 @@ static int loopback_pcm_new(struct loopback *loopback, | |||
804 | substreams, substreams, &pcm); | 791 | substreams, substreams, &pcm); |
805 | if (err < 0) | 792 | if (err < 0) |
806 | return err; | 793 | return err; |
807 | snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &loopback_playback_ops); | 794 | snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, &loopback_pcm_ops); |
808 | snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &loopback_capture_ops); | 795 | snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, &loopback_pcm_ops); |
809 | 796 | ||
810 | pcm->private_data = loopback; | 797 | pcm->private_data = loopback; |
811 | pcm->info_flags = 0; | 798 | pcm->info_flags = 0; |
diff --git a/sound/drivers/dummy.c b/sound/drivers/dummy.c index 8fb9a54fe8ba..9af154db530a 100644 --- a/sound/drivers/dummy.c +++ b/sound/drivers/dummy.c | |||
@@ -1042,7 +1042,7 @@ static void dummy_proc_init(struct snd_dummy *chip) | |||
1042 | if (!snd_card_proc_new(chip->card, "dummy_pcm", &entry)) { | 1042 | if (!snd_card_proc_new(chip->card, "dummy_pcm", &entry)) { |
1043 | snd_info_set_text_ops(entry, chip, dummy_proc_read); | 1043 | snd_info_set_text_ops(entry, chip, dummy_proc_read); |
1044 | entry->c.text.write = dummy_proc_write; | 1044 | entry->c.text.write = dummy_proc_write; |
1045 | entry->mode |= S_IWUSR; | 1045 | entry->mode |= 0200; |
1046 | entry->private_data = chip; | 1046 | entry->private_data = chip; |
1047 | } | 1047 | } |
1048 | } | 1048 | } |
diff --git a/sound/drivers/mts64.c b/sound/drivers/mts64.c index f32e81342247..b68e71ca7abd 100644 --- a/sound/drivers/mts64.c +++ b/sound/drivers/mts64.c | |||
@@ -41,11 +41,11 @@ static bool enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP; | |||
41 | static struct platform_device *platform_devices[SNDRV_CARDS]; | 41 | static struct platform_device *platform_devices[SNDRV_CARDS]; |
42 | static int device_count; | 42 | static int device_count; |
43 | 43 | ||
44 | module_param_array(index, int, NULL, S_IRUGO); | 44 | module_param_array(index, int, NULL, 0444); |
45 | MODULE_PARM_DESC(index, "Index value for " CARD_NAME " soundcard."); | 45 | MODULE_PARM_DESC(index, "Index value for " CARD_NAME " soundcard."); |
46 | module_param_array(id, charp, NULL, S_IRUGO); | 46 | module_param_array(id, charp, NULL, 0444); |
47 | MODULE_PARM_DESC(id, "ID string for " CARD_NAME " soundcard."); | 47 | MODULE_PARM_DESC(id, "ID string for " CARD_NAME " soundcard."); |
48 | module_param_array(enable, bool, NULL, S_IRUGO); | 48 | module_param_array(enable, bool, NULL, 0444); |
49 | MODULE_PARM_DESC(enable, "Enable " CARD_NAME " soundcard."); | 49 | MODULE_PARM_DESC(enable, "Enable " CARD_NAME " soundcard."); |
50 | 50 | ||
51 | MODULE_AUTHOR("Matthias Koenig <mk@phasorlab.de>"); | 51 | MODULE_AUTHOR("Matthias Koenig <mk@phasorlab.de>"); |
diff --git a/sound/drivers/opl4/opl4_proc.c b/sound/drivers/opl4/opl4_proc.c index cd2c07fa2ef4..16b24091d799 100644 --- a/sound/drivers/opl4/opl4_proc.c +++ b/sound/drivers/opl4/opl4_proc.c | |||
@@ -104,7 +104,7 @@ int snd_opl4_create_proc(struct snd_opl4 *opl4) | |||
104 | if (entry) { | 104 | if (entry) { |
105 | if (opl4->hardware < OPL3_HW_OPL4_ML) { | 105 | if (opl4->hardware < OPL3_HW_OPL4_ML) { |
106 | /* OPL4 can access 4 MB external ROM/SRAM */ | 106 | /* OPL4 can access 4 MB external ROM/SRAM */ |
107 | entry->mode |= S_IWUSR; | 107 | entry->mode |= 0200; |
108 | entry->size = 4 * 1024 * 1024; | 108 | entry->size = 4 * 1024 * 1024; |
109 | } else { | 109 | } else { |
110 | /* OPL4-ML has 1 MB internal ROM */ | 110 | /* OPL4-ML has 1 MB internal ROM */ |
diff --git a/sound/drivers/portman2x4.c b/sound/drivers/portman2x4.c index ec8a94325ef6..3cdf0a88d71b 100644 --- a/sound/drivers/portman2x4.c +++ b/sound/drivers/portman2x4.c | |||
@@ -60,11 +60,11 @@ static bool enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP; | |||
60 | static struct platform_device *platform_devices[SNDRV_CARDS]; | 60 | static struct platform_device *platform_devices[SNDRV_CARDS]; |
61 | static int device_count; | 61 | static int device_count; |
62 | 62 | ||
63 | module_param_array(index, int, NULL, S_IRUGO); | 63 | module_param_array(index, int, NULL, 0444); |
64 | MODULE_PARM_DESC(index, "Index value for " CARD_NAME " soundcard."); | 64 | MODULE_PARM_DESC(index, "Index value for " CARD_NAME " soundcard."); |
65 | module_param_array(id, charp, NULL, S_IRUGO); | 65 | module_param_array(id, charp, NULL, 0444); |
66 | MODULE_PARM_DESC(id, "ID string for " CARD_NAME " soundcard."); | 66 | MODULE_PARM_DESC(id, "ID string for " CARD_NAME " soundcard."); |
67 | module_param_array(enable, bool, NULL, S_IRUGO); | 67 | module_param_array(enable, bool, NULL, 0444); |
68 | MODULE_PARM_DESC(enable, "Enable " CARD_NAME " soundcard."); | 68 | MODULE_PARM_DESC(enable, "Enable " CARD_NAME " soundcard."); |
69 | 69 | ||
70 | MODULE_AUTHOR("Levent Guendogdu, Tobias Gehrig, Matthias Koenig"); | 70 | MODULE_AUTHOR("Levent Guendogdu, Tobias Gehrig, Matthias Koenig"); |
diff --git a/sound/firewire/bebob/bebob_proc.c b/sound/firewire/bebob/bebob_proc.c index ec24f96794f5..8096891af913 100644 --- a/sound/firewire/bebob/bebob_proc.c +++ b/sound/firewire/bebob/bebob_proc.c | |||
@@ -183,7 +183,7 @@ void snd_bebob_proc_init(struct snd_bebob *bebob) | |||
183 | bebob->card->proc_root); | 183 | bebob->card->proc_root); |
184 | if (root == NULL) | 184 | if (root == NULL) |
185 | return; | 185 | return; |
186 | root->mode = S_IFDIR | S_IRUGO | S_IXUGO; | 186 | root->mode = S_IFDIR | 0555; |
187 | if (snd_info_register(root) < 0) { | 187 | if (snd_info_register(root) < 0) { |
188 | snd_info_free_entry(root); | 188 | snd_info_free_entry(root); |
189 | return; | 189 | return; |
diff --git a/sound/firewire/dice/Makefile b/sound/firewire/dice/Makefile index 55b4be9b0034..37062a233f6a 100644 --- a/sound/firewire/dice/Makefile +++ b/sound/firewire/dice/Makefile | |||
@@ -1,3 +1,4 @@ | |||
1 | snd-dice-objs := dice-transaction.o dice-stream.o dice-proc.o dice-midi.o \ | 1 | snd-dice-objs := dice-transaction.o dice-stream.o dice-proc.o dice-midi.o \ |
2 | dice-pcm.o dice-hwdep.o dice.o | 2 | dice-pcm.o dice-hwdep.o dice.o dice-tcelectronic.o \ |
3 | dice-alesis.o dice-extension.o dice-mytek.o | ||
3 | obj-$(CONFIG_SND_DICE) += snd-dice.o | 4 | obj-$(CONFIG_SND_DICE) += snd-dice.o |
diff --git a/sound/firewire/dice/dice-alesis.c b/sound/firewire/dice/dice-alesis.c new file mode 100644 index 000000000000..b2efb1c71a98 --- /dev/null +++ b/sound/firewire/dice/dice-alesis.c | |||
@@ -0,0 +1,52 @@ | |||
1 | // SPDX-License-Identifier: GPL-2.0 | ||
2 | /* | ||
3 | * dice-alesis.c - a part of driver for DICE based devices | ||
4 | * | ||
5 | * Copyright (c) 2018 Takashi Sakamoto | ||
6 | */ | ||
7 | |||
8 | #include "dice.h" | ||
9 | |||
10 | static const unsigned int | ||
11 | alesis_io14_tx_pcm_chs[MAX_STREAMS][SND_DICE_RATE_MODE_COUNT] = { | ||
12 | {6, 6, 4}, /* Tx0 = Analog + S/PDIF. */ | ||
13 | {8, 4, 0}, /* Tx1 = ADAT1. */ | ||
14 | }; | ||
15 | |||
16 | static const unsigned int | ||
17 | alesis_io26_tx_pcm_chs[MAX_STREAMS][SND_DICE_RATE_MODE_COUNT] = { | ||
18 | {10, 10, 8}, /* Tx0 = Analog + S/PDIF. */ | ||
19 | {16, 8, 0}, /* Tx1 = ADAT1 + ADAT2. */ | ||
20 | }; | ||
21 | |||
22 | int snd_dice_detect_alesis_formats(struct snd_dice *dice) | ||
23 | { | ||
24 | __be32 reg; | ||
25 | u32 data; | ||
26 | int i; | ||
27 | int err; | ||
28 | |||
29 | err = snd_dice_transaction_read_tx(dice, TX_NUMBER_AUDIO, ®, | ||
30 | sizeof(reg)); | ||
31 | if (err < 0) | ||
32 | return err; | ||
33 | data = be32_to_cpu(reg); | ||
34 | |||
35 | if (data == 4 || data == 6) { | ||
36 | memcpy(dice->tx_pcm_chs, alesis_io14_tx_pcm_chs, | ||
37 | MAX_STREAMS * SND_DICE_RATE_MODE_COUNT * | ||
38 | sizeof(unsigned int)); | ||
39 | } else { | ||
40 | memcpy(dice->rx_pcm_chs, alesis_io26_tx_pcm_chs, | ||
41 | MAX_STREAMS * SND_DICE_RATE_MODE_COUNT * | ||
42 | sizeof(unsigned int)); | ||
43 | } | ||
44 | |||
45 | for (i = 0; i < SND_DICE_RATE_MODE_COUNT; ++i) | ||
46 | dice->rx_pcm_chs[0][i] = 8; | ||
47 | |||
48 | dice->tx_midi_ports[0] = 1; | ||
49 | dice->rx_midi_ports[0] = 1; | ||
50 | |||
51 | return 0; | ||
52 | } | ||
diff --git a/sound/firewire/dice/dice-extension.c b/sound/firewire/dice/dice-extension.c new file mode 100644 index 000000000000..a63fcbc875ad --- /dev/null +++ b/sound/firewire/dice/dice-extension.c | |||
@@ -0,0 +1,172 @@ | |||
1 | // SPDX-License-Identifier: GPL-2.0 | ||
2 | /* | ||
3 | * dice-extension.c - a part of driver for DICE based devices | ||
4 | * | ||
5 | * Copyright (c) 2018 Takashi Sakamoto | ||
6 | */ | ||
7 | |||
8 | #include "dice.h" | ||
9 | |||
10 | /* For TCD2210/2220, TCAT defines extension of application protocol. */ | ||
11 | |||
12 | #define DICE_EXT_APP_SPACE 0xffffe0200000uLL | ||
13 | |||
14 | #define DICE_EXT_APP_CAPS_OFFSET 0x00 | ||
15 | #define DICE_EXT_APP_CAPS_SIZE 0x04 | ||
16 | #define DICE_EXT_APP_CMD_OFFSET 0x08 | ||
17 | #define DICE_EXT_APP_CMD_SIZE 0x0c | ||
18 | #define DICE_EXT_APP_MIXER_OFFSET 0x10 | ||
19 | #define DICE_EXT_APP_MIXER_SIZE 0x14 | ||
20 | #define DICE_EXT_APP_PEAK_OFFSET 0x18 | ||
21 | #define DICE_EXT_APP_PEAK_SIZE 0x1c | ||
22 | #define DICE_EXT_APP_ROUTER_OFFSET 0x20 | ||
23 | #define DICE_EXT_APP_ROUTER_SIZE 0x24 | ||
24 | #define DICE_EXT_APP_STREAM_OFFSET 0x28 | ||
25 | #define DICE_EXT_APP_STREAM_SIZE 0x2c | ||
26 | #define DICE_EXT_APP_CURRENT_OFFSET 0x30 | ||
27 | #define DICE_EXT_APP_CURRENT_SIZE 0x34 | ||
28 | #define DICE_EXT_APP_STANDALONE_OFFSET 0x38 | ||
29 | #define DICE_EXT_APP_STANDALONE_SIZE 0x3c | ||
30 | #define DICE_EXT_APP_APPLICATION_OFFSET 0x40 | ||
31 | #define DICE_EXT_APP_APPLICATION_SIZE 0x44 | ||
32 | |||
33 | #define EXT_APP_STREAM_TX_NUMBER 0x0000 | ||
34 | #define EXT_APP_STREAM_RX_NUMBER 0x0004 | ||
35 | #define EXT_APP_STREAM_ENTRIES 0x0008 | ||
36 | #define EXT_APP_STREAM_ENTRY_SIZE 0x010c | ||
37 | #define EXT_APP_NUMBER_AUDIO 0x0000 | ||
38 | #define EXT_APP_NUMBER_MIDI 0x0004 | ||
39 | #define EXT_APP_NAMES 0x0008 | ||
40 | #define EXT_APP_NAMES_SIZE 256 | ||
41 | #define EXT_APP_AC3 0x0108 | ||
42 | |||
43 | #define EXT_APP_CONFIG_LOW_ROUTER 0x0000 | ||
44 | #define EXT_APP_CONFIG_LOW_STREAM 0x1000 | ||
45 | #define EXT_APP_CONFIG_MIDDLE_ROUTER 0x2000 | ||
46 | #define EXT_APP_CONFIG_MIDDLE_STREAM 0x3000 | ||
47 | #define EXT_APP_CONFIG_HIGH_ROUTER 0x4000 | ||
48 | #define EXT_APP_CONFIG_HIGH_STREAM 0x5000 | ||
49 | |||
50 | static inline int read_transaction(struct snd_dice *dice, u64 section_addr, | ||
51 | u32 offset, void *buf, size_t len) | ||
52 | { | ||
53 | return snd_fw_transaction(dice->unit, | ||
54 | len == 4 ? TCODE_READ_QUADLET_REQUEST : | ||
55 | TCODE_READ_BLOCK_REQUEST, | ||
56 | section_addr + offset, buf, len, 0); | ||
57 | } | ||
58 | |||
59 | static int read_stream_entries(struct snd_dice *dice, u64 section_addr, | ||
60 | u32 base_offset, unsigned int stream_count, | ||
61 | unsigned int mode, | ||
62 | unsigned int pcm_channels[MAX_STREAMS][3], | ||
63 | unsigned int midi_ports[MAX_STREAMS]) | ||
64 | { | ||
65 | u32 entry_offset; | ||
66 | __be32 reg[2]; | ||
67 | int err; | ||
68 | int i; | ||
69 | |||
70 | for (i = 0; i < stream_count; ++i) { | ||
71 | entry_offset = base_offset + i * EXT_APP_STREAM_ENTRY_SIZE; | ||
72 | err = read_transaction(dice, section_addr, | ||
73 | entry_offset + EXT_APP_NUMBER_AUDIO, | ||
74 | reg, sizeof(reg)); | ||
75 | if (err < 0) | ||
76 | return err; | ||
77 | pcm_channels[i][mode] = be32_to_cpu(reg[0]); | ||
78 | midi_ports[i] = max(midi_ports[i], be32_to_cpu(reg[1])); | ||
79 | } | ||
80 | |||
81 | return 0; | ||
82 | } | ||
83 | |||
84 | static int detect_stream_formats(struct snd_dice *dice, u64 section_addr) | ||
85 | { | ||
86 | u32 base_offset; | ||
87 | __be32 reg[2]; | ||
88 | unsigned int stream_count; | ||
89 | int mode; | ||
90 | int err = 0; | ||
91 | |||
92 | for (mode = 0; mode < SND_DICE_RATE_MODE_COUNT; ++mode) { | ||
93 | unsigned int cap; | ||
94 | |||
95 | /* | ||
96 | * Some models report stream formats at highest mode, however | ||
97 | * they don't support the mode. Check clock capabilities. | ||
98 | */ | ||
99 | if (mode == 2) { | ||
100 | cap = CLOCK_CAP_RATE_176400 | CLOCK_CAP_RATE_192000; | ||
101 | } else if (mode == 1) { | ||
102 | cap = CLOCK_CAP_RATE_88200 | CLOCK_CAP_RATE_96000; | ||
103 | } else { | ||
104 | cap = CLOCK_CAP_RATE_32000 | CLOCK_CAP_RATE_44100 | | ||
105 | CLOCK_CAP_RATE_48000; | ||
106 | } | ||
107 | if (!(cap & dice->clock_caps)) | ||
108 | continue; | ||
109 | |||
110 | base_offset = 0x2000 * mode + 0x1000; | ||
111 | |||
112 | err = read_transaction(dice, section_addr, | ||
113 | base_offset + EXT_APP_STREAM_TX_NUMBER, | ||
114 | ®, sizeof(reg)); | ||
115 | if (err < 0) | ||
116 | break; | ||
117 | |||
118 | base_offset += EXT_APP_STREAM_ENTRIES; | ||
119 | stream_count = be32_to_cpu(reg[0]); | ||
120 | err = read_stream_entries(dice, section_addr, base_offset, | ||
121 | stream_count, mode, | ||
122 | dice->tx_pcm_chs, | ||
123 | dice->tx_midi_ports); | ||
124 | if (err < 0) | ||
125 | break; | ||
126 | |||
127 | base_offset += stream_count * EXT_APP_STREAM_ENTRY_SIZE; | ||
128 | stream_count = be32_to_cpu(reg[1]); | ||
129 | err = read_stream_entries(dice, section_addr, base_offset, | ||
130 | stream_count, | ||
131 | mode, dice->rx_pcm_chs, | ||
132 | dice->rx_midi_ports); | ||
133 | if (err < 0) | ||
134 | break; | ||
135 | } | ||
136 | |||
137 | return err; | ||
138 | } | ||
139 | |||
140 | int snd_dice_detect_extension_formats(struct snd_dice *dice) | ||
141 | { | ||
142 | __be32 *pointers; | ||
143 | unsigned int i; | ||
144 | u64 section_addr; | ||
145 | int err; | ||
146 | |||
147 | pointers = kmalloc_array(9, sizeof(__be32) * 2, GFP_KERNEL); | ||
148 | if (pointers == NULL) | ||
149 | return -ENOMEM; | ||
150 | |||
151 | err = snd_fw_transaction(dice->unit, TCODE_READ_BLOCK_REQUEST, | ||
152 | DICE_EXT_APP_SPACE, pointers, | ||
153 | 9 * sizeof(__be32) * 2, 0); | ||
154 | if (err < 0) | ||
155 | goto end; | ||
156 | |||
157 | /* Check two of them for offset have the same value or not. */ | ||
158 | for (i = 0; i < 9; ++i) { | ||
159 | int j; | ||
160 | |||
161 | for (j = i + 1; j < 9; ++j) { | ||
162 | if (pointers[i * 2] == pointers[j * 2]) | ||
163 | goto end; | ||
164 | } | ||
165 | } | ||
166 | |||
167 | section_addr = DICE_EXT_APP_SPACE + be32_to_cpu(pointers[12]) * 4; | ||
168 | err = detect_stream_formats(dice, section_addr); | ||
169 | end: | ||
170 | kfree(pointers); | ||
171 | return err; | ||
172 | } | ||
diff --git a/sound/firewire/dice/dice-interface.h b/sound/firewire/dice/dice-interface.h index 15a484b05298..9cad3d608229 100644 --- a/sound/firewire/dice/dice-interface.h +++ b/sound/firewire/dice/dice-interface.h | |||
@@ -175,13 +175,18 @@ | |||
175 | #define GLOBAL_SAMPLE_RATE 0x05c | 175 | #define GLOBAL_SAMPLE_RATE 0x05c |
176 | 176 | ||
177 | /* | 177 | /* |
178 | * Some old firmware versions do not have the following global registers. | ||
179 | * Windows drivers produced by TCAT lost backward compatibility in its | ||
180 | * early release because they can handle firmware only which supports the | ||
181 | * following registers. | ||
182 | */ | ||
183 | |||
184 | /* | ||
178 | * The version of the DICE driver specification that this device conforms to; | 185 | * The version of the DICE driver specification that this device conforms to; |
179 | * read-only. | 186 | * read-only. |
180 | */ | 187 | */ |
181 | #define GLOBAL_VERSION 0x060 | 188 | #define GLOBAL_VERSION 0x060 |
182 | 189 | ||
183 | /* Some old firmware versions do not have the following global registers: */ | ||
184 | |||
185 | /* | 190 | /* |
186 | * Supported sample rates and clock sources; read-only. | 191 | * Supported sample rates and clock sources; read-only. |
187 | */ | 192 | */ |
diff --git a/sound/firewire/dice/dice-midi.c b/sound/firewire/dice/dice-midi.c index 8ff6da3c51f7..84eca8a51a02 100644 --- a/sound/firewire/dice/dice-midi.c +++ b/sound/firewire/dice/dice-midi.c | |||
@@ -101,27 +101,18 @@ int snd_dice_create_midi(struct snd_dice *dice) | |||
101 | .close = midi_close, | 101 | .close = midi_close, |
102 | .trigger = midi_playback_trigger, | 102 | .trigger = midi_playback_trigger, |
103 | }; | 103 | }; |
104 | __be32 reg; | ||
105 | struct snd_rawmidi *rmidi; | 104 | struct snd_rawmidi *rmidi; |
106 | struct snd_rawmidi_str *str; | 105 | struct snd_rawmidi_str *str; |
107 | unsigned int midi_in_ports, midi_out_ports; | 106 | unsigned int midi_in_ports, midi_out_ports; |
107 | int i; | ||
108 | int err; | 108 | int err; |
109 | 109 | ||
110 | /* | 110 | midi_in_ports = 0; |
111 | * Use the number of MIDI conformant data channel at current sampling | 111 | midi_out_ports = 0; |
112 | * transfer frequency. | 112 | for (i = 0; i < MAX_STREAMS; ++i) { |
113 | */ | 113 | midi_in_ports = max(midi_in_ports, dice->tx_midi_ports[i]); |
114 | err = snd_dice_transaction_read_tx(dice, TX_NUMBER_MIDI, | 114 | midi_out_ports = max(midi_out_ports, dice->rx_midi_ports[i]); |
115 | ®, sizeof(reg)); | 115 | } |
116 | if (err < 0) | ||
117 | return err; | ||
118 | midi_in_ports = be32_to_cpu(reg); | ||
119 | |||
120 | err = snd_dice_transaction_read_rx(dice, RX_NUMBER_MIDI, | ||
121 | ®, sizeof(reg)); | ||
122 | if (err < 0) | ||
123 | return err; | ||
124 | midi_out_ports = be32_to_cpu(reg); | ||
125 | 116 | ||
126 | if (midi_in_ports + midi_out_ports == 0) | 117 | if (midi_in_ports + midi_out_ports == 0) |
127 | return 0; | 118 | return 0; |
diff --git a/sound/firewire/dice/dice-mytek.c b/sound/firewire/dice/dice-mytek.c new file mode 100644 index 000000000000..eb7d5492d10b --- /dev/null +++ b/sound/firewire/dice/dice-mytek.c | |||
@@ -0,0 +1,46 @@ | |||
1 | // SPDX-License-Identifier: GPL-2.0 | ||
2 | /* | ||
3 | * dice-mytek.c - a part of driver for DICE based devices | ||
4 | * | ||
5 | * Copyright (c) 2018 Melvin Vermeeren | ||
6 | */ | ||
7 | |||
8 | #include "dice.h" | ||
9 | |||
10 | struct dice_mytek_spec { | ||
11 | unsigned int tx_pcm_chs[MAX_STREAMS][SND_DICE_RATE_MODE_COUNT]; | ||
12 | unsigned int rx_pcm_chs[MAX_STREAMS][SND_DICE_RATE_MODE_COUNT]; | ||
13 | }; | ||
14 | |||
15 | static const struct dice_mytek_spec stereo_192_dsd_dac = { | ||
16 | /* AES, TOSLINK, SPDIF, ADAT inputs on device */ | ||
17 | .tx_pcm_chs = {{8, 8, 8}, {0, 0, 0} }, | ||
18 | /* PCM 44.1-192, native DSD64/DSD128 to device */ | ||
19 | .rx_pcm_chs = {{4, 4, 4}, {0, 0, 0} } | ||
20 | }; | ||
21 | |||
22 | /* | ||
23 | * Mytek has a few other firewire-capable devices, though newer models appear | ||
24 | * to lack the port more often than not. As I don't have access to any of them | ||
25 | * they are missing here. An example is the Mytek 8x192 ADDA, which is DICE. | ||
26 | */ | ||
27 | |||
28 | int snd_dice_detect_mytek_formats(struct snd_dice *dice) | ||
29 | { | ||
30 | int i; | ||
31 | const struct dice_mytek_spec *dev; | ||
32 | |||
33 | dev = &stereo_192_dsd_dac; | ||
34 | |||
35 | memcpy(dice->tx_pcm_chs, dev->tx_pcm_chs, | ||
36 | MAX_STREAMS * SND_DICE_RATE_MODE_COUNT * sizeof(unsigned int)); | ||
37 | memcpy(dice->rx_pcm_chs, dev->rx_pcm_chs, | ||
38 | MAX_STREAMS * SND_DICE_RATE_MODE_COUNT * sizeof(unsigned int)); | ||
39 | |||
40 | for (i = 0; i < MAX_STREAMS; ++i) { | ||
41 | dice->tx_midi_ports[i] = 0; | ||
42 | dice->rx_midi_ports[i] = 0; | ||
43 | } | ||
44 | |||
45 | return 0; | ||
46 | } | ||
diff --git a/sound/firewire/dice/dice-pcm.c b/sound/firewire/dice/dice-pcm.c index 7cb9e9713ac3..80351b29fe0d 100644 --- a/sound/firewire/dice/dice-pcm.c +++ b/sound/firewire/dice/dice-pcm.c | |||
@@ -9,43 +9,115 @@ | |||
9 | 9 | ||
10 | #include "dice.h" | 10 | #include "dice.h" |
11 | 11 | ||
12 | static int dice_rate_constraint(struct snd_pcm_hw_params *params, | ||
13 | struct snd_pcm_hw_rule *rule) | ||
14 | { | ||
15 | struct snd_pcm_substream *substream = rule->private; | ||
16 | struct snd_dice *dice = substream->private_data; | ||
17 | unsigned int index = substream->pcm->device; | ||
18 | |||
19 | const struct snd_interval *c = | ||
20 | hw_param_interval_c(params, SNDRV_PCM_HW_PARAM_CHANNELS); | ||
21 | struct snd_interval *r = | ||
22 | hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE); | ||
23 | struct snd_interval rates = { | ||
24 | .min = UINT_MAX, .max = 0, .integer = 1 | ||
25 | }; | ||
26 | unsigned int *pcm_channels; | ||
27 | enum snd_dice_rate_mode mode; | ||
28 | unsigned int i, rate; | ||
29 | |||
30 | if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) | ||
31 | pcm_channels = dice->tx_pcm_chs[index]; | ||
32 | else | ||
33 | pcm_channels = dice->rx_pcm_chs[index]; | ||
34 | |||
35 | for (i = 0; i < ARRAY_SIZE(snd_dice_rates); ++i) { | ||
36 | rate = snd_dice_rates[i]; | ||
37 | if (snd_dice_stream_get_rate_mode(dice, rate, &mode) < 0) | ||
38 | continue; | ||
39 | |||
40 | if (!snd_interval_test(c, pcm_channels[mode])) | ||
41 | continue; | ||
42 | |||
43 | rates.min = min(rates.min, rate); | ||
44 | rates.max = max(rates.max, rate); | ||
45 | } | ||
46 | |||
47 | return snd_interval_refine(r, &rates); | ||
48 | } | ||
49 | |||
50 | static int dice_channels_constraint(struct snd_pcm_hw_params *params, | ||
51 | struct snd_pcm_hw_rule *rule) | ||
52 | { | ||
53 | struct snd_pcm_substream *substream = rule->private; | ||
54 | struct snd_dice *dice = substream->private_data; | ||
55 | unsigned int index = substream->pcm->device; | ||
56 | |||
57 | const struct snd_interval *r = | ||
58 | hw_param_interval_c(params, SNDRV_PCM_HW_PARAM_RATE); | ||
59 | struct snd_interval *c = | ||
60 | hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS); | ||
61 | struct snd_interval channels = { | ||
62 | .min = UINT_MAX, .max = 0, .integer = 1 | ||
63 | }; | ||
64 | unsigned int *pcm_channels; | ||
65 | enum snd_dice_rate_mode mode; | ||
66 | unsigned int i, rate; | ||
67 | |||
68 | if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) | ||
69 | pcm_channels = dice->tx_pcm_chs[index]; | ||
70 | else | ||
71 | pcm_channels = dice->rx_pcm_chs[index]; | ||
72 | |||
73 | for (i = 0; i < ARRAY_SIZE(snd_dice_rates); ++i) { | ||
74 | rate = snd_dice_rates[i]; | ||
75 | if (snd_dice_stream_get_rate_mode(dice, rate, &mode) < 0) | ||
76 | continue; | ||
77 | |||
78 | if (!snd_interval_test(r, rate)) | ||
79 | continue; | ||
80 | |||
81 | channels.min = min(channels.min, pcm_channels[mode]); | ||
82 | channels.max = max(channels.max, pcm_channels[mode]); | ||
83 | } | ||
84 | |||
85 | return snd_interval_refine(c, &channels); | ||
86 | } | ||
87 | |||
12 | static int limit_channels_and_rates(struct snd_dice *dice, | 88 | static int limit_channels_and_rates(struct snd_dice *dice, |
13 | struct snd_pcm_runtime *runtime, | 89 | struct snd_pcm_runtime *runtime, |
14 | enum amdtp_stream_direction dir, | 90 | enum amdtp_stream_direction dir, |
15 | unsigned int index, unsigned int size) | 91 | unsigned int index) |
16 | { | 92 | { |
17 | struct snd_pcm_hardware *hw = &runtime->hw; | 93 | struct snd_pcm_hardware *hw = &runtime->hw; |
18 | struct amdtp_stream *stream; | 94 | unsigned int *pcm_channels; |
19 | unsigned int rate; | 95 | unsigned int i; |
20 | __be32 reg; | 96 | |
21 | int err; | 97 | if (dir == AMDTP_IN_STREAM) |
22 | 98 | pcm_channels = dice->tx_pcm_chs[index]; | |
23 | /* | 99 | else |
24 | * Retrieve current Multi Bit Linear Audio data channel and limit to | 100 | pcm_channels = dice->rx_pcm_chs[index]; |
25 | * it. | 101 | |
26 | */ | 102 | hw->channels_min = UINT_MAX; |
27 | if (dir == AMDTP_IN_STREAM) { | 103 | hw->channels_max = 0; |
28 | stream = &dice->tx_stream[index]; | 104 | |
29 | err = snd_dice_transaction_read_tx(dice, | 105 | for (i = 0; i < ARRAY_SIZE(snd_dice_rates); ++i) { |
30 | size * index + TX_NUMBER_AUDIO, | 106 | enum snd_dice_rate_mode mode; |
31 | ®, sizeof(reg)); | 107 | unsigned int rate, channels; |
32 | } else { | 108 | |
33 | stream = &dice->rx_stream[index]; | 109 | rate = snd_dice_rates[i]; |
34 | err = snd_dice_transaction_read_rx(dice, | 110 | if (snd_dice_stream_get_rate_mode(dice, rate, &mode) < 0) |
35 | size * index + RX_NUMBER_AUDIO, | 111 | continue; |
36 | ®, sizeof(reg)); | 112 | hw->rates |= snd_pcm_rate_to_rate_bit(rate); |
113 | |||
114 | channels = pcm_channels[mode]; | ||
115 | if (channels == 0) | ||
116 | continue; | ||
117 | hw->channels_min = min(hw->channels_min, channels); | ||
118 | hw->channels_max = max(hw->channels_max, channels); | ||
37 | } | 119 | } |
38 | if (err < 0) | ||
39 | return err; | ||
40 | 120 | ||
41 | hw->channels_min = hw->channels_max = be32_to_cpu(reg); | ||
42 | |||
43 | /* Retrieve current sampling transfer frequency and limit to it. */ | ||
44 | err = snd_dice_transaction_get_rate(dice, &rate); | ||
45 | if (err < 0) | ||
46 | return err; | ||
47 | |||
48 | hw->rates = snd_pcm_rate_to_rate_bit(rate); | ||
49 | snd_pcm_limit_hw_rates(runtime); | 121 | snd_pcm_limit_hw_rates(runtime); |
50 | 122 | ||
51 | return 0; | 123 | return 0; |
@@ -56,36 +128,34 @@ static int init_hw_info(struct snd_dice *dice, | |||
56 | { | 128 | { |
57 | struct snd_pcm_runtime *runtime = substream->runtime; | 129 | struct snd_pcm_runtime *runtime = substream->runtime; |
58 | struct snd_pcm_hardware *hw = &runtime->hw; | 130 | struct snd_pcm_hardware *hw = &runtime->hw; |
131 | unsigned int index = substream->pcm->device; | ||
59 | enum amdtp_stream_direction dir; | 132 | enum amdtp_stream_direction dir; |
60 | struct amdtp_stream *stream; | 133 | struct amdtp_stream *stream; |
61 | __be32 reg[2]; | ||
62 | unsigned int count, size; | ||
63 | int err; | 134 | int err; |
64 | 135 | ||
65 | if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) { | 136 | if (substream->stream == SNDRV_PCM_STREAM_CAPTURE) { |
66 | hw->formats = AM824_IN_PCM_FORMAT_BITS; | 137 | hw->formats = AM824_IN_PCM_FORMAT_BITS; |
67 | dir = AMDTP_IN_STREAM; | 138 | dir = AMDTP_IN_STREAM; |
68 | stream = &dice->tx_stream[substream->pcm->device]; | 139 | stream = &dice->tx_stream[index]; |
69 | err = snd_dice_transaction_read_tx(dice, TX_NUMBER, reg, | ||
70 | sizeof(reg)); | ||
71 | } else { | 140 | } else { |
72 | hw->formats = AM824_OUT_PCM_FORMAT_BITS; | 141 | hw->formats = AM824_OUT_PCM_FORMAT_BITS; |
73 | dir = AMDTP_OUT_STREAM; | 142 | dir = AMDTP_OUT_STREAM; |
74 | stream = &dice->rx_stream[substream->pcm->device]; | 143 | stream = &dice->rx_stream[index]; |
75 | err = snd_dice_transaction_read_rx(dice, RX_NUMBER, reg, | ||
76 | sizeof(reg)); | ||
77 | } | 144 | } |
78 | 145 | ||
146 | err = limit_channels_and_rates(dice, substream->runtime, dir, | ||
147 | index); | ||
79 | if (err < 0) | 148 | if (err < 0) |
80 | return err; | 149 | return err; |
81 | 150 | ||
82 | count = min_t(unsigned int, be32_to_cpu(reg[0]), MAX_STREAMS); | 151 | err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, |
83 | if (substream->pcm->device >= count) | 152 | dice_rate_constraint, substream, |
84 | return -ENXIO; | 153 | SNDRV_PCM_HW_PARAM_CHANNELS, -1); |
85 | 154 | if (err < 0) | |
86 | size = be32_to_cpu(reg[1]) * 4; | 155 | return err; |
87 | err = limit_channels_and_rates(dice, substream->runtime, dir, | 156 | err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, |
88 | substream->pcm->device, size); | 157 | dice_channels_constraint, substream, |
158 | SNDRV_PCM_HW_PARAM_RATE, -1); | ||
89 | if (err < 0) | 159 | if (err < 0) |
90 | return err; | 160 | return err; |
91 | 161 | ||
@@ -95,6 +165,8 @@ static int init_hw_info(struct snd_dice *dice, | |||
95 | static int pcm_open(struct snd_pcm_substream *substream) | 165 | static int pcm_open(struct snd_pcm_substream *substream) |
96 | { | 166 | { |
97 | struct snd_dice *dice = substream->private_data; | 167 | struct snd_dice *dice = substream->private_data; |
168 | unsigned int source; | ||
169 | bool internal; | ||
98 | int err; | 170 | int err; |
99 | 171 | ||
100 | err = snd_dice_stream_lock_try(dice); | 172 | err = snd_dice_stream_lock_try(dice); |
@@ -105,6 +177,43 @@ static int pcm_open(struct snd_pcm_substream *substream) | |||
105 | if (err < 0) | 177 | if (err < 0) |
106 | goto err_locked; | 178 | goto err_locked; |
107 | 179 | ||
180 | err = snd_dice_transaction_get_clock_source(dice, &source); | ||
181 | if (err < 0) | ||
182 | goto err_locked; | ||
183 | switch (source) { | ||
184 | case CLOCK_SOURCE_AES1: | ||
185 | case CLOCK_SOURCE_AES2: | ||
186 | case CLOCK_SOURCE_AES3: | ||
187 | case CLOCK_SOURCE_AES4: | ||
188 | case CLOCK_SOURCE_AES_ANY: | ||
189 | case CLOCK_SOURCE_ADAT: | ||
190 | case CLOCK_SOURCE_TDIF: | ||
191 | case CLOCK_SOURCE_WC: | ||
192 | internal = false; | ||
193 | break; | ||
194 | default: | ||
195 | internal = true; | ||
196 | break; | ||
197 | } | ||
198 | |||
199 | /* | ||
200 | * When source of clock is not internal or any PCM streams are running, | ||
201 | * available sampling rate is limited at current sampling rate. | ||
202 | */ | ||
203 | if (!internal || | ||
204 | amdtp_stream_pcm_running(&dice->tx_stream[0]) || | ||
205 | amdtp_stream_pcm_running(&dice->tx_stream[1]) || | ||
206 | amdtp_stream_pcm_running(&dice->rx_stream[0]) || | ||
207 | amdtp_stream_pcm_running(&dice->rx_stream[1])) { | ||
208 | unsigned int rate; | ||
209 | |||
210 | err = snd_dice_transaction_get_rate(dice, &rate); | ||
211 | if (err < 0) | ||
212 | goto err_locked; | ||
213 | substream->runtime->hw.rate_min = rate; | ||
214 | substream->runtime->hw.rate_max = rate; | ||
215 | } | ||
216 | |||
108 | snd_pcm_set_sync(substream); | 217 | snd_pcm_set_sync(substream); |
109 | end: | 218 | end: |
110 | return err; | 219 | return err; |
@@ -318,37 +427,19 @@ int snd_dice_create_pcm(struct snd_dice *dice) | |||
318 | .page = snd_pcm_lib_get_vmalloc_page, | 427 | .page = snd_pcm_lib_get_vmalloc_page, |
319 | .mmap = snd_pcm_lib_mmap_vmalloc, | 428 | .mmap = snd_pcm_lib_mmap_vmalloc, |
320 | }; | 429 | }; |
321 | __be32 reg; | ||
322 | struct snd_pcm *pcm; | 430 | struct snd_pcm *pcm; |
323 | unsigned int i, max_capture, max_playback, capture, playback; | 431 | unsigned int capture, playback; |
432 | int i, j; | ||
324 | int err; | 433 | int err; |
325 | 434 | ||
326 | /* Check whether PCM substreams are required. */ | ||
327 | if (dice->force_two_pcms) { | ||
328 | max_capture = max_playback = 2; | ||
329 | } else { | ||
330 | max_capture = max_playback = 0; | ||
331 | err = snd_dice_transaction_read_tx(dice, TX_NUMBER, ®, | ||
332 | sizeof(reg)); | ||
333 | if (err < 0) | ||
334 | return err; | ||
335 | max_capture = min_t(unsigned int, be32_to_cpu(reg), MAX_STREAMS); | ||
336 | |||
337 | err = snd_dice_transaction_read_rx(dice, RX_NUMBER, ®, | ||
338 | sizeof(reg)); | ||
339 | if (err < 0) | ||
340 | return err; | ||
341 | max_playback = min_t(unsigned int, be32_to_cpu(reg), MAX_STREAMS); | ||
342 | } | ||
343 | |||
344 | for (i = 0; i < MAX_STREAMS; i++) { | 435 | for (i = 0; i < MAX_STREAMS; i++) { |
345 | capture = playback = 0; | 436 | capture = playback = 0; |
346 | if (i < max_capture) | 437 | for (j = 0; j < SND_DICE_RATE_MODE_COUNT; ++j) { |
347 | capture = 1; | 438 | if (dice->tx_pcm_chs[i][j] > 0) |
348 | if (i < max_playback) | 439 | capture = 1; |
349 | playback = 1; | 440 | if (dice->rx_pcm_chs[i][j] > 0) |
350 | if (capture == 0 && playback == 0) | 441 | playback = 1; |
351 | break; | 442 | } |
352 | 443 | ||
353 | err = snd_pcm_new(dice->card, "DICE", i, playback, capture, | 444 | err = snd_pcm_new(dice->card, "DICE", i, playback, capture, |
354 | &pcm); | 445 | &pcm); |
diff --git a/sound/firewire/dice/dice-proc.c b/sound/firewire/dice/dice-proc.c index f5c1d1bced59..bb870fc73f99 100644 --- a/sound/firewire/dice/dice-proc.c +++ b/sound/firewire/dice/dice-proc.c | |||
@@ -148,12 +148,12 @@ static void dice_proc_read(struct snd_info_entry *entry, | |||
148 | >> CLOCK_RATE_SHIFT)); | 148 | >> CLOCK_RATE_SHIFT)); |
149 | snd_iprintf(buffer, " ext status: %08x\n", buf.global.extended_status); | 149 | snd_iprintf(buffer, " ext status: %08x\n", buf.global.extended_status); |
150 | snd_iprintf(buffer, " sample rate: %u\n", buf.global.sample_rate); | 150 | snd_iprintf(buffer, " sample rate: %u\n", buf.global.sample_rate); |
151 | snd_iprintf(buffer, " version: %u.%u.%u.%u\n", | ||
152 | (buf.global.version >> 24) & 0xff, | ||
153 | (buf.global.version >> 16) & 0xff, | ||
154 | (buf.global.version >> 8) & 0xff, | ||
155 | (buf.global.version >> 0) & 0xff); | ||
156 | if (quadlets >= 90) { | 151 | if (quadlets >= 90) { |
152 | snd_iprintf(buffer, " version: %u.%u.%u.%u\n", | ||
153 | (buf.global.version >> 24) & 0xff, | ||
154 | (buf.global.version >> 16) & 0xff, | ||
155 | (buf.global.version >> 8) & 0xff, | ||
156 | (buf.global.version >> 0) & 0xff); | ||
157 | snd_iprintf(buffer, " clock caps:"); | 157 | snd_iprintf(buffer, " clock caps:"); |
158 | for (i = 0; i <= 6; ++i) | 158 | for (i = 0; i <= 6; ++i) |
159 | if (buf.global.clock_caps & (1 << i)) | 159 | if (buf.global.clock_caps & (1 << i)) |
@@ -243,10 +243,74 @@ static void dice_proc_read(struct snd_info_entry *entry, | |||
243 | } | 243 | } |
244 | } | 244 | } |
245 | 245 | ||
246 | void snd_dice_create_proc(struct snd_dice *dice) | 246 | static void dice_proc_read_formation(struct snd_info_entry *entry, |
247 | struct snd_info_buffer *buffer) | ||
248 | { | ||
249 | static const char *const rate_labels[] = { | ||
250 | [SND_DICE_RATE_MODE_LOW] = "low", | ||
251 | [SND_DICE_RATE_MODE_MIDDLE] = "middle", | ||
252 | [SND_DICE_RATE_MODE_HIGH] = "high", | ||
253 | }; | ||
254 | struct snd_dice *dice = entry->private_data; | ||
255 | int i, j; | ||
256 | |||
257 | snd_iprintf(buffer, "Output stream from unit:\n"); | ||
258 | for (i = 0; i < SND_DICE_RATE_MODE_COUNT; ++i) | ||
259 | snd_iprintf(buffer, "\t%s", rate_labels[i]); | ||
260 | snd_iprintf(buffer, "\tMIDI\n"); | ||
261 | for (i = 0; i < MAX_STREAMS; ++i) { | ||
262 | snd_iprintf(buffer, "Tx %u:", i); | ||
263 | for (j = 0; j < SND_DICE_RATE_MODE_COUNT; ++j) | ||
264 | snd_iprintf(buffer, "\t%u", dice->tx_pcm_chs[i][j]); | ||
265 | snd_iprintf(buffer, "\t%u\n", dice->tx_midi_ports[i]); | ||
266 | } | ||
267 | |||
268 | snd_iprintf(buffer, "Input stream to unit:\n"); | ||
269 | for (i = 0; i < SND_DICE_RATE_MODE_COUNT; ++i) | ||
270 | snd_iprintf(buffer, "\t%s", rate_labels[i]); | ||
271 | snd_iprintf(buffer, "\n"); | ||
272 | for (i = 0; i < MAX_STREAMS; ++i) { | ||
273 | snd_iprintf(buffer, "Rx %u:", i); | ||
274 | for (j = 0; j < SND_DICE_RATE_MODE_COUNT; ++j) | ||
275 | snd_iprintf(buffer, "\t%u", dice->rx_pcm_chs[i][j]); | ||
276 | snd_iprintf(buffer, "\t%u\n", dice->rx_midi_ports[i]); | ||
277 | } | ||
278 | } | ||
279 | |||
280 | static void add_node(struct snd_dice *dice, struct snd_info_entry *root, | ||
281 | const char *name, | ||
282 | void (*op)(struct snd_info_entry *entry, | ||
283 | struct snd_info_buffer *buffer)) | ||
247 | { | 284 | { |
248 | struct snd_info_entry *entry; | 285 | struct snd_info_entry *entry; |
249 | 286 | ||
250 | if (!snd_card_proc_new(dice->card, "dice", &entry)) | 287 | entry = snd_info_create_card_entry(dice->card, name, root); |
251 | snd_info_set_text_ops(entry, dice, dice_proc_read); | 288 | if (!entry) |
289 | return; | ||
290 | |||
291 | snd_info_set_text_ops(entry, dice, op); | ||
292 | if (snd_info_register(entry) < 0) | ||
293 | snd_info_free_entry(entry); | ||
294 | } | ||
295 | |||
296 | void snd_dice_create_proc(struct snd_dice *dice) | ||
297 | { | ||
298 | struct snd_info_entry *root; | ||
299 | |||
300 | /* | ||
301 | * All nodes are automatically removed at snd_card_disconnect(), | ||
302 | * by following to link list. | ||
303 | */ | ||
304 | root = snd_info_create_card_entry(dice->card, "firewire", | ||
305 | dice->card->proc_root); | ||
306 | if (!root) | ||
307 | return; | ||
308 | root->mode = S_IFDIR | 0555; | ||
309 | if (snd_info_register(root) < 0) { | ||
310 | snd_info_free_entry(root); | ||
311 | return; | ||
312 | } | ||
313 | |||
314 | add_node(dice, root, "dice", dice_proc_read); | ||
315 | add_node(dice, root, "formation", dice_proc_read_formation); | ||
252 | } | 316 | } |
diff --git a/sound/firewire/dice/dice-stream.c b/sound/firewire/dice/dice-stream.c index 928a255bfc35..c3c892c5c7ff 100644 --- a/sound/firewire/dice/dice-stream.c +++ b/sound/firewire/dice/dice-stream.c | |||
@@ -30,13 +30,43 @@ const unsigned int snd_dice_rates[SND_DICE_RATES_COUNT] = { | |||
30 | [6] = 192000, | 30 | [6] = 192000, |
31 | }; | 31 | }; |
32 | 32 | ||
33 | int snd_dice_stream_get_rate_mode(struct snd_dice *dice, unsigned int rate, | ||
34 | enum snd_dice_rate_mode *mode) | ||
35 | { | ||
36 | /* Corresponding to each entry in snd_dice_rates. */ | ||
37 | static const enum snd_dice_rate_mode modes[] = { | ||
38 | [0] = SND_DICE_RATE_MODE_LOW, | ||
39 | [1] = SND_DICE_RATE_MODE_LOW, | ||
40 | [2] = SND_DICE_RATE_MODE_LOW, | ||
41 | [3] = SND_DICE_RATE_MODE_MIDDLE, | ||
42 | [4] = SND_DICE_RATE_MODE_MIDDLE, | ||
43 | [5] = SND_DICE_RATE_MODE_HIGH, | ||
44 | [6] = SND_DICE_RATE_MODE_HIGH, | ||
45 | }; | ||
46 | int i; | ||
47 | |||
48 | for (i = 0; i < ARRAY_SIZE(snd_dice_rates); i++) { | ||
49 | if (!(dice->clock_caps & BIT(i))) | ||
50 | continue; | ||
51 | if (snd_dice_rates[i] != rate) | ||
52 | continue; | ||
53 | |||
54 | *mode = modes[i]; | ||
55 | return 0; | ||
56 | } | ||
57 | |||
58 | return -EINVAL; | ||
59 | } | ||
60 | |||
33 | /* | 61 | /* |
34 | * This operation has an effect to synchronize GLOBAL_STATUS/GLOBAL_SAMPLE_RATE | 62 | * This operation has an effect to synchronize GLOBAL_STATUS/GLOBAL_SAMPLE_RATE |
35 | * to GLOBAL_STATUS. Especially, just after powering on, these are different. | 63 | * to GLOBAL_STATUS. Especially, just after powering on, these are different. |
36 | */ | 64 | */ |
37 | static int ensure_phase_lock(struct snd_dice *dice) | 65 | static int ensure_phase_lock(struct snd_dice *dice, unsigned int rate) |
38 | { | 66 | { |
39 | __be32 reg, nominal; | 67 | __be32 reg, nominal; |
68 | u32 data; | ||
69 | int i; | ||
40 | int err; | 70 | int err; |
41 | 71 | ||
42 | err = snd_dice_transaction_read_global(dice, GLOBAL_CLOCK_SELECT, | 72 | err = snd_dice_transaction_read_global(dice, GLOBAL_CLOCK_SELECT, |
@@ -44,9 +74,21 @@ static int ensure_phase_lock(struct snd_dice *dice) | |||
44 | if (err < 0) | 74 | if (err < 0) |
45 | return err; | 75 | return err; |
46 | 76 | ||
77 | data = be32_to_cpu(reg); | ||
78 | |||
79 | data &= ~CLOCK_RATE_MASK; | ||
80 | for (i = 0; i < ARRAY_SIZE(snd_dice_rates); ++i) { | ||
81 | if (snd_dice_rates[i] == rate) | ||
82 | break; | ||
83 | } | ||
84 | if (i == ARRAY_SIZE(snd_dice_rates)) | ||
85 | return -EINVAL; | ||
86 | data |= i << CLOCK_RATE_SHIFT; | ||
87 | |||
47 | if (completion_done(&dice->clock_accepted)) | 88 | if (completion_done(&dice->clock_accepted)) |
48 | reinit_completion(&dice->clock_accepted); | 89 | reinit_completion(&dice->clock_accepted); |
49 | 90 | ||
91 | reg = cpu_to_be32(data); | ||
50 | err = snd_dice_transaction_write_global(dice, GLOBAL_CLOCK_SELECT, | 92 | err = snd_dice_transaction_write_global(dice, GLOBAL_CLOCK_SELECT, |
51 | ®, sizeof(reg)); | 93 | ®, sizeof(reg)); |
52 | if (err < 0) | 94 | if (err < 0) |
@@ -192,6 +234,7 @@ static int start_streams(struct snd_dice *dice, enum amdtp_stream_direction dir, | |||
192 | unsigned int rate, struct reg_params *params) | 234 | unsigned int rate, struct reg_params *params) |
193 | { | 235 | { |
194 | __be32 reg[2]; | 236 | __be32 reg[2]; |
237 | enum snd_dice_rate_mode mode; | ||
195 | unsigned int i, pcm_chs, midi_ports; | 238 | unsigned int i, pcm_chs, midi_ports; |
196 | struct amdtp_stream *streams; | 239 | struct amdtp_stream *streams; |
197 | struct fw_iso_resources *resources; | 240 | struct fw_iso_resources *resources; |
@@ -206,12 +249,23 @@ static int start_streams(struct snd_dice *dice, enum amdtp_stream_direction dir, | |||
206 | resources = dice->rx_resources; | 249 | resources = dice->rx_resources; |
207 | } | 250 | } |
208 | 251 | ||
252 | err = snd_dice_stream_get_rate_mode(dice, rate, &mode); | ||
253 | if (err < 0) | ||
254 | return err; | ||
255 | |||
209 | for (i = 0; i < params->count; i++) { | 256 | for (i = 0; i < params->count; i++) { |
257 | unsigned int pcm_cache; | ||
258 | unsigned int midi_cache; | ||
259 | |||
210 | if (dir == AMDTP_IN_STREAM) { | 260 | if (dir == AMDTP_IN_STREAM) { |
261 | pcm_cache = dice->tx_pcm_chs[i][mode]; | ||
262 | midi_cache = dice->tx_midi_ports[i]; | ||
211 | err = snd_dice_transaction_read_tx(dice, | 263 | err = snd_dice_transaction_read_tx(dice, |
212 | params->size * i + TX_NUMBER_AUDIO, | 264 | params->size * i + TX_NUMBER_AUDIO, |
213 | reg, sizeof(reg)); | 265 | reg, sizeof(reg)); |
214 | } else { | 266 | } else { |
267 | pcm_cache = dice->rx_pcm_chs[i][mode]; | ||
268 | midi_cache = dice->rx_midi_ports[i]; | ||
215 | err = snd_dice_transaction_read_rx(dice, | 269 | err = snd_dice_transaction_read_rx(dice, |
216 | params->size * i + RX_NUMBER_AUDIO, | 270 | params->size * i + RX_NUMBER_AUDIO, |
217 | reg, sizeof(reg)); | 271 | reg, sizeof(reg)); |
@@ -221,6 +275,14 @@ static int start_streams(struct snd_dice *dice, enum amdtp_stream_direction dir, | |||
221 | pcm_chs = be32_to_cpu(reg[0]); | 275 | pcm_chs = be32_to_cpu(reg[0]); |
222 | midi_ports = be32_to_cpu(reg[1]); | 276 | midi_ports = be32_to_cpu(reg[1]); |
223 | 277 | ||
278 | /* These are important for developer of this driver. */ | ||
279 | if (pcm_chs != pcm_cache || midi_ports != midi_cache) { | ||
280 | dev_info(&dice->unit->device, | ||
281 | "cache mismatch: pcm: %u:%u, midi: %u:%u\n", | ||
282 | pcm_chs, pcm_cache, midi_ports, midi_cache); | ||
283 | return -EPROTO; | ||
284 | } | ||
285 | |||
224 | err = keep_resources(dice, dir, i, rate, pcm_chs, midi_ports); | 286 | err = keep_resources(dice, dir, i, rate, pcm_chs, midi_ports); |
225 | if (err < 0) | 287 | if (err < 0) |
226 | return err; | 288 | return err; |
@@ -256,6 +318,68 @@ static int start_streams(struct snd_dice *dice, enum amdtp_stream_direction dir, | |||
256 | return err; | 318 | return err; |
257 | } | 319 | } |
258 | 320 | ||
321 | static int start_duplex_streams(struct snd_dice *dice, unsigned int rate) | ||
322 | { | ||
323 | struct reg_params tx_params, rx_params; | ||
324 | int i; | ||
325 | int err; | ||
326 | |||
327 | err = get_register_params(dice, &tx_params, &rx_params); | ||
328 | if (err < 0) | ||
329 | return err; | ||
330 | |||
331 | /* Stop transmission. */ | ||
332 | stop_streams(dice, AMDTP_IN_STREAM, &tx_params); | ||
333 | stop_streams(dice, AMDTP_OUT_STREAM, &rx_params); | ||
334 | snd_dice_transaction_clear_enable(dice); | ||
335 | release_resources(dice); | ||
336 | |||
337 | err = ensure_phase_lock(dice, rate); | ||
338 | if (err < 0) { | ||
339 | dev_err(&dice->unit->device, "fail to ensure phase lock\n"); | ||
340 | return err; | ||
341 | } | ||
342 | |||
343 | /* Likely to have changed stream formats. */ | ||
344 | err = get_register_params(dice, &tx_params, &rx_params); | ||
345 | if (err < 0) | ||
346 | return err; | ||
347 | |||
348 | /* Start both streams. */ | ||
349 | err = start_streams(dice, AMDTP_IN_STREAM, rate, &tx_params); | ||
350 | if (err < 0) | ||
351 | goto error; | ||
352 | err = start_streams(dice, AMDTP_OUT_STREAM, rate, &rx_params); | ||
353 | if (err < 0) | ||
354 | goto error; | ||
355 | |||
356 | err = snd_dice_transaction_set_enable(dice); | ||
357 | if (err < 0) { | ||
358 | dev_err(&dice->unit->device, "fail to enable interface\n"); | ||
359 | goto error; | ||
360 | } | ||
361 | |||
362 | for (i = 0; i < MAX_STREAMS; i++) { | ||
363 | if ((i < tx_params.count && | ||
364 | !amdtp_stream_wait_callback(&dice->tx_stream[i], | ||
365 | CALLBACK_TIMEOUT)) || | ||
366 | (i < rx_params.count && | ||
367 | !amdtp_stream_wait_callback(&dice->rx_stream[i], | ||
368 | CALLBACK_TIMEOUT))) { | ||
369 | err = -ETIMEDOUT; | ||
370 | goto error; | ||
371 | } | ||
372 | } | ||
373 | |||
374 | return 0; | ||
375 | error: | ||
376 | stop_streams(dice, AMDTP_IN_STREAM, &tx_params); | ||
377 | stop_streams(dice, AMDTP_OUT_STREAM, &rx_params); | ||
378 | snd_dice_transaction_clear_enable(dice); | ||
379 | release_resources(dice); | ||
380 | return err; | ||
381 | } | ||
382 | |||
259 | /* | 383 | /* |
260 | * MEMO: After this function, there're two states of streams: | 384 | * MEMO: After this function, there're two states of streams: |
261 | * - None streams are running. | 385 | * - None streams are running. |
@@ -265,17 +389,13 @@ int snd_dice_stream_start_duplex(struct snd_dice *dice, unsigned int rate) | |||
265 | { | 389 | { |
266 | unsigned int curr_rate; | 390 | unsigned int curr_rate; |
267 | unsigned int i; | 391 | unsigned int i; |
268 | struct reg_params tx_params, rx_params; | 392 | enum snd_dice_rate_mode mode; |
269 | bool need_to_start; | ||
270 | int err; | 393 | int err; |
271 | 394 | ||
272 | if (dice->substreams_counter == 0) | 395 | if (dice->substreams_counter == 0) |
273 | return -EIO; | 396 | return -EIO; |
274 | 397 | ||
275 | err = get_register_params(dice, &tx_params, &rx_params); | 398 | /* Check sampling transmission frequency. */ |
276 | if (err < 0) | ||
277 | return err; | ||
278 | |||
279 | err = snd_dice_transaction_get_rate(dice, &curr_rate); | 399 | err = snd_dice_transaction_get_rate(dice, &curr_rate); |
280 | if (err < 0) { | 400 | if (err < 0) { |
281 | dev_err(&dice->unit->device, | 401 | dev_err(&dice->unit->device, |
@@ -285,72 +405,36 @@ int snd_dice_stream_start_duplex(struct snd_dice *dice, unsigned int rate) | |||
285 | if (rate == 0) | 405 | if (rate == 0) |
286 | rate = curr_rate; | 406 | rate = curr_rate; |
287 | if (rate != curr_rate) | 407 | if (rate != curr_rate) |
288 | return -EINVAL; | 408 | goto restart; |
289 | 409 | ||
290 | /* Judge to need to restart streams. */ | 410 | /* Check error of packet streaming. */ |
291 | for (i = 0; i < MAX_STREAMS; i++) { | 411 | for (i = 0; i < MAX_STREAMS; ++i) { |
292 | if (i < tx_params.count) { | 412 | if (amdtp_streaming_error(&dice->tx_stream[i])) |
293 | if (amdtp_streaming_error(&dice->tx_stream[i]) || | 413 | break; |
294 | !amdtp_stream_running(&dice->tx_stream[i])) | 414 | if (amdtp_streaming_error(&dice->rx_stream[i])) |
295 | break; | 415 | break; |
296 | } | ||
297 | if (i < rx_params.count) { | ||
298 | if (amdtp_streaming_error(&dice->rx_stream[i]) || | ||
299 | !amdtp_stream_running(&dice->rx_stream[i])) | ||
300 | break; | ||
301 | } | ||
302 | } | 416 | } |
303 | need_to_start = (i < MAX_STREAMS); | 417 | if (i < MAX_STREAMS) |
304 | 418 | goto restart; | |
305 | if (need_to_start) { | ||
306 | /* Stop transmission. */ | ||
307 | snd_dice_transaction_clear_enable(dice); | ||
308 | stop_streams(dice, AMDTP_IN_STREAM, &tx_params); | ||
309 | stop_streams(dice, AMDTP_OUT_STREAM, &rx_params); | ||
310 | release_resources(dice); | ||
311 | |||
312 | err = ensure_phase_lock(dice); | ||
313 | if (err < 0) { | ||
314 | dev_err(&dice->unit->device, | ||
315 | "fail to ensure phase lock\n"); | ||
316 | return err; | ||
317 | } | ||
318 | 419 | ||
319 | /* Start both streams. */ | 420 | /* Check required streams are running or not. */ |
320 | err = start_streams(dice, AMDTP_IN_STREAM, rate, &tx_params); | 421 | err = snd_dice_stream_get_rate_mode(dice, rate, &mode); |
321 | if (err < 0) | 422 | if (err < 0) |
322 | goto error; | 423 | return err; |
323 | err = start_streams(dice, AMDTP_OUT_STREAM, rate, &rx_params); | 424 | for (i = 0; i < MAX_STREAMS; ++i) { |
324 | if (err < 0) | 425 | if (dice->tx_pcm_chs[i][mode] > 0 && |
325 | goto error; | 426 | !amdtp_stream_running(&dice->tx_stream[i])) |
326 | 427 | break; | |
327 | err = snd_dice_transaction_set_enable(dice); | 428 | if (dice->rx_pcm_chs[i][mode] > 0 && |
328 | if (err < 0) { | 429 | !amdtp_stream_running(&dice->rx_stream[i])) |
329 | dev_err(&dice->unit->device, | 430 | break; |
330 | "fail to enable interface\n"); | ||
331 | goto error; | ||
332 | } | ||
333 | |||
334 | for (i = 0; i < MAX_STREAMS; i++) { | ||
335 | if ((i < tx_params.count && | ||
336 | !amdtp_stream_wait_callback(&dice->tx_stream[i], | ||
337 | CALLBACK_TIMEOUT)) || | ||
338 | (i < rx_params.count && | ||
339 | !amdtp_stream_wait_callback(&dice->rx_stream[i], | ||
340 | CALLBACK_TIMEOUT))) { | ||
341 | err = -ETIMEDOUT; | ||
342 | goto error; | ||
343 | } | ||
344 | } | ||
345 | } | 431 | } |
432 | if (i < MAX_STREAMS) | ||
433 | goto restart; | ||
346 | 434 | ||
347 | return err; | 435 | return 0; |
348 | error: | 436 | restart: |
349 | snd_dice_transaction_clear_enable(dice); | 437 | return start_duplex_streams(dice, rate); |
350 | stop_streams(dice, AMDTP_IN_STREAM, &tx_params); | ||
351 | stop_streams(dice, AMDTP_OUT_STREAM, &rx_params); | ||
352 | release_resources(dice); | ||
353 | return err; | ||
354 | } | 438 | } |
355 | 439 | ||
356 | /* | 440 | /* |
@@ -484,6 +568,69 @@ void snd_dice_stream_update_duplex(struct snd_dice *dice) | |||
484 | } | 568 | } |
485 | } | 569 | } |
486 | 570 | ||
571 | int snd_dice_stream_detect_current_formats(struct snd_dice *dice) | ||
572 | { | ||
573 | unsigned int rate; | ||
574 | enum snd_dice_rate_mode mode; | ||
575 | __be32 reg[2]; | ||
576 | struct reg_params tx_params, rx_params; | ||
577 | int i; | ||
578 | int err; | ||
579 | |||
580 | /* If extended protocol is available, detect detail spec. */ | ||
581 | err = snd_dice_detect_extension_formats(dice); | ||
582 | if (err >= 0) | ||
583 | return err; | ||
584 | |||
585 | /* | ||
586 | * Available stream format is restricted at current mode of sampling | ||
587 | * clock. | ||
588 | */ | ||
589 | err = snd_dice_transaction_get_rate(dice, &rate); | ||
590 | if (err < 0) | ||
591 | return err; | ||
592 | |||
593 | err = snd_dice_stream_get_rate_mode(dice, rate, &mode); | ||
594 | if (err < 0) | ||
595 | return err; | ||
596 | |||
597 | /* | ||
598 | * Just after owning the unit (GLOBAL_OWNER), the unit can return | ||
599 | * invalid stream formats. Selecting clock parameters have an effect | ||
600 | * for the unit to refine it. | ||
601 | */ | ||
602 | err = ensure_phase_lock(dice, rate); | ||
603 | if (err < 0) | ||
604 | return err; | ||
605 | |||
606 | err = get_register_params(dice, &tx_params, &rx_params); | ||
607 | if (err < 0) | ||
608 | return err; | ||
609 | |||
610 | for (i = 0; i < tx_params.count; ++i) { | ||
611 | err = snd_dice_transaction_read_tx(dice, | ||
612 | tx_params.size * i + TX_NUMBER_AUDIO, | ||
613 | reg, sizeof(reg)); | ||
614 | if (err < 0) | ||
615 | return err; | ||
616 | dice->tx_pcm_chs[i][mode] = be32_to_cpu(reg[0]); | ||
617 | dice->tx_midi_ports[i] = max_t(unsigned int, | ||
618 | be32_to_cpu(reg[1]), dice->tx_midi_ports[i]); | ||
619 | } | ||
620 | for (i = 0; i < rx_params.count; ++i) { | ||
621 | err = snd_dice_transaction_read_rx(dice, | ||
622 | rx_params.size * i + RX_NUMBER_AUDIO, | ||
623 | reg, sizeof(reg)); | ||
624 | if (err < 0) | ||
625 | return err; | ||
626 | dice->rx_pcm_chs[i][mode] = be32_to_cpu(reg[0]); | ||
627 | dice->rx_midi_ports[i] = max_t(unsigned int, | ||
628 | be32_to_cpu(reg[1]), dice->rx_midi_ports[i]); | ||
629 | } | ||
630 | |||
631 | return 0; | ||
632 | } | ||
633 | |||
487 | static void dice_lock_changed(struct snd_dice *dice) | 634 | static void dice_lock_changed(struct snd_dice *dice) |
488 | { | 635 | { |
489 | dice->dev_lock_changed = true; | 636 | dice->dev_lock_changed = true; |
diff --git a/sound/firewire/dice/dice-tcelectronic.c b/sound/firewire/dice/dice-tcelectronic.c new file mode 100644 index 000000000000..a8875d24ba2a --- /dev/null +++ b/sound/firewire/dice/dice-tcelectronic.c | |||
@@ -0,0 +1,104 @@ | |||
1 | // SPDX-License-Identifier: GPL-2.0 | ||
2 | /* | ||
3 | * dice-tc_electronic.c - a part of driver for DICE based devices | ||
4 | * | ||
5 | * Copyright (c) 2018 Takashi Sakamoto | ||
6 | */ | ||
7 | |||
8 | #include "dice.h" | ||
9 | |||
10 | struct dice_tc_spec { | ||
11 | unsigned int tx_pcm_chs[MAX_STREAMS][SND_DICE_RATE_MODE_COUNT]; | ||
12 | unsigned int rx_pcm_chs[MAX_STREAMS][SND_DICE_RATE_MODE_COUNT]; | ||
13 | bool has_midi; | ||
14 | }; | ||
15 | |||
16 | static const struct dice_tc_spec desktop_konnekt6 = { | ||
17 | .tx_pcm_chs = {{6, 6, 2}, {0, 0, 0} }, | ||
18 | .rx_pcm_chs = {{6, 6, 4}, {0, 0, 0} }, | ||
19 | .has_midi = false, | ||
20 | }; | ||
21 | |||
22 | static const struct dice_tc_spec impact_twin = { | ||
23 | .tx_pcm_chs = {{14, 10, 6}, {0, 0, 0} }, | ||
24 | .rx_pcm_chs = {{14, 10, 6}, {0, 0, 0} }, | ||
25 | .has_midi = true, | ||
26 | }; | ||
27 | |||
28 | static const struct dice_tc_spec konnekt_8 = { | ||
29 | .tx_pcm_chs = {{4, 4, 3}, {0, 0, 0} }, | ||
30 | .rx_pcm_chs = {{4, 4, 3}, {0, 0, 0} }, | ||
31 | .has_midi = true, | ||
32 | }; | ||
33 | |||
34 | static const struct dice_tc_spec konnekt_24d = { | ||
35 | .tx_pcm_chs = {{16, 16, 6}, {0, 0, 0} }, | ||
36 | .rx_pcm_chs = {{16, 16, 6}, {0, 0, 0} }, | ||
37 | .has_midi = true, | ||
38 | }; | ||
39 | |||
40 | static const struct dice_tc_spec konnekt_live = { | ||
41 | .tx_pcm_chs = {{16, 16, 16}, {0, 0, 0} }, | ||
42 | .rx_pcm_chs = {{16, 16, 16}, {0, 0, 0} }, | ||
43 | .has_midi = true, | ||
44 | }; | ||
45 | |||
46 | static const struct dice_tc_spec studio_konnekt_48 = { | ||
47 | .tx_pcm_chs = {{16, 16, 8}, {16, 16, 7} }, | ||
48 | .rx_pcm_chs = {{16, 16, 8}, {14, 14, 7} }, | ||
49 | .has_midi = true, | ||
50 | }; | ||
51 | |||
52 | static const struct dice_tc_spec digital_konnekt_x32 = { | ||
53 | .tx_pcm_chs = {{16, 16, 4}, {0, 0, 0} }, | ||
54 | .rx_pcm_chs = {{16, 16, 4}, {0, 0, 0} }, | ||
55 | .has_midi = false, | ||
56 | }; | ||
57 | |||
58 | int snd_dice_detect_tcelectronic_formats(struct snd_dice *dice) | ||
59 | { | ||
60 | static const struct { | ||
61 | u32 model_id; | ||
62 | const struct dice_tc_spec *spec; | ||
63 | } *entry, entries[] = { | ||
64 | {0x00000020, &konnekt_24d}, | ||
65 | {0x00000021, &konnekt_8}, | ||
66 | {0x00000022, &studio_konnekt_48}, | ||
67 | {0x00000023, &konnekt_live}, | ||
68 | {0x00000024, &desktop_konnekt6}, | ||
69 | {0x00000027, &impact_twin}, | ||
70 | {0x00000030, &digital_konnekt_x32}, | ||
71 | }; | ||
72 | struct fw_csr_iterator it; | ||
73 | int key, val, model_id; | ||
74 | int i; | ||
75 | |||
76 | model_id = 0; | ||
77 | fw_csr_iterator_init(&it, dice->unit->directory); | ||
78 | while (fw_csr_iterator_next(&it, &key, &val)) { | ||
79 | if (key == CSR_MODEL) { | ||
80 | model_id = val; | ||
81 | break; | ||
82 | } | ||
83 | } | ||
84 | |||
85 | for (i = 0; i < ARRAY_SIZE(entries); ++i) { | ||
86 | entry = entries + i; | ||
87 | if (entry->model_id == model_id) | ||
88 | break; | ||
89 | } | ||
90 | if (i == ARRAY_SIZE(entries)) | ||
91 | return -ENODEV; | ||
92 | |||
93 | memcpy(dice->tx_pcm_chs, entry->spec->tx_pcm_chs, | ||
94 | MAX_STREAMS * SND_DICE_RATE_MODE_COUNT * sizeof(unsigned int)); | ||
95 | memcpy(dice->rx_pcm_chs, entry->spec->rx_pcm_chs, | ||
96 | MAX_STREAMS * SND_DICE_RATE_MODE_COUNT * sizeof(unsigned int)); | ||
97 | |||
98 | if (entry->spec->has_midi) { | ||
99 | dice->tx_midi_ports[0] = 1; | ||
100 | dice->rx_midi_ports[0] = 1; | ||
101 | } | ||
102 | |||
103 | return 0; | ||
104 | } | ||
diff --git a/sound/firewire/dice/dice-transaction.c b/sound/firewire/dice/dice-transaction.c index 0f0350320ae8..b7e138b5abcf 100644 --- a/sound/firewire/dice/dice-transaction.c +++ b/sound/firewire/dice/dice-transaction.c | |||
@@ -265,7 +265,7 @@ int snd_dice_transaction_reinit(struct snd_dice *dice) | |||
265 | static int get_subaddrs(struct snd_dice *dice) | 265 | static int get_subaddrs(struct snd_dice *dice) |
266 | { | 266 | { |
267 | static const int min_values[10] = { | 267 | static const int min_values[10] = { |
268 | 10, 0x64 / 4, | 268 | 10, 0x60 / 4, |
269 | 10, 0x18 / 4, | 269 | 10, 0x18 / 4, |
270 | 10, 0x18 / 4, | 270 | 10, 0x18 / 4, |
271 | 0, 0, | 271 | 0, 0, |
@@ -301,33 +301,40 @@ static int get_subaddrs(struct snd_dice *dice) | |||
301 | } | 301 | } |
302 | } | 302 | } |
303 | 303 | ||
304 | /* | 304 | if (be32_to_cpu(pointers[1]) > 0x18) { |
305 | * Check that the implemented DICE driver specification major version | 305 | /* |
306 | * number matches. | 306 | * Check that the implemented DICE driver specification major |
307 | */ | 307 | * version number matches. |
308 | err = snd_fw_transaction(dice->unit, TCODE_READ_QUADLET_REQUEST, | 308 | */ |
309 | DICE_PRIVATE_SPACE + | 309 | err = snd_fw_transaction(dice->unit, TCODE_READ_QUADLET_REQUEST, |
310 | be32_to_cpu(pointers[0]) * 4 + GLOBAL_VERSION, | 310 | DICE_PRIVATE_SPACE + |
311 | &version, sizeof(version), 0); | 311 | be32_to_cpu(pointers[0]) * 4 + GLOBAL_VERSION, |
312 | if (err < 0) | 312 | &version, sizeof(version), 0); |
313 | goto end; | 313 | if (err < 0) |
314 | goto end; | ||
314 | 315 | ||
315 | if ((version & cpu_to_be32(0xff000000)) != cpu_to_be32(0x01000000)) { | 316 | if ((version & cpu_to_be32(0xff000000)) != |
316 | dev_err(&dice->unit->device, | 317 | cpu_to_be32(0x01000000)) { |
317 | "unknown DICE version: 0x%08x\n", be32_to_cpu(version)); | 318 | dev_err(&dice->unit->device, |
318 | err = -ENODEV; | 319 | "unknown DICE version: 0x%08x\n", |
319 | goto end; | 320 | be32_to_cpu(version)); |
321 | err = -ENODEV; | ||
322 | goto end; | ||
323 | } | ||
324 | |||
325 | /* Set up later. */ | ||
326 | dice->clock_caps = 1; | ||
320 | } | 327 | } |
321 | 328 | ||
322 | dice->global_offset = be32_to_cpu(pointers[0]) * 4; | 329 | dice->global_offset = be32_to_cpu(pointers[0]) * 4; |
323 | dice->tx_offset = be32_to_cpu(pointers[2]) * 4; | 330 | dice->tx_offset = be32_to_cpu(pointers[2]) * 4; |
324 | dice->rx_offset = be32_to_cpu(pointers[4]) * 4; | 331 | dice->rx_offset = be32_to_cpu(pointers[4]) * 4; |
325 | dice->sync_offset = be32_to_cpu(pointers[6]) * 4; | ||
326 | dice->rsrv_offset = be32_to_cpu(pointers[8]) * 4; | ||
327 | 332 | ||
328 | /* Set up later. */ | 333 | /* Old firmware doesn't support these fields. */ |
329 | if (be32_to_cpu(pointers[1]) * 4 >= GLOBAL_CLOCK_CAPABILITIES + 4) | 334 | if (pointers[7]) |
330 | dice->clock_caps = 1; | 335 | dice->sync_offset = be32_to_cpu(pointers[6]) * 4; |
336 | if (pointers[9]) | ||
337 | dice->rsrv_offset = be32_to_cpu(pointers[8]) * 4; | ||
331 | end: | 338 | end: |
332 | kfree(pointers); | 339 | kfree(pointers); |
333 | return err; | 340 | return err; |
diff --git a/sound/firewire/dice/dice.c b/sound/firewire/dice/dice.c index 96bb01b6b751..774eb2205668 100644 --- a/sound/firewire/dice/dice.c +++ b/sound/firewire/dice/dice.c | |||
@@ -15,40 +15,15 @@ MODULE_LICENSE("GPL v2"); | |||
15 | #define OUI_LOUD 0x000ff2 | 15 | #define OUI_LOUD 0x000ff2 |
16 | #define OUI_FOCUSRITE 0x00130e | 16 | #define OUI_FOCUSRITE 0x00130e |
17 | #define OUI_TCELECTRONIC 0x000166 | 17 | #define OUI_TCELECTRONIC 0x000166 |
18 | #define OUI_ALESIS 0x000595 | ||
19 | #define OUI_MAUDIO 0x000d6c | ||
20 | #define OUI_MYTEK 0x001ee8 | ||
18 | 21 | ||
19 | #define DICE_CATEGORY_ID 0x04 | 22 | #define DICE_CATEGORY_ID 0x04 |
20 | #define WEISS_CATEGORY_ID 0x00 | 23 | #define WEISS_CATEGORY_ID 0x00 |
21 | #define LOUD_CATEGORY_ID 0x10 | 24 | #define LOUD_CATEGORY_ID 0x10 |
22 | 25 | ||
23 | /* | 26 | #define MODEL_ALESIS_IO_BOTH 0x000001 |
24 | * Some models support several isochronous channels, while these streams are not | ||
25 | * always available. In this case, add the model name to this list. | ||
26 | */ | ||
27 | static bool force_two_pcm_support(struct fw_unit *unit) | ||
28 | { | ||
29 | static const char *const models[] = { | ||
30 | /* TC Electronic models. */ | ||
31 | "StudioKonnekt48", | ||
32 | /* Focusrite models. */ | ||
33 | "SAFFIRE_PRO_40", | ||
34 | "LIQUID_SAFFIRE_56", | ||
35 | "SAFFIRE_PRO_40_1", | ||
36 | }; | ||
37 | char model[32]; | ||
38 | unsigned int i; | ||
39 | int err; | ||
40 | |||
41 | err = fw_csr_string(unit->directory, CSR_MODEL, model, sizeof(model)); | ||
42 | if (err < 0) | ||
43 | return false; | ||
44 | |||
45 | for (i = 0; i < ARRAY_SIZE(models); i++) { | ||
46 | if (strcmp(models[i], model) == 0) | ||
47 | break; | ||
48 | } | ||
49 | |||
50 | return i < ARRAY_SIZE(models); | ||
51 | } | ||
52 | 27 | ||
53 | static int check_dice_category(struct fw_unit *unit) | 28 | static int check_dice_category(struct fw_unit *unit) |
54 | { | 29 | { |
@@ -75,11 +50,6 @@ static int check_dice_category(struct fw_unit *unit) | |||
75 | } | 50 | } |
76 | } | 51 | } |
77 | 52 | ||
78 | if (vendor == OUI_FOCUSRITE || vendor == OUI_TCELECTRONIC) { | ||
79 | if (force_two_pcm_support(unit)) | ||
80 | return 0; | ||
81 | } | ||
82 | |||
83 | if (vendor == OUI_WEISS) | 53 | if (vendor == OUI_WEISS) |
84 | category = WEISS_CATEGORY_ID; | 54 | category = WEISS_CATEGORY_ID; |
85 | else if (vendor == OUI_LOUD) | 55 | else if (vendor == OUI_LOUD) |
@@ -186,9 +156,6 @@ static void do_registration(struct work_struct *work) | |||
186 | if (err < 0) | 156 | if (err < 0) |
187 | return; | 157 | return; |
188 | 158 | ||
189 | if (force_two_pcm_support(dice->unit)) | ||
190 | dice->force_two_pcms = true; | ||
191 | |||
192 | err = snd_dice_transaction_init(dice); | 159 | err = snd_dice_transaction_init(dice); |
193 | if (err < 0) | 160 | if (err < 0) |
194 | goto error; | 161 | goto error; |
@@ -199,6 +166,10 @@ static void do_registration(struct work_struct *work) | |||
199 | 166 | ||
200 | dice_card_strings(dice); | 167 | dice_card_strings(dice); |
201 | 168 | ||
169 | err = dice->detect_formats(dice); | ||
170 | if (err < 0) | ||
171 | goto error; | ||
172 | |||
202 | err = snd_dice_stream_init_duplex(dice); | 173 | err = snd_dice_stream_init_duplex(dice); |
203 | if (err < 0) | 174 | if (err < 0) |
204 | goto error; | 175 | goto error; |
@@ -239,14 +210,17 @@ error: | |||
239 | "Sound card registration failed: %d\n", err); | 210 | "Sound card registration failed: %d\n", err); |
240 | } | 211 | } |
241 | 212 | ||
242 | static int dice_probe(struct fw_unit *unit, const struct ieee1394_device_id *id) | 213 | static int dice_probe(struct fw_unit *unit, |
214 | const struct ieee1394_device_id *entry) | ||
243 | { | 215 | { |
244 | struct snd_dice *dice; | 216 | struct snd_dice *dice; |
245 | int err; | 217 | int err; |
246 | 218 | ||
247 | err = check_dice_category(unit); | 219 | if (!entry->driver_data) { |
248 | if (err < 0) | 220 | err = check_dice_category(unit); |
249 | return -ENODEV; | 221 | if (err < 0) |
222 | return -ENODEV; | ||
223 | } | ||
250 | 224 | ||
251 | /* Allocate this independent of sound card instance. */ | 225 | /* Allocate this independent of sound card instance. */ |
252 | dice = kzalloc(sizeof(struct snd_dice), GFP_KERNEL); | 226 | dice = kzalloc(sizeof(struct snd_dice), GFP_KERNEL); |
@@ -256,6 +230,13 @@ static int dice_probe(struct fw_unit *unit, const struct ieee1394_device_id *id) | |||
256 | dice->unit = fw_unit_get(unit); | 230 | dice->unit = fw_unit_get(unit); |
257 | dev_set_drvdata(&unit->device, dice); | 231 | dev_set_drvdata(&unit->device, dice); |
258 | 232 | ||
233 | if (!entry->driver_data) { | ||
234 | dice->detect_formats = snd_dice_stream_detect_current_formats; | ||
235 | } else { | ||
236 | dice->detect_formats = | ||
237 | (snd_dice_detect_formats_t)entry->driver_data; | ||
238 | } | ||
239 | |||
259 | spin_lock_init(&dice->lock); | 240 | spin_lock_init(&dice->lock); |
260 | mutex_init(&dice->mutex); | 241 | mutex_init(&dice->mutex); |
261 | init_completion(&dice->clock_accepted); | 242 | init_completion(&dice->clock_accepted); |
@@ -313,16 +294,97 @@ static void dice_bus_reset(struct fw_unit *unit) | |||
313 | #define DICE_INTERFACE 0x000001 | 294 | #define DICE_INTERFACE 0x000001 |
314 | 295 | ||
315 | static const struct ieee1394_device_id dice_id_table[] = { | 296 | static const struct ieee1394_device_id dice_id_table[] = { |
297 | /* M-Audio Profire 2626 has a different value in version field. */ | ||
316 | { | 298 | { |
317 | .match_flags = IEEE1394_MATCH_VERSION, | 299 | .match_flags = IEEE1394_MATCH_VENDOR_ID | |
318 | .version = DICE_INTERFACE, | 300 | IEEE1394_MATCH_MODEL_ID, |
301 | .vendor_id = OUI_MAUDIO, | ||
302 | .model_id = 0x000010, | ||
303 | .driver_data = (kernel_ulong_t)snd_dice_detect_extension_formats, | ||
319 | }, | 304 | }, |
320 | /* M-Audio Profire 610/2626 has a different value in version field. */ | 305 | /* M-Audio Profire 610 has a different value in version field. */ |
321 | { | 306 | { |
322 | .match_flags = IEEE1394_MATCH_VENDOR_ID | | 307 | .match_flags = IEEE1394_MATCH_VENDOR_ID | |
323 | IEEE1394_MATCH_SPECIFIER_ID, | 308 | IEEE1394_MATCH_MODEL_ID, |
324 | .vendor_id = 0x000d6c, | 309 | .vendor_id = OUI_MAUDIO, |
325 | .specifier_id = 0x000d6c, | 310 | .model_id = 0x000011, |
311 | .driver_data = (kernel_ulong_t)snd_dice_detect_extension_formats, | ||
312 | }, | ||
313 | /* TC Electronic Konnekt 24D. */ | ||
314 | { | ||
315 | .match_flags = IEEE1394_MATCH_VENDOR_ID | | ||
316 | IEEE1394_MATCH_MODEL_ID, | ||
317 | .vendor_id = OUI_TCELECTRONIC, | ||
318 | .model_id = 0x000020, | ||
319 | .driver_data = (kernel_ulong_t)snd_dice_detect_tcelectronic_formats, | ||
320 | }, | ||
321 | /* TC Electronic Konnekt 8. */ | ||
322 | { | ||
323 | .match_flags = IEEE1394_MATCH_VENDOR_ID | | ||
324 | IEEE1394_MATCH_MODEL_ID, | ||
325 | .vendor_id = OUI_TCELECTRONIC, | ||
326 | .model_id = 0x000021, | ||
327 | .driver_data = (kernel_ulong_t)snd_dice_detect_tcelectronic_formats, | ||
328 | }, | ||
329 | /* TC Electronic Studio Konnekt 48. */ | ||
330 | { | ||
331 | .match_flags = IEEE1394_MATCH_VENDOR_ID | | ||
332 | IEEE1394_MATCH_MODEL_ID, | ||
333 | .vendor_id = OUI_TCELECTRONIC, | ||
334 | .model_id = 0x000022, | ||
335 | .driver_data = (kernel_ulong_t)snd_dice_detect_tcelectronic_formats, | ||
336 | }, | ||
337 | /* TC Electronic Konnekt Live. */ | ||
338 | { | ||
339 | .match_flags = IEEE1394_MATCH_VENDOR_ID | | ||
340 | IEEE1394_MATCH_MODEL_ID, | ||
341 | .vendor_id = OUI_TCELECTRONIC, | ||
342 | .model_id = 0x000023, | ||
343 | .driver_data = (kernel_ulong_t)snd_dice_detect_tcelectronic_formats, | ||
344 | }, | ||
345 | /* TC Electronic Desktop Konnekt 6. */ | ||
346 | { | ||
347 | .match_flags = IEEE1394_MATCH_VENDOR_ID | | ||
348 | IEEE1394_MATCH_MODEL_ID, | ||
349 | .vendor_id = OUI_TCELECTRONIC, | ||
350 | .model_id = 0x000024, | ||
351 | .driver_data = (kernel_ulong_t)snd_dice_detect_tcelectronic_formats, | ||
352 | }, | ||
353 | /* TC Electronic Impact Twin. */ | ||
354 | { | ||
355 | .match_flags = IEEE1394_MATCH_VENDOR_ID | | ||
356 | IEEE1394_MATCH_MODEL_ID, | ||
357 | .vendor_id = OUI_TCELECTRONIC, | ||
358 | .model_id = 0x000027, | ||
359 | .driver_data = (kernel_ulong_t)snd_dice_detect_tcelectronic_formats, | ||
360 | }, | ||
361 | /* TC Electronic Digital Konnekt x32. */ | ||
362 | { | ||
363 | .match_flags = IEEE1394_MATCH_VENDOR_ID | | ||
364 | IEEE1394_MATCH_MODEL_ID, | ||
365 | .vendor_id = OUI_TCELECTRONIC, | ||
366 | .model_id = 0x000030, | ||
367 | .driver_data = (kernel_ulong_t)snd_dice_detect_tcelectronic_formats, | ||
368 | }, | ||
369 | /* Alesis iO14/iO26. */ | ||
370 | { | ||
371 | .match_flags = IEEE1394_MATCH_VENDOR_ID | | ||
372 | IEEE1394_MATCH_MODEL_ID, | ||
373 | .vendor_id = OUI_ALESIS, | ||
374 | .model_id = MODEL_ALESIS_IO_BOTH, | ||
375 | .driver_data = (kernel_ulong_t)snd_dice_detect_alesis_formats, | ||
376 | }, | ||
377 | /* Mytek Stereo 192 DSD-DAC. */ | ||
378 | { | ||
379 | .match_flags = IEEE1394_MATCH_VENDOR_ID | | ||
380 | IEEE1394_MATCH_MODEL_ID, | ||
381 | .vendor_id = OUI_MYTEK, | ||
382 | .model_id = 0x000002, | ||
383 | .driver_data = (kernel_ulong_t)snd_dice_detect_mytek_formats, | ||
384 | }, | ||
385 | { | ||
386 | .match_flags = IEEE1394_MATCH_VERSION, | ||
387 | .version = DICE_INTERFACE, | ||
326 | }, | 388 | }, |
327 | { } | 389 | { } |
328 | }; | 390 | }; |
diff --git a/sound/firewire/dice/dice.h b/sound/firewire/dice/dice.h index da00e75e09d4..83353a3559e8 100644 --- a/sound/firewire/dice/dice.h +++ b/sound/firewire/dice/dice.h | |||
@@ -63,6 +63,16 @@ | |||
63 | */ | 63 | */ |
64 | #define MAX_STREAMS 2 | 64 | #define MAX_STREAMS 2 |
65 | 65 | ||
66 | enum snd_dice_rate_mode { | ||
67 | SND_DICE_RATE_MODE_LOW = 0, | ||
68 | SND_DICE_RATE_MODE_MIDDLE, | ||
69 | SND_DICE_RATE_MODE_HIGH, | ||
70 | SND_DICE_RATE_MODE_COUNT, | ||
71 | }; | ||
72 | |||
73 | struct snd_dice; | ||
74 | typedef int (*snd_dice_detect_formats_t)(struct snd_dice *dice); | ||
75 | |||
66 | struct snd_dice { | 76 | struct snd_dice { |
67 | struct snd_card *card; | 77 | struct snd_card *card; |
68 | struct fw_unit *unit; | 78 | struct fw_unit *unit; |
@@ -80,6 +90,11 @@ struct snd_dice { | |||
80 | unsigned int rsrv_offset; | 90 | unsigned int rsrv_offset; |
81 | 91 | ||
82 | unsigned int clock_caps; | 92 | unsigned int clock_caps; |
93 | unsigned int tx_pcm_chs[MAX_STREAMS][SND_DICE_RATE_MODE_COUNT]; | ||
94 | unsigned int rx_pcm_chs[MAX_STREAMS][SND_DICE_RATE_MODE_COUNT]; | ||
95 | unsigned int tx_midi_ports[MAX_STREAMS]; | ||
96 | unsigned int rx_midi_ports[MAX_STREAMS]; | ||
97 | snd_dice_detect_formats_t detect_formats; | ||
83 | 98 | ||
84 | struct fw_address_handler notification_handler; | 99 | struct fw_address_handler notification_handler; |
85 | int owner_generation; | 100 | int owner_generation; |
@@ -98,8 +113,6 @@ struct snd_dice { | |||
98 | bool global_enabled; | 113 | bool global_enabled; |
99 | struct completion clock_accepted; | 114 | struct completion clock_accepted; |
100 | unsigned int substreams_counter; | 115 | unsigned int substreams_counter; |
101 | |||
102 | bool force_two_pcms; | ||
103 | }; | 116 | }; |
104 | 117 | ||
105 | enum snd_dice_addr_type { | 118 | enum snd_dice_addr_type { |
@@ -190,11 +203,14 @@ void snd_dice_transaction_destroy(struct snd_dice *dice); | |||
190 | #define SND_DICE_RATES_COUNT 7 | 203 | #define SND_DICE_RATES_COUNT 7 |
191 | extern const unsigned int snd_dice_rates[SND_DICE_RATES_COUNT]; | 204 | extern const unsigned int snd_dice_rates[SND_DICE_RATES_COUNT]; |
192 | 205 | ||
206 | int snd_dice_stream_get_rate_mode(struct snd_dice *dice, unsigned int rate, | ||
207 | enum snd_dice_rate_mode *mode); | ||
193 | int snd_dice_stream_start_duplex(struct snd_dice *dice, unsigned int rate); | 208 | int snd_dice_stream_start_duplex(struct snd_dice *dice, unsigned int rate); |
194 | void snd_dice_stream_stop_duplex(struct snd_dice *dice); | 209 | void snd_dice_stream_stop_duplex(struct snd_dice *dice); |
195 | int snd_dice_stream_init_duplex(struct snd_dice *dice); | 210 | int snd_dice_stream_init_duplex(struct snd_dice *dice); |
196 | void snd_dice_stream_destroy_duplex(struct snd_dice *dice); | 211 | void snd_dice_stream_destroy_duplex(struct snd_dice *dice); |
197 | void snd_dice_stream_update_duplex(struct snd_dice *dice); | 212 | void snd_dice_stream_update_duplex(struct snd_dice *dice); |
213 | int snd_dice_stream_detect_current_formats(struct snd_dice *dice); | ||
198 | 214 | ||
199 | int snd_dice_stream_lock_try(struct snd_dice *dice); | 215 | int snd_dice_stream_lock_try(struct snd_dice *dice); |
200 | void snd_dice_stream_lock_release(struct snd_dice *dice); | 216 | void snd_dice_stream_lock_release(struct snd_dice *dice); |
@@ -207,4 +223,9 @@ void snd_dice_create_proc(struct snd_dice *dice); | |||
207 | 223 | ||
208 | int snd_dice_create_midi(struct snd_dice *dice); | 224 | int snd_dice_create_midi(struct snd_dice *dice); |
209 | 225 | ||
226 | int snd_dice_detect_tcelectronic_formats(struct snd_dice *dice); | ||
227 | int snd_dice_detect_alesis_formats(struct snd_dice *dice); | ||
228 | int snd_dice_detect_extension_formats(struct snd_dice *dice); | ||
229 | int snd_dice_detect_mytek_formats(struct snd_dice *dice); | ||
230 | |||
210 | #endif | 231 | #endif |
diff --git a/sound/firewire/digi00x/digi00x-proc.c b/sound/firewire/digi00x/digi00x-proc.c index a1d601f31165..6996d5a6ff5f 100644 --- a/sound/firewire/digi00x/digi00x-proc.c +++ b/sound/firewire/digi00x/digi00x-proc.c | |||
@@ -79,7 +79,7 @@ void snd_dg00x_proc_init(struct snd_dg00x *dg00x) | |||
79 | if (root == NULL) | 79 | if (root == NULL) |
80 | return; | 80 | return; |
81 | 81 | ||
82 | root->mode = S_IFDIR | S_IRUGO | S_IXUGO; | 82 | root->mode = S_IFDIR | 0555; |
83 | if (snd_info_register(root) < 0) { | 83 | if (snd_info_register(root) < 0) { |
84 | snd_info_free_entry(root); | 84 | snd_info_free_entry(root); |
85 | return; | 85 | return; |
diff --git a/sound/firewire/fireface/ff-proc.c b/sound/firewire/fireface/ff-proc.c index 69441d121f71..40ccbfd8ef89 100644 --- a/sound/firewire/fireface/ff-proc.c +++ b/sound/firewire/fireface/ff-proc.c | |||
@@ -52,7 +52,7 @@ void snd_ff_proc_init(struct snd_ff *ff) | |||
52 | ff->card->proc_root); | 52 | ff->card->proc_root); |
53 | if (root == NULL) | 53 | if (root == NULL) |
54 | return; | 54 | return; |
55 | root->mode = S_IFDIR | S_IRUGO | S_IXUGO; | 55 | root->mode = S_IFDIR | 0555; |
56 | if (snd_info_register(root) < 0) { | 56 | if (snd_info_register(root) < 0) { |
57 | snd_info_free_entry(root); | 57 | snd_info_free_entry(root); |
58 | return; | 58 | return; |
diff --git a/sound/firewire/fireworks/fireworks_proc.c b/sound/firewire/fireworks/fireworks_proc.c index 9c21f31b8b21..779ecec5af62 100644 --- a/sound/firewire/fireworks/fireworks_proc.c +++ b/sound/firewire/fireworks/fireworks_proc.c | |||
@@ -219,7 +219,7 @@ void snd_efw_proc_init(struct snd_efw *efw) | |||
219 | efw->card->proc_root); | 219 | efw->card->proc_root); |
220 | if (root == NULL) | 220 | if (root == NULL) |
221 | return; | 221 | return; |
222 | root->mode = S_IFDIR | S_IRUGO | S_IXUGO; | 222 | root->mode = S_IFDIR | 0555; |
223 | if (snd_info_register(root) < 0) { | 223 | if (snd_info_register(root) < 0) { |
224 | snd_info_free_entry(root); | 224 | snd_info_free_entry(root); |
225 | return; | 225 | return; |
diff --git a/sound/firewire/isight.c b/sound/firewire/isight.c index 46092fa3ff9b..3919e186a30b 100644 --- a/sound/firewire/isight.c +++ b/sound/firewire/isight.c | |||
@@ -569,18 +569,20 @@ static int isight_create_mixer(struct isight *isight) | |||
569 | return err; | 569 | return err; |
570 | isight->gain_max = be32_to_cpu(value); | 570 | isight->gain_max = be32_to_cpu(value); |
571 | 571 | ||
572 | isight->gain_tlv[0] = SNDRV_CTL_TLVT_DB_MINMAX; | 572 | isight->gain_tlv[SNDRV_CTL_TLVO_TYPE] = SNDRV_CTL_TLVT_DB_MINMAX; |
573 | isight->gain_tlv[1] = 2 * sizeof(unsigned int); | 573 | isight->gain_tlv[SNDRV_CTL_TLVO_LEN] = 2 * sizeof(unsigned int); |
574 | 574 | ||
575 | err = reg_read(isight, REG_GAIN_DB_START, &value); | 575 | err = reg_read(isight, REG_GAIN_DB_START, &value); |
576 | if (err < 0) | 576 | if (err < 0) |
577 | return err; | 577 | return err; |
578 | isight->gain_tlv[2] = (s32)be32_to_cpu(value) * 100; | 578 | isight->gain_tlv[SNDRV_CTL_TLVO_DB_MINMAX_MIN] = |
579 | (s32)be32_to_cpu(value) * 100; | ||
579 | 580 | ||
580 | err = reg_read(isight, REG_GAIN_DB_END, &value); | 581 | err = reg_read(isight, REG_GAIN_DB_END, &value); |
581 | if (err < 0) | 582 | if (err < 0) |
582 | return err; | 583 | return err; |
583 | isight->gain_tlv[3] = (s32)be32_to_cpu(value) * 100; | 584 | isight->gain_tlv[SNDRV_CTL_TLVO_DB_MINMAX_MAX] = |
585 | (s32)be32_to_cpu(value) * 100; | ||
584 | 586 | ||
585 | ctl = snd_ctl_new1(&gain_control, isight); | 587 | ctl = snd_ctl_new1(&gain_control, isight); |
586 | if (ctl) | 588 | if (ctl) |
diff --git a/sound/firewire/motu/motu-proc.c b/sound/firewire/motu/motu-proc.c index 4edc064999ed..ab6830a6d242 100644 --- a/sound/firewire/motu/motu-proc.c +++ b/sound/firewire/motu/motu-proc.c | |||
@@ -107,7 +107,7 @@ void snd_motu_proc_init(struct snd_motu *motu) | |||
107 | motu->card->proc_root); | 107 | motu->card->proc_root); |
108 | if (root == NULL) | 108 | if (root == NULL) |
109 | return; | 109 | return; |
110 | root->mode = S_IFDIR | S_IRUGO | S_IXUGO; | 110 | root->mode = S_IFDIR | 0555; |
111 | if (snd_info_register(root) < 0) { | 111 | if (snd_info_register(root) < 0) { |
112 | snd_info_free_entry(root); | 112 | snd_info_free_entry(root); |
113 | return; | 113 | return; |
diff --git a/sound/firewire/oxfw/oxfw-proc.c b/sound/firewire/oxfw/oxfw-proc.c index 8ba4f9f262b8..27dac071bc73 100644 --- a/sound/firewire/oxfw/oxfw-proc.c +++ b/sound/firewire/oxfw/oxfw-proc.c | |||
@@ -103,7 +103,7 @@ void snd_oxfw_proc_init(struct snd_oxfw *oxfw) | |||
103 | oxfw->card->proc_root); | 103 | oxfw->card->proc_root); |
104 | if (root == NULL) | 104 | if (root == NULL) |
105 | return; | 105 | return; |
106 | root->mode = S_IFDIR | S_IRUGO | S_IXUGO; | 106 | root->mode = S_IFDIR | 0555; |
107 | if (snd_info_register(root) < 0) { | 107 | if (snd_info_register(root) < 0) { |
108 | snd_info_free_entry(root); | 108 | snd_info_free_entry(root); |
109 | return; | 109 | return; |
diff --git a/sound/firewire/oxfw/oxfw.c b/sound/firewire/oxfw/oxfw.c index 413ab6313bb6..1e5b2c802635 100644 --- a/sound/firewire/oxfw/oxfw.c +++ b/sound/firewire/oxfw/oxfw.c | |||
@@ -49,7 +49,6 @@ static bool detect_loud_models(struct fw_unit *unit) | |||
49 | "Tapco LINK.firewire 4x6", | 49 | "Tapco LINK.firewire 4x6", |
50 | "U.420"}; | 50 | "U.420"}; |
51 | char model[32]; | 51 | char model[32]; |
52 | unsigned int i; | ||
53 | int err; | 52 | int err; |
54 | 53 | ||
55 | err = fw_csr_string(unit->directory, CSR_MODEL, | 54 | err = fw_csr_string(unit->directory, CSR_MODEL, |
@@ -57,12 +56,7 @@ static bool detect_loud_models(struct fw_unit *unit) | |||
57 | if (err < 0) | 56 | if (err < 0) |
58 | return false; | 57 | return false; |
59 | 58 | ||
60 | for (i = 0; i < ARRAY_SIZE(models); i++) { | 59 | return match_string(models, ARRAY_SIZE(models), model) >= 0; |
61 | if (strcmp(models[i], model) == 0) | ||
62 | break; | ||
63 | } | ||
64 | |||
65 | return (i < ARRAY_SIZE(models)); | ||
66 | } | 60 | } |
67 | 61 | ||
68 | static int name_card(struct snd_oxfw *oxfw) | 62 | static int name_card(struct snd_oxfw *oxfw) |
diff --git a/sound/firewire/tascam/tascam-proc.c b/sound/firewire/tascam/tascam-proc.c index bfd4a4c06914..fee3bf32a0da 100644 --- a/sound/firewire/tascam/tascam-proc.c +++ b/sound/firewire/tascam/tascam-proc.c | |||
@@ -78,7 +78,7 @@ void snd_tscm_proc_init(struct snd_tscm *tscm) | |||
78 | tscm->card->proc_root); | 78 | tscm->card->proc_root); |
79 | if (root == NULL) | 79 | if (root == NULL) |
80 | return; | 80 | return; |
81 | root->mode = S_IFDIR | S_IRUGO | S_IXUGO; | 81 | root->mode = S_IFDIR | 0555; |
82 | if (snd_info_register(root) < 0) { | 82 | if (snd_info_register(root) < 0) { |
83 | snd_info_free_entry(root); | 83 | snd_info_free_entry(root); |
84 | return; | 84 | return; |
diff --git a/sound/hda/hdac_regmap.c b/sound/hda/hdac_regmap.c index 47a358fab132..419e285e0226 100644 --- a/sound/hda/hdac_regmap.c +++ b/sound/hda/hdac_regmap.c | |||
@@ -65,10 +65,10 @@ static bool hda_writeable_reg(struct device *dev, unsigned int reg) | |||
65 | { | 65 | { |
66 | struct hdac_device *codec = dev_to_hdac_dev(dev); | 66 | struct hdac_device *codec = dev_to_hdac_dev(dev); |
67 | unsigned int verb = get_verb(reg); | 67 | unsigned int verb = get_verb(reg); |
68 | const unsigned int *v; | ||
68 | int i; | 69 | int i; |
69 | 70 | ||
70 | for (i = 0; i < codec->vendor_verbs.used; i++) { | 71 | snd_array_for_each(&codec->vendor_verbs, i, v) { |
71 | unsigned int *v = snd_array_elem(&codec->vendor_verbs, i); | ||
72 | if (verb == *v) | 72 | if (verb == *v) |
73 | return true; | 73 | return true; |
74 | } | 74 | } |
diff --git a/sound/isa/cmi8328.c b/sound/isa/cmi8328.c index d09e456107ad..de6ef1b1cf0e 100644 --- a/sound/isa/cmi8328.c +++ b/sound/isa/cmi8328.c | |||
@@ -192,7 +192,7 @@ static int snd_cmi8328_mixer(struct snd_wss *chip) | |||
192 | } | 192 | } |
193 | 193 | ||
194 | /* find index of an item in "-1"-ended array */ | 194 | /* find index of an item in "-1"-ended array */ |
195 | int array_find(int array[], int item) | 195 | static int array_find(int array[], int item) |
196 | { | 196 | { |
197 | int i; | 197 | int i; |
198 | 198 | ||
@@ -203,7 +203,7 @@ int array_find(int array[], int item) | |||
203 | return -1; | 203 | return -1; |
204 | } | 204 | } |
205 | /* the same for long */ | 205 | /* the same for long */ |
206 | int array_find_l(long array[], long item) | 206 | static int array_find_l(long array[], long item) |
207 | { | 207 | { |
208 | int i; | 208 | int i; |
209 | 209 | ||
diff --git a/sound/isa/msnd/msnd_pinnacle.c b/sound/isa/msnd/msnd_pinnacle.c index 45e561c425bf..6c584d9b6c42 100644 --- a/sound/isa/msnd/msnd_pinnacle.c +++ b/sound/isa/msnd/msnd_pinnacle.c | |||
@@ -757,9 +757,9 @@ static int snd_msnd_pinnacle_cfg_reset(int cfg) | |||
757 | static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-MAX */ | 757 | static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; /* Index 0-MAX */ |
758 | static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* ID for this card */ | 758 | static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* ID for this card */ |
759 | 759 | ||
760 | module_param_array(index, int, NULL, S_IRUGO); | 760 | module_param_array(index, int, NULL, 0444); |
761 | MODULE_PARM_DESC(index, "Index value for msnd_pinnacle soundcard."); | 761 | MODULE_PARM_DESC(index, "Index value for msnd_pinnacle soundcard."); |
762 | module_param_array(id, charp, NULL, S_IRUGO); | 762 | module_param_array(id, charp, NULL, 0444); |
763 | MODULE_PARM_DESC(id, "ID string for msnd_pinnacle soundcard."); | 763 | MODULE_PARM_DESC(id, "ID string for msnd_pinnacle soundcard."); |
764 | 764 | ||
765 | static long io[SNDRV_CARDS] = SNDRV_DEFAULT_PORT; | 765 | static long io[SNDRV_CARDS] = SNDRV_DEFAULT_PORT; |
@@ -801,22 +801,22 @@ MODULE_LICENSE("GPL"); | |||
801 | MODULE_FIRMWARE(INITCODEFILE); | 801 | MODULE_FIRMWARE(INITCODEFILE); |
802 | MODULE_FIRMWARE(PERMCODEFILE); | 802 | MODULE_FIRMWARE(PERMCODEFILE); |
803 | 803 | ||
804 | module_param_hw_array(io, long, ioport, NULL, S_IRUGO); | 804 | module_param_hw_array(io, long, ioport, NULL, 0444); |
805 | MODULE_PARM_DESC(io, "IO port #"); | 805 | MODULE_PARM_DESC(io, "IO port #"); |
806 | module_param_hw_array(irq, int, irq, NULL, S_IRUGO); | 806 | module_param_hw_array(irq, int, irq, NULL, 0444); |
807 | module_param_hw_array(mem, long, iomem, NULL, S_IRUGO); | 807 | module_param_hw_array(mem, long, iomem, NULL, 0444); |
808 | module_param_array(write_ndelay, int, NULL, S_IRUGO); | 808 | module_param_array(write_ndelay, int, NULL, 0444); |
809 | module_param(calibrate_signal, int, S_IRUGO); | 809 | module_param(calibrate_signal, int, 0444); |
810 | #ifndef MSND_CLASSIC | 810 | #ifndef MSND_CLASSIC |
811 | module_param_array(digital, int, NULL, S_IRUGO); | 811 | module_param_array(digital, int, NULL, 0444); |
812 | module_param_hw_array(cfg, long, ioport, NULL, S_IRUGO); | 812 | module_param_hw_array(cfg, long, ioport, NULL, 0444); |
813 | module_param_array(reset, int, 0, S_IRUGO); | 813 | module_param_array(reset, int, 0, 0444); |
814 | module_param_hw_array(mpu_io, long, ioport, NULL, S_IRUGO); | 814 | module_param_hw_array(mpu_io, long, ioport, NULL, 0444); |
815 | module_param_hw_array(mpu_irq, int, irq, NULL, S_IRUGO); | 815 | module_param_hw_array(mpu_irq, int, irq, NULL, 0444); |
816 | module_param_hw_array(ide_io0, long, ioport, NULL, S_IRUGO); | 816 | module_param_hw_array(ide_io0, long, ioport, NULL, 0444); |
817 | module_param_hw_array(ide_io1, long, ioport, NULL, S_IRUGO); | 817 | module_param_hw_array(ide_io1, long, ioport, NULL, 0444); |
818 | module_param_hw_array(ide_irq, int, irq, NULL, S_IRUGO); | 818 | module_param_hw_array(ide_irq, int, irq, NULL, 0444); |
819 | module_param_hw_array(joystick_io, long, ioport, NULL, S_IRUGO); | 819 | module_param_hw_array(joystick_io, long, ioport, NULL, 0444); |
820 | #endif | 820 | #endif |
821 | 821 | ||
822 | 822 | ||
diff --git a/sound/isa/sc6000.c b/sound/isa/sc6000.c index c09d9b914efe..a985e9183be9 100644 --- a/sound/isa/sc6000.c +++ b/sound/isa/sc6000.c | |||
@@ -592,7 +592,7 @@ static int snd_sc6000_probe(struct device *devptr, unsigned int dev) | |||
592 | *vport = devm_ioport_map(devptr, port[dev], 0x10); | 592 | *vport = devm_ioport_map(devptr, port[dev], 0x10); |
593 | if (*vport == NULL) { | 593 | if (*vport == NULL) { |
594 | snd_printk(KERN_ERR PFX | 594 | snd_printk(KERN_ERR PFX |
595 | "I/O port cannot be iomaped.\n"); | 595 | "I/O port cannot be iomapped.\n"); |
596 | err = -EBUSY; | 596 | err = -EBUSY; |
597 | goto err_unmap1; | 597 | goto err_unmap1; |
598 | } | 598 | } |
@@ -607,7 +607,7 @@ static int snd_sc6000_probe(struct device *devptr, unsigned int dev) | |||
607 | vmss_port = devm_ioport_map(devptr, mss_port[dev], 4); | 607 | vmss_port = devm_ioport_map(devptr, mss_port[dev], 4); |
608 | if (!vmss_port) { | 608 | if (!vmss_port) { |
609 | snd_printk(KERN_ERR PFX | 609 | snd_printk(KERN_ERR PFX |
610 | "MSS port I/O cannot be iomaped.\n"); | 610 | "MSS port I/O cannot be iomapped.\n"); |
611 | err = -EBUSY; | 611 | err = -EBUSY; |
612 | goto err_unmap2; | 612 | goto err_unmap2; |
613 | } | 613 | } |
diff --git a/sound/pci/ac97/ac97_proc.c b/sound/pci/ac97/ac97_proc.c index 6320bf084e47..e120a11c69e8 100644 --- a/sound/pci/ac97/ac97_proc.c +++ b/sound/pci/ac97/ac97_proc.c | |||
@@ -448,7 +448,7 @@ void snd_ac97_proc_init(struct snd_ac97 * ac97) | |||
448 | if ((entry = snd_info_create_card_entry(ac97->bus->card, name, ac97->bus->proc)) != NULL) { | 448 | if ((entry = snd_info_create_card_entry(ac97->bus->card, name, ac97->bus->proc)) != NULL) { |
449 | snd_info_set_text_ops(entry, ac97, snd_ac97_proc_regs_read); | 449 | snd_info_set_text_ops(entry, ac97, snd_ac97_proc_regs_read); |
450 | #ifdef CONFIG_SND_DEBUG | 450 | #ifdef CONFIG_SND_DEBUG |
451 | entry->mode |= S_IWUSR; | 451 | entry->mode |= 0200; |
452 | entry->c.text.write = snd_ac97_proc_regs_write; | 452 | entry->c.text.write = snd_ac97_proc_regs_write; |
453 | #endif | 453 | #endif |
454 | if (snd_info_register(entry) < 0) { | 454 | if (snd_info_register(entry) < 0) { |
@@ -474,7 +474,7 @@ void snd_ac97_bus_proc_init(struct snd_ac97_bus * bus) | |||
474 | 474 | ||
475 | sprintf(name, "codec97#%d", bus->num); | 475 | sprintf(name, "codec97#%d", bus->num); |
476 | if ((entry = snd_info_create_card_entry(bus->card, name, bus->card->proc_root)) != NULL) { | 476 | if ((entry = snd_info_create_card_entry(bus->card, name, bus->card->proc_root)) != NULL) { |
477 | entry->mode = S_IFDIR | S_IRUGO | S_IXUGO; | 477 | entry->mode = S_IFDIR | 0555; |
478 | if (snd_info_register(entry) < 0) { | 478 | if (snd_info_register(entry) < 0) { |
479 | snd_info_free_entry(entry); | 479 | snd_info_free_entry(entry); |
480 | entry = NULL; | 480 | entry = NULL; |
diff --git a/sound/pci/ad1889.c b/sound/pci/ad1889.c index 0bf2c04eeada..d9c54c08e2db 100644 --- a/sound/pci/ad1889.c +++ b/sound/pci/ad1889.c | |||
@@ -258,7 +258,7 @@ snd_ad1889_ac97_ready(struct snd_ad1889 *chip) | |||
258 | 258 | ||
259 | while (!(ad1889_readw(chip, AD_AC97_ACIC) & AD_AC97_ACIC_ACRDY) | 259 | while (!(ad1889_readw(chip, AD_AC97_ACIC) & AD_AC97_ACIC_ACRDY) |
260 | && --retry) | 260 | && --retry) |
261 | mdelay(1); | 261 | usleep_range(1000, 2000); |
262 | if (!retry) { | 262 | if (!retry) { |
263 | dev_err(chip->card->dev, "[%s] Link is not ready.\n", | 263 | dev_err(chip->card->dev, "[%s] Link is not ready.\n", |
264 | __func__); | 264 | __func__); |
@@ -872,7 +872,7 @@ snd_ad1889_init(struct snd_ad1889 *chip) | |||
872 | ad1889_writew(chip, AD_DS_CCS, AD_DS_CCS_CLKEN); /* turn on clock */ | 872 | ad1889_writew(chip, AD_DS_CCS, AD_DS_CCS_CLKEN); /* turn on clock */ |
873 | ad1889_readw(chip, AD_DS_CCS); /* flush posted write */ | 873 | ad1889_readw(chip, AD_DS_CCS); /* flush posted write */ |
874 | 874 | ||
875 | mdelay(10); | 875 | usleep_range(10000, 11000); |
876 | 876 | ||
877 | /* enable Master and Target abort interrupts */ | 877 | /* enable Master and Target abort interrupts */ |
878 | ad1889_writel(chip, AD_DMA_DISR, AD_DMA_DISR_PMAE | AD_DMA_DISR_PTAE); | 878 | ad1889_writel(chip, AD_DMA_DISR, AD_DMA_DISR_PMAE | AD_DMA_DISR_PTAE); |
diff --git a/sound/pci/asihpi/asihpi.c b/sound/pci/asihpi/asihpi.c index 720361455c60..64e0961f93ba 100644 --- a/sound/pci/asihpi/asihpi.c +++ b/sound/pci/asihpi/asihpi.c | |||
@@ -69,27 +69,27 @@ static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; /* ID for this card */ | |||
69 | static bool enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP; | 69 | static bool enable[SNDRV_CARDS] = SNDRV_DEFAULT_ENABLE_PNP; |
70 | static bool enable_hpi_hwdep = 1; | 70 | static bool enable_hpi_hwdep = 1; |
71 | 71 | ||
72 | module_param_array(index, int, NULL, S_IRUGO); | 72 | module_param_array(index, int, NULL, 0444); |
73 | MODULE_PARM_DESC(index, "ALSA index value for AudioScience soundcard."); | 73 | MODULE_PARM_DESC(index, "ALSA index value for AudioScience soundcard."); |
74 | 74 | ||
75 | module_param_array(id, charp, NULL, S_IRUGO); | 75 | module_param_array(id, charp, NULL, 0444); |
76 | MODULE_PARM_DESC(id, "ALSA ID string for AudioScience soundcard."); | 76 | MODULE_PARM_DESC(id, "ALSA ID string for AudioScience soundcard."); |
77 | 77 | ||
78 | module_param_array(enable, bool, NULL, S_IRUGO); | 78 | module_param_array(enable, bool, NULL, 0444); |
79 | MODULE_PARM_DESC(enable, "ALSA enable AudioScience soundcard."); | 79 | MODULE_PARM_DESC(enable, "ALSA enable AudioScience soundcard."); |
80 | 80 | ||
81 | module_param(enable_hpi_hwdep, bool, S_IRUGO|S_IWUSR); | 81 | module_param(enable_hpi_hwdep, bool, 0644); |
82 | MODULE_PARM_DESC(enable_hpi_hwdep, | 82 | MODULE_PARM_DESC(enable_hpi_hwdep, |
83 | "ALSA enable HPI hwdep for AudioScience soundcard "); | 83 | "ALSA enable HPI hwdep for AudioScience soundcard "); |
84 | 84 | ||
85 | /* identify driver */ | 85 | /* identify driver */ |
86 | #ifdef KERNEL_ALSA_BUILD | 86 | #ifdef KERNEL_ALSA_BUILD |
87 | static char *build_info = "Built using headers from kernel source"; | 87 | static char *build_info = "Built using headers from kernel source"; |
88 | module_param(build_info, charp, S_IRUGO); | 88 | module_param(build_info, charp, 0444); |
89 | MODULE_PARM_DESC(build_info, "Built using headers from kernel source"); | 89 | MODULE_PARM_DESC(build_info, "Built using headers from kernel source"); |
90 | #else | 90 | #else |
91 | static char *build_info = "Built within ALSA source"; | 91 | static char *build_info = "Built within ALSA source"; |
92 | module_param(build_info, charp, S_IRUGO); | 92 | module_param(build_info, charp, 0444); |
93 | MODULE_PARM_DESC(build_info, "Built within ALSA source"); | 93 | MODULE_PARM_DESC(build_info, "Built within ALSA source"); |
94 | #endif | 94 | #endif |
95 | 95 | ||
diff --git a/sound/pci/asihpi/hpioctl.c b/sound/pci/asihpi/hpioctl.c index b1a2a7ea4172..7d049569012c 100644 --- a/sound/pci/asihpi/hpioctl.c +++ b/sound/pci/asihpi/hpioctl.c | |||
@@ -46,14 +46,14 @@ MODULE_FIRMWARE("asihpi/dsp8900.bin"); | |||
46 | #endif | 46 | #endif |
47 | 47 | ||
48 | static int prealloc_stream_buf; | 48 | static int prealloc_stream_buf; |
49 | module_param(prealloc_stream_buf, int, S_IRUGO); | 49 | module_param(prealloc_stream_buf, int, 0444); |
50 | MODULE_PARM_DESC(prealloc_stream_buf, | 50 | MODULE_PARM_DESC(prealloc_stream_buf, |
51 | "Preallocate size for per-adapter stream buffer"); | 51 | "Preallocate size for per-adapter stream buffer"); |
52 | 52 | ||
53 | /* Allow the debug level to be changed after module load. | 53 | /* Allow the debug level to be changed after module load. |
54 | E.g. echo 2 > /sys/module/asihpi/parameters/hpiDebugLevel | 54 | E.g. echo 2 > /sys/module/asihpi/parameters/hpiDebugLevel |
55 | */ | 55 | */ |
56 | module_param(hpi_debug_level, int, S_IRUGO | S_IWUSR); | 56 | module_param(hpi_debug_level, int, 0644); |
57 | MODULE_PARM_DESC(hpi_debug_level, "debug verbosity 0..5"); | 57 | MODULE_PARM_DESC(hpi_debug_level, "debug verbosity 0..5"); |
58 | 58 | ||
59 | /* List of adapters found */ | 59 | /* List of adapters found */ |
diff --git a/sound/pci/ca0106/ca0106_proc.c b/sound/pci/ca0106/ca0106_proc.c index 9b2b8b38122f..a2c85cc37972 100644 --- a/sound/pci/ca0106/ca0106_proc.c +++ b/sound/pci/ca0106/ca0106_proc.c | |||
@@ -431,7 +431,7 @@ int snd_ca0106_proc_init(struct snd_ca0106 *emu) | |||
431 | if(! snd_card_proc_new(emu->card, "ca0106_reg32", &entry)) { | 431 | if(! snd_card_proc_new(emu->card, "ca0106_reg32", &entry)) { |
432 | snd_info_set_text_ops(entry, emu, snd_ca0106_proc_reg_read32); | 432 | snd_info_set_text_ops(entry, emu, snd_ca0106_proc_reg_read32); |
433 | entry->c.text.write = snd_ca0106_proc_reg_write32; | 433 | entry->c.text.write = snd_ca0106_proc_reg_write32; |
434 | entry->mode |= S_IWUSR; | 434 | entry->mode |= 0200; |
435 | } | 435 | } |
436 | if(! snd_card_proc_new(emu->card, "ca0106_reg16", &entry)) | 436 | if(! snd_card_proc_new(emu->card, "ca0106_reg16", &entry)) |
437 | snd_info_set_text_ops(entry, emu, snd_ca0106_proc_reg_read16); | 437 | snd_info_set_text_ops(entry, emu, snd_ca0106_proc_reg_read16); |
@@ -440,12 +440,12 @@ int snd_ca0106_proc_init(struct snd_ca0106 *emu) | |||
440 | if(! snd_card_proc_new(emu->card, "ca0106_regs1", &entry)) { | 440 | if(! snd_card_proc_new(emu->card, "ca0106_regs1", &entry)) { |
441 | snd_info_set_text_ops(entry, emu, snd_ca0106_proc_reg_read1); | 441 | snd_info_set_text_ops(entry, emu, snd_ca0106_proc_reg_read1); |
442 | entry->c.text.write = snd_ca0106_proc_reg_write; | 442 | entry->c.text.write = snd_ca0106_proc_reg_write; |
443 | entry->mode |= S_IWUSR; | 443 | entry->mode |= 0200; |
444 | } | 444 | } |
445 | if(! snd_card_proc_new(emu->card, "ca0106_i2c", &entry)) { | 445 | if(! snd_card_proc_new(emu->card, "ca0106_i2c", &entry)) { |
446 | entry->c.text.write = snd_ca0106_proc_i2c_write; | 446 | entry->c.text.write = snd_ca0106_proc_i2c_write; |
447 | entry->private_data = emu; | 447 | entry->private_data = emu; |
448 | entry->mode |= S_IWUSR; | 448 | entry->mode |= 0200; |
449 | } | 449 | } |
450 | if(! snd_card_proc_new(emu->card, "ca0106_regs2", &entry)) | 450 | if(! snd_card_proc_new(emu->card, "ca0106_regs2", &entry)) |
451 | snd_info_set_text_ops(entry, emu, snd_ca0106_proc_reg_read2); | 451 | snd_info_set_text_ops(entry, emu, snd_ca0106_proc_reg_read2); |
diff --git a/sound/pci/cmipci.c b/sound/pci/cmipci.c index 26a657870664..452cc79b44af 100644 --- a/sound/pci/cmipci.c +++ b/sound/pci/cmipci.c | |||
@@ -1139,7 +1139,7 @@ static int save_mixer_state(struct cmipci *cm) | |||
1139 | struct snd_ctl_elem_value *val; | 1139 | struct snd_ctl_elem_value *val; |
1140 | unsigned int i; | 1140 | unsigned int i; |
1141 | 1141 | ||
1142 | val = kmalloc(sizeof(*val), GFP_ATOMIC); | 1142 | val = kmalloc(sizeof(*val), GFP_KERNEL); |
1143 | if (!val) | 1143 | if (!val) |
1144 | return -ENOMEM; | 1144 | return -ENOMEM; |
1145 | for (i = 0; i < CM_SAVED_MIXERS; i++) { | 1145 | for (i = 0; i < CM_SAVED_MIXERS; i++) { |
diff --git a/sound/pci/cs46xx/cs46xx.c b/sound/pci/cs46xx/cs46xx.c index 655fbea1692c..4910d3f46d4b 100644 --- a/sound/pci/cs46xx/cs46xx.c +++ b/sound/pci/cs46xx/cs46xx.c | |||
@@ -58,7 +58,7 @@ MODULE_PARM_DESC(id, "ID string for the CS46xx soundcard."); | |||
58 | module_param_array(enable, bool, NULL, 0444); | 58 | module_param_array(enable, bool, NULL, 0444); |
59 | MODULE_PARM_DESC(enable, "Enable CS46xx soundcard."); | 59 | MODULE_PARM_DESC(enable, "Enable CS46xx soundcard."); |
60 | module_param_array(external_amp, bool, NULL, 0444); | 60 | module_param_array(external_amp, bool, NULL, 0444); |
61 | MODULE_PARM_DESC(external_amp, "Force to enable external amplifer."); | 61 | MODULE_PARM_DESC(external_amp, "Force to enable external amplifier."); |
62 | module_param_array(thinkpad, bool, NULL, 0444); | 62 | module_param_array(thinkpad, bool, NULL, 0444); |
63 | MODULE_PARM_DESC(thinkpad, "Force to enable Thinkpad's CLKRUN control."); | 63 | MODULE_PARM_DESC(thinkpad, "Force to enable Thinkpad's CLKRUN control."); |
64 | module_param_array(mmap_valid, bool, NULL, 0444); | 64 | module_param_array(mmap_valid, bool, NULL, 0444); |
diff --git a/sound/pci/cs46xx/cs46xx_lib.c b/sound/pci/cs46xx/cs46xx_lib.c index 0020fd0efc46..ed1251c5f449 100644 --- a/sound/pci/cs46xx/cs46xx_lib.c +++ b/sound/pci/cs46xx/cs46xx_lib.c | |||
@@ -2849,7 +2849,7 @@ static int snd_cs46xx_proc_init(struct snd_card *card, struct snd_cs46xx *chip) | |||
2849 | entry->private_data = chip; | 2849 | entry->private_data = chip; |
2850 | entry->c.ops = &snd_cs46xx_proc_io_ops; | 2850 | entry->c.ops = &snd_cs46xx_proc_io_ops; |
2851 | entry->size = region->size; | 2851 | entry->size = region->size; |
2852 | entry->mode = S_IFREG | S_IRUSR; | 2852 | entry->mode = S_IFREG | 0400; |
2853 | } | 2853 | } |
2854 | } | 2854 | } |
2855 | #ifdef CONFIG_SND_CS46XX_NEW_DSP | 2855 | #ifdef CONFIG_SND_CS46XX_NEW_DSP |
diff --git a/sound/pci/cs46xx/dsp_spos.c b/sound/pci/cs46xx/dsp_spos.c index aa61615288ff..c44eadef64ae 100644 --- a/sound/pci/cs46xx/dsp_spos.c +++ b/sound/pci/cs46xx/dsp_spos.c | |||
@@ -798,7 +798,7 @@ int cs46xx_dsp_proc_init (struct snd_card *card, struct snd_cs46xx *chip) | |||
798 | 798 | ||
799 | if ((entry = snd_info_create_card_entry(card, "dsp", card->proc_root)) != NULL) { | 799 | if ((entry = snd_info_create_card_entry(card, "dsp", card->proc_root)) != NULL) { |
800 | entry->content = SNDRV_INFO_CONTENT_TEXT; | 800 | entry->content = SNDRV_INFO_CONTENT_TEXT; |
801 | entry->mode = S_IFDIR | S_IRUGO | S_IXUGO; | 801 | entry->mode = S_IFDIR | 0555; |
802 | 802 | ||
803 | if (snd_info_register(entry) < 0) { | 803 | if (snd_info_register(entry) < 0) { |
804 | snd_info_free_entry(entry); | 804 | snd_info_free_entry(entry); |
@@ -814,7 +814,7 @@ int cs46xx_dsp_proc_init (struct snd_card *card, struct snd_cs46xx *chip) | |||
814 | if ((entry = snd_info_create_card_entry(card, "spos_symbols", ins->proc_dsp_dir)) != NULL) { | 814 | if ((entry = snd_info_create_card_entry(card, "spos_symbols", ins->proc_dsp_dir)) != NULL) { |
815 | entry->content = SNDRV_INFO_CONTENT_TEXT; | 815 | entry->content = SNDRV_INFO_CONTENT_TEXT; |
816 | entry->private_data = chip; | 816 | entry->private_data = chip; |
817 | entry->mode = S_IFREG | S_IRUGO | S_IWUSR; | 817 | entry->mode = S_IFREG | 0644; |
818 | entry->c.text.read = cs46xx_dsp_proc_symbol_table_read; | 818 | entry->c.text.read = cs46xx_dsp_proc_symbol_table_read; |
819 | if (snd_info_register(entry) < 0) { | 819 | if (snd_info_register(entry) < 0) { |
820 | snd_info_free_entry(entry); | 820 | snd_info_free_entry(entry); |
@@ -826,7 +826,7 @@ int cs46xx_dsp_proc_init (struct snd_card *card, struct snd_cs46xx *chip) | |||
826 | if ((entry = snd_info_create_card_entry(card, "spos_modules", ins->proc_dsp_dir)) != NULL) { | 826 | if ((entry = snd_info_create_card_entry(card, "spos_modules", ins->proc_dsp_dir)) != NULL) { |
827 | entry->content = SNDRV_INFO_CONTENT_TEXT; | 827 | entry->content = SNDRV_INFO_CONTENT_TEXT; |
828 | entry->private_data = chip; | 828 | entry->private_data = chip; |
829 | entry->mode = S_IFREG | S_IRUGO | S_IWUSR; | 829 | entry->mode = S_IFREG | 0644; |
830 | entry->c.text.read = cs46xx_dsp_proc_modules_read; | 830 | entry->c.text.read = cs46xx_dsp_proc_modules_read; |
831 | if (snd_info_register(entry) < 0) { | 831 | if (snd_info_register(entry) < 0) { |
832 | snd_info_free_entry(entry); | 832 | snd_info_free_entry(entry); |
@@ -838,7 +838,7 @@ int cs46xx_dsp_proc_init (struct snd_card *card, struct snd_cs46xx *chip) | |||
838 | if ((entry = snd_info_create_card_entry(card, "parameter", ins->proc_dsp_dir)) != NULL) { | 838 | if ((entry = snd_info_create_card_entry(card, "parameter", ins->proc_dsp_dir)) != NULL) { |
839 | entry->content = SNDRV_INFO_CONTENT_TEXT; | 839 | entry->content = SNDRV_INFO_CONTENT_TEXT; |
840 | entry->private_data = chip; | 840 | entry->private_data = chip; |
841 | entry->mode = S_IFREG | S_IRUGO | S_IWUSR; | 841 | entry->mode = S_IFREG | 0644; |
842 | entry->c.text.read = cs46xx_dsp_proc_parameter_dump_read; | 842 | entry->c.text.read = cs46xx_dsp_proc_parameter_dump_read; |
843 | if (snd_info_register(entry) < 0) { | 843 | if (snd_info_register(entry) < 0) { |
844 | snd_info_free_entry(entry); | 844 | snd_info_free_entry(entry); |
@@ -850,7 +850,7 @@ int cs46xx_dsp_proc_init (struct snd_card *card, struct snd_cs46xx *chip) | |||
850 | if ((entry = snd_info_create_card_entry(card, "sample", ins->proc_dsp_dir)) != NULL) { | 850 | if ((entry = snd_info_create_card_entry(card, "sample", ins->proc_dsp_dir)) != NULL) { |
851 | entry->content = SNDRV_INFO_CONTENT_TEXT; | 851 | entry->content = SNDRV_INFO_CONTENT_TEXT; |
852 | entry->private_data = chip; | 852 | entry->private_data = chip; |
853 | entry->mode = S_IFREG | S_IRUGO | S_IWUSR; | 853 | entry->mode = S_IFREG | 0644; |
854 | entry->c.text.read = cs46xx_dsp_proc_sample_dump_read; | 854 | entry->c.text.read = cs46xx_dsp_proc_sample_dump_read; |
855 | if (snd_info_register(entry) < 0) { | 855 | if (snd_info_register(entry) < 0) { |
856 | snd_info_free_entry(entry); | 856 | snd_info_free_entry(entry); |
@@ -862,7 +862,7 @@ int cs46xx_dsp_proc_init (struct snd_card *card, struct snd_cs46xx *chip) | |||
862 | if ((entry = snd_info_create_card_entry(card, "task_tree", ins->proc_dsp_dir)) != NULL) { | 862 | if ((entry = snd_info_create_card_entry(card, "task_tree", ins->proc_dsp_dir)) != NULL) { |
863 | entry->content = SNDRV_INFO_CONTENT_TEXT; | 863 | entry->content = SNDRV_INFO_CONTENT_TEXT; |
864 | entry->private_data = chip; | 864 | entry->private_data = chip; |
865 | entry->mode = S_IFREG | S_IRUGO | S_IWUSR; | 865 | entry->mode = S_IFREG | 0644; |
866 | entry->c.text.read = cs46xx_dsp_proc_task_tree_read; | 866 | entry->c.text.read = cs46xx_dsp_proc_task_tree_read; |
867 | if (snd_info_register(entry) < 0) { | 867 | if (snd_info_register(entry) < 0) { |
868 | snd_info_free_entry(entry); | 868 | snd_info_free_entry(entry); |
@@ -874,7 +874,7 @@ int cs46xx_dsp_proc_init (struct snd_card *card, struct snd_cs46xx *chip) | |||
874 | if ((entry = snd_info_create_card_entry(card, "scb_info", ins->proc_dsp_dir)) != NULL) { | 874 | if ((entry = snd_info_create_card_entry(card, "scb_info", ins->proc_dsp_dir)) != NULL) { |
875 | entry->content = SNDRV_INFO_CONTENT_TEXT; | 875 | entry->content = SNDRV_INFO_CONTENT_TEXT; |
876 | entry->private_data = chip; | 876 | entry->private_data = chip; |
877 | entry->mode = S_IFREG | S_IRUGO | S_IWUSR; | 877 | entry->mode = S_IFREG | 0644; |
878 | entry->c.text.read = cs46xx_dsp_proc_scb_read; | 878 | entry->c.text.read = cs46xx_dsp_proc_scb_read; |
879 | if (snd_info_register(entry) < 0) { | 879 | if (snd_info_register(entry) < 0) { |
880 | snd_info_free_entry(entry); | 880 | snd_info_free_entry(entry); |
diff --git a/sound/pci/cs46xx/dsp_spos_scb_lib.c b/sound/pci/cs46xx/dsp_spos_scb_lib.c index 7488e1b7a770..abb01ce66983 100644 --- a/sound/pci/cs46xx/dsp_spos_scb_lib.c +++ b/sound/pci/cs46xx/dsp_spos_scb_lib.c | |||
@@ -271,7 +271,7 @@ void cs46xx_dsp_proc_register_scb_desc (struct snd_cs46xx *chip, | |||
271 | 271 | ||
272 | entry->content = SNDRV_INFO_CONTENT_TEXT; | 272 | entry->content = SNDRV_INFO_CONTENT_TEXT; |
273 | entry->private_data = scb_info; | 273 | entry->private_data = scb_info; |
274 | entry->mode = S_IFREG | S_IRUGO | S_IWUSR; | 274 | entry->mode = S_IFREG | 0644; |
275 | 275 | ||
276 | entry->c.text.read = cs46xx_dsp_proc_scb_info_read; | 276 | entry->c.text.read = cs46xx_dsp_proc_scb_info_read; |
277 | 277 | ||
diff --git a/sound/pci/ctxfi/cttimer.c b/sound/pci/ctxfi/cttimer.c index 08e874e9a7f6..2099e9ce441a 100644 --- a/sound/pci/ctxfi/cttimer.c +++ b/sound/pci/ctxfi/cttimer.c | |||
@@ -17,7 +17,7 @@ | |||
17 | 17 | ||
18 | static bool use_system_timer; | 18 | static bool use_system_timer; |
19 | MODULE_PARM_DESC(use_system_timer, "Force to use system-timer"); | 19 | MODULE_PARM_DESC(use_system_timer, "Force to use system-timer"); |
20 | module_param(use_system_timer, bool, S_IRUGO); | 20 | module_param(use_system_timer, bool, 0444); |
21 | 21 | ||
22 | struct ct_timer_ops { | 22 | struct ct_timer_ops { |
23 | void (*init)(struct ct_timer_instance *); | 23 | void (*init)(struct ct_timer_instance *); |
diff --git a/sound/pci/ctxfi/xfi.c b/sound/pci/ctxfi/xfi.c index f2f32779de98..b2874220be1b 100644 --- a/sound/pci/ctxfi/xfi.c +++ b/sound/pci/ctxfi/xfi.c | |||
@@ -26,9 +26,9 @@ MODULE_SUPPORTED_DEVICE("{{Creative Labs, Sound Blaster X-Fi}"); | |||
26 | static unsigned int reference_rate = 48000; | 26 | static unsigned int reference_rate = 48000; |
27 | static unsigned int multiple = 2; | 27 | static unsigned int multiple = 2; |
28 | MODULE_PARM_DESC(reference_rate, "Reference rate (default=48000)"); | 28 | MODULE_PARM_DESC(reference_rate, "Reference rate (default=48000)"); |
29 | module_param(reference_rate, uint, S_IRUGO); | 29 | module_param(reference_rate, uint, 0444); |
30 | MODULE_PARM_DESC(multiple, "Rate multiplier (default=2)"); | 30 | MODULE_PARM_DESC(multiple, "Rate multiplier (default=2)"); |
31 | module_param(multiple, uint, S_IRUGO); | 31 | module_param(multiple, uint, 0444); |
32 | 32 | ||
33 | static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; | 33 | static int index[SNDRV_CARDS] = SNDRV_DEFAULT_IDX; |
34 | static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; | 34 | static char *id[SNDRV_CARDS] = SNDRV_DEFAULT_STR; |
diff --git a/sound/pci/echoaudio/echoaudio.c b/sound/pci/echoaudio/echoaudio.c index 0935a5c8741f..358ef7dcf410 100644 --- a/sound/pci/echoaudio/echoaudio.c +++ b/sound/pci/echoaudio/echoaudio.c | |||
@@ -59,7 +59,7 @@ static int get_firmware(const struct firmware **fw_entry, | |||
59 | dev_dbg(chip->card->dev, | 59 | dev_dbg(chip->card->dev, |
60 | "firmware requested: %s\n", card_fw[fw_index].data); | 60 | "firmware requested: %s\n", card_fw[fw_index].data); |
61 | snprintf(name, sizeof(name), "ea/%s", card_fw[fw_index].data); | 61 | snprintf(name, sizeof(name), "ea/%s", card_fw[fw_index].data); |
62 | err = request_firmware(fw_entry, name, pci_device(chip)); | 62 | err = request_firmware(fw_entry, name, &chip->pci->dev); |
63 | if (err < 0) | 63 | if (err < 0) |
64 | dev_err(chip->card->dev, | 64 | dev_err(chip->card->dev, |
65 | "get_firmware(): Firmware not available (%d)\n", err); | 65 | "get_firmware(): Firmware not available (%d)\n", err); |
diff --git a/sound/pci/echoaudio/echoaudio.h b/sound/pci/echoaudio/echoaudio.h index 152ce158583c..44b390a667d5 100644 --- a/sound/pci/echoaudio/echoaudio.h +++ b/sound/pci/echoaudio/echoaudio.h | |||
@@ -559,10 +559,4 @@ static inline int monitor_index(const struct echoaudio *chip, int out, int in) | |||
559 | return out * num_busses_in(chip) + in; | 559 | return out * num_busses_in(chip) + in; |
560 | } | 560 | } |
561 | 561 | ||
562 | |||
563 | #ifndef pci_device | ||
564 | #define pci_device(chip) (&chip->pci->dev) | ||
565 | #endif | ||
566 | |||
567 | |||
568 | #endif /* _ECHOAUDIO_H_ */ | 562 | #endif /* _ECHOAUDIO_H_ */ |
diff --git a/sound/pci/emu10k1/emu10k1x.c b/sound/pci/emu10k1/emu10k1x.c index 2c2b12a06177..611589cbdad6 100644 --- a/sound/pci/emu10k1/emu10k1x.c +++ b/sound/pci/emu10k1/emu10k1x.c | |||
@@ -1070,7 +1070,7 @@ static int snd_emu10k1x_proc_init(struct emu10k1x *emu) | |||
1070 | if(! snd_card_proc_new(emu->card, "emu10k1x_regs", &entry)) { | 1070 | if(! snd_card_proc_new(emu->card, "emu10k1x_regs", &entry)) { |
1071 | snd_info_set_text_ops(entry, emu, snd_emu10k1x_proc_reg_read); | 1071 | snd_info_set_text_ops(entry, emu, snd_emu10k1x_proc_reg_read); |
1072 | entry->c.text.write = snd_emu10k1x_proc_reg_write; | 1072 | entry->c.text.write = snd_emu10k1x_proc_reg_write; |
1073 | entry->mode |= S_IWUSR; | 1073 | entry->mode |= 0200; |
1074 | entry->private_data = emu; | 1074 | entry->private_data = emu; |
1075 | } | 1075 | } |
1076 | 1076 | ||
diff --git a/sound/pci/emu10k1/emufx.c b/sound/pci/emu10k1/emufx.c index a2b56b188be4..b45a01bb73e5 100644 --- a/sound/pci/emu10k1/emufx.c +++ b/sound/pci/emu10k1/emufx.c | |||
@@ -170,7 +170,7 @@ static char *audigy_outs[32] = { | |||
170 | /* 0x0f */ "Rear Right", | 170 | /* 0x0f */ "Rear Right", |
171 | /* 0x10 */ "AC97 Front Left", | 171 | /* 0x10 */ "AC97 Front Left", |
172 | /* 0x11 */ "AC97 Front Right", | 172 | /* 0x11 */ "AC97 Front Right", |
173 | /* 0x12 */ "ADC Caputre Left", | 173 | /* 0x12 */ "ADC Capture Left", |
174 | /* 0x13 */ "ADC Capture Right", | 174 | /* 0x13 */ "ADC Capture Right", |
175 | /* 0x14 */ NULL, | 175 | /* 0x14 */ NULL, |
176 | /* 0x15 */ NULL, | 176 | /* 0x15 */ NULL, |
@@ -421,14 +421,10 @@ int snd_emu10k1_fx8010_register_irq_handler(struct snd_emu10k1 *emu, | |||
421 | snd_fx8010_irq_handler_t *handler, | 421 | snd_fx8010_irq_handler_t *handler, |
422 | unsigned char gpr_running, | 422 | unsigned char gpr_running, |
423 | void *private_data, | 423 | void *private_data, |
424 | struct snd_emu10k1_fx8010_irq **r_irq) | 424 | struct snd_emu10k1_fx8010_irq *irq) |
425 | { | 425 | { |
426 | struct snd_emu10k1_fx8010_irq *irq; | ||
427 | unsigned long flags; | 426 | unsigned long flags; |
428 | 427 | ||
429 | irq = kmalloc(sizeof(*irq), GFP_ATOMIC); | ||
430 | if (irq == NULL) | ||
431 | return -ENOMEM; | ||
432 | irq->handler = handler; | 428 | irq->handler = handler; |
433 | irq->gpr_running = gpr_running; | 429 | irq->gpr_running = gpr_running; |
434 | irq->private_data = private_data; | 430 | irq->private_data = private_data; |
@@ -443,8 +439,6 @@ int snd_emu10k1_fx8010_register_irq_handler(struct snd_emu10k1 *emu, | |||
443 | emu->fx8010.irq_handlers = irq; | 439 | emu->fx8010.irq_handlers = irq; |
444 | } | 440 | } |
445 | spin_unlock_irqrestore(&emu->fx8010.irq_lock, flags); | 441 | spin_unlock_irqrestore(&emu->fx8010.irq_lock, flags); |
446 | if (r_irq) | ||
447 | *r_irq = irq; | ||
448 | return 0; | 442 | return 0; |
449 | } | 443 | } |
450 | 444 | ||
@@ -468,7 +462,6 @@ int snd_emu10k1_fx8010_unregister_irq_handler(struct snd_emu10k1 *emu, | |||
468 | tmp->next = tmp->next->next; | 462 | tmp->next = tmp->next->next; |
469 | } | 463 | } |
470 | spin_unlock_irqrestore(&emu->fx8010.irq_lock, flags); | 464 | spin_unlock_irqrestore(&emu->fx8010.irq_lock, flags); |
471 | kfree(irq); | ||
472 | return 0; | 465 | return 0; |
473 | } | 466 | } |
474 | 467 | ||
diff --git a/sound/pci/emu10k1/emupcm.c b/sound/pci/emu10k1/emupcm.c index cefe613ef7b7..d39458ab251f 100644 --- a/sound/pci/emu10k1/emupcm.c +++ b/sound/pci/emu10k1/emupcm.c | |||
@@ -1724,7 +1724,7 @@ static int snd_emu10k1_fx8010_playback_trigger(struct snd_pcm_substream *substre | |||
1724 | case SNDRV_PCM_TRIGGER_STOP: | 1724 | case SNDRV_PCM_TRIGGER_STOP: |
1725 | case SNDRV_PCM_TRIGGER_PAUSE_PUSH: | 1725 | case SNDRV_PCM_TRIGGER_PAUSE_PUSH: |
1726 | case SNDRV_PCM_TRIGGER_SUSPEND: | 1726 | case SNDRV_PCM_TRIGGER_SUSPEND: |
1727 | snd_emu10k1_fx8010_unregister_irq_handler(emu, pcm->irq); pcm->irq = NULL; | 1727 | snd_emu10k1_fx8010_unregister_irq_handler(emu, &pcm->irq); |
1728 | snd_emu10k1_ptr_write(emu, emu->gpr_base + pcm->gpr_trigger, 0, 0); | 1728 | snd_emu10k1_ptr_write(emu, emu->gpr_base + pcm->gpr_trigger, 0, 0); |
1729 | pcm->tram_pos = INITIAL_TRAM_POS(pcm->buffer_size); | 1729 | pcm->tram_pos = INITIAL_TRAM_POS(pcm->buffer_size); |
1730 | pcm->tram_shift = 0; | 1730 | pcm->tram_shift = 0; |
diff --git a/sound/pci/emu10k1/emuproc.c b/sound/pci/emu10k1/emuproc.c index bde0d1954f56..b57008031792 100644 --- a/sound/pci/emu10k1/emuproc.c +++ b/sound/pci/emu10k1/emuproc.c | |||
@@ -135,7 +135,7 @@ static void snd_emu10k1_proc_read(struct snd_info_entry *entry, | |||
135 | /* 15 */ "Rear Right", | 135 | /* 15 */ "Rear Right", |
136 | /* 16 */ "AC97 Front Left", | 136 | /* 16 */ "AC97 Front Left", |
137 | /* 17 */ "AC97 Front Right", | 137 | /* 17 */ "AC97 Front Right", |
138 | /* 18 */ "ADC Caputre Left", | 138 | /* 18 */ "ADC Capture Left", |
139 | /* 19 */ "ADC Capture Right", | 139 | /* 19 */ "ADC Capture Right", |
140 | /* 20 */ "???", | 140 | /* 20 */ "???", |
141 | /* 21 */ "???", | 141 | /* 21 */ "???", |
@@ -574,32 +574,32 @@ int snd_emu10k1_proc_init(struct snd_emu10k1 *emu) | |||
574 | if (! snd_card_proc_new(emu->card, "io_regs", &entry)) { | 574 | if (! snd_card_proc_new(emu->card, "io_regs", &entry)) { |
575 | snd_info_set_text_ops(entry, emu, snd_emu_proc_io_reg_read); | 575 | snd_info_set_text_ops(entry, emu, snd_emu_proc_io_reg_read); |
576 | entry->c.text.write = snd_emu_proc_io_reg_write; | 576 | entry->c.text.write = snd_emu_proc_io_reg_write; |
577 | entry->mode |= S_IWUSR; | 577 | entry->mode |= 0200; |
578 | } | 578 | } |
579 | if (! snd_card_proc_new(emu->card, "ptr_regs00a", &entry)) { | 579 | if (! snd_card_proc_new(emu->card, "ptr_regs00a", &entry)) { |
580 | snd_info_set_text_ops(entry, emu, snd_emu_proc_ptr_reg_read00a); | 580 | snd_info_set_text_ops(entry, emu, snd_emu_proc_ptr_reg_read00a); |
581 | entry->c.text.write = snd_emu_proc_ptr_reg_write00; | 581 | entry->c.text.write = snd_emu_proc_ptr_reg_write00; |
582 | entry->mode |= S_IWUSR; | 582 | entry->mode |= 0200; |
583 | } | 583 | } |
584 | if (! snd_card_proc_new(emu->card, "ptr_regs00b", &entry)) { | 584 | if (! snd_card_proc_new(emu->card, "ptr_regs00b", &entry)) { |
585 | snd_info_set_text_ops(entry, emu, snd_emu_proc_ptr_reg_read00b); | 585 | snd_info_set_text_ops(entry, emu, snd_emu_proc_ptr_reg_read00b); |
586 | entry->c.text.write = snd_emu_proc_ptr_reg_write00; | 586 | entry->c.text.write = snd_emu_proc_ptr_reg_write00; |
587 | entry->mode |= S_IWUSR; | 587 | entry->mode |= 0200; |
588 | } | 588 | } |
589 | if (! snd_card_proc_new(emu->card, "ptr_regs20a", &entry)) { | 589 | if (! snd_card_proc_new(emu->card, "ptr_regs20a", &entry)) { |
590 | snd_info_set_text_ops(entry, emu, snd_emu_proc_ptr_reg_read20a); | 590 | snd_info_set_text_ops(entry, emu, snd_emu_proc_ptr_reg_read20a); |
591 | entry->c.text.write = snd_emu_proc_ptr_reg_write20; | 591 | entry->c.text.write = snd_emu_proc_ptr_reg_write20; |
592 | entry->mode |= S_IWUSR; | 592 | entry->mode |= 0200; |
593 | } | 593 | } |
594 | if (! snd_card_proc_new(emu->card, "ptr_regs20b", &entry)) { | 594 | if (! snd_card_proc_new(emu->card, "ptr_regs20b", &entry)) { |
595 | snd_info_set_text_ops(entry, emu, snd_emu_proc_ptr_reg_read20b); | 595 | snd_info_set_text_ops(entry, emu, snd_emu_proc_ptr_reg_read20b); |
596 | entry->c.text.write = snd_emu_proc_ptr_reg_write20; | 596 | entry->c.text.write = snd_emu_proc_ptr_reg_write20; |
597 | entry->mode |= S_IWUSR; | 597 | entry->mode |= 0200; |
598 | } | 598 | } |
599 | if (! snd_card_proc_new(emu->card, "ptr_regs20c", &entry)) { | 599 | if (! snd_card_proc_new(emu->card, "ptr_regs20c", &entry)) { |
600 | snd_info_set_text_ops(entry, emu, snd_emu_proc_ptr_reg_read20c); | 600 | snd_info_set_text_ops(entry, emu, snd_emu_proc_ptr_reg_read20c); |
601 | entry->c.text.write = snd_emu_proc_ptr_reg_write20; | 601 | entry->c.text.write = snd_emu_proc_ptr_reg_write20; |
602 | entry->mode |= S_IWUSR; | 602 | entry->mode |= 0200; |
603 | } | 603 | } |
604 | #endif | 604 | #endif |
605 | 605 | ||
@@ -621,35 +621,35 @@ int snd_emu10k1_proc_init(struct snd_emu10k1 *emu) | |||
621 | if (! snd_card_proc_new(emu->card, "fx8010_gpr", &entry)) { | 621 | if (! snd_card_proc_new(emu->card, "fx8010_gpr", &entry)) { |
622 | entry->content = SNDRV_INFO_CONTENT_DATA; | 622 | entry->content = SNDRV_INFO_CONTENT_DATA; |
623 | entry->private_data = emu; | 623 | entry->private_data = emu; |
624 | entry->mode = S_IFREG | S_IRUGO /*| S_IWUSR*/; | 624 | entry->mode = S_IFREG | 0444 /*| S_IWUSR*/; |
625 | entry->size = emu->audigy ? A_TOTAL_SIZE_GPR : TOTAL_SIZE_GPR; | 625 | entry->size = emu->audigy ? A_TOTAL_SIZE_GPR : TOTAL_SIZE_GPR; |
626 | entry->c.ops = &snd_emu10k1_proc_ops_fx8010; | 626 | entry->c.ops = &snd_emu10k1_proc_ops_fx8010; |
627 | } | 627 | } |
628 | if (! snd_card_proc_new(emu->card, "fx8010_tram_data", &entry)) { | 628 | if (! snd_card_proc_new(emu->card, "fx8010_tram_data", &entry)) { |
629 | entry->content = SNDRV_INFO_CONTENT_DATA; | 629 | entry->content = SNDRV_INFO_CONTENT_DATA; |
630 | entry->private_data = emu; | 630 | entry->private_data = emu; |
631 | entry->mode = S_IFREG | S_IRUGO /*| S_IWUSR*/; | 631 | entry->mode = S_IFREG | 0444 /*| S_IWUSR*/; |
632 | entry->size = emu->audigy ? A_TOTAL_SIZE_TANKMEM_DATA : TOTAL_SIZE_TANKMEM_DATA ; | 632 | entry->size = emu->audigy ? A_TOTAL_SIZE_TANKMEM_DATA : TOTAL_SIZE_TANKMEM_DATA ; |
633 | entry->c.ops = &snd_emu10k1_proc_ops_fx8010; | 633 | entry->c.ops = &snd_emu10k1_proc_ops_fx8010; |
634 | } | 634 | } |
635 | if (! snd_card_proc_new(emu->card, "fx8010_tram_addr", &entry)) { | 635 | if (! snd_card_proc_new(emu->card, "fx8010_tram_addr", &entry)) { |
636 | entry->content = SNDRV_INFO_CONTENT_DATA; | 636 | entry->content = SNDRV_INFO_CONTENT_DATA; |
637 | entry->private_data = emu; | 637 | entry->private_data = emu; |
638 | entry->mode = S_IFREG | S_IRUGO /*| S_IWUSR*/; | 638 | entry->mode = S_IFREG | 0444 /*| S_IWUSR*/; |
639 | entry->size = emu->audigy ? A_TOTAL_SIZE_TANKMEM_ADDR : TOTAL_SIZE_TANKMEM_ADDR ; | 639 | entry->size = emu->audigy ? A_TOTAL_SIZE_TANKMEM_ADDR : TOTAL_SIZE_TANKMEM_ADDR ; |
640 | entry->c.ops = &snd_emu10k1_proc_ops_fx8010; | 640 | entry->c.ops = &snd_emu10k1_proc_ops_fx8010; |
641 | } | 641 | } |
642 | if (! snd_card_proc_new(emu->card, "fx8010_code", &entry)) { | 642 | if (! snd_card_proc_new(emu->card, "fx8010_code", &entry)) { |
643 | entry->content = SNDRV_INFO_CONTENT_DATA; | 643 | entry->content = SNDRV_INFO_CONTENT_DATA; |
644 | entry->private_data = emu; | 644 | entry->private_data = emu; |
645 | entry->mode = S_IFREG | S_IRUGO /*| S_IWUSR*/; | 645 | entry->mode = S_IFREG | 0444 /*| S_IWUSR*/; |
646 | entry->size = emu->audigy ? A_TOTAL_SIZE_CODE : TOTAL_SIZE_CODE; | 646 | entry->size = emu->audigy ? A_TOTAL_SIZE_CODE : TOTAL_SIZE_CODE; |
647 | entry->c.ops = &snd_emu10k1_proc_ops_fx8010; | 647 | entry->c.ops = &snd_emu10k1_proc_ops_fx8010; |
648 | } | 648 | } |
649 | if (! snd_card_proc_new(emu->card, "fx8010_acode", &entry)) { | 649 | if (! snd_card_proc_new(emu->card, "fx8010_acode", &entry)) { |
650 | entry->content = SNDRV_INFO_CONTENT_TEXT; | 650 | entry->content = SNDRV_INFO_CONTENT_TEXT; |
651 | entry->private_data = emu; | 651 | entry->private_data = emu; |
652 | entry->mode = S_IFREG | S_IRUGO /*| S_IWUSR*/; | 652 | entry->mode = S_IFREG | 0444 /*| S_IWUSR*/; |
653 | entry->c.text.read = snd_emu10k1_proc_acode_read; | 653 | entry->c.text.read = snd_emu10k1_proc_acode_read; |
654 | } | 654 | } |
655 | return 0; | 655 | return 0; |
diff --git a/sound/pci/emu10k1/memory.c b/sound/pci/emu10k1/memory.c index 5865f3b90b34..dbc7d8d0e1c4 100644 --- a/sound/pci/emu10k1/memory.c +++ b/sound/pci/emu10k1/memory.c | |||
@@ -248,13 +248,13 @@ __found_pages: | |||
248 | static int is_valid_page(struct snd_emu10k1 *emu, dma_addr_t addr) | 248 | static int is_valid_page(struct snd_emu10k1 *emu, dma_addr_t addr) |
249 | { | 249 | { |
250 | if (addr & ~emu->dma_mask) { | 250 | if (addr & ~emu->dma_mask) { |
251 | dev_err(emu->card->dev, | 251 | dev_err_ratelimited(emu->card->dev, |
252 | "max memory size is 0x%lx (addr = 0x%lx)!!\n", | 252 | "max memory size is 0x%lx (addr = 0x%lx)!!\n", |
253 | emu->dma_mask, (unsigned long)addr); | 253 | emu->dma_mask, (unsigned long)addr); |
254 | return 0; | 254 | return 0; |
255 | } | 255 | } |
256 | if (addr & (EMUPAGESIZE-1)) { | 256 | if (addr & (EMUPAGESIZE-1)) { |
257 | dev_err(emu->card->dev, "page is not aligned\n"); | 257 | dev_err_ratelimited(emu->card->dev, "page is not aligned\n"); |
258 | return 0; | 258 | return 0; |
259 | } | 259 | } |
260 | return 1; | 260 | return 1; |
@@ -345,7 +345,7 @@ snd_emu10k1_alloc_pages(struct snd_emu10k1 *emu, struct snd_pcm_substream *subst | |||
345 | else | 345 | else |
346 | addr = snd_pcm_sgbuf_get_addr(substream, ofs); | 346 | addr = snd_pcm_sgbuf_get_addr(substream, ofs); |
347 | if (! is_valid_page(emu, addr)) { | 347 | if (! is_valid_page(emu, addr)) { |
348 | dev_err(emu->card->dev, | 348 | dev_err_ratelimited(emu->card->dev, |
349 | "emu: failure page = %d\n", idx); | 349 | "emu: failure page = %d\n", idx); |
350 | mutex_unlock(&hdr->block_mutex); | 350 | mutex_unlock(&hdr->block_mutex); |
351 | return NULL; | 351 | return NULL; |
diff --git a/sound/pci/hda/Kconfig b/sound/pci/hda/Kconfig index f7a492c382d9..4235907b7858 100644 --- a/sound/pci/hda/Kconfig +++ b/sound/pci/hda/Kconfig | |||
@@ -127,11 +127,15 @@ comment "Set to Y if you want auto-loading the codec driver" | |||
127 | 127 | ||
128 | config SND_HDA_CODEC_HDMI | 128 | config SND_HDA_CODEC_HDMI |
129 | tristate "Build HDMI/DisplayPort HD-audio codec support" | 129 | tristate "Build HDMI/DisplayPort HD-audio codec support" |
130 | select SND_DYNAMIC_MINORS | ||
130 | help | 131 | help |
131 | Say Y or M here to include HDMI and DisplayPort HD-audio codec | 132 | Say Y or M here to include HDMI and DisplayPort HD-audio codec |
132 | support in snd-hda-intel driver. This includes all AMD/ATI, | 133 | support in snd-hda-intel driver. This includes all AMD/ATI, |
133 | Intel and Nvidia HDMI/DisplayPort codecs. | 134 | Intel and Nvidia HDMI/DisplayPort codecs. |
134 | 135 | ||
136 | Note that this option mandatorily enables CONFIG_SND_DYNAMIC_MINORS | ||
137 | to assure the multiple streams for DP-MST support. | ||
138 | |||
135 | comment "Set to Y if you want auto-loading the codec driver" | 139 | comment "Set to Y if you want auto-loading the codec driver" |
136 | depends on SND_HDA=y && SND_HDA_CODEC_HDMI=m | 140 | depends on SND_HDA=y && SND_HDA_CODEC_HDMI=m |
137 | 141 | ||
diff --git a/sound/pci/hda/hda_auto_parser.c b/sound/pci/hda/hda_auto_parser.c index d3ea73171a3d..b9a6b66aeb0e 100644 --- a/sound/pci/hda/hda_auto_parser.c +++ b/sound/pci/hda/hda_auto_parser.c | |||
@@ -793,11 +793,11 @@ EXPORT_SYMBOL_GPL(snd_hda_add_verbs); | |||
793 | */ | 793 | */ |
794 | void snd_hda_apply_verbs(struct hda_codec *codec) | 794 | void snd_hda_apply_verbs(struct hda_codec *codec) |
795 | { | 795 | { |
796 | const struct hda_verb **v; | ||
796 | int i; | 797 | int i; |
797 | for (i = 0; i < codec->verbs.used; i++) { | 798 | |
798 | struct hda_verb **v = snd_array_elem(&codec->verbs, i); | 799 | snd_array_for_each(&codec->verbs, i, v) |
799 | snd_hda_sequence_write(codec, *v); | 800 | snd_hda_sequence_write(codec, *v); |
800 | } | ||
801 | } | 801 | } |
802 | EXPORT_SYMBOL_GPL(snd_hda_apply_verbs); | 802 | EXPORT_SYMBOL_GPL(snd_hda_apply_verbs); |
803 | 803 | ||
@@ -890,10 +890,10 @@ EXPORT_SYMBOL_GPL(snd_hda_apply_fixup); | |||
890 | static bool pin_config_match(struct hda_codec *codec, | 890 | static bool pin_config_match(struct hda_codec *codec, |
891 | const struct hda_pintbl *pins) | 891 | const struct hda_pintbl *pins) |
892 | { | 892 | { |
893 | const struct hda_pincfg *pin; | ||
893 | int i; | 894 | int i; |
894 | 895 | ||
895 | for (i = 0; i < codec->init_pins.used; i++) { | 896 | snd_array_for_each(&codec->init_pins, i, pin) { |
896 | struct hda_pincfg *pin = snd_array_elem(&codec->init_pins, i); | ||
897 | hda_nid_t nid = pin->nid; | 897 | hda_nid_t nid = pin->nid; |
898 | u32 cfg = pin->cfg; | 898 | u32 cfg = pin->cfg; |
899 | const struct hda_pintbl *t_pins; | 899 | const struct hda_pintbl *t_pins; |
diff --git a/sound/pci/hda/hda_codec.c b/sound/pci/hda/hda_codec.c index 5bc3a7468e17..08151f3c0b13 100644 --- a/sound/pci/hda/hda_codec.c +++ b/sound/pci/hda/hda_codec.c | |||
@@ -481,9 +481,10 @@ static struct hda_pincfg *look_up_pincfg(struct hda_codec *codec, | |||
481 | struct snd_array *array, | 481 | struct snd_array *array, |
482 | hda_nid_t nid) | 482 | hda_nid_t nid) |
483 | { | 483 | { |
484 | struct hda_pincfg *pin; | ||
484 | int i; | 485 | int i; |
485 | for (i = 0; i < array->used; i++) { | 486 | |
486 | struct hda_pincfg *pin = snd_array_elem(array, i); | 487 | snd_array_for_each(array, i, pin) { |
487 | if (pin->nid == nid) | 488 | if (pin->nid == nid) |
488 | return pin; | 489 | return pin; |
489 | } | 490 | } |
@@ -618,14 +619,15 @@ EXPORT_SYMBOL_GPL(snd_hda_codec_get_pin_target); | |||
618 | */ | 619 | */ |
619 | void snd_hda_shutup_pins(struct hda_codec *codec) | 620 | void snd_hda_shutup_pins(struct hda_codec *codec) |
620 | { | 621 | { |
622 | const struct hda_pincfg *pin; | ||
621 | int i; | 623 | int i; |
624 | |||
622 | /* don't shut up pins when unloading the driver; otherwise it breaks | 625 | /* don't shut up pins when unloading the driver; otherwise it breaks |
623 | * the default pin setup at the next load of the driver | 626 | * the default pin setup at the next load of the driver |
624 | */ | 627 | */ |
625 | if (codec->bus->shutdown) | 628 | if (codec->bus->shutdown) |
626 | return; | 629 | return; |
627 | for (i = 0; i < codec->init_pins.used; i++) { | 630 | snd_array_for_each(&codec->init_pins, i, pin) { |
628 | struct hda_pincfg *pin = snd_array_elem(&codec->init_pins, i); | ||
629 | /* use read here for syncing after issuing each verb */ | 631 | /* use read here for syncing after issuing each verb */ |
630 | snd_hda_codec_read(codec, pin->nid, 0, | 632 | snd_hda_codec_read(codec, pin->nid, 0, |
631 | AC_VERB_SET_PIN_WIDGET_CONTROL, 0); | 633 | AC_VERB_SET_PIN_WIDGET_CONTROL, 0); |
@@ -638,13 +640,14 @@ EXPORT_SYMBOL_GPL(snd_hda_shutup_pins); | |||
638 | /* Restore the pin controls cleared previously via snd_hda_shutup_pins() */ | 640 | /* Restore the pin controls cleared previously via snd_hda_shutup_pins() */ |
639 | static void restore_shutup_pins(struct hda_codec *codec) | 641 | static void restore_shutup_pins(struct hda_codec *codec) |
640 | { | 642 | { |
643 | const struct hda_pincfg *pin; | ||
641 | int i; | 644 | int i; |
645 | |||
642 | if (!codec->pins_shutup) | 646 | if (!codec->pins_shutup) |
643 | return; | 647 | return; |
644 | if (codec->bus->shutdown) | 648 | if (codec->bus->shutdown) |
645 | return; | 649 | return; |
646 | for (i = 0; i < codec->init_pins.used; i++) { | 650 | snd_array_for_each(&codec->init_pins, i, pin) { |
647 | struct hda_pincfg *pin = snd_array_elem(&codec->init_pins, i); | ||
648 | snd_hda_codec_write(codec, pin->nid, 0, | 651 | snd_hda_codec_write(codec, pin->nid, 0, |
649 | AC_VERB_SET_PIN_WIDGET_CONTROL, | 652 | AC_VERB_SET_PIN_WIDGET_CONTROL, |
650 | pin->ctrl); | 653 | pin->ctrl); |
@@ -697,8 +700,7 @@ get_hda_cvt_setup(struct hda_codec *codec, hda_nid_t nid) | |||
697 | struct hda_cvt_setup *p; | 700 | struct hda_cvt_setup *p; |
698 | int i; | 701 | int i; |
699 | 702 | ||
700 | for (i = 0; i < codec->cvt_setups.used; i++) { | 703 | snd_array_for_each(&codec->cvt_setups, i, p) { |
701 | p = snd_array_elem(&codec->cvt_setups, i); | ||
702 | if (p->nid == nid) | 704 | if (p->nid == nid) |
703 | return p; | 705 | return p; |
704 | } | 706 | } |
@@ -1076,8 +1078,7 @@ void snd_hda_codec_setup_stream(struct hda_codec *codec, hda_nid_t nid, | |||
1076 | /* make other inactive cvts with the same stream-tag dirty */ | 1078 | /* make other inactive cvts with the same stream-tag dirty */ |
1077 | type = get_wcaps_type(get_wcaps(codec, nid)); | 1079 | type = get_wcaps_type(get_wcaps(codec, nid)); |
1078 | list_for_each_codec(c, codec->bus) { | 1080 | list_for_each_codec(c, codec->bus) { |
1079 | for (i = 0; i < c->cvt_setups.used; i++) { | 1081 | snd_array_for_each(&c->cvt_setups, i, p) { |
1080 | p = snd_array_elem(&c->cvt_setups, i); | ||
1081 | if (!p->active && p->stream_tag == stream_tag && | 1082 | if (!p->active && p->stream_tag == stream_tag && |
1082 | get_wcaps_type(get_wcaps(c, p->nid)) == type) | 1083 | get_wcaps_type(get_wcaps(c, p->nid)) == type) |
1083 | p->dirty = 1; | 1084 | p->dirty = 1; |
@@ -1140,12 +1141,11 @@ static void really_cleanup_stream(struct hda_codec *codec, | |||
1140 | static void purify_inactive_streams(struct hda_codec *codec) | 1141 | static void purify_inactive_streams(struct hda_codec *codec) |
1141 | { | 1142 | { |
1142 | struct hda_codec *c; | 1143 | struct hda_codec *c; |
1144 | struct hda_cvt_setup *p; | ||
1143 | int i; | 1145 | int i; |
1144 | 1146 | ||
1145 | list_for_each_codec(c, codec->bus) { | 1147 | list_for_each_codec(c, codec->bus) { |
1146 | for (i = 0; i < c->cvt_setups.used; i++) { | 1148 | snd_array_for_each(&c->cvt_setups, i, p) { |
1147 | struct hda_cvt_setup *p; | ||
1148 | p = snd_array_elem(&c->cvt_setups, i); | ||
1149 | if (p->dirty) | 1149 | if (p->dirty) |
1150 | really_cleanup_stream(c, p); | 1150 | really_cleanup_stream(c, p); |
1151 | } | 1151 | } |
@@ -1156,10 +1156,10 @@ static void purify_inactive_streams(struct hda_codec *codec) | |||
1156 | /* clean up all streams; called from suspend */ | 1156 | /* clean up all streams; called from suspend */ |
1157 | static void hda_cleanup_all_streams(struct hda_codec *codec) | 1157 | static void hda_cleanup_all_streams(struct hda_codec *codec) |
1158 | { | 1158 | { |
1159 | struct hda_cvt_setup *p; | ||
1159 | int i; | 1160 | int i; |
1160 | 1161 | ||
1161 | for (i = 0; i < codec->cvt_setups.used; i++) { | 1162 | snd_array_for_each(&codec->cvt_setups, i, p) { |
1162 | struct hda_cvt_setup *p = snd_array_elem(&codec->cvt_setups, i); | ||
1163 | if (p->stream_tag) | 1163 | if (p->stream_tag) |
1164 | really_cleanup_stream(codec, p); | 1164 | really_cleanup_stream(codec, p); |
1165 | } | 1165 | } |
@@ -1493,10 +1493,10 @@ static void get_ctl_amp_tlv(struct snd_kcontrol *kcontrol, unsigned int *tlv) | |||
1493 | val1 = ((int)val1) * ((int)val2); | 1493 | val1 = ((int)val1) * ((int)val2); |
1494 | if (min_mute || (caps & AC_AMPCAP_MIN_MUTE)) | 1494 | if (min_mute || (caps & AC_AMPCAP_MIN_MUTE)) |
1495 | val2 |= TLV_DB_SCALE_MUTE; | 1495 | val2 |= TLV_DB_SCALE_MUTE; |
1496 | tlv[0] = SNDRV_CTL_TLVT_DB_SCALE; | 1496 | tlv[SNDRV_CTL_TLVO_TYPE] = SNDRV_CTL_TLVT_DB_SCALE; |
1497 | tlv[1] = 2 * sizeof(unsigned int); | 1497 | tlv[SNDRV_CTL_TLVO_LEN] = 2 * sizeof(unsigned int); |
1498 | tlv[2] = val1; | 1498 | tlv[SNDRV_CTL_TLVO_DB_SCALE_MIN] = val1; |
1499 | tlv[3] = val2; | 1499 | tlv[SNDRV_CTL_TLVO_DB_SCALE_MUTE_AND_STEP] = val2; |
1500 | } | 1500 | } |
1501 | 1501 | ||
1502 | /** | 1502 | /** |
@@ -1544,10 +1544,10 @@ void snd_hda_set_vmaster_tlv(struct hda_codec *codec, hda_nid_t nid, int dir, | |||
1544 | nums = (caps & AC_AMPCAP_NUM_STEPS) >> AC_AMPCAP_NUM_STEPS_SHIFT; | 1544 | nums = (caps & AC_AMPCAP_NUM_STEPS) >> AC_AMPCAP_NUM_STEPS_SHIFT; |
1545 | step = (caps & AC_AMPCAP_STEP_SIZE) >> AC_AMPCAP_STEP_SIZE_SHIFT; | 1545 | step = (caps & AC_AMPCAP_STEP_SIZE) >> AC_AMPCAP_STEP_SIZE_SHIFT; |
1546 | step = (step + 1) * 25; | 1546 | step = (step + 1) * 25; |
1547 | tlv[0] = SNDRV_CTL_TLVT_DB_SCALE; | 1547 | tlv[SNDRV_CTL_TLVO_TYPE] = SNDRV_CTL_TLVT_DB_SCALE; |
1548 | tlv[1] = 2 * sizeof(unsigned int); | 1548 | tlv[SNDRV_CTL_TLVO_LEN] = 2 * sizeof(unsigned int); |
1549 | tlv[2] = -nums * step; | 1549 | tlv[SNDRV_CTL_TLVO_DB_SCALE_MIN] = -nums * step; |
1550 | tlv[3] = step; | 1550 | tlv[SNDRV_CTL_TLVO_DB_SCALE_MUTE_AND_STEP] = step; |
1551 | } | 1551 | } |
1552 | EXPORT_SYMBOL_GPL(snd_hda_set_vmaster_tlv); | 1552 | EXPORT_SYMBOL_GPL(snd_hda_set_vmaster_tlv); |
1553 | 1553 | ||
@@ -1845,10 +1845,10 @@ static int init_slave_0dB(struct snd_kcontrol *slave, | |||
1845 | } else if (kctl->vd[0].access & SNDRV_CTL_ELEM_ACCESS_TLV_READ) | 1845 | } else if (kctl->vd[0].access & SNDRV_CTL_ELEM_ACCESS_TLV_READ) |
1846 | tlv = kctl->tlv.p; | 1846 | tlv = kctl->tlv.p; |
1847 | 1847 | ||
1848 | if (!tlv || tlv[0] != SNDRV_CTL_TLVT_DB_SCALE) | 1848 | if (!tlv || tlv[SNDRV_CTL_TLVO_TYPE] != SNDRV_CTL_TLVT_DB_SCALE) |
1849 | return 0; | 1849 | return 0; |
1850 | 1850 | ||
1851 | step = tlv[3]; | 1851 | step = tlv[SNDRV_CTL_TLVO_DB_SCALE_MUTE_AND_STEP]; |
1852 | step &= ~TLV_DB_SCALE_MUTE; | 1852 | step &= ~TLV_DB_SCALE_MUTE; |
1853 | if (!step) | 1853 | if (!step) |
1854 | return 0; | 1854 | return 0; |
@@ -1860,7 +1860,7 @@ static int init_slave_0dB(struct snd_kcontrol *slave, | |||
1860 | } | 1860 | } |
1861 | 1861 | ||
1862 | arg->step = step; | 1862 | arg->step = step; |
1863 | val = -tlv[2] / step; | 1863 | val = -tlv[SNDRV_CTL_TLVO_DB_SCALE_MIN] / step; |
1864 | if (val > 0) { | 1864 | if (val > 0) { |
1865 | put_kctl_with_value(slave, val); | 1865 | put_kctl_with_value(slave, val); |
1866 | return val; | 1866 | return val; |
@@ -2175,6 +2175,8 @@ static int snd_hda_spdif_default_get(struct snd_kcontrol *kcontrol, | |||
2175 | int idx = kcontrol->private_value; | 2175 | int idx = kcontrol->private_value; |
2176 | struct hda_spdif_out *spdif; | 2176 | struct hda_spdif_out *spdif; |
2177 | 2177 | ||
2178 | if (WARN_ON(codec->spdif_out.used <= idx)) | ||
2179 | return -EINVAL; | ||
2178 | mutex_lock(&codec->spdif_mutex); | 2180 | mutex_lock(&codec->spdif_mutex); |
2179 | spdif = snd_array_elem(&codec->spdif_out, idx); | 2181 | spdif = snd_array_elem(&codec->spdif_out, idx); |
2180 | ucontrol->value.iec958.status[0] = spdif->status & 0xff; | 2182 | ucontrol->value.iec958.status[0] = spdif->status & 0xff; |
@@ -2282,6 +2284,8 @@ static int snd_hda_spdif_default_put(struct snd_kcontrol *kcontrol, | |||
2282 | unsigned short val; | 2284 | unsigned short val; |
2283 | int change; | 2285 | int change; |
2284 | 2286 | ||
2287 | if (WARN_ON(codec->spdif_out.used <= idx)) | ||
2288 | return -EINVAL; | ||
2285 | mutex_lock(&codec->spdif_mutex); | 2289 | mutex_lock(&codec->spdif_mutex); |
2286 | spdif = snd_array_elem(&codec->spdif_out, idx); | 2290 | spdif = snd_array_elem(&codec->spdif_out, idx); |
2287 | nid = spdif->nid; | 2291 | nid = spdif->nid; |
@@ -2308,6 +2312,8 @@ static int snd_hda_spdif_out_switch_get(struct snd_kcontrol *kcontrol, | |||
2308 | int idx = kcontrol->private_value; | 2312 | int idx = kcontrol->private_value; |
2309 | struct hda_spdif_out *spdif; | 2313 | struct hda_spdif_out *spdif; |
2310 | 2314 | ||
2315 | if (WARN_ON(codec->spdif_out.used <= idx)) | ||
2316 | return -EINVAL; | ||
2311 | mutex_lock(&codec->spdif_mutex); | 2317 | mutex_lock(&codec->spdif_mutex); |
2312 | spdif = snd_array_elem(&codec->spdif_out, idx); | 2318 | spdif = snd_array_elem(&codec->spdif_out, idx); |
2313 | ucontrol->value.integer.value[0] = spdif->ctls & AC_DIG1_ENABLE; | 2319 | ucontrol->value.integer.value[0] = spdif->ctls & AC_DIG1_ENABLE; |
@@ -2336,6 +2342,8 @@ static int snd_hda_spdif_out_switch_put(struct snd_kcontrol *kcontrol, | |||
2336 | unsigned short val; | 2342 | unsigned short val; |
2337 | int change; | 2343 | int change; |
2338 | 2344 | ||
2345 | if (WARN_ON(codec->spdif_out.used <= idx)) | ||
2346 | return -EINVAL; | ||
2339 | mutex_lock(&codec->spdif_mutex); | 2347 | mutex_lock(&codec->spdif_mutex); |
2340 | spdif = snd_array_elem(&codec->spdif_out, idx); | 2348 | spdif = snd_array_elem(&codec->spdif_out, idx); |
2341 | nid = spdif->nid; | 2349 | nid = spdif->nid; |
@@ -2461,10 +2469,10 @@ EXPORT_SYMBOL_GPL(snd_hda_create_dig_out_ctls); | |||
2461 | struct hda_spdif_out *snd_hda_spdif_out_of_nid(struct hda_codec *codec, | 2469 | struct hda_spdif_out *snd_hda_spdif_out_of_nid(struct hda_codec *codec, |
2462 | hda_nid_t nid) | 2470 | hda_nid_t nid) |
2463 | { | 2471 | { |
2472 | struct hda_spdif_out *spdif; | ||
2464 | int i; | 2473 | int i; |
2465 | for (i = 0; i < codec->spdif_out.used; i++) { | 2474 | |
2466 | struct hda_spdif_out *spdif = | 2475 | snd_array_for_each(&codec->spdif_out, i, spdif) { |
2467 | snd_array_elem(&codec->spdif_out, i); | ||
2468 | if (spdif->nid == nid) | 2476 | if (spdif->nid == nid) |
2469 | return spdif; | 2477 | return spdif; |
2470 | } | 2478 | } |
@@ -2483,6 +2491,8 @@ void snd_hda_spdif_ctls_unassign(struct hda_codec *codec, int idx) | |||
2483 | { | 2491 | { |
2484 | struct hda_spdif_out *spdif; | 2492 | struct hda_spdif_out *spdif; |
2485 | 2493 | ||
2494 | if (WARN_ON(codec->spdif_out.used <= idx)) | ||
2495 | return; | ||
2486 | mutex_lock(&codec->spdif_mutex); | 2496 | mutex_lock(&codec->spdif_mutex); |
2487 | spdif = snd_array_elem(&codec->spdif_out, idx); | 2497 | spdif = snd_array_elem(&codec->spdif_out, idx); |
2488 | spdif->nid = (u16)-1; | 2498 | spdif->nid = (u16)-1; |
@@ -2503,6 +2513,8 @@ void snd_hda_spdif_ctls_assign(struct hda_codec *codec, int idx, hda_nid_t nid) | |||
2503 | struct hda_spdif_out *spdif; | 2513 | struct hda_spdif_out *spdif; |
2504 | unsigned short val; | 2514 | unsigned short val; |
2505 | 2515 | ||
2516 | if (WARN_ON(codec->spdif_out.used <= idx)) | ||
2517 | return; | ||
2506 | mutex_lock(&codec->spdif_mutex); | 2518 | mutex_lock(&codec->spdif_mutex); |
2507 | spdif = snd_array_elem(&codec->spdif_out, idx); | 2519 | spdif = snd_array_elem(&codec->spdif_out, idx); |
2508 | if (spdif->nid != nid) { | 2520 | if (spdif->nid != nid) { |
diff --git a/sound/pci/hda/hda_controller.c b/sound/pci/hda/hda_controller.c index d1eb14842340..a12e594d4e3b 100644 --- a/sound/pci/hda/hda_controller.c +++ b/sound/pci/hda/hda_controller.c | |||
@@ -748,8 +748,10 @@ int snd_hda_attach_pcm_stream(struct hda_bus *_bus, struct hda_codec *codec, | |||
748 | return err; | 748 | return err; |
749 | strlcpy(pcm->name, cpcm->name, sizeof(pcm->name)); | 749 | strlcpy(pcm->name, cpcm->name, sizeof(pcm->name)); |
750 | apcm = kzalloc(sizeof(*apcm), GFP_KERNEL); | 750 | apcm = kzalloc(sizeof(*apcm), GFP_KERNEL); |
751 | if (apcm == NULL) | 751 | if (apcm == NULL) { |
752 | snd_device_free(chip->card, pcm); | ||
752 | return -ENOMEM; | 753 | return -ENOMEM; |
754 | } | ||
753 | apcm->chip = chip; | 755 | apcm->chip = chip; |
754 | apcm->pcm = pcm; | 756 | apcm->pcm = pcm; |
755 | apcm->codec = codec; | 757 | apcm->codec = codec; |
diff --git a/sound/pci/hda/hda_generic.c b/sound/pci/hda/hda_generic.c index 5cc65093d941..db773e219aaa 100644 --- a/sound/pci/hda/hda_generic.c +++ b/sound/pci/hda/hda_generic.c | |||
@@ -264,10 +264,10 @@ static struct nid_path *get_nid_path(struct hda_codec *codec, | |||
264 | int anchor_nid) | 264 | int anchor_nid) |
265 | { | 265 | { |
266 | struct hda_gen_spec *spec = codec->spec; | 266 | struct hda_gen_spec *spec = codec->spec; |
267 | struct nid_path *path; | ||
267 | int i; | 268 | int i; |
268 | 269 | ||
269 | for (i = 0; i < spec->paths.used; i++) { | 270 | snd_array_for_each(&spec->paths, i, path) { |
270 | struct nid_path *path = snd_array_elem(&spec->paths, i); | ||
271 | if (path->depth <= 0) | 271 | if (path->depth <= 0) |
272 | continue; | 272 | continue; |
273 | if ((!from_nid || path->path[0] == from_nid) && | 273 | if ((!from_nid || path->path[0] == from_nid) && |
@@ -325,10 +325,10 @@ EXPORT_SYMBOL_GPL(snd_hda_get_path_from_idx); | |||
325 | static bool is_dac_already_used(struct hda_codec *codec, hda_nid_t nid) | 325 | static bool is_dac_already_used(struct hda_codec *codec, hda_nid_t nid) |
326 | { | 326 | { |
327 | struct hda_gen_spec *spec = codec->spec; | 327 | struct hda_gen_spec *spec = codec->spec; |
328 | const struct nid_path *path; | ||
328 | int i; | 329 | int i; |
329 | 330 | ||
330 | for (i = 0; i < spec->paths.used; i++) { | 331 | snd_array_for_each(&spec->paths, i, path) { |
331 | struct nid_path *path = snd_array_elem(&spec->paths, i); | ||
332 | if (path->path[0] == nid) | 332 | if (path->path[0] == nid) |
333 | return true; | 333 | return true; |
334 | } | 334 | } |
@@ -351,11 +351,11 @@ static bool is_reachable_path(struct hda_codec *codec, | |||
351 | static bool is_ctl_used(struct hda_codec *codec, unsigned int val, int type) | 351 | static bool is_ctl_used(struct hda_codec *codec, unsigned int val, int type) |
352 | { | 352 | { |
353 | struct hda_gen_spec *spec = codec->spec; | 353 | struct hda_gen_spec *spec = codec->spec; |
354 | const struct nid_path *path; | ||
354 | int i; | 355 | int i; |
355 | 356 | ||
356 | val &= AMP_VAL_COMPARE_MASK; | 357 | val &= AMP_VAL_COMPARE_MASK; |
357 | for (i = 0; i < spec->paths.used; i++) { | 358 | snd_array_for_each(&spec->paths, i, path) { |
358 | struct nid_path *path = snd_array_elem(&spec->paths, i); | ||
359 | if ((path->ctls[type] & AMP_VAL_COMPARE_MASK) == val) | 359 | if ((path->ctls[type] & AMP_VAL_COMPARE_MASK) == val) |
360 | return true; | 360 | return true; |
361 | } | 361 | } |
@@ -638,13 +638,13 @@ static bool is_active_nid(struct hda_codec *codec, hda_nid_t nid, | |||
638 | { | 638 | { |
639 | struct hda_gen_spec *spec = codec->spec; | 639 | struct hda_gen_spec *spec = codec->spec; |
640 | int type = get_wcaps_type(get_wcaps(codec, nid)); | 640 | int type = get_wcaps_type(get_wcaps(codec, nid)); |
641 | const struct nid_path *path; | ||
641 | int i, n; | 642 | int i, n; |
642 | 643 | ||
643 | if (nid == codec->core.afg) | 644 | if (nid == codec->core.afg) |
644 | return true; | 645 | return true; |
645 | 646 | ||
646 | for (n = 0; n < spec->paths.used; n++) { | 647 | snd_array_for_each(&spec->paths, n, path) { |
647 | struct nid_path *path = snd_array_elem(&spec->paths, n); | ||
648 | if (!path->active) | 648 | if (!path->active) |
649 | continue; | 649 | continue; |
650 | if (codec->power_save_node) { | 650 | if (codec->power_save_node) { |
@@ -2065,7 +2065,7 @@ static int parse_output_paths(struct hda_codec *codec) | |||
2065 | snd_hda_set_vmaster_tlv(codec, spec->vmaster_nid, | 2065 | snd_hda_set_vmaster_tlv(codec, spec->vmaster_nid, |
2066 | HDA_OUTPUT, spec->vmaster_tlv); | 2066 | HDA_OUTPUT, spec->vmaster_tlv); |
2067 | if (spec->dac_min_mute) | 2067 | if (spec->dac_min_mute) |
2068 | spec->vmaster_tlv[3] |= TLV_DB_SCALE_MUTE; | 2068 | spec->vmaster_tlv[SNDRV_CTL_TLVO_DB_SCALE_MUTE_AND_STEP] |= TLV_DB_SCALE_MUTE; |
2069 | } | 2069 | } |
2070 | } | 2070 | } |
2071 | 2071 | ||
@@ -2696,10 +2696,10 @@ static const struct snd_kcontrol_new out_jack_mode_enum = { | |||
2696 | static bool find_kctl_name(struct hda_codec *codec, const char *name, int idx) | 2696 | static bool find_kctl_name(struct hda_codec *codec, const char *name, int idx) |
2697 | { | 2697 | { |
2698 | struct hda_gen_spec *spec = codec->spec; | 2698 | struct hda_gen_spec *spec = codec->spec; |
2699 | const struct snd_kcontrol_new *kctl; | ||
2699 | int i; | 2700 | int i; |
2700 | 2701 | ||
2701 | for (i = 0; i < spec->kctls.used; i++) { | 2702 | snd_array_for_each(&spec->kctls, i, kctl) { |
2702 | struct snd_kcontrol_new *kctl = snd_array_elem(&spec->kctls, i); | ||
2703 | if (!strcmp(kctl->name, name) && kctl->index == idx) | 2703 | if (!strcmp(kctl->name, name) && kctl->index == idx) |
2704 | return true; | 2704 | return true; |
2705 | } | 2705 | } |
@@ -4021,8 +4021,7 @@ static hda_nid_t set_path_power(struct hda_codec *codec, hda_nid_t nid, | |||
4021 | struct nid_path *path; | 4021 | struct nid_path *path; |
4022 | int n; | 4022 | int n; |
4023 | 4023 | ||
4024 | for (n = 0; n < spec->paths.used; n++) { | 4024 | snd_array_for_each(&spec->paths, n, path) { |
4025 | path = snd_array_elem(&spec->paths, n); | ||
4026 | if (!path->depth) | 4025 | if (!path->depth) |
4027 | continue; | 4026 | continue; |
4028 | if (path->path[0] == nid || | 4027 | if (path->path[0] == nid || |
@@ -5831,10 +5830,10 @@ static void init_digital(struct hda_codec *codec) | |||
5831 | */ | 5830 | */ |
5832 | static void clear_unsol_on_unused_pins(struct hda_codec *codec) | 5831 | static void clear_unsol_on_unused_pins(struct hda_codec *codec) |
5833 | { | 5832 | { |
5833 | const struct hda_pincfg *pin; | ||
5834 | int i; | 5834 | int i; |
5835 | 5835 | ||
5836 | for (i = 0; i < codec->init_pins.used; i++) { | 5836 | snd_array_for_each(&codec->init_pins, i, pin) { |
5837 | struct hda_pincfg *pin = snd_array_elem(&codec->init_pins, i); | ||
5838 | hda_nid_t nid = pin->nid; | 5837 | hda_nid_t nid = pin->nid; |
5839 | if (is_jack_detectable(codec, nid) && | 5838 | if (is_jack_detectable(codec, nid) && |
5840 | !snd_hda_jack_tbl_get(codec, nid)) | 5839 | !snd_hda_jack_tbl_get(codec, nid)) |
diff --git a/sound/pci/hda/hda_intel.c b/sound/pci/hda/hda_intel.c index a0c93b9c9a28..1ae1850b3bfd 100644 --- a/sound/pci/hda/hda_intel.c +++ b/sound/pci/hda/hda_intel.c | |||
@@ -2209,7 +2209,18 @@ static struct snd_pci_quirk power_save_blacklist[] = { | |||
2209 | /* https://bugzilla.redhat.com/show_bug.cgi?id=1525104 */ | 2209 | /* https://bugzilla.redhat.com/show_bug.cgi?id=1525104 */ |
2210 | SND_PCI_QUIRK(0x1849, 0x0c0c, "Asrock B85M-ITX", 0), | 2210 | SND_PCI_QUIRK(0x1849, 0x0c0c, "Asrock B85M-ITX", 0), |
2211 | /* https://bugzilla.redhat.com/show_bug.cgi?id=1525104 */ | 2211 | /* https://bugzilla.redhat.com/show_bug.cgi?id=1525104 */ |
2212 | SND_PCI_QUIRK(0x1849, 0x7662, "Asrock H81M-HDS", 0), | ||
2213 | /* https://bugzilla.redhat.com/show_bug.cgi?id=1525104 */ | ||
2212 | SND_PCI_QUIRK(0x1043, 0x8733, "Asus Prime X370-Pro", 0), | 2214 | SND_PCI_QUIRK(0x1043, 0x8733, "Asus Prime X370-Pro", 0), |
2215 | /* https://bugzilla.redhat.com/show_bug.cgi?id=1581607 */ | ||
2216 | SND_PCI_QUIRK(0x1558, 0x3501, "Clevo W35xSS_370SS", 0), | ||
2217 | /* https://bugzilla.redhat.com/show_bug.cgi?id=1525104 */ | ||
2218 | /* Note the P55A-UD3 and Z87-D3HP share the subsys id for the HDA dev */ | ||
2219 | SND_PCI_QUIRK(0x1458, 0xa002, "Gigabyte P55A-UD3 / Z87-D3HP", 0), | ||
2220 | /* https://bugzilla.kernel.org/show_bug.cgi?id=199607 */ | ||
2221 | SND_PCI_QUIRK(0x8086, 0x2057, "Intel NUC5i7RYB", 0), | ||
2222 | /* https://bugzilla.redhat.com/show_bug.cgi?id=1520902 */ | ||
2223 | SND_PCI_QUIRK(0x8086, 0x2068, "Intel NUC7i3BNB", 0), | ||
2213 | /* https://bugzilla.redhat.com/show_bug.cgi?id=1572975 */ | 2224 | /* https://bugzilla.redhat.com/show_bug.cgi?id=1572975 */ |
2214 | SND_PCI_QUIRK(0x17aa, 0x36a7, "Lenovo C50 All in one", 0), | 2225 | SND_PCI_QUIRK(0x17aa, 0x36a7, "Lenovo C50 All in one", 0), |
2215 | /* https://bugzilla.kernel.org/show_bug.cgi?id=198611 */ | 2226 | /* https://bugzilla.kernel.org/show_bug.cgi?id=198611 */ |
diff --git a/sound/pci/hda/hda_sysfs.c b/sound/pci/hda/hda_sysfs.c index 9b7efece4484..6ec79c58d48d 100644 --- a/sound/pci/hda/hda_sysfs.c +++ b/sound/pci/hda/hda_sysfs.c | |||
@@ -80,10 +80,10 @@ static ssize_t pin_configs_show(struct hda_codec *codec, | |||
80 | struct snd_array *list, | 80 | struct snd_array *list, |
81 | char *buf) | 81 | char *buf) |
82 | { | 82 | { |
83 | const struct hda_pincfg *pin; | ||
83 | int i, len = 0; | 84 | int i, len = 0; |
84 | mutex_lock(&codec->user_mutex); | 85 | mutex_lock(&codec->user_mutex); |
85 | for (i = 0; i < list->used; i++) { | 86 | snd_array_for_each(list, i, pin) { |
86 | struct hda_pincfg *pin = snd_array_elem(list, i); | ||
87 | len += sprintf(buf + len, "0x%02x 0x%08x\n", | 87 | len += sprintf(buf + len, "0x%02x 0x%08x\n", |
88 | pin->nid, pin->cfg); | 88 | pin->nid, pin->cfg); |
89 | } | 89 | } |
@@ -217,10 +217,10 @@ static ssize_t init_verbs_show(struct device *dev, | |||
217 | char *buf) | 217 | char *buf) |
218 | { | 218 | { |
219 | struct hda_codec *codec = dev_get_drvdata(dev); | 219 | struct hda_codec *codec = dev_get_drvdata(dev); |
220 | const struct hda_verb *v; | ||
220 | int i, len = 0; | 221 | int i, len = 0; |
221 | mutex_lock(&codec->user_mutex); | 222 | mutex_lock(&codec->user_mutex); |
222 | for (i = 0; i < codec->init_verbs.used; i++) { | 223 | snd_array_for_each(&codec->init_verbs, i, v) { |
223 | struct hda_verb *v = snd_array_elem(&codec->init_verbs, i); | ||
224 | len += snprintf(buf + len, PAGE_SIZE - len, | 224 | len += snprintf(buf + len, PAGE_SIZE - len, |
225 | "0x%02x 0x%03x 0x%04x\n", | 225 | "0x%02x 0x%03x 0x%04x\n", |
226 | v->nid, v->verb, v->param); | 226 | v->nid, v->verb, v->param); |
@@ -267,10 +267,10 @@ static ssize_t hints_show(struct device *dev, | |||
267 | char *buf) | 267 | char *buf) |
268 | { | 268 | { |
269 | struct hda_codec *codec = dev_get_drvdata(dev); | 269 | struct hda_codec *codec = dev_get_drvdata(dev); |
270 | const struct hda_hint *hint; | ||
270 | int i, len = 0; | 271 | int i, len = 0; |
271 | mutex_lock(&codec->user_mutex); | 272 | mutex_lock(&codec->user_mutex); |
272 | for (i = 0; i < codec->hints.used; i++) { | 273 | snd_array_for_each(&codec->hints, i, hint) { |
273 | struct hda_hint *hint = snd_array_elem(&codec->hints, i); | ||
274 | len += snprintf(buf + len, PAGE_SIZE - len, | 274 | len += snprintf(buf + len, PAGE_SIZE - len, |
275 | "%s = %s\n", hint->key, hint->val); | 275 | "%s = %s\n", hint->key, hint->val); |
276 | } | 276 | } |
@@ -280,10 +280,10 @@ static ssize_t hints_show(struct device *dev, | |||
280 | 280 | ||
281 | static struct hda_hint *get_hint(struct hda_codec *codec, const char *key) | 281 | static struct hda_hint *get_hint(struct hda_codec *codec, const char *key) |
282 | { | 282 | { |
283 | struct hda_hint *hint; | ||
283 | int i; | 284 | int i; |
284 | 285 | ||
285 | for (i = 0; i < codec->hints.used; i++) { | 286 | snd_array_for_each(&codec->hints, i, hint) { |
286 | struct hda_hint *hint = snd_array_elem(&codec->hints, i); | ||
287 | if (!strcmp(hint->key, key)) | 287 | if (!strcmp(hint->key, key)) |
288 | return hint; | 288 | return hint; |
289 | } | 289 | } |
@@ -783,13 +783,13 @@ void snd_hda_sysfs_init(struct hda_codec *codec) | |||
783 | void snd_hda_sysfs_clear(struct hda_codec *codec) | 783 | void snd_hda_sysfs_clear(struct hda_codec *codec) |
784 | { | 784 | { |
785 | #ifdef CONFIG_SND_HDA_RECONFIG | 785 | #ifdef CONFIG_SND_HDA_RECONFIG |
786 | struct hda_hint *hint; | ||
786 | int i; | 787 | int i; |
787 | 788 | ||
788 | /* clear init verbs */ | 789 | /* clear init verbs */ |
789 | snd_array_free(&codec->init_verbs); | 790 | snd_array_free(&codec->init_verbs); |
790 | /* clear hints */ | 791 | /* clear hints */ |
791 | for (i = 0; i < codec->hints.used; i++) { | 792 | snd_array_for_each(&codec->hints, i, hint) { |
792 | struct hda_hint *hint = snd_array_elem(&codec->hints, i); | ||
793 | kfree(hint->key); /* we don't need to free hint->val */ | 793 | kfree(hint->key); /* we don't need to free hint->val */ |
794 | } | 794 | } |
795 | snd_array_free(&codec->hints); | 795 | snd_array_free(&codec->hints); |
diff --git a/sound/pci/hda/hp_x360_helper.c b/sound/pci/hda/hp_x360_helper.c new file mode 100644 index 000000000000..969542c57358 --- /dev/null +++ b/sound/pci/hda/hp_x360_helper.c | |||
@@ -0,0 +1,95 @@ | |||
1 | // SPDX-License-Identifier: GPL-2.0 | ||
2 | /* Fixes for HP X360 laptops with top B&O speakers | ||
3 | * to be included from codec driver | ||
4 | */ | ||
5 | |||
6 | static void alc295_fixup_hp_top_speakers(struct hda_codec *codec, | ||
7 | const struct hda_fixup *fix, int action) | ||
8 | { | ||
9 | static const struct hda_pintbl pincfgs[] = { | ||
10 | { 0x17, 0x90170110 }, | ||
11 | { } | ||
12 | }; | ||
13 | static const struct coef_fw alc295_hp_speakers_coefs[] = { | ||
14 | WRITE_COEF(0x24, 0x0012), WRITE_COEF(0x26, 0x0000), WRITE_COEF(0x28, 0x0000), WRITE_COEF(0x29, 0xb024), | ||
15 | WRITE_COEF(0x24, 0x0012), WRITE_COEF(0x26, 0x003f), WRITE_COEF(0x28, 0x1000), WRITE_COEF(0x29, 0xb024), | ||
16 | WRITE_COEF(0x24, 0x0012), WRITE_COEF(0x26, 0x0004), WRITE_COEF(0x28, 0x0600), WRITE_COEF(0x29, 0xb024), | ||
17 | WRITE_COEF(0x24, 0x0012), WRITE_COEF(0x26, 0x006a), WRITE_COEF(0x28, 0x0006), WRITE_COEF(0x29, 0xb024), | ||
18 | WRITE_COEF(0x24, 0x0012), WRITE_COEF(0x26, 0x006c), WRITE_COEF(0x28, 0xc0c0), WRITE_COEF(0x29, 0xb024), | ||
19 | WRITE_COEF(0x24, 0x0012), WRITE_COEF(0x26, 0x0008), WRITE_COEF(0x28, 0xb000), WRITE_COEF(0x29, 0xb024), | ||
20 | WRITE_COEF(0x24, 0x0012), WRITE_COEF(0x26, 0x002e), WRITE_COEF(0x28, 0x0800), WRITE_COEF(0x29, 0xb024), | ||
21 | WRITE_COEF(0x24, 0x0012), WRITE_COEF(0x26, 0x006a), WRITE_COEF(0x28, 0x00c1), WRITE_COEF(0x29, 0xb024), | ||
22 | WRITE_COEF(0x24, 0x0012), WRITE_COEF(0x26, 0x006c), WRITE_COEF(0x28, 0x0320), WRITE_COEF(0x29, 0xb024), | ||
23 | WRITE_COEF(0x24, 0x0012), WRITE_COEF(0x26, 0x0039), WRITE_COEF(0x28, 0x0000), WRITE_COEF(0x29, 0xb024), | ||
24 | WRITE_COEF(0x24, 0x0012), WRITE_COEF(0x26, 0x003b), WRITE_COEF(0x28, 0xffff), WRITE_COEF(0x29, 0xb024), | ||
25 | WRITE_COEF(0x24, 0x0012), WRITE_COEF(0x26, 0x003c), WRITE_COEF(0x28, 0xffd0), WRITE_COEF(0x29, 0xb024), | ||
26 | WRITE_COEF(0x24, 0x0012), WRITE_COEF(0x26, 0x003a), WRITE_COEF(0x28, 0x1dfe), WRITE_COEF(0x29, 0xb024), | ||
27 | WRITE_COEF(0x24, 0x0012), WRITE_COEF(0x26, 0x0080), WRITE_COEF(0x28, 0x0880), WRITE_COEF(0x29, 0xb024), | ||
28 | WRITE_COEF(0x24, 0x0012), WRITE_COEF(0x26, 0x003a), WRITE_COEF(0x28, 0x0dfe), WRITE_COEF(0x29, 0xb024), | ||
29 | WRITE_COEF(0x24, 0x0012), WRITE_COEF(0x26, 0x0018), WRITE_COEF(0x28, 0x0219), WRITE_COEF(0x29, 0xb024), | ||
30 | WRITE_COEF(0x24, 0x0012), WRITE_COEF(0x26, 0x006a), WRITE_COEF(0x28, 0x005d), WRITE_COEF(0x29, 0xb024), | ||
31 | WRITE_COEF(0x24, 0x0012), WRITE_COEF(0x26, 0x006c), WRITE_COEF(0x28, 0x9142), WRITE_COEF(0x29, 0xb024), | ||
32 | WRITE_COEF(0x24, 0x0012), WRITE_COEF(0x26, 0x00c0), WRITE_COEF(0x28, 0x01ce), WRITE_COEF(0x29, 0xb024), | ||
33 | WRITE_COEF(0x24, 0x0012), WRITE_COEF(0x26, 0x00c1), WRITE_COEF(0x28, 0xed0c), WRITE_COEF(0x29, 0xb024), | ||
34 | WRITE_COEF(0x24, 0x0012), WRITE_COEF(0x26, 0x00c2), WRITE_COEF(0x28, 0x1c00), WRITE_COEF(0x29, 0xb024), | ||
35 | WRITE_COEF(0x24, 0x0012), WRITE_COEF(0x26, 0x00c3), WRITE_COEF(0x28, 0x0000), WRITE_COEF(0x29, 0xb024), | ||
36 | WRITE_COEF(0x24, 0x0012), WRITE_COEF(0x26, 0x00c4), WRITE_COEF(0x28, 0x0200), WRITE_COEF(0x29, 0xb024), | ||
37 | WRITE_COEF(0x24, 0x0012), WRITE_COEF(0x26, 0x00c5), WRITE_COEF(0x28, 0x0000), WRITE_COEF(0x29, 0xb024), | ||
38 | WRITE_COEF(0x24, 0x0012), WRITE_COEF(0x26, 0x00c6), WRITE_COEF(0x28, 0x0399), WRITE_COEF(0x29, 0xb024), | ||
39 | WRITE_COEF(0x24, 0x0012), WRITE_COEF(0x26, 0x00c7), WRITE_COEF(0x28, 0x2330), WRITE_COEF(0x29, 0xb024), | ||
40 | WRITE_COEF(0x24, 0x0012), WRITE_COEF(0x26, 0x00c8), WRITE_COEF(0x28, 0x1e5d), WRITE_COEF(0x29, 0xb024), | ||
41 | WRITE_COEF(0x24, 0x0012), WRITE_COEF(0x26, 0x00c9), WRITE_COEF(0x28, 0x6eff), WRITE_COEF(0x29, 0xb024), | ||
42 | WRITE_COEF(0x24, 0x0012), WRITE_COEF(0x26, 0x00ca), WRITE_COEF(0x28, 0x01c0), WRITE_COEF(0x29, 0xb024), | ||
43 | WRITE_COEF(0x24, 0x0012), WRITE_COEF(0x26, 0x00cb), WRITE_COEF(0x28, 0xed0c), WRITE_COEF(0x29, 0xb024), | ||
44 | WRITE_COEF(0x24, 0x0012), WRITE_COEF(0x26, 0x00cc), WRITE_COEF(0x28, 0x1c00), WRITE_COEF(0x29, 0xb024), | ||
45 | WRITE_COEF(0x24, 0x0012), WRITE_COEF(0x26, 0x00cd), WRITE_COEF(0x28, 0x0000), WRITE_COEF(0x29, 0xb024), | ||
46 | WRITE_COEF(0x24, 0x0012), WRITE_COEF(0x26, 0x00ce), WRITE_COEF(0x28, 0x0200), WRITE_COEF(0x29, 0xb024), | ||
47 | WRITE_COEF(0x24, 0x0012), WRITE_COEF(0x26, 0x00cf), WRITE_COEF(0x28, 0x0000), WRITE_COEF(0x29, 0xb024), | ||
48 | WRITE_COEF(0x24, 0x0012), WRITE_COEF(0x26, 0x00d0), WRITE_COEF(0x28, 0x0399), WRITE_COEF(0x29, 0xb024), | ||
49 | WRITE_COEF(0x24, 0x0012), WRITE_COEF(0x26, 0x00d1), WRITE_COEF(0x28, 0x2330), WRITE_COEF(0x29, 0xb024), | ||
50 | WRITE_COEF(0x24, 0x0012), WRITE_COEF(0x26, 0x00d2), WRITE_COEF(0x28, 0x1e5d), WRITE_COEF(0x29, 0xb024), | ||
51 | WRITE_COEF(0x24, 0x0012), WRITE_COEF(0x26, 0x00d3), WRITE_COEF(0x28, 0x6eff), WRITE_COEF(0x29, 0xb024), | ||
52 | WRITE_COEF(0x24, 0x0012), WRITE_COEF(0x26, 0x0062), WRITE_COEF(0x28, 0x8000), WRITE_COEF(0x29, 0xb024), | ||
53 | WRITE_COEF(0x24, 0x0012), WRITE_COEF(0x26, 0x0063), WRITE_COEF(0x28, 0x5f5f), WRITE_COEF(0x29, 0xb024), | ||
54 | WRITE_COEF(0x24, 0x0012), WRITE_COEF(0x26, 0x0064), WRITE_COEF(0x28, 0x1000), WRITE_COEF(0x29, 0xb024), | ||
55 | WRITE_COEF(0x24, 0x0012), WRITE_COEF(0x26, 0x0065), WRITE_COEF(0x28, 0x0000), WRITE_COEF(0x29, 0xb024), | ||
56 | WRITE_COEF(0x24, 0x0012), WRITE_COEF(0x26, 0x0066), WRITE_COEF(0x28, 0x4004), WRITE_COEF(0x29, 0xb024), | ||
57 | WRITE_COEF(0x24, 0x0012), WRITE_COEF(0x26, 0x0067), WRITE_COEF(0x28, 0x0802), WRITE_COEF(0x29, 0xb024), | ||
58 | WRITE_COEF(0x24, 0x0012), WRITE_COEF(0x26, 0x0068), WRITE_COEF(0x28, 0x890f), WRITE_COEF(0x29, 0xb024), | ||
59 | WRITE_COEF(0x24, 0x0012), WRITE_COEF(0x26, 0x0069), WRITE_COEF(0x28, 0xe021), WRITE_COEF(0x29, 0xb024), | ||
60 | WRITE_COEF(0x24, 0x0012), WRITE_COEF(0x26, 0x0070), WRITE_COEF(0x28, 0x8012), WRITE_COEF(0x29, 0xb024), | ||
61 | WRITE_COEF(0x24, 0x0012), WRITE_COEF(0x26, 0x0071), WRITE_COEF(0x28, 0x3450), WRITE_COEF(0x29, 0xb024), | ||
62 | WRITE_COEF(0x24, 0x0012), WRITE_COEF(0x26, 0x0072), WRITE_COEF(0x28, 0x0123), WRITE_COEF(0x29, 0xb024), | ||
63 | WRITE_COEF(0x24, 0x0012), WRITE_COEF(0x26, 0x0073), WRITE_COEF(0x28, 0x4543), WRITE_COEF(0x29, 0xb024), | ||
64 | WRITE_COEF(0x24, 0x0012), WRITE_COEF(0x26, 0x0074), WRITE_COEF(0x28, 0x2100), WRITE_COEF(0x29, 0xb024), | ||
65 | WRITE_COEF(0x24, 0x0012), WRITE_COEF(0x26, 0x0075), WRITE_COEF(0x28, 0x4321), WRITE_COEF(0x29, 0xb024), | ||
66 | WRITE_COEF(0x24, 0x0012), WRITE_COEF(0x26, 0x0076), WRITE_COEF(0x28, 0x0000), WRITE_COEF(0x29, 0xb024), | ||
67 | WRITE_COEF(0x24, 0x0012), WRITE_COEF(0x26, 0x0050), WRITE_COEF(0x28, 0x8200), WRITE_COEF(0x29, 0xb024), | ||
68 | WRITE_COEF(0x24, 0x0012), WRITE_COEF(0x26, 0x003a), WRITE_COEF(0x28, 0x1dfe), WRITE_COEF(0x29, 0xb024), | ||
69 | WRITE_COEF(0x24, 0x0012), WRITE_COEF(0x26, 0x0051), WRITE_COEF(0x28, 0x0707), WRITE_COEF(0x29, 0xb024), | ||
70 | WRITE_COEF(0x24, 0x0012), WRITE_COEF(0x26, 0x0052), WRITE_COEF(0x28, 0x4090), WRITE_COEF(0x29, 0xb024), | ||
71 | WRITE_COEF(0x24, 0x0012), WRITE_COEF(0x26, 0x006a), WRITE_COEF(0x28, 0x0090), WRITE_COEF(0x29, 0xb024), | ||
72 | WRITE_COEF(0x24, 0x0012), WRITE_COEF(0x26, 0x006c), WRITE_COEF(0x28, 0x721f), WRITE_COEF(0x29, 0xb024), | ||
73 | WRITE_COEF(0x24, 0x0012), WRITE_COEF(0x26, 0x0012), WRITE_COEF(0x28, 0xebeb), WRITE_COEF(0x29, 0xb024), | ||
74 | WRITE_COEF(0x24, 0x0012), WRITE_COEF(0x26, 0x009e), WRITE_COEF(0x28, 0x0000), WRITE_COEF(0x29, 0xb024), | ||
75 | WRITE_COEF(0x24, 0x0012), WRITE_COEF(0x26, 0x0060), WRITE_COEF(0x28, 0x2213), WRITE_COEF(0x29, 0xb024), | ||
76 | WRITE_COEF(0x24, 0x0012), WRITE_COEF(0x26, 0x006a), WRITE_COEF(0x28, 0x0006), WRITE_COEF(0x29, 0xb024), | ||
77 | WRITE_COEF(0x24, 0x0012), WRITE_COEF(0x26, 0x006c), WRITE_COEF(0x28, 0x0000), WRITE_COEF(0x29, 0xb024), | ||
78 | WRITE_COEF(0x24, 0x0012), WRITE_COEF(0x26, 0x003f), WRITE_COEF(0x28, 0x3000), WRITE_COEF(0x29, 0xb024), | ||
79 | WRITE_COEF(0x24, 0x0012), WRITE_COEF(0x26, 0x0004), WRITE_COEF(0x28, 0x0500), WRITE_COEF(0x29, 0xb024), | ||
80 | WRITE_COEF(0x24, 0x0012), WRITE_COEF(0x26, 0x0040), WRITE_COEF(0x28, 0x800c), WRITE_COEF(0x29, 0xb024), | ||
81 | WRITE_COEF(0x24, 0x0012), WRITE_COEF(0x26, 0x0046), WRITE_COEF(0x28, 0xc22e), WRITE_COEF(0x29, 0xb024), | ||
82 | WRITE_COEF(0x24, 0x0012), WRITE_COEF(0x26, 0x004b), WRITE_COEF(0x28, 0x0000), WRITE_COEF(0x29, 0xb024), | ||
83 | WRITE_COEF(0x24, 0x0012), WRITE_COEF(0x26, 0x0050), WRITE_COEF(0x28, 0x82ec), WRITE_COEF(0x29, 0xb024), | ||
84 | }; | ||
85 | |||
86 | switch (action) { | ||
87 | case HDA_FIXUP_ACT_PRE_PROBE: | ||
88 | snd_hda_apply_pincfgs(codec, pincfgs); | ||
89 | alc295_fixup_disable_dac3(codec, fix, action); | ||
90 | break; | ||
91 | case HDA_FIXUP_ACT_INIT: | ||
92 | alc_process_coef_fw(codec, alc295_hp_speakers_coefs); | ||
93 | break; | ||
94 | } | ||
95 | } | ||
diff --git a/sound/pci/hda/local.h b/sound/pci/hda/local.h deleted file mode 100644 index 3b8b7d78f9e0..000000000000 --- a/sound/pci/hda/local.h +++ /dev/null | |||
@@ -1,40 +0,0 @@ | |||
1 | /* SPDX-License-Identifier: GPL-2.0 */ | ||
2 | /* | ||
3 | */ | ||
4 | |||
5 | #ifndef __HDAC_LOCAL_H | ||
6 | #define __HDAC_LOCAL_H | ||
7 | |||
8 | int hdac_read_parm(struct hdac_device *codec, hda_nid_t nid, int parm); | ||
9 | |||
10 | #define get_wcaps(codec, nid) \ | ||
11 | hdac_read_parm(codec, nid, AC_PAR_AUDIO_WIDGET_CAP) | ||
12 | /* get the widget type from widget capability bits */ | ||
13 | static inline int get_wcaps_type(unsigned int wcaps) | ||
14 | { | ||
15 | if (!wcaps) | ||
16 | return -1; /* invalid type */ | ||
17 | return (wcaps & AC_WCAP_TYPE) >> AC_WCAP_TYPE_SHIFT; | ||
18 | } | ||
19 | |||
20 | #define get_pin_caps(codec, nid) \ | ||
21 | hdac_read_parm(codec, nid, AC_PAR_PIN_CAP) | ||
22 | |||
23 | static inline | ||
24 | unsigned int get_pin_cfg(struct hdac_device *codec, hda_nid_t nid) | ||
25 | { | ||
26 | unsigned int val; | ||
27 | |||
28 | if (snd_hdac_read(codec, nid, AC_VERB_GET_CONFIG_DEFAULT, 0, &val)) | ||
29 | return -1; | ||
30 | return val; | ||
31 | } | ||
32 | |||
33 | #define get_amp_caps(codec, nid, dir) \ | ||
34 | hdac_read_parm(codec, nid, (dir) == HDA_OUTPUT ? \ | ||
35 | AC_PAR_AMP_OUT_CAP : AC_PAR_AMP_IN_CAP) | ||
36 | |||
37 | #define get_power_caps(codec, nid) \ | ||
38 | hdac_read_parm(codec, nid, AC_PAR_POWER_STATE) | ||
39 | |||
40 | #endif /* __HDAC_LOCAL_H */ | ||
diff --git a/sound/pci/hda/patch_ca0132.c b/sound/pci/hda/patch_ca0132.c index 768ea8651993..292e2c592c17 100644 --- a/sound/pci/hda/patch_ca0132.c +++ b/sound/pci/hda/patch_ca0132.c | |||
@@ -28,6 +28,9 @@ | |||
28 | #include <linux/module.h> | 28 | #include <linux/module.h> |
29 | #include <linux/firmware.h> | 29 | #include <linux/firmware.h> |
30 | #include <linux/kernel.h> | 30 | #include <linux/kernel.h> |
31 | #include <linux/types.h> | ||
32 | #include <linux/io.h> | ||
33 | #include <linux/pci.h> | ||
31 | #include <sound/core.h> | 34 | #include <sound/core.h> |
32 | #include "hda_codec.h" | 35 | #include "hda_codec.h" |
33 | #include "hda_local.h" | 36 | #include "hda_local.h" |
@@ -39,9 +42,15 @@ | |||
39 | /* Enable this to see controls for tuning purpose. */ | 42 | /* Enable this to see controls for tuning purpose. */ |
40 | /*#define ENABLE_TUNING_CONTROLS*/ | 43 | /*#define ENABLE_TUNING_CONTROLS*/ |
41 | 44 | ||
45 | #ifdef ENABLE_TUNING_CONTROLS | ||
46 | #include <sound/tlv.h> | ||
47 | #endif | ||
48 | |||
42 | #define FLOAT_ZERO 0x00000000 | 49 | #define FLOAT_ZERO 0x00000000 |
43 | #define FLOAT_ONE 0x3f800000 | 50 | #define FLOAT_ONE 0x3f800000 |
44 | #define FLOAT_TWO 0x40000000 | 51 | #define FLOAT_TWO 0x40000000 |
52 | #define FLOAT_THREE 0x40400000 | ||
53 | #define FLOAT_EIGHT 0x41000000 | ||
45 | #define FLOAT_MINUS_5 0xc0a00000 | 54 | #define FLOAT_MINUS_5 0xc0a00000 |
46 | 55 | ||
47 | #define UNSOL_TAG_DSP 0x16 | 56 | #define UNSOL_TAG_DSP 0x16 |
@@ -72,16 +81,22 @@ | |||
72 | #define SCP_GET 1 | 81 | #define SCP_GET 1 |
73 | 82 | ||
74 | #define EFX_FILE "ctefx.bin" | 83 | #define EFX_FILE "ctefx.bin" |
84 | #define SBZ_EFX_FILE "ctefx-sbz.bin" | ||
85 | #define R3DI_EFX_FILE "ctefx-r3di.bin" | ||
75 | 86 | ||
76 | #ifdef CONFIG_SND_HDA_CODEC_CA0132_DSP | 87 | #ifdef CONFIG_SND_HDA_CODEC_CA0132_DSP |
77 | MODULE_FIRMWARE(EFX_FILE); | 88 | MODULE_FIRMWARE(EFX_FILE); |
89 | MODULE_FIRMWARE(SBZ_EFX_FILE); | ||
90 | MODULE_FIRMWARE(R3DI_EFX_FILE); | ||
78 | #endif | 91 | #endif |
79 | 92 | ||
80 | static char *dirstr[2] = { "Playback", "Capture" }; | 93 | static const char *const dirstr[2] = { "Playback", "Capture" }; |
81 | 94 | ||
95 | #define NUM_OF_OUTPUTS 3 | ||
82 | enum { | 96 | enum { |
83 | SPEAKER_OUT, | 97 | SPEAKER_OUT, |
84 | HEADPHONE_OUT | 98 | HEADPHONE_OUT, |
99 | SURROUND_OUT | ||
85 | }; | 100 | }; |
86 | 101 | ||
87 | enum { | 102 | enum { |
@@ -89,6 +104,15 @@ enum { | |||
89 | LINE_MIC_IN | 104 | LINE_MIC_IN |
90 | }; | 105 | }; |
91 | 106 | ||
107 | /* Strings for Input Source Enum Control */ | ||
108 | static const char *const in_src_str[3] = {"Rear Mic", "Line", "Front Mic" }; | ||
109 | #define IN_SRC_NUM_OF_INPUTS 3 | ||
110 | enum { | ||
111 | REAR_MIC, | ||
112 | REAR_LINE_IN, | ||
113 | FRONT_MIC, | ||
114 | }; | ||
115 | |||
92 | enum { | 116 | enum { |
93 | #define VNODE_START_NID 0x80 | 117 | #define VNODE_START_NID 0x80 |
94 | VNID_SPK = VNODE_START_NID, /* Speaker vnid */ | 118 | VNID_SPK = VNODE_START_NID, /* Speaker vnid */ |
@@ -122,13 +146,28 @@ enum { | |||
122 | VOICEFX = IN_EFFECT_END_NID, | 146 | VOICEFX = IN_EFFECT_END_NID, |
123 | PLAY_ENHANCEMENT, | 147 | PLAY_ENHANCEMENT, |
124 | CRYSTAL_VOICE, | 148 | CRYSTAL_VOICE, |
125 | EFFECT_END_NID | 149 | EFFECT_END_NID, |
150 | OUTPUT_SOURCE_ENUM, | ||
151 | INPUT_SOURCE_ENUM, | ||
152 | XBASS_XOVER, | ||
153 | EQ_PRESET_ENUM, | ||
154 | SMART_VOLUME_ENUM, | ||
155 | MIC_BOOST_ENUM | ||
126 | #define EFFECTS_COUNT (EFFECT_END_NID - EFFECT_START_NID) | 156 | #define EFFECTS_COUNT (EFFECT_END_NID - EFFECT_START_NID) |
127 | }; | 157 | }; |
128 | 158 | ||
129 | /* Effects values size*/ | 159 | /* Effects values size*/ |
130 | #define EFFECT_VALS_MAX_COUNT 12 | 160 | #define EFFECT_VALS_MAX_COUNT 12 |
131 | 161 | ||
162 | /* | ||
163 | * Default values for the effect slider controls, they are in order of their | ||
164 | * effect NID's. Surround, Crystalizer, Dialog Plus, Smart Volume, and then | ||
165 | * X-bass. | ||
166 | */ | ||
167 | static const unsigned int effect_slider_defaults[] = {67, 65, 50, 74, 50}; | ||
168 | /* Amount of effect level sliders for ca0132_alt controls. */ | ||
169 | #define EFFECT_LEVEL_SLIDERS 5 | ||
170 | |||
132 | /* Latency introduced by DSP blocks in milliseconds. */ | 171 | /* Latency introduced by DSP blocks in milliseconds. */ |
133 | #define DSP_CAPTURE_INIT_LATENCY 0 | 172 | #define DSP_CAPTURE_INIT_LATENCY 0 |
134 | #define DSP_CRYSTAL_VOICE_LATENCY 124 | 173 | #define DSP_CRYSTAL_VOICE_LATENCY 124 |
@@ -150,7 +189,7 @@ struct ct_effect { | |||
150 | #define EFX_DIR_OUT 0 | 189 | #define EFX_DIR_OUT 0 |
151 | #define EFX_DIR_IN 1 | 190 | #define EFX_DIR_IN 1 |
152 | 191 | ||
153 | static struct ct_effect ca0132_effects[EFFECTS_COUNT] = { | 192 | static const struct ct_effect ca0132_effects[EFFECTS_COUNT] = { |
154 | { .name = "Surround", | 193 | { .name = "Surround", |
155 | .nid = SURROUND, | 194 | .nid = SURROUND, |
156 | .mid = 0x96, | 195 | .mid = 0x96, |
@@ -277,7 +316,7 @@ struct ct_tuning_ctl { | |||
277 | unsigned int def_val;/*effect default values*/ | 316 | unsigned int def_val;/*effect default values*/ |
278 | }; | 317 | }; |
279 | 318 | ||
280 | static struct ct_tuning_ctl ca0132_tuning_ctls[] = { | 319 | static const struct ct_tuning_ctl ca0132_tuning_ctls[] = { |
281 | { .name = "Wedge Angle", | 320 | { .name = "Wedge Angle", |
282 | .parent_nid = VOICE_FOCUS, | 321 | .parent_nid = VOICE_FOCUS, |
283 | .nid = WEDGE_ANGLE, | 322 | .nid = WEDGE_ANGLE, |
@@ -392,14 +431,14 @@ struct ct_voicefx_preset { | |||
392 | unsigned int vals[VOICEFX_MAX_PARAM_COUNT]; | 431 | unsigned int vals[VOICEFX_MAX_PARAM_COUNT]; |
393 | }; | 432 | }; |
394 | 433 | ||
395 | static struct ct_voicefx ca0132_voicefx = { | 434 | static const struct ct_voicefx ca0132_voicefx = { |
396 | .name = "VoiceFX Capture Switch", | 435 | .name = "VoiceFX Capture Switch", |
397 | .nid = VOICEFX, | 436 | .nid = VOICEFX, |
398 | .mid = 0x95, | 437 | .mid = 0x95, |
399 | .reqs = {10, 11, 12, 13, 14, 15, 16, 17, 18} | 438 | .reqs = {10, 11, 12, 13, 14, 15, 16, 17, 18} |
400 | }; | 439 | }; |
401 | 440 | ||
402 | static struct ct_voicefx_preset ca0132_voicefx_presets[] = { | 441 | static const struct ct_voicefx_preset ca0132_voicefx_presets[] = { |
403 | { .name = "Neutral", | 442 | { .name = "Neutral", |
404 | .vals = { 0x00000000, 0x43C80000, 0x44AF0000, | 443 | .vals = { 0x00000000, 0x43C80000, 0x44AF0000, |
405 | 0x44FA0000, 0x3F800000, 0x3F800000, | 444 | 0x44FA0000, 0x3F800000, 0x3F800000, |
@@ -472,6 +511,161 @@ static struct ct_voicefx_preset ca0132_voicefx_presets[] = { | |||
472 | } | 511 | } |
473 | }; | 512 | }; |
474 | 513 | ||
514 | /* ca0132 EQ presets, taken from Windows Sound Blaster Z Driver */ | ||
515 | |||
516 | #define EQ_PRESET_MAX_PARAM_COUNT 11 | ||
517 | |||
518 | struct ct_eq { | ||
519 | char *name; | ||
520 | hda_nid_t nid; | ||
521 | int mid; | ||
522 | int reqs[EQ_PRESET_MAX_PARAM_COUNT]; /*effect module request*/ | ||
523 | }; | ||
524 | |||
525 | struct ct_eq_preset { | ||
526 | char *name; /*preset name*/ | ||
527 | unsigned int vals[EQ_PRESET_MAX_PARAM_COUNT]; | ||
528 | }; | ||
529 | |||
530 | static const struct ct_eq ca0132_alt_eq_enum = { | ||
531 | .name = "FX: Equalizer Preset Switch", | ||
532 | .nid = EQ_PRESET_ENUM, | ||
533 | .mid = 0x96, | ||
534 | .reqs = {10, 11, 12, 13, 14, 15, 16, 17, 18, 19, 20} | ||
535 | }; | ||
536 | |||
537 | |||
538 | static const struct ct_eq_preset ca0132_alt_eq_presets[] = { | ||
539 | { .name = "Flat", | ||
540 | .vals = { 0x00000000, 0x00000000, 0x00000000, | ||
541 | 0x00000000, 0x00000000, 0x00000000, | ||
542 | 0x00000000, 0x00000000, 0x00000000, | ||
543 | 0x00000000, 0x00000000 } | ||
544 | }, | ||
545 | { .name = "Acoustic", | ||
546 | .vals = { 0x00000000, 0x00000000, 0x3F8CCCCD, | ||
547 | 0x40000000, 0x00000000, 0x00000000, | ||
548 | 0x00000000, 0x00000000, 0x40000000, | ||
549 | 0x40000000, 0x40000000 } | ||
550 | }, | ||
551 | { .name = "Classical", | ||
552 | .vals = { 0x00000000, 0x00000000, 0x40C00000, | ||
553 | 0x40C00000, 0x40466666, 0x00000000, | ||
554 | 0x00000000, 0x00000000, 0x00000000, | ||
555 | 0x40466666, 0x40466666 } | ||
556 | }, | ||
557 | { .name = "Country", | ||
558 | .vals = { 0x00000000, 0xBF99999A, 0x00000000, | ||
559 | 0x3FA66666, 0x3FA66666, 0x3F8CCCCD, | ||
560 | 0x00000000, 0x00000000, 0x40000000, | ||
561 | 0x40466666, 0x40800000 } | ||
562 | }, | ||
563 | { .name = "Dance", | ||
564 | .vals = { 0x00000000, 0xBF99999A, 0x40000000, | ||
565 | 0x40466666, 0x40866666, 0xBF99999A, | ||
566 | 0xBF99999A, 0x00000000, 0x00000000, | ||
567 | 0x40800000, 0x40800000 } | ||
568 | }, | ||
569 | { .name = "Jazz", | ||
570 | .vals = { 0x00000000, 0x00000000, 0x00000000, | ||
571 | 0x3F8CCCCD, 0x40800000, 0x40800000, | ||
572 | 0x40800000, 0x00000000, 0x3F8CCCCD, | ||
573 | 0x40466666, 0x40466666 } | ||
574 | }, | ||
575 | { .name = "New Age", | ||
576 | .vals = { 0x00000000, 0x00000000, 0x40000000, | ||
577 | 0x40000000, 0x00000000, 0x00000000, | ||
578 | 0x00000000, 0x3F8CCCCD, 0x40000000, | ||
579 | 0x40000000, 0x40000000 } | ||
580 | }, | ||
581 | { .name = "Pop", | ||
582 | .vals = { 0x00000000, 0xBFCCCCCD, 0x00000000, | ||
583 | 0x40000000, 0x40000000, 0x00000000, | ||
584 | 0xBF99999A, 0xBF99999A, 0x00000000, | ||
585 | 0x40466666, 0x40C00000 } | ||
586 | }, | ||
587 | { .name = "Rock", | ||
588 | .vals = { 0x00000000, 0xBF99999A, 0xBF99999A, | ||
589 | 0x3F8CCCCD, 0x40000000, 0xBF99999A, | ||
590 | 0xBF99999A, 0x00000000, 0x00000000, | ||
591 | 0x40800000, 0x40800000 } | ||
592 | }, | ||
593 | { .name = "Vocal", | ||
594 | .vals = { 0x00000000, 0xC0000000, 0xBF99999A, | ||
595 | 0xBF99999A, 0x00000000, 0x40466666, | ||
596 | 0x40800000, 0x40466666, 0x00000000, | ||
597 | 0x00000000, 0x3F8CCCCD } | ||
598 | } | ||
599 | }; | ||
600 | |||
601 | /* DSP command sequences for ca0132_alt_select_out */ | ||
602 | #define ALT_OUT_SET_MAX_COMMANDS 9 /* Max number of commands in sequence */ | ||
603 | struct ca0132_alt_out_set { | ||
604 | char *name; /*preset name*/ | ||
605 | unsigned char commands; | ||
606 | unsigned int mids[ALT_OUT_SET_MAX_COMMANDS]; | ||
607 | unsigned int reqs[ALT_OUT_SET_MAX_COMMANDS]; | ||
608 | unsigned int vals[ALT_OUT_SET_MAX_COMMANDS]; | ||
609 | }; | ||
610 | |||
611 | static const struct ca0132_alt_out_set alt_out_presets[] = { | ||
612 | { .name = "Line Out", | ||
613 | .commands = 7, | ||
614 | .mids = { 0x96, 0x96, 0x96, 0x8F, | ||
615 | 0x96, 0x96, 0x96 }, | ||
616 | .reqs = { 0x19, 0x17, 0x18, 0x01, | ||
617 | 0x1F, 0x15, 0x3A }, | ||
618 | .vals = { 0x3F000000, 0x42A00000, 0x00000000, | ||
619 | 0x00000000, 0x00000000, 0x00000000, | ||
620 | 0x00000000 } | ||
621 | }, | ||
622 | { .name = "Headphone", | ||
623 | .commands = 7, | ||
624 | .mids = { 0x96, 0x96, 0x96, 0x8F, | ||
625 | 0x96, 0x96, 0x96 }, | ||
626 | .reqs = { 0x19, 0x17, 0x18, 0x01, | ||
627 | 0x1F, 0x15, 0x3A }, | ||
628 | .vals = { 0x3F000000, 0x42A00000, 0x00000000, | ||
629 | 0x00000000, 0x00000000, 0x00000000, | ||
630 | 0x00000000 } | ||
631 | }, | ||
632 | { .name = "Surround", | ||
633 | .commands = 8, | ||
634 | .mids = { 0x96, 0x8F, 0x96, 0x96, | ||
635 | 0x96, 0x96, 0x96, 0x96 }, | ||
636 | .reqs = { 0x18, 0x01, 0x1F, 0x15, | ||
637 | 0x3A, 0x1A, 0x1B, 0x1C }, | ||
638 | .vals = { 0x00000000, 0x00000000, 0x00000000, | ||
639 | 0x00000000, 0x00000000, 0x00000000, | ||
640 | 0x00000000, 0x00000000 } | ||
641 | } | ||
642 | }; | ||
643 | |||
644 | /* | ||
645 | * DSP volume setting structs. Req 1 is left volume, req 2 is right volume, | ||
646 | * and I don't know what the third req is, but it's always zero. I assume it's | ||
647 | * some sort of update or set command to tell the DSP there's new volume info. | ||
648 | */ | ||
649 | #define DSP_VOL_OUT 0 | ||
650 | #define DSP_VOL_IN 1 | ||
651 | |||
652 | struct ct_dsp_volume_ctl { | ||
653 | hda_nid_t vnid; | ||
654 | int mid; /* module ID*/ | ||
655 | unsigned int reqs[3]; /* scp req ID */ | ||
656 | }; | ||
657 | |||
658 | static const struct ct_dsp_volume_ctl ca0132_alt_vol_ctls[] = { | ||
659 | { .vnid = VNID_SPK, | ||
660 | .mid = 0x32, | ||
661 | .reqs = {3, 4, 2} | ||
662 | }, | ||
663 | { .vnid = VNID_MIC, | ||
664 | .mid = 0x37, | ||
665 | .reqs = {2, 3, 1} | ||
666 | } | ||
667 | }; | ||
668 | |||
475 | enum hda_cmd_vendor_io { | 669 | enum hda_cmd_vendor_io { |
476 | /* for DspIO node */ | 670 | /* for DspIO node */ |
477 | VENDOR_DSPIO_SCP_WRITE_DATA_LOW = 0x000, | 671 | VENDOR_DSPIO_SCP_WRITE_DATA_LOW = 0x000, |
@@ -698,11 +892,12 @@ enum dsp_download_state { | |||
698 | */ | 892 | */ |
699 | 893 | ||
700 | struct ca0132_spec { | 894 | struct ca0132_spec { |
701 | struct snd_kcontrol_new *mixers[5]; | 895 | const struct snd_kcontrol_new *mixers[5]; |
702 | unsigned int num_mixers; | 896 | unsigned int num_mixers; |
703 | const struct hda_verb *base_init_verbs; | 897 | const struct hda_verb *base_init_verbs; |
704 | const struct hda_verb *base_exit_verbs; | 898 | const struct hda_verb *base_exit_verbs; |
705 | const struct hda_verb *chip_init_verbs; | 899 | const struct hda_verb *chip_init_verbs; |
900 | const struct hda_verb *sbz_init_verbs; | ||
706 | struct hda_verb *spec_init_verbs; | 901 | struct hda_verb *spec_init_verbs; |
707 | struct auto_pin_cfg autocfg; | 902 | struct auto_pin_cfg autocfg; |
708 | 903 | ||
@@ -719,6 +914,7 @@ struct ca0132_spec { | |||
719 | hda_nid_t shared_mic_nid; | 914 | hda_nid_t shared_mic_nid; |
720 | hda_nid_t shared_out_nid; | 915 | hda_nid_t shared_out_nid; |
721 | hda_nid_t unsol_tag_hp; | 916 | hda_nid_t unsol_tag_hp; |
917 | hda_nid_t unsol_tag_front_hp; /* for desktop ca0132 codecs */ | ||
722 | hda_nid_t unsol_tag_amic1; | 918 | hda_nid_t unsol_tag_amic1; |
723 | 919 | ||
724 | /* chip access */ | 920 | /* chip access */ |
@@ -734,6 +930,9 @@ struct ca0132_spec { | |||
734 | unsigned int scp_resp_header; | 930 | unsigned int scp_resp_header; |
735 | unsigned int scp_resp_data[4]; | 931 | unsigned int scp_resp_data[4]; |
736 | unsigned int scp_resp_count; | 932 | unsigned int scp_resp_count; |
933 | bool alt_firmware_present; | ||
934 | bool startup_check_entered; | ||
935 | bool dsp_reload; | ||
737 | 936 | ||
738 | /* mixer and effects related */ | 937 | /* mixer and effects related */ |
739 | unsigned char dmic_ctl; | 938 | unsigned char dmic_ctl; |
@@ -746,6 +945,17 @@ struct ca0132_spec { | |||
746 | long effects_switch[EFFECTS_COUNT]; | 945 | long effects_switch[EFFECTS_COUNT]; |
747 | long voicefx_val; | 946 | long voicefx_val; |
748 | long cur_mic_boost; | 947 | long cur_mic_boost; |
948 | /* ca0132_alt control related values */ | ||
949 | unsigned char in_enum_val; | ||
950 | unsigned char out_enum_val; | ||
951 | unsigned char mic_boost_enum_val; | ||
952 | unsigned char smart_volume_setting; | ||
953 | long fx_ctl_val[EFFECT_LEVEL_SLIDERS]; | ||
954 | long xbass_xover_freq; | ||
955 | long eq_preset_val; | ||
956 | unsigned int tlv[4]; | ||
957 | struct hda_vmaster_mute_hook vmaster_mute; | ||
958 | |||
749 | 959 | ||
750 | struct hda_codec *codec; | 960 | struct hda_codec *codec; |
751 | struct delayed_work unsol_hp_work; | 961 | struct delayed_work unsol_hp_work; |
@@ -754,6 +964,25 @@ struct ca0132_spec { | |||
754 | #ifdef ENABLE_TUNING_CONTROLS | 964 | #ifdef ENABLE_TUNING_CONTROLS |
755 | long cur_ctl_vals[TUNING_CTLS_COUNT]; | 965 | long cur_ctl_vals[TUNING_CTLS_COUNT]; |
756 | #endif | 966 | #endif |
967 | /* | ||
968 | * Sound Blaster Z PCI region 2 iomem, used for input and output | ||
969 | * switching, and other unknown commands. | ||
970 | */ | ||
971 | void __iomem *mem_base; | ||
972 | |||
973 | /* | ||
974 | * Whether or not to use the alt functions like alt_select_out, | ||
975 | * alt_select_in, etc. Only used on desktop codecs for now, because of | ||
976 | * surround sound support. | ||
977 | */ | ||
978 | bool use_alt_functions; | ||
979 | |||
980 | /* | ||
981 | * Whether or not to use alt controls: volume effect sliders, EQ | ||
982 | * presets, smart volume presets, and new control names with FX prefix. | ||
983 | * Renames PlayEnhancement and CrystalVoice too. | ||
984 | */ | ||
985 | bool use_alt_controls; | ||
757 | }; | 986 | }; |
758 | 987 | ||
759 | /* | 988 | /* |
@@ -762,6 +991,8 @@ struct ca0132_spec { | |||
762 | enum { | 991 | enum { |
763 | QUIRK_NONE, | 992 | QUIRK_NONE, |
764 | QUIRK_ALIENWARE, | 993 | QUIRK_ALIENWARE, |
994 | QUIRK_SBZ, | ||
995 | QUIRK_R3DI, | ||
765 | }; | 996 | }; |
766 | 997 | ||
767 | static const struct hda_pintbl alienware_pincfgs[] = { | 998 | static const struct hda_pintbl alienware_pincfgs[] = { |
@@ -778,10 +1009,44 @@ static const struct hda_pintbl alienware_pincfgs[] = { | |||
778 | {} | 1009 | {} |
779 | }; | 1010 | }; |
780 | 1011 | ||
1012 | /* Sound Blaster Z pin configs taken from Windows Driver */ | ||
1013 | static const struct hda_pintbl sbz_pincfgs[] = { | ||
1014 | { 0x0b, 0x01017010 }, /* Port G -- Lineout FRONT L/R */ | ||
1015 | { 0x0c, 0x014510f0 }, /* SPDIF Out 1 */ | ||
1016 | { 0x0d, 0x014510f0 }, /* Digital Out */ | ||
1017 | { 0x0e, 0x01c510f0 }, /* SPDIF In */ | ||
1018 | { 0x0f, 0x0221701f }, /* Port A -- BackPanel HP */ | ||
1019 | { 0x10, 0x01017012 }, /* Port D -- Center/LFE or FP Hp */ | ||
1020 | { 0x11, 0x01017014 }, /* Port B -- LineMicIn2 / Rear L/R */ | ||
1021 | { 0x12, 0x01a170f0 }, /* Port C -- LineIn1 */ | ||
1022 | { 0x13, 0x908700f0 }, /* What U Hear In*/ | ||
1023 | { 0x18, 0x50d000f0 }, /* N/A */ | ||
1024 | {} | ||
1025 | }; | ||
1026 | |||
1027 | /* Recon3D integrated pin configs taken from Windows Driver */ | ||
1028 | static const struct hda_pintbl r3di_pincfgs[] = { | ||
1029 | { 0x0b, 0x01014110 }, /* Port G -- Lineout FRONT L/R */ | ||
1030 | { 0x0c, 0x014510f0 }, /* SPDIF Out 1 */ | ||
1031 | { 0x0d, 0x014510f0 }, /* Digital Out */ | ||
1032 | { 0x0e, 0x41c520f0 }, /* SPDIF In */ | ||
1033 | { 0x0f, 0x0221401f }, /* Port A -- BackPanel HP */ | ||
1034 | { 0x10, 0x01016011 }, /* Port D -- Center/LFE or FP Hp */ | ||
1035 | { 0x11, 0x01011014 }, /* Port B -- LineMicIn2 / Rear L/R */ | ||
1036 | { 0x12, 0x02a090f0 }, /* Port C -- LineIn1 */ | ||
1037 | { 0x13, 0x908700f0 }, /* What U Hear In*/ | ||
1038 | { 0x18, 0x500000f0 }, /* N/A */ | ||
1039 | {} | ||
1040 | }; | ||
1041 | |||
781 | static const struct snd_pci_quirk ca0132_quirks[] = { | 1042 | static const struct snd_pci_quirk ca0132_quirks[] = { |
782 | SND_PCI_QUIRK(0x1028, 0x0685, "Alienware 15 2015", QUIRK_ALIENWARE), | 1043 | SND_PCI_QUIRK(0x1028, 0x0685, "Alienware 15 2015", QUIRK_ALIENWARE), |
783 | SND_PCI_QUIRK(0x1028, 0x0688, "Alienware 17 2015", QUIRK_ALIENWARE), | 1044 | SND_PCI_QUIRK(0x1028, 0x0688, "Alienware 17 2015", QUIRK_ALIENWARE), |
784 | SND_PCI_QUIRK(0x1028, 0x0708, "Alienware 15 R2 2016", QUIRK_ALIENWARE), | 1045 | SND_PCI_QUIRK(0x1028, 0x0708, "Alienware 15 R2 2016", QUIRK_ALIENWARE), |
1046 | SND_PCI_QUIRK(0x1102, 0x0010, "Sound Blaster Z", QUIRK_SBZ), | ||
1047 | SND_PCI_QUIRK(0x1102, 0x0023, "Sound Blaster Z", QUIRK_SBZ), | ||
1048 | SND_PCI_QUIRK(0x1458, 0xA016, "Recon3Di", QUIRK_R3DI), | ||
1049 | SND_PCI_QUIRK(0x1458, 0xA036, "Recon3Di", QUIRK_R3DI), | ||
785 | {} | 1050 | {} |
786 | }; | 1051 | }; |
787 | 1052 | ||
@@ -965,6 +1230,29 @@ exit: | |||
965 | } | 1230 | } |
966 | 1231 | ||
967 | /* | 1232 | /* |
1233 | * Write given value to the given address through the chip I/O widget. | ||
1234 | * not protected by the Mutex | ||
1235 | */ | ||
1236 | static int chipio_write_no_mutex(struct hda_codec *codec, | ||
1237 | unsigned int chip_addx, const unsigned int data) | ||
1238 | { | ||
1239 | int err; | ||
1240 | |||
1241 | |||
1242 | /* write the address, and if successful proceed to write data */ | ||
1243 | err = chipio_write_address(codec, chip_addx); | ||
1244 | if (err < 0) | ||
1245 | goto exit; | ||
1246 | |||
1247 | err = chipio_write_data(codec, data); | ||
1248 | if (err < 0) | ||
1249 | goto exit; | ||
1250 | |||
1251 | exit: | ||
1252 | return err; | ||
1253 | } | ||
1254 | |||
1255 | /* | ||
968 | * Write multiple values to the given address through the chip I/O widget. | 1256 | * Write multiple values to the given address through the chip I/O widget. |
969 | * protected by the Mutex | 1257 | * protected by the Mutex |
970 | */ | 1258 | */ |
@@ -1058,6 +1346,81 @@ static void chipio_set_control_param(struct hda_codec *codec, | |||
1058 | } | 1346 | } |
1059 | 1347 | ||
1060 | /* | 1348 | /* |
1349 | * Set chip parameters through the chip I/O widget. NO MUTEX. | ||
1350 | */ | ||
1351 | static void chipio_set_control_param_no_mutex(struct hda_codec *codec, | ||
1352 | enum control_param_id param_id, int param_val) | ||
1353 | { | ||
1354 | int val; | ||
1355 | |||
1356 | if ((param_id < 32) && (param_val < 8)) { | ||
1357 | val = (param_val << 5) | (param_id); | ||
1358 | snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0, | ||
1359 | VENDOR_CHIPIO_PARAM_SET, val); | ||
1360 | } else { | ||
1361 | if (chipio_send(codec, VENDOR_CHIPIO_STATUS, 0) == 0) { | ||
1362 | snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0, | ||
1363 | VENDOR_CHIPIO_PARAM_EX_ID_SET, | ||
1364 | param_id); | ||
1365 | snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0, | ||
1366 | VENDOR_CHIPIO_PARAM_EX_VALUE_SET, | ||
1367 | param_val); | ||
1368 | } | ||
1369 | } | ||
1370 | } | ||
1371 | /* | ||
1372 | * Connect stream to a source point, and then connect | ||
1373 | * that source point to a destination point. | ||
1374 | */ | ||
1375 | static void chipio_set_stream_source_dest(struct hda_codec *codec, | ||
1376 | int streamid, int source_point, int dest_point) | ||
1377 | { | ||
1378 | chipio_set_control_param_no_mutex(codec, | ||
1379 | CONTROL_PARAM_STREAM_ID, streamid); | ||
1380 | chipio_set_control_param_no_mutex(codec, | ||
1381 | CONTROL_PARAM_STREAM_SOURCE_CONN_POINT, source_point); | ||
1382 | chipio_set_control_param_no_mutex(codec, | ||
1383 | CONTROL_PARAM_STREAM_DEST_CONN_POINT, dest_point); | ||
1384 | } | ||
1385 | |||
1386 | /* | ||
1387 | * Set number of channels in the selected stream. | ||
1388 | */ | ||
1389 | static void chipio_set_stream_channels(struct hda_codec *codec, | ||
1390 | int streamid, unsigned int channels) | ||
1391 | { | ||
1392 | chipio_set_control_param_no_mutex(codec, | ||
1393 | CONTROL_PARAM_STREAM_ID, streamid); | ||
1394 | chipio_set_control_param_no_mutex(codec, | ||
1395 | CONTROL_PARAM_STREAMS_CHANNELS, channels); | ||
1396 | } | ||
1397 | |||
1398 | /* | ||
1399 | * Enable/Disable audio stream. | ||
1400 | */ | ||
1401 | static void chipio_set_stream_control(struct hda_codec *codec, | ||
1402 | int streamid, int enable) | ||
1403 | { | ||
1404 | chipio_set_control_param_no_mutex(codec, | ||
1405 | CONTROL_PARAM_STREAM_ID, streamid); | ||
1406 | chipio_set_control_param_no_mutex(codec, | ||
1407 | CONTROL_PARAM_STREAM_CONTROL, enable); | ||
1408 | } | ||
1409 | |||
1410 | |||
1411 | /* | ||
1412 | * Set sampling rate of the connection point. NO MUTEX. | ||
1413 | */ | ||
1414 | static void chipio_set_conn_rate_no_mutex(struct hda_codec *codec, | ||
1415 | int connid, enum ca0132_sample_rate rate) | ||
1416 | { | ||
1417 | chipio_set_control_param_no_mutex(codec, | ||
1418 | CONTROL_PARAM_CONN_POINT_ID, connid); | ||
1419 | chipio_set_control_param_no_mutex(codec, | ||
1420 | CONTROL_PARAM_CONN_POINT_SAMPLE_RATE, rate); | ||
1421 | } | ||
1422 | |||
1423 | /* | ||
1061 | * Set sampling rate of the connection point. | 1424 | * Set sampling rate of the connection point. |
1062 | */ | 1425 | */ |
1063 | static void chipio_set_conn_rate(struct hda_codec *codec, | 1426 | static void chipio_set_conn_rate(struct hda_codec *codec, |
@@ -1420,8 +1783,8 @@ static int dspio_send_scp_message(struct hda_codec *codec, | |||
1420 | * Returns zero or a negative error code. | 1783 | * Returns zero or a negative error code. |
1421 | */ | 1784 | */ |
1422 | static int dspio_scp(struct hda_codec *codec, | 1785 | static int dspio_scp(struct hda_codec *codec, |
1423 | int mod_id, int req, int dir, void *data, unsigned int len, | 1786 | int mod_id, int src_id, int req, int dir, const void *data, |
1424 | void *reply, unsigned int *reply_len) | 1787 | unsigned int len, void *reply, unsigned int *reply_len) |
1425 | { | 1788 | { |
1426 | int status = 0; | 1789 | int status = 0; |
1427 | struct scp_msg scp_send, scp_reply; | 1790 | struct scp_msg scp_send, scp_reply; |
@@ -1445,7 +1808,7 @@ static int dspio_scp(struct hda_codec *codec, | |||
1445 | return -EINVAL; | 1808 | return -EINVAL; |
1446 | } | 1809 | } |
1447 | 1810 | ||
1448 | scp_send.hdr = make_scp_header(mod_id, 0x20, (dir == SCP_GET), req, | 1811 | scp_send.hdr = make_scp_header(mod_id, src_id, (dir == SCP_GET), req, |
1449 | 0, 0, 0, len/sizeof(unsigned int)); | 1812 | 0, 0, 0, len/sizeof(unsigned int)); |
1450 | if (data != NULL && len > 0) { | 1813 | if (data != NULL && len > 0) { |
1451 | len = min((unsigned int)(sizeof(scp_send.data)), len); | 1814 | len = min((unsigned int)(sizeof(scp_send.data)), len); |
@@ -1502,15 +1865,24 @@ static int dspio_scp(struct hda_codec *codec, | |||
1502 | * Set DSP parameters | 1865 | * Set DSP parameters |
1503 | */ | 1866 | */ |
1504 | static int dspio_set_param(struct hda_codec *codec, int mod_id, | 1867 | static int dspio_set_param(struct hda_codec *codec, int mod_id, |
1505 | int req, void *data, unsigned int len) | 1868 | int src_id, int req, const void *data, unsigned int len) |
1506 | { | 1869 | { |
1507 | return dspio_scp(codec, mod_id, req, SCP_SET, data, len, NULL, NULL); | 1870 | return dspio_scp(codec, mod_id, src_id, req, SCP_SET, data, len, NULL, |
1871 | NULL); | ||
1508 | } | 1872 | } |
1509 | 1873 | ||
1510 | static int dspio_set_uint_param(struct hda_codec *codec, int mod_id, | 1874 | static int dspio_set_uint_param(struct hda_codec *codec, int mod_id, |
1511 | int req, unsigned int data) | 1875 | int req, const unsigned int data) |
1512 | { | 1876 | { |
1513 | return dspio_set_param(codec, mod_id, req, &data, sizeof(unsigned int)); | 1877 | return dspio_set_param(codec, mod_id, 0x20, req, &data, |
1878 | sizeof(unsigned int)); | ||
1879 | } | ||
1880 | |||
1881 | static int dspio_set_uint_param_no_source(struct hda_codec *codec, int mod_id, | ||
1882 | int req, const unsigned int data) | ||
1883 | { | ||
1884 | return dspio_set_param(codec, mod_id, 0x00, req, &data, | ||
1885 | sizeof(unsigned int)); | ||
1514 | } | 1886 | } |
1515 | 1887 | ||
1516 | /* | 1888 | /* |
@@ -1522,8 +1894,9 @@ static int dspio_alloc_dma_chan(struct hda_codec *codec, unsigned int *dma_chan) | |||
1522 | unsigned int size = sizeof(dma_chan); | 1894 | unsigned int size = sizeof(dma_chan); |
1523 | 1895 | ||
1524 | codec_dbg(codec, " dspio_alloc_dma_chan() -- begin\n"); | 1896 | codec_dbg(codec, " dspio_alloc_dma_chan() -- begin\n"); |
1525 | status = dspio_scp(codec, MASTERCONTROL, MASTERCONTROL_ALLOC_DMA_CHAN, | 1897 | status = dspio_scp(codec, MASTERCONTROL, 0x20, |
1526 | SCP_GET, NULL, 0, dma_chan, &size); | 1898 | MASTERCONTROL_ALLOC_DMA_CHAN, SCP_GET, NULL, 0, |
1899 | dma_chan, &size); | ||
1527 | 1900 | ||
1528 | if (status < 0) { | 1901 | if (status < 0) { |
1529 | codec_dbg(codec, "dspio_alloc_dma_chan: SCP Failed\n"); | 1902 | codec_dbg(codec, "dspio_alloc_dma_chan: SCP Failed\n"); |
@@ -1552,8 +1925,9 @@ static int dspio_free_dma_chan(struct hda_codec *codec, unsigned int dma_chan) | |||
1552 | codec_dbg(codec, " dspio_free_dma_chan() -- begin\n"); | 1925 | codec_dbg(codec, " dspio_free_dma_chan() -- begin\n"); |
1553 | codec_dbg(codec, "dspio_free_dma_chan: chan=%d\n", dma_chan); | 1926 | codec_dbg(codec, "dspio_free_dma_chan: chan=%d\n", dma_chan); |
1554 | 1927 | ||
1555 | status = dspio_scp(codec, MASTERCONTROL, MASTERCONTROL_ALLOC_DMA_CHAN, | 1928 | status = dspio_scp(codec, MASTERCONTROL, 0x20, |
1556 | SCP_SET, &dma_chan, sizeof(dma_chan), NULL, &dummy); | 1929 | MASTERCONTROL_ALLOC_DMA_CHAN, SCP_SET, &dma_chan, |
1930 | sizeof(dma_chan), NULL, &dummy); | ||
1557 | 1931 | ||
1558 | if (status < 0) { | 1932 | if (status < 0) { |
1559 | codec_dbg(codec, "dspio_free_dma_chan: SCP Failed\n"); | 1933 | codec_dbg(codec, "dspio_free_dma_chan: SCP Failed\n"); |
@@ -2575,14 +2949,16 @@ exit: | |||
2575 | */ | 2949 | */ |
2576 | static void dspload_post_setup(struct hda_codec *codec) | 2950 | static void dspload_post_setup(struct hda_codec *codec) |
2577 | { | 2951 | { |
2952 | struct ca0132_spec *spec = codec->spec; | ||
2578 | codec_dbg(codec, "---- dspload_post_setup ------\n"); | 2953 | codec_dbg(codec, "---- dspload_post_setup ------\n"); |
2954 | if (!spec->use_alt_functions) { | ||
2955 | /*set DSP speaker to 2.0 configuration*/ | ||
2956 | chipio_write(codec, XRAM_XRAM_INST_OFFSET(0x18), 0x08080080); | ||
2957 | chipio_write(codec, XRAM_XRAM_INST_OFFSET(0x19), 0x3f800000); | ||
2579 | 2958 | ||
2580 | /*set DSP speaker to 2.0 configuration*/ | 2959 | /*update write pointer*/ |
2581 | chipio_write(codec, XRAM_XRAM_INST_OFFSET(0x18), 0x08080080); | 2960 | chipio_write(codec, XRAM_XRAM_INST_OFFSET(0x29), 0x00000002); |
2582 | chipio_write(codec, XRAM_XRAM_INST_OFFSET(0x19), 0x3f800000); | 2961 | } |
2583 | |||
2584 | /*update write pointer*/ | ||
2585 | chipio_write(codec, XRAM_XRAM_INST_OFFSET(0x29), 0x00000002); | ||
2586 | } | 2962 | } |
2587 | 2963 | ||
2588 | /** | 2964 | /** |
@@ -2690,6 +3066,170 @@ static bool dspload_wait_loaded(struct hda_codec *codec) | |||
2690 | } | 3066 | } |
2691 | 3067 | ||
2692 | /* | 3068 | /* |
3069 | * Setup GPIO for the other variants of Core3D. | ||
3070 | */ | ||
3071 | |||
3072 | /* | ||
3073 | * Sets up the GPIO pins so that they are discoverable. If this isn't done, | ||
3074 | * the card shows as having no GPIO pins. | ||
3075 | */ | ||
3076 | static void ca0132_gpio_init(struct hda_codec *codec) | ||
3077 | { | ||
3078 | struct ca0132_spec *spec = codec->spec; | ||
3079 | |||
3080 | switch (spec->quirk) { | ||
3081 | case QUIRK_SBZ: | ||
3082 | snd_hda_codec_write(codec, 0x01, 0, 0x793, 0x00); | ||
3083 | snd_hda_codec_write(codec, 0x01, 0, 0x794, 0x53); | ||
3084 | snd_hda_codec_write(codec, 0x01, 0, 0x790, 0x23); | ||
3085 | break; | ||
3086 | case QUIRK_R3DI: | ||
3087 | snd_hda_codec_write(codec, 0x01, 0, 0x793, 0x00); | ||
3088 | snd_hda_codec_write(codec, 0x01, 0, 0x794, 0x5B); | ||
3089 | break; | ||
3090 | } | ||
3091 | |||
3092 | } | ||
3093 | |||
3094 | /* Sets the GPIO for audio output. */ | ||
3095 | static void ca0132_gpio_setup(struct hda_codec *codec) | ||
3096 | { | ||
3097 | struct ca0132_spec *spec = codec->spec; | ||
3098 | |||
3099 | switch (spec->quirk) { | ||
3100 | case QUIRK_SBZ: | ||
3101 | snd_hda_codec_write(codec, 0x01, 0, | ||
3102 | AC_VERB_SET_GPIO_DIRECTION, 0x07); | ||
3103 | snd_hda_codec_write(codec, 0x01, 0, | ||
3104 | AC_VERB_SET_GPIO_MASK, 0x07); | ||
3105 | snd_hda_codec_write(codec, 0x01, 0, | ||
3106 | AC_VERB_SET_GPIO_DATA, 0x04); | ||
3107 | snd_hda_codec_write(codec, 0x01, 0, | ||
3108 | AC_VERB_SET_GPIO_DATA, 0x06); | ||
3109 | break; | ||
3110 | case QUIRK_R3DI: | ||
3111 | snd_hda_codec_write(codec, 0x01, 0, | ||
3112 | AC_VERB_SET_GPIO_DIRECTION, 0x1E); | ||
3113 | snd_hda_codec_write(codec, 0x01, 0, | ||
3114 | AC_VERB_SET_GPIO_MASK, 0x1F); | ||
3115 | snd_hda_codec_write(codec, 0x01, 0, | ||
3116 | AC_VERB_SET_GPIO_DATA, 0x0C); | ||
3117 | break; | ||
3118 | } | ||
3119 | } | ||
3120 | |||
3121 | /* | ||
3122 | * GPIO control functions for the Recon3D integrated. | ||
3123 | */ | ||
3124 | |||
3125 | enum r3di_gpio_bit { | ||
3126 | /* Bit 1 - Switch between front/rear mic. 0 = rear, 1 = front */ | ||
3127 | R3DI_MIC_SELECT_BIT = 1, | ||
3128 | /* Bit 2 - Switch between headphone/line out. 0 = Headphone, 1 = Line */ | ||
3129 | R3DI_OUT_SELECT_BIT = 2, | ||
3130 | /* | ||
3131 | * I dunno what this actually does, but it stays on until the dsp | ||
3132 | * is downloaded. | ||
3133 | */ | ||
3134 | R3DI_GPIO_DSP_DOWNLOADING = 3, | ||
3135 | /* | ||
3136 | * Same as above, no clue what it does, but it comes on after the dsp | ||
3137 | * is downloaded. | ||
3138 | */ | ||
3139 | R3DI_GPIO_DSP_DOWNLOADED = 4 | ||
3140 | }; | ||
3141 | |||
3142 | enum r3di_mic_select { | ||
3143 | /* Set GPIO bit 1 to 0 for rear mic */ | ||
3144 | R3DI_REAR_MIC = 0, | ||
3145 | /* Set GPIO bit 1 to 1 for front microphone*/ | ||
3146 | R3DI_FRONT_MIC = 1 | ||
3147 | }; | ||
3148 | |||
3149 | enum r3di_out_select { | ||
3150 | /* Set GPIO bit 2 to 0 for headphone */ | ||
3151 | R3DI_HEADPHONE_OUT = 0, | ||
3152 | /* Set GPIO bit 2 to 1 for speaker */ | ||
3153 | R3DI_LINE_OUT = 1 | ||
3154 | }; | ||
3155 | enum r3di_dsp_status { | ||
3156 | /* Set GPIO bit 3 to 1 until DSP is downloaded */ | ||
3157 | R3DI_DSP_DOWNLOADING = 0, | ||
3158 | /* Set GPIO bit 4 to 1 once DSP is downloaded */ | ||
3159 | R3DI_DSP_DOWNLOADED = 1 | ||
3160 | }; | ||
3161 | |||
3162 | |||
3163 | static void r3di_gpio_mic_set(struct hda_codec *codec, | ||
3164 | enum r3di_mic_select cur_mic) | ||
3165 | { | ||
3166 | unsigned int cur_gpio; | ||
3167 | |||
3168 | /* Get the current GPIO Data setup */ | ||
3169 | cur_gpio = snd_hda_codec_read(codec, 0x01, 0, AC_VERB_GET_GPIO_DATA, 0); | ||
3170 | |||
3171 | switch (cur_mic) { | ||
3172 | case R3DI_REAR_MIC: | ||
3173 | cur_gpio &= ~(1 << R3DI_MIC_SELECT_BIT); | ||
3174 | break; | ||
3175 | case R3DI_FRONT_MIC: | ||
3176 | cur_gpio |= (1 << R3DI_MIC_SELECT_BIT); | ||
3177 | break; | ||
3178 | } | ||
3179 | snd_hda_codec_write(codec, codec->core.afg, 0, | ||
3180 | AC_VERB_SET_GPIO_DATA, cur_gpio); | ||
3181 | } | ||
3182 | |||
3183 | static void r3di_gpio_out_set(struct hda_codec *codec, | ||
3184 | enum r3di_out_select cur_out) | ||
3185 | { | ||
3186 | unsigned int cur_gpio; | ||
3187 | |||
3188 | /* Get the current GPIO Data setup */ | ||
3189 | cur_gpio = snd_hda_codec_read(codec, 0x01, 0, AC_VERB_GET_GPIO_DATA, 0); | ||
3190 | |||
3191 | switch (cur_out) { | ||
3192 | case R3DI_HEADPHONE_OUT: | ||
3193 | cur_gpio &= ~(1 << R3DI_OUT_SELECT_BIT); | ||
3194 | break; | ||
3195 | case R3DI_LINE_OUT: | ||
3196 | cur_gpio |= (1 << R3DI_OUT_SELECT_BIT); | ||
3197 | break; | ||
3198 | } | ||
3199 | snd_hda_codec_write(codec, codec->core.afg, 0, | ||
3200 | AC_VERB_SET_GPIO_DATA, cur_gpio); | ||
3201 | } | ||
3202 | |||
3203 | static void r3di_gpio_dsp_status_set(struct hda_codec *codec, | ||
3204 | enum r3di_dsp_status dsp_status) | ||
3205 | { | ||
3206 | unsigned int cur_gpio; | ||
3207 | |||
3208 | /* Get the current GPIO Data setup */ | ||
3209 | cur_gpio = snd_hda_codec_read(codec, 0x01, 0, AC_VERB_GET_GPIO_DATA, 0); | ||
3210 | |||
3211 | switch (dsp_status) { | ||
3212 | case R3DI_DSP_DOWNLOADING: | ||
3213 | cur_gpio |= (1 << R3DI_GPIO_DSP_DOWNLOADING); | ||
3214 | snd_hda_codec_write(codec, codec->core.afg, 0, | ||
3215 | AC_VERB_SET_GPIO_DATA, cur_gpio); | ||
3216 | break; | ||
3217 | case R3DI_DSP_DOWNLOADED: | ||
3218 | /* Set DOWNLOADING bit to 0. */ | ||
3219 | cur_gpio &= ~(1 << R3DI_GPIO_DSP_DOWNLOADING); | ||
3220 | |||
3221 | snd_hda_codec_write(codec, codec->core.afg, 0, | ||
3222 | AC_VERB_SET_GPIO_DATA, cur_gpio); | ||
3223 | |||
3224 | cur_gpio |= (1 << R3DI_GPIO_DSP_DOWNLOADED); | ||
3225 | break; | ||
3226 | } | ||
3227 | |||
3228 | snd_hda_codec_write(codec, codec->core.afg, 0, | ||
3229 | AC_VERB_SET_GPIO_DATA, cur_gpio); | ||
3230 | } | ||
3231 | |||
3232 | /* | ||
2693 | * PCM callbacks | 3233 | * PCM callbacks |
2694 | */ | 3234 | */ |
2695 | static int ca0132_playback_pcm_prepare(struct hda_pcm_stream *hinfo, | 3235 | static int ca0132_playback_pcm_prepare(struct hda_pcm_stream *hinfo, |
@@ -2852,6 +3392,24 @@ static unsigned int ca0132_capture_pcm_delay(struct hda_pcm_stream *info, | |||
2852 | .tlv = { .c = ca0132_volume_tlv }, \ | 3392 | .tlv = { .c = ca0132_volume_tlv }, \ |
2853 | .private_value = HDA_COMPOSE_AMP_VAL(nid, channel, 0, dir) } | 3393 | .private_value = HDA_COMPOSE_AMP_VAL(nid, channel, 0, dir) } |
2854 | 3394 | ||
3395 | /* | ||
3396 | * Creates a mixer control that uses defaults of HDA_CODEC_VOL except for the | ||
3397 | * volume put, which is used for setting the DSP volume. This was done because | ||
3398 | * the ca0132 functions were taking too much time and causing lag. | ||
3399 | */ | ||
3400 | #define CA0132_ALT_CODEC_VOL_MONO(xname, nid, channel, dir) \ | ||
3401 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ | ||
3402 | .name = xname, \ | ||
3403 | .subdevice = HDA_SUBDEV_AMP_FLAG, \ | ||
3404 | .access = SNDRV_CTL_ELEM_ACCESS_READWRITE | \ | ||
3405 | SNDRV_CTL_ELEM_ACCESS_TLV_READ | \ | ||
3406 | SNDRV_CTL_ELEM_ACCESS_TLV_CALLBACK, \ | ||
3407 | .info = snd_hda_mixer_amp_volume_info, \ | ||
3408 | .get = snd_hda_mixer_amp_volume_get, \ | ||
3409 | .put = ca0132_alt_volume_put, \ | ||
3410 | .tlv = { .c = snd_hda_mixer_amp_tlv }, \ | ||
3411 | .private_value = HDA_COMPOSE_AMP_VAL(nid, channel, 0, dir) } | ||
3412 | |||
2855 | #define CA0132_CODEC_MUTE_MONO(xname, nid, channel, dir) \ | 3413 | #define CA0132_CODEC_MUTE_MONO(xname, nid, channel, dir) \ |
2856 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ | 3414 | { .iface = SNDRV_CTL_ELEM_IFACE_MIXER, \ |
2857 | .name = xname, \ | 3415 | .name = xname, \ |
@@ -2864,9 +3422,88 @@ static unsigned int ca0132_capture_pcm_delay(struct hda_pcm_stream *info, | |||
2864 | /* stereo */ | 3422 | /* stereo */ |
2865 | #define CA0132_CODEC_VOL(xname, nid, dir) \ | 3423 | #define CA0132_CODEC_VOL(xname, nid, dir) \ |
2866 | CA0132_CODEC_VOL_MONO(xname, nid, 3, dir) | 3424 | CA0132_CODEC_VOL_MONO(xname, nid, 3, dir) |
3425 | #define CA0132_ALT_CODEC_VOL(xname, nid, dir) \ | ||
3426 | CA0132_ALT_CODEC_VOL_MONO(xname, nid, 3, dir) | ||
2867 | #define CA0132_CODEC_MUTE(xname, nid, dir) \ | 3427 | #define CA0132_CODEC_MUTE(xname, nid, dir) \ |
2868 | CA0132_CODEC_MUTE_MONO(xname, nid, 3, dir) | 3428 | CA0132_CODEC_MUTE_MONO(xname, nid, 3, dir) |
2869 | 3429 | ||
3430 | /* lookup tables */ | ||
3431 | /* | ||
3432 | * Lookup table with decibel values for the DSP. When volume is changed in | ||
3433 | * Windows, the DSP is also sent the dB value in floating point. In Windows, | ||
3434 | * these values have decimal points, probably because the Windows driver | ||
3435 | * actually uses floating point. We can't here, so I made a lookup table of | ||
3436 | * values -90 to 9. -90 is the lowest decibel value for both the ADC's and the | ||
3437 | * DAC's, and 9 is the maximum. | ||
3438 | */ | ||
3439 | static const unsigned int float_vol_db_lookup[] = { | ||
3440 | 0xC2B40000, 0xC2B20000, 0xC2B00000, 0xC2AE0000, 0xC2AC0000, 0xC2AA0000, | ||
3441 | 0xC2A80000, 0xC2A60000, 0xC2A40000, 0xC2A20000, 0xC2A00000, 0xC29E0000, | ||
3442 | 0xC29C0000, 0xC29A0000, 0xC2980000, 0xC2960000, 0xC2940000, 0xC2920000, | ||
3443 | 0xC2900000, 0xC28E0000, 0xC28C0000, 0xC28A0000, 0xC2880000, 0xC2860000, | ||
3444 | 0xC2840000, 0xC2820000, 0xC2800000, 0xC27C0000, 0xC2780000, 0xC2740000, | ||
3445 | 0xC2700000, 0xC26C0000, 0xC2680000, 0xC2640000, 0xC2600000, 0xC25C0000, | ||
3446 | 0xC2580000, 0xC2540000, 0xC2500000, 0xC24C0000, 0xC2480000, 0xC2440000, | ||
3447 | 0xC2400000, 0xC23C0000, 0xC2380000, 0xC2340000, 0xC2300000, 0xC22C0000, | ||
3448 | 0xC2280000, 0xC2240000, 0xC2200000, 0xC21C0000, 0xC2180000, 0xC2140000, | ||
3449 | 0xC2100000, 0xC20C0000, 0xC2080000, 0xC2040000, 0xC2000000, 0xC1F80000, | ||
3450 | 0xC1F00000, 0xC1E80000, 0xC1E00000, 0xC1D80000, 0xC1D00000, 0xC1C80000, | ||
3451 | 0xC1C00000, 0xC1B80000, 0xC1B00000, 0xC1A80000, 0xC1A00000, 0xC1980000, | ||
3452 | 0xC1900000, 0xC1880000, 0xC1800000, 0xC1700000, 0xC1600000, 0xC1500000, | ||
3453 | 0xC1400000, 0xC1300000, 0xC1200000, 0xC1100000, 0xC1000000, 0xC0E00000, | ||
3454 | 0xC0C00000, 0xC0A00000, 0xC0800000, 0xC0400000, 0xC0000000, 0xBF800000, | ||
3455 | 0x00000000, 0x3F800000, 0x40000000, 0x40400000, 0x40800000, 0x40A00000, | ||
3456 | 0x40C00000, 0x40E00000, 0x41000000, 0x41100000 | ||
3457 | }; | ||
3458 | |||
3459 | /* | ||
3460 | * This table counts from float 0 to 1 in increments of .01, which is | ||
3461 | * useful for a few different sliders. | ||
3462 | */ | ||
3463 | static const unsigned int float_zero_to_one_lookup[] = { | ||
3464 | 0x00000000, 0x3C23D70A, 0x3CA3D70A, 0x3CF5C28F, 0x3D23D70A, 0x3D4CCCCD, | ||
3465 | 0x3D75C28F, 0x3D8F5C29, 0x3DA3D70A, 0x3DB851EC, 0x3DCCCCCD, 0x3DE147AE, | ||
3466 | 0x3DF5C28F, 0x3E051EB8, 0x3E0F5C29, 0x3E19999A, 0x3E23D70A, 0x3E2E147B, | ||
3467 | 0x3E3851EC, 0x3E428F5C, 0x3E4CCCCD, 0x3E570A3D, 0x3E6147AE, 0x3E6B851F, | ||
3468 | 0x3E75C28F, 0x3E800000, 0x3E851EB8, 0x3E8A3D71, 0x3E8F5C29, 0x3E947AE1, | ||
3469 | 0x3E99999A, 0x3E9EB852, 0x3EA3D70A, 0x3EA8F5C3, 0x3EAE147B, 0x3EB33333, | ||
3470 | 0x3EB851EC, 0x3EBD70A4, 0x3EC28F5C, 0x3EC7AE14, 0x3ECCCCCD, 0x3ED1EB85, | ||
3471 | 0x3ED70A3D, 0x3EDC28F6, 0x3EE147AE, 0x3EE66666, 0x3EEB851F, 0x3EF0A3D7, | ||
3472 | 0x3EF5C28F, 0x3EFAE148, 0x3F000000, 0x3F028F5C, 0x3F051EB8, 0x3F07AE14, | ||
3473 | 0x3F0A3D71, 0x3F0CCCCD, 0x3F0F5C29, 0x3F11EB85, 0x3F147AE1, 0x3F170A3D, | ||
3474 | 0x3F19999A, 0x3F1C28F6, 0x3F1EB852, 0x3F2147AE, 0x3F23D70A, 0x3F266666, | ||
3475 | 0x3F28F5C3, 0x3F2B851F, 0x3F2E147B, 0x3F30A3D7, 0x3F333333, 0x3F35C28F, | ||
3476 | 0x3F3851EC, 0x3F3AE148, 0x3F3D70A4, 0x3F400000, 0x3F428F5C, 0x3F451EB8, | ||
3477 | 0x3F47AE14, 0x3F4A3D71, 0x3F4CCCCD, 0x3F4F5C29, 0x3F51EB85, 0x3F547AE1, | ||
3478 | 0x3F570A3D, 0x3F59999A, 0x3F5C28F6, 0x3F5EB852, 0x3F6147AE, 0x3F63D70A, | ||
3479 | 0x3F666666, 0x3F68F5C3, 0x3F6B851F, 0x3F6E147B, 0x3F70A3D7, 0x3F733333, | ||
3480 | 0x3F75C28F, 0x3F7851EC, 0x3F7AE148, 0x3F7D70A4, 0x3F800000 | ||
3481 | }; | ||
3482 | |||
3483 | /* | ||
3484 | * This table counts from float 10 to 1000, which is the range of the x-bass | ||
3485 | * crossover slider in Windows. | ||
3486 | */ | ||
3487 | static const unsigned int float_xbass_xover_lookup[] = { | ||
3488 | 0x41200000, 0x41A00000, 0x41F00000, 0x42200000, 0x42480000, 0x42700000, | ||
3489 | 0x428C0000, 0x42A00000, 0x42B40000, 0x42C80000, 0x42DC0000, 0x42F00000, | ||
3490 | 0x43020000, 0x430C0000, 0x43160000, 0x43200000, 0x432A0000, 0x43340000, | ||
3491 | 0x433E0000, 0x43480000, 0x43520000, 0x435C0000, 0x43660000, 0x43700000, | ||
3492 | 0x437A0000, 0x43820000, 0x43870000, 0x438C0000, 0x43910000, 0x43960000, | ||
3493 | 0x439B0000, 0x43A00000, 0x43A50000, 0x43AA0000, 0x43AF0000, 0x43B40000, | ||
3494 | 0x43B90000, 0x43BE0000, 0x43C30000, 0x43C80000, 0x43CD0000, 0x43D20000, | ||
3495 | 0x43D70000, 0x43DC0000, 0x43E10000, 0x43E60000, 0x43EB0000, 0x43F00000, | ||
3496 | 0x43F50000, 0x43FA0000, 0x43FF0000, 0x44020000, 0x44048000, 0x44070000, | ||
3497 | 0x44098000, 0x440C0000, 0x440E8000, 0x44110000, 0x44138000, 0x44160000, | ||
3498 | 0x44188000, 0x441B0000, 0x441D8000, 0x44200000, 0x44228000, 0x44250000, | ||
3499 | 0x44278000, 0x442A0000, 0x442C8000, 0x442F0000, 0x44318000, 0x44340000, | ||
3500 | 0x44368000, 0x44390000, 0x443B8000, 0x443E0000, 0x44408000, 0x44430000, | ||
3501 | 0x44458000, 0x44480000, 0x444A8000, 0x444D0000, 0x444F8000, 0x44520000, | ||
3502 | 0x44548000, 0x44570000, 0x44598000, 0x445C0000, 0x445E8000, 0x44610000, | ||
3503 | 0x44638000, 0x44660000, 0x44688000, 0x446B0000, 0x446D8000, 0x44700000, | ||
3504 | 0x44728000, 0x44750000, 0x44778000, 0x447A0000 | ||
3505 | }; | ||
3506 | |||
2870 | /* The following are for tuning of products */ | 3507 | /* The following are for tuning of products */ |
2871 | #ifdef ENABLE_TUNING_CONTROLS | 3508 | #ifdef ENABLE_TUNING_CONTROLS |
2872 | 3509 | ||
@@ -2942,7 +3579,7 @@ static int tuning_ctl_set(struct hda_codec *codec, hda_nid_t nid, | |||
2942 | break; | 3579 | break; |
2943 | 3580 | ||
2944 | snd_hda_power_up(codec); | 3581 | snd_hda_power_up(codec); |
2945 | dspio_set_param(codec, ca0132_tuning_ctls[i].mid, | 3582 | dspio_set_param(codec, ca0132_tuning_ctls[i].mid, 0x20, |
2946 | ca0132_tuning_ctls[i].req, | 3583 | ca0132_tuning_ctls[i].req, |
2947 | &(lookup[idx]), sizeof(unsigned int)); | 3584 | &(lookup[idx]), sizeof(unsigned int)); |
2948 | snd_hda_power_down(codec); | 3585 | snd_hda_power_down(codec); |
@@ -3068,8 +3705,8 @@ static int equalizer_ctl_put(struct snd_kcontrol *kcontrol, | |||
3068 | return 1; | 3705 | return 1; |
3069 | } | 3706 | } |
3070 | 3707 | ||
3071 | static const DECLARE_TLV_DB_SCALE(voice_focus_db_scale, 2000, 100, 0); | 3708 | static const SNDRV_CTL_TLVD_DECLARE_DB_SCALE(voice_focus_db_scale, 2000, 100, 0); |
3072 | static const DECLARE_TLV_DB_SCALE(eq_db_scale, -2400, 100, 0); | 3709 | static const SNDRV_CTL_TLVD_DECLARE_DB_SCALE(eq_db_scale, -2400, 100, 0); |
3073 | 3710 | ||
3074 | static int add_tuning_control(struct hda_codec *codec, | 3711 | static int add_tuning_control(struct hda_codec *codec, |
3075 | hda_nid_t pnid, hda_nid_t nid, | 3712 | hda_nid_t pnid, hda_nid_t nid, |
@@ -3207,7 +3844,7 @@ static int ca0132_select_out(struct hda_codec *codec) | |||
3207 | pin_ctl & ~PIN_HP); | 3844 | pin_ctl & ~PIN_HP); |
3208 | /* enable speaker node */ | 3845 | /* enable speaker node */ |
3209 | pin_ctl = snd_hda_codec_read(codec, spec->out_pins[0], 0, | 3846 | pin_ctl = snd_hda_codec_read(codec, spec->out_pins[0], 0, |
3210 | AC_VERB_GET_PIN_WIDGET_CONTROL, 0); | 3847 | AC_VERB_GET_PIN_WIDGET_CONTROL, 0); |
3211 | snd_hda_set_pin_ctl(codec, spec->out_pins[0], | 3848 | snd_hda_set_pin_ctl(codec, spec->out_pins[0], |
3212 | pin_ctl | PIN_OUT); | 3849 | pin_ctl | PIN_OUT); |
3213 | } else { | 3850 | } else { |
@@ -3251,13 +3888,209 @@ exit: | |||
3251 | return err < 0 ? err : 0; | 3888 | return err < 0 ? err : 0; |
3252 | } | 3889 | } |
3253 | 3890 | ||
3891 | /* | ||
3892 | * This function behaves similarly to the ca0132_select_out funciton above, | ||
3893 | * except with a few differences. It adds the ability to select the current | ||
3894 | * output with an enumerated control "output source" if the auto detect | ||
3895 | * mute switch is set to off. If the auto detect mute switch is enabled, it | ||
3896 | * will detect either headphone or lineout(SPEAKER_OUT) from jack detection. | ||
3897 | * It also adds the ability to auto-detect the front headphone port. The only | ||
3898 | * way to select surround is to disable auto detect, and set Surround with the | ||
3899 | * enumerated control. | ||
3900 | */ | ||
3901 | static int ca0132_alt_select_out(struct hda_codec *codec) | ||
3902 | { | ||
3903 | struct ca0132_spec *spec = codec->spec; | ||
3904 | unsigned int pin_ctl; | ||
3905 | int jack_present; | ||
3906 | int auto_jack; | ||
3907 | unsigned int i; | ||
3908 | unsigned int tmp; | ||
3909 | int err; | ||
3910 | /* Default Headphone is rear headphone */ | ||
3911 | hda_nid_t headphone_nid = spec->out_pins[1]; | ||
3912 | |||
3913 | codec_dbg(codec, "%s\n", __func__); | ||
3914 | |||
3915 | snd_hda_power_up_pm(codec); | ||
3916 | |||
3917 | auto_jack = spec->vnode_lswitch[VNID_HP_ASEL - VNODE_START_NID]; | ||
3918 | |||
3919 | /* | ||
3920 | * If headphone rear or front is plugged in, set to headphone. | ||
3921 | * If neither is plugged in, set to rear line out. Only if | ||
3922 | * hp/speaker auto detect is enabled. | ||
3923 | */ | ||
3924 | if (auto_jack) { | ||
3925 | jack_present = snd_hda_jack_detect(codec, spec->unsol_tag_hp) || | ||
3926 | snd_hda_jack_detect(codec, spec->unsol_tag_front_hp); | ||
3927 | |||
3928 | if (jack_present) | ||
3929 | spec->cur_out_type = HEADPHONE_OUT; | ||
3930 | else | ||
3931 | spec->cur_out_type = SPEAKER_OUT; | ||
3932 | } else | ||
3933 | spec->cur_out_type = spec->out_enum_val; | ||
3934 | |||
3935 | /* Begin DSP output switch */ | ||
3936 | tmp = FLOAT_ONE; | ||
3937 | err = dspio_set_uint_param(codec, 0x96, 0x3A, tmp); | ||
3938 | if (err < 0) | ||
3939 | goto exit; | ||
3940 | |||
3941 | switch (spec->cur_out_type) { | ||
3942 | case SPEAKER_OUT: | ||
3943 | codec_dbg(codec, "%s speaker\n", __func__); | ||
3944 | /*speaker out config*/ | ||
3945 | switch (spec->quirk) { | ||
3946 | case QUIRK_SBZ: | ||
3947 | writew(0x0007, spec->mem_base + 0x320); | ||
3948 | writew(0x0104, spec->mem_base + 0x320); | ||
3949 | writew(0x0101, spec->mem_base + 0x320); | ||
3950 | chipio_set_control_param(codec, 0x0D, 0x18); | ||
3951 | break; | ||
3952 | case QUIRK_R3DI: | ||
3953 | chipio_set_control_param(codec, 0x0D, 0x24); | ||
3954 | r3di_gpio_out_set(codec, R3DI_LINE_OUT); | ||
3955 | break; | ||
3956 | } | ||
3957 | |||
3958 | /* disable headphone node */ | ||
3959 | pin_ctl = snd_hda_codec_read(codec, spec->out_pins[1], 0, | ||
3960 | AC_VERB_GET_PIN_WIDGET_CONTROL, 0); | ||
3961 | snd_hda_set_pin_ctl(codec, spec->out_pins[1], | ||
3962 | pin_ctl & ~PIN_HP); | ||
3963 | /* enable line-out node */ | ||
3964 | pin_ctl = snd_hda_codec_read(codec, spec->out_pins[0], 0, | ||
3965 | AC_VERB_GET_PIN_WIDGET_CONTROL, 0); | ||
3966 | snd_hda_set_pin_ctl(codec, spec->out_pins[0], | ||
3967 | pin_ctl | PIN_OUT); | ||
3968 | /* Enable EAPD */ | ||
3969 | snd_hda_codec_write(codec, spec->out_pins[0], 0, | ||
3970 | AC_VERB_SET_EAPD_BTLENABLE, 0x01); | ||
3971 | |||
3972 | /* If PlayEnhancement is enabled, set different source */ | ||
3973 | if (spec->effects_switch[PLAY_ENHANCEMENT - EFFECT_START_NID]) | ||
3974 | dspio_set_uint_param(codec, 0x80, 0x04, FLOAT_ONE); | ||
3975 | else | ||
3976 | dspio_set_uint_param(codec, 0x80, 0x04, FLOAT_EIGHT); | ||
3977 | break; | ||
3978 | case HEADPHONE_OUT: | ||
3979 | codec_dbg(codec, "%s hp\n", __func__); | ||
3980 | /* Headphone out config*/ | ||
3981 | switch (spec->quirk) { | ||
3982 | case QUIRK_SBZ: | ||
3983 | writew(0x0107, spec->mem_base + 0x320); | ||
3984 | writew(0x0104, spec->mem_base + 0x320); | ||
3985 | writew(0x0001, spec->mem_base + 0x320); | ||
3986 | chipio_set_control_param(codec, 0x0D, 0x12); | ||
3987 | break; | ||
3988 | case QUIRK_R3DI: | ||
3989 | chipio_set_control_param(codec, 0x0D, 0x21); | ||
3990 | r3di_gpio_out_set(codec, R3DI_HEADPHONE_OUT); | ||
3991 | break; | ||
3992 | } | ||
3993 | |||
3994 | snd_hda_codec_write(codec, spec->out_pins[0], 0, | ||
3995 | AC_VERB_SET_EAPD_BTLENABLE, 0x00); | ||
3996 | |||
3997 | /* disable speaker*/ | ||
3998 | pin_ctl = snd_hda_codec_read(codec, spec->out_pins[0], 0, | ||
3999 | AC_VERB_GET_PIN_WIDGET_CONTROL, 0); | ||
4000 | snd_hda_set_pin_ctl(codec, spec->out_pins[0], | ||
4001 | pin_ctl & ~PIN_HP); | ||
4002 | |||
4003 | /* enable headphone, either front or rear */ | ||
4004 | |||
4005 | if (snd_hda_jack_detect(codec, spec->unsol_tag_front_hp)) | ||
4006 | headphone_nid = spec->out_pins[2]; | ||
4007 | else if (snd_hda_jack_detect(codec, spec->unsol_tag_hp)) | ||
4008 | headphone_nid = spec->out_pins[1]; | ||
4009 | |||
4010 | pin_ctl = snd_hda_codec_read(codec, headphone_nid, 0, | ||
4011 | AC_VERB_GET_PIN_WIDGET_CONTROL, 0); | ||
4012 | snd_hda_set_pin_ctl(codec, headphone_nid, | ||
4013 | pin_ctl | PIN_HP); | ||
4014 | |||
4015 | if (spec->effects_switch[PLAY_ENHANCEMENT - EFFECT_START_NID]) | ||
4016 | dspio_set_uint_param(codec, 0x80, 0x04, FLOAT_ONE); | ||
4017 | else | ||
4018 | dspio_set_uint_param(codec, 0x80, 0x04, FLOAT_ZERO); | ||
4019 | break; | ||
4020 | case SURROUND_OUT: | ||
4021 | codec_dbg(codec, "%s surround\n", __func__); | ||
4022 | /* Surround out config*/ | ||
4023 | switch (spec->quirk) { | ||
4024 | case QUIRK_SBZ: | ||
4025 | writew(0x0007, spec->mem_base + 0x320); | ||
4026 | writew(0x0104, spec->mem_base + 0x320); | ||
4027 | writew(0x0101, spec->mem_base + 0x320); | ||
4028 | chipio_set_control_param(codec, 0x0D, 0x18); | ||
4029 | break; | ||
4030 | case QUIRK_R3DI: | ||
4031 | chipio_set_control_param(codec, 0x0D, 0x24); | ||
4032 | r3di_gpio_out_set(codec, R3DI_LINE_OUT); | ||
4033 | break; | ||
4034 | } | ||
4035 | /* enable line out node */ | ||
4036 | pin_ctl = snd_hda_codec_read(codec, spec->out_pins[0], 0, | ||
4037 | AC_VERB_GET_PIN_WIDGET_CONTROL, 0); | ||
4038 | snd_hda_set_pin_ctl(codec, spec->out_pins[0], | ||
4039 | pin_ctl | PIN_OUT); | ||
4040 | /* Disable headphone out */ | ||
4041 | pin_ctl = snd_hda_codec_read(codec, spec->out_pins[1], 0, | ||
4042 | AC_VERB_GET_PIN_WIDGET_CONTROL, 0); | ||
4043 | snd_hda_set_pin_ctl(codec, spec->out_pins[1], | ||
4044 | pin_ctl & ~PIN_HP); | ||
4045 | /* Enable EAPD on line out */ | ||
4046 | snd_hda_codec_write(codec, spec->out_pins[0], 0, | ||
4047 | AC_VERB_SET_EAPD_BTLENABLE, 0x01); | ||
4048 | /* enable center/lfe out node */ | ||
4049 | pin_ctl = snd_hda_codec_read(codec, spec->out_pins[2], 0, | ||
4050 | AC_VERB_GET_PIN_WIDGET_CONTROL, 0); | ||
4051 | snd_hda_set_pin_ctl(codec, spec->out_pins[2], | ||
4052 | pin_ctl | PIN_OUT); | ||
4053 | /* Now set rear surround node as out. */ | ||
4054 | pin_ctl = snd_hda_codec_read(codec, spec->out_pins[3], 0, | ||
4055 | AC_VERB_GET_PIN_WIDGET_CONTROL, 0); | ||
4056 | snd_hda_set_pin_ctl(codec, spec->out_pins[3], | ||
4057 | pin_ctl | PIN_OUT); | ||
4058 | |||
4059 | if (spec->effects_switch[PLAY_ENHANCEMENT - EFFECT_START_NID]) | ||
4060 | dspio_set_uint_param(codec, 0x80, 0x04, FLOAT_ONE); | ||
4061 | else | ||
4062 | dspio_set_uint_param(codec, 0x80, 0x04, FLOAT_EIGHT); | ||
4063 | break; | ||
4064 | } | ||
4065 | |||
4066 | /* run through the output dsp commands for line-out */ | ||
4067 | for (i = 0; i < alt_out_presets[spec->cur_out_type].commands; i++) { | ||
4068 | err = dspio_set_uint_param(codec, | ||
4069 | alt_out_presets[spec->cur_out_type].mids[i], | ||
4070 | alt_out_presets[spec->cur_out_type].reqs[i], | ||
4071 | alt_out_presets[spec->cur_out_type].vals[i]); | ||
4072 | |||
4073 | if (err < 0) | ||
4074 | goto exit; | ||
4075 | } | ||
4076 | |||
4077 | exit: | ||
4078 | snd_hda_power_down_pm(codec); | ||
4079 | |||
4080 | return err < 0 ? err : 0; | ||
4081 | } | ||
4082 | |||
3254 | static void ca0132_unsol_hp_delayed(struct work_struct *work) | 4083 | static void ca0132_unsol_hp_delayed(struct work_struct *work) |
3255 | { | 4084 | { |
3256 | struct ca0132_spec *spec = container_of( | 4085 | struct ca0132_spec *spec = container_of( |
3257 | to_delayed_work(work), struct ca0132_spec, unsol_hp_work); | 4086 | to_delayed_work(work), struct ca0132_spec, unsol_hp_work); |
3258 | struct hda_jack_tbl *jack; | 4087 | struct hda_jack_tbl *jack; |
3259 | 4088 | ||
3260 | ca0132_select_out(spec->codec); | 4089 | if (spec->use_alt_functions) |
4090 | ca0132_alt_select_out(spec->codec); | ||
4091 | else | ||
4092 | ca0132_select_out(spec->codec); | ||
4093 | |||
3261 | jack = snd_hda_jack_tbl_get(spec->codec, spec->unsol_tag_hp); | 4094 | jack = snd_hda_jack_tbl_get(spec->codec, spec->unsol_tag_hp); |
3262 | if (jack) { | 4095 | if (jack) { |
3263 | jack->block_report = 0; | 4096 | jack->block_report = 0; |
@@ -3268,6 +4101,10 @@ static void ca0132_unsol_hp_delayed(struct work_struct *work) | |||
3268 | static void ca0132_set_dmic(struct hda_codec *codec, int enable); | 4101 | static void ca0132_set_dmic(struct hda_codec *codec, int enable); |
3269 | static int ca0132_mic_boost_set(struct hda_codec *codec, long val); | 4102 | static int ca0132_mic_boost_set(struct hda_codec *codec, long val); |
3270 | static int ca0132_effects_set(struct hda_codec *codec, hda_nid_t nid, long val); | 4103 | static int ca0132_effects_set(struct hda_codec *codec, hda_nid_t nid, long val); |
4104 | static void resume_mic1(struct hda_codec *codec, unsigned int oldval); | ||
4105 | static int stop_mic1(struct hda_codec *codec); | ||
4106 | static int ca0132_cvoice_switch_set(struct hda_codec *codec); | ||
4107 | static int ca0132_alt_mic_boost_set(struct hda_codec *codec, long val); | ||
3271 | 4108 | ||
3272 | /* | 4109 | /* |
3273 | * Select the active VIP source | 4110 | * Select the active VIP source |
@@ -3310,6 +4147,71 @@ static int ca0132_set_vipsource(struct hda_codec *codec, int val) | |||
3310 | return 1; | 4147 | return 1; |
3311 | } | 4148 | } |
3312 | 4149 | ||
4150 | static int ca0132_alt_set_vipsource(struct hda_codec *codec, int val) | ||
4151 | { | ||
4152 | struct ca0132_spec *spec = codec->spec; | ||
4153 | unsigned int tmp; | ||
4154 | |||
4155 | if (spec->dsp_state != DSP_DOWNLOADED) | ||
4156 | return 0; | ||
4157 | |||
4158 | codec_dbg(codec, "%s\n", __func__); | ||
4159 | |||
4160 | chipio_set_stream_control(codec, 0x03, 0); | ||
4161 | chipio_set_stream_control(codec, 0x04, 0); | ||
4162 | |||
4163 | /* if CrystalVoice is off, vipsource should be 0 */ | ||
4164 | if (!spec->effects_switch[CRYSTAL_VOICE - EFFECT_START_NID] || | ||
4165 | (val == 0) || spec->in_enum_val == REAR_LINE_IN) { | ||
4166 | codec_dbg(codec, "%s: off.", __func__); | ||
4167 | chipio_set_control_param(codec, CONTROL_PARAM_VIP_SOURCE, 0); | ||
4168 | |||
4169 | tmp = FLOAT_ZERO; | ||
4170 | dspio_set_uint_param(codec, 0x80, 0x05, tmp); | ||
4171 | |||
4172 | chipio_set_conn_rate(codec, MEM_CONNID_MICIN1, SR_96_000); | ||
4173 | chipio_set_conn_rate(codec, MEM_CONNID_MICOUT1, SR_96_000); | ||
4174 | if (spec->quirk == QUIRK_R3DI) | ||
4175 | chipio_set_conn_rate(codec, 0x0F, SR_96_000); | ||
4176 | |||
4177 | |||
4178 | if (spec->in_enum_val == REAR_LINE_IN) | ||
4179 | tmp = FLOAT_ZERO; | ||
4180 | else { | ||
4181 | if (spec->quirk == QUIRK_SBZ) | ||
4182 | tmp = FLOAT_THREE; | ||
4183 | else | ||
4184 | tmp = FLOAT_ONE; | ||
4185 | } | ||
4186 | |||
4187 | dspio_set_uint_param(codec, 0x80, 0x00, tmp); | ||
4188 | |||
4189 | } else { | ||
4190 | codec_dbg(codec, "%s: on.", __func__); | ||
4191 | chipio_set_conn_rate(codec, MEM_CONNID_MICIN1, SR_16_000); | ||
4192 | chipio_set_conn_rate(codec, MEM_CONNID_MICOUT1, SR_16_000); | ||
4193 | if (spec->quirk == QUIRK_R3DI) | ||
4194 | chipio_set_conn_rate(codec, 0x0F, SR_16_000); | ||
4195 | |||
4196 | if (spec->effects_switch[VOICE_FOCUS - EFFECT_START_NID]) | ||
4197 | tmp = FLOAT_TWO; | ||
4198 | else | ||
4199 | tmp = FLOAT_ONE; | ||
4200 | dspio_set_uint_param(codec, 0x80, 0x00, tmp); | ||
4201 | |||
4202 | tmp = FLOAT_ONE; | ||
4203 | dspio_set_uint_param(codec, 0x80, 0x05, tmp); | ||
4204 | |||
4205 | msleep(20); | ||
4206 | chipio_set_control_param(codec, CONTROL_PARAM_VIP_SOURCE, val); | ||
4207 | } | ||
4208 | |||
4209 | chipio_set_stream_control(codec, 0x03, 1); | ||
4210 | chipio_set_stream_control(codec, 0x04, 1); | ||
4211 | |||
4212 | return 1; | ||
4213 | } | ||
4214 | |||
3313 | /* | 4215 | /* |
3314 | * Select the active microphone. | 4216 | * Select the active microphone. |
3315 | * If autodetect is enabled, mic will be selected based on jack detection. | 4217 | * If autodetect is enabled, mic will be selected based on jack detection. |
@@ -3363,6 +4265,125 @@ static int ca0132_select_mic(struct hda_codec *codec) | |||
3363 | } | 4265 | } |
3364 | 4266 | ||
3365 | /* | 4267 | /* |
4268 | * Select the active input. | ||
4269 | * Mic detection isn't used, because it's kind of pointless on the SBZ. | ||
4270 | * The front mic has no jack-detection, so the only way to switch to it | ||
4271 | * is to do it manually in alsamixer. | ||
4272 | */ | ||
4273 | static int ca0132_alt_select_in(struct hda_codec *codec) | ||
4274 | { | ||
4275 | struct ca0132_spec *spec = codec->spec; | ||
4276 | unsigned int tmp; | ||
4277 | |||
4278 | codec_dbg(codec, "%s\n", __func__); | ||
4279 | |||
4280 | snd_hda_power_up_pm(codec); | ||
4281 | |||
4282 | chipio_set_stream_control(codec, 0x03, 0); | ||
4283 | chipio_set_stream_control(codec, 0x04, 0); | ||
4284 | |||
4285 | spec->cur_mic_type = spec->in_enum_val; | ||
4286 | |||
4287 | switch (spec->cur_mic_type) { | ||
4288 | case REAR_MIC: | ||
4289 | switch (spec->quirk) { | ||
4290 | case QUIRK_SBZ: | ||
4291 | writew(0x0000, spec->mem_base + 0x320); | ||
4292 | tmp = FLOAT_THREE; | ||
4293 | break; | ||
4294 | case QUIRK_R3DI: | ||
4295 | r3di_gpio_mic_set(codec, R3DI_REAR_MIC); | ||
4296 | tmp = FLOAT_ONE; | ||
4297 | break; | ||
4298 | default: | ||
4299 | tmp = FLOAT_ONE; | ||
4300 | break; | ||
4301 | } | ||
4302 | |||
4303 | chipio_set_conn_rate(codec, MEM_CONNID_MICIN1, SR_96_000); | ||
4304 | chipio_set_conn_rate(codec, MEM_CONNID_MICOUT1, SR_96_000); | ||
4305 | if (spec->quirk == QUIRK_R3DI) | ||
4306 | chipio_set_conn_rate(codec, 0x0F, SR_96_000); | ||
4307 | |||
4308 | dspio_set_uint_param(codec, 0x80, 0x00, tmp); | ||
4309 | |||
4310 | chipio_set_stream_control(codec, 0x03, 1); | ||
4311 | chipio_set_stream_control(codec, 0x04, 1); | ||
4312 | |||
4313 | if (spec->quirk == QUIRK_SBZ) { | ||
4314 | chipio_write(codec, 0x18B098, 0x0000000C); | ||
4315 | chipio_write(codec, 0x18B09C, 0x0000000C); | ||
4316 | } | ||
4317 | ca0132_alt_mic_boost_set(codec, spec->mic_boost_enum_val); | ||
4318 | break; | ||
4319 | case REAR_LINE_IN: | ||
4320 | ca0132_mic_boost_set(codec, 0); | ||
4321 | switch (spec->quirk) { | ||
4322 | case QUIRK_SBZ: | ||
4323 | writew(0x0000, spec->mem_base + 0x320); | ||
4324 | break; | ||
4325 | case QUIRK_R3DI: | ||
4326 | r3di_gpio_mic_set(codec, R3DI_REAR_MIC); | ||
4327 | break; | ||
4328 | } | ||
4329 | |||
4330 | chipio_set_conn_rate(codec, MEM_CONNID_MICIN1, SR_96_000); | ||
4331 | chipio_set_conn_rate(codec, MEM_CONNID_MICOUT1, SR_96_000); | ||
4332 | if (spec->quirk == QUIRK_R3DI) | ||
4333 | chipio_set_conn_rate(codec, 0x0F, SR_96_000); | ||
4334 | |||
4335 | tmp = FLOAT_ZERO; | ||
4336 | dspio_set_uint_param(codec, 0x80, 0x00, tmp); | ||
4337 | |||
4338 | if (spec->quirk == QUIRK_SBZ) { | ||
4339 | chipio_write(codec, 0x18B098, 0x00000000); | ||
4340 | chipio_write(codec, 0x18B09C, 0x00000000); | ||
4341 | } | ||
4342 | |||
4343 | chipio_set_stream_control(codec, 0x03, 1); | ||
4344 | chipio_set_stream_control(codec, 0x04, 1); | ||
4345 | break; | ||
4346 | case FRONT_MIC: | ||
4347 | switch (spec->quirk) { | ||
4348 | case QUIRK_SBZ: | ||
4349 | writew(0x0100, spec->mem_base + 0x320); | ||
4350 | writew(0x0005, spec->mem_base + 0x320); | ||
4351 | tmp = FLOAT_THREE; | ||
4352 | break; | ||
4353 | case QUIRK_R3DI: | ||
4354 | r3di_gpio_mic_set(codec, R3DI_FRONT_MIC); | ||
4355 | tmp = FLOAT_ONE; | ||
4356 | break; | ||
4357 | default: | ||
4358 | tmp = FLOAT_ONE; | ||
4359 | break; | ||
4360 | } | ||
4361 | |||
4362 | chipio_set_conn_rate(codec, MEM_CONNID_MICIN1, SR_96_000); | ||
4363 | chipio_set_conn_rate(codec, MEM_CONNID_MICOUT1, SR_96_000); | ||
4364 | if (spec->quirk == QUIRK_R3DI) | ||
4365 | chipio_set_conn_rate(codec, 0x0F, SR_96_000); | ||
4366 | |||
4367 | dspio_set_uint_param(codec, 0x80, 0x00, tmp); | ||
4368 | |||
4369 | chipio_set_stream_control(codec, 0x03, 1); | ||
4370 | chipio_set_stream_control(codec, 0x04, 1); | ||
4371 | |||
4372 | if (spec->quirk == QUIRK_SBZ) { | ||
4373 | chipio_write(codec, 0x18B098, 0x0000000C); | ||
4374 | chipio_write(codec, 0x18B09C, 0x000000CC); | ||
4375 | } | ||
4376 | ca0132_alt_mic_boost_set(codec, spec->mic_boost_enum_val); | ||
4377 | break; | ||
4378 | } | ||
4379 | ca0132_cvoice_switch_set(codec); | ||
4380 | |||
4381 | snd_hda_power_down_pm(codec); | ||
4382 | return 0; | ||
4383 | |||
4384 | } | ||
4385 | |||
4386 | /* | ||
3366 | * Check if VNODE settings take effect immediately. | 4387 | * Check if VNODE settings take effect immediately. |
3367 | */ | 4388 | */ |
3368 | static bool ca0132_is_vnode_effective(struct hda_codec *codec, | 4389 | static bool ca0132_is_vnode_effective(struct hda_codec *codec, |
@@ -3418,7 +4439,7 @@ static int ca0132_voicefx_set(struct hda_codec *codec, int enable) | |||
3418 | static int ca0132_effects_set(struct hda_codec *codec, hda_nid_t nid, long val) | 4439 | static int ca0132_effects_set(struct hda_codec *codec, hda_nid_t nid, long val) |
3419 | { | 4440 | { |
3420 | struct ca0132_spec *spec = codec->spec; | 4441 | struct ca0132_spec *spec = codec->spec; |
3421 | unsigned int on; | 4442 | unsigned int on, tmp; |
3422 | int num_fx = OUT_EFFECTS_COUNT + IN_EFFECTS_COUNT; | 4443 | int num_fx = OUT_EFFECTS_COUNT + IN_EFFECTS_COUNT; |
3423 | int err = 0; | 4444 | int err = 0; |
3424 | int idx = nid - EFFECT_START_NID; | 4445 | int idx = nid - EFFECT_START_NID; |
@@ -3442,6 +4463,46 @@ static int ca0132_effects_set(struct hda_codec *codec, hda_nid_t nid, long val) | |||
3442 | /* Voice Focus applies to 2-ch Mic, Digital Mic */ | 4463 | /* Voice Focus applies to 2-ch Mic, Digital Mic */ |
3443 | if ((nid == VOICE_FOCUS) && (spec->cur_mic_type != DIGITAL_MIC)) | 4464 | if ((nid == VOICE_FOCUS) && (spec->cur_mic_type != DIGITAL_MIC)) |
3444 | val = 0; | 4465 | val = 0; |
4466 | |||
4467 | /* If Voice Focus on SBZ, set to two channel. */ | ||
4468 | if ((nid == VOICE_FOCUS) && (spec->quirk == QUIRK_SBZ) | ||
4469 | && (spec->cur_mic_type != REAR_LINE_IN)) { | ||
4470 | if (spec->effects_switch[CRYSTAL_VOICE - | ||
4471 | EFFECT_START_NID]) { | ||
4472 | |||
4473 | if (spec->effects_switch[VOICE_FOCUS - | ||
4474 | EFFECT_START_NID]) { | ||
4475 | tmp = FLOAT_TWO; | ||
4476 | val = 1; | ||
4477 | } else | ||
4478 | tmp = FLOAT_ONE; | ||
4479 | |||
4480 | dspio_set_uint_param(codec, 0x80, 0x00, tmp); | ||
4481 | } | ||
4482 | } | ||
4483 | /* | ||
4484 | * For SBZ noise reduction, there's an extra command | ||
4485 | * to module ID 0x47. No clue why. | ||
4486 | */ | ||
4487 | if ((nid == NOISE_REDUCTION) && (spec->quirk == QUIRK_SBZ) | ||
4488 | && (spec->cur_mic_type != REAR_LINE_IN)) { | ||
4489 | if (spec->effects_switch[CRYSTAL_VOICE - | ||
4490 | EFFECT_START_NID]) { | ||
4491 | if (spec->effects_switch[NOISE_REDUCTION - | ||
4492 | EFFECT_START_NID]) | ||
4493 | tmp = FLOAT_ONE; | ||
4494 | else | ||
4495 | tmp = FLOAT_ZERO; | ||
4496 | } else | ||
4497 | tmp = FLOAT_ZERO; | ||
4498 | |||
4499 | dspio_set_uint_param(codec, 0x47, 0x00, tmp); | ||
4500 | } | ||
4501 | |||
4502 | /* If rear line in disable effects. */ | ||
4503 | if (spec->use_alt_functions && | ||
4504 | spec->in_enum_val == REAR_LINE_IN) | ||
4505 | val = 0; | ||
3445 | } | 4506 | } |
3446 | 4507 | ||
3447 | codec_dbg(codec, "ca0132_effect_set: nid=0x%x, val=%ld\n", | 4508 | codec_dbg(codec, "ca0132_effect_set: nid=0x%x, val=%ld\n", |
@@ -3469,6 +4530,9 @@ static int ca0132_pe_switch_set(struct hda_codec *codec) | |||
3469 | codec_dbg(codec, "ca0132_pe_switch_set: val=%ld\n", | 4530 | codec_dbg(codec, "ca0132_pe_switch_set: val=%ld\n", |
3470 | spec->effects_switch[PLAY_ENHANCEMENT - EFFECT_START_NID]); | 4531 | spec->effects_switch[PLAY_ENHANCEMENT - EFFECT_START_NID]); |
3471 | 4532 | ||
4533 | if (spec->use_alt_functions) | ||
4534 | ca0132_alt_select_out(codec); | ||
4535 | |||
3472 | i = OUT_EFFECT_START_NID - EFFECT_START_NID; | 4536 | i = OUT_EFFECT_START_NID - EFFECT_START_NID; |
3473 | nid = OUT_EFFECT_START_NID; | 4537 | nid = OUT_EFFECT_START_NID; |
3474 | /* PE affects all out effects */ | 4538 | /* PE affects all out effects */ |
@@ -3526,7 +4590,10 @@ static int ca0132_cvoice_switch_set(struct hda_codec *codec) | |||
3526 | 4590 | ||
3527 | /* set correct vipsource */ | 4591 | /* set correct vipsource */ |
3528 | oldval = stop_mic1(codec); | 4592 | oldval = stop_mic1(codec); |
3529 | ret |= ca0132_set_vipsource(codec, 1); | 4593 | if (spec->use_alt_functions) |
4594 | ret |= ca0132_alt_set_vipsource(codec, 1); | ||
4595 | else | ||
4596 | ret |= ca0132_set_vipsource(codec, 1); | ||
3530 | resume_mic1(codec, oldval); | 4597 | resume_mic1(codec, oldval); |
3531 | return ret; | 4598 | return ret; |
3532 | } | 4599 | } |
@@ -3546,6 +4613,16 @@ static int ca0132_mic_boost_set(struct hda_codec *codec, long val) | |||
3546 | return ret; | 4613 | return ret; |
3547 | } | 4614 | } |
3548 | 4615 | ||
4616 | static int ca0132_alt_mic_boost_set(struct hda_codec *codec, long val) | ||
4617 | { | ||
4618 | struct ca0132_spec *spec = codec->spec; | ||
4619 | int ret = 0; | ||
4620 | |||
4621 | ret = snd_hda_codec_amp_update(codec, spec->input_pins[0], 0, | ||
4622 | HDA_INPUT, 0, HDA_AMP_VOLMASK, val); | ||
4623 | return ret; | ||
4624 | } | ||
4625 | |||
3549 | static int ca0132_vnode_switch_set(struct snd_kcontrol *kcontrol, | 4626 | static int ca0132_vnode_switch_set(struct snd_kcontrol *kcontrol, |
3550 | struct snd_ctl_elem_value *ucontrol) | 4627 | struct snd_ctl_elem_value *ucontrol) |
3551 | { | 4628 | { |
@@ -3560,8 +4637,12 @@ static int ca0132_vnode_switch_set(struct snd_kcontrol *kcontrol, | |||
3560 | if (nid == VNID_HP_SEL) { | 4637 | if (nid == VNID_HP_SEL) { |
3561 | auto_jack = | 4638 | auto_jack = |
3562 | spec->vnode_lswitch[VNID_HP_ASEL - VNODE_START_NID]; | 4639 | spec->vnode_lswitch[VNID_HP_ASEL - VNODE_START_NID]; |
3563 | if (!auto_jack) | 4640 | if (!auto_jack) { |
3564 | ca0132_select_out(codec); | 4641 | if (spec->use_alt_functions) |
4642 | ca0132_alt_select_out(codec); | ||
4643 | else | ||
4644 | ca0132_select_out(codec); | ||
4645 | } | ||
3565 | return 1; | 4646 | return 1; |
3566 | } | 4647 | } |
3567 | 4648 | ||
@@ -3574,7 +4655,10 @@ static int ca0132_vnode_switch_set(struct snd_kcontrol *kcontrol, | |||
3574 | } | 4655 | } |
3575 | 4656 | ||
3576 | if (nid == VNID_HP_ASEL) { | 4657 | if (nid == VNID_HP_ASEL) { |
3577 | ca0132_select_out(codec); | 4658 | if (spec->use_alt_functions) |
4659 | ca0132_alt_select_out(codec); | ||
4660 | else | ||
4661 | ca0132_select_out(codec); | ||
3578 | return 1; | 4662 | return 1; |
3579 | } | 4663 | } |
3580 | 4664 | ||
@@ -3602,6 +4686,432 @@ static int ca0132_vnode_switch_set(struct snd_kcontrol *kcontrol, | |||
3602 | return ret; | 4686 | return ret; |
3603 | } | 4687 | } |
3604 | /* End of control change helpers. */ | 4688 | /* End of control change helpers. */ |
4689 | /* | ||
4690 | * Below I've added controls to mess with the effect levels, I've only enabled | ||
4691 | * them on the Sound Blaster Z, but they would probably also work on the | ||
4692 | * Chromebook. I figured they were probably tuned specifically for it, and left | ||
4693 | * out for a reason. | ||
4694 | */ | ||
4695 | |||
4696 | /* Sets DSP effect level from the sliders above the controls */ | ||
4697 | static int ca0132_alt_slider_ctl_set(struct hda_codec *codec, hda_nid_t nid, | ||
4698 | const unsigned int *lookup, int idx) | ||
4699 | { | ||
4700 | int i = 0; | ||
4701 | unsigned int y; | ||
4702 | /* | ||
4703 | * For X_BASS, req 2 is actually crossover freq instead of | ||
4704 | * effect level | ||
4705 | */ | ||
4706 | if (nid == X_BASS) | ||
4707 | y = 2; | ||
4708 | else | ||
4709 | y = 1; | ||
4710 | |||
4711 | snd_hda_power_up(codec); | ||
4712 | if (nid == XBASS_XOVER) { | ||
4713 | for (i = 0; i < OUT_EFFECTS_COUNT; i++) | ||
4714 | if (ca0132_effects[i].nid == X_BASS) | ||
4715 | break; | ||
4716 | |||
4717 | dspio_set_param(codec, ca0132_effects[i].mid, 0x20, | ||
4718 | ca0132_effects[i].reqs[1], | ||
4719 | &(lookup[idx - 1]), sizeof(unsigned int)); | ||
4720 | } else { | ||
4721 | /* Find the actual effect structure */ | ||
4722 | for (i = 0; i < OUT_EFFECTS_COUNT; i++) | ||
4723 | if (nid == ca0132_effects[i].nid) | ||
4724 | break; | ||
4725 | |||
4726 | dspio_set_param(codec, ca0132_effects[i].mid, 0x20, | ||
4727 | ca0132_effects[i].reqs[y], | ||
4728 | &(lookup[idx]), sizeof(unsigned int)); | ||
4729 | } | ||
4730 | |||
4731 | snd_hda_power_down(codec); | ||
4732 | |||
4733 | return 0; | ||
4734 | } | ||
4735 | |||
4736 | static int ca0132_alt_xbass_xover_slider_ctl_get(struct snd_kcontrol *kcontrol, | ||
4737 | struct snd_ctl_elem_value *ucontrol) | ||
4738 | { | ||
4739 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | ||
4740 | struct ca0132_spec *spec = codec->spec; | ||
4741 | long *valp = ucontrol->value.integer.value; | ||
4742 | |||
4743 | *valp = spec->xbass_xover_freq; | ||
4744 | return 0; | ||
4745 | } | ||
4746 | |||
4747 | static int ca0132_alt_slider_ctl_get(struct snd_kcontrol *kcontrol, | ||
4748 | struct snd_ctl_elem_value *ucontrol) | ||
4749 | { | ||
4750 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | ||
4751 | struct ca0132_spec *spec = codec->spec; | ||
4752 | hda_nid_t nid = get_amp_nid(kcontrol); | ||
4753 | long *valp = ucontrol->value.integer.value; | ||
4754 | int idx = nid - OUT_EFFECT_START_NID; | ||
4755 | |||
4756 | *valp = spec->fx_ctl_val[idx]; | ||
4757 | return 0; | ||
4758 | } | ||
4759 | |||
4760 | /* | ||
4761 | * The X-bass crossover starts at 10hz, so the min is 1. The | ||
4762 | * frequency is set in multiples of 10. | ||
4763 | */ | ||
4764 | static int ca0132_alt_xbass_xover_slider_info(struct snd_kcontrol *kcontrol, | ||
4765 | struct snd_ctl_elem_info *uinfo) | ||
4766 | { | ||
4767 | uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; | ||
4768 | uinfo->count = 1; | ||
4769 | uinfo->value.integer.min = 1; | ||
4770 | uinfo->value.integer.max = 100; | ||
4771 | uinfo->value.integer.step = 1; | ||
4772 | |||
4773 | return 0; | ||
4774 | } | ||
4775 | |||
4776 | static int ca0132_alt_effect_slider_info(struct snd_kcontrol *kcontrol, | ||
4777 | struct snd_ctl_elem_info *uinfo) | ||
4778 | { | ||
4779 | int chs = get_amp_channels(kcontrol); | ||
4780 | |||
4781 | uinfo->type = SNDRV_CTL_ELEM_TYPE_INTEGER; | ||
4782 | uinfo->count = chs == 3 ? 2 : 1; | ||
4783 | uinfo->value.integer.min = 0; | ||
4784 | uinfo->value.integer.max = 100; | ||
4785 | uinfo->value.integer.step = 1; | ||
4786 | |||
4787 | return 0; | ||
4788 | } | ||
4789 | |||
4790 | static int ca0132_alt_xbass_xover_slider_put(struct snd_kcontrol *kcontrol, | ||
4791 | struct snd_ctl_elem_value *ucontrol) | ||
4792 | { | ||
4793 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | ||
4794 | struct ca0132_spec *spec = codec->spec; | ||
4795 | hda_nid_t nid = get_amp_nid(kcontrol); | ||
4796 | long *valp = ucontrol->value.integer.value; | ||
4797 | int idx; | ||
4798 | |||
4799 | /* any change? */ | ||
4800 | if (spec->xbass_xover_freq == *valp) | ||
4801 | return 0; | ||
4802 | |||
4803 | spec->xbass_xover_freq = *valp; | ||
4804 | |||
4805 | idx = *valp; | ||
4806 | ca0132_alt_slider_ctl_set(codec, nid, float_xbass_xover_lookup, idx); | ||
4807 | |||
4808 | return 0; | ||
4809 | } | ||
4810 | |||
4811 | static int ca0132_alt_effect_slider_put(struct snd_kcontrol *kcontrol, | ||
4812 | struct snd_ctl_elem_value *ucontrol) | ||
4813 | { | ||
4814 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | ||
4815 | struct ca0132_spec *spec = codec->spec; | ||
4816 | hda_nid_t nid = get_amp_nid(kcontrol); | ||
4817 | long *valp = ucontrol->value.integer.value; | ||
4818 | int idx; | ||
4819 | |||
4820 | idx = nid - EFFECT_START_NID; | ||
4821 | /* any change? */ | ||
4822 | if (spec->fx_ctl_val[idx] == *valp) | ||
4823 | return 0; | ||
4824 | |||
4825 | spec->fx_ctl_val[idx] = *valp; | ||
4826 | |||
4827 | idx = *valp; | ||
4828 | ca0132_alt_slider_ctl_set(codec, nid, float_zero_to_one_lookup, idx); | ||
4829 | |||
4830 | return 0; | ||
4831 | } | ||
4832 | |||
4833 | |||
4834 | /* | ||
4835 | * Mic Boost Enum for alternative ca0132 codecs. I didn't like that the original | ||
4836 | * only has off or full 30 dB, and didn't like making a volume slider that has | ||
4837 | * traditional 0-100 in alsamixer that goes in big steps. I like enum better. | ||
4838 | */ | ||
4839 | #define MIC_BOOST_NUM_OF_STEPS 4 | ||
4840 | #define MIC_BOOST_ENUM_MAX_STRLEN 10 | ||
4841 | |||
4842 | static int ca0132_alt_mic_boost_info(struct snd_kcontrol *kcontrol, | ||
4843 | struct snd_ctl_elem_info *uinfo) | ||
4844 | { | ||
4845 | char *sfx = "dB"; | ||
4846 | char namestr[SNDRV_CTL_ELEM_ID_NAME_MAXLEN]; | ||
4847 | |||
4848 | uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; | ||
4849 | uinfo->count = 1; | ||
4850 | uinfo->value.enumerated.items = MIC_BOOST_NUM_OF_STEPS; | ||
4851 | if (uinfo->value.enumerated.item >= MIC_BOOST_NUM_OF_STEPS) | ||
4852 | uinfo->value.enumerated.item = MIC_BOOST_NUM_OF_STEPS - 1; | ||
4853 | sprintf(namestr, "%d %s", (uinfo->value.enumerated.item * 10), sfx); | ||
4854 | strcpy(uinfo->value.enumerated.name, namestr); | ||
4855 | return 0; | ||
4856 | } | ||
4857 | |||
4858 | static int ca0132_alt_mic_boost_get(struct snd_kcontrol *kcontrol, | ||
4859 | struct snd_ctl_elem_value *ucontrol) | ||
4860 | { | ||
4861 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | ||
4862 | struct ca0132_spec *spec = codec->spec; | ||
4863 | |||
4864 | ucontrol->value.enumerated.item[0] = spec->mic_boost_enum_val; | ||
4865 | return 0; | ||
4866 | } | ||
4867 | |||
4868 | static int ca0132_alt_mic_boost_put(struct snd_kcontrol *kcontrol, | ||
4869 | struct snd_ctl_elem_value *ucontrol) | ||
4870 | { | ||
4871 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | ||
4872 | struct ca0132_spec *spec = codec->spec; | ||
4873 | int sel = ucontrol->value.enumerated.item[0]; | ||
4874 | unsigned int items = MIC_BOOST_NUM_OF_STEPS; | ||
4875 | |||
4876 | if (sel >= items) | ||
4877 | return 0; | ||
4878 | |||
4879 | codec_dbg(codec, "ca0132_alt_mic_boost: boost=%d\n", | ||
4880 | sel); | ||
4881 | |||
4882 | spec->mic_boost_enum_val = sel; | ||
4883 | |||
4884 | if (spec->in_enum_val != REAR_LINE_IN) | ||
4885 | ca0132_alt_mic_boost_set(codec, spec->mic_boost_enum_val); | ||
4886 | |||
4887 | return 1; | ||
4888 | } | ||
4889 | |||
4890 | |||
4891 | /* | ||
4892 | * Input Select Control for alternative ca0132 codecs. This exists because | ||
4893 | * front microphone has no auto-detect, and we need a way to set the rear | ||
4894 | * as line-in | ||
4895 | */ | ||
4896 | static int ca0132_alt_input_source_info(struct snd_kcontrol *kcontrol, | ||
4897 | struct snd_ctl_elem_info *uinfo) | ||
4898 | { | ||
4899 | uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; | ||
4900 | uinfo->count = 1; | ||
4901 | uinfo->value.enumerated.items = IN_SRC_NUM_OF_INPUTS; | ||
4902 | if (uinfo->value.enumerated.item >= IN_SRC_NUM_OF_INPUTS) | ||
4903 | uinfo->value.enumerated.item = IN_SRC_NUM_OF_INPUTS - 1; | ||
4904 | strcpy(uinfo->value.enumerated.name, | ||
4905 | in_src_str[uinfo->value.enumerated.item]); | ||
4906 | return 0; | ||
4907 | } | ||
4908 | |||
4909 | static int ca0132_alt_input_source_get(struct snd_kcontrol *kcontrol, | ||
4910 | struct snd_ctl_elem_value *ucontrol) | ||
4911 | { | ||
4912 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | ||
4913 | struct ca0132_spec *spec = codec->spec; | ||
4914 | |||
4915 | ucontrol->value.enumerated.item[0] = spec->in_enum_val; | ||
4916 | return 0; | ||
4917 | } | ||
4918 | |||
4919 | static int ca0132_alt_input_source_put(struct snd_kcontrol *kcontrol, | ||
4920 | struct snd_ctl_elem_value *ucontrol) | ||
4921 | { | ||
4922 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | ||
4923 | struct ca0132_spec *spec = codec->spec; | ||
4924 | int sel = ucontrol->value.enumerated.item[0]; | ||
4925 | unsigned int items = IN_SRC_NUM_OF_INPUTS; | ||
4926 | |||
4927 | if (sel >= items) | ||
4928 | return 0; | ||
4929 | |||
4930 | codec_dbg(codec, "ca0132_alt_input_select: sel=%d, preset=%s\n", | ||
4931 | sel, in_src_str[sel]); | ||
4932 | |||
4933 | spec->in_enum_val = sel; | ||
4934 | |||
4935 | ca0132_alt_select_in(codec); | ||
4936 | |||
4937 | return 1; | ||
4938 | } | ||
4939 | |||
4940 | /* Sound Blaster Z Output Select Control */ | ||
4941 | static int ca0132_alt_output_select_get_info(struct snd_kcontrol *kcontrol, | ||
4942 | struct snd_ctl_elem_info *uinfo) | ||
4943 | { | ||
4944 | uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; | ||
4945 | uinfo->count = 1; | ||
4946 | uinfo->value.enumerated.items = NUM_OF_OUTPUTS; | ||
4947 | if (uinfo->value.enumerated.item >= NUM_OF_OUTPUTS) | ||
4948 | uinfo->value.enumerated.item = NUM_OF_OUTPUTS - 1; | ||
4949 | strcpy(uinfo->value.enumerated.name, | ||
4950 | alt_out_presets[uinfo->value.enumerated.item].name); | ||
4951 | return 0; | ||
4952 | } | ||
4953 | |||
4954 | static int ca0132_alt_output_select_get(struct snd_kcontrol *kcontrol, | ||
4955 | struct snd_ctl_elem_value *ucontrol) | ||
4956 | { | ||
4957 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | ||
4958 | struct ca0132_spec *spec = codec->spec; | ||
4959 | |||
4960 | ucontrol->value.enumerated.item[0] = spec->out_enum_val; | ||
4961 | return 0; | ||
4962 | } | ||
4963 | |||
4964 | static int ca0132_alt_output_select_put(struct snd_kcontrol *kcontrol, | ||
4965 | struct snd_ctl_elem_value *ucontrol) | ||
4966 | { | ||
4967 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | ||
4968 | struct ca0132_spec *spec = codec->spec; | ||
4969 | int sel = ucontrol->value.enumerated.item[0]; | ||
4970 | unsigned int items = NUM_OF_OUTPUTS; | ||
4971 | unsigned int auto_jack; | ||
4972 | |||
4973 | if (sel >= items) | ||
4974 | return 0; | ||
4975 | |||
4976 | codec_dbg(codec, "ca0132_alt_output_select: sel=%d, preset=%s\n", | ||
4977 | sel, alt_out_presets[sel].name); | ||
4978 | |||
4979 | spec->out_enum_val = sel; | ||
4980 | |||
4981 | auto_jack = spec->vnode_lswitch[VNID_HP_ASEL - VNODE_START_NID]; | ||
4982 | |||
4983 | if (!auto_jack) | ||
4984 | ca0132_alt_select_out(codec); | ||
4985 | |||
4986 | return 1; | ||
4987 | } | ||
4988 | |||
4989 | /* | ||
4990 | * Smart Volume output setting control. Three different settings, Normal, | ||
4991 | * which takes the value from the smart volume slider. The two others, loud | ||
4992 | * and night, disregard the slider value and have uneditable values. | ||
4993 | */ | ||
4994 | #define NUM_OF_SVM_SETTINGS 3 | ||
4995 | static const char *const out_svm_set_enum_str[3] = {"Normal", "Loud", "Night" }; | ||
4996 | |||
4997 | static int ca0132_alt_svm_setting_info(struct snd_kcontrol *kcontrol, | ||
4998 | struct snd_ctl_elem_info *uinfo) | ||
4999 | { | ||
5000 | uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; | ||
5001 | uinfo->count = 1; | ||
5002 | uinfo->value.enumerated.items = NUM_OF_SVM_SETTINGS; | ||
5003 | if (uinfo->value.enumerated.item >= NUM_OF_SVM_SETTINGS) | ||
5004 | uinfo->value.enumerated.item = NUM_OF_SVM_SETTINGS - 1; | ||
5005 | strcpy(uinfo->value.enumerated.name, | ||
5006 | out_svm_set_enum_str[uinfo->value.enumerated.item]); | ||
5007 | return 0; | ||
5008 | } | ||
5009 | |||
5010 | static int ca0132_alt_svm_setting_get(struct snd_kcontrol *kcontrol, | ||
5011 | struct snd_ctl_elem_value *ucontrol) | ||
5012 | { | ||
5013 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | ||
5014 | struct ca0132_spec *spec = codec->spec; | ||
5015 | |||
5016 | ucontrol->value.enumerated.item[0] = spec->smart_volume_setting; | ||
5017 | return 0; | ||
5018 | } | ||
5019 | |||
5020 | static int ca0132_alt_svm_setting_put(struct snd_kcontrol *kcontrol, | ||
5021 | struct snd_ctl_elem_value *ucontrol) | ||
5022 | { | ||
5023 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | ||
5024 | struct ca0132_spec *spec = codec->spec; | ||
5025 | int sel = ucontrol->value.enumerated.item[0]; | ||
5026 | unsigned int items = NUM_OF_SVM_SETTINGS; | ||
5027 | unsigned int idx = SMART_VOLUME - EFFECT_START_NID; | ||
5028 | unsigned int tmp; | ||
5029 | |||
5030 | if (sel >= items) | ||
5031 | return 0; | ||
5032 | |||
5033 | codec_dbg(codec, "ca0132_alt_svm_setting: sel=%d, preset=%s\n", | ||
5034 | sel, out_svm_set_enum_str[sel]); | ||
5035 | |||
5036 | spec->smart_volume_setting = sel; | ||
5037 | |||
5038 | switch (sel) { | ||
5039 | case 0: | ||
5040 | tmp = FLOAT_ZERO; | ||
5041 | break; | ||
5042 | case 1: | ||
5043 | tmp = FLOAT_ONE; | ||
5044 | break; | ||
5045 | case 2: | ||
5046 | tmp = FLOAT_TWO; | ||
5047 | break; | ||
5048 | default: | ||
5049 | tmp = FLOAT_ZERO; | ||
5050 | break; | ||
5051 | } | ||
5052 | /* Req 2 is the Smart Volume Setting req. */ | ||
5053 | dspio_set_uint_param(codec, ca0132_effects[idx].mid, | ||
5054 | ca0132_effects[idx].reqs[2], tmp); | ||
5055 | return 1; | ||
5056 | } | ||
5057 | |||
5058 | /* Sound Blaster Z EQ preset controls */ | ||
5059 | static int ca0132_alt_eq_preset_info(struct snd_kcontrol *kcontrol, | ||
5060 | struct snd_ctl_elem_info *uinfo) | ||
5061 | { | ||
5062 | unsigned int items = ARRAY_SIZE(ca0132_alt_eq_presets); | ||
5063 | |||
5064 | uinfo->type = SNDRV_CTL_ELEM_TYPE_ENUMERATED; | ||
5065 | uinfo->count = 1; | ||
5066 | uinfo->value.enumerated.items = items; | ||
5067 | if (uinfo->value.enumerated.item >= items) | ||
5068 | uinfo->value.enumerated.item = items - 1; | ||
5069 | strcpy(uinfo->value.enumerated.name, | ||
5070 | ca0132_alt_eq_presets[uinfo->value.enumerated.item].name); | ||
5071 | return 0; | ||
5072 | } | ||
5073 | |||
5074 | static int ca0132_alt_eq_preset_get(struct snd_kcontrol *kcontrol, | ||
5075 | struct snd_ctl_elem_value *ucontrol) | ||
5076 | { | ||
5077 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | ||
5078 | struct ca0132_spec *spec = codec->spec; | ||
5079 | |||
5080 | ucontrol->value.enumerated.item[0] = spec->eq_preset_val; | ||
5081 | return 0; | ||
5082 | } | ||
5083 | |||
5084 | static int ca0132_alt_eq_preset_put(struct snd_kcontrol *kcontrol, | ||
5085 | struct snd_ctl_elem_value *ucontrol) | ||
5086 | { | ||
5087 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | ||
5088 | struct ca0132_spec *spec = codec->spec; | ||
5089 | int i, err = 0; | ||
5090 | int sel = ucontrol->value.enumerated.item[0]; | ||
5091 | unsigned int items = ARRAY_SIZE(ca0132_alt_eq_presets); | ||
5092 | |||
5093 | if (sel >= items) | ||
5094 | return 0; | ||
5095 | |||
5096 | codec_dbg(codec, "%s: sel=%d, preset=%s\n", __func__, sel, | ||
5097 | ca0132_alt_eq_presets[sel].name); | ||
5098 | /* | ||
5099 | * Idx 0 is default. | ||
5100 | * Default needs to qualify with CrystalVoice state. | ||
5101 | */ | ||
5102 | for (i = 0; i < EQ_PRESET_MAX_PARAM_COUNT; i++) { | ||
5103 | err = dspio_set_uint_param(codec, ca0132_alt_eq_enum.mid, | ||
5104 | ca0132_alt_eq_enum.reqs[i], | ||
5105 | ca0132_alt_eq_presets[sel].vals[i]); | ||
5106 | if (err < 0) | ||
5107 | break; | ||
5108 | } | ||
5109 | |||
5110 | if (err >= 0) | ||
5111 | spec->eq_preset_val = sel; | ||
5112 | |||
5113 | return 1; | ||
5114 | } | ||
3605 | 5115 | ||
3606 | static int ca0132_voicefx_info(struct snd_kcontrol *kcontrol, | 5116 | static int ca0132_voicefx_info(struct snd_kcontrol *kcontrol, |
3607 | struct snd_ctl_elem_info *uinfo) | 5117 | struct snd_ctl_elem_info *uinfo) |
@@ -3753,10 +5263,15 @@ static int ca0132_switch_put(struct snd_kcontrol *kcontrol, | |||
3753 | /* mic boost */ | 5263 | /* mic boost */ |
3754 | if (nid == spec->input_pins[0]) { | 5264 | if (nid == spec->input_pins[0]) { |
3755 | spec->cur_mic_boost = *valp; | 5265 | spec->cur_mic_boost = *valp; |
5266 | if (spec->use_alt_functions) { | ||
5267 | if (spec->in_enum_val != REAR_LINE_IN) | ||
5268 | changed = ca0132_mic_boost_set(codec, *valp); | ||
5269 | } else { | ||
5270 | /* Mic boost does not apply to Digital Mic */ | ||
5271 | if (spec->cur_mic_type != DIGITAL_MIC) | ||
5272 | changed = ca0132_mic_boost_set(codec, *valp); | ||
5273 | } | ||
3756 | 5274 | ||
3757 | /* Mic boost does not apply to Digital Mic */ | ||
3758 | if (spec->cur_mic_type != DIGITAL_MIC) | ||
3759 | changed = ca0132_mic_boost_set(codec, *valp); | ||
3760 | goto exit; | 5275 | goto exit; |
3761 | } | 5276 | } |
3762 | 5277 | ||
@@ -3768,6 +5283,41 @@ exit: | |||
3768 | /* | 5283 | /* |
3769 | * Volume related | 5284 | * Volume related |
3770 | */ | 5285 | */ |
5286 | /* | ||
5287 | * Sets the internal DSP decibel level to match the DAC for output, and the | ||
5288 | * ADC for input. Currently only the SBZ sets dsp capture volume level, and | ||
5289 | * all alternative codecs set DSP playback volume. | ||
5290 | */ | ||
5291 | static void ca0132_alt_dsp_volume_put(struct hda_codec *codec, hda_nid_t nid) | ||
5292 | { | ||
5293 | struct ca0132_spec *spec = codec->spec; | ||
5294 | unsigned int dsp_dir; | ||
5295 | unsigned int lookup_val; | ||
5296 | |||
5297 | if (nid == VNID_SPK) | ||
5298 | dsp_dir = DSP_VOL_OUT; | ||
5299 | else | ||
5300 | dsp_dir = DSP_VOL_IN; | ||
5301 | |||
5302 | lookup_val = spec->vnode_lvol[nid - VNODE_START_NID]; | ||
5303 | |||
5304 | dspio_set_uint_param(codec, | ||
5305 | ca0132_alt_vol_ctls[dsp_dir].mid, | ||
5306 | ca0132_alt_vol_ctls[dsp_dir].reqs[0], | ||
5307 | float_vol_db_lookup[lookup_val]); | ||
5308 | |||
5309 | lookup_val = spec->vnode_rvol[nid - VNODE_START_NID]; | ||
5310 | |||
5311 | dspio_set_uint_param(codec, | ||
5312 | ca0132_alt_vol_ctls[dsp_dir].mid, | ||
5313 | ca0132_alt_vol_ctls[dsp_dir].reqs[1], | ||
5314 | float_vol_db_lookup[lookup_val]); | ||
5315 | |||
5316 | dspio_set_uint_param(codec, | ||
5317 | ca0132_alt_vol_ctls[dsp_dir].mid, | ||
5318 | ca0132_alt_vol_ctls[dsp_dir].reqs[2], FLOAT_ZERO); | ||
5319 | } | ||
5320 | |||
3771 | static int ca0132_volume_info(struct snd_kcontrol *kcontrol, | 5321 | static int ca0132_volume_info(struct snd_kcontrol *kcontrol, |
3772 | struct snd_ctl_elem_info *uinfo) | 5322 | struct snd_ctl_elem_info *uinfo) |
3773 | { | 5323 | { |
@@ -3869,6 +5419,51 @@ static int ca0132_volume_put(struct snd_kcontrol *kcontrol, | |||
3869 | return changed; | 5419 | return changed; |
3870 | } | 5420 | } |
3871 | 5421 | ||
5422 | /* | ||
5423 | * This function is the same as the one above, because using an if statement | ||
5424 | * inside of the above volume control for the DSP volume would cause too much | ||
5425 | * lag. This is a lot more smooth. | ||
5426 | */ | ||
5427 | static int ca0132_alt_volume_put(struct snd_kcontrol *kcontrol, | ||
5428 | struct snd_ctl_elem_value *ucontrol) | ||
5429 | { | ||
5430 | struct hda_codec *codec = snd_kcontrol_chip(kcontrol); | ||
5431 | struct ca0132_spec *spec = codec->spec; | ||
5432 | hda_nid_t nid = get_amp_nid(kcontrol); | ||
5433 | int ch = get_amp_channels(kcontrol); | ||
5434 | long *valp = ucontrol->value.integer.value; | ||
5435 | hda_nid_t vnid = 0; | ||
5436 | int changed = 1; | ||
5437 | |||
5438 | switch (nid) { | ||
5439 | case 0x02: | ||
5440 | vnid = VNID_SPK; | ||
5441 | break; | ||
5442 | case 0x07: | ||
5443 | vnid = VNID_MIC; | ||
5444 | break; | ||
5445 | } | ||
5446 | |||
5447 | /* store the left and right volume */ | ||
5448 | if (ch & 1) { | ||
5449 | spec->vnode_lvol[vnid - VNODE_START_NID] = *valp; | ||
5450 | valp++; | ||
5451 | } | ||
5452 | if (ch & 2) { | ||
5453 | spec->vnode_rvol[vnid - VNODE_START_NID] = *valp; | ||
5454 | valp++; | ||
5455 | } | ||
5456 | |||
5457 | snd_hda_power_up(codec); | ||
5458 | ca0132_alt_dsp_volume_put(codec, vnid); | ||
5459 | mutex_lock(&codec->control_mutex); | ||
5460 | changed = snd_hda_mixer_amp_volume_put(kcontrol, ucontrol); | ||
5461 | mutex_unlock(&codec->control_mutex); | ||
5462 | snd_hda_power_down(codec); | ||
5463 | |||
5464 | return changed; | ||
5465 | } | ||
5466 | |||
3872 | static int ca0132_volume_tlv(struct snd_kcontrol *kcontrol, int op_flag, | 5467 | static int ca0132_volume_tlv(struct snd_kcontrol *kcontrol, int op_flag, |
3873 | unsigned int size, unsigned int __user *tlv) | 5468 | unsigned int size, unsigned int __user *tlv) |
3874 | { | 5469 | { |
@@ -3907,14 +5502,59 @@ static int ca0132_volume_tlv(struct snd_kcontrol *kcontrol, int op_flag, | |||
3907 | return err; | 5502 | return err; |
3908 | } | 5503 | } |
3909 | 5504 | ||
5505 | /* Add volume slider control for effect level */ | ||
5506 | static int ca0132_alt_add_effect_slider(struct hda_codec *codec, hda_nid_t nid, | ||
5507 | const char *pfx, int dir) | ||
5508 | { | ||
5509 | char namestr[SNDRV_CTL_ELEM_ID_NAME_MAXLEN]; | ||
5510 | int type = dir ? HDA_INPUT : HDA_OUTPUT; | ||
5511 | struct snd_kcontrol_new knew = | ||
5512 | HDA_CODEC_VOLUME_MONO(namestr, nid, 1, 0, type); | ||
5513 | |||
5514 | sprintf(namestr, "FX: %s %s Volume", pfx, dirstr[dir]); | ||
5515 | |||
5516 | knew.tlv.c = 0; | ||
5517 | knew.tlv.p = 0; | ||
5518 | |||
5519 | switch (nid) { | ||
5520 | case XBASS_XOVER: | ||
5521 | knew.info = ca0132_alt_xbass_xover_slider_info; | ||
5522 | knew.get = ca0132_alt_xbass_xover_slider_ctl_get; | ||
5523 | knew.put = ca0132_alt_xbass_xover_slider_put; | ||
5524 | break; | ||
5525 | default: | ||
5526 | knew.info = ca0132_alt_effect_slider_info; | ||
5527 | knew.get = ca0132_alt_slider_ctl_get; | ||
5528 | knew.put = ca0132_alt_effect_slider_put; | ||
5529 | knew.private_value = | ||
5530 | HDA_COMPOSE_AMP_VAL(nid, 1, 0, type); | ||
5531 | break; | ||
5532 | } | ||
5533 | |||
5534 | return snd_hda_ctl_add(codec, nid, snd_ctl_new1(&knew, codec)); | ||
5535 | } | ||
5536 | |||
5537 | /* | ||
5538 | * Added FX: prefix for the alternative codecs, because otherwise the surround | ||
5539 | * effect would conflict with the Surround sound volume control. Also seems more | ||
5540 | * clear as to what the switches do. Left alone for others. | ||
5541 | */ | ||
3910 | static int add_fx_switch(struct hda_codec *codec, hda_nid_t nid, | 5542 | static int add_fx_switch(struct hda_codec *codec, hda_nid_t nid, |
3911 | const char *pfx, int dir) | 5543 | const char *pfx, int dir) |
3912 | { | 5544 | { |
5545 | struct ca0132_spec *spec = codec->spec; | ||
3913 | char namestr[SNDRV_CTL_ELEM_ID_NAME_MAXLEN]; | 5546 | char namestr[SNDRV_CTL_ELEM_ID_NAME_MAXLEN]; |
3914 | int type = dir ? HDA_INPUT : HDA_OUTPUT; | 5547 | int type = dir ? HDA_INPUT : HDA_OUTPUT; |
3915 | struct snd_kcontrol_new knew = | 5548 | struct snd_kcontrol_new knew = |
3916 | CA0132_CODEC_MUTE_MONO(namestr, nid, 1, type); | 5549 | CA0132_CODEC_MUTE_MONO(namestr, nid, 1, type); |
3917 | sprintf(namestr, "%s %s Switch", pfx, dirstr[dir]); | 5550 | /* If using alt_controls, add FX: prefix. But, don't add FX: |
5551 | * prefix to OutFX or InFX enable controls. | ||
5552 | */ | ||
5553 | if ((spec->use_alt_controls) && (nid <= IN_EFFECT_END_NID)) | ||
5554 | sprintf(namestr, "FX: %s %s Switch", pfx, dirstr[dir]); | ||
5555 | else | ||
5556 | sprintf(namestr, "%s %s Switch", pfx, dirstr[dir]); | ||
5557 | |||
3918 | return snd_hda_ctl_add(codec, nid, snd_ctl_new1(&knew, codec)); | 5558 | return snd_hda_ctl_add(codec, nid, snd_ctl_new1(&knew, codec)); |
3919 | } | 5559 | } |
3920 | 5560 | ||
@@ -3929,11 +5569,141 @@ static int add_voicefx(struct hda_codec *codec) | |||
3929 | return snd_hda_ctl_add(codec, VOICEFX, snd_ctl_new1(&knew, codec)); | 5569 | return snd_hda_ctl_add(codec, VOICEFX, snd_ctl_new1(&knew, codec)); |
3930 | } | 5570 | } |
3931 | 5571 | ||
5572 | /* Create the EQ Preset control */ | ||
5573 | static int add_ca0132_alt_eq_presets(struct hda_codec *codec) | ||
5574 | { | ||
5575 | struct snd_kcontrol_new knew = | ||
5576 | HDA_CODEC_MUTE_MONO(ca0132_alt_eq_enum.name, | ||
5577 | EQ_PRESET_ENUM, 1, 0, HDA_OUTPUT); | ||
5578 | knew.info = ca0132_alt_eq_preset_info; | ||
5579 | knew.get = ca0132_alt_eq_preset_get; | ||
5580 | knew.put = ca0132_alt_eq_preset_put; | ||
5581 | return snd_hda_ctl_add(codec, EQ_PRESET_ENUM, | ||
5582 | snd_ctl_new1(&knew, codec)); | ||
5583 | } | ||
5584 | |||
5585 | /* | ||
5586 | * Add enumerated control for the three different settings of the smart volume | ||
5587 | * output effect. Normal just uses the slider value, and loud and night are | ||
5588 | * their own things that ignore that value. | ||
5589 | */ | ||
5590 | static int ca0132_alt_add_svm_enum(struct hda_codec *codec) | ||
5591 | { | ||
5592 | struct snd_kcontrol_new knew = | ||
5593 | HDA_CODEC_MUTE_MONO("FX: Smart Volume Setting", | ||
5594 | SMART_VOLUME_ENUM, 1, 0, HDA_OUTPUT); | ||
5595 | knew.info = ca0132_alt_svm_setting_info; | ||
5596 | knew.get = ca0132_alt_svm_setting_get; | ||
5597 | knew.put = ca0132_alt_svm_setting_put; | ||
5598 | return snd_hda_ctl_add(codec, SMART_VOLUME_ENUM, | ||
5599 | snd_ctl_new1(&knew, codec)); | ||
5600 | |||
5601 | } | ||
5602 | |||
5603 | /* | ||
5604 | * Create an Output Select enumerated control for codecs with surround | ||
5605 | * out capabilities. | ||
5606 | */ | ||
5607 | static int ca0132_alt_add_output_enum(struct hda_codec *codec) | ||
5608 | { | ||
5609 | struct snd_kcontrol_new knew = | ||
5610 | HDA_CODEC_MUTE_MONO("Output Select", | ||
5611 | OUTPUT_SOURCE_ENUM, 1, 0, HDA_OUTPUT); | ||
5612 | knew.info = ca0132_alt_output_select_get_info; | ||
5613 | knew.get = ca0132_alt_output_select_get; | ||
5614 | knew.put = ca0132_alt_output_select_put; | ||
5615 | return snd_hda_ctl_add(codec, OUTPUT_SOURCE_ENUM, | ||
5616 | snd_ctl_new1(&knew, codec)); | ||
5617 | } | ||
5618 | |||
5619 | /* | ||
5620 | * Create an Input Source enumerated control for the alternate ca0132 codecs | ||
5621 | * because the front microphone has no auto-detect, and Line-in has to be set | ||
5622 | * somehow. | ||
5623 | */ | ||
5624 | static int ca0132_alt_add_input_enum(struct hda_codec *codec) | ||
5625 | { | ||
5626 | struct snd_kcontrol_new knew = | ||
5627 | HDA_CODEC_MUTE_MONO("Input Source", | ||
5628 | INPUT_SOURCE_ENUM, 1, 0, HDA_INPUT); | ||
5629 | knew.info = ca0132_alt_input_source_info; | ||
5630 | knew.get = ca0132_alt_input_source_get; | ||
5631 | knew.put = ca0132_alt_input_source_put; | ||
5632 | return snd_hda_ctl_add(codec, INPUT_SOURCE_ENUM, | ||
5633 | snd_ctl_new1(&knew, codec)); | ||
5634 | } | ||
5635 | |||
5636 | /* | ||
5637 | * Add mic boost enumerated control. Switches through 0dB to 30dB. This adds | ||
5638 | * more control than the original mic boost, which is either full 30dB or off. | ||
5639 | */ | ||
5640 | static int ca0132_alt_add_mic_boost_enum(struct hda_codec *codec) | ||
5641 | { | ||
5642 | struct snd_kcontrol_new knew = | ||
5643 | HDA_CODEC_MUTE_MONO("Mic Boost Capture Switch", | ||
5644 | MIC_BOOST_ENUM, 1, 0, HDA_INPUT); | ||
5645 | knew.info = ca0132_alt_mic_boost_info; | ||
5646 | knew.get = ca0132_alt_mic_boost_get; | ||
5647 | knew.put = ca0132_alt_mic_boost_put; | ||
5648 | return snd_hda_ctl_add(codec, MIC_BOOST_ENUM, | ||
5649 | snd_ctl_new1(&knew, codec)); | ||
5650 | |||
5651 | } | ||
5652 | |||
5653 | /* | ||
5654 | * Need to create slave controls for the alternate codecs that have surround | ||
5655 | * capabilities. | ||
5656 | */ | ||
5657 | static const char * const ca0132_alt_slave_pfxs[] = { | ||
5658 | "Front", "Surround", "Center", "LFE", NULL, | ||
5659 | }; | ||
5660 | |||
5661 | /* | ||
5662 | * Also need special channel map, because the default one is incorrect. | ||
5663 | * I think this has to do with the pin for rear surround being 0x11, | ||
5664 | * and the center/lfe being 0x10. Usually the pin order is the opposite. | ||
5665 | */ | ||
5666 | const struct snd_pcm_chmap_elem ca0132_alt_chmaps[] = { | ||
5667 | { .channels = 2, | ||
5668 | .map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR } }, | ||
5669 | { .channels = 4, | ||
5670 | .map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR, | ||
5671 | SNDRV_CHMAP_RL, SNDRV_CHMAP_RR } }, | ||
5672 | { .channels = 6, | ||
5673 | .map = { SNDRV_CHMAP_FL, SNDRV_CHMAP_FR, | ||
5674 | SNDRV_CHMAP_FC, SNDRV_CHMAP_LFE, | ||
5675 | SNDRV_CHMAP_RL, SNDRV_CHMAP_RR } }, | ||
5676 | { } | ||
5677 | }; | ||
5678 | |||
5679 | /* Add the correct chmap for streams with 6 channels. */ | ||
5680 | static void ca0132_alt_add_chmap_ctls(struct hda_codec *codec) | ||
5681 | { | ||
5682 | int err = 0; | ||
5683 | struct hda_pcm *pcm; | ||
5684 | |||
5685 | list_for_each_entry(pcm, &codec->pcm_list_head, list) { | ||
5686 | struct hda_pcm_stream *hinfo = | ||
5687 | &pcm->stream[SNDRV_PCM_STREAM_PLAYBACK]; | ||
5688 | struct snd_pcm_chmap *chmap; | ||
5689 | const struct snd_pcm_chmap_elem *elem; | ||
5690 | |||
5691 | elem = ca0132_alt_chmaps; | ||
5692 | if (hinfo->channels_max == 6) { | ||
5693 | err = snd_pcm_add_chmap_ctls(pcm->pcm, | ||
5694 | SNDRV_PCM_STREAM_PLAYBACK, | ||
5695 | elem, hinfo->channels_max, 0, &chmap); | ||
5696 | if (err < 0) | ||
5697 | codec_dbg(codec, "snd_pcm_add_chmap_ctls failed!"); | ||
5698 | } | ||
5699 | } | ||
5700 | } | ||
5701 | |||
3932 | /* | 5702 | /* |
3933 | * When changing Node IDs for Mixer Controls below, make sure to update | 5703 | * When changing Node IDs for Mixer Controls below, make sure to update |
3934 | * Node IDs in ca0132_config() as well. | 5704 | * Node IDs in ca0132_config() as well. |
3935 | */ | 5705 | */ |
3936 | static struct snd_kcontrol_new ca0132_mixer[] = { | 5706 | static const struct snd_kcontrol_new ca0132_mixer[] = { |
3937 | CA0132_CODEC_VOL("Master Playback Volume", VNID_SPK, HDA_OUTPUT), | 5707 | CA0132_CODEC_VOL("Master Playback Volume", VNID_SPK, HDA_OUTPUT), |
3938 | CA0132_CODEC_MUTE("Master Playback Switch", VNID_SPK, HDA_OUTPUT), | 5708 | CA0132_CODEC_MUTE("Master Playback Switch", VNID_SPK, HDA_OUTPUT), |
3939 | CA0132_CODEC_VOL("Capture Volume", VNID_MIC, HDA_INPUT), | 5709 | CA0132_CODEC_VOL("Capture Volume", VNID_MIC, HDA_INPUT), |
@@ -3955,10 +5725,55 @@ static struct snd_kcontrol_new ca0132_mixer[] = { | |||
3955 | { } /* end */ | 5725 | { } /* end */ |
3956 | }; | 5726 | }; |
3957 | 5727 | ||
5728 | /* | ||
5729 | * SBZ specific control mixer. Removes auto-detect for mic, and adds surround | ||
5730 | * controls. Also sets both the Front Playback and Capture Volume controls to | ||
5731 | * alt so they set the DSP's decibel level. | ||
5732 | */ | ||
5733 | static const struct snd_kcontrol_new sbz_mixer[] = { | ||
5734 | CA0132_ALT_CODEC_VOL("Front Playback Volume", 0x02, HDA_OUTPUT), | ||
5735 | CA0132_CODEC_MUTE("Front Playback Switch", VNID_SPK, HDA_OUTPUT), | ||
5736 | HDA_CODEC_VOLUME("Surround Playback Volume", 0x04, 0, HDA_OUTPUT), | ||
5737 | HDA_CODEC_MUTE("Surround Playback Switch", 0x04, 0, HDA_OUTPUT), | ||
5738 | HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x03, 1, 0, HDA_OUTPUT), | ||
5739 | HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x03, 1, 0, HDA_OUTPUT), | ||
5740 | HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x03, 2, 0, HDA_OUTPUT), | ||
5741 | HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x03, 2, 0, HDA_OUTPUT), | ||
5742 | CA0132_ALT_CODEC_VOL("Capture Volume", 0x07, HDA_INPUT), | ||
5743 | CA0132_CODEC_MUTE("Capture Switch", VNID_MIC, HDA_INPUT), | ||
5744 | HDA_CODEC_VOLUME("What U Hear Capture Volume", 0x0a, 0, HDA_INPUT), | ||
5745 | HDA_CODEC_MUTE("What U Hear Capture Switch", 0x0a, 0, HDA_INPUT), | ||
5746 | CA0132_CODEC_MUTE_MONO("HP/Speaker Auto Detect Playback Switch", | ||
5747 | VNID_HP_ASEL, 1, HDA_OUTPUT), | ||
5748 | { } /* end */ | ||
5749 | }; | ||
5750 | |||
5751 | /* | ||
5752 | * Same as the Sound Blaster Z, except doesn't use the alt volume for capture | ||
5753 | * because it doesn't set decibel levels for the DSP for capture. | ||
5754 | */ | ||
5755 | static const struct snd_kcontrol_new r3di_mixer[] = { | ||
5756 | CA0132_ALT_CODEC_VOL("Front Playback Volume", 0x02, HDA_OUTPUT), | ||
5757 | CA0132_CODEC_MUTE("Front Playback Switch", VNID_SPK, HDA_OUTPUT), | ||
5758 | HDA_CODEC_VOLUME("Surround Playback Volume", 0x04, 0, HDA_OUTPUT), | ||
5759 | HDA_CODEC_MUTE("Surround Playback Switch", 0x04, 0, HDA_OUTPUT), | ||
5760 | HDA_CODEC_VOLUME_MONO("Center Playback Volume", 0x03, 1, 0, HDA_OUTPUT), | ||
5761 | HDA_CODEC_MUTE_MONO("Center Playback Switch", 0x03, 1, 0, HDA_OUTPUT), | ||
5762 | HDA_CODEC_VOLUME_MONO("LFE Playback Volume", 0x03, 2, 0, HDA_OUTPUT), | ||
5763 | HDA_CODEC_MUTE_MONO("LFE Playback Switch", 0x03, 2, 0, HDA_OUTPUT), | ||
5764 | CA0132_CODEC_VOL("Capture Volume", VNID_MIC, HDA_INPUT), | ||
5765 | CA0132_CODEC_MUTE("Capture Switch", VNID_MIC, HDA_INPUT), | ||
5766 | HDA_CODEC_VOLUME("What U Hear Capture Volume", 0x0a, 0, HDA_INPUT), | ||
5767 | HDA_CODEC_MUTE("What U Hear Capture Switch", 0x0a, 0, HDA_INPUT), | ||
5768 | CA0132_CODEC_MUTE_MONO("HP/Speaker Auto Detect Playback Switch", | ||
5769 | VNID_HP_ASEL, 1, HDA_OUTPUT), | ||
5770 | { } /* end */ | ||
5771 | }; | ||
5772 | |||
3958 | static int ca0132_build_controls(struct hda_codec *codec) | 5773 | static int ca0132_build_controls(struct hda_codec *codec) |
3959 | { | 5774 | { |
3960 | struct ca0132_spec *spec = codec->spec; | 5775 | struct ca0132_spec *spec = codec->spec; |
3961 | int i, num_fx; | 5776 | int i, num_fx, num_sliders; |
3962 | int err = 0; | 5777 | int err = 0; |
3963 | 5778 | ||
3964 | /* Add Mixer controls */ | 5779 | /* Add Mixer controls */ |
@@ -3967,29 +5782,94 @@ static int ca0132_build_controls(struct hda_codec *codec) | |||
3967 | if (err < 0) | 5782 | if (err < 0) |
3968 | return err; | 5783 | return err; |
3969 | } | 5784 | } |
5785 | /* Setup vmaster with surround slaves for desktop ca0132 devices */ | ||
5786 | if (spec->use_alt_functions) { | ||
5787 | snd_hda_set_vmaster_tlv(codec, spec->dacs[0], HDA_OUTPUT, | ||
5788 | spec->tlv); | ||
5789 | snd_hda_add_vmaster(codec, "Master Playback Volume", | ||
5790 | spec->tlv, ca0132_alt_slave_pfxs, | ||
5791 | "Playback Volume"); | ||
5792 | err = __snd_hda_add_vmaster(codec, "Master Playback Switch", | ||
5793 | NULL, ca0132_alt_slave_pfxs, | ||
5794 | "Playback Switch", | ||
5795 | true, &spec->vmaster_mute.sw_kctl); | ||
5796 | |||
5797 | } | ||
3970 | 5798 | ||
3971 | /* Add in and out effects controls. | 5799 | /* Add in and out effects controls. |
3972 | * VoiceFX, PE and CrystalVoice are added separately. | 5800 | * VoiceFX, PE and CrystalVoice are added separately. |
3973 | */ | 5801 | */ |
3974 | num_fx = OUT_EFFECTS_COUNT + IN_EFFECTS_COUNT; | 5802 | num_fx = OUT_EFFECTS_COUNT + IN_EFFECTS_COUNT; |
3975 | for (i = 0; i < num_fx; i++) { | 5803 | for (i = 0; i < num_fx; i++) { |
5804 | /* SBZ breaks if Echo Cancellation is used */ | ||
5805 | if (spec->quirk == QUIRK_SBZ) { | ||
5806 | if (i == (ECHO_CANCELLATION - IN_EFFECT_START_NID + | ||
5807 | OUT_EFFECTS_COUNT)) | ||
5808 | continue; | ||
5809 | } | ||
5810 | |||
3976 | err = add_fx_switch(codec, ca0132_effects[i].nid, | 5811 | err = add_fx_switch(codec, ca0132_effects[i].nid, |
3977 | ca0132_effects[i].name, | 5812 | ca0132_effects[i].name, |
3978 | ca0132_effects[i].direct); | 5813 | ca0132_effects[i].direct); |
3979 | if (err < 0) | 5814 | if (err < 0) |
3980 | return err; | 5815 | return err; |
3981 | } | 5816 | } |
5817 | /* | ||
5818 | * If codec has use_alt_controls set to true, add effect level sliders, | ||
5819 | * EQ presets, and Smart Volume presets. Also, change names to add FX | ||
5820 | * prefix, and change PlayEnhancement and CrystalVoice to match. | ||
5821 | */ | ||
5822 | if (spec->use_alt_controls) { | ||
5823 | ca0132_alt_add_svm_enum(codec); | ||
5824 | add_ca0132_alt_eq_presets(codec); | ||
5825 | err = add_fx_switch(codec, PLAY_ENHANCEMENT, | ||
5826 | "Enable OutFX", 0); | ||
5827 | if (err < 0) | ||
5828 | return err; | ||
3982 | 5829 | ||
3983 | err = add_fx_switch(codec, PLAY_ENHANCEMENT, "PlayEnhancement", 0); | 5830 | err = add_fx_switch(codec, CRYSTAL_VOICE, |
3984 | if (err < 0) | 5831 | "Enable InFX", 1); |
3985 | return err; | 5832 | if (err < 0) |
5833 | return err; | ||
3986 | 5834 | ||
3987 | err = add_fx_switch(codec, CRYSTAL_VOICE, "CrystalVoice", 1); | 5835 | num_sliders = OUT_EFFECTS_COUNT - 1; |
3988 | if (err < 0) | 5836 | for (i = 0; i < num_sliders; i++) { |
3989 | return err; | 5837 | err = ca0132_alt_add_effect_slider(codec, |
5838 | ca0132_effects[i].nid, | ||
5839 | ca0132_effects[i].name, | ||
5840 | ca0132_effects[i].direct); | ||
5841 | if (err < 0) | ||
5842 | return err; | ||
5843 | } | ||
5844 | |||
5845 | err = ca0132_alt_add_effect_slider(codec, XBASS_XOVER, | ||
5846 | "X-Bass Crossover", EFX_DIR_OUT); | ||
3990 | 5847 | ||
5848 | if (err < 0) | ||
5849 | return err; | ||
5850 | } else { | ||
5851 | err = add_fx_switch(codec, PLAY_ENHANCEMENT, | ||
5852 | "PlayEnhancement", 0); | ||
5853 | if (err < 0) | ||
5854 | return err; | ||
5855 | |||
5856 | err = add_fx_switch(codec, CRYSTAL_VOICE, | ||
5857 | "CrystalVoice", 1); | ||
5858 | if (err < 0) | ||
5859 | return err; | ||
5860 | } | ||
3991 | add_voicefx(codec); | 5861 | add_voicefx(codec); |
3992 | 5862 | ||
5863 | /* | ||
5864 | * If the codec uses alt_functions, you need the enumerated controls | ||
5865 | * to select the new outputs and inputs, plus add the new mic boost | ||
5866 | * setting control. | ||
5867 | */ | ||
5868 | if (spec->use_alt_functions) { | ||
5869 | ca0132_alt_add_output_enum(codec); | ||
5870 | ca0132_alt_add_input_enum(codec); | ||
5871 | ca0132_alt_add_mic_boost_enum(codec); | ||
5872 | } | ||
3993 | #ifdef ENABLE_TUNING_CONTROLS | 5873 | #ifdef ENABLE_TUNING_CONTROLS |
3994 | add_tuning_ctls(codec); | 5874 | add_tuning_ctls(codec); |
3995 | #endif | 5875 | #endif |
@@ -4014,6 +5894,10 @@ static int ca0132_build_controls(struct hda_codec *codec) | |||
4014 | if (err < 0) | 5894 | if (err < 0) |
4015 | return err; | 5895 | return err; |
4016 | } | 5896 | } |
5897 | |||
5898 | if (spec->use_alt_functions) | ||
5899 | ca0132_alt_add_chmap_ctls(codec); | ||
5900 | |||
4017 | return 0; | 5901 | return 0; |
4018 | } | 5902 | } |
4019 | 5903 | ||
@@ -4068,6 +5952,11 @@ static int ca0132_build_pcms(struct hda_codec *codec) | |||
4068 | info = snd_hda_codec_pcm_new(codec, "CA0132 Analog"); | 5952 | info = snd_hda_codec_pcm_new(codec, "CA0132 Analog"); |
4069 | if (!info) | 5953 | if (!info) |
4070 | return -ENOMEM; | 5954 | return -ENOMEM; |
5955 | if (spec->use_alt_functions) { | ||
5956 | info->own_chmap = true; | ||
5957 | info->stream[SNDRV_PCM_STREAM_PLAYBACK].chmap | ||
5958 | = ca0132_alt_chmaps; | ||
5959 | } | ||
4071 | info->stream[SNDRV_PCM_STREAM_PLAYBACK] = ca0132_pcm_analog_playback; | 5960 | info->stream[SNDRV_PCM_STREAM_PLAYBACK] = ca0132_pcm_analog_playback; |
4072 | info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->dacs[0]; | 5961 | info->stream[SNDRV_PCM_STREAM_PLAYBACK].nid = spec->dacs[0]; |
4073 | info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max = | 5962 | info->stream[SNDRV_PCM_STREAM_PLAYBACK].channels_max = |
@@ -4076,12 +5965,16 @@ static int ca0132_build_pcms(struct hda_codec *codec) | |||
4076 | info->stream[SNDRV_PCM_STREAM_CAPTURE].substreams = 1; | 5965 | info->stream[SNDRV_PCM_STREAM_CAPTURE].substreams = 1; |
4077 | info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->adcs[0]; | 5966 | info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->adcs[0]; |
4078 | 5967 | ||
4079 | info = snd_hda_codec_pcm_new(codec, "CA0132 Analog Mic-In2"); | 5968 | /* With the DSP enabled, desktops don't use this ADC. */ |
4080 | if (!info) | 5969 | if (spec->use_alt_functions) { |
4081 | return -ENOMEM; | 5970 | info = snd_hda_codec_pcm_new(codec, "CA0132 Analog Mic-In2"); |
4082 | info->stream[SNDRV_PCM_STREAM_CAPTURE] = ca0132_pcm_analog_capture; | 5971 | if (!info) |
4083 | info->stream[SNDRV_PCM_STREAM_CAPTURE].substreams = 1; | 5972 | return -ENOMEM; |
4084 | info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->adcs[1]; | 5973 | info->stream[SNDRV_PCM_STREAM_CAPTURE] = |
5974 | ca0132_pcm_analog_capture; | ||
5975 | info->stream[SNDRV_PCM_STREAM_CAPTURE].substreams = 1; | ||
5976 | info->stream[SNDRV_PCM_STREAM_CAPTURE].nid = spec->adcs[1]; | ||
5977 | } | ||
4085 | 5978 | ||
4086 | info = snd_hda_codec_pcm_new(codec, "CA0132 What U Hear"); | 5979 | info = snd_hda_codec_pcm_new(codec, "CA0132 What U Hear"); |
4087 | if (!info) | 5980 | if (!info) |
@@ -4288,6 +6181,196 @@ static void ca0132_refresh_widget_caps(struct hda_codec *codec) | |||
4288 | } | 6181 | } |
4289 | 6182 | ||
4290 | /* | 6183 | /* |
6184 | * Recon3Di r3di_setup_defaults sub functions. | ||
6185 | */ | ||
6186 | |||
6187 | static void r3di_dsp_scp_startup(struct hda_codec *codec) | ||
6188 | { | ||
6189 | unsigned int tmp; | ||
6190 | |||
6191 | tmp = 0x00000000; | ||
6192 | dspio_set_uint_param_no_source(codec, 0x80, 0x0A, tmp); | ||
6193 | |||
6194 | tmp = 0x00000001; | ||
6195 | dspio_set_uint_param_no_source(codec, 0x80, 0x0B, tmp); | ||
6196 | |||
6197 | tmp = 0x00000004; | ||
6198 | dspio_set_uint_param_no_source(codec, 0x80, 0x0C, tmp); | ||
6199 | |||
6200 | tmp = 0x00000005; | ||
6201 | dspio_set_uint_param_no_source(codec, 0x80, 0x0C, tmp); | ||
6202 | |||
6203 | tmp = 0x00000000; | ||
6204 | dspio_set_uint_param_no_source(codec, 0x80, 0x0C, tmp); | ||
6205 | |||
6206 | } | ||
6207 | |||
6208 | static void r3di_dsp_initial_mic_setup(struct hda_codec *codec) | ||
6209 | { | ||
6210 | unsigned int tmp; | ||
6211 | |||
6212 | /* Mic 1 Setup */ | ||
6213 | chipio_set_conn_rate(codec, MEM_CONNID_MICIN1, SR_96_000); | ||
6214 | chipio_set_conn_rate(codec, MEM_CONNID_MICOUT1, SR_96_000); | ||
6215 | /* This ConnPointID is unique to Recon3Di. Haven't seen it elsewhere */ | ||
6216 | chipio_set_conn_rate(codec, 0x0F, SR_96_000); | ||
6217 | tmp = FLOAT_ONE; | ||
6218 | dspio_set_uint_param(codec, 0x80, 0x00, tmp); | ||
6219 | |||
6220 | /* Mic 2 Setup, even though it isn't connected on SBZ */ | ||
6221 | chipio_set_conn_rate(codec, MEM_CONNID_MICIN2, SR_96_000); | ||
6222 | chipio_set_conn_rate(codec, MEM_CONNID_MICOUT2, SR_96_000); | ||
6223 | chipio_set_conn_rate(codec, 0x0F, SR_96_000); | ||
6224 | tmp = FLOAT_ZERO; | ||
6225 | dspio_set_uint_param(codec, 0x80, 0x01, tmp); | ||
6226 | } | ||
6227 | |||
6228 | /* | ||
6229 | * Initialize Sound Blaster Z analog microphones. | ||
6230 | */ | ||
6231 | static void sbz_init_analog_mics(struct hda_codec *codec) | ||
6232 | { | ||
6233 | unsigned int tmp; | ||
6234 | |||
6235 | /* Mic 1 Setup */ | ||
6236 | chipio_set_conn_rate(codec, MEM_CONNID_MICIN1, SR_96_000); | ||
6237 | chipio_set_conn_rate(codec, MEM_CONNID_MICOUT1, SR_96_000); | ||
6238 | tmp = FLOAT_THREE; | ||
6239 | dspio_set_uint_param(codec, 0x80, 0x00, tmp); | ||
6240 | |||
6241 | /* Mic 2 Setup, even though it isn't connected on SBZ */ | ||
6242 | chipio_set_conn_rate(codec, MEM_CONNID_MICIN2, SR_96_000); | ||
6243 | chipio_set_conn_rate(codec, MEM_CONNID_MICOUT2, SR_96_000); | ||
6244 | tmp = FLOAT_ZERO; | ||
6245 | dspio_set_uint_param(codec, 0x80, 0x01, tmp); | ||
6246 | |||
6247 | } | ||
6248 | |||
6249 | /* | ||
6250 | * Sets the source of stream 0x14 to connpointID 0x48, and the destination | ||
6251 | * connpointID to 0x91. If this isn't done, the destination is 0x71, and | ||
6252 | * you get no sound. I'm guessing this has to do with the Sound Blaster Z | ||
6253 | * having an updated DAC, which changes the destination to that DAC. | ||
6254 | */ | ||
6255 | static void sbz_connect_streams(struct hda_codec *codec) | ||
6256 | { | ||
6257 | struct ca0132_spec *spec = codec->spec; | ||
6258 | |||
6259 | mutex_lock(&spec->chipio_mutex); | ||
6260 | |||
6261 | codec_dbg(codec, "Connect Streams entered, mutex locked and loaded.\n"); | ||
6262 | |||
6263 | chipio_set_stream_channels(codec, 0x0C, 6); | ||
6264 | chipio_set_stream_control(codec, 0x0C, 1); | ||
6265 | |||
6266 | /* This value is 0x43 for 96khz, and 0x83 for 192khz. */ | ||
6267 | chipio_write_no_mutex(codec, 0x18a020, 0x00000043); | ||
6268 | |||
6269 | /* Setup stream 0x14 with it's source and destination points */ | ||
6270 | chipio_set_stream_source_dest(codec, 0x14, 0x48, 0x91); | ||
6271 | chipio_set_conn_rate_no_mutex(codec, 0x48, SR_96_000); | ||
6272 | chipio_set_conn_rate_no_mutex(codec, 0x91, SR_96_000); | ||
6273 | chipio_set_stream_channels(codec, 0x14, 2); | ||
6274 | chipio_set_stream_control(codec, 0x14, 1); | ||
6275 | |||
6276 | codec_dbg(codec, "Connect Streams exited, mutex released.\n"); | ||
6277 | |||
6278 | mutex_unlock(&spec->chipio_mutex); | ||
6279 | |||
6280 | } | ||
6281 | |||
6282 | /* | ||
6283 | * Write data through ChipIO to setup proper stream destinations. | ||
6284 | * Not sure how it exactly works, but it seems to direct data | ||
6285 | * to different destinations. Example is f8 to c0, e0 to c0. | ||
6286 | * All I know is, if you don't set these, you get no sound. | ||
6287 | */ | ||
6288 | static void sbz_chipio_startup_data(struct hda_codec *codec) | ||
6289 | { | ||
6290 | struct ca0132_spec *spec = codec->spec; | ||
6291 | |||
6292 | mutex_lock(&spec->chipio_mutex); | ||
6293 | codec_dbg(codec, "Startup Data entered, mutex locked and loaded.\n"); | ||
6294 | |||
6295 | /* These control audio output */ | ||
6296 | chipio_write_no_mutex(codec, 0x190060, 0x0001f8c0); | ||
6297 | chipio_write_no_mutex(codec, 0x190064, 0x0001f9c1); | ||
6298 | chipio_write_no_mutex(codec, 0x190068, 0x0001fac6); | ||
6299 | chipio_write_no_mutex(codec, 0x19006c, 0x0001fbc7); | ||
6300 | /* Signal to update I think */ | ||
6301 | chipio_write_no_mutex(codec, 0x19042c, 0x00000001); | ||
6302 | |||
6303 | chipio_set_stream_channels(codec, 0x0C, 6); | ||
6304 | chipio_set_stream_control(codec, 0x0C, 1); | ||
6305 | /* No clue what these control */ | ||
6306 | chipio_write_no_mutex(codec, 0x190030, 0x0001e0c0); | ||
6307 | chipio_write_no_mutex(codec, 0x190034, 0x0001e1c1); | ||
6308 | chipio_write_no_mutex(codec, 0x190038, 0x0001e4c2); | ||
6309 | chipio_write_no_mutex(codec, 0x19003c, 0x0001e5c3); | ||
6310 | chipio_write_no_mutex(codec, 0x190040, 0x0001e2c4); | ||
6311 | chipio_write_no_mutex(codec, 0x190044, 0x0001e3c5); | ||
6312 | chipio_write_no_mutex(codec, 0x190048, 0x0001e8c6); | ||
6313 | chipio_write_no_mutex(codec, 0x19004c, 0x0001e9c7); | ||
6314 | chipio_write_no_mutex(codec, 0x190050, 0x0001ecc8); | ||
6315 | chipio_write_no_mutex(codec, 0x190054, 0x0001edc9); | ||
6316 | chipio_write_no_mutex(codec, 0x190058, 0x0001eaca); | ||
6317 | chipio_write_no_mutex(codec, 0x19005c, 0x0001ebcb); | ||
6318 | |||
6319 | chipio_write_no_mutex(codec, 0x19042c, 0x00000001); | ||
6320 | |||
6321 | codec_dbg(codec, "Startup Data exited, mutex released.\n"); | ||
6322 | mutex_unlock(&spec->chipio_mutex); | ||
6323 | } | ||
6324 | |||
6325 | /* | ||
6326 | * Sound Blaster Z uses these after DSP is loaded. Weird SCP commands | ||
6327 | * without a 0x20 source like normal. | ||
6328 | */ | ||
6329 | static void sbz_dsp_scp_startup(struct hda_codec *codec) | ||
6330 | { | ||
6331 | unsigned int tmp; | ||
6332 | |||
6333 | tmp = 0x00000003; | ||
6334 | dspio_set_uint_param_no_source(codec, 0x80, 0x0C, tmp); | ||
6335 | |||
6336 | tmp = 0x00000000; | ||
6337 | dspio_set_uint_param_no_source(codec, 0x80, 0x0A, tmp); | ||
6338 | |||
6339 | tmp = 0x00000001; | ||
6340 | dspio_set_uint_param_no_source(codec, 0x80, 0x0B, tmp); | ||
6341 | |||
6342 | tmp = 0x00000004; | ||
6343 | dspio_set_uint_param_no_source(codec, 0x80, 0x0C, tmp); | ||
6344 | |||
6345 | tmp = 0x00000005; | ||
6346 | dspio_set_uint_param_no_source(codec, 0x80, 0x0C, tmp); | ||
6347 | |||
6348 | tmp = 0x00000000; | ||
6349 | dspio_set_uint_param_no_source(codec, 0x80, 0x0C, tmp); | ||
6350 | |||
6351 | } | ||
6352 | |||
6353 | static void sbz_dsp_initial_mic_setup(struct hda_codec *codec) | ||
6354 | { | ||
6355 | unsigned int tmp; | ||
6356 | |||
6357 | chipio_set_stream_control(codec, 0x03, 0); | ||
6358 | chipio_set_stream_control(codec, 0x04, 0); | ||
6359 | |||
6360 | chipio_set_conn_rate(codec, MEM_CONNID_MICIN1, SR_96_000); | ||
6361 | chipio_set_conn_rate(codec, MEM_CONNID_MICOUT1, SR_96_000); | ||
6362 | |||
6363 | tmp = FLOAT_THREE; | ||
6364 | dspio_set_uint_param(codec, 0x80, 0x00, tmp); | ||
6365 | |||
6366 | chipio_set_stream_control(codec, 0x03, 1); | ||
6367 | chipio_set_stream_control(codec, 0x04, 1); | ||
6368 | |||
6369 | chipio_write(codec, 0x18b098, 0x0000000c); | ||
6370 | chipio_write(codec, 0x18b09C, 0x0000000c); | ||
6371 | } | ||
6372 | |||
6373 | /* | ||
4291 | * Setup default parameters for DSP | 6374 | * Setup default parameters for DSP |
4292 | */ | 6375 | */ |
4293 | static void ca0132_setup_defaults(struct hda_codec *codec) | 6376 | static void ca0132_setup_defaults(struct hda_codec *codec) |
@@ -4332,16 +6415,159 @@ static void ca0132_setup_defaults(struct hda_codec *codec) | |||
4332 | } | 6415 | } |
4333 | 6416 | ||
4334 | /* | 6417 | /* |
6418 | * Setup default parameters for Recon3Di DSP. | ||
6419 | */ | ||
6420 | |||
6421 | static void r3di_setup_defaults(struct hda_codec *codec) | ||
6422 | { | ||
6423 | struct ca0132_spec *spec = codec->spec; | ||
6424 | unsigned int tmp; | ||
6425 | int num_fx; | ||
6426 | int idx, i; | ||
6427 | |||
6428 | if (spec->dsp_state != DSP_DOWNLOADED) | ||
6429 | return; | ||
6430 | |||
6431 | r3di_dsp_scp_startup(codec); | ||
6432 | |||
6433 | r3di_dsp_initial_mic_setup(codec); | ||
6434 | |||
6435 | /*remove DSP headroom*/ | ||
6436 | tmp = FLOAT_ZERO; | ||
6437 | dspio_set_uint_param(codec, 0x96, 0x3C, tmp); | ||
6438 | |||
6439 | /* set WUH source */ | ||
6440 | tmp = FLOAT_TWO; | ||
6441 | dspio_set_uint_param(codec, 0x31, 0x00, tmp); | ||
6442 | chipio_set_conn_rate(codec, MEM_CONNID_WUH, SR_48_000); | ||
6443 | |||
6444 | /* Set speaker source? */ | ||
6445 | dspio_set_uint_param(codec, 0x32, 0x00, tmp); | ||
6446 | |||
6447 | r3di_gpio_dsp_status_set(codec, R3DI_DSP_DOWNLOADED); | ||
6448 | |||
6449 | /* Setup effect defaults */ | ||
6450 | num_fx = OUT_EFFECTS_COUNT + IN_EFFECTS_COUNT + 1; | ||
6451 | for (idx = 0; idx < num_fx; idx++) { | ||
6452 | for (i = 0; i <= ca0132_effects[idx].params; i++) { | ||
6453 | dspio_set_uint_param(codec, | ||
6454 | ca0132_effects[idx].mid, | ||
6455 | ca0132_effects[idx].reqs[i], | ||
6456 | ca0132_effects[idx].def_vals[i]); | ||
6457 | } | ||
6458 | } | ||
6459 | |||
6460 | } | ||
6461 | |||
6462 | /* | ||
6463 | * Setup default parameters for the Sound Blaster Z DSP. A lot more going on | ||
6464 | * than the Chromebook setup. | ||
6465 | */ | ||
6466 | static void sbz_setup_defaults(struct hda_codec *codec) | ||
6467 | { | ||
6468 | struct ca0132_spec *spec = codec->spec; | ||
6469 | unsigned int tmp, stream_format; | ||
6470 | int num_fx; | ||
6471 | int idx, i; | ||
6472 | |||
6473 | if (spec->dsp_state != DSP_DOWNLOADED) | ||
6474 | return; | ||
6475 | |||
6476 | sbz_dsp_scp_startup(codec); | ||
6477 | |||
6478 | sbz_init_analog_mics(codec); | ||
6479 | |||
6480 | sbz_connect_streams(codec); | ||
6481 | |||
6482 | sbz_chipio_startup_data(codec); | ||
6483 | |||
6484 | chipio_set_stream_control(codec, 0x03, 1); | ||
6485 | chipio_set_stream_control(codec, 0x04, 1); | ||
6486 | |||
6487 | /* | ||
6488 | * Sets internal input loopback to off, used to have a switch to | ||
6489 | * enable input loopback, but turned out to be way too buggy. | ||
6490 | */ | ||
6491 | tmp = FLOAT_ONE; | ||
6492 | dspio_set_uint_param(codec, 0x37, 0x08, tmp); | ||
6493 | dspio_set_uint_param(codec, 0x37, 0x10, tmp); | ||
6494 | |||
6495 | /*remove DSP headroom*/ | ||
6496 | tmp = FLOAT_ZERO; | ||
6497 | dspio_set_uint_param(codec, 0x96, 0x3C, tmp); | ||
6498 | |||
6499 | /* set WUH source */ | ||
6500 | tmp = FLOAT_TWO; | ||
6501 | dspio_set_uint_param(codec, 0x31, 0x00, tmp); | ||
6502 | chipio_set_conn_rate(codec, MEM_CONNID_WUH, SR_48_000); | ||
6503 | |||
6504 | /* Set speaker source? */ | ||
6505 | dspio_set_uint_param(codec, 0x32, 0x00, tmp); | ||
6506 | |||
6507 | sbz_dsp_initial_mic_setup(codec); | ||
6508 | |||
6509 | |||
6510 | /* out, in effects + voicefx */ | ||
6511 | num_fx = OUT_EFFECTS_COUNT + IN_EFFECTS_COUNT + 1; | ||
6512 | for (idx = 0; idx < num_fx; idx++) { | ||
6513 | for (i = 0; i <= ca0132_effects[idx].params; i++) { | ||
6514 | dspio_set_uint_param(codec, | ||
6515 | ca0132_effects[idx].mid, | ||
6516 | ca0132_effects[idx].reqs[i], | ||
6517 | ca0132_effects[idx].def_vals[i]); | ||
6518 | } | ||
6519 | } | ||
6520 | |||
6521 | /* | ||
6522 | * Have to make a stream to bind the sound output to, otherwise | ||
6523 | * you'll get dead audio. Before I did this, it would bind to an | ||
6524 | * audio input, and would never work | ||
6525 | */ | ||
6526 | stream_format = snd_hdac_calc_stream_format(48000, 2, | ||
6527 | SNDRV_PCM_FORMAT_S32_LE, 32, 0); | ||
6528 | |||
6529 | snd_hda_codec_setup_stream(codec, spec->dacs[0], spec->dsp_stream_id, | ||
6530 | 0, stream_format); | ||
6531 | |||
6532 | snd_hda_codec_cleanup_stream(codec, spec->dacs[0]); | ||
6533 | |||
6534 | snd_hda_codec_setup_stream(codec, spec->dacs[0], spec->dsp_stream_id, | ||
6535 | 0, stream_format); | ||
6536 | |||
6537 | snd_hda_codec_cleanup_stream(codec, spec->dacs[0]); | ||
6538 | } | ||
6539 | |||
6540 | /* | ||
4335 | * Initialization of flags in chip | 6541 | * Initialization of flags in chip |
4336 | */ | 6542 | */ |
4337 | static void ca0132_init_flags(struct hda_codec *codec) | 6543 | static void ca0132_init_flags(struct hda_codec *codec) |
4338 | { | 6544 | { |
4339 | chipio_set_control_flag(codec, CONTROL_FLAG_IDLE_ENABLE, 0); | 6545 | struct ca0132_spec *spec = codec->spec; |
4340 | chipio_set_control_flag(codec, CONTROL_FLAG_PORT_A_COMMON_MODE, 0); | 6546 | |
4341 | chipio_set_control_flag(codec, CONTROL_FLAG_PORT_D_COMMON_MODE, 0); | 6547 | if (spec->use_alt_functions) { |
4342 | chipio_set_control_flag(codec, CONTROL_FLAG_PORT_A_10KOHM_LOAD, 0); | 6548 | chipio_set_control_flag(codec, CONTROL_FLAG_DSP_96KHZ, 1); |
4343 | chipio_set_control_flag(codec, CONTROL_FLAG_PORT_D_10KOHM_LOAD, 0); | 6549 | chipio_set_control_flag(codec, CONTROL_FLAG_DAC_96KHZ, 1); |
4344 | chipio_set_control_flag(codec, CONTROL_FLAG_ADC_C_HIGH_PASS, 1); | 6550 | chipio_set_control_flag(codec, CONTROL_FLAG_ADC_B_96KHZ, 1); |
6551 | chipio_set_control_flag(codec, CONTROL_FLAG_ADC_C_96KHZ, 1); | ||
6552 | chipio_set_control_flag(codec, CONTROL_FLAG_SRC_RATE_96KHZ, 1); | ||
6553 | chipio_set_control_flag(codec, CONTROL_FLAG_IDLE_ENABLE, 0); | ||
6554 | chipio_set_control_flag(codec, CONTROL_FLAG_SPDIF2OUT, 0); | ||
6555 | chipio_set_control_flag(codec, | ||
6556 | CONTROL_FLAG_PORT_D_10KOHM_LOAD, 0); | ||
6557 | chipio_set_control_flag(codec, | ||
6558 | CONTROL_FLAG_PORT_A_10KOHM_LOAD, 1); | ||
6559 | } else { | ||
6560 | chipio_set_control_flag(codec, CONTROL_FLAG_IDLE_ENABLE, 0); | ||
6561 | chipio_set_control_flag(codec, | ||
6562 | CONTROL_FLAG_PORT_A_COMMON_MODE, 0); | ||
6563 | chipio_set_control_flag(codec, | ||
6564 | CONTROL_FLAG_PORT_D_COMMON_MODE, 0); | ||
6565 | chipio_set_control_flag(codec, | ||
6566 | CONTROL_FLAG_PORT_A_10KOHM_LOAD, 0); | ||
6567 | chipio_set_control_flag(codec, | ||
6568 | CONTROL_FLAG_PORT_D_10KOHM_LOAD, 0); | ||
6569 | chipio_set_control_flag(codec, CONTROL_FLAG_ADC_C_HIGH_PASS, 1); | ||
6570 | } | ||
4345 | } | 6571 | } |
4346 | 6572 | ||
4347 | /* | 6573 | /* |
@@ -4349,6 +6575,16 @@ static void ca0132_init_flags(struct hda_codec *codec) | |||
4349 | */ | 6575 | */ |
4350 | static void ca0132_init_params(struct hda_codec *codec) | 6576 | static void ca0132_init_params(struct hda_codec *codec) |
4351 | { | 6577 | { |
6578 | struct ca0132_spec *spec = codec->spec; | ||
6579 | |||
6580 | if (spec->use_alt_functions) { | ||
6581 | chipio_set_conn_rate(codec, MEM_CONNID_WUH, SR_48_000); | ||
6582 | chipio_set_conn_rate(codec, 0x0B, SR_48_000); | ||
6583 | chipio_set_control_param(codec, CONTROL_PARAM_SPDIF1_SOURCE, 0); | ||
6584 | chipio_set_control_param(codec, 0, 0); | ||
6585 | chipio_set_control_param(codec, CONTROL_PARAM_VIP_SOURCE, 0); | ||
6586 | } | ||
6587 | |||
4352 | chipio_set_control_param(codec, CONTROL_PARAM_PORTA_160OHM_GAIN, 6); | 6588 | chipio_set_control_param(codec, CONTROL_PARAM_PORTA_160OHM_GAIN, 6); |
4353 | chipio_set_control_param(codec, CONTROL_PARAM_PORTD_160OHM_GAIN, 6); | 6589 | chipio_set_control_param(codec, CONTROL_PARAM_PORTD_160OHM_GAIN, 6); |
4354 | } | 6590 | } |
@@ -4370,11 +6606,49 @@ static void ca0132_set_dsp_msr(struct hda_codec *codec, bool is96k) | |||
4370 | static bool ca0132_download_dsp_images(struct hda_codec *codec) | 6606 | static bool ca0132_download_dsp_images(struct hda_codec *codec) |
4371 | { | 6607 | { |
4372 | bool dsp_loaded = false; | 6608 | bool dsp_loaded = false; |
6609 | struct ca0132_spec *spec = codec->spec; | ||
4373 | const struct dsp_image_seg *dsp_os_image; | 6610 | const struct dsp_image_seg *dsp_os_image; |
4374 | const struct firmware *fw_entry; | 6611 | const struct firmware *fw_entry; |
4375 | 6612 | /* | |
4376 | if (request_firmware(&fw_entry, EFX_FILE, codec->card->dev) != 0) | 6613 | * Alternate firmwares for different variants. The Recon3Di apparently |
4377 | return false; | 6614 | * can use the default firmware, but I'll leave the option in case |
6615 | * it needs it again. | ||
6616 | */ | ||
6617 | switch (spec->quirk) { | ||
6618 | case QUIRK_SBZ: | ||
6619 | if (request_firmware(&fw_entry, SBZ_EFX_FILE, | ||
6620 | codec->card->dev) != 0) { | ||
6621 | codec_dbg(codec, "SBZ alt firmware not detected. "); | ||
6622 | spec->alt_firmware_present = false; | ||
6623 | } else { | ||
6624 | codec_dbg(codec, "Sound Blaster Z firmware selected."); | ||
6625 | spec->alt_firmware_present = true; | ||
6626 | } | ||
6627 | break; | ||
6628 | case QUIRK_R3DI: | ||
6629 | if (request_firmware(&fw_entry, R3DI_EFX_FILE, | ||
6630 | codec->card->dev) != 0) { | ||
6631 | codec_dbg(codec, "Recon3Di alt firmware not detected."); | ||
6632 | spec->alt_firmware_present = false; | ||
6633 | } else { | ||
6634 | codec_dbg(codec, "Recon3Di firmware selected."); | ||
6635 | spec->alt_firmware_present = true; | ||
6636 | } | ||
6637 | break; | ||
6638 | default: | ||
6639 | spec->alt_firmware_present = false; | ||
6640 | break; | ||
6641 | } | ||
6642 | /* | ||
6643 | * Use default ctefx.bin if no alt firmware is detected, or if none | ||
6644 | * exists for your particular codec. | ||
6645 | */ | ||
6646 | if (!spec->alt_firmware_present) { | ||
6647 | codec_dbg(codec, "Default firmware selected."); | ||
6648 | if (request_firmware(&fw_entry, EFX_FILE, | ||
6649 | codec->card->dev) != 0) | ||
6650 | return false; | ||
6651 | } | ||
4378 | 6652 | ||
4379 | dsp_os_image = (struct dsp_image_seg *)(fw_entry->data); | 6653 | dsp_os_image = (struct dsp_image_seg *)(fw_entry->data); |
4380 | if (dspload_image(codec, dsp_os_image, 0, 0, true, 0)) { | 6654 | if (dspload_image(codec, dsp_os_image, 0, 0, true, 0)) { |
@@ -4402,13 +6676,17 @@ static void ca0132_download_dsp(struct hda_codec *codec) | |||
4402 | return; /* don't retry failures */ | 6676 | return; /* don't retry failures */ |
4403 | 6677 | ||
4404 | chipio_enable_clocks(codec); | 6678 | chipio_enable_clocks(codec); |
4405 | spec->dsp_state = DSP_DOWNLOADING; | 6679 | if (spec->dsp_state != DSP_DOWNLOADED) { |
4406 | if (!ca0132_download_dsp_images(codec)) | 6680 | spec->dsp_state = DSP_DOWNLOADING; |
4407 | spec->dsp_state = DSP_DOWNLOAD_FAILED; | ||
4408 | else | ||
4409 | spec->dsp_state = DSP_DOWNLOADED; | ||
4410 | 6681 | ||
4411 | if (spec->dsp_state == DSP_DOWNLOADED) | 6682 | if (!ca0132_download_dsp_images(codec)) |
6683 | spec->dsp_state = DSP_DOWNLOAD_FAILED; | ||
6684 | else | ||
6685 | spec->dsp_state = DSP_DOWNLOADED; | ||
6686 | } | ||
6687 | |||
6688 | /* For codecs using alt functions, this is already done earlier */ | ||
6689 | if (spec->dsp_state == DSP_DOWNLOADED && (!spec->use_alt_functions)) | ||
4412 | ca0132_set_dsp_msr(codec, true); | 6690 | ca0132_set_dsp_msr(codec, true); |
4413 | } | 6691 | } |
4414 | 6692 | ||
@@ -4454,6 +6732,10 @@ static void ca0132_init_unsol(struct hda_codec *codec) | |||
4454 | amic_callback); | 6732 | amic_callback); |
4455 | snd_hda_jack_detect_enable_callback(codec, UNSOL_TAG_DSP, | 6733 | snd_hda_jack_detect_enable_callback(codec, UNSOL_TAG_DSP, |
4456 | ca0132_process_dsp_response); | 6734 | ca0132_process_dsp_response); |
6735 | /* Front headphone jack detection */ | ||
6736 | if (spec->use_alt_functions) | ||
6737 | snd_hda_jack_detect_enable_callback(codec, | ||
6738 | spec->unsol_tag_front_hp, hp_callback); | ||
4457 | } | 6739 | } |
4458 | 6740 | ||
4459 | /* | 6741 | /* |
@@ -4476,7 +6758,8 @@ static struct hda_verb ca0132_base_exit_verbs[] = { | |||
4476 | {} | 6758 | {} |
4477 | }; | 6759 | }; |
4478 | 6760 | ||
4479 | /* Other verbs tables. Sends after DSP download. */ | 6761 | /* Other verbs tables. Sends after DSP download. */ |
6762 | |||
4480 | static struct hda_verb ca0132_init_verbs0[] = { | 6763 | static struct hda_verb ca0132_init_verbs0[] = { |
4481 | /* chip init verbs */ | 6764 | /* chip init verbs */ |
4482 | {0x15, 0x70D, 0xF0}, | 6765 | {0x15, 0x70D, 0xF0}, |
@@ -4506,8 +6789,27 @@ static struct hda_verb ca0132_init_verbs0[] = { | |||
4506 | {0x15, 0x546, 0xC9}, | 6789 | {0x15, 0x546, 0xC9}, |
4507 | {0x15, 0x53B, 0xCE}, | 6790 | {0x15, 0x53B, 0xCE}, |
4508 | {0x15, 0x5E8, 0xC9}, | 6791 | {0x15, 0x5E8, 0xC9}, |
4509 | {0x15, 0x717, 0x0D}, | 6792 | {} |
4510 | {0x15, 0x718, 0x20}, | 6793 | }; |
6794 | |||
6795 | /* Extra init verbs for SBZ */ | ||
6796 | static struct hda_verb sbz_init_verbs[] = { | ||
6797 | {0x15, 0x70D, 0x20}, | ||
6798 | {0x15, 0x70E, 0x19}, | ||
6799 | {0x15, 0x707, 0x00}, | ||
6800 | {0x15, 0x539, 0xCE}, | ||
6801 | {0x15, 0x546, 0xC9}, | ||
6802 | {0x15, 0x70D, 0xB7}, | ||
6803 | {0x15, 0x70E, 0x09}, | ||
6804 | {0x15, 0x707, 0x10}, | ||
6805 | {0x15, 0x70D, 0xAF}, | ||
6806 | {0x15, 0x70E, 0x09}, | ||
6807 | {0x15, 0x707, 0x01}, | ||
6808 | {0x15, 0x707, 0x05}, | ||
6809 | {0x15, 0x70D, 0x73}, | ||
6810 | {0x15, 0x70E, 0x09}, | ||
6811 | {0x15, 0x707, 0x14}, | ||
6812 | {0x15, 0x6FF, 0xC4}, | ||
4511 | {} | 6813 | {} |
4512 | }; | 6814 | }; |
4513 | 6815 | ||
@@ -4521,7 +6823,11 @@ static void ca0132_init_chip(struct hda_codec *codec) | |||
4521 | mutex_init(&spec->chipio_mutex); | 6823 | mutex_init(&spec->chipio_mutex); |
4522 | 6824 | ||
4523 | spec->cur_out_type = SPEAKER_OUT; | 6825 | spec->cur_out_type = SPEAKER_OUT; |
4524 | spec->cur_mic_type = DIGITAL_MIC; | 6826 | if (!spec->use_alt_functions) |
6827 | spec->cur_mic_type = DIGITAL_MIC; | ||
6828 | else | ||
6829 | spec->cur_mic_type = REAR_MIC; | ||
6830 | |||
4525 | spec->cur_mic_boost = 0; | 6831 | spec->cur_mic_boost = 0; |
4526 | 6832 | ||
4527 | for (i = 0; i < VNODES_COUNT; i++) { | 6833 | for (i = 0; i < VNODES_COUNT; i++) { |
@@ -4539,6 +6845,15 @@ static void ca0132_init_chip(struct hda_codec *codec) | |||
4539 | on = (unsigned int)ca0132_effects[i].reqs[0]; | 6845 | on = (unsigned int)ca0132_effects[i].reqs[0]; |
4540 | spec->effects_switch[i] = on ? 1 : 0; | 6846 | spec->effects_switch[i] = on ? 1 : 0; |
4541 | } | 6847 | } |
6848 | /* | ||
6849 | * Sets defaults for the effect slider controls, only for alternative | ||
6850 | * ca0132 codecs. Also sets x-bass crossover frequency to 80hz. | ||
6851 | */ | ||
6852 | if (spec->use_alt_controls) { | ||
6853 | spec->xbass_xover_freq = 8; | ||
6854 | for (i = 0; i < EFFECT_LEVEL_SLIDERS; i++) | ||
6855 | spec->fx_ctl_val[i] = effect_slider_defaults[i]; | ||
6856 | } | ||
4542 | 6857 | ||
4543 | spec->voicefx_val = 0; | 6858 | spec->voicefx_val = 0; |
4544 | spec->effects_switch[PLAY_ENHANCEMENT - EFFECT_START_NID] = 1; | 6859 | spec->effects_switch[PLAY_ENHANCEMENT - EFFECT_START_NID] = 1; |
@@ -4549,6 +6864,120 @@ static void ca0132_init_chip(struct hda_codec *codec) | |||
4549 | #endif | 6864 | #endif |
4550 | } | 6865 | } |
4551 | 6866 | ||
6867 | /* | ||
6868 | * Recon3Di exit specific commands. | ||
6869 | */ | ||
6870 | /* prevents popping noise on shutdown */ | ||
6871 | static void r3di_gpio_shutdown(struct hda_codec *codec) | ||
6872 | { | ||
6873 | snd_hda_codec_write(codec, 0x01, 0, AC_VERB_SET_GPIO_DATA, 0x00); | ||
6874 | } | ||
6875 | |||
6876 | /* | ||
6877 | * Sound Blaster Z exit specific commands. | ||
6878 | */ | ||
6879 | static void sbz_region2_exit(struct hda_codec *codec) | ||
6880 | { | ||
6881 | struct ca0132_spec *spec = codec->spec; | ||
6882 | unsigned int i; | ||
6883 | |||
6884 | for (i = 0; i < 4; i++) | ||
6885 | writeb(0x0, spec->mem_base + 0x100); | ||
6886 | for (i = 0; i < 8; i++) | ||
6887 | writeb(0xb3, spec->mem_base + 0x304); | ||
6888 | /* | ||
6889 | * I believe these are GPIO, with the right most hex digit being the | ||
6890 | * gpio pin, and the second digit being on or off. We see this more in | ||
6891 | * the input/output select functions. | ||
6892 | */ | ||
6893 | writew(0x0000, spec->mem_base + 0x320); | ||
6894 | writew(0x0001, spec->mem_base + 0x320); | ||
6895 | writew(0x0104, spec->mem_base + 0x320); | ||
6896 | writew(0x0005, spec->mem_base + 0x320); | ||
6897 | writew(0x0007, spec->mem_base + 0x320); | ||
6898 | } | ||
6899 | |||
6900 | static void sbz_set_pin_ctl_default(struct hda_codec *codec) | ||
6901 | { | ||
6902 | hda_nid_t pins[5] = {0x0B, 0x0C, 0x0E, 0x12, 0x13}; | ||
6903 | unsigned int i; | ||
6904 | |||
6905 | snd_hda_codec_write(codec, 0x11, 0, | ||
6906 | AC_VERB_SET_PIN_WIDGET_CONTROL, 0x40); | ||
6907 | |||
6908 | for (i = 0; i < 5; i++) | ||
6909 | snd_hda_codec_write(codec, pins[i], 0, | ||
6910 | AC_VERB_SET_PIN_WIDGET_CONTROL, 0x00); | ||
6911 | } | ||
6912 | |||
6913 | static void sbz_clear_unsolicited(struct hda_codec *codec) | ||
6914 | { | ||
6915 | hda_nid_t pins[7] = {0x0B, 0x0E, 0x0F, 0x10, 0x11, 0x12, 0x13}; | ||
6916 | unsigned int i; | ||
6917 | |||
6918 | for (i = 0; i < 7; i++) { | ||
6919 | snd_hda_codec_write(codec, pins[i], 0, | ||
6920 | AC_VERB_SET_UNSOLICITED_ENABLE, 0x00); | ||
6921 | } | ||
6922 | } | ||
6923 | |||
6924 | /* On shutdown, sends commands in sets of three */ | ||
6925 | static void sbz_gpio_shutdown_commands(struct hda_codec *codec, int dir, | ||
6926 | int mask, int data) | ||
6927 | { | ||
6928 | if (dir >= 0) | ||
6929 | snd_hda_codec_write(codec, 0x01, 0, | ||
6930 | AC_VERB_SET_GPIO_DIRECTION, dir); | ||
6931 | if (mask >= 0) | ||
6932 | snd_hda_codec_write(codec, 0x01, 0, | ||
6933 | AC_VERB_SET_GPIO_MASK, mask); | ||
6934 | |||
6935 | if (data >= 0) | ||
6936 | snd_hda_codec_write(codec, 0x01, 0, | ||
6937 | AC_VERB_SET_GPIO_DATA, data); | ||
6938 | } | ||
6939 | |||
6940 | static void sbz_exit_chip(struct hda_codec *codec) | ||
6941 | { | ||
6942 | chipio_set_stream_control(codec, 0x03, 0); | ||
6943 | chipio_set_stream_control(codec, 0x04, 0); | ||
6944 | |||
6945 | /* Mess with GPIO */ | ||
6946 | sbz_gpio_shutdown_commands(codec, 0x07, 0x07, -1); | ||
6947 | sbz_gpio_shutdown_commands(codec, 0x07, 0x07, 0x05); | ||
6948 | sbz_gpio_shutdown_commands(codec, 0x07, 0x07, 0x01); | ||
6949 | |||
6950 | chipio_set_stream_control(codec, 0x14, 0); | ||
6951 | chipio_set_stream_control(codec, 0x0C, 0); | ||
6952 | |||
6953 | chipio_set_conn_rate(codec, 0x41, SR_192_000); | ||
6954 | chipio_set_conn_rate(codec, 0x91, SR_192_000); | ||
6955 | |||
6956 | chipio_write(codec, 0x18a020, 0x00000083); | ||
6957 | |||
6958 | sbz_gpio_shutdown_commands(codec, 0x07, 0x07, 0x03); | ||
6959 | sbz_gpio_shutdown_commands(codec, 0x07, 0x07, 0x07); | ||
6960 | sbz_gpio_shutdown_commands(codec, 0x07, 0x07, 0x06); | ||
6961 | |||
6962 | chipio_set_stream_control(codec, 0x0C, 0); | ||
6963 | |||
6964 | chipio_set_control_param(codec, 0x0D, 0x24); | ||
6965 | |||
6966 | sbz_clear_unsolicited(codec); | ||
6967 | sbz_set_pin_ctl_default(codec); | ||
6968 | |||
6969 | snd_hda_codec_write(codec, 0x0B, 0, | ||
6970 | AC_VERB_SET_EAPD_BTLENABLE, 0x00); | ||
6971 | |||
6972 | if (dspload_is_loaded(codec)) | ||
6973 | dsp_reset(codec); | ||
6974 | |||
6975 | snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0, | ||
6976 | VENDOR_CHIPIO_CT_EXTENSIONS_ENABLE, 0x00); | ||
6977 | |||
6978 | sbz_region2_exit(codec); | ||
6979 | } | ||
6980 | |||
4552 | static void ca0132_exit_chip(struct hda_codec *codec) | 6981 | static void ca0132_exit_chip(struct hda_codec *codec) |
4553 | { | 6982 | { |
4554 | /* put any chip cleanup stuffs here. */ | 6983 | /* put any chip cleanup stuffs here. */ |
@@ -4557,28 +6986,264 @@ static void ca0132_exit_chip(struct hda_codec *codec) | |||
4557 | dsp_reset(codec); | 6986 | dsp_reset(codec); |
4558 | } | 6987 | } |
4559 | 6988 | ||
6989 | /* | ||
6990 | * This fixes a problem that was hard to reproduce. Very rarely, I would | ||
6991 | * boot up, and there would be no sound, but the DSP indicated it had loaded | ||
6992 | * properly. I did a few memory dumps to see if anything was different, and | ||
6993 | * there were a few areas of memory uninitialized with a1a2a3a4. This function | ||
6994 | * checks if those areas are uninitialized, and if they are, it'll attempt to | ||
6995 | * reload the card 3 times. Usually it fixes by the second. | ||
6996 | */ | ||
6997 | static void sbz_dsp_startup_check(struct hda_codec *codec) | ||
6998 | { | ||
6999 | struct ca0132_spec *spec = codec->spec; | ||
7000 | unsigned int dsp_data_check[4]; | ||
7001 | unsigned int cur_address = 0x390; | ||
7002 | unsigned int i; | ||
7003 | unsigned int failure = 0; | ||
7004 | unsigned int reload = 3; | ||
7005 | |||
7006 | if (spec->startup_check_entered) | ||
7007 | return; | ||
7008 | |||
7009 | spec->startup_check_entered = true; | ||
7010 | |||
7011 | for (i = 0; i < 4; i++) { | ||
7012 | chipio_read(codec, cur_address, &dsp_data_check[i]); | ||
7013 | cur_address += 0x4; | ||
7014 | } | ||
7015 | for (i = 0; i < 4; i++) { | ||
7016 | if (dsp_data_check[i] == 0xa1a2a3a4) | ||
7017 | failure = 1; | ||
7018 | } | ||
7019 | |||
7020 | codec_dbg(codec, "Startup Check: %d ", failure); | ||
7021 | if (failure) | ||
7022 | codec_info(codec, "DSP not initialized properly. Attempting to fix."); | ||
7023 | /* | ||
7024 | * While the failure condition is true, and we haven't reached our | ||
7025 | * three reload limit, continue trying to reload the driver and | ||
7026 | * fix the issue. | ||
7027 | */ | ||
7028 | while (failure && (reload != 0)) { | ||
7029 | codec_info(codec, "Reloading... Tries left: %d", reload); | ||
7030 | sbz_exit_chip(codec); | ||
7031 | spec->dsp_state = DSP_DOWNLOAD_INIT; | ||
7032 | codec->patch_ops.init(codec); | ||
7033 | failure = 0; | ||
7034 | for (i = 0; i < 4; i++) { | ||
7035 | chipio_read(codec, cur_address, &dsp_data_check[i]); | ||
7036 | cur_address += 0x4; | ||
7037 | } | ||
7038 | for (i = 0; i < 4; i++) { | ||
7039 | if (dsp_data_check[i] == 0xa1a2a3a4) | ||
7040 | failure = 1; | ||
7041 | } | ||
7042 | reload--; | ||
7043 | } | ||
7044 | |||
7045 | if (!failure && reload < 3) | ||
7046 | codec_info(codec, "DSP fixed."); | ||
7047 | |||
7048 | if (!failure) | ||
7049 | return; | ||
7050 | |||
7051 | codec_info(codec, "DSP failed to initialize properly. Either try a full shutdown or a suspend to clear the internal memory."); | ||
7052 | } | ||
7053 | |||
7054 | /* | ||
7055 | * This is for the extra volume verbs 0x797 (left) and 0x798 (right). These add | ||
7056 | * extra precision for decibel values. If you had the dB value in floating point | ||
7057 | * you would take the value after the decimal point, multiply by 64, and divide | ||
7058 | * by 2. So for 8.59, it's (59 * 64) / 100. Useful if someone wanted to | ||
7059 | * implement fixed point or floating point dB volumes. For now, I'll set them | ||
7060 | * to 0 just incase a value has lingered from a boot into Windows. | ||
7061 | */ | ||
7062 | static void ca0132_alt_vol_setup(struct hda_codec *codec) | ||
7063 | { | ||
7064 | snd_hda_codec_write(codec, 0x02, 0, 0x797, 0x00); | ||
7065 | snd_hda_codec_write(codec, 0x02, 0, 0x798, 0x00); | ||
7066 | snd_hda_codec_write(codec, 0x03, 0, 0x797, 0x00); | ||
7067 | snd_hda_codec_write(codec, 0x03, 0, 0x798, 0x00); | ||
7068 | snd_hda_codec_write(codec, 0x04, 0, 0x797, 0x00); | ||
7069 | snd_hda_codec_write(codec, 0x04, 0, 0x798, 0x00); | ||
7070 | snd_hda_codec_write(codec, 0x07, 0, 0x797, 0x00); | ||
7071 | snd_hda_codec_write(codec, 0x07, 0, 0x798, 0x00); | ||
7072 | } | ||
7073 | |||
7074 | /* | ||
7075 | * Extra commands that don't really fit anywhere else. | ||
7076 | */ | ||
7077 | static void sbz_pre_dsp_setup(struct hda_codec *codec) | ||
7078 | { | ||
7079 | struct ca0132_spec *spec = codec->spec; | ||
7080 | |||
7081 | writel(0x00820680, spec->mem_base + 0x01C); | ||
7082 | writel(0x00820680, spec->mem_base + 0x01C); | ||
7083 | |||
7084 | snd_hda_codec_write(codec, 0x15, 0, 0xd00, 0xfc); | ||
7085 | snd_hda_codec_write(codec, 0x15, 0, 0xd00, 0xfd); | ||
7086 | snd_hda_codec_write(codec, 0x15, 0, 0xd00, 0xfe); | ||
7087 | snd_hda_codec_write(codec, 0x15, 0, 0xd00, 0xff); | ||
7088 | |||
7089 | chipio_write(codec, 0x18b0a4, 0x000000c2); | ||
7090 | |||
7091 | snd_hda_codec_write(codec, 0x11, 0, | ||
7092 | AC_VERB_SET_PIN_WIDGET_CONTROL, 0x44); | ||
7093 | } | ||
7094 | |||
7095 | /* | ||
7096 | * Extra commands that don't really fit anywhere else. | ||
7097 | */ | ||
7098 | static void r3di_pre_dsp_setup(struct hda_codec *codec) | ||
7099 | { | ||
7100 | chipio_write(codec, 0x18b0a4, 0x000000c2); | ||
7101 | |||
7102 | snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0, | ||
7103 | VENDOR_CHIPIO_8051_ADDRESS_LOW, 0x1E); | ||
7104 | snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0, | ||
7105 | VENDOR_CHIPIO_8051_ADDRESS_HIGH, 0x1C); | ||
7106 | snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0, | ||
7107 | VENDOR_CHIPIO_8051_DATA_WRITE, 0x5B); | ||
7108 | |||
7109 | snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0, | ||
7110 | VENDOR_CHIPIO_8051_ADDRESS_LOW, 0x20); | ||
7111 | snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0, | ||
7112 | VENDOR_CHIPIO_8051_ADDRESS_HIGH, 0x19); | ||
7113 | snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0, | ||
7114 | VENDOR_CHIPIO_8051_DATA_WRITE, 0x00); | ||
7115 | snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0, | ||
7116 | VENDOR_CHIPIO_8051_DATA_WRITE, 0x40); | ||
7117 | |||
7118 | snd_hda_codec_write(codec, 0x11, 0, | ||
7119 | AC_VERB_SET_PIN_WIDGET_CONTROL, 0x04); | ||
7120 | } | ||
7121 | |||
7122 | |||
7123 | /* | ||
7124 | * These are sent before the DSP is downloaded. Not sure | ||
7125 | * what they do, or if they're necessary. Could possibly | ||
7126 | * be removed. Figure they're better to leave in. | ||
7127 | */ | ||
7128 | static void sbz_region2_startup(struct hda_codec *codec) | ||
7129 | { | ||
7130 | struct ca0132_spec *spec = codec->spec; | ||
7131 | |||
7132 | writel(0x00000000, spec->mem_base + 0x400); | ||
7133 | writel(0x00000000, spec->mem_base + 0x408); | ||
7134 | writel(0x00000000, spec->mem_base + 0x40C); | ||
7135 | writel(0x00880680, spec->mem_base + 0x01C); | ||
7136 | writel(0x00000083, spec->mem_base + 0xC0C); | ||
7137 | writel(0x00000030, spec->mem_base + 0xC00); | ||
7138 | writel(0x00000000, spec->mem_base + 0xC04); | ||
7139 | writel(0x00000003, spec->mem_base + 0xC0C); | ||
7140 | writel(0x00000003, spec->mem_base + 0xC0C); | ||
7141 | writel(0x00000003, spec->mem_base + 0xC0C); | ||
7142 | writel(0x00000003, spec->mem_base + 0xC0C); | ||
7143 | writel(0x000000C1, spec->mem_base + 0xC08); | ||
7144 | writel(0x000000F1, spec->mem_base + 0xC08); | ||
7145 | writel(0x00000001, spec->mem_base + 0xC08); | ||
7146 | writel(0x000000C7, spec->mem_base + 0xC08); | ||
7147 | writel(0x000000C1, spec->mem_base + 0xC08); | ||
7148 | writel(0x00000080, spec->mem_base + 0xC04); | ||
7149 | } | ||
7150 | |||
7151 | /* | ||
7152 | * Extra init functions for alternative ca0132 codecs. Done | ||
7153 | * here so they don't clutter up the main ca0132_init function | ||
7154 | * anymore than they have to. | ||
7155 | */ | ||
7156 | static void ca0132_alt_init(struct hda_codec *codec) | ||
7157 | { | ||
7158 | struct ca0132_spec *spec = codec->spec; | ||
7159 | |||
7160 | ca0132_alt_vol_setup(codec); | ||
7161 | |||
7162 | switch (spec->quirk) { | ||
7163 | case QUIRK_SBZ: | ||
7164 | codec_dbg(codec, "SBZ alt_init"); | ||
7165 | ca0132_gpio_init(codec); | ||
7166 | sbz_pre_dsp_setup(codec); | ||
7167 | snd_hda_sequence_write(codec, spec->chip_init_verbs); | ||
7168 | snd_hda_sequence_write(codec, spec->sbz_init_verbs); | ||
7169 | break; | ||
7170 | case QUIRK_R3DI: | ||
7171 | codec_dbg(codec, "R3DI alt_init"); | ||
7172 | ca0132_gpio_init(codec); | ||
7173 | ca0132_gpio_setup(codec); | ||
7174 | r3di_gpio_dsp_status_set(codec, R3DI_DSP_DOWNLOADING); | ||
7175 | r3di_pre_dsp_setup(codec); | ||
7176 | snd_hda_sequence_write(codec, spec->chip_init_verbs); | ||
7177 | snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0, 0x6FF, 0xC4); | ||
7178 | break; | ||
7179 | } | ||
7180 | } | ||
7181 | |||
4560 | static int ca0132_init(struct hda_codec *codec) | 7182 | static int ca0132_init(struct hda_codec *codec) |
4561 | { | 7183 | { |
4562 | struct ca0132_spec *spec = codec->spec; | 7184 | struct ca0132_spec *spec = codec->spec; |
4563 | struct auto_pin_cfg *cfg = &spec->autocfg; | 7185 | struct auto_pin_cfg *cfg = &spec->autocfg; |
4564 | int i; | 7186 | int i; |
7187 | bool dsp_loaded; | ||
7188 | |||
7189 | /* | ||
7190 | * If the DSP is already downloaded, and init has been entered again, | ||
7191 | * there's only two reasons for it. One, the codec has awaken from a | ||
7192 | * suspended state, and in that case dspload_is_loaded will return | ||
7193 | * false, and the init will be ran again. The other reason it gets | ||
7194 | * re entered is on startup for some reason it triggers a suspend and | ||
7195 | * resume state. In this case, it will check if the DSP is downloaded, | ||
7196 | * and not run the init function again. For codecs using alt_functions, | ||
7197 | * it will check if the DSP is loaded properly. | ||
7198 | */ | ||
7199 | if (spec->dsp_state == DSP_DOWNLOADED) { | ||
7200 | dsp_loaded = dspload_is_loaded(codec); | ||
7201 | if (!dsp_loaded) { | ||
7202 | spec->dsp_reload = true; | ||
7203 | spec->dsp_state = DSP_DOWNLOAD_INIT; | ||
7204 | } else { | ||
7205 | if (spec->quirk == QUIRK_SBZ) | ||
7206 | sbz_dsp_startup_check(codec); | ||
7207 | return 0; | ||
7208 | } | ||
7209 | } | ||
4565 | 7210 | ||
4566 | if (spec->dsp_state != DSP_DOWNLOAD_FAILED) | 7211 | if (spec->dsp_state != DSP_DOWNLOAD_FAILED) |
4567 | spec->dsp_state = DSP_DOWNLOAD_INIT; | 7212 | spec->dsp_state = DSP_DOWNLOAD_INIT; |
4568 | spec->curr_chip_addx = INVALID_CHIP_ADDRESS; | 7213 | spec->curr_chip_addx = INVALID_CHIP_ADDRESS; |
4569 | 7214 | ||
7215 | if (spec->quirk == QUIRK_SBZ) | ||
7216 | sbz_region2_startup(codec); | ||
7217 | |||
4570 | snd_hda_power_up_pm(codec); | 7218 | snd_hda_power_up_pm(codec); |
4571 | 7219 | ||
4572 | ca0132_init_unsol(codec); | 7220 | ca0132_init_unsol(codec); |
4573 | |||
4574 | ca0132_init_params(codec); | 7221 | ca0132_init_params(codec); |
4575 | ca0132_init_flags(codec); | 7222 | ca0132_init_flags(codec); |
7223 | |||
4576 | snd_hda_sequence_write(codec, spec->base_init_verbs); | 7224 | snd_hda_sequence_write(codec, spec->base_init_verbs); |
7225 | |||
7226 | if (spec->quirk != QUIRK_NONE) | ||
7227 | ca0132_alt_init(codec); | ||
7228 | |||
4577 | ca0132_download_dsp(codec); | 7229 | ca0132_download_dsp(codec); |
7230 | |||
4578 | ca0132_refresh_widget_caps(codec); | 7231 | ca0132_refresh_widget_caps(codec); |
4579 | ca0132_setup_defaults(codec); | 7232 | |
4580 | ca0132_init_analog_mic2(codec); | 7233 | if (spec->quirk == QUIRK_SBZ) |
4581 | ca0132_init_dmic(codec); | 7234 | writew(0x0107, spec->mem_base + 0x320); |
7235 | |||
7236 | switch (spec->quirk) { | ||
7237 | case QUIRK_R3DI: | ||
7238 | r3di_setup_defaults(codec); | ||
7239 | break; | ||
7240 | case QUIRK_NONE: | ||
7241 | case QUIRK_ALIENWARE: | ||
7242 | ca0132_setup_defaults(codec); | ||
7243 | ca0132_init_analog_mic2(codec); | ||
7244 | ca0132_init_dmic(codec); | ||
7245 | break; | ||
7246 | } | ||
4582 | 7247 | ||
4583 | for (i = 0; i < spec->num_outputs; i++) | 7248 | for (i = 0; i < spec->num_outputs; i++) |
4584 | init_output(codec, spec->out_pins[i], spec->dacs[0]); | 7249 | init_output(codec, spec->out_pins[i], spec->dacs[0]); |
@@ -4590,14 +7255,45 @@ static int ca0132_init(struct hda_codec *codec) | |||
4590 | 7255 | ||
4591 | init_input(codec, cfg->dig_in_pin, spec->dig_in); | 7256 | init_input(codec, cfg->dig_in_pin, spec->dig_in); |
4592 | 7257 | ||
4593 | snd_hda_sequence_write(codec, spec->chip_init_verbs); | 7258 | if (!spec->use_alt_functions) { |
4594 | snd_hda_sequence_write(codec, spec->spec_init_verbs); | 7259 | snd_hda_sequence_write(codec, spec->chip_init_verbs); |
7260 | snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0, | ||
7261 | VENDOR_CHIPIO_PARAM_EX_ID_SET, 0x0D); | ||
7262 | snd_hda_codec_write(codec, WIDGET_CHIP_CTRL, 0, | ||
7263 | VENDOR_CHIPIO_PARAM_EX_VALUE_SET, 0x20); | ||
7264 | } | ||
4595 | 7265 | ||
4596 | ca0132_select_out(codec); | 7266 | if (spec->quirk == QUIRK_SBZ) |
4597 | ca0132_select_mic(codec); | 7267 | ca0132_gpio_setup(codec); |
7268 | |||
7269 | snd_hda_sequence_write(codec, spec->spec_init_verbs); | ||
7270 | switch (spec->quirk) { | ||
7271 | case QUIRK_SBZ: | ||
7272 | sbz_setup_defaults(codec); | ||
7273 | ca0132_alt_select_out(codec); | ||
7274 | ca0132_alt_select_in(codec); | ||
7275 | break; | ||
7276 | case QUIRK_R3DI: | ||
7277 | ca0132_alt_select_out(codec); | ||
7278 | ca0132_alt_select_in(codec); | ||
7279 | break; | ||
7280 | default: | ||
7281 | ca0132_select_out(codec); | ||
7282 | ca0132_select_mic(codec); | ||
7283 | break; | ||
7284 | } | ||
4598 | 7285 | ||
4599 | snd_hda_jack_report_sync(codec); | 7286 | snd_hda_jack_report_sync(codec); |
4600 | 7287 | ||
7288 | /* | ||
7289 | * Re set the PlayEnhancement switch on a resume event, because the | ||
7290 | * controls will not be reloaded. | ||
7291 | */ | ||
7292 | if (spec->dsp_reload) { | ||
7293 | spec->dsp_reload = false; | ||
7294 | ca0132_pe_switch_set(codec); | ||
7295 | } | ||
7296 | |||
4601 | snd_hda_power_down_pm(codec); | 7297 | snd_hda_power_down_pm(codec); |
4602 | 7298 | ||
4603 | return 0; | 7299 | return 0; |
@@ -4609,19 +7305,39 @@ static void ca0132_free(struct hda_codec *codec) | |||
4609 | 7305 | ||
4610 | cancel_delayed_work_sync(&spec->unsol_hp_work); | 7306 | cancel_delayed_work_sync(&spec->unsol_hp_work); |
4611 | snd_hda_power_up(codec); | 7307 | snd_hda_power_up(codec); |
4612 | snd_hda_sequence_write(codec, spec->base_exit_verbs); | 7308 | switch (spec->quirk) { |
4613 | ca0132_exit_chip(codec); | 7309 | case QUIRK_SBZ: |
7310 | sbz_exit_chip(codec); | ||
7311 | break; | ||
7312 | case QUIRK_R3DI: | ||
7313 | r3di_gpio_shutdown(codec); | ||
7314 | snd_hda_sequence_write(codec, spec->base_exit_verbs); | ||
7315 | ca0132_exit_chip(codec); | ||
7316 | break; | ||
7317 | default: | ||
7318 | snd_hda_sequence_write(codec, spec->base_exit_verbs); | ||
7319 | ca0132_exit_chip(codec); | ||
7320 | break; | ||
7321 | } | ||
4614 | snd_hda_power_down(codec); | 7322 | snd_hda_power_down(codec); |
7323 | if (spec->mem_base) | ||
7324 | iounmap(spec->mem_base); | ||
4615 | kfree(spec->spec_init_verbs); | 7325 | kfree(spec->spec_init_verbs); |
4616 | kfree(codec->spec); | 7326 | kfree(codec->spec); |
4617 | } | 7327 | } |
4618 | 7328 | ||
7329 | static void ca0132_reboot_notify(struct hda_codec *codec) | ||
7330 | { | ||
7331 | codec->patch_ops.free(codec); | ||
7332 | } | ||
7333 | |||
4619 | static const struct hda_codec_ops ca0132_patch_ops = { | 7334 | static const struct hda_codec_ops ca0132_patch_ops = { |
4620 | .build_controls = ca0132_build_controls, | 7335 | .build_controls = ca0132_build_controls, |
4621 | .build_pcms = ca0132_build_pcms, | 7336 | .build_pcms = ca0132_build_pcms, |
4622 | .init = ca0132_init, | 7337 | .init = ca0132_init, |
4623 | .free = ca0132_free, | 7338 | .free = ca0132_free, |
4624 | .unsol_event = snd_hda_jack_unsol_event, | 7339 | .unsol_event = snd_hda_jack_unsol_event, |
7340 | .reboot_notify = ca0132_reboot_notify, | ||
4625 | }; | 7341 | }; |
4626 | 7342 | ||
4627 | static void ca0132_config(struct hda_codec *codec) | 7343 | static void ca0132_config(struct hda_codec *codec) |
@@ -4635,9 +7351,14 @@ static void ca0132_config(struct hda_codec *codec) | |||
4635 | 7351 | ||
4636 | spec->multiout.dac_nids = spec->dacs; | 7352 | spec->multiout.dac_nids = spec->dacs; |
4637 | spec->multiout.num_dacs = 3; | 7353 | spec->multiout.num_dacs = 3; |
4638 | spec->multiout.max_channels = 2; | ||
4639 | 7354 | ||
4640 | if (spec->quirk == QUIRK_ALIENWARE) { | 7355 | if (!spec->use_alt_functions) |
7356 | spec->multiout.max_channels = 2; | ||
7357 | else | ||
7358 | spec->multiout.max_channels = 6; | ||
7359 | |||
7360 | switch (spec->quirk) { | ||
7361 | case QUIRK_ALIENWARE: | ||
4641 | codec_dbg(codec, "ca0132_config: QUIRK_ALIENWARE applied.\n"); | 7362 | codec_dbg(codec, "ca0132_config: QUIRK_ALIENWARE applied.\n"); |
4642 | snd_hda_apply_pincfgs(codec, alienware_pincfgs); | 7363 | snd_hda_apply_pincfgs(codec, alienware_pincfgs); |
4643 | 7364 | ||
@@ -4657,7 +7378,71 @@ static void ca0132_config(struct hda_codec *codec) | |||
4657 | spec->input_pins[2] = 0x13; | 7378 | spec->input_pins[2] = 0x13; |
4658 | spec->shared_mic_nid = 0x7; | 7379 | spec->shared_mic_nid = 0x7; |
4659 | spec->unsol_tag_amic1 = 0x11; | 7380 | spec->unsol_tag_amic1 = 0x11; |
4660 | } else { | 7381 | break; |
7382 | case QUIRK_SBZ: | ||
7383 | codec_dbg(codec, "%s: QUIRK_SBZ applied.\n", __func__); | ||
7384 | snd_hda_apply_pincfgs(codec, sbz_pincfgs); | ||
7385 | |||
7386 | spec->num_outputs = 2; | ||
7387 | spec->out_pins[0] = 0x0B; /* Line out */ | ||
7388 | spec->out_pins[1] = 0x0F; /* Rear headphone out */ | ||
7389 | spec->out_pins[2] = 0x10; /* Front Headphone / Center/LFE*/ | ||
7390 | spec->out_pins[3] = 0x11; /* Rear surround */ | ||
7391 | spec->shared_out_nid = 0x2; | ||
7392 | spec->unsol_tag_hp = spec->out_pins[1]; | ||
7393 | spec->unsol_tag_front_hp = spec->out_pins[2]; | ||
7394 | |||
7395 | spec->adcs[0] = 0x7; /* Rear Mic / Line-in */ | ||
7396 | spec->adcs[1] = 0x8; /* Front Mic, but only if no DSP */ | ||
7397 | spec->adcs[2] = 0xa; /* what u hear */ | ||
7398 | |||
7399 | spec->num_inputs = 2; | ||
7400 | spec->input_pins[0] = 0x12; /* Rear Mic / Line-in */ | ||
7401 | spec->input_pins[1] = 0x13; /* What U Hear */ | ||
7402 | spec->shared_mic_nid = 0x7; | ||
7403 | spec->unsol_tag_amic1 = spec->input_pins[0]; | ||
7404 | |||
7405 | /* SPDIF I/O */ | ||
7406 | spec->dig_out = 0x05; | ||
7407 | spec->multiout.dig_out_nid = spec->dig_out; | ||
7408 | cfg->dig_out_pins[0] = 0x0c; | ||
7409 | cfg->dig_outs = 1; | ||
7410 | cfg->dig_out_type[0] = HDA_PCM_TYPE_SPDIF; | ||
7411 | spec->dig_in = 0x09; | ||
7412 | cfg->dig_in_pin = 0x0e; | ||
7413 | cfg->dig_in_type = HDA_PCM_TYPE_SPDIF; | ||
7414 | break; | ||
7415 | case QUIRK_R3DI: | ||
7416 | codec_dbg(codec, "%s: QUIRK_R3DI applied.\n", __func__); | ||
7417 | snd_hda_apply_pincfgs(codec, r3di_pincfgs); | ||
7418 | |||
7419 | spec->num_outputs = 2; | ||
7420 | spec->out_pins[0] = 0x0B; /* Line out */ | ||
7421 | spec->out_pins[1] = 0x0F; /* Rear headphone out */ | ||
7422 | spec->out_pins[2] = 0x10; /* Front Headphone / Center/LFE*/ | ||
7423 | spec->out_pins[3] = 0x11; /* Rear surround */ | ||
7424 | spec->shared_out_nid = 0x2; | ||
7425 | spec->unsol_tag_hp = spec->out_pins[1]; | ||
7426 | spec->unsol_tag_front_hp = spec->out_pins[2]; | ||
7427 | |||
7428 | spec->adcs[0] = 0x07; /* Rear Mic / Line-in */ | ||
7429 | spec->adcs[1] = 0x08; /* Front Mic, but only if no DSP */ | ||
7430 | spec->adcs[2] = 0x0a; /* what u hear */ | ||
7431 | |||
7432 | spec->num_inputs = 2; | ||
7433 | spec->input_pins[0] = 0x12; /* Rear Mic / Line-in */ | ||
7434 | spec->input_pins[1] = 0x13; /* What U Hear */ | ||
7435 | spec->shared_mic_nid = 0x7; | ||
7436 | spec->unsol_tag_amic1 = spec->input_pins[0]; | ||
7437 | |||
7438 | /* SPDIF I/O */ | ||
7439 | spec->dig_out = 0x05; | ||
7440 | spec->multiout.dig_out_nid = spec->dig_out; | ||
7441 | cfg->dig_out_pins[0] = 0x0c; | ||
7442 | cfg->dig_outs = 1; | ||
7443 | cfg->dig_out_type[0] = HDA_PCM_TYPE_SPDIF; | ||
7444 | break; | ||
7445 | default: | ||
4661 | spec->num_outputs = 2; | 7446 | spec->num_outputs = 2; |
4662 | spec->out_pins[0] = 0x0b; /* speaker out */ | 7447 | spec->out_pins[0] = 0x0b; /* speaker out */ |
4663 | spec->out_pins[1] = 0x10; /* headphone out */ | 7448 | spec->out_pins[1] = 0x10; /* headphone out */ |
@@ -4684,6 +7469,7 @@ static void ca0132_config(struct hda_codec *codec) | |||
4684 | spec->dig_in = 0x09; | 7469 | spec->dig_in = 0x09; |
4685 | cfg->dig_in_pin = 0x0e; | 7470 | cfg->dig_in_pin = 0x0e; |
4686 | cfg->dig_in_type = HDA_PCM_TYPE_SPDIF; | 7471 | cfg->dig_in_type = HDA_PCM_TYPE_SPDIF; |
7472 | break; | ||
4687 | } | 7473 | } |
4688 | } | 7474 | } |
4689 | 7475 | ||
@@ -4694,6 +7480,8 @@ static int ca0132_prepare_verbs(struct hda_codec *codec) | |||
4694 | struct ca0132_spec *spec = codec->spec; | 7480 | struct ca0132_spec *spec = codec->spec; |
4695 | 7481 | ||
4696 | spec->chip_init_verbs = ca0132_init_verbs0; | 7482 | spec->chip_init_verbs = ca0132_init_verbs0; |
7483 | if (spec->quirk == QUIRK_SBZ) | ||
7484 | spec->sbz_init_verbs = sbz_init_verbs; | ||
4697 | spec->spec_init_verbs = kzalloc(sizeof(struct hda_verb) * NUM_SPEC_VERBS, GFP_KERNEL); | 7485 | spec->spec_init_verbs = kzalloc(sizeof(struct hda_verb) * NUM_SPEC_VERBS, GFP_KERNEL); |
4698 | if (!spec->spec_init_verbs) | 7486 | if (!spec->spec_init_verbs) |
4699 | return -ENOMEM; | 7487 | return -ENOMEM; |
@@ -4757,9 +7545,46 @@ static int patch_ca0132(struct hda_codec *codec) | |||
4757 | else | 7545 | else |
4758 | spec->quirk = QUIRK_NONE; | 7546 | spec->quirk = QUIRK_NONE; |
4759 | 7547 | ||
7548 | /* Setup BAR Region 2 for Sound Blaster Z */ | ||
7549 | if (spec->quirk == QUIRK_SBZ) { | ||
7550 | spec->mem_base = pci_iomap(codec->bus->pci, 2, 0xC20); | ||
7551 | if (spec->mem_base == NULL) { | ||
7552 | codec_warn(codec, "pci_iomap failed!"); | ||
7553 | codec_info(codec, "perhaps this is not an SBZ?"); | ||
7554 | spec->quirk = QUIRK_NONE; | ||
7555 | } | ||
7556 | } | ||
7557 | |||
4760 | spec->dsp_state = DSP_DOWNLOAD_INIT; | 7558 | spec->dsp_state = DSP_DOWNLOAD_INIT; |
4761 | spec->num_mixers = 1; | 7559 | spec->num_mixers = 1; |
4762 | spec->mixers[0] = ca0132_mixer; | 7560 | |
7561 | /* Set which mixers each quirk uses. */ | ||
7562 | switch (spec->quirk) { | ||
7563 | case QUIRK_SBZ: | ||
7564 | spec->mixers[0] = sbz_mixer; | ||
7565 | snd_hda_codec_set_name(codec, "Sound Blaster Z"); | ||
7566 | break; | ||
7567 | case QUIRK_R3DI: | ||
7568 | spec->mixers[0] = r3di_mixer; | ||
7569 | snd_hda_codec_set_name(codec, "Recon3Di"); | ||
7570 | break; | ||
7571 | default: | ||
7572 | spec->mixers[0] = ca0132_mixer; | ||
7573 | break; | ||
7574 | } | ||
7575 | |||
7576 | /* Setup whether or not to use alt functions/controls */ | ||
7577 | switch (spec->quirk) { | ||
7578 | case QUIRK_SBZ: | ||
7579 | case QUIRK_R3DI: | ||
7580 | spec->use_alt_controls = true; | ||
7581 | spec->use_alt_functions = true; | ||
7582 | break; | ||
7583 | default: | ||
7584 | spec->use_alt_controls = false; | ||
7585 | spec->use_alt_functions = false; | ||
7586 | break; | ||
7587 | } | ||
4763 | 7588 | ||
4764 | spec->base_init_verbs = ca0132_base_init_verbs; | 7589 | spec->base_init_verbs = ca0132_base_init_verbs; |
4765 | spec->base_exit_verbs = ca0132_base_exit_verbs; | 7590 | spec->base_exit_verbs = ca0132_base_exit_verbs; |
diff --git a/sound/pci/hda/patch_conexant.c b/sound/pci/hda/patch_conexant.c index 5b4dbcec6de8..dbf9910c5269 100644 --- a/sound/pci/hda/patch_conexant.c +++ b/sound/pci/hda/patch_conexant.c | |||
@@ -588,6 +588,7 @@ static void cxt_fixup_olpc_xo(struct hda_codec *codec, | |||
588 | const struct hda_fixup *fix, int action) | 588 | const struct hda_fixup *fix, int action) |
589 | { | 589 | { |
590 | struct conexant_spec *spec = codec->spec; | 590 | struct conexant_spec *spec = codec->spec; |
591 | struct snd_kcontrol_new *kctl; | ||
591 | int i; | 592 | int i; |
592 | 593 | ||
593 | if (action != HDA_FIXUP_ACT_PROBE) | 594 | if (action != HDA_FIXUP_ACT_PROBE) |
@@ -606,9 +607,7 @@ static void cxt_fixup_olpc_xo(struct hda_codec *codec, | |||
606 | snd_hda_codec_set_pin_target(codec, 0x1a, PIN_VREF50); | 607 | snd_hda_codec_set_pin_target(codec, 0x1a, PIN_VREF50); |
607 | 608 | ||
608 | /* override mic boost control */ | 609 | /* override mic boost control */ |
609 | for (i = 0; i < spec->gen.kctls.used; i++) { | 610 | snd_array_for_each(&spec->gen.kctls, i, kctl) { |
610 | struct snd_kcontrol_new *kctl = | ||
611 | snd_array_elem(&spec->gen.kctls, i); | ||
612 | if (!strcmp(kctl->name, "Mic Boost Volume")) { | 611 | if (!strcmp(kctl->name, "Mic Boost Volume")) { |
613 | kctl->put = olpc_xo_mic_boost_put; | 612 | kctl->put = olpc_xo_mic_boost_put; |
614 | break; | 613 | break; |
@@ -965,6 +964,7 @@ static const struct snd_pci_quirk cxt5066_fixups[] = { | |||
965 | SND_PCI_QUIRK(0x103c, 0x822e, "HP ProBook 440 G4", CXT_FIXUP_MUTE_LED_GPIO), | 964 | SND_PCI_QUIRK(0x103c, 0x822e, "HP ProBook 440 G4", CXT_FIXUP_MUTE_LED_GPIO), |
966 | SND_PCI_QUIRK(0x103c, 0x8299, "HP 800 G3 SFF", CXT_FIXUP_HP_MIC_NO_PRESENCE), | 965 | SND_PCI_QUIRK(0x103c, 0x8299, "HP 800 G3 SFF", CXT_FIXUP_HP_MIC_NO_PRESENCE), |
967 | SND_PCI_QUIRK(0x103c, 0x829a, "HP 800 G3 DM", CXT_FIXUP_HP_MIC_NO_PRESENCE), | 966 | SND_PCI_QUIRK(0x103c, 0x829a, "HP 800 G3 DM", CXT_FIXUP_HP_MIC_NO_PRESENCE), |
967 | SND_PCI_QUIRK(0x103c, 0x8455, "HP Z2 G4", CXT_FIXUP_HP_MIC_NO_PRESENCE), | ||
968 | SND_PCI_QUIRK(0x1043, 0x138d, "Asus", CXT_FIXUP_HEADPHONE_MIC_PIN), | 968 | SND_PCI_QUIRK(0x1043, 0x138d, "Asus", CXT_FIXUP_HEADPHONE_MIC_PIN), |
969 | SND_PCI_QUIRK(0x152d, 0x0833, "OLPC XO-1.5", CXT_FIXUP_OLPC_XO), | 969 | SND_PCI_QUIRK(0x152d, 0x0833, "OLPC XO-1.5", CXT_FIXUP_OLPC_XO), |
970 | SND_PCI_QUIRK(0x17aa, 0x20f2, "Lenovo T400", CXT_PINCFG_LENOVO_TP410), | 970 | SND_PCI_QUIRK(0x17aa, 0x20f2, "Lenovo T400", CXT_PINCFG_LENOVO_TP410), |
@@ -998,6 +998,7 @@ static const struct hda_model_fixup cxt5066_fixup_models[] = { | |||
998 | { .id = CXT_FIXUP_MUTE_LED_EAPD, .name = "mute-led-eapd" }, | 998 | { .id = CXT_FIXUP_MUTE_LED_EAPD, .name = "mute-led-eapd" }, |
999 | { .id = CXT_FIXUP_HP_DOCK, .name = "hp-dock" }, | 999 | { .id = CXT_FIXUP_HP_DOCK, .name = "hp-dock" }, |
1000 | { .id = CXT_FIXUP_MUTE_LED_GPIO, .name = "mute-led-gpio" }, | 1000 | { .id = CXT_FIXUP_MUTE_LED_GPIO, .name = "mute-led-gpio" }, |
1001 | { .id = CXT_FIXUP_HP_MIC_NO_PRESENCE, .name = "hp-mic-fix" }, | ||
1001 | {} | 1002 | {} |
1002 | }; | 1003 | }; |
1003 | 1004 | ||
diff --git a/sound/pci/hda/patch_hdmi.c b/sound/pci/hda/patch_hdmi.c index 7d7eb1354eee..8840daf9c6a3 100644 --- a/sound/pci/hda/patch_hdmi.c +++ b/sound/pci/hda/patch_hdmi.c | |||
@@ -510,7 +510,7 @@ static int eld_proc_new(struct hdmi_spec_per_pin *per_pin, int index) | |||
510 | 510 | ||
511 | snd_info_set_text_ops(entry, per_pin, print_eld_info); | 511 | snd_info_set_text_ops(entry, per_pin, print_eld_info); |
512 | entry->c.text.write = write_eld_info; | 512 | entry->c.text.write = write_eld_info; |
513 | entry->mode |= S_IWUSR; | 513 | entry->mode |= 0200; |
514 | per_pin->proc_entry = entry; | 514 | per_pin->proc_entry = entry; |
515 | 515 | ||
516 | return 0; | 516 | return 0; |
diff --git a/sound/pci/hda/patch_realtek.c b/sound/pci/hda/patch_realtek.c index 01a6643fc7d4..d64dcb9a4c99 100644 --- a/sound/pci/hda/patch_realtek.c +++ b/sound/pci/hda/patch_realtek.c | |||
@@ -2830,6 +2830,7 @@ static int find_ext_mic_pin(struct hda_codec *codec); | |||
2830 | 2830 | ||
2831 | static void alc286_shutup(struct hda_codec *codec) | 2831 | static void alc286_shutup(struct hda_codec *codec) |
2832 | { | 2832 | { |
2833 | const struct hda_pincfg *pin; | ||
2833 | int i; | 2834 | int i; |
2834 | int mic_pin = find_ext_mic_pin(codec); | 2835 | int mic_pin = find_ext_mic_pin(codec); |
2835 | /* don't shut up pins when unloading the driver; otherwise it breaks | 2836 | /* don't shut up pins when unloading the driver; otherwise it breaks |
@@ -2837,8 +2838,7 @@ static void alc286_shutup(struct hda_codec *codec) | |||
2837 | */ | 2838 | */ |
2838 | if (codec->bus->shutdown) | 2839 | if (codec->bus->shutdown) |
2839 | return; | 2840 | return; |
2840 | for (i = 0; i < codec->init_pins.used; i++) { | 2841 | snd_array_for_each(&codec->init_pins, i, pin) { |
2841 | struct hda_pincfg *pin = snd_array_elem(&codec->init_pins, i); | ||
2842 | /* use read here for syncing after issuing each verb */ | 2842 | /* use read here for syncing after issuing each verb */ |
2843 | if (pin->nid != mic_pin) | 2843 | if (pin->nid != mic_pin) |
2844 | snd_hda_codec_read(codec, pin->nid, 0, | 2844 | snd_hda_codec_read(codec, pin->nid, 0, |
@@ -3653,30 +3653,37 @@ static void alc269_fixup_hp_mute_led(struct hda_codec *codec, | |||
3653 | } | 3653 | } |
3654 | } | 3654 | } |
3655 | 3655 | ||
3656 | static void alc269_fixup_hp_mute_led_mic1(struct hda_codec *codec, | 3656 | static void alc269_fixup_hp_mute_led_micx(struct hda_codec *codec, |
3657 | const struct hda_fixup *fix, int action) | 3657 | const struct hda_fixup *fix, |
3658 | int action, hda_nid_t pin) | ||
3658 | { | 3659 | { |
3659 | struct alc_spec *spec = codec->spec; | 3660 | struct alc_spec *spec = codec->spec; |
3661 | |||
3660 | if (action == HDA_FIXUP_ACT_PRE_PROBE) { | 3662 | if (action == HDA_FIXUP_ACT_PRE_PROBE) { |
3661 | spec->mute_led_polarity = 0; | 3663 | spec->mute_led_polarity = 0; |
3662 | spec->mute_led_nid = 0x18; | 3664 | spec->mute_led_nid = pin; |
3663 | spec->gen.vmaster_mute.hook = alc269_fixup_mic_mute_hook; | 3665 | spec->gen.vmaster_mute.hook = alc269_fixup_mic_mute_hook; |
3664 | spec->gen.vmaster_mute_enum = 1; | 3666 | spec->gen.vmaster_mute_enum = 1; |
3665 | codec->power_filter = led_power_filter; | 3667 | codec->power_filter = led_power_filter; |
3666 | } | 3668 | } |
3667 | } | 3669 | } |
3668 | 3670 | ||
3671 | static void alc269_fixup_hp_mute_led_mic1(struct hda_codec *codec, | ||
3672 | const struct hda_fixup *fix, int action) | ||
3673 | { | ||
3674 | alc269_fixup_hp_mute_led_micx(codec, fix, action, 0x18); | ||
3675 | } | ||
3676 | |||
3669 | static void alc269_fixup_hp_mute_led_mic2(struct hda_codec *codec, | 3677 | static void alc269_fixup_hp_mute_led_mic2(struct hda_codec *codec, |
3670 | const struct hda_fixup *fix, int action) | 3678 | const struct hda_fixup *fix, int action) |
3671 | { | 3679 | { |
3672 | struct alc_spec *spec = codec->spec; | 3680 | alc269_fixup_hp_mute_led_micx(codec, fix, action, 0x19); |
3673 | if (action == HDA_FIXUP_ACT_PRE_PROBE) { | 3681 | } |
3674 | spec->mute_led_polarity = 0; | 3682 | |
3675 | spec->mute_led_nid = 0x19; | 3683 | static void alc269_fixup_hp_mute_led_mic3(struct hda_codec *codec, |
3676 | spec->gen.vmaster_mute.hook = alc269_fixup_mic_mute_hook; | 3684 | const struct hda_fixup *fix, int action) |
3677 | spec->gen.vmaster_mute_enum = 1; | 3685 | { |
3678 | codec->power_filter = led_power_filter; | 3686 | alc269_fixup_hp_mute_led_micx(codec, fix, action, 0x1b); |
3679 | } | ||
3680 | } | 3687 | } |
3681 | 3688 | ||
3682 | /* update LED status via GPIO */ | 3689 | /* update LED status via GPIO */ |
@@ -5387,6 +5394,9 @@ static void alc274_fixup_bind_dacs(struct hda_codec *codec, | |||
5387 | /* for dell wmi mic mute led */ | 5394 | /* for dell wmi mic mute led */ |
5388 | #include "dell_wmi_helper.c" | 5395 | #include "dell_wmi_helper.c" |
5389 | 5396 | ||
5397 | /* for alc295_fixup_hp_top_speakers */ | ||
5398 | #include "hp_x360_helper.c" | ||
5399 | |||
5390 | enum { | 5400 | enum { |
5391 | ALC269_FIXUP_SONY_VAIO, | 5401 | ALC269_FIXUP_SONY_VAIO, |
5392 | ALC275_FIXUP_SONY_VAIO_GPIO2, | 5402 | ALC275_FIXUP_SONY_VAIO_GPIO2, |
@@ -5413,6 +5423,7 @@ enum { | |||
5413 | ALC269_FIXUP_HP_MUTE_LED, | 5423 | ALC269_FIXUP_HP_MUTE_LED, |
5414 | ALC269_FIXUP_HP_MUTE_LED_MIC1, | 5424 | ALC269_FIXUP_HP_MUTE_LED_MIC1, |
5415 | ALC269_FIXUP_HP_MUTE_LED_MIC2, | 5425 | ALC269_FIXUP_HP_MUTE_LED_MIC2, |
5426 | ALC269_FIXUP_HP_MUTE_LED_MIC3, | ||
5416 | ALC269_FIXUP_HP_GPIO_LED, | 5427 | ALC269_FIXUP_HP_GPIO_LED, |
5417 | ALC269_FIXUP_HP_GPIO_MIC1_LED, | 5428 | ALC269_FIXUP_HP_GPIO_MIC1_LED, |
5418 | ALC269_FIXUP_HP_LINE1_MIC1_LED, | 5429 | ALC269_FIXUP_HP_LINE1_MIC1_LED, |
@@ -5506,6 +5517,7 @@ enum { | |||
5506 | ALC298_FIXUP_TPT470_DOCK, | 5517 | ALC298_FIXUP_TPT470_DOCK, |
5507 | ALC255_FIXUP_DUMMY_LINEOUT_VERB, | 5518 | ALC255_FIXUP_DUMMY_LINEOUT_VERB, |
5508 | ALC255_FIXUP_DELL_HEADSET_MIC, | 5519 | ALC255_FIXUP_DELL_HEADSET_MIC, |
5520 | ALC295_FIXUP_HP_X360, | ||
5509 | }; | 5521 | }; |
5510 | 5522 | ||
5511 | static const struct hda_fixup alc269_fixups[] = { | 5523 | static const struct hda_fixup alc269_fixups[] = { |
@@ -5672,6 +5684,10 @@ static const struct hda_fixup alc269_fixups[] = { | |||
5672 | .type = HDA_FIXUP_FUNC, | 5684 | .type = HDA_FIXUP_FUNC, |
5673 | .v.func = alc269_fixup_hp_mute_led_mic2, | 5685 | .v.func = alc269_fixup_hp_mute_led_mic2, |
5674 | }, | 5686 | }, |
5687 | [ALC269_FIXUP_HP_MUTE_LED_MIC3] = { | ||
5688 | .type = HDA_FIXUP_FUNC, | ||
5689 | .v.func = alc269_fixup_hp_mute_led_mic3, | ||
5690 | }, | ||
5675 | [ALC269_FIXUP_HP_GPIO_LED] = { | 5691 | [ALC269_FIXUP_HP_GPIO_LED] = { |
5676 | .type = HDA_FIXUP_FUNC, | 5692 | .type = HDA_FIXUP_FUNC, |
5677 | .v.func = alc269_fixup_hp_gpio_led, | 5693 | .v.func = alc269_fixup_hp_gpio_led, |
@@ -6375,6 +6391,12 @@ static const struct hda_fixup alc269_fixups[] = { | |||
6375 | .chained = true, | 6391 | .chained = true, |
6376 | .chain_id = ALC269_FIXUP_HEADSET_MIC | 6392 | .chain_id = ALC269_FIXUP_HEADSET_MIC |
6377 | }, | 6393 | }, |
6394 | [ALC295_FIXUP_HP_X360] = { | ||
6395 | .type = HDA_FIXUP_FUNC, | ||
6396 | .v.func = alc295_fixup_hp_top_speakers, | ||
6397 | .chained = true, | ||
6398 | .chain_id = ALC269_FIXUP_HP_MUTE_LED_MIC3 | ||
6399 | } | ||
6378 | }; | 6400 | }; |
6379 | 6401 | ||
6380 | static const struct snd_pci_quirk alc269_fixup_tbl[] = { | 6402 | static const struct snd_pci_quirk alc269_fixup_tbl[] = { |
@@ -6494,6 +6516,7 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { | |||
6494 | SND_PCI_QUIRK(0x103c, 0x2337, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), | 6516 | SND_PCI_QUIRK(0x103c, 0x2337, "HP", ALC269_FIXUP_HP_MUTE_LED_MIC1), |
6495 | SND_PCI_QUIRK(0x103c, 0x221c, "HP EliteBook 755 G2", ALC280_FIXUP_HP_HEADSET_MIC), | 6517 | SND_PCI_QUIRK(0x103c, 0x221c, "HP EliteBook 755 G2", ALC280_FIXUP_HP_HEADSET_MIC), |
6496 | SND_PCI_QUIRK(0x103c, 0x8256, "HP", ALC221_FIXUP_HP_FRONT_MIC), | 6518 | SND_PCI_QUIRK(0x103c, 0x8256, "HP", ALC221_FIXUP_HP_FRONT_MIC), |
6519 | SND_PCI_QUIRK(0x103c, 0x827e, "HP x360", ALC295_FIXUP_HP_X360), | ||
6497 | SND_PCI_QUIRK(0x103c, 0x82bf, "HP", ALC221_FIXUP_HP_MIC_NO_PRESENCE), | 6520 | SND_PCI_QUIRK(0x103c, 0x82bf, "HP", ALC221_FIXUP_HP_MIC_NO_PRESENCE), |
6498 | SND_PCI_QUIRK(0x103c, 0x82c0, "HP", ALC221_FIXUP_HP_MIC_NO_PRESENCE), | 6521 | SND_PCI_QUIRK(0x103c, 0x82c0, "HP", ALC221_FIXUP_HP_MIC_NO_PRESENCE), |
6499 | SND_PCI_QUIRK(0x1043, 0x103e, "ASUS X540SA", ALC256_FIXUP_ASUS_MIC), | 6522 | SND_PCI_QUIRK(0x1043, 0x103e, "ASUS X540SA", ALC256_FIXUP_ASUS_MIC), |
@@ -6580,7 +6603,6 @@ static const struct snd_pci_quirk alc269_fixup_tbl[] = { | |||
6580 | SND_PCI_QUIRK(0x17aa, 0x312f, "ThinkCentre Station", ALC294_FIXUP_LENOVO_MIC_LOCATION), | 6603 | SND_PCI_QUIRK(0x17aa, 0x312f, "ThinkCentre Station", ALC294_FIXUP_LENOVO_MIC_LOCATION), |
6581 | SND_PCI_QUIRK(0x17aa, 0x3138, "ThinkCentre Station", ALC294_FIXUP_LENOVO_MIC_LOCATION), | 6604 | SND_PCI_QUIRK(0x17aa, 0x3138, "ThinkCentre Station", ALC294_FIXUP_LENOVO_MIC_LOCATION), |
6582 | SND_PCI_QUIRK(0x17aa, 0x313c, "ThinkCentre Station", ALC294_FIXUP_LENOVO_MIC_LOCATION), | 6605 | SND_PCI_QUIRK(0x17aa, 0x313c, "ThinkCentre Station", ALC294_FIXUP_LENOVO_MIC_LOCATION), |
6583 | SND_PCI_QUIRK(0x17aa, 0x3112, "ThinkCentre AIO", ALC233_FIXUP_LENOVO_LINE2_MIC_HOTKEY), | ||
6584 | SND_PCI_QUIRK(0x17aa, 0x3902, "Lenovo E50-80", ALC269_FIXUP_DMIC_THINKPAD_ACPI), | 6606 | SND_PCI_QUIRK(0x17aa, 0x3902, "Lenovo E50-80", ALC269_FIXUP_DMIC_THINKPAD_ACPI), |
6585 | SND_PCI_QUIRK(0x17aa, 0x3977, "IdeaPad S210", ALC283_FIXUP_INT_MIC), | 6607 | SND_PCI_QUIRK(0x17aa, 0x3977, "IdeaPad S210", ALC283_FIXUP_INT_MIC), |
6586 | SND_PCI_QUIRK(0x17aa, 0x3978, "IdeaPad Y410P", ALC269_FIXUP_NO_SHUTUP), | 6608 | SND_PCI_QUIRK(0x17aa, 0x3978, "IdeaPad Y410P", ALC269_FIXUP_NO_SHUTUP), |
@@ -6752,6 +6774,11 @@ static const struct snd_hda_pin_quirk alc269_pin_fixup_tbl[] = { | |||
6752 | {0x1b, 0x01111010}, | 6774 | {0x1b, 0x01111010}, |
6753 | {0x1e, 0x01451130}, | 6775 | {0x1e, 0x01451130}, |
6754 | {0x21, 0x02211020}), | 6776 | {0x21, 0x02211020}), |
6777 | SND_HDA_PIN_QUIRK(0x10ec0235, 0x17aa, "Lenovo", ALC233_FIXUP_LENOVO_LINE2_MIC_HOTKEY, | ||
6778 | {0x12, 0x90a60140}, | ||
6779 | {0x14, 0x90170110}, | ||
6780 | {0x19, 0x02a11030}, | ||
6781 | {0x21, 0x02211020}), | ||
6755 | SND_HDA_PIN_QUIRK(0x10ec0236, 0x1028, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE, | 6782 | SND_HDA_PIN_QUIRK(0x10ec0236, 0x1028, "Dell", ALC255_FIXUP_DELL1_MIC_NO_PRESENCE, |
6756 | {0x12, 0x90a60140}, | 6783 | {0x12, 0x90a60140}, |
6757 | {0x14, 0x90170110}, | 6784 | {0x14, 0x90170110}, |
diff --git a/sound/pci/ice1712/pontis.c b/sound/pci/ice1712/pontis.c index 5101f40f6fbd..93b8cfc6636f 100644 --- a/sound/pci/ice1712/pontis.c +++ b/sound/pci/ice1712/pontis.c | |||
@@ -662,7 +662,7 @@ static void wm_proc_init(struct snd_ice1712 *ice) | |||
662 | struct snd_info_entry *entry; | 662 | struct snd_info_entry *entry; |
663 | if (! snd_card_proc_new(ice->card, "wm_codec", &entry)) { | 663 | if (! snd_card_proc_new(ice->card, "wm_codec", &entry)) { |
664 | snd_info_set_text_ops(entry, ice, wm_proc_regs_read); | 664 | snd_info_set_text_ops(entry, ice, wm_proc_regs_read); |
665 | entry->mode |= S_IWUSR; | 665 | entry->mode |= 0200; |
666 | entry->c.text.write = wm_proc_regs_write; | 666 | entry->c.text.write = wm_proc_regs_write; |
667 | } | 667 | } |
668 | } | 668 | } |
diff --git a/sound/pci/ice1712/prodigy_hifi.c b/sound/pci/ice1712/prodigy_hifi.c index 8dabd4d0211d..d7366ade5a25 100644 --- a/sound/pci/ice1712/prodigy_hifi.c +++ b/sound/pci/ice1712/prodigy_hifi.c | |||
@@ -926,7 +926,7 @@ static void wm_proc_init(struct snd_ice1712 *ice) | |||
926 | struct snd_info_entry *entry; | 926 | struct snd_info_entry *entry; |
927 | if (!snd_card_proc_new(ice->card, "wm_codec", &entry)) { | 927 | if (!snd_card_proc_new(ice->card, "wm_codec", &entry)) { |
928 | snd_info_set_text_ops(entry, ice, wm_proc_regs_read); | 928 | snd_info_set_text_ops(entry, ice, wm_proc_regs_read); |
929 | entry->mode |= S_IWUSR; | 929 | entry->mode |= 0200; |
930 | entry->c.text.write = wm_proc_regs_write; | 930 | entry->c.text.write = wm_proc_regs_write; |
931 | } | 931 | } |
932 | } | 932 | } |
diff --git a/sound/pci/lola/lola_proc.c b/sound/pci/lola/lola_proc.c index c241dc06dd92..904e3c4f4dfe 100644 --- a/sound/pci/lola/lola_proc.c +++ b/sound/pci/lola/lola_proc.c | |||
@@ -214,7 +214,7 @@ void lola_proc_debug_new(struct lola *chip) | |||
214 | snd_info_set_text_ops(entry, chip, lola_proc_codec_read); | 214 | snd_info_set_text_ops(entry, chip, lola_proc_codec_read); |
215 | if (!snd_card_proc_new(chip->card, "codec_rw", &entry)) { | 215 | if (!snd_card_proc_new(chip->card, "codec_rw", &entry)) { |
216 | snd_info_set_text_ops(entry, chip, lola_proc_codec_rw_read); | 216 | snd_info_set_text_ops(entry, chip, lola_proc_codec_rw_read); |
217 | entry->mode |= S_IWUSR; | 217 | entry->mode |= 0200; |
218 | entry->c.text.write = lola_proc_codec_rw_write; | 218 | entry->c.text.write = lola_proc_codec_rw_write; |
219 | } | 219 | } |
220 | if (!snd_card_proc_new(chip->card, "regs", &entry)) | 220 | if (!snd_card_proc_new(chip->card, "regs", &entry)) |
diff --git a/sound/pci/oxygen/oxygen_mixer.c b/sound/pci/oxygen/oxygen_mixer.c index 4ca12665ff73..81af21ac1439 100644 --- a/sound/pci/oxygen/oxygen_mixer.c +++ b/sound/pci/oxygen/oxygen_mixer.c | |||
@@ -1052,10 +1052,10 @@ static int add_controls(struct oxygen *chip, | |||
1052 | [CONTROL_CD_CAPTURE_SWITCH] = "CD Capture Switch", | 1052 | [CONTROL_CD_CAPTURE_SWITCH] = "CD Capture Switch", |
1053 | [CONTROL_AUX_CAPTURE_SWITCH] = "Aux Capture Switch", | 1053 | [CONTROL_AUX_CAPTURE_SWITCH] = "Aux Capture Switch", |
1054 | }; | 1054 | }; |
1055 | unsigned int i, j; | 1055 | unsigned int i; |
1056 | struct snd_kcontrol_new template; | 1056 | struct snd_kcontrol_new template; |
1057 | struct snd_kcontrol *ctl; | 1057 | struct snd_kcontrol *ctl; |
1058 | int err; | 1058 | int j, err; |
1059 | 1059 | ||
1060 | for (i = 0; i < count; ++i) { | 1060 | for (i = 0; i < count; ++i) { |
1061 | template = controls[i]; | 1061 | template = controls[i]; |
@@ -1086,11 +1086,11 @@ static int add_controls(struct oxygen *chip, | |||
1086 | err = snd_ctl_add(chip->card, ctl); | 1086 | err = snd_ctl_add(chip->card, ctl); |
1087 | if (err < 0) | 1087 | if (err < 0) |
1088 | return err; | 1088 | return err; |
1089 | for (j = 0; j < CONTROL_COUNT; ++j) | 1089 | j = match_string(known_ctl_names, CONTROL_COUNT, ctl->id.name); |
1090 | if (!strcmp(ctl->id.name, known_ctl_names[j])) { | 1090 | if (j >= 0) { |
1091 | chip->controls[j] = ctl; | 1091 | chip->controls[j] = ctl; |
1092 | ctl->private_free = oxygen_any_ctl_free; | 1092 | ctl->private_free = oxygen_any_ctl_free; |
1093 | } | 1093 | } |
1094 | } | 1094 | } |
1095 | return 0; | 1095 | return 0; |
1096 | } | 1096 | } |
diff --git a/sound/pci/pcxhr/pcxhr.c b/sound/pci/pcxhr/pcxhr.c index f9ae72f28ddc..e57da4036231 100644 --- a/sound/pci/pcxhr/pcxhr.c +++ b/sound/pci/pcxhr/pcxhr.c | |||
@@ -1465,7 +1465,7 @@ static void pcxhr_proc_init(struct snd_pcxhr *chip) | |||
1465 | !snd_card_proc_new(chip->card, "gpio", &entry)) { | 1465 | !snd_card_proc_new(chip->card, "gpio", &entry)) { |
1466 | snd_info_set_text_ops(entry, chip, pcxhr_proc_gpio_read); | 1466 | snd_info_set_text_ops(entry, chip, pcxhr_proc_gpio_read); |
1467 | entry->c.text.write = pcxhr_proc_gpo_write; | 1467 | entry->c.text.write = pcxhr_proc_gpo_write; |
1468 | entry->mode |= S_IWUSR; | 1468 | entry->mode |= 0200; |
1469 | } | 1469 | } |
1470 | if (!snd_card_proc_new(chip->card, "ltc", &entry)) | 1470 | if (!snd_card_proc_new(chip->card, "ltc", &entry)) |
1471 | snd_info_set_text_ops(entry, chip, pcxhr_proc_ltc); | 1471 | snd_info_set_text_ops(entry, chip, pcxhr_proc_ltc); |
diff --git a/sound/soc/codecs/cs43130.c b/sound/soc/codecs/cs43130.c index feca0a672976..80dc42197154 100644 --- a/sound/soc/codecs/cs43130.c +++ b/sound/soc/codecs/cs43130.c | |||
@@ -1733,10 +1733,10 @@ static ssize_t cs43130_show_ac_r(struct device *dev, | |||
1733 | return cs43130_show_ac(dev, buf, HP_RIGHT); | 1733 | return cs43130_show_ac(dev, buf, HP_RIGHT); |
1734 | } | 1734 | } |
1735 | 1735 | ||
1736 | static DEVICE_ATTR(hpload_dc_l, S_IRUGO, cs43130_show_dc_l, NULL); | 1736 | static DEVICE_ATTR(hpload_dc_l, 0444, cs43130_show_dc_l, NULL); |
1737 | static DEVICE_ATTR(hpload_dc_r, S_IRUGO, cs43130_show_dc_r, NULL); | 1737 | static DEVICE_ATTR(hpload_dc_r, 0444, cs43130_show_dc_r, NULL); |
1738 | static DEVICE_ATTR(hpload_ac_l, S_IRUGO, cs43130_show_ac_l, NULL); | 1738 | static DEVICE_ATTR(hpload_ac_l, 0444, cs43130_show_ac_l, NULL); |
1739 | static DEVICE_ATTR(hpload_ac_r, S_IRUGO, cs43130_show_ac_r, NULL); | 1739 | static DEVICE_ATTR(hpload_ac_r, 0444, cs43130_show_ac_r, NULL); |
1740 | 1740 | ||
1741 | static struct reg_sequence hp_en_cal_seq[] = { | 1741 | static struct reg_sequence hp_en_cal_seq[] = { |
1742 | {CS43130_INT_MASK_4, CS43130_INT_MASK_ALL}, | 1742 | {CS43130_INT_MASK_4, CS43130_INT_MASK_ALL}, |
diff --git a/sound/soc/codecs/wm_adsp.c b/sound/soc/codecs/wm_adsp.c index 82b0927e6ed7..af062c4f4017 100644 --- a/sound/soc/codecs/wm_adsp.c +++ b/sound/soc/codecs/wm_adsp.c | |||
@@ -627,22 +627,21 @@ static void wm_adsp2_init_debugfs(struct wm_adsp *dsp, | |||
627 | if (!root) | 627 | if (!root) |
628 | goto err; | 628 | goto err; |
629 | 629 | ||
630 | if (!debugfs_create_bool("booted", S_IRUGO, root, &dsp->booted)) | 630 | if (!debugfs_create_bool("booted", 0444, root, &dsp->booted)) |
631 | goto err; | 631 | goto err; |
632 | 632 | ||
633 | if (!debugfs_create_bool("running", S_IRUGO, root, &dsp->running)) | 633 | if (!debugfs_create_bool("running", 0444, root, &dsp->running)) |
634 | goto err; | 634 | goto err; |
635 | 635 | ||
636 | if (!debugfs_create_x32("fw_id", S_IRUGO, root, &dsp->fw_id)) | 636 | if (!debugfs_create_x32("fw_id", 0444, root, &dsp->fw_id)) |
637 | goto err; | 637 | goto err; |
638 | 638 | ||
639 | if (!debugfs_create_x32("fw_version", S_IRUGO, root, | 639 | if (!debugfs_create_x32("fw_version", 0444, root, &dsp->fw_id_version)) |
640 | &dsp->fw_id_version)) | ||
641 | goto err; | 640 | goto err; |
642 | 641 | ||
643 | for (i = 0; i < ARRAY_SIZE(wm_adsp_debugfs_fops); ++i) { | 642 | for (i = 0; i < ARRAY_SIZE(wm_adsp_debugfs_fops); ++i) { |
644 | if (!debugfs_create_file(wm_adsp_debugfs_fops[i].name, | 643 | if (!debugfs_create_file(wm_adsp_debugfs_fops[i].name, |
645 | S_IRUGO, root, dsp, | 644 | 0444, root, dsp, |
646 | &wm_adsp_debugfs_fops[i].fops)) | 645 | &wm_adsp_debugfs_fops[i].fops)) |
647 | goto err; | 646 | goto err; |
648 | } | 647 | } |
diff --git a/sound/soc/fsl/fsl_ssi_dbg.c b/sound/soc/fsl/fsl_ssi_dbg.c index 7aac63e2c561..0ff469c027dd 100644 --- a/sound/soc/fsl/fsl_ssi_dbg.c +++ b/sound/soc/fsl/fsl_ssi_dbg.c | |||
@@ -146,7 +146,7 @@ int fsl_ssi_debugfs_create(struct fsl_ssi_dbg *ssi_dbg, struct device *dev) | |||
146 | if (!ssi_dbg->dbg_dir) | 146 | if (!ssi_dbg->dbg_dir) |
147 | return -ENOMEM; | 147 | return -ENOMEM; |
148 | 148 | ||
149 | ssi_dbg->dbg_stats = debugfs_create_file("stats", S_IRUGO, | 149 | ssi_dbg->dbg_stats = debugfs_create_file("stats", 0444, |
150 | ssi_dbg->dbg_dir, ssi_dbg, | 150 | ssi_dbg->dbg_dir, ssi_dbg, |
151 | &fsl_ssi_stats_ops); | 151 | &fsl_ssi_stats_ops); |
152 | if (!ssi_dbg->dbg_stats) { | 152 | if (!ssi_dbg->dbg_stats) { |
diff --git a/sound/sound_core.c b/sound/sound_core.c index b4efb22db561..40ad000c2e3c 100644 --- a/sound/sound_core.c +++ b/sound/sound_core.c | |||
@@ -413,7 +413,7 @@ int register_sound_special_device(const struct file_operations *fops, int unit, | |||
413 | break; | 413 | break; |
414 | } | 414 | } |
415 | return sound_insert_unit(&chains[chain], fops, -1, unit, max_unit, | 415 | return sound_insert_unit(&chains[chain], fops, -1, unit, max_unit, |
416 | name, S_IRUSR | S_IWUSR, dev); | 416 | name, 0600, dev); |
417 | } | 417 | } |
418 | 418 | ||
419 | EXPORT_SYMBOL(register_sound_special_device); | 419 | EXPORT_SYMBOL(register_sound_special_device); |
@@ -440,7 +440,7 @@ EXPORT_SYMBOL(register_sound_special); | |||
440 | int register_sound_mixer(const struct file_operations *fops, int dev) | 440 | int register_sound_mixer(const struct file_operations *fops, int dev) |
441 | { | 441 | { |
442 | return sound_insert_unit(&chains[0], fops, dev, 0, 128, | 442 | return sound_insert_unit(&chains[0], fops, dev, 0, 128, |
443 | "mixer", S_IRUSR | S_IWUSR, NULL); | 443 | "mixer", 0600, NULL); |
444 | } | 444 | } |
445 | 445 | ||
446 | EXPORT_SYMBOL(register_sound_mixer); | 446 | EXPORT_SYMBOL(register_sound_mixer); |
@@ -468,7 +468,7 @@ EXPORT_SYMBOL(register_sound_mixer); | |||
468 | int register_sound_dsp(const struct file_operations *fops, int dev) | 468 | int register_sound_dsp(const struct file_operations *fops, int dev) |
469 | { | 469 | { |
470 | return sound_insert_unit(&chains[3], fops, dev, 3, 131, | 470 | return sound_insert_unit(&chains[3], fops, dev, 3, 131, |
471 | "dsp", S_IWUSR | S_IRUSR, NULL); | 471 | "dsp", 0600, NULL); |
472 | } | 472 | } |
473 | 473 | ||
474 | EXPORT_SYMBOL(register_sound_dsp); | 474 | EXPORT_SYMBOL(register_sound_dsp); |
diff --git a/sound/sparc/dbri.c b/sound/sparc/dbri.c index abc7bd5055eb..7609eceba1a2 100644 --- a/sound/sparc/dbri.c +++ b/sound/sparc/dbri.c | |||
@@ -2518,7 +2518,7 @@ static void snd_dbri_proc(struct snd_card *card) | |||
2518 | #ifdef DBRI_DEBUG | 2518 | #ifdef DBRI_DEBUG |
2519 | if (!snd_card_proc_new(card, "debug", &entry)) { | 2519 | if (!snd_card_proc_new(card, "debug", &entry)) { |
2520 | snd_info_set_text_ops(entry, dbri, dbri_debug_read); | 2520 | snd_info_set_text_ops(entry, dbri, dbri_debug_read); |
2521 | entry->mode = S_IFREG | S_IRUGO; /* Readable only. */ | 2521 | entry->mode = S_IFREG | 0444; /* Readable only. */ |
2522 | } | 2522 | } |
2523 | #endif | 2523 | #endif |
2524 | } | 2524 | } |
@@ -2542,7 +2542,7 @@ static int snd_dbri_create(struct snd_card *card, | |||
2542 | dbri->irq = irq; | 2542 | dbri->irq = irq; |
2543 | 2543 | ||
2544 | dbri->dma = dma_zalloc_coherent(&op->dev, sizeof(struct dbri_dma), | 2544 | dbri->dma = dma_zalloc_coherent(&op->dev, sizeof(struct dbri_dma), |
2545 | &dbri->dma_dvma, GFP_ATOMIC); | 2545 | &dbri->dma_dvma, GFP_KERNEL); |
2546 | if (!dbri->dma) | 2546 | if (!dbri->dma) |
2547 | return -ENOMEM; | 2547 | return -ENOMEM; |
2548 | 2548 | ||
diff --git a/sound/usb/card.c b/sound/usb/card.c index 4a1c6bb3dfa0..a1ed798a1c6b 100644 --- a/sound/usb/card.c +++ b/sound/usb/card.c | |||
@@ -86,6 +86,8 @@ static bool ignore_ctl_error; | |||
86 | static bool autoclock = true; | 86 | static bool autoclock = true; |
87 | static char *quirk_alias[SNDRV_CARDS]; | 87 | static char *quirk_alias[SNDRV_CARDS]; |
88 | 88 | ||
89 | bool snd_usb_use_vmalloc = true; | ||
90 | |||
89 | module_param_array(index, int, NULL, 0444); | 91 | module_param_array(index, int, NULL, 0444); |
90 | MODULE_PARM_DESC(index, "Index value for the USB audio adapter."); | 92 | MODULE_PARM_DESC(index, "Index value for the USB audio adapter."); |
91 | module_param_array(id, charp, NULL, 0444); | 93 | module_param_array(id, charp, NULL, 0444); |
@@ -105,6 +107,8 @@ module_param(autoclock, bool, 0444); | |||
105 | MODULE_PARM_DESC(autoclock, "Enable auto-clock selection for UAC2 devices (default: yes)."); | 107 | MODULE_PARM_DESC(autoclock, "Enable auto-clock selection for UAC2 devices (default: yes)."); |
106 | module_param_array(quirk_alias, charp, NULL, 0444); | 108 | module_param_array(quirk_alias, charp, NULL, 0444); |
107 | MODULE_PARM_DESC(quirk_alias, "Quirk aliases, e.g. 0123abcd:5678beef."); | 109 | MODULE_PARM_DESC(quirk_alias, "Quirk aliases, e.g. 0123abcd:5678beef."); |
110 | module_param_named(use_vmalloc, snd_usb_use_vmalloc, bool, 0444); | ||
111 | MODULE_PARM_DESC(use_vmalloc, "Use vmalloc for PCM intermediate buffers (default: yes)."); | ||
108 | 112 | ||
109 | /* | 113 | /* |
110 | * we keep the snd_usb_audio_t instances by ourselves for merging | 114 | * we keep the snd_usb_audio_t instances by ourselves for merging |
@@ -221,32 +225,13 @@ static int snd_usb_create_streams(struct snd_usb_audio *chip, int ctrlif) | |||
221 | struct usb_device *dev = chip->dev; | 225 | struct usb_device *dev = chip->dev; |
222 | struct usb_host_interface *host_iface; | 226 | struct usb_host_interface *host_iface; |
223 | struct usb_interface_descriptor *altsd; | 227 | struct usb_interface_descriptor *altsd; |
224 | void *control_header; | ||
225 | int i, protocol; | 228 | int i, protocol; |
226 | int rest_bytes; | ||
227 | 229 | ||
228 | /* find audiocontrol interface */ | 230 | /* find audiocontrol interface */ |
229 | host_iface = &usb_ifnum_to_if(dev, ctrlif)->altsetting[0]; | 231 | host_iface = &usb_ifnum_to_if(dev, ctrlif)->altsetting[0]; |
230 | control_header = snd_usb_find_csint_desc(host_iface->extra, | ||
231 | host_iface->extralen, | ||
232 | NULL, UAC_HEADER); | ||
233 | altsd = get_iface_desc(host_iface); | 232 | altsd = get_iface_desc(host_iface); |
234 | protocol = altsd->bInterfaceProtocol; | 233 | protocol = altsd->bInterfaceProtocol; |
235 | 234 | ||
236 | if (!control_header) { | ||
237 | dev_err(&dev->dev, "cannot find UAC_HEADER\n"); | ||
238 | return -EINVAL; | ||
239 | } | ||
240 | |||
241 | rest_bytes = (void *)(host_iface->extra + host_iface->extralen) - | ||
242 | control_header; | ||
243 | |||
244 | /* just to be sure -- this shouldn't hit at all */ | ||
245 | if (rest_bytes <= 0) { | ||
246 | dev_err(&dev->dev, "invalid control header\n"); | ||
247 | return -EINVAL; | ||
248 | } | ||
249 | |||
250 | switch (protocol) { | 235 | switch (protocol) { |
251 | default: | 236 | default: |
252 | dev_warn(&dev->dev, | 237 | dev_warn(&dev->dev, |
@@ -255,7 +240,25 @@ static int snd_usb_create_streams(struct snd_usb_audio *chip, int ctrlif) | |||
255 | /* fall through */ | 240 | /* fall through */ |
256 | 241 | ||
257 | case UAC_VERSION_1: { | 242 | case UAC_VERSION_1: { |
258 | struct uac1_ac_header_descriptor *h1 = control_header; | 243 | struct uac1_ac_header_descriptor *h1; |
244 | int rest_bytes; | ||
245 | |||
246 | h1 = snd_usb_find_csint_desc(host_iface->extra, | ||
247 | host_iface->extralen, | ||
248 | NULL, UAC_HEADER); | ||
249 | if (!h1) { | ||
250 | dev_err(&dev->dev, "cannot find UAC_HEADER\n"); | ||
251 | return -EINVAL; | ||
252 | } | ||
253 | |||
254 | rest_bytes = (void *)(host_iface->extra + | ||
255 | host_iface->extralen) - (void *)h1; | ||
256 | |||
257 | /* just to be sure -- this shouldn't hit at all */ | ||
258 | if (rest_bytes <= 0) { | ||
259 | dev_err(&dev->dev, "invalid control header\n"); | ||
260 | return -EINVAL; | ||
261 | } | ||
259 | 262 | ||
260 | if (rest_bytes < sizeof(*h1)) { | 263 | if (rest_bytes < sizeof(*h1)) { |
261 | dev_err(&dev->dev, "too short v1 buffer descriptor\n"); | 264 | dev_err(&dev->dev, "too short v1 buffer descriptor\n"); |
@@ -308,6 +311,20 @@ static int snd_usb_create_streams(struct snd_usb_audio *chip, int ctrlif) | |||
308 | return -EINVAL; | 311 | return -EINVAL; |
309 | } | 312 | } |
310 | 313 | ||
314 | if (protocol == UAC_VERSION_3) { | ||
315 | int badd = assoc->bFunctionSubClass; | ||
316 | |||
317 | if (badd != UAC3_FUNCTION_SUBCLASS_FULL_ADC_3_0 && | ||
318 | (badd < UAC3_FUNCTION_SUBCLASS_GENERIC_IO || | ||
319 | badd > UAC3_FUNCTION_SUBCLASS_SPEAKERPHONE)) { | ||
320 | dev_err(&dev->dev, | ||
321 | "Unsupported UAC3 BADD profile\n"); | ||
322 | return -EINVAL; | ||
323 | } | ||
324 | |||
325 | chip->badd_profile = badd; | ||
326 | } | ||
327 | |||
311 | for (i = 0; i < assoc->bInterfaceCount; i++) { | 328 | for (i = 0; i < assoc->bInterfaceCount; i++) { |
312 | int intf = assoc->bFirstInterface + i; | 329 | int intf = assoc->bFirstInterface + i; |
313 | 330 | ||
@@ -329,8 +346,9 @@ static int snd_usb_create_streams(struct snd_usb_audio *chip, int ctrlif) | |||
329 | * | 346 | * |
330 | */ | 347 | */ |
331 | 348 | ||
332 | static int snd_usb_audio_free(struct snd_usb_audio *chip) | 349 | static void snd_usb_audio_free(struct snd_card *card) |
333 | { | 350 | { |
351 | struct snd_usb_audio *chip = card->private_data; | ||
334 | struct snd_usb_endpoint *ep, *n; | 352 | struct snd_usb_endpoint *ep, *n; |
335 | 353 | ||
336 | list_for_each_entry_safe(ep, n, &chip->ep_list, list) | 354 | list_for_each_entry_safe(ep, n, &chip->ep_list, list) |
@@ -339,14 +357,90 @@ static int snd_usb_audio_free(struct snd_usb_audio *chip) | |||
339 | mutex_destroy(&chip->mutex); | 357 | mutex_destroy(&chip->mutex); |
340 | if (!atomic_read(&chip->shutdown)) | 358 | if (!atomic_read(&chip->shutdown)) |
341 | dev_set_drvdata(&chip->dev->dev, NULL); | 359 | dev_set_drvdata(&chip->dev->dev, NULL); |
342 | kfree(chip); | ||
343 | return 0; | ||
344 | } | 360 | } |
345 | 361 | ||
346 | static int snd_usb_audio_dev_free(struct snd_device *device) | 362 | static void usb_audio_make_shortname(struct usb_device *dev, |
363 | struct snd_usb_audio *chip, | ||
364 | const struct snd_usb_audio_quirk *quirk) | ||
347 | { | 365 | { |
348 | struct snd_usb_audio *chip = device->device_data; | 366 | struct snd_card *card = chip->card; |
349 | return snd_usb_audio_free(chip); | 367 | |
368 | if (quirk && quirk->product_name && *quirk->product_name) { | ||
369 | strlcpy(card->shortname, quirk->product_name, | ||
370 | sizeof(card->shortname)); | ||
371 | return; | ||
372 | } | ||
373 | |||
374 | /* retrieve the device string as shortname */ | ||
375 | if (!dev->descriptor.iProduct || | ||
376 | usb_string(dev, dev->descriptor.iProduct, | ||
377 | card->shortname, sizeof(card->shortname)) <= 0) { | ||
378 | /* no name available from anywhere, so use ID */ | ||
379 | sprintf(card->shortname, "USB Device %#04x:%#04x", | ||
380 | USB_ID_VENDOR(chip->usb_id), | ||
381 | USB_ID_PRODUCT(chip->usb_id)); | ||
382 | } | ||
383 | |||
384 | strim(card->shortname); | ||
385 | } | ||
386 | |||
387 | static void usb_audio_make_longname(struct usb_device *dev, | ||
388 | struct snd_usb_audio *chip, | ||
389 | const struct snd_usb_audio_quirk *quirk) | ||
390 | { | ||
391 | struct snd_card *card = chip->card; | ||
392 | int len; | ||
393 | |||
394 | /* shortcut - if any pre-defined string is given, use it */ | ||
395 | if (quirk && quirk->profile_name && *quirk->profile_name) { | ||
396 | strlcpy(card->longname, quirk->profile_name, | ||
397 | sizeof(card->longname)); | ||
398 | return; | ||
399 | } | ||
400 | |||
401 | if (quirk && quirk->vendor_name && *quirk->vendor_name) { | ||
402 | len = strlcpy(card->longname, quirk->vendor_name, sizeof(card->longname)); | ||
403 | } else { | ||
404 | /* retrieve the vendor and device strings as longname */ | ||
405 | if (dev->descriptor.iManufacturer) | ||
406 | len = usb_string(dev, dev->descriptor.iManufacturer, | ||
407 | card->longname, sizeof(card->longname)); | ||
408 | else | ||
409 | len = 0; | ||
410 | /* we don't really care if there isn't any vendor string */ | ||
411 | } | ||
412 | if (len > 0) { | ||
413 | strim(card->longname); | ||
414 | if (*card->longname) | ||
415 | strlcat(card->longname, " ", sizeof(card->longname)); | ||
416 | } | ||
417 | |||
418 | strlcat(card->longname, card->shortname, sizeof(card->longname)); | ||
419 | |||
420 | len = strlcat(card->longname, " at ", sizeof(card->longname)); | ||
421 | |||
422 | if (len < sizeof(card->longname)) | ||
423 | usb_make_path(dev, card->longname + len, sizeof(card->longname) - len); | ||
424 | |||
425 | switch (snd_usb_get_speed(dev)) { | ||
426 | case USB_SPEED_LOW: | ||
427 | strlcat(card->longname, ", low speed", sizeof(card->longname)); | ||
428 | break; | ||
429 | case USB_SPEED_FULL: | ||
430 | strlcat(card->longname, ", full speed", sizeof(card->longname)); | ||
431 | break; | ||
432 | case USB_SPEED_HIGH: | ||
433 | strlcat(card->longname, ", high speed", sizeof(card->longname)); | ||
434 | break; | ||
435 | case USB_SPEED_SUPER: | ||
436 | strlcat(card->longname, ", super speed", sizeof(card->longname)); | ||
437 | break; | ||
438 | case USB_SPEED_SUPER_PLUS: | ||
439 | strlcat(card->longname, ", super speed plus", sizeof(card->longname)); | ||
440 | break; | ||
441 | default: | ||
442 | break; | ||
443 | } | ||
350 | } | 444 | } |
351 | 445 | ||
352 | /* | 446 | /* |
@@ -360,11 +454,8 @@ static int snd_usb_audio_create(struct usb_interface *intf, | |||
360 | { | 454 | { |
361 | struct snd_card *card; | 455 | struct snd_card *card; |
362 | struct snd_usb_audio *chip; | 456 | struct snd_usb_audio *chip; |
363 | int err, len; | 457 | int err; |
364 | char component[14]; | 458 | char component[14]; |
365 | static struct snd_device_ops ops = { | ||
366 | .dev_free = snd_usb_audio_dev_free, | ||
367 | }; | ||
368 | 459 | ||
369 | *rchip = NULL; | 460 | *rchip = NULL; |
370 | 461 | ||
@@ -382,18 +473,13 @@ static int snd_usb_audio_create(struct usb_interface *intf, | |||
382 | } | 473 | } |
383 | 474 | ||
384 | err = snd_card_new(&intf->dev, index[idx], id[idx], THIS_MODULE, | 475 | err = snd_card_new(&intf->dev, index[idx], id[idx], THIS_MODULE, |
385 | 0, &card); | 476 | sizeof(*chip), &card); |
386 | if (err < 0) { | 477 | if (err < 0) { |
387 | dev_err(&dev->dev, "cannot create card instance %d\n", idx); | 478 | dev_err(&dev->dev, "cannot create card instance %d\n", idx); |
388 | return err; | 479 | return err; |
389 | } | 480 | } |
390 | 481 | ||
391 | chip = kzalloc(sizeof(*chip), GFP_KERNEL); | 482 | chip = card->private_data; |
392 | if (! chip) { | ||
393 | snd_card_free(card); | ||
394 | return -ENOMEM; | ||
395 | } | ||
396 | |||
397 | mutex_init(&chip->mutex); | 483 | mutex_init(&chip->mutex); |
398 | init_waitqueue_head(&chip->shutdown_wait); | 484 | init_waitqueue_head(&chip->shutdown_wait); |
399 | chip->index = idx; | 485 | chip->index = idx; |
@@ -411,75 +497,15 @@ static int snd_usb_audio_create(struct usb_interface *intf, | |||
411 | INIT_LIST_HEAD(&chip->midi_list); | 497 | INIT_LIST_HEAD(&chip->midi_list); |
412 | INIT_LIST_HEAD(&chip->mixer_list); | 498 | INIT_LIST_HEAD(&chip->mixer_list); |
413 | 499 | ||
414 | if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, chip, &ops)) < 0) { | 500 | card->private_free = snd_usb_audio_free; |
415 | snd_usb_audio_free(chip); | ||
416 | snd_card_free(card); | ||
417 | return err; | ||
418 | } | ||
419 | 501 | ||
420 | strcpy(card->driver, "USB-Audio"); | 502 | strcpy(card->driver, "USB-Audio"); |
421 | sprintf(component, "USB%04x:%04x", | 503 | sprintf(component, "USB%04x:%04x", |
422 | USB_ID_VENDOR(chip->usb_id), USB_ID_PRODUCT(chip->usb_id)); | 504 | USB_ID_VENDOR(chip->usb_id), USB_ID_PRODUCT(chip->usb_id)); |
423 | snd_component_add(card, component); | 505 | snd_component_add(card, component); |
424 | 506 | ||
425 | /* retrieve the device string as shortname */ | 507 | usb_audio_make_shortname(dev, chip, quirk); |
426 | if (quirk && quirk->product_name && *quirk->product_name) { | 508 | usb_audio_make_longname(dev, chip, quirk); |
427 | strlcpy(card->shortname, quirk->product_name, sizeof(card->shortname)); | ||
428 | } else { | ||
429 | if (!dev->descriptor.iProduct || | ||
430 | usb_string(dev, dev->descriptor.iProduct, | ||
431 | card->shortname, sizeof(card->shortname)) <= 0) { | ||
432 | /* no name available from anywhere, so use ID */ | ||
433 | sprintf(card->shortname, "USB Device %#04x:%#04x", | ||
434 | USB_ID_VENDOR(chip->usb_id), | ||
435 | USB_ID_PRODUCT(chip->usb_id)); | ||
436 | } | ||
437 | } | ||
438 | strim(card->shortname); | ||
439 | |||
440 | /* retrieve the vendor and device strings as longname */ | ||
441 | if (quirk && quirk->vendor_name && *quirk->vendor_name) { | ||
442 | len = strlcpy(card->longname, quirk->vendor_name, sizeof(card->longname)); | ||
443 | } else { | ||
444 | if (dev->descriptor.iManufacturer) | ||
445 | len = usb_string(dev, dev->descriptor.iManufacturer, | ||
446 | card->longname, sizeof(card->longname)); | ||
447 | else | ||
448 | len = 0; | ||
449 | /* we don't really care if there isn't any vendor string */ | ||
450 | } | ||
451 | if (len > 0) { | ||
452 | strim(card->longname); | ||
453 | if (*card->longname) | ||
454 | strlcat(card->longname, " ", sizeof(card->longname)); | ||
455 | } | ||
456 | |||
457 | strlcat(card->longname, card->shortname, sizeof(card->longname)); | ||
458 | |||
459 | len = strlcat(card->longname, " at ", sizeof(card->longname)); | ||
460 | |||
461 | if (len < sizeof(card->longname)) | ||
462 | usb_make_path(dev, card->longname + len, sizeof(card->longname) - len); | ||
463 | |||
464 | switch (snd_usb_get_speed(dev)) { | ||
465 | case USB_SPEED_LOW: | ||
466 | strlcat(card->longname, ", low speed", sizeof(card->longname)); | ||
467 | break; | ||
468 | case USB_SPEED_FULL: | ||
469 | strlcat(card->longname, ", full speed", sizeof(card->longname)); | ||
470 | break; | ||
471 | case USB_SPEED_HIGH: | ||
472 | strlcat(card->longname, ", high speed", sizeof(card->longname)); | ||
473 | break; | ||
474 | case USB_SPEED_SUPER: | ||
475 | strlcat(card->longname, ", super speed", sizeof(card->longname)); | ||
476 | break; | ||
477 | case USB_SPEED_SUPER_PLUS: | ||
478 | strlcat(card->longname, ", super speed plus", sizeof(card->longname)); | ||
479 | break; | ||
480 | default: | ||
481 | break; | ||
482 | } | ||
483 | 509 | ||
484 | snd_usb_audio_create_proc(chip); | 510 | snd_usb_audio_create_proc(chip); |
485 | 511 | ||
diff --git a/sound/usb/clock.c b/sound/usb/clock.c index 0b030d8fe3fa..c79749613fa6 100644 --- a/sound/usb/clock.c +++ b/sound/usb/clock.c | |||
@@ -443,10 +443,11 @@ static int set_sample_rate_v1(struct snd_usb_audio *chip, int iface, | |||
443 | data[0] = rate; | 443 | data[0] = rate; |
444 | data[1] = rate >> 8; | 444 | data[1] = rate >> 8; |
445 | data[2] = rate >> 16; | 445 | data[2] = rate >> 16; |
446 | if ((err = snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0), UAC_SET_CUR, | 446 | err = snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0), UAC_SET_CUR, |
447 | USB_TYPE_CLASS | USB_RECIP_ENDPOINT | USB_DIR_OUT, | 447 | USB_TYPE_CLASS | USB_RECIP_ENDPOINT | USB_DIR_OUT, |
448 | UAC_EP_CS_ATTR_SAMPLE_RATE << 8, ep, | 448 | UAC_EP_CS_ATTR_SAMPLE_RATE << 8, ep, |
449 | data, sizeof(data))) < 0) { | 449 | data, sizeof(data)); |
450 | if (err < 0) { | ||
450 | dev_err(&dev->dev, "%d:%d: cannot set freq %d to ep %#x\n", | 451 | dev_err(&dev->dev, "%d:%d: cannot set freq %d to ep %#x\n", |
451 | iface, fmt->altsetting, rate, ep); | 452 | iface, fmt->altsetting, rate, ep); |
452 | return err; | 453 | return err; |
@@ -460,10 +461,11 @@ static int set_sample_rate_v1(struct snd_usb_audio *chip, int iface, | |||
460 | if (chip->sample_rate_read_error > 2) | 461 | if (chip->sample_rate_read_error > 2) |
461 | return 0; | 462 | return 0; |
462 | 463 | ||
463 | if ((err = snd_usb_ctl_msg(dev, usb_rcvctrlpipe(dev, 0), UAC_GET_CUR, | 464 | err = snd_usb_ctl_msg(dev, usb_rcvctrlpipe(dev, 0), UAC_GET_CUR, |
464 | USB_TYPE_CLASS | USB_RECIP_ENDPOINT | USB_DIR_IN, | 465 | USB_TYPE_CLASS | USB_RECIP_ENDPOINT | USB_DIR_IN, |
465 | UAC_EP_CS_ATTR_SAMPLE_RATE << 8, ep, | 466 | UAC_EP_CS_ATTR_SAMPLE_RATE << 8, ep, |
466 | data, sizeof(data))) < 0) { | 467 | data, sizeof(data)); |
468 | if (err < 0) { | ||
467 | dev_err(&dev->dev, "%d:%d: cannot get freq at ep %#x\n", | 469 | dev_err(&dev->dev, "%d:%d: cannot get freq at ep %#x\n", |
468 | iface, fmt->altsetting, ep); | 470 | iface, fmt->altsetting, ep); |
469 | chip->sample_rate_read_error++; | 471 | chip->sample_rate_read_error++; |
@@ -587,8 +589,15 @@ int snd_usb_init_sample_rate(struct snd_usb_audio *chip, int iface, | |||
587 | default: | 589 | default: |
588 | return set_sample_rate_v1(chip, iface, alts, fmt, rate); | 590 | return set_sample_rate_v1(chip, iface, alts, fmt, rate); |
589 | 591 | ||
590 | case UAC_VERSION_2: | ||
591 | case UAC_VERSION_3: | 592 | case UAC_VERSION_3: |
593 | if (chip->badd_profile >= UAC3_FUNCTION_SUBCLASS_GENERIC_IO) { | ||
594 | if (rate != UAC3_BADD_SAMPLING_RATE) | ||
595 | return -ENXIO; | ||
596 | else | ||
597 | return 0; | ||
598 | } | ||
599 | /* fall through */ | ||
600 | case UAC_VERSION_2: | ||
592 | return set_sample_rate_v2v3(chip, iface, alts, fmt, rate); | 601 | return set_sample_rate_v2v3(chip, iface, alts, fmt, rate); |
593 | } | 602 | } |
594 | } | 603 | } |
diff --git a/sound/usb/helper.h b/sound/usb/helper.h index 4463e6d6dcb3..d338bd0e0ca6 100644 --- a/sound/usb/helper.h +++ b/sound/usb/helper.h | |||
@@ -18,16 +18,12 @@ unsigned char snd_usb_parse_datainterval(struct snd_usb_audio *chip, | |||
18 | * retrieve usb_interface descriptor from the host interface | 18 | * retrieve usb_interface descriptor from the host interface |
19 | * (conditional for compatibility with the older API) | 19 | * (conditional for compatibility with the older API) |
20 | */ | 20 | */ |
21 | #ifndef get_iface_desc | ||
22 | #define get_iface_desc(iface) (&(iface)->desc) | 21 | #define get_iface_desc(iface) (&(iface)->desc) |
23 | #define get_endpoint(alt,ep) (&(alt)->endpoint[ep].desc) | 22 | #define get_endpoint(alt,ep) (&(alt)->endpoint[ep].desc) |
24 | #define get_ep_desc(ep) (&(ep)->desc) | 23 | #define get_ep_desc(ep) (&(ep)->desc) |
25 | #define get_cfg_desc(cfg) (&(cfg)->desc) | 24 | #define get_cfg_desc(cfg) (&(cfg)->desc) |
26 | #endif | ||
27 | 25 | ||
28 | #ifndef snd_usb_get_speed | ||
29 | #define snd_usb_get_speed(dev) ((dev)->speed) | 26 | #define snd_usb_get_speed(dev) ((dev)->speed) |
30 | #endif | ||
31 | 27 | ||
32 | static inline int snd_usb_ctrl_intf(struct snd_usb_audio *chip) | 28 | static inline int snd_usb_ctrl_intf(struct snd_usb_audio *chip) |
33 | { | 29 | { |
diff --git a/sound/usb/mixer.c b/sound/usb/mixer.c index bb5ab7a7dfa5..898afd3001ea 100644 --- a/sound/usb/mixer.c +++ b/sound/usb/mixer.c | |||
@@ -112,14 +112,12 @@ enum { | |||
112 | #include "mixer_maps.c" | 112 | #include "mixer_maps.c" |
113 | 113 | ||
114 | static const struct usbmix_name_map * | 114 | static const struct usbmix_name_map * |
115 | find_map(struct mixer_build *state, int unitid, int control) | 115 | find_map(const struct usbmix_name_map *p, int unitid, int control) |
116 | { | 116 | { |
117 | const struct usbmix_name_map *p = state->map; | ||
118 | |||
119 | if (!p) | 117 | if (!p) |
120 | return NULL; | 118 | return NULL; |
121 | 119 | ||
122 | for (p = state->map; p->id; p++) { | 120 | for (; p->id; p++) { |
123 | if (p->id == unitid && | 121 | if (p->id == unitid && |
124 | (!control || !p->control || control == p->control)) | 122 | (!control || !p->control || control == p->control)) |
125 | return p; | 123 | return p; |
@@ -201,10 +199,10 @@ static void *find_audio_control_unit(struct mixer_build *state, | |||
201 | /* | 199 | /* |
202 | * copy a string with the given id | 200 | * copy a string with the given id |
203 | */ | 201 | */ |
204 | static int snd_usb_copy_string_desc(struct mixer_build *state, | 202 | static int snd_usb_copy_string_desc(struct snd_usb_audio *chip, |
205 | int index, char *buf, int maxlen) | 203 | int index, char *buf, int maxlen) |
206 | { | 204 | { |
207 | int len = usb_string(state->chip->dev, index, buf, maxlen - 1); | 205 | int len = usb_string(chip->dev, index, buf, maxlen - 1); |
208 | 206 | ||
209 | if (len < 0) | 207 | if (len < 0) |
210 | return 0; | 208 | return 0; |
@@ -600,7 +598,8 @@ int snd_usb_mixer_add_control(struct usb_mixer_elem_list *list, | |||
600 | 598 | ||
601 | while (snd_ctl_find_id(mixer->chip->card, &kctl->id)) | 599 | while (snd_ctl_find_id(mixer->chip->card, &kctl->id)) |
602 | kctl->id.index++; | 600 | kctl->id.index++; |
603 | if ((err = snd_ctl_add(mixer->chip->card, kctl)) < 0) { | 601 | err = snd_ctl_add(mixer->chip->card, kctl); |
602 | if (err < 0) { | ||
604 | usb_audio_dbg(mixer->chip, "cannot add control (err = %d)\n", | 603 | usb_audio_dbg(mixer->chip, "cannot add control (err = %d)\n", |
605 | err); | 604 | err); |
606 | return err; | 605 | return err; |
@@ -658,14 +657,14 @@ static struct iterm_name_combo { | |||
658 | { 0 }, | 657 | { 0 }, |
659 | }; | 658 | }; |
660 | 659 | ||
661 | static int get_term_name(struct mixer_build *state, struct usb_audio_term *iterm, | 660 | static int get_term_name(struct snd_usb_audio *chip, struct usb_audio_term *iterm, |
662 | unsigned char *name, int maxlen, int term_only) | 661 | unsigned char *name, int maxlen, int term_only) |
663 | { | 662 | { |
664 | struct iterm_name_combo *names; | 663 | struct iterm_name_combo *names; |
665 | int len; | 664 | int len; |
666 | 665 | ||
667 | if (iterm->name) { | 666 | if (iterm->name) { |
668 | len = snd_usb_copy_string_desc(state, iterm->name, | 667 | len = snd_usb_copy_string_desc(chip, iterm->name, |
669 | name, maxlen); | 668 | name, maxlen); |
670 | if (len) | 669 | if (len) |
671 | return len; | 670 | return len; |
@@ -719,6 +718,66 @@ static int get_term_name(struct mixer_build *state, struct usb_audio_term *iterm | |||
719 | } | 718 | } |
720 | 719 | ||
721 | /* | 720 | /* |
721 | * Get logical cluster information for UAC3 devices. | ||
722 | */ | ||
723 | static int get_cluster_channels_v3(struct mixer_build *state, unsigned int cluster_id) | ||
724 | { | ||
725 | struct uac3_cluster_header_descriptor c_header; | ||
726 | int err; | ||
727 | |||
728 | err = snd_usb_ctl_msg(state->chip->dev, | ||
729 | usb_rcvctrlpipe(state->chip->dev, 0), | ||
730 | UAC3_CS_REQ_HIGH_CAPABILITY_DESCRIPTOR, | ||
731 | USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN, | ||
732 | cluster_id, | ||
733 | snd_usb_ctrl_intf(state->chip), | ||
734 | &c_header, sizeof(c_header)); | ||
735 | if (err < 0) | ||
736 | goto error; | ||
737 | if (err != sizeof(c_header)) { | ||
738 | err = -EIO; | ||
739 | goto error; | ||
740 | } | ||
741 | |||
742 | return c_header.bNrChannels; | ||
743 | |||
744 | error: | ||
745 | usb_audio_err(state->chip, "cannot request logical cluster ID: %d (err: %d)\n", cluster_id, err); | ||
746 | return err; | ||
747 | } | ||
748 | |||
749 | /* | ||
750 | * Get number of channels for a Mixer Unit. | ||
751 | */ | ||
752 | static int uac_mixer_unit_get_channels(struct mixer_build *state, | ||
753 | struct uac_mixer_unit_descriptor *desc) | ||
754 | { | ||
755 | int mu_channels; | ||
756 | |||
757 | if (desc->bLength < 11) | ||
758 | return -EINVAL; | ||
759 | if (!desc->bNrInPins) | ||
760 | return -EINVAL; | ||
761 | |||
762 | switch (state->mixer->protocol) { | ||
763 | case UAC_VERSION_1: | ||
764 | case UAC_VERSION_2: | ||
765 | default: | ||
766 | mu_channels = uac_mixer_unit_bNrChannels(desc); | ||
767 | break; | ||
768 | case UAC_VERSION_3: | ||
769 | mu_channels = get_cluster_channels_v3(state, | ||
770 | uac3_mixer_unit_wClusterDescrID(desc)); | ||
771 | break; | ||
772 | } | ||
773 | |||
774 | if (!mu_channels) | ||
775 | return -EINVAL; | ||
776 | |||
777 | return mu_channels; | ||
778 | } | ||
779 | |||
780 | /* | ||
722 | * parse the source unit recursively until it reaches to a terminal | 781 | * parse the source unit recursively until it reaches to a terminal |
723 | * or a branched unit. | 782 | * or a branched unit. |
724 | */ | 783 | */ |
@@ -844,8 +903,12 @@ static int check_input_term(struct mixer_build *state, int id, | |||
844 | term->id = id; | 903 | term->id = id; |
845 | term->type = le16_to_cpu(d->wTerminalType); | 904 | term->type = le16_to_cpu(d->wTerminalType); |
846 | 905 | ||
847 | /* REVISIT: UAC3 IT doesn't have channels/cfg */ | 906 | err = get_cluster_channels_v3(state, le16_to_cpu(d->wClusterDescrID)); |
848 | term->channels = 0; | 907 | if (err < 0) |
908 | return err; | ||
909 | term->channels = err; | ||
910 | |||
911 | /* REVISIT: UAC3 IT doesn't have channels cfg */ | ||
849 | term->chconfig = 0; | 912 | term->chconfig = 0; |
850 | 913 | ||
851 | term->name = le16_to_cpu(d->wTerminalDescrStr); | 914 | term->name = le16_to_cpu(d->wTerminalDescrStr); |
@@ -865,6 +928,18 @@ static int check_input_term(struct mixer_build *state, int id, | |||
865 | term->name = le16_to_cpu(d->wClockSourceStr); | 928 | term->name = le16_to_cpu(d->wClockSourceStr); |
866 | return 0; | 929 | return 0; |
867 | } | 930 | } |
931 | case UAC3_MIXER_UNIT: { | ||
932 | struct uac_mixer_unit_descriptor *d = p1; | ||
933 | |||
934 | err = uac_mixer_unit_get_channels(state, d); | ||
935 | if (err < 0) | ||
936 | return err; | ||
937 | |||
938 | term->channels = err; | ||
939 | term->type = d->bDescriptorSubtype << 16; /* virtual type */ | ||
940 | |||
941 | return 0; | ||
942 | } | ||
868 | default: | 943 | default: |
869 | return -ENODEV; | 944 | return -ENODEV; |
870 | } | 945 | } |
@@ -1258,6 +1333,51 @@ static int mixer_ctl_master_bool_get(struct snd_kcontrol *kcontrol, | |||
1258 | return 0; | 1333 | return 0; |
1259 | } | 1334 | } |
1260 | 1335 | ||
1336 | /* get the connectors status and report it as boolean type */ | ||
1337 | static int mixer_ctl_connector_get(struct snd_kcontrol *kcontrol, | ||
1338 | struct snd_ctl_elem_value *ucontrol) | ||
1339 | { | ||
1340 | struct usb_mixer_elem_info *cval = kcontrol->private_data; | ||
1341 | struct snd_usb_audio *chip = cval->head.mixer->chip; | ||
1342 | int idx = 0, validx, ret, val; | ||
1343 | |||
1344 | validx = cval->control << 8 | 0; | ||
1345 | |||
1346 | ret = snd_usb_lock_shutdown(chip) ? -EIO : 0; | ||
1347 | if (ret) | ||
1348 | goto error; | ||
1349 | |||
1350 | idx = snd_usb_ctrl_intf(chip) | (cval->head.id << 8); | ||
1351 | if (cval->head.mixer->protocol == UAC_VERSION_2) { | ||
1352 | struct uac2_connectors_ctl_blk uac2_conn; | ||
1353 | |||
1354 | ret = snd_usb_ctl_msg(chip->dev, usb_rcvctrlpipe(chip->dev, 0), UAC2_CS_CUR, | ||
1355 | USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN, | ||
1356 | validx, idx, &uac2_conn, sizeof(uac2_conn)); | ||
1357 | val = !!uac2_conn.bNrChannels; | ||
1358 | } else { /* UAC_VERSION_3 */ | ||
1359 | struct uac3_insertion_ctl_blk uac3_conn; | ||
1360 | |||
1361 | ret = snd_usb_ctl_msg(chip->dev, usb_rcvctrlpipe(chip->dev, 0), UAC2_CS_CUR, | ||
1362 | USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN, | ||
1363 | validx, idx, &uac3_conn, sizeof(uac3_conn)); | ||
1364 | val = !!uac3_conn.bmConInserted; | ||
1365 | } | ||
1366 | |||
1367 | snd_usb_unlock_shutdown(chip); | ||
1368 | |||
1369 | if (ret < 0) { | ||
1370 | error: | ||
1371 | usb_audio_err(chip, | ||
1372 | "cannot get connectors status: req = %#x, wValue = %#x, wIndex = %#x, type = %d\n", | ||
1373 | UAC_GET_CUR, validx, idx, cval->val_type); | ||
1374 | return ret; | ||
1375 | } | ||
1376 | |||
1377 | ucontrol->value.integer.value[0] = val; | ||
1378 | return 0; | ||
1379 | } | ||
1380 | |||
1261 | static struct snd_kcontrol_new usb_feature_unit_ctl = { | 1381 | static struct snd_kcontrol_new usb_feature_unit_ctl = { |
1262 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, | 1382 | .iface = SNDRV_CTL_ELEM_IFACE_MIXER, |
1263 | .name = "", /* will be filled later manually */ | 1383 | .name = "", /* will be filled later manually */ |
@@ -1288,6 +1408,15 @@ static struct snd_kcontrol_new usb_bool_master_control_ctl_ro = { | |||
1288 | .put = NULL, | 1408 | .put = NULL, |
1289 | }; | 1409 | }; |
1290 | 1410 | ||
1411 | static const struct snd_kcontrol_new usb_connector_ctl_ro = { | ||
1412 | .iface = SNDRV_CTL_ELEM_IFACE_CARD, | ||
1413 | .name = "", /* will be filled later manually */ | ||
1414 | .access = SNDRV_CTL_ELEM_ACCESS_READ, | ||
1415 | .info = snd_ctl_boolean_mono_info, | ||
1416 | .get = mixer_ctl_connector_get, | ||
1417 | .put = NULL, | ||
1418 | }; | ||
1419 | |||
1291 | /* | 1420 | /* |
1292 | * This symbol is exported in order to allow the mixer quirks to | 1421 | * This symbol is exported in order to allow the mixer quirks to |
1293 | * hook up to the standard feature unit control mechanism | 1422 | * hook up to the standard feature unit control mechanism |
@@ -1341,16 +1470,16 @@ static struct usb_feature_control_info *get_feature_control_info(int control) | |||
1341 | return NULL; | 1470 | return NULL; |
1342 | } | 1471 | } |
1343 | 1472 | ||
1344 | static void build_feature_ctl(struct mixer_build *state, void *raw_desc, | 1473 | static void __build_feature_ctl(struct usb_mixer_interface *mixer, |
1345 | unsigned int ctl_mask, int control, | 1474 | const struct usbmix_name_map *imap, |
1346 | struct usb_audio_term *iterm, int unitid, | 1475 | unsigned int ctl_mask, int control, |
1347 | int readonly_mask) | 1476 | struct usb_audio_term *iterm, |
1477 | struct usb_audio_term *oterm, | ||
1478 | int unitid, int nameid, int readonly_mask) | ||
1348 | { | 1479 | { |
1349 | struct uac_feature_unit_descriptor *desc = raw_desc; | ||
1350 | struct usb_feature_control_info *ctl_info; | 1480 | struct usb_feature_control_info *ctl_info; |
1351 | unsigned int len = 0; | 1481 | unsigned int len = 0; |
1352 | int mapped_name = 0; | 1482 | int mapped_name = 0; |
1353 | int nameid = uac_feature_unit_iFeature(desc); | ||
1354 | struct snd_kcontrol *kctl; | 1483 | struct snd_kcontrol *kctl; |
1355 | struct usb_mixer_elem_info *cval; | 1484 | struct usb_mixer_elem_info *cval; |
1356 | const struct usbmix_name_map *map; | 1485 | const struct usbmix_name_map *map; |
@@ -1361,14 +1490,14 @@ static void build_feature_ctl(struct mixer_build *state, void *raw_desc, | |||
1361 | return; | 1490 | return; |
1362 | } | 1491 | } |
1363 | 1492 | ||
1364 | map = find_map(state, unitid, control); | 1493 | map = find_map(imap, unitid, control); |
1365 | if (check_ignored_ctl(map)) | 1494 | if (check_ignored_ctl(map)) |
1366 | return; | 1495 | return; |
1367 | 1496 | ||
1368 | cval = kzalloc(sizeof(*cval), GFP_KERNEL); | 1497 | cval = kzalloc(sizeof(*cval), GFP_KERNEL); |
1369 | if (!cval) | 1498 | if (!cval) |
1370 | return; | 1499 | return; |
1371 | snd_usb_mixer_elem_init_std(&cval->head, state->mixer, unitid); | 1500 | snd_usb_mixer_elem_init_std(&cval->head, mixer, unitid); |
1372 | cval->control = control; | 1501 | cval->control = control; |
1373 | cval->cmask = ctl_mask; | 1502 | cval->cmask = ctl_mask; |
1374 | 1503 | ||
@@ -1377,7 +1506,7 @@ static void build_feature_ctl(struct mixer_build *state, void *raw_desc, | |||
1377 | kfree(cval); | 1506 | kfree(cval); |
1378 | return; | 1507 | return; |
1379 | } | 1508 | } |
1380 | if (state->mixer->protocol == UAC_VERSION_1) | 1509 | if (mixer->protocol == UAC_VERSION_1) |
1381 | cval->val_type = ctl_info->type; | 1510 | cval->val_type = ctl_info->type; |
1382 | else /* UAC_VERSION_2 */ | 1511 | else /* UAC_VERSION_2 */ |
1383 | cval->val_type = ctl_info->type_uac2 >= 0 ? | 1512 | cval->val_type = ctl_info->type_uac2 >= 0 ? |
@@ -1406,7 +1535,7 @@ static void build_feature_ctl(struct mixer_build *state, void *raw_desc, | |||
1406 | kctl = snd_ctl_new1(&usb_feature_unit_ctl, cval); | 1535 | kctl = snd_ctl_new1(&usb_feature_unit_ctl, cval); |
1407 | 1536 | ||
1408 | if (!kctl) { | 1537 | if (!kctl) { |
1409 | usb_audio_err(state->chip, "cannot malloc kcontrol\n"); | 1538 | usb_audio_err(mixer->chip, "cannot malloc kcontrol\n"); |
1410 | kfree(cval); | 1539 | kfree(cval); |
1411 | return; | 1540 | return; |
1412 | } | 1541 | } |
@@ -1415,7 +1544,7 @@ static void build_feature_ctl(struct mixer_build *state, void *raw_desc, | |||
1415 | len = check_mapped_name(map, kctl->id.name, sizeof(kctl->id.name)); | 1544 | len = check_mapped_name(map, kctl->id.name, sizeof(kctl->id.name)); |
1416 | mapped_name = len != 0; | 1545 | mapped_name = len != 0; |
1417 | if (!len && nameid) | 1546 | if (!len && nameid) |
1418 | len = snd_usb_copy_string_desc(state, nameid, | 1547 | len = snd_usb_copy_string_desc(mixer->chip, nameid, |
1419 | kctl->id.name, sizeof(kctl->id.name)); | 1548 | kctl->id.name, sizeof(kctl->id.name)); |
1420 | 1549 | ||
1421 | switch (control) { | 1550 | switch (control) { |
@@ -1430,10 +1559,12 @@ static void build_feature_ctl(struct mixer_build *state, void *raw_desc, | |||
1430 | * - otherwise, anonymous name. | 1559 | * - otherwise, anonymous name. |
1431 | */ | 1560 | */ |
1432 | if (!len) { | 1561 | if (!len) { |
1433 | len = get_term_name(state, iterm, kctl->id.name, | 1562 | if (iterm) |
1434 | sizeof(kctl->id.name), 1); | 1563 | len = get_term_name(mixer->chip, iterm, |
1435 | if (!len) | 1564 | kctl->id.name, |
1436 | len = get_term_name(state, &state->oterm, | 1565 | sizeof(kctl->id.name), 1); |
1566 | if (!len && oterm) | ||
1567 | len = get_term_name(mixer->chip, oterm, | ||
1437 | kctl->id.name, | 1568 | kctl->id.name, |
1438 | sizeof(kctl->id.name), 1); | 1569 | sizeof(kctl->id.name), 1); |
1439 | if (!len) | 1570 | if (!len) |
@@ -1442,15 +1573,15 @@ static void build_feature_ctl(struct mixer_build *state, void *raw_desc, | |||
1442 | } | 1573 | } |
1443 | 1574 | ||
1444 | if (!mapped_name) | 1575 | if (!mapped_name) |
1445 | check_no_speaker_on_headset(kctl, state->mixer->chip->card); | 1576 | check_no_speaker_on_headset(kctl, mixer->chip->card); |
1446 | 1577 | ||
1447 | /* | 1578 | /* |
1448 | * determine the stream direction: | 1579 | * determine the stream direction: |
1449 | * if the connected output is USB stream, then it's likely a | 1580 | * if the connected output is USB stream, then it's likely a |
1450 | * capture stream. otherwise it should be playback (hopefully :) | 1581 | * capture stream. otherwise it should be playback (hopefully :) |
1451 | */ | 1582 | */ |
1452 | if (!mapped_name && !(state->oterm.type >> 16)) { | 1583 | if (!mapped_name && oterm && !(oterm->type >> 16)) { |
1453 | if ((state->oterm.type & 0xff00) == 0x0100) | 1584 | if ((oterm->type & 0xff00) == 0x0100) |
1454 | append_ctl_name(kctl, " Capture"); | 1585 | append_ctl_name(kctl, " Capture"); |
1455 | else | 1586 | else |
1456 | append_ctl_name(kctl, " Playback"); | 1587 | append_ctl_name(kctl, " Playback"); |
@@ -1478,7 +1609,7 @@ static void build_feature_ctl(struct mixer_build *state, void *raw_desc, | |||
1478 | } | 1609 | } |
1479 | } | 1610 | } |
1480 | 1611 | ||
1481 | snd_usb_mixer_fu_apply_quirk(state->mixer, cval, unitid, kctl); | 1612 | snd_usb_mixer_fu_apply_quirk(mixer, cval, unitid, kctl); |
1482 | 1613 | ||
1483 | range = (cval->max - cval->min) / cval->res; | 1614 | range = (cval->max - cval->min) / cval->res; |
1484 | /* | 1615 | /* |
@@ -1487,26 +1618,46 @@ static void build_feature_ctl(struct mixer_build *state, void *raw_desc, | |||
1487 | * devices. It will definitively catch all buggy Logitech devices. | 1618 | * devices. It will definitively catch all buggy Logitech devices. |
1488 | */ | 1619 | */ |
1489 | if (range > 384) { | 1620 | if (range > 384) { |
1490 | usb_audio_warn(state->chip, | 1621 | usb_audio_warn(mixer->chip, |
1491 | "Warning! Unlikely big volume range (=%u), cval->res is probably wrong.", | 1622 | "Warning! Unlikely big volume range (=%u), cval->res is probably wrong.", |
1492 | range); | 1623 | range); |
1493 | usb_audio_warn(state->chip, | 1624 | usb_audio_warn(mixer->chip, |
1494 | "[%d] FU [%s] ch = %d, val = %d/%d/%d", | 1625 | "[%d] FU [%s] ch = %d, val = %d/%d/%d", |
1495 | cval->head.id, kctl->id.name, cval->channels, | 1626 | cval->head.id, kctl->id.name, cval->channels, |
1496 | cval->min, cval->max, cval->res); | 1627 | cval->min, cval->max, cval->res); |
1497 | } | 1628 | } |
1498 | 1629 | ||
1499 | usb_audio_dbg(state->chip, "[%d] FU [%s] ch = %d, val = %d/%d/%d\n", | 1630 | usb_audio_dbg(mixer->chip, "[%d] FU [%s] ch = %d, val = %d/%d/%d\n", |
1500 | cval->head.id, kctl->id.name, cval->channels, | 1631 | cval->head.id, kctl->id.name, cval->channels, |
1501 | cval->min, cval->max, cval->res); | 1632 | cval->min, cval->max, cval->res); |
1502 | snd_usb_mixer_add_control(&cval->head, kctl); | 1633 | snd_usb_mixer_add_control(&cval->head, kctl); |
1503 | } | 1634 | } |
1504 | 1635 | ||
1636 | static void build_feature_ctl(struct mixer_build *state, void *raw_desc, | ||
1637 | unsigned int ctl_mask, int control, | ||
1638 | struct usb_audio_term *iterm, int unitid, | ||
1639 | int readonly_mask) | ||
1640 | { | ||
1641 | struct uac_feature_unit_descriptor *desc = raw_desc; | ||
1642 | int nameid = uac_feature_unit_iFeature(desc); | ||
1643 | |||
1644 | __build_feature_ctl(state->mixer, state->map, ctl_mask, control, | ||
1645 | iterm, &state->oterm, unitid, nameid, readonly_mask); | ||
1646 | } | ||
1647 | |||
1648 | static void build_feature_ctl_badd(struct usb_mixer_interface *mixer, | ||
1649 | unsigned int ctl_mask, int control, int unitid, | ||
1650 | const struct usbmix_name_map *badd_map) | ||
1651 | { | ||
1652 | __build_feature_ctl(mixer, badd_map, ctl_mask, control, | ||
1653 | NULL, NULL, unitid, 0, 0); | ||
1654 | } | ||
1655 | |||
1505 | static void get_connector_control_name(struct mixer_build *state, | 1656 | static void get_connector_control_name(struct mixer_build *state, |
1506 | struct usb_audio_term *term, | 1657 | struct usb_audio_term *term, |
1507 | bool is_input, char *name, int name_size) | 1658 | bool is_input, char *name, int name_size) |
1508 | { | 1659 | { |
1509 | int name_len = get_term_name(state, term, name, name_size, 0); | 1660 | int name_len = get_term_name(state->chip, term, name, name_size, 0); |
1510 | 1661 | ||
1511 | if (name_len == 0) | 1662 | if (name_len == 0) |
1512 | strlcpy(name, "Unknown", name_size); | 1663 | strlcpy(name, "Unknown", name_size); |
@@ -1534,17 +1685,25 @@ static void build_connector_control(struct mixer_build *state, | |||
1534 | return; | 1685 | return; |
1535 | snd_usb_mixer_elem_init_std(&cval->head, state->mixer, term->id); | 1686 | snd_usb_mixer_elem_init_std(&cval->head, state->mixer, term->id); |
1536 | /* | 1687 | /* |
1537 | * The first byte from reading the UAC2_TE_CONNECTOR control returns the | 1688 | * UAC2: The first byte from reading the UAC2_TE_CONNECTOR control returns the |
1538 | * number of channels connected. This boolean ctl will simply report | 1689 | * number of channels connected. |
1539 | * if any channels are connected or not. | 1690 | * |
1540 | * (Audio20_final.pdf Table 5-10: Connector Control CUR Parameter Block) | 1691 | * UAC3: The first byte specifies size of bitmap for the inserted controls. The |
1692 | * following byte(s) specifies which connectors are inserted. | ||
1693 | * | ||
1694 | * This boolean ctl will simply report if any channels are connected | ||
1695 | * or not. | ||
1541 | */ | 1696 | */ |
1542 | cval->control = UAC2_TE_CONNECTOR; | 1697 | if (state->mixer->protocol == UAC_VERSION_2) |
1698 | cval->control = UAC2_TE_CONNECTOR; | ||
1699 | else /* UAC_VERSION_3 */ | ||
1700 | cval->control = UAC3_TE_INSERTION; | ||
1701 | |||
1543 | cval->val_type = USB_MIXER_BOOLEAN; | 1702 | cval->val_type = USB_MIXER_BOOLEAN; |
1544 | cval->channels = 1; /* report true if any channel is connected */ | 1703 | cval->channels = 1; /* report true if any channel is connected */ |
1545 | cval->min = 0; | 1704 | cval->min = 0; |
1546 | cval->max = 1; | 1705 | cval->max = 1; |
1547 | kctl = snd_ctl_new1(&usb_bool_master_control_ctl_ro, cval); | 1706 | kctl = snd_ctl_new1(&usb_connector_ctl_ro, cval); |
1548 | if (!kctl) { | 1707 | if (!kctl) { |
1549 | usb_audio_err(state->chip, "cannot malloc kcontrol\n"); | 1708 | usb_audio_err(state->chip, "cannot malloc kcontrol\n"); |
1550 | kfree(cval); | 1709 | kfree(cval); |
@@ -1605,7 +1764,7 @@ static int parse_clock_source_unit(struct mixer_build *state, int unitid, | |||
1605 | } | 1764 | } |
1606 | 1765 | ||
1607 | kctl->private_free = snd_usb_mixer_elem_free; | 1766 | kctl->private_free = snd_usb_mixer_elem_free; |
1608 | ret = snd_usb_copy_string_desc(state, hdr->iClockSource, | 1767 | ret = snd_usb_copy_string_desc(state->chip, hdr->iClockSource, |
1609 | name, sizeof(name)); | 1768 | name, sizeof(name)); |
1610 | if (ret > 0) | 1769 | if (ret > 0) |
1611 | snprintf(kctl->id.name, sizeof(kctl->id.name), | 1770 | snprintf(kctl->id.name, sizeof(kctl->id.name), |
@@ -1692,7 +1851,8 @@ static int parse_audio_feature_unit(struct mixer_build *state, int unitid, | |||
1692 | } | 1851 | } |
1693 | 1852 | ||
1694 | /* parse the source unit */ | 1853 | /* parse the source unit */ |
1695 | if ((err = parse_audio_unit(state, hdr->bSourceID)) < 0) | 1854 | err = parse_audio_unit(state, hdr->bSourceID); |
1855 | if (err < 0) | ||
1696 | return err; | 1856 | return err; |
1697 | 1857 | ||
1698 | /* determine the input source type and name */ | 1858 | /* determine the input source type and name */ |
@@ -1806,16 +1966,15 @@ static int parse_audio_feature_unit(struct mixer_build *state, int unitid, | |||
1806 | */ | 1966 | */ |
1807 | static void build_mixer_unit_ctl(struct mixer_build *state, | 1967 | static void build_mixer_unit_ctl(struct mixer_build *state, |
1808 | struct uac_mixer_unit_descriptor *desc, | 1968 | struct uac_mixer_unit_descriptor *desc, |
1809 | int in_pin, int in_ch, int unitid, | 1969 | int in_pin, int in_ch, int num_outs, |
1810 | struct usb_audio_term *iterm) | 1970 | int unitid, struct usb_audio_term *iterm) |
1811 | { | 1971 | { |
1812 | struct usb_mixer_elem_info *cval; | 1972 | struct usb_mixer_elem_info *cval; |
1813 | unsigned int num_outs = uac_mixer_unit_bNrChannels(desc); | ||
1814 | unsigned int i, len; | 1973 | unsigned int i, len; |
1815 | struct snd_kcontrol *kctl; | 1974 | struct snd_kcontrol *kctl; |
1816 | const struct usbmix_name_map *map; | 1975 | const struct usbmix_name_map *map; |
1817 | 1976 | ||
1818 | map = find_map(state, unitid, 0); | 1977 | map = find_map(state->map, unitid, 0); |
1819 | if (check_ignored_ctl(map)) | 1978 | if (check_ignored_ctl(map)) |
1820 | return; | 1979 | return; |
1821 | 1980 | ||
@@ -1848,7 +2007,7 @@ static void build_mixer_unit_ctl(struct mixer_build *state, | |||
1848 | 2007 | ||
1849 | len = check_mapped_name(map, kctl->id.name, sizeof(kctl->id.name)); | 2008 | len = check_mapped_name(map, kctl->id.name, sizeof(kctl->id.name)); |
1850 | if (!len) | 2009 | if (!len) |
1851 | len = get_term_name(state, iterm, kctl->id.name, | 2010 | len = get_term_name(state->chip, iterm, kctl->id.name, |
1852 | sizeof(kctl->id.name), 0); | 2011 | sizeof(kctl->id.name), 0); |
1853 | if (!len) | 2012 | if (!len) |
1854 | len = sprintf(kctl->id.name, "Mixer Source %d", in_ch + 1); | 2013 | len = sprintf(kctl->id.name, "Mixer Source %d", in_ch + 1); |
@@ -1863,16 +2022,28 @@ static int parse_audio_input_terminal(struct mixer_build *state, int unitid, | |||
1863 | void *raw_desc) | 2022 | void *raw_desc) |
1864 | { | 2023 | { |
1865 | struct usb_audio_term iterm; | 2024 | struct usb_audio_term iterm; |
1866 | struct uac2_input_terminal_descriptor *d = raw_desc; | 2025 | unsigned int control, bmctls, term_id; |
1867 | 2026 | ||
1868 | check_input_term(state, d->bTerminalID, &iterm); | ||
1869 | if (state->mixer->protocol == UAC_VERSION_2) { | 2027 | if (state->mixer->protocol == UAC_VERSION_2) { |
1870 | /* Check for jack detection. */ | 2028 | struct uac2_input_terminal_descriptor *d_v2 = raw_desc; |
1871 | if (uac_v2v3_control_is_readable(le16_to_cpu(d->bmControls), | 2029 | control = UAC2_TE_CONNECTOR; |
1872 | UAC2_TE_CONNECTOR)) { | 2030 | term_id = d_v2->bTerminalID; |
1873 | build_connector_control(state, &iterm, true); | 2031 | bmctls = le16_to_cpu(d_v2->bmControls); |
1874 | } | 2032 | } else if (state->mixer->protocol == UAC_VERSION_3) { |
2033 | struct uac3_input_terminal_descriptor *d_v3 = raw_desc; | ||
2034 | control = UAC3_TE_INSERTION; | ||
2035 | term_id = d_v3->bTerminalID; | ||
2036 | bmctls = le32_to_cpu(d_v3->bmControls); | ||
2037 | } else { | ||
2038 | return 0; /* UAC1. No Insertion control */ | ||
1875 | } | 2039 | } |
2040 | |||
2041 | check_input_term(state, term_id, &iterm); | ||
2042 | |||
2043 | /* Check for jack detection. */ | ||
2044 | if (uac_v2v3_control_is_readable(bmctls, control)) | ||
2045 | build_connector_control(state, &iterm, true); | ||
2046 | |||
1876 | return 0; | 2047 | return 0; |
1877 | } | 2048 | } |
1878 | 2049 | ||
@@ -1887,14 +2058,17 @@ static int parse_audio_mixer_unit(struct mixer_build *state, int unitid, | |||
1887 | int input_pins, num_ins, num_outs; | 2058 | int input_pins, num_ins, num_outs; |
1888 | int pin, ich, err; | 2059 | int pin, ich, err; |
1889 | 2060 | ||
1890 | if (desc->bLength < 11 || !(input_pins = desc->bNrInPins) || | 2061 | err = uac_mixer_unit_get_channels(state, desc); |
1891 | !(num_outs = uac_mixer_unit_bNrChannels(desc))) { | 2062 | if (err < 0) { |
1892 | usb_audio_err(state->chip, | 2063 | usb_audio_err(state->chip, |
1893 | "invalid MIXER UNIT descriptor %d\n", | 2064 | "invalid MIXER UNIT descriptor %d\n", |
1894 | unitid); | 2065 | unitid); |
1895 | return -EINVAL; | 2066 | return err; |
1896 | } | 2067 | } |
1897 | 2068 | ||
2069 | num_outs = err; | ||
2070 | input_pins = desc->bNrInPins; | ||
2071 | |||
1898 | num_ins = 0; | 2072 | num_ins = 0; |
1899 | ich = 0; | 2073 | ich = 0; |
1900 | for (pin = 0; pin < input_pins; pin++) { | 2074 | for (pin = 0; pin < input_pins; pin++) { |
@@ -1921,7 +2095,7 @@ static int parse_audio_mixer_unit(struct mixer_build *state, int unitid, | |||
1921 | } | 2095 | } |
1922 | } | 2096 | } |
1923 | if (ich_has_controls) | 2097 | if (ich_has_controls) |
1924 | build_mixer_unit_ctl(state, desc, pin, ich, | 2098 | build_mixer_unit_ctl(state, desc, pin, ich, num_outs, |
1925 | unitid, &iterm); | 2099 | unitid, &iterm); |
1926 | } | 2100 | } |
1927 | } | 2101 | } |
@@ -2098,7 +2272,8 @@ static int build_audio_procunit(struct mixer_build *state, int unitid, | |||
2098 | } | 2272 | } |
2099 | 2273 | ||
2100 | for (i = 0; i < num_ins; i++) { | 2274 | for (i = 0; i < num_ins; i++) { |
2101 | if ((err = parse_audio_unit(state, desc->baSourceID[i])) < 0) | 2275 | err = parse_audio_unit(state, desc->baSourceID[i]); |
2276 | if (err < 0) | ||
2102 | return err; | 2277 | return err; |
2103 | } | 2278 | } |
2104 | 2279 | ||
@@ -2114,7 +2289,7 @@ static int build_audio_procunit(struct mixer_build *state, int unitid, | |||
2114 | 2289 | ||
2115 | if (!(controls[valinfo->control / 8] & (1 << ((valinfo->control % 8) - 1)))) | 2290 | if (!(controls[valinfo->control / 8] & (1 << ((valinfo->control % 8) - 1)))) |
2116 | continue; | 2291 | continue; |
2117 | map = find_map(state, unitid, valinfo->control); | 2292 | map = find_map(state->map, unitid, valinfo->control); |
2118 | if (check_ignored_ctl(map)) | 2293 | if (check_ignored_ctl(map)) |
2119 | continue; | 2294 | continue; |
2120 | cval = kzalloc(sizeof(*cval), GFP_KERNEL); | 2295 | cval = kzalloc(sizeof(*cval), GFP_KERNEL); |
@@ -2162,7 +2337,8 @@ static int build_audio_procunit(struct mixer_build *state, int unitid, | |||
2162 | nameid = uac_processing_unit_iProcessing(desc, state->mixer->protocol); | 2337 | nameid = uac_processing_unit_iProcessing(desc, state->mixer->protocol); |
2163 | len = 0; | 2338 | len = 0; |
2164 | if (nameid) | 2339 | if (nameid) |
2165 | len = snd_usb_copy_string_desc(state, nameid, | 2340 | len = snd_usb_copy_string_desc(state->chip, |
2341 | nameid, | ||
2166 | kctl->id.name, | 2342 | kctl->id.name, |
2167 | sizeof(kctl->id.name)); | 2343 | sizeof(kctl->id.name)); |
2168 | if (!len) | 2344 | if (!len) |
@@ -2310,14 +2486,15 @@ static int parse_audio_selector_unit(struct mixer_build *state, int unitid, | |||
2310 | } | 2486 | } |
2311 | 2487 | ||
2312 | for (i = 0; i < desc->bNrInPins; i++) { | 2488 | for (i = 0; i < desc->bNrInPins; i++) { |
2313 | if ((err = parse_audio_unit(state, desc->baSourceID[i])) < 0) | 2489 | err = parse_audio_unit(state, desc->baSourceID[i]); |
2490 | if (err < 0) | ||
2314 | return err; | 2491 | return err; |
2315 | } | 2492 | } |
2316 | 2493 | ||
2317 | if (desc->bNrInPins == 1) /* only one ? nonsense! */ | 2494 | if (desc->bNrInPins == 1) /* only one ? nonsense! */ |
2318 | return 0; | 2495 | return 0; |
2319 | 2496 | ||
2320 | map = find_map(state, unitid, 0); | 2497 | map = find_map(state->map, unitid, 0); |
2321 | if (check_ignored_ctl(map)) | 2498 | if (check_ignored_ctl(map)) |
2322 | return 0; | 2499 | return 0; |
2323 | 2500 | ||
@@ -2358,7 +2535,8 @@ static int parse_audio_selector_unit(struct mixer_build *state, int unitid, | |||
2358 | len = check_mapped_selector_name(state, unitid, i, namelist[i], | 2535 | len = check_mapped_selector_name(state, unitid, i, namelist[i], |
2359 | MAX_ITEM_NAME_LEN); | 2536 | MAX_ITEM_NAME_LEN); |
2360 | if (! len && check_input_term(state, desc->baSourceID[i], &iterm) >= 0) | 2537 | if (! len && check_input_term(state, desc->baSourceID[i], &iterm) >= 0) |
2361 | len = get_term_name(state, &iterm, namelist[i], MAX_ITEM_NAME_LEN, 0); | 2538 | len = get_term_name(state->chip, &iterm, namelist[i], |
2539 | MAX_ITEM_NAME_LEN, 0); | ||
2362 | if (! len) | 2540 | if (! len) |
2363 | sprintf(namelist[i], "Input %u", i); | 2541 | sprintf(namelist[i], "Input %u", i); |
2364 | } | 2542 | } |
@@ -2380,12 +2558,12 @@ static int parse_audio_selector_unit(struct mixer_build *state, int unitid, | |||
2380 | /* if iSelector is given, use it */ | 2558 | /* if iSelector is given, use it */ |
2381 | nameid = uac_selector_unit_iSelector(desc); | 2559 | nameid = uac_selector_unit_iSelector(desc); |
2382 | if (nameid) | 2560 | if (nameid) |
2383 | len = snd_usb_copy_string_desc(state, nameid, | 2561 | len = snd_usb_copy_string_desc(state->chip, nameid, |
2384 | kctl->id.name, | 2562 | kctl->id.name, |
2385 | sizeof(kctl->id.name)); | 2563 | sizeof(kctl->id.name)); |
2386 | /* ... or pick up the terminal name at next */ | 2564 | /* ... or pick up the terminal name at next */ |
2387 | if (!len) | 2565 | if (!len) |
2388 | len = get_term_name(state, &state->oterm, | 2566 | len = get_term_name(state->chip, &state->oterm, |
2389 | kctl->id.name, sizeof(kctl->id.name), 0); | 2567 | kctl->id.name, sizeof(kctl->id.name), 0); |
2390 | /* ... or use the fixed string "USB" as the last resort */ | 2568 | /* ... or use the fixed string "USB" as the last resort */ |
2391 | if (!len) | 2569 | if (!len) |
@@ -2458,7 +2636,7 @@ static int parse_audio_unit(struct mixer_build *state, int unitid) | |||
2458 | } else { /* UAC_VERSION_3 */ | 2636 | } else { /* UAC_VERSION_3 */ |
2459 | switch (p1[2]) { | 2637 | switch (p1[2]) { |
2460 | case UAC_INPUT_TERMINAL: | 2638 | case UAC_INPUT_TERMINAL: |
2461 | return 0; /* NOP */ | 2639 | return parse_audio_input_terminal(state, unitid, p1); |
2462 | case UAC3_MIXER_UNIT: | 2640 | case UAC3_MIXER_UNIT: |
2463 | return parse_audio_mixer_unit(state, unitid, p1); | 2641 | return parse_audio_mixer_unit(state, unitid, p1); |
2464 | case UAC3_CLOCK_SOURCE: | 2642 | case UAC3_CLOCK_SOURCE: |
@@ -2503,6 +2681,246 @@ static int snd_usb_mixer_dev_free(struct snd_device *device) | |||
2503 | return 0; | 2681 | return 0; |
2504 | } | 2682 | } |
2505 | 2683 | ||
2684 | /* UAC3 predefined channels configuration */ | ||
2685 | struct uac3_badd_profile { | ||
2686 | int subclass; | ||
2687 | const char *name; | ||
2688 | int c_chmask; /* capture channels mask */ | ||
2689 | int p_chmask; /* playback channels mask */ | ||
2690 | int st_chmask; /* side tone mixing channel mask */ | ||
2691 | }; | ||
2692 | |||
2693 | static struct uac3_badd_profile uac3_badd_profiles[] = { | ||
2694 | { | ||
2695 | /* | ||
2696 | * BAIF, BAOF or combination of both | ||
2697 | * IN: Mono or Stereo cfg, Mono alt possible | ||
2698 | * OUT: Mono or Stereo cfg, Mono alt possible | ||
2699 | */ | ||
2700 | .subclass = UAC3_FUNCTION_SUBCLASS_GENERIC_IO, | ||
2701 | .name = "GENERIC IO", | ||
2702 | .c_chmask = -1, /* dynamic channels */ | ||
2703 | .p_chmask = -1, /* dynamic channels */ | ||
2704 | }, | ||
2705 | { | ||
2706 | /* BAOF; Stereo only cfg, Mono alt possible */ | ||
2707 | .subclass = UAC3_FUNCTION_SUBCLASS_HEADPHONE, | ||
2708 | .name = "HEADPHONE", | ||
2709 | .p_chmask = 3, | ||
2710 | }, | ||
2711 | { | ||
2712 | /* BAOF; Mono or Stereo cfg, Mono alt possible */ | ||
2713 | .subclass = UAC3_FUNCTION_SUBCLASS_SPEAKER, | ||
2714 | .name = "SPEAKER", | ||
2715 | .p_chmask = -1, /* dynamic channels */ | ||
2716 | }, | ||
2717 | { | ||
2718 | /* BAIF; Mono or Stereo cfg, Mono alt possible */ | ||
2719 | .subclass = UAC3_FUNCTION_SUBCLASS_MICROPHONE, | ||
2720 | .name = "MICROPHONE", | ||
2721 | .c_chmask = -1, /* dynamic channels */ | ||
2722 | }, | ||
2723 | { | ||
2724 | /* | ||
2725 | * BAIOF topology | ||
2726 | * IN: Mono only | ||
2727 | * OUT: Mono or Stereo cfg, Mono alt possible | ||
2728 | */ | ||
2729 | .subclass = UAC3_FUNCTION_SUBCLASS_HEADSET, | ||
2730 | .name = "HEADSET", | ||
2731 | .c_chmask = 1, | ||
2732 | .p_chmask = -1, /* dynamic channels */ | ||
2733 | .st_chmask = 1, | ||
2734 | }, | ||
2735 | { | ||
2736 | /* BAIOF; IN: Mono only; OUT: Stereo only, Mono alt possible */ | ||
2737 | .subclass = UAC3_FUNCTION_SUBCLASS_HEADSET_ADAPTER, | ||
2738 | .name = "HEADSET ADAPTER", | ||
2739 | .c_chmask = 1, | ||
2740 | .p_chmask = 3, | ||
2741 | .st_chmask = 1, | ||
2742 | }, | ||
2743 | { | ||
2744 | /* BAIF + BAOF; IN: Mono only; OUT: Mono only */ | ||
2745 | .subclass = UAC3_FUNCTION_SUBCLASS_SPEAKERPHONE, | ||
2746 | .name = "SPEAKERPHONE", | ||
2747 | .c_chmask = 1, | ||
2748 | .p_chmask = 1, | ||
2749 | }, | ||
2750 | { 0 } /* terminator */ | ||
2751 | }; | ||
2752 | |||
2753 | static bool uac3_badd_func_has_valid_channels(struct usb_mixer_interface *mixer, | ||
2754 | struct uac3_badd_profile *f, | ||
2755 | int c_chmask, int p_chmask) | ||
2756 | { | ||
2757 | /* | ||
2758 | * If both playback/capture channels are dynamic, make sure | ||
2759 | * at least one channel is present | ||
2760 | */ | ||
2761 | if (f->c_chmask < 0 && f->p_chmask < 0) { | ||
2762 | if (!c_chmask && !p_chmask) { | ||
2763 | usb_audio_warn(mixer->chip, "BAAD %s: no channels?", | ||
2764 | f->name); | ||
2765 | return false; | ||
2766 | } | ||
2767 | return true; | ||
2768 | } | ||
2769 | |||
2770 | if ((f->c_chmask < 0 && !c_chmask) || | ||
2771 | (f->c_chmask >= 0 && f->c_chmask != c_chmask)) { | ||
2772 | usb_audio_warn(mixer->chip, "BAAD %s c_chmask mismatch", | ||
2773 | f->name); | ||
2774 | return false; | ||
2775 | } | ||
2776 | if ((f->p_chmask < 0 && !p_chmask) || | ||
2777 | (f->p_chmask >= 0 && f->p_chmask != p_chmask)) { | ||
2778 | usb_audio_warn(mixer->chip, "BAAD %s p_chmask mismatch", | ||
2779 | f->name); | ||
2780 | return false; | ||
2781 | } | ||
2782 | return true; | ||
2783 | } | ||
2784 | |||
2785 | /* | ||
2786 | * create mixer controls for UAC3 BADD profiles | ||
2787 | * | ||
2788 | * UAC3 BADD device doesn't contain CS descriptors thus we will guess everything | ||
2789 | * | ||
2790 | * BADD device may contain Mixer Unit, which doesn't have any controls, skip it | ||
2791 | */ | ||
2792 | static int snd_usb_mixer_controls_badd(struct usb_mixer_interface *mixer, | ||
2793 | int ctrlif) | ||
2794 | { | ||
2795 | struct usb_device *dev = mixer->chip->dev; | ||
2796 | struct usb_interface_assoc_descriptor *assoc; | ||
2797 | int badd_profile = mixer->chip->badd_profile; | ||
2798 | struct uac3_badd_profile *f; | ||
2799 | const struct usbmix_ctl_map *map; | ||
2800 | int p_chmask = 0, c_chmask = 0, st_chmask = 0; | ||
2801 | int i; | ||
2802 | |||
2803 | assoc = usb_ifnum_to_if(dev, ctrlif)->intf_assoc; | ||
2804 | |||
2805 | /* Detect BADD capture/playback channels from AS EP descriptors */ | ||
2806 | for (i = 0; i < assoc->bInterfaceCount; i++) { | ||
2807 | int intf = assoc->bFirstInterface + i; | ||
2808 | |||
2809 | struct usb_interface *iface; | ||
2810 | struct usb_host_interface *alts; | ||
2811 | struct usb_interface_descriptor *altsd; | ||
2812 | unsigned int maxpacksize; | ||
2813 | char dir_in; | ||
2814 | int chmask, num; | ||
2815 | |||
2816 | if (intf == ctrlif) | ||
2817 | continue; | ||
2818 | |||
2819 | iface = usb_ifnum_to_if(dev, intf); | ||
2820 | num = iface->num_altsetting; | ||
2821 | |||
2822 | if (num < 2) | ||
2823 | return -EINVAL; | ||
2824 | |||
2825 | /* | ||
2826 | * The number of Channels in an AudioStreaming interface | ||
2827 | * and the audio sample bit resolution (16 bits or 24 | ||
2828 | * bits) can be derived from the wMaxPacketSize field in | ||
2829 | * the Standard AS Audio Data Endpoint descriptor in | ||
2830 | * Alternate Setting 1 | ||
2831 | */ | ||
2832 | alts = &iface->altsetting[1]; | ||
2833 | altsd = get_iface_desc(alts); | ||
2834 | |||
2835 | if (altsd->bNumEndpoints < 1) | ||
2836 | return -EINVAL; | ||
2837 | |||
2838 | /* check direction */ | ||
2839 | dir_in = (get_endpoint(alts, 0)->bEndpointAddress & USB_DIR_IN); | ||
2840 | maxpacksize = le16_to_cpu(get_endpoint(alts, 0)->wMaxPacketSize); | ||
2841 | |||
2842 | switch (maxpacksize) { | ||
2843 | default: | ||
2844 | usb_audio_err(mixer->chip, | ||
2845 | "incorrect wMaxPacketSize 0x%x for BADD profile\n", | ||
2846 | maxpacksize); | ||
2847 | return -EINVAL; | ||
2848 | case UAC3_BADD_EP_MAXPSIZE_SYNC_MONO_16: | ||
2849 | case UAC3_BADD_EP_MAXPSIZE_ASYNC_MONO_16: | ||
2850 | case UAC3_BADD_EP_MAXPSIZE_SYNC_MONO_24: | ||
2851 | case UAC3_BADD_EP_MAXPSIZE_ASYNC_MONO_24: | ||
2852 | chmask = 1; | ||
2853 | break; | ||
2854 | case UAC3_BADD_EP_MAXPSIZE_SYNC_STEREO_16: | ||
2855 | case UAC3_BADD_EP_MAXPSIZE_ASYNC_STEREO_16: | ||
2856 | case UAC3_BADD_EP_MAXPSIZE_SYNC_STEREO_24: | ||
2857 | case UAC3_BADD_EP_MAXPSIZE_ASYNC_STEREO_24: | ||
2858 | chmask = 3; | ||
2859 | break; | ||
2860 | } | ||
2861 | |||
2862 | if (dir_in) | ||
2863 | c_chmask = chmask; | ||
2864 | else | ||
2865 | p_chmask = chmask; | ||
2866 | } | ||
2867 | |||
2868 | usb_audio_dbg(mixer->chip, | ||
2869 | "UAC3 BADD profile 0x%x: detected c_chmask=%d p_chmask=%d\n", | ||
2870 | badd_profile, c_chmask, p_chmask); | ||
2871 | |||
2872 | /* check the mapping table */ | ||
2873 | for (map = uac3_badd_usbmix_ctl_maps; map->id; map++) { | ||
2874 | if (map->id == badd_profile) | ||
2875 | break; | ||
2876 | } | ||
2877 | |||
2878 | if (!map->id) | ||
2879 | return -EINVAL; | ||
2880 | |||
2881 | for (f = uac3_badd_profiles; f->name; f++) { | ||
2882 | if (badd_profile == f->subclass) | ||
2883 | break; | ||
2884 | } | ||
2885 | if (!f->name) | ||
2886 | return -EINVAL; | ||
2887 | if (!uac3_badd_func_has_valid_channels(mixer, f, c_chmask, p_chmask)) | ||
2888 | return -EINVAL; | ||
2889 | st_chmask = f->st_chmask; | ||
2890 | |||
2891 | /* Playback */ | ||
2892 | if (p_chmask) { | ||
2893 | /* Master channel, always writable */ | ||
2894 | build_feature_ctl_badd(mixer, 0, UAC_FU_MUTE, | ||
2895 | UAC3_BADD_FU_ID2, map->map); | ||
2896 | /* Mono/Stereo volume channels, always writable */ | ||
2897 | build_feature_ctl_badd(mixer, p_chmask, UAC_FU_VOLUME, | ||
2898 | UAC3_BADD_FU_ID2, map->map); | ||
2899 | } | ||
2900 | |||
2901 | /* Capture */ | ||
2902 | if (c_chmask) { | ||
2903 | /* Master channel, always writable */ | ||
2904 | build_feature_ctl_badd(mixer, 0, UAC_FU_MUTE, | ||
2905 | UAC3_BADD_FU_ID5, map->map); | ||
2906 | /* Mono/Stereo volume channels, always writable */ | ||
2907 | build_feature_ctl_badd(mixer, c_chmask, UAC_FU_VOLUME, | ||
2908 | UAC3_BADD_FU_ID5, map->map); | ||
2909 | } | ||
2910 | |||
2911 | /* Side tone-mixing */ | ||
2912 | if (st_chmask) { | ||
2913 | /* Master channel, always writable */ | ||
2914 | build_feature_ctl_badd(mixer, 0, UAC_FU_MUTE, | ||
2915 | UAC3_BADD_FU_ID7, map->map); | ||
2916 | /* Mono volume channel, always writable */ | ||
2917 | build_feature_ctl_badd(mixer, 1, UAC_FU_VOLUME, | ||
2918 | UAC3_BADD_FU_ID7, map->map); | ||
2919 | } | ||
2920 | |||
2921 | return 0; | ||
2922 | } | ||
2923 | |||
2506 | /* | 2924 | /* |
2507 | * create mixer controls | 2925 | * create mixer controls |
2508 | * | 2926 | * |
@@ -2596,6 +3014,12 @@ static int snd_usb_mixer_controls(struct usb_mixer_interface *mixer) | |||
2596 | err = parse_audio_unit(&state, desc->bCSourceID); | 3014 | err = parse_audio_unit(&state, desc->bCSourceID); |
2597 | if (err < 0 && err != -EINVAL) | 3015 | if (err < 0 && err != -EINVAL) |
2598 | return err; | 3016 | return err; |
3017 | |||
3018 | if (uac_v2v3_control_is_readable(le32_to_cpu(desc->bmControls), | ||
3019 | UAC3_TE_INSERTION)) { | ||
3020 | build_connector_control(&state, &state.oterm, | ||
3021 | false); | ||
3022 | } | ||
2599 | } | 3023 | } |
2600 | } | 3024 | } |
2601 | 3025 | ||
@@ -2606,9 +3030,9 @@ void snd_usb_mixer_notify_id(struct usb_mixer_interface *mixer, int unitid) | |||
2606 | { | 3030 | { |
2607 | struct usb_mixer_elem_list *list; | 3031 | struct usb_mixer_elem_list *list; |
2608 | 3032 | ||
2609 | for (list = mixer->id_elems[unitid]; list; list = list->next_id_elem) { | 3033 | for_each_mixer_elem(list, mixer, unitid) { |
2610 | struct usb_mixer_elem_info *info = | 3034 | struct usb_mixer_elem_info *info = |
2611 | (struct usb_mixer_elem_info *)list; | 3035 | mixer_elem_list_to_info(list); |
2612 | /* invalidate cache, so the value is read from the device */ | 3036 | /* invalidate cache, so the value is read from the device */ |
2613 | info->cached = 0; | 3037 | info->cached = 0; |
2614 | snd_ctl_notify(mixer->chip->card, SNDRV_CTL_EVENT_MASK_VALUE, | 3038 | snd_ctl_notify(mixer->chip->card, SNDRV_CTL_EVENT_MASK_VALUE, |
@@ -2619,7 +3043,7 @@ void snd_usb_mixer_notify_id(struct usb_mixer_interface *mixer, int unitid) | |||
2619 | static void snd_usb_mixer_dump_cval(struct snd_info_buffer *buffer, | 3043 | static void snd_usb_mixer_dump_cval(struct snd_info_buffer *buffer, |
2620 | struct usb_mixer_elem_list *list) | 3044 | struct usb_mixer_elem_list *list) |
2621 | { | 3045 | { |
2622 | struct usb_mixer_elem_info *cval = (struct usb_mixer_elem_info *)list; | 3046 | struct usb_mixer_elem_info *cval = mixer_elem_list_to_info(list); |
2623 | static char *val_types[] = {"BOOLEAN", "INV_BOOLEAN", | 3047 | static char *val_types[] = {"BOOLEAN", "INV_BOOLEAN", |
2624 | "S8", "U8", "S16", "U16"}; | 3048 | "S8", "U8", "S16", "U16"}; |
2625 | snd_iprintf(buffer, " Info: id=%i, control=%i, cmask=0x%x, " | 3049 | snd_iprintf(buffer, " Info: id=%i, control=%i, cmask=0x%x, " |
@@ -2645,8 +3069,7 @@ static void snd_usb_mixer_proc_read(struct snd_info_entry *entry, | |||
2645 | mixer->ignore_ctl_error); | 3069 | mixer->ignore_ctl_error); |
2646 | snd_iprintf(buffer, "Card: %s\n", chip->card->longname); | 3070 | snd_iprintf(buffer, "Card: %s\n", chip->card->longname); |
2647 | for (unitid = 0; unitid < MAX_ID_ELEMS; unitid++) { | 3071 | for (unitid = 0; unitid < MAX_ID_ELEMS; unitid++) { |
2648 | for (list = mixer->id_elems[unitid]; list; | 3072 | for_each_mixer_elem(list, mixer, unitid) { |
2649 | list = list->next_id_elem) { | ||
2650 | snd_iprintf(buffer, " Unit: %i\n", list->id); | 3073 | snd_iprintf(buffer, " Unit: %i\n", list->id); |
2651 | if (list->kctl) | 3074 | if (list->kctl) |
2652 | snd_iprintf(buffer, | 3075 | snd_iprintf(buffer, |
@@ -2676,19 +3099,19 @@ static void snd_usb_mixer_interrupt_v2(struct usb_mixer_interface *mixer, | |||
2676 | return; | 3099 | return; |
2677 | } | 3100 | } |
2678 | 3101 | ||
2679 | for (list = mixer->id_elems[unitid]; list; list = list->next_id_elem) | 3102 | for_each_mixer_elem(list, mixer, unitid) |
2680 | count++; | 3103 | count++; |
2681 | 3104 | ||
2682 | if (count == 0) | 3105 | if (count == 0) |
2683 | return; | 3106 | return; |
2684 | 3107 | ||
2685 | for (list = mixer->id_elems[unitid]; list; list = list->next_id_elem) { | 3108 | for_each_mixer_elem(list, mixer, unitid) { |
2686 | struct usb_mixer_elem_info *info; | 3109 | struct usb_mixer_elem_info *info; |
2687 | 3110 | ||
2688 | if (!list->kctl) | 3111 | if (!list->kctl) |
2689 | continue; | 3112 | continue; |
2690 | 3113 | ||
2691 | info = (struct usb_mixer_elem_info *)list; | 3114 | info = mixer_elem_list_to_info(list); |
2692 | if (count > 1 && info->control != control) | 3115 | if (count > 1 && info->control != control) |
2693 | continue; | 3116 | continue; |
2694 | 3117 | ||
@@ -2809,6 +3232,48 @@ static int snd_usb_mixer_status_create(struct usb_mixer_interface *mixer) | |||
2809 | return 0; | 3232 | return 0; |
2810 | } | 3233 | } |
2811 | 3234 | ||
3235 | static int keep_iface_ctl_get(struct snd_kcontrol *kcontrol, | ||
3236 | struct snd_ctl_elem_value *ucontrol) | ||
3237 | { | ||
3238 | struct usb_mixer_interface *mixer = snd_kcontrol_chip(kcontrol); | ||
3239 | |||
3240 | ucontrol->value.integer.value[0] = mixer->chip->keep_iface; | ||
3241 | return 0; | ||
3242 | } | ||
3243 | |||
3244 | static int keep_iface_ctl_put(struct snd_kcontrol *kcontrol, | ||
3245 | struct snd_ctl_elem_value *ucontrol) | ||
3246 | { | ||
3247 | struct usb_mixer_interface *mixer = snd_kcontrol_chip(kcontrol); | ||
3248 | bool keep_iface = !!ucontrol->value.integer.value[0]; | ||
3249 | |||
3250 | if (mixer->chip->keep_iface == keep_iface) | ||
3251 | return 0; | ||
3252 | mixer->chip->keep_iface = keep_iface; | ||
3253 | return 1; | ||
3254 | } | ||
3255 | |||
3256 | static const struct snd_kcontrol_new keep_iface_ctl = { | ||
3257 | .iface = SNDRV_CTL_ELEM_IFACE_CARD, | ||
3258 | .name = "Keep Interface", | ||
3259 | .info = snd_ctl_boolean_mono_info, | ||
3260 | .get = keep_iface_ctl_get, | ||
3261 | .put = keep_iface_ctl_put, | ||
3262 | }; | ||
3263 | |||
3264 | static int create_keep_iface_ctl(struct usb_mixer_interface *mixer) | ||
3265 | { | ||
3266 | struct snd_kcontrol *kctl = snd_ctl_new1(&keep_iface_ctl, mixer); | ||
3267 | |||
3268 | /* need only one control per card */ | ||
3269 | if (snd_ctl_find_id(mixer->chip->card, &kctl->id)) { | ||
3270 | snd_ctl_free_one(kctl); | ||
3271 | return 0; | ||
3272 | } | ||
3273 | |||
3274 | return snd_ctl_add(mixer->chip->card, kctl); | ||
3275 | } | ||
3276 | |||
2812 | int snd_usb_create_mixer(struct snd_usb_audio *chip, int ctrlif, | 3277 | int snd_usb_create_mixer(struct snd_usb_audio *chip, int ctrlif, |
2813 | int ignore_error) | 3278 | int ignore_error) |
2814 | { | 3279 | { |
@@ -2847,8 +3312,21 @@ int snd_usb_create_mixer(struct snd_usb_audio *chip, int ctrlif, | |||
2847 | break; | 3312 | break; |
2848 | } | 3313 | } |
2849 | 3314 | ||
2850 | if ((err = snd_usb_mixer_controls(mixer)) < 0 || | 3315 | if (mixer->protocol == UAC_VERSION_3 && |
2851 | (err = snd_usb_mixer_status_create(mixer)) < 0) | 3316 | chip->badd_profile >= UAC3_FUNCTION_SUBCLASS_GENERIC_IO) { |
3317 | err = snd_usb_mixer_controls_badd(mixer, ctrlif); | ||
3318 | if (err < 0) | ||
3319 | goto _error; | ||
3320 | } else { | ||
3321 | err = snd_usb_mixer_controls(mixer); | ||
3322 | if (err < 0) | ||
3323 | goto _error; | ||
3324 | err = snd_usb_mixer_status_create(mixer); | ||
3325 | if (err < 0) | ||
3326 | goto _error; | ||
3327 | } | ||
3328 | err = create_keep_iface_ctl(mixer); | ||
3329 | if (err < 0) | ||
2852 | goto _error; | 3330 | goto _error; |
2853 | 3331 | ||
2854 | snd_usb_mixer_apply_create_quirk(mixer); | 3332 | snd_usb_mixer_apply_create_quirk(mixer); |
@@ -2909,7 +3387,7 @@ int snd_usb_mixer_suspend(struct usb_mixer_interface *mixer) | |||
2909 | 3387 | ||
2910 | static int restore_mixer_value(struct usb_mixer_elem_list *list) | 3388 | static int restore_mixer_value(struct usb_mixer_elem_list *list) |
2911 | { | 3389 | { |
2912 | struct usb_mixer_elem_info *cval = (struct usb_mixer_elem_info *)list; | 3390 | struct usb_mixer_elem_info *cval = mixer_elem_list_to_info(list); |
2913 | int c, err, idx; | 3391 | int c, err, idx; |
2914 | 3392 | ||
2915 | if (cval->cmask) { | 3393 | if (cval->cmask) { |
@@ -2945,8 +3423,7 @@ int snd_usb_mixer_resume(struct usb_mixer_interface *mixer, bool reset_resume) | |||
2945 | if (reset_resume) { | 3423 | if (reset_resume) { |
2946 | /* restore cached mixer values */ | 3424 | /* restore cached mixer values */ |
2947 | for (id = 0; id < MAX_ID_ELEMS; id++) { | 3425 | for (id = 0; id < MAX_ID_ELEMS; id++) { |
2948 | for (list = mixer->id_elems[id]; list; | 3426 | for_each_mixer_elem(list, mixer, id) { |
2949 | list = list->next_id_elem) { | ||
2950 | if (list->resume) { | 3427 | if (list->resume) { |
2951 | err = list->resume(list); | 3428 | err = list->resume(list); |
2952 | if (err < 0) | 3429 | if (err < 0) |
@@ -2956,6 +3433,8 @@ int snd_usb_mixer_resume(struct usb_mixer_interface *mixer, bool reset_resume) | |||
2956 | } | 3433 | } |
2957 | } | 3434 | } |
2958 | 3435 | ||
3436 | snd_usb_mixer_resume_quirk(mixer); | ||
3437 | |||
2959 | return snd_usb_mixer_activate(mixer); | 3438 | return snd_usb_mixer_activate(mixer); |
2960 | } | 3439 | } |
2961 | #endif | 3440 | #endif |
diff --git a/sound/usb/mixer.h b/sound/usb/mixer.h index ba27f7ade670..e02653465e29 100644 --- a/sound/usb/mixer.h +++ b/sound/usb/mixer.h | |||
@@ -53,6 +53,12 @@ struct usb_mixer_elem_list { | |||
53 | usb_mixer_elem_resume_func_t resume; | 53 | usb_mixer_elem_resume_func_t resume; |
54 | }; | 54 | }; |
55 | 55 | ||
56 | /* iterate over mixer element list of the given unit id */ | ||
57 | #define for_each_mixer_elem(list, mixer, id) \ | ||
58 | for ((list) = (mixer)->id_elems[id]; (list); (list) = (list)->next_id_elem) | ||
59 | #define mixer_elem_list_to_info(list) \ | ||
60 | container_of(list, struct usb_mixer_elem_info, head) | ||
61 | |||
56 | struct usb_mixer_elem_info { | 62 | struct usb_mixer_elem_info { |
57 | struct usb_mixer_elem_list head; | 63 | struct usb_mixer_elem_list head; |
58 | unsigned int control; /* CS or ICN (high byte) */ | 64 | unsigned int control; /* CS or ICN (high byte) */ |
diff --git a/sound/usb/mixer_maps.c b/sound/usb/mixer_maps.c index eaa03acd4686..71069e110897 100644 --- a/sound/usb/mixer_maps.c +++ b/sound/usb/mixer_maps.c | |||
@@ -485,3 +485,68 @@ static struct usbmix_ctl_map usbmix_ctl_maps[] = { | |||
485 | { 0 } /* terminator */ | 485 | { 0 } /* terminator */ |
486 | }; | 486 | }; |
487 | 487 | ||
488 | /* | ||
489 | * Control map entries for UAC3 BADD profiles | ||
490 | */ | ||
491 | |||
492 | static struct usbmix_name_map uac3_badd_generic_io_map[] = { | ||
493 | { UAC3_BADD_FU_ID2, "Generic Out Playback" }, | ||
494 | { UAC3_BADD_FU_ID5, "Generic In Capture" }, | ||
495 | { 0 } /* terminator */ | ||
496 | }; | ||
497 | static struct usbmix_name_map uac3_badd_headphone_map[] = { | ||
498 | { UAC3_BADD_FU_ID2, "Headphone Playback" }, | ||
499 | { 0 } /* terminator */ | ||
500 | }; | ||
501 | static struct usbmix_name_map uac3_badd_speaker_map[] = { | ||
502 | { UAC3_BADD_FU_ID2, "Speaker Playback" }, | ||
503 | { 0 } /* terminator */ | ||
504 | }; | ||
505 | static struct usbmix_name_map uac3_badd_microphone_map[] = { | ||
506 | { UAC3_BADD_FU_ID5, "Mic Capture" }, | ||
507 | { 0 } /* terminator */ | ||
508 | }; | ||
509 | /* Covers also 'headset adapter' profile */ | ||
510 | static struct usbmix_name_map uac3_badd_headset_map[] = { | ||
511 | { UAC3_BADD_FU_ID2, "Headset Playback" }, | ||
512 | { UAC3_BADD_FU_ID5, "Headset Capture" }, | ||
513 | { UAC3_BADD_FU_ID7, "Sidetone Mixing" }, | ||
514 | { 0 } /* terminator */ | ||
515 | }; | ||
516 | static struct usbmix_name_map uac3_badd_speakerphone_map[] = { | ||
517 | { UAC3_BADD_FU_ID2, "Speaker Playback" }, | ||
518 | { UAC3_BADD_FU_ID5, "Mic Capture" }, | ||
519 | { 0 } /* terminator */ | ||
520 | }; | ||
521 | |||
522 | static struct usbmix_ctl_map uac3_badd_usbmix_ctl_maps[] = { | ||
523 | { | ||
524 | .id = UAC3_FUNCTION_SUBCLASS_GENERIC_IO, | ||
525 | .map = uac3_badd_generic_io_map, | ||
526 | }, | ||
527 | { | ||
528 | .id = UAC3_FUNCTION_SUBCLASS_HEADPHONE, | ||
529 | .map = uac3_badd_headphone_map, | ||
530 | }, | ||
531 | { | ||
532 | .id = UAC3_FUNCTION_SUBCLASS_SPEAKER, | ||
533 | .map = uac3_badd_speaker_map, | ||
534 | }, | ||
535 | { | ||
536 | .id = UAC3_FUNCTION_SUBCLASS_MICROPHONE, | ||
537 | .map = uac3_badd_microphone_map, | ||
538 | }, | ||
539 | { | ||
540 | .id = UAC3_FUNCTION_SUBCLASS_HEADSET, | ||
541 | .map = uac3_badd_headset_map, | ||
542 | }, | ||
543 | { | ||
544 | .id = UAC3_FUNCTION_SUBCLASS_HEADSET_ADAPTER, | ||
545 | .map = uac3_badd_headset_map, | ||
546 | }, | ||
547 | { | ||
548 | .id = UAC3_FUNCTION_SUBCLASS_SPEAKERPHONE, | ||
549 | .map = uac3_badd_speakerphone_map, | ||
550 | }, | ||
551 | { 0 } /* terminator */ | ||
552 | }; | ||
diff --git a/sound/usb/mixer_quirks.c b/sound/usb/mixer_quirks.c index 56537a156580..4149543f613e 100644 --- a/sound/usb/mixer_quirks.c +++ b/sound/usb/mixer_quirks.c | |||
@@ -1172,7 +1172,7 @@ void snd_emuusb_set_samplerate(struct snd_usb_audio *chip, | |||
1172 | int unitid = 12; /* SamleRate ExtensionUnit ID */ | 1172 | int unitid = 12; /* SamleRate ExtensionUnit ID */ |
1173 | 1173 | ||
1174 | list_for_each_entry(mixer, &chip->mixer_list, list) { | 1174 | list_for_each_entry(mixer, &chip->mixer_list, list) { |
1175 | cval = (struct usb_mixer_elem_info *)mixer->id_elems[unitid]; | 1175 | cval = mixer_elem_list_to_info(mixer->id_elems[unitid]); |
1176 | if (cval) { | 1176 | if (cval) { |
1177 | snd_usb_mixer_set_ctl_value(cval, UAC_SET_CUR, | 1177 | snd_usb_mixer_set_ctl_value(cval, UAC_SET_CUR, |
1178 | cval->control << 8, | 1178 | cval->control << 8, |
@@ -1799,12 +1799,33 @@ static int snd_soundblaster_e1_switch_create(struct usb_mixer_interface *mixer) | |||
1799 | NULL); | 1799 | NULL); |
1800 | } | 1800 | } |
1801 | 1801 | ||
1802 | static void dell_dock_init_vol(struct snd_usb_audio *chip, int ch, int id) | ||
1803 | { | ||
1804 | u16 buf = 0; | ||
1805 | |||
1806 | snd_usb_ctl_msg(chip->dev, usb_sndctrlpipe(chip->dev, 0), UAC_SET_CUR, | ||
1807 | USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_OUT, | ||
1808 | ch, snd_usb_ctrl_intf(chip) | (id << 8), | ||
1809 | &buf, 2); | ||
1810 | } | ||
1811 | |||
1812 | static int dell_dock_mixer_init(struct usb_mixer_interface *mixer) | ||
1813 | { | ||
1814 | /* fix to 0dB playback volumes */ | ||
1815 | dell_dock_init_vol(mixer->chip, 1, 16); | ||
1816 | dell_dock_init_vol(mixer->chip, 2, 16); | ||
1817 | dell_dock_init_vol(mixer->chip, 1, 19); | ||
1818 | dell_dock_init_vol(mixer->chip, 2, 19); | ||
1819 | return 0; | ||
1820 | } | ||
1821 | |||
1802 | int snd_usb_mixer_apply_create_quirk(struct usb_mixer_interface *mixer) | 1822 | int snd_usb_mixer_apply_create_quirk(struct usb_mixer_interface *mixer) |
1803 | { | 1823 | { |
1804 | int err = 0; | 1824 | int err = 0; |
1805 | struct snd_info_entry *entry; | 1825 | struct snd_info_entry *entry; |
1806 | 1826 | ||
1807 | if ((err = snd_usb_soundblaster_remote_init(mixer)) < 0) | 1827 | err = snd_usb_soundblaster_remote_init(mixer); |
1828 | if (err < 0) | ||
1808 | return err; | 1829 | return err; |
1809 | 1830 | ||
1810 | switch (mixer->chip->usb_id) { | 1831 | switch (mixer->chip->usb_id) { |
@@ -1884,11 +1905,25 @@ int snd_usb_mixer_apply_create_quirk(struct usb_mixer_interface *mixer) | |||
1884 | case USB_ID(0x041e, 0x323b): /* Creative Sound Blaster E1 */ | 1905 | case USB_ID(0x041e, 0x323b): /* Creative Sound Blaster E1 */ |
1885 | err = snd_soundblaster_e1_switch_create(mixer); | 1906 | err = snd_soundblaster_e1_switch_create(mixer); |
1886 | break; | 1907 | break; |
1908 | case USB_ID(0x0bda, 0x4014): /* Dell WD15 dock */ | ||
1909 | err = dell_dock_mixer_init(mixer); | ||
1910 | break; | ||
1887 | } | 1911 | } |
1888 | 1912 | ||
1889 | return err; | 1913 | return err; |
1890 | } | 1914 | } |
1891 | 1915 | ||
1916 | #ifdef CONFIG_PM | ||
1917 | void snd_usb_mixer_resume_quirk(struct usb_mixer_interface *mixer) | ||
1918 | { | ||
1919 | switch (mixer->chip->usb_id) { | ||
1920 | case USB_ID(0x0bda, 0x4014): /* Dell WD15 dock */ | ||
1921 | dell_dock_mixer_init(mixer); | ||
1922 | break; | ||
1923 | } | ||
1924 | } | ||
1925 | #endif | ||
1926 | |||
1892 | void snd_usb_mixer_rc_memory_change(struct usb_mixer_interface *mixer, | 1927 | void snd_usb_mixer_rc_memory_change(struct usb_mixer_interface *mixer, |
1893 | int unitid) | 1928 | int unitid) |
1894 | { | 1929 | { |
diff --git a/sound/usb/mixer_quirks.h b/sound/usb/mixer_quirks.h index b5abd328a361..52be26db558f 100644 --- a/sound/usb/mixer_quirks.h +++ b/sound/usb/mixer_quirks.h | |||
@@ -14,5 +14,9 @@ void snd_usb_mixer_fu_apply_quirk(struct usb_mixer_interface *mixer, | |||
14 | struct usb_mixer_elem_info *cval, int unitid, | 14 | struct usb_mixer_elem_info *cval, int unitid, |
15 | struct snd_kcontrol *kctl); | 15 | struct snd_kcontrol *kctl); |
16 | 16 | ||
17 | #ifdef CONFIG_PM | ||
18 | void snd_usb_mixer_resume_quirk(struct usb_mixer_interface *mixer); | ||
19 | #endif | ||
20 | |||
17 | #endif /* SND_USB_MIXER_QUIRKS_H */ | 21 | #endif /* SND_USB_MIXER_QUIRKS_H */ |
18 | 22 | ||
diff --git a/sound/usb/mixer_scarlett.c b/sound/usb/mixer_scarlett.c index c33e2378089d..4aeb9488a0c9 100644 --- a/sound/usb/mixer_scarlett.c +++ b/sound/usb/mixer_scarlett.c | |||
@@ -287,8 +287,7 @@ static int scarlett_ctl_switch_put(struct snd_kcontrol *kctl, | |||
287 | 287 | ||
288 | static int scarlett_ctl_resume(struct usb_mixer_elem_list *list) | 288 | static int scarlett_ctl_resume(struct usb_mixer_elem_list *list) |
289 | { | 289 | { |
290 | struct usb_mixer_elem_info *elem = | 290 | struct usb_mixer_elem_info *elem = mixer_elem_list_to_info(list); |
291 | container_of(list, struct usb_mixer_elem_info, head); | ||
292 | int i; | 291 | int i; |
293 | 292 | ||
294 | for (i = 0; i < elem->channels; i++) | 293 | for (i = 0; i < elem->channels; i++) |
@@ -447,8 +446,7 @@ static int scarlett_ctl_enum_put(struct snd_kcontrol *kctl, | |||
447 | 446 | ||
448 | static int scarlett_ctl_enum_resume(struct usb_mixer_elem_list *list) | 447 | static int scarlett_ctl_enum_resume(struct usb_mixer_elem_list *list) |
449 | { | 448 | { |
450 | struct usb_mixer_elem_info *elem = | 449 | struct usb_mixer_elem_info *elem = mixer_elem_list_to_info(list); |
451 | container_of(list, struct usb_mixer_elem_info, head); | ||
452 | 450 | ||
453 | if (elem->cached) | 451 | if (elem->cached) |
454 | snd_usb_set_cur_mix_value(elem, 0, 0, *elem->cache_val); | 452 | snd_usb_set_cur_mix_value(elem, 0, 0, *elem->cache_val); |
diff --git a/sound/usb/pcm.c b/sound/usb/pcm.c index 3cbfae6604f9..78d1cad08a0a 100644 --- a/sound/usb/pcm.c +++ b/sound/usb/pcm.c | |||
@@ -76,10 +76,9 @@ snd_pcm_uframes_t snd_usb_pcm_delay(struct snd_usb_substream *subs, | |||
76 | */ | 76 | */ |
77 | static snd_pcm_uframes_t snd_usb_pcm_pointer(struct snd_pcm_substream *substream) | 77 | static snd_pcm_uframes_t snd_usb_pcm_pointer(struct snd_pcm_substream *substream) |
78 | { | 78 | { |
79 | struct snd_usb_substream *subs; | 79 | struct snd_usb_substream *subs = substream->runtime->private_data; |
80 | unsigned int hwptr_done; | 80 | unsigned int hwptr_done; |
81 | 81 | ||
82 | subs = (struct snd_usb_substream *)substream->runtime->private_data; | ||
83 | if (atomic_read(&subs->stream->chip->shutdown)) | 82 | if (atomic_read(&subs->stream->chip->shutdown)) |
84 | return SNDRV_PCM_POS_XRUN; | 83 | return SNDRV_PCM_POS_XRUN; |
85 | spin_lock(&subs->lock); | 84 | spin_lock(&subs->lock); |
@@ -164,10 +163,11 @@ static int init_pitch_v1(struct snd_usb_audio *chip, int iface, | |||
164 | ep = get_endpoint(alts, 0)->bEndpointAddress; | 163 | ep = get_endpoint(alts, 0)->bEndpointAddress; |
165 | 164 | ||
166 | data[0] = 1; | 165 | data[0] = 1; |
167 | if ((err = snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0), UAC_SET_CUR, | 166 | err = snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0), UAC_SET_CUR, |
168 | USB_TYPE_CLASS|USB_RECIP_ENDPOINT|USB_DIR_OUT, | 167 | USB_TYPE_CLASS|USB_RECIP_ENDPOINT|USB_DIR_OUT, |
169 | UAC_EP_CS_ATTR_PITCH_CONTROL << 8, ep, | 168 | UAC_EP_CS_ATTR_PITCH_CONTROL << 8, ep, |
170 | data, sizeof(data))) < 0) { | 169 | data, sizeof(data)); |
170 | if (err < 0) { | ||
171 | usb_audio_err(chip, "%d:%d: cannot set enable PITCH\n", | 171 | usb_audio_err(chip, "%d:%d: cannot set enable PITCH\n", |
172 | iface, ep); | 172 | iface, ep); |
173 | return err; | 173 | return err; |
@@ -185,10 +185,11 @@ static int init_pitch_v2(struct snd_usb_audio *chip, int iface, | |||
185 | int err; | 185 | int err; |
186 | 186 | ||
187 | data[0] = 1; | 187 | data[0] = 1; |
188 | if ((err = snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0), UAC2_CS_CUR, | 188 | err = snd_usb_ctl_msg(dev, usb_sndctrlpipe(dev, 0), UAC2_CS_CUR, |
189 | USB_TYPE_CLASS | USB_RECIP_ENDPOINT | USB_DIR_OUT, | 189 | USB_TYPE_CLASS | USB_RECIP_ENDPOINT | USB_DIR_OUT, |
190 | UAC2_EP_CS_PITCH << 8, 0, | 190 | UAC2_EP_CS_PITCH << 8, 0, |
191 | data, sizeof(data))) < 0) { | 191 | data, sizeof(data)); |
192 | if (err < 0) { | ||
192 | usb_audio_err(chip, "%d:%d: cannot set enable PITCH (v2)\n", | 193 | usb_audio_err(chip, "%d:%d: cannot set enable PITCH (v2)\n", |
193 | iface, fmt->altsetting); | 194 | iface, fmt->altsetting); |
194 | return err; | 195 | return err; |
@@ -321,6 +322,7 @@ static int set_sync_ep_implicit_fb_quirk(struct snd_usb_substream *subs, | |||
321 | struct usb_host_interface *alts; | 322 | struct usb_host_interface *alts; |
322 | struct usb_interface *iface; | 323 | struct usb_interface *iface; |
323 | unsigned int ep; | 324 | unsigned int ep; |
325 | unsigned int ifnum; | ||
324 | 326 | ||
325 | /* Implicit feedback sync EPs consumers are always playback EPs */ | 327 | /* Implicit feedback sync EPs consumers are always playback EPs */ |
326 | if (subs->direction != SNDRV_PCM_STREAM_PLAYBACK) | 328 | if (subs->direction != SNDRV_PCM_STREAM_PLAYBACK) |
@@ -330,44 +332,27 @@ static int set_sync_ep_implicit_fb_quirk(struct snd_usb_substream *subs, | |||
330 | case USB_ID(0x0763, 0x2030): /* M-Audio Fast Track C400 */ | 332 | case USB_ID(0x0763, 0x2030): /* M-Audio Fast Track C400 */ |
331 | case USB_ID(0x0763, 0x2031): /* M-Audio Fast Track C600 */ | 333 | case USB_ID(0x0763, 0x2031): /* M-Audio Fast Track C600 */ |
332 | ep = 0x81; | 334 | ep = 0x81; |
333 | iface = usb_ifnum_to_if(dev, 3); | 335 | ifnum = 3; |
334 | 336 | goto add_sync_ep_from_ifnum; | |
335 | if (!iface || iface->num_altsetting == 0) | ||
336 | return -EINVAL; | ||
337 | |||
338 | alts = &iface->altsetting[1]; | ||
339 | goto add_sync_ep; | ||
340 | break; | ||
341 | case USB_ID(0x0763, 0x2080): /* M-Audio FastTrack Ultra */ | 337 | case USB_ID(0x0763, 0x2080): /* M-Audio FastTrack Ultra */ |
342 | case USB_ID(0x0763, 0x2081): | 338 | case USB_ID(0x0763, 0x2081): |
343 | ep = 0x81; | 339 | ep = 0x81; |
344 | iface = usb_ifnum_to_if(dev, 2); | 340 | ifnum = 2; |
345 | 341 | goto add_sync_ep_from_ifnum; | |
346 | if (!iface || iface->num_altsetting == 0) | 342 | case USB_ID(0x2466, 0x8003): /* Fractal Audio Axe-Fx II */ |
347 | return -EINVAL; | ||
348 | |||
349 | alts = &iface->altsetting[1]; | ||
350 | goto add_sync_ep; | ||
351 | case USB_ID(0x2466, 0x8003): | ||
352 | ep = 0x86; | 343 | ep = 0x86; |
353 | iface = usb_ifnum_to_if(dev, 2); | 344 | ifnum = 2; |
354 | 345 | goto add_sync_ep_from_ifnum; | |
355 | if (!iface || iface->num_altsetting == 0) | 346 | case USB_ID(0x2466, 0x8010): /* Fractal Audio Axe-Fx III */ |
356 | return -EINVAL; | ||
357 | |||
358 | alts = &iface->altsetting[1]; | ||
359 | goto add_sync_ep; | ||
360 | case USB_ID(0x1397, 0x0002): | ||
361 | ep = 0x81; | 347 | ep = 0x81; |
362 | iface = usb_ifnum_to_if(dev, 1); | 348 | ifnum = 2; |
363 | 349 | goto add_sync_ep_from_ifnum; | |
364 | if (!iface || iface->num_altsetting == 0) | 350 | case USB_ID(0x1397, 0x0002): /* Behringer UFX1204 */ |
365 | return -EINVAL; | 351 | ep = 0x81; |
366 | 352 | ifnum = 1; | |
367 | alts = &iface->altsetting[1]; | 353 | goto add_sync_ep_from_ifnum; |
368 | goto add_sync_ep; | ||
369 | |||
370 | } | 354 | } |
355 | |||
371 | if (attr == USB_ENDPOINT_SYNC_ASYNC && | 356 | if (attr == USB_ENDPOINT_SYNC_ASYNC && |
372 | altsd->bInterfaceClass == USB_CLASS_VENDOR_SPEC && | 357 | altsd->bInterfaceClass == USB_CLASS_VENDOR_SPEC && |
373 | altsd->bInterfaceProtocol == 2 && | 358 | altsd->bInterfaceProtocol == 2 && |
@@ -382,6 +367,14 @@ static int set_sync_ep_implicit_fb_quirk(struct snd_usb_substream *subs, | |||
382 | /* No quirk */ | 367 | /* No quirk */ |
383 | return 0; | 368 | return 0; |
384 | 369 | ||
370 | add_sync_ep_from_ifnum: | ||
371 | iface = usb_ifnum_to_if(dev, ifnum); | ||
372 | |||
373 | if (!iface || iface->num_altsetting == 0) | ||
374 | return -EINVAL; | ||
375 | |||
376 | alts = &iface->altsetting[1]; | ||
377 | |||
385 | add_sync_ep: | 378 | add_sync_ep: |
386 | subs->sync_endpoint = snd_usb_add_endpoint(subs->stream->chip, | 379 | subs->sync_endpoint = snd_usb_add_endpoint(subs->stream->chip, |
387 | alts, ep, !subs->direction, | 380 | alts, ep, !subs->direction, |
@@ -507,7 +500,7 @@ static int set_format(struct snd_usb_substream *subs, struct audioformat *fmt) | |||
507 | iface = usb_ifnum_to_if(dev, fmt->iface); | 500 | iface = usb_ifnum_to_if(dev, fmt->iface); |
508 | if (WARN_ON(!iface)) | 501 | if (WARN_ON(!iface)) |
509 | return -EINVAL; | 502 | return -EINVAL; |
510 | alts = &iface->altsetting[fmt->altset_idx]; | 503 | alts = usb_altnum_to_altsetting(iface, fmt->altsetting); |
511 | altsd = get_iface_desc(alts); | 504 | altsd = get_iface_desc(alts); |
512 | if (WARN_ON(altsd->bAlternateSetting != fmt->altsetting)) | 505 | if (WARN_ON(altsd->bAlternateSetting != fmt->altsetting)) |
513 | return -EINVAL; | 506 | return -EINVAL; |
@@ -517,21 +510,21 @@ static int set_format(struct snd_usb_substream *subs, struct audioformat *fmt) | |||
517 | 510 | ||
518 | /* close the old interface */ | 511 | /* close the old interface */ |
519 | if (subs->interface >= 0 && subs->interface != fmt->iface) { | 512 | if (subs->interface >= 0 && subs->interface != fmt->iface) { |
520 | err = usb_set_interface(subs->dev, subs->interface, 0); | 513 | if (!subs->stream->chip->keep_iface) { |
521 | if (err < 0) { | 514 | err = usb_set_interface(subs->dev, subs->interface, 0); |
522 | dev_err(&dev->dev, | 515 | if (err < 0) { |
523 | "%d:%d: return to setting 0 failed (%d)\n", | 516 | dev_err(&dev->dev, |
524 | fmt->iface, fmt->altsetting, err); | 517 | "%d:%d: return to setting 0 failed (%d)\n", |
525 | return -EIO; | 518 | fmt->iface, fmt->altsetting, err); |
519 | return -EIO; | ||
520 | } | ||
526 | } | 521 | } |
527 | subs->interface = -1; | 522 | subs->interface = -1; |
528 | subs->altset_idx = 0; | 523 | subs->altset_idx = 0; |
529 | } | 524 | } |
530 | 525 | ||
531 | /* set interface */ | 526 | /* set interface */ |
532 | if (subs->interface != fmt->iface || | 527 | if (iface->cur_altsetting != alts) { |
533 | subs->altset_idx != fmt->altset_idx) { | ||
534 | |||
535 | err = snd_usb_select_mode_quirk(subs, fmt); | 528 | err = snd_usb_select_mode_quirk(subs, fmt); |
536 | if (err < 0) | 529 | if (err < 0) |
537 | return -EIO; | 530 | return -EIO; |
@@ -545,12 +538,11 @@ static int set_format(struct snd_usb_substream *subs, struct audioformat *fmt) | |||
545 | } | 538 | } |
546 | dev_dbg(&dev->dev, "setting usb interface %d:%d\n", | 539 | dev_dbg(&dev->dev, "setting usb interface %d:%d\n", |
547 | fmt->iface, fmt->altsetting); | 540 | fmt->iface, fmt->altsetting); |
548 | subs->interface = fmt->iface; | ||
549 | subs->altset_idx = fmt->altset_idx; | ||
550 | |||
551 | snd_usb_set_interface_quirk(dev); | 541 | snd_usb_set_interface_quirk(dev); |
552 | } | 542 | } |
553 | 543 | ||
544 | subs->interface = fmt->iface; | ||
545 | subs->altset_idx = fmt->altset_idx; | ||
554 | subs->data_endpoint = snd_usb_add_endpoint(subs->stream->chip, | 546 | subs->data_endpoint = snd_usb_add_endpoint(subs->stream->chip, |
555 | alts, fmt->endpoint, subs->direction, | 547 | alts, fmt->endpoint, subs->direction, |
556 | SND_USB_ENDPOINT_TYPE_DATA); | 548 | SND_USB_ENDPOINT_TYPE_DATA); |
@@ -736,7 +728,11 @@ static int snd_usb_hw_params(struct snd_pcm_substream *substream, | |||
736 | struct audioformat *fmt; | 728 | struct audioformat *fmt; |
737 | int ret; | 729 | int ret; |
738 | 730 | ||
739 | ret = snd_pcm_lib_alloc_vmalloc_buffer(substream, | 731 | if (snd_usb_use_vmalloc) |
732 | ret = snd_pcm_lib_alloc_vmalloc_buffer(substream, | ||
733 | params_buffer_bytes(hw_params)); | ||
734 | else | ||
735 | ret = snd_pcm_lib_malloc_pages(substream, | ||
740 | params_buffer_bytes(hw_params)); | 736 | params_buffer_bytes(hw_params)); |
741 | if (ret < 0) | 737 | if (ret < 0) |
742 | return ret; | 738 | return ret; |
@@ -789,7 +785,11 @@ static int snd_usb_hw_free(struct snd_pcm_substream *substream) | |||
789 | snd_usb_endpoint_deactivate(subs->data_endpoint); | 785 | snd_usb_endpoint_deactivate(subs->data_endpoint); |
790 | snd_usb_unlock_shutdown(subs->stream->chip); | 786 | snd_usb_unlock_shutdown(subs->stream->chip); |
791 | } | 787 | } |
792 | return snd_pcm_lib_free_vmalloc_buffer(substream); | 788 | |
789 | if (snd_usb_use_vmalloc) | ||
790 | return snd_pcm_lib_free_vmalloc_buffer(substream); | ||
791 | else | ||
792 | return snd_pcm_lib_free_pages(substream); | ||
793 | } | 793 | } |
794 | 794 | ||
795 | /* | 795 | /* |
@@ -1181,9 +1181,6 @@ static int setup_hw_info(struct snd_pcm_runtime *runtime, struct snd_usb_substre | |||
1181 | pt = 125 * (1 << fp->datainterval); | 1181 | pt = 125 * (1 << fp->datainterval); |
1182 | ptmin = min(ptmin, pt); | 1182 | ptmin = min(ptmin, pt); |
1183 | } | 1183 | } |
1184 | err = snd_usb_autoresume(subs->stream->chip); | ||
1185 | if (err < 0) | ||
1186 | return err; | ||
1187 | 1184 | ||
1188 | param_period_time_if_needed = SNDRV_PCM_HW_PARAM_PERIOD_TIME; | 1185 | param_period_time_if_needed = SNDRV_PCM_HW_PARAM_PERIOD_TIME; |
1189 | if (subs->speed == USB_SPEED_FULL) | 1186 | if (subs->speed == USB_SPEED_FULL) |
@@ -1192,30 +1189,37 @@ static int setup_hw_info(struct snd_pcm_runtime *runtime, struct snd_usb_substre | |||
1192 | if (ptmin == 1000) | 1189 | if (ptmin == 1000) |
1193 | /* if period time doesn't go below 1 ms, no rules needed */ | 1190 | /* if period time doesn't go below 1 ms, no rules needed */ |
1194 | param_period_time_if_needed = -1; | 1191 | param_period_time_if_needed = -1; |
1195 | snd_pcm_hw_constraint_minmax(runtime, SNDRV_PCM_HW_PARAM_PERIOD_TIME, | 1192 | |
1196 | ptmin, UINT_MAX); | 1193 | err = snd_pcm_hw_constraint_minmax(runtime, |
1197 | 1194 | SNDRV_PCM_HW_PARAM_PERIOD_TIME, | |
1198 | if ((err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, | 1195 | ptmin, UINT_MAX); |
1199 | hw_rule_rate, subs, | 1196 | if (err < 0) |
1200 | SNDRV_PCM_HW_PARAM_FORMAT, | 1197 | return err; |
1201 | SNDRV_PCM_HW_PARAM_CHANNELS, | 1198 | |
1202 | param_period_time_if_needed, | 1199 | err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, |
1203 | -1)) < 0) | 1200 | hw_rule_rate, subs, |
1204 | goto rep_err; | 1201 | SNDRV_PCM_HW_PARAM_FORMAT, |
1205 | if ((err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, | 1202 | SNDRV_PCM_HW_PARAM_CHANNELS, |
1206 | hw_rule_channels, subs, | 1203 | param_period_time_if_needed, |
1207 | SNDRV_PCM_HW_PARAM_FORMAT, | 1204 | -1); |
1208 | SNDRV_PCM_HW_PARAM_RATE, | 1205 | if (err < 0) |
1209 | param_period_time_if_needed, | 1206 | return err; |
1210 | -1)) < 0) | 1207 | err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, |
1211 | goto rep_err; | 1208 | hw_rule_channels, subs, |
1212 | if ((err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_FORMAT, | 1209 | SNDRV_PCM_HW_PARAM_FORMAT, |
1213 | hw_rule_format, subs, | 1210 | SNDRV_PCM_HW_PARAM_RATE, |
1214 | SNDRV_PCM_HW_PARAM_RATE, | 1211 | param_period_time_if_needed, |
1215 | SNDRV_PCM_HW_PARAM_CHANNELS, | 1212 | -1); |
1216 | param_period_time_if_needed, | 1213 | if (err < 0) |
1217 | -1)) < 0) | 1214 | return err; |
1218 | goto rep_err; | 1215 | err = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_FORMAT, |
1216 | hw_rule_format, subs, | ||
1217 | SNDRV_PCM_HW_PARAM_RATE, | ||
1218 | SNDRV_PCM_HW_PARAM_CHANNELS, | ||
1219 | param_period_time_if_needed, | ||
1220 | -1); | ||
1221 | if (err < 0) | ||
1222 | return err; | ||
1219 | if (param_period_time_if_needed >= 0) { | 1223 | if (param_period_time_if_needed >= 0) { |
1220 | err = snd_pcm_hw_rule_add(runtime, 0, | 1224 | err = snd_pcm_hw_rule_add(runtime, 0, |
1221 | SNDRV_PCM_HW_PARAM_PERIOD_TIME, | 1225 | SNDRV_PCM_HW_PARAM_PERIOD_TIME, |
@@ -1225,19 +1229,18 @@ static int setup_hw_info(struct snd_pcm_runtime *runtime, struct snd_usb_substre | |||
1225 | SNDRV_PCM_HW_PARAM_RATE, | 1229 | SNDRV_PCM_HW_PARAM_RATE, |
1226 | -1); | 1230 | -1); |
1227 | if (err < 0) | 1231 | if (err < 0) |
1228 | goto rep_err; | 1232 | return err; |
1229 | } | 1233 | } |
1230 | if ((err = snd_usb_pcm_check_knot(runtime, subs)) < 0) | 1234 | err = snd_usb_pcm_check_knot(runtime, subs); |
1231 | goto rep_err; | 1235 | if (err < 0) |
1232 | return 0; | 1236 | return err; |
1233 | 1237 | ||
1234 | rep_err: | 1238 | return snd_usb_autoresume(subs->stream->chip); |
1235 | snd_usb_autosuspend(subs->stream->chip); | ||
1236 | return err; | ||
1237 | } | 1239 | } |
1238 | 1240 | ||
1239 | static int snd_usb_pcm_open(struct snd_pcm_substream *substream, int direction) | 1241 | static int snd_usb_pcm_open(struct snd_pcm_substream *substream) |
1240 | { | 1242 | { |
1243 | int direction = substream->stream; | ||
1241 | struct snd_usb_stream *as = snd_pcm_substream_chip(substream); | 1244 | struct snd_usb_stream *as = snd_pcm_substream_chip(substream); |
1242 | struct snd_pcm_runtime *runtime = substream->runtime; | 1245 | struct snd_pcm_runtime *runtime = substream->runtime; |
1243 | struct snd_usb_substream *subs = &as->substream[direction]; | 1246 | struct snd_usb_substream *subs = &as->substream[direction]; |
@@ -1257,14 +1260,16 @@ static int snd_usb_pcm_open(struct snd_pcm_substream *substream, int direction) | |||
1257 | return setup_hw_info(runtime, subs); | 1260 | return setup_hw_info(runtime, subs); |
1258 | } | 1261 | } |
1259 | 1262 | ||
1260 | static int snd_usb_pcm_close(struct snd_pcm_substream *substream, int direction) | 1263 | static int snd_usb_pcm_close(struct snd_pcm_substream *substream) |
1261 | { | 1264 | { |
1265 | int direction = substream->stream; | ||
1262 | struct snd_usb_stream *as = snd_pcm_substream_chip(substream); | 1266 | struct snd_usb_stream *as = snd_pcm_substream_chip(substream); |
1263 | struct snd_usb_substream *subs = &as->substream[direction]; | 1267 | struct snd_usb_substream *subs = &as->substream[direction]; |
1264 | 1268 | ||
1265 | stop_endpoints(subs, true); | 1269 | stop_endpoints(subs, true); |
1266 | 1270 | ||
1267 | if (subs->interface >= 0 && | 1271 | if (!as->chip->keep_iface && |
1272 | subs->interface >= 0 && | ||
1268 | !snd_usb_lock_shutdown(subs->stream->chip)) { | 1273 | !snd_usb_lock_shutdown(subs->stream->chip)) { |
1269 | usb_set_interface(subs->dev, subs->interface, 0); | 1274 | usb_set_interface(subs->dev, subs->interface, 0); |
1270 | subs->interface = -1; | 1275 | subs->interface = -1; |
@@ -1311,7 +1316,7 @@ static void retire_capture_urb(struct snd_usb_substream *subs, | |||
1311 | if (bytes % (runtime->sample_bits >> 3) != 0) { | 1316 | if (bytes % (runtime->sample_bits >> 3) != 0) { |
1312 | int oldbytes = bytes; | 1317 | int oldbytes = bytes; |
1313 | bytes = frames * stride; | 1318 | bytes = frames * stride; |
1314 | dev_warn(&subs->dev->dev, | 1319 | dev_warn_ratelimited(&subs->dev->dev, |
1315 | "Corrected urb data len. %d->%d\n", | 1320 | "Corrected urb data len. %d->%d\n", |
1316 | oldbytes, bytes); | 1321 | oldbytes, bytes); |
1317 | } | 1322 | } |
@@ -1619,26 +1624,6 @@ static void retire_playback_urb(struct snd_usb_substream *subs, | |||
1619 | spin_unlock_irqrestore(&subs->lock, flags); | 1624 | spin_unlock_irqrestore(&subs->lock, flags); |
1620 | } | 1625 | } |
1621 | 1626 | ||
1622 | static int snd_usb_playback_open(struct snd_pcm_substream *substream) | ||
1623 | { | ||
1624 | return snd_usb_pcm_open(substream, SNDRV_PCM_STREAM_PLAYBACK); | ||
1625 | } | ||
1626 | |||
1627 | static int snd_usb_playback_close(struct snd_pcm_substream *substream) | ||
1628 | { | ||
1629 | return snd_usb_pcm_close(substream, SNDRV_PCM_STREAM_PLAYBACK); | ||
1630 | } | ||
1631 | |||
1632 | static int snd_usb_capture_open(struct snd_pcm_substream *substream) | ||
1633 | { | ||
1634 | return snd_usb_pcm_open(substream, SNDRV_PCM_STREAM_CAPTURE); | ||
1635 | } | ||
1636 | |||
1637 | static int snd_usb_capture_close(struct snd_pcm_substream *substream) | ||
1638 | { | ||
1639 | return snd_usb_pcm_close(substream, SNDRV_PCM_STREAM_CAPTURE); | ||
1640 | } | ||
1641 | |||
1642 | static int snd_usb_substream_playback_trigger(struct snd_pcm_substream *substream, | 1627 | static int snd_usb_substream_playback_trigger(struct snd_pcm_substream *substream, |
1643 | int cmd) | 1628 | int cmd) |
1644 | { | 1629 | { |
@@ -1700,8 +1685,8 @@ static int snd_usb_substream_capture_trigger(struct snd_pcm_substream *substream | |||
1700 | } | 1685 | } |
1701 | 1686 | ||
1702 | static const struct snd_pcm_ops snd_usb_playback_ops = { | 1687 | static const struct snd_pcm_ops snd_usb_playback_ops = { |
1703 | .open = snd_usb_playback_open, | 1688 | .open = snd_usb_pcm_open, |
1704 | .close = snd_usb_playback_close, | 1689 | .close = snd_usb_pcm_close, |
1705 | .ioctl = snd_pcm_lib_ioctl, | 1690 | .ioctl = snd_pcm_lib_ioctl, |
1706 | .hw_params = snd_usb_hw_params, | 1691 | .hw_params = snd_usb_hw_params, |
1707 | .hw_free = snd_usb_hw_free, | 1692 | .hw_free = snd_usb_hw_free, |
@@ -1713,8 +1698,8 @@ static const struct snd_pcm_ops snd_usb_playback_ops = { | |||
1713 | }; | 1698 | }; |
1714 | 1699 | ||
1715 | static const struct snd_pcm_ops snd_usb_capture_ops = { | 1700 | static const struct snd_pcm_ops snd_usb_capture_ops = { |
1716 | .open = snd_usb_capture_open, | 1701 | .open = snd_usb_pcm_open, |
1717 | .close = snd_usb_capture_close, | 1702 | .close = snd_usb_pcm_close, |
1718 | .ioctl = snd_pcm_lib_ioctl, | 1703 | .ioctl = snd_pcm_lib_ioctl, |
1719 | .hw_params = snd_usb_hw_params, | 1704 | .hw_params = snd_usb_hw_params, |
1720 | .hw_free = snd_usb_hw_free, | 1705 | .hw_free = snd_usb_hw_free, |
@@ -1725,9 +1710,50 @@ static const struct snd_pcm_ops snd_usb_capture_ops = { | |||
1725 | .mmap = snd_pcm_lib_mmap_vmalloc, | 1710 | .mmap = snd_pcm_lib_mmap_vmalloc, |
1726 | }; | 1711 | }; |
1727 | 1712 | ||
1713 | static const struct snd_pcm_ops snd_usb_playback_dev_ops = { | ||
1714 | .open = snd_usb_pcm_open, | ||
1715 | .close = snd_usb_pcm_close, | ||
1716 | .ioctl = snd_pcm_lib_ioctl, | ||
1717 | .hw_params = snd_usb_hw_params, | ||
1718 | .hw_free = snd_usb_hw_free, | ||
1719 | .prepare = snd_usb_pcm_prepare, | ||
1720 | .trigger = snd_usb_substream_playback_trigger, | ||
1721 | .pointer = snd_usb_pcm_pointer, | ||
1722 | .page = snd_pcm_sgbuf_ops_page, | ||
1723 | }; | ||
1724 | |||
1725 | static const struct snd_pcm_ops snd_usb_capture_dev_ops = { | ||
1726 | .open = snd_usb_pcm_open, | ||
1727 | .close = snd_usb_pcm_close, | ||
1728 | .ioctl = snd_pcm_lib_ioctl, | ||
1729 | .hw_params = snd_usb_hw_params, | ||
1730 | .hw_free = snd_usb_hw_free, | ||
1731 | .prepare = snd_usb_pcm_prepare, | ||
1732 | .trigger = snd_usb_substream_capture_trigger, | ||
1733 | .pointer = snd_usb_pcm_pointer, | ||
1734 | .page = snd_pcm_sgbuf_ops_page, | ||
1735 | }; | ||
1736 | |||
1728 | void snd_usb_set_pcm_ops(struct snd_pcm *pcm, int stream) | 1737 | void snd_usb_set_pcm_ops(struct snd_pcm *pcm, int stream) |
1729 | { | 1738 | { |
1730 | snd_pcm_set_ops(pcm, stream, | 1739 | const struct snd_pcm_ops *ops; |
1731 | stream == SNDRV_PCM_STREAM_PLAYBACK ? | 1740 | |
1732 | &snd_usb_playback_ops : &snd_usb_capture_ops); | 1741 | if (snd_usb_use_vmalloc) |
1742 | ops = stream == SNDRV_PCM_STREAM_PLAYBACK ? | ||
1743 | &snd_usb_playback_ops : &snd_usb_capture_ops; | ||
1744 | else | ||
1745 | ops = stream == SNDRV_PCM_STREAM_PLAYBACK ? | ||
1746 | &snd_usb_playback_dev_ops : &snd_usb_capture_dev_ops; | ||
1747 | snd_pcm_set_ops(pcm, stream, ops); | ||
1748 | } | ||
1749 | |||
1750 | void snd_usb_preallocate_buffer(struct snd_usb_substream *subs) | ||
1751 | { | ||
1752 | struct snd_pcm *pcm = subs->stream->pcm; | ||
1753 | struct snd_pcm_substream *s = pcm->streams[subs->direction].substream; | ||
1754 | struct device *dev = subs->dev->bus->controller; | ||
1755 | |||
1756 | if (!snd_usb_use_vmalloc) | ||
1757 | snd_pcm_lib_preallocate_pages(s, SNDRV_DMA_TYPE_DEV_SG, | ||
1758 | dev, 64*1024, 512*1024); | ||
1733 | } | 1759 | } |
diff --git a/sound/usb/pcm.h b/sound/usb/pcm.h index 35740d5ef268..f77ec58bf1a1 100644 --- a/sound/usb/pcm.h +++ b/sound/usb/pcm.h | |||
@@ -10,6 +10,7 @@ void snd_usb_set_pcm_ops(struct snd_pcm *pcm, int stream); | |||
10 | int snd_usb_init_pitch(struct snd_usb_audio *chip, int iface, | 10 | int snd_usb_init_pitch(struct snd_usb_audio *chip, int iface, |
11 | struct usb_host_interface *alts, | 11 | struct usb_host_interface *alts, |
12 | struct audioformat *fmt); | 12 | struct audioformat *fmt); |
13 | void snd_usb_preallocate_buffer(struct snd_usb_substream *subs); | ||
13 | 14 | ||
14 | 15 | ||
15 | #endif /* __USBAUDIO_PCM_H */ | 16 | #endif /* __USBAUDIO_PCM_H */ |
diff --git a/sound/usb/quirks-table.h b/sound/usb/quirks-table.h index 754e632a27bd..0e37e358ca97 100644 --- a/sound/usb/quirks-table.h +++ b/sound/usb/quirks-table.h | |||
@@ -3371,5 +3371,15 @@ AU0828_DEVICE(0x2040, 0x7270, "Hauppauge", "HVR-950Q"), | |||
3371 | } | 3371 | } |
3372 | } | 3372 | } |
3373 | }, | 3373 | }, |
3374 | /* Dell WD15 Dock */ | ||
3375 | { | ||
3376 | USB_DEVICE(0x0bda, 0x4014), | ||
3377 | .driver_info = (unsigned long) & (const struct snd_usb_audio_quirk) { | ||
3378 | .vendor_name = "Dell", | ||
3379 | .product_name = "WD15 Dock", | ||
3380 | .profile_name = "Dell-WD15-Dock", | ||
3381 | .ifnum = QUIRK_NO_INTERFACE | ||
3382 | } | ||
3383 | }, | ||
3374 | 3384 | ||
3375 | #undef USB_DEVICE_VENDOR_SPEC | 3385 | #undef USB_DEVICE_VENDOR_SPEC |
diff --git a/sound/usb/quirks.c b/sound/usb/quirks.c index acbeb52f6fd6..f4b69173682c 100644 --- a/sound/usb/quirks.c +++ b/sound/usb/quirks.c | |||
@@ -851,6 +851,36 @@ static int snd_usb_mbox2_boot_quirk(struct usb_device *dev) | |||
851 | return 0; /* Successful boot */ | 851 | return 0; /* Successful boot */ |
852 | } | 852 | } |
853 | 853 | ||
854 | static int snd_usb_axefx3_boot_quirk(struct usb_device *dev) | ||
855 | { | ||
856 | int err; | ||
857 | |||
858 | dev_dbg(&dev->dev, "Waiting for Axe-Fx III to boot up...\n"); | ||
859 | |||
860 | /* If the Axe-Fx III has not fully booted, it will timeout when trying | ||
861 | * to enable the audio streaming interface. A more generous timeout is | ||
862 | * used here to detect when the Axe-Fx III has finished booting as the | ||
863 | * set interface message will be acked once it has | ||
864 | */ | ||
865 | err = usb_control_msg(dev, usb_sndctrlpipe(dev, 0), | ||
866 | USB_REQ_SET_INTERFACE, USB_RECIP_INTERFACE, | ||
867 | 1, 1, NULL, 0, 120000); | ||
868 | if (err < 0) { | ||
869 | dev_err(&dev->dev, | ||
870 | "failed waiting for Axe-Fx III to boot: %d\n", err); | ||
871 | return err; | ||
872 | } | ||
873 | |||
874 | dev_dbg(&dev->dev, "Axe-Fx III is now ready\n"); | ||
875 | |||
876 | err = usb_set_interface(dev, 1, 0); | ||
877 | if (err < 0) | ||
878 | dev_dbg(&dev->dev, | ||
879 | "error stopping Axe-Fx III interface: %d\n", err); | ||
880 | |||
881 | return 0; | ||
882 | } | ||
883 | |||
854 | /* | 884 | /* |
855 | * Setup quirks | 885 | * Setup quirks |
856 | */ | 886 | */ |
@@ -1026,6 +1056,8 @@ int snd_usb_apply_boot_quirk(struct usb_device *dev, | |||
1026 | return snd_usb_fasttrackpro_boot_quirk(dev); | 1056 | return snd_usb_fasttrackpro_boot_quirk(dev); |
1027 | case USB_ID(0x047f, 0xc010): /* Plantronics Gamecom 780 */ | 1057 | case USB_ID(0x047f, 0xc010): /* Plantronics Gamecom 780 */ |
1028 | return snd_usb_gamecon780_boot_quirk(dev); | 1058 | return snd_usb_gamecon780_boot_quirk(dev); |
1059 | case USB_ID(0x2466, 0x8010): /* Fractal Audio Axe-Fx 3 */ | ||
1060 | return snd_usb_axefx3_boot_quirk(dev); | ||
1029 | } | 1061 | } |
1030 | 1062 | ||
1031 | return 0; | 1063 | return 0; |
@@ -1327,20 +1359,47 @@ u64 snd_usb_interface_dsd_format_quirks(struct snd_usb_audio *chip, | |||
1327 | 1359 | ||
1328 | /* XMOS based USB DACs */ | 1360 | /* XMOS based USB DACs */ |
1329 | switch (chip->usb_id) { | 1361 | switch (chip->usb_id) { |
1362 | case USB_ID(0x1511, 0x0037): /* AURALiC VEGA */ | ||
1363 | case USB_ID(0x20b1, 0x0002): /* Wyred 4 Sound DAC-2 DSD */ | ||
1364 | case USB_ID(0x20b1, 0x2004): /* Matrix Audio X-SPDIF 2 */ | ||
1330 | case USB_ID(0x20b1, 0x3008): /* iFi Audio micro/nano iDSD */ | 1365 | case USB_ID(0x20b1, 0x3008): /* iFi Audio micro/nano iDSD */ |
1331 | case USB_ID(0x20b1, 0x2008): /* Matrix Audio X-Sabre */ | 1366 | case USB_ID(0x20b1, 0x2008): /* Matrix Audio X-Sabre */ |
1332 | case USB_ID(0x20b1, 0x300a): /* Matrix Audio Mini-i Pro */ | 1367 | case USB_ID(0x20b1, 0x300a): /* Matrix Audio Mini-i Pro */ |
1333 | case USB_ID(0x22d9, 0x0416): /* OPPO HA-1 */ | 1368 | case USB_ID(0x22d9, 0x0416): /* OPPO HA-1 */ |
1369 | case USB_ID(0x22d9, 0x0436): /* OPPO Sonica */ | ||
1370 | case USB_ID(0x22d9, 0x0461): /* OPPO UDP-205 */ | ||
1371 | case USB_ID(0x2522, 0x0012): /* LH Labs VI DAC Infinity */ | ||
1372 | case USB_ID(0x25ce, 0x001f): /* Mytek Brooklyn DAC */ | ||
1373 | case USB_ID(0x25ce, 0x0021): /* Mytek Manhattan DAC */ | ||
1374 | case USB_ID(0x25ce, 0x8025): /* Mytek Brooklyn DAC+ */ | ||
1334 | case USB_ID(0x2772, 0x0230): /* Pro-Ject Pre Box S2 Digital */ | 1375 | case USB_ID(0x2772, 0x0230): /* Pro-Ject Pre Box S2 Digital */ |
1335 | if (fp->altsetting == 2) | 1376 | if (fp->altsetting == 2) |
1336 | return SNDRV_PCM_FMTBIT_DSD_U32_BE; | 1377 | return SNDRV_PCM_FMTBIT_DSD_U32_BE; |
1337 | break; | 1378 | break; |
1338 | 1379 | ||
1380 | case USB_ID(0x0d8c, 0x0316): /* Hegel HD12 DSD */ | ||
1381 | case USB_ID(0x16b0, 0x06b2): /* NuPrime DAC-10 */ | ||
1382 | case USB_ID(0x16d0, 0x0733): /* Furutech ADL Stratos */ | ||
1383 | case USB_ID(0x16d0, 0x09db): /* NuPrime Audio DAC-9 */ | ||
1384 | case USB_ID(0x1db5, 0x0003): /* Bryston BDA3 */ | ||
1339 | case USB_ID(0x20b1, 0x000a): /* Gustard DAC-X20U */ | 1385 | case USB_ID(0x20b1, 0x000a): /* Gustard DAC-X20U */ |
1386 | case USB_ID(0x20b1, 0x2005): /* Denafrips Ares DAC */ | ||
1340 | case USB_ID(0x20b1, 0x2009): /* DIYINHK DSD DXD 384kHz USB to I2S/DSD */ | 1387 | case USB_ID(0x20b1, 0x2009): /* DIYINHK DSD DXD 384kHz USB to I2S/DSD */ |
1341 | case USB_ID(0x20b1, 0x2023): /* JLsounds I2SoverUSB */ | 1388 | case USB_ID(0x20b1, 0x2023): /* JLsounds I2SoverUSB */ |
1389 | case USB_ID(0x20b1, 0x3021): /* Eastern El. MiniMax Tube DAC Supreme */ | ||
1342 | case USB_ID(0x20b1, 0x3023): /* Aune X1S 32BIT/384 DSD DAC */ | 1390 | case USB_ID(0x20b1, 0x3023): /* Aune X1S 32BIT/384 DSD DAC */ |
1391 | case USB_ID(0x20b1, 0x302d): /* Unison Research Unico CD Due */ | ||
1392 | case USB_ID(0x20b1, 0x3036): /* Holo Springs Level 3 R2R DAC */ | ||
1393 | case USB_ID(0x20b1, 0x307b): /* CH Precision C1 DAC */ | ||
1394 | case USB_ID(0x20b1, 0x3086): /* Singxer F-1 converter board */ | ||
1395 | case USB_ID(0x22d9, 0x0426): /* OPPO HA-2 */ | ||
1396 | case USB_ID(0x22e1, 0xca01): /* HDTA Serenade DSD */ | ||
1397 | case USB_ID(0x249c, 0x9326): /* M2Tech Young MkIII */ | ||
1343 | case USB_ID(0x2616, 0x0106): /* PS Audio NuWave DAC */ | 1398 | case USB_ID(0x2616, 0x0106): /* PS Audio NuWave DAC */ |
1399 | case USB_ID(0x2622, 0x0041): /* Audiolab M-DAC+ */ | ||
1400 | case USB_ID(0x27f7, 0x3002): /* W4S DAC-2v2SE */ | ||
1401 | case USB_ID(0x29a2, 0x0086): /* Mutec MC3+ USB */ | ||
1402 | case USB_ID(0x6b42, 0x0042): /* MSB Technology */ | ||
1344 | if (fp->altsetting == 3) | 1403 | if (fp->altsetting == 3) |
1345 | return SNDRV_PCM_FMTBIT_DSD_U32_BE; | 1404 | return SNDRV_PCM_FMTBIT_DSD_U32_BE; |
1346 | break; | 1405 | break; |
diff --git a/sound/usb/stream.c b/sound/usb/stream.c index 5ed334575fc7..729afd808cc4 100644 --- a/sound/usb/stream.c +++ b/sound/usb/stream.c | |||
@@ -106,6 +106,8 @@ static void snd_usb_init_substream(struct snd_usb_stream *as, | |||
106 | subs->ep_num = fp->endpoint; | 106 | subs->ep_num = fp->endpoint; |
107 | if (fp->channels > subs->channels_max) | 107 | if (fp->channels > subs->channels_max) |
108 | subs->channels_max = fp->channels; | 108 | subs->channels_max = fp->channels; |
109 | |||
110 | snd_usb_preallocate_buffer(subs); | ||
109 | } | 111 | } |
110 | 112 | ||
111 | /* kctl callbacks for usb-audio channel maps */ | 113 | /* kctl callbacks for usb-audio channel maps */ |
@@ -633,6 +635,395 @@ snd_usb_find_output_terminal_descriptor(struct usb_host_interface *ctrl_iface, | |||
633 | return NULL; | 635 | return NULL; |
634 | } | 636 | } |
635 | 637 | ||
638 | static struct audioformat * | ||
639 | audio_format_alloc_init(struct snd_usb_audio *chip, | ||
640 | struct usb_host_interface *alts, | ||
641 | int protocol, int iface_no, int altset_idx, | ||
642 | int altno, int num_channels, int clock) | ||
643 | { | ||
644 | struct audioformat *fp; | ||
645 | |||
646 | fp = kzalloc(sizeof(*fp), GFP_KERNEL); | ||
647 | if (!fp) | ||
648 | return NULL; | ||
649 | |||
650 | fp->iface = iface_no; | ||
651 | fp->altsetting = altno; | ||
652 | fp->altset_idx = altset_idx; | ||
653 | fp->endpoint = get_endpoint(alts, 0)->bEndpointAddress; | ||
654 | fp->ep_attr = get_endpoint(alts, 0)->bmAttributes; | ||
655 | fp->datainterval = snd_usb_parse_datainterval(chip, alts); | ||
656 | fp->protocol = protocol; | ||
657 | fp->maxpacksize = le16_to_cpu(get_endpoint(alts, 0)->wMaxPacketSize); | ||
658 | fp->channels = num_channels; | ||
659 | if (snd_usb_get_speed(chip->dev) == USB_SPEED_HIGH) | ||
660 | fp->maxpacksize = (((fp->maxpacksize >> 11) & 3) + 1) | ||
661 | * (fp->maxpacksize & 0x7ff); | ||
662 | fp->clock = clock; | ||
663 | INIT_LIST_HEAD(&fp->list); | ||
664 | |||
665 | return fp; | ||
666 | } | ||
667 | |||
668 | static struct audioformat * | ||
669 | snd_usb_get_audioformat_uac12(struct snd_usb_audio *chip, | ||
670 | struct usb_host_interface *alts, | ||
671 | int protocol, int iface_no, int altset_idx, | ||
672 | int altno, int stream, int bm_quirk) | ||
673 | { | ||
674 | struct usb_device *dev = chip->dev; | ||
675 | struct uac_format_type_i_continuous_descriptor *fmt; | ||
676 | unsigned int num_channels = 0, chconfig = 0; | ||
677 | struct audioformat *fp; | ||
678 | int clock = 0; | ||
679 | u64 format; | ||
680 | |||
681 | /* get audio formats */ | ||
682 | if (protocol == UAC_VERSION_1) { | ||
683 | struct uac1_as_header_descriptor *as = | ||
684 | snd_usb_find_csint_desc(alts->extra, alts->extralen, | ||
685 | NULL, UAC_AS_GENERAL); | ||
686 | struct uac_input_terminal_descriptor *iterm; | ||
687 | |||
688 | if (!as) { | ||
689 | dev_err(&dev->dev, | ||
690 | "%u:%d : UAC_AS_GENERAL descriptor not found\n", | ||
691 | iface_no, altno); | ||
692 | return NULL; | ||
693 | } | ||
694 | |||
695 | if (as->bLength < sizeof(*as)) { | ||
696 | dev_err(&dev->dev, | ||
697 | "%u:%d : invalid UAC_AS_GENERAL desc\n", | ||
698 | iface_no, altno); | ||
699 | return NULL; | ||
700 | } | ||
701 | |||
702 | format = le16_to_cpu(as->wFormatTag); /* remember the format value */ | ||
703 | |||
704 | iterm = snd_usb_find_input_terminal_descriptor(chip->ctrl_intf, | ||
705 | as->bTerminalLink); | ||
706 | if (iterm) { | ||
707 | num_channels = iterm->bNrChannels; | ||
708 | chconfig = le16_to_cpu(iterm->wChannelConfig); | ||
709 | } | ||
710 | } else { /* UAC_VERSION_2 */ | ||
711 | struct uac2_input_terminal_descriptor *input_term; | ||
712 | struct uac2_output_terminal_descriptor *output_term; | ||
713 | struct uac2_as_header_descriptor *as = | ||
714 | snd_usb_find_csint_desc(alts->extra, alts->extralen, | ||
715 | NULL, UAC_AS_GENERAL); | ||
716 | |||
717 | if (!as) { | ||
718 | dev_err(&dev->dev, | ||
719 | "%u:%d : UAC_AS_GENERAL descriptor not found\n", | ||
720 | iface_no, altno); | ||
721 | return NULL; | ||
722 | } | ||
723 | |||
724 | if (as->bLength < sizeof(*as)) { | ||
725 | dev_err(&dev->dev, | ||
726 | "%u:%d : invalid UAC_AS_GENERAL desc\n", | ||
727 | iface_no, altno); | ||
728 | return NULL; | ||
729 | } | ||
730 | |||
731 | num_channels = as->bNrChannels; | ||
732 | format = le32_to_cpu(as->bmFormats); | ||
733 | chconfig = le32_to_cpu(as->bmChannelConfig); | ||
734 | |||
735 | /* | ||
736 | * lookup the terminal associated to this interface | ||
737 | * to extract the clock | ||
738 | */ | ||
739 | input_term = snd_usb_find_input_terminal_descriptor(chip->ctrl_intf, | ||
740 | as->bTerminalLink); | ||
741 | if (input_term) { | ||
742 | clock = input_term->bCSourceID; | ||
743 | if (!chconfig && (num_channels == input_term->bNrChannels)) | ||
744 | chconfig = le32_to_cpu(input_term->bmChannelConfig); | ||
745 | goto found_clock; | ||
746 | } | ||
747 | |||
748 | output_term = snd_usb_find_output_terminal_descriptor(chip->ctrl_intf, | ||
749 | as->bTerminalLink); | ||
750 | if (output_term) { | ||
751 | clock = output_term->bCSourceID; | ||
752 | goto found_clock; | ||
753 | } | ||
754 | |||
755 | dev_err(&dev->dev, | ||
756 | "%u:%d : bogus bTerminalLink %d\n", | ||
757 | iface_no, altno, as->bTerminalLink); | ||
758 | return NULL; | ||
759 | } | ||
760 | |||
761 | found_clock: | ||
762 | /* get format type */ | ||
763 | fmt = snd_usb_find_csint_desc(alts->extra, alts->extralen, | ||
764 | NULL, UAC_FORMAT_TYPE); | ||
765 | if (!fmt) { | ||
766 | dev_err(&dev->dev, | ||
767 | "%u:%d : no UAC_FORMAT_TYPE desc\n", | ||
768 | iface_no, altno); | ||
769 | return NULL; | ||
770 | } | ||
771 | if (((protocol == UAC_VERSION_1) && (fmt->bLength < 8)) | ||
772 | || ((protocol == UAC_VERSION_2) && | ||
773 | (fmt->bLength < 6))) { | ||
774 | dev_err(&dev->dev, | ||
775 | "%u:%d : invalid UAC_FORMAT_TYPE desc\n", | ||
776 | iface_no, altno); | ||
777 | return NULL; | ||
778 | } | ||
779 | |||
780 | /* | ||
781 | * Blue Microphones workaround: The last altsetting is | ||
782 | * identical with the previous one, except for a larger | ||
783 | * packet size, but is actually a mislabeled two-channel | ||
784 | * setting; ignore it. | ||
785 | * | ||
786 | * Part 2: analyze quirk flag and format | ||
787 | */ | ||
788 | if (bm_quirk && fmt->bNrChannels == 1 && fmt->bSubframeSize == 2) | ||
789 | return NULL; | ||
790 | |||
791 | fp = audio_format_alloc_init(chip, alts, protocol, iface_no, | ||
792 | altset_idx, altno, num_channels, clock); | ||
793 | if (!fp) | ||
794 | return ERR_PTR(-ENOMEM); | ||
795 | |||
796 | fp->attributes = parse_uac_endpoint_attributes(chip, alts, protocol, | ||
797 | iface_no); | ||
798 | |||
799 | /* some quirks for attributes here */ | ||
800 | snd_usb_audioformat_attributes_quirk(chip, fp, stream); | ||
801 | |||
802 | /* ok, let's parse further... */ | ||
803 | if (snd_usb_parse_audio_format(chip, fp, format, | ||
804 | fmt, stream) < 0) { | ||
805 | kfree(fp->rate_table); | ||
806 | kfree(fp); | ||
807 | return NULL; | ||
808 | } | ||
809 | |||
810 | /* Create chmap */ | ||
811 | if (fp->channels != num_channels) | ||
812 | chconfig = 0; | ||
813 | |||
814 | fp->chmap = convert_chmap(fp->channels, chconfig, protocol); | ||
815 | |||
816 | return fp; | ||
817 | } | ||
818 | |||
819 | static struct audioformat * | ||
820 | snd_usb_get_audioformat_uac3(struct snd_usb_audio *chip, | ||
821 | struct usb_host_interface *alts, | ||
822 | int iface_no, int altset_idx, | ||
823 | int altno, int stream) | ||
824 | { | ||
825 | struct usb_device *dev = chip->dev; | ||
826 | struct uac3_input_terminal_descriptor *input_term; | ||
827 | struct uac3_output_terminal_descriptor *output_term; | ||
828 | struct uac3_cluster_header_descriptor *cluster; | ||
829 | struct uac3_as_header_descriptor *as = NULL; | ||
830 | struct uac3_hc_descriptor_header hc_header; | ||
831 | struct snd_pcm_chmap_elem *chmap; | ||
832 | unsigned char badd_profile; | ||
833 | u64 badd_formats = 0; | ||
834 | unsigned int num_channels; | ||
835 | struct audioformat *fp; | ||
836 | u16 cluster_id, wLength; | ||
837 | int clock = 0; | ||
838 | int err; | ||
839 | |||
840 | badd_profile = chip->badd_profile; | ||
841 | |||
842 | if (badd_profile >= UAC3_FUNCTION_SUBCLASS_GENERIC_IO) { | ||
843 | unsigned int maxpacksize = | ||
844 | le16_to_cpu(get_endpoint(alts, 0)->wMaxPacketSize); | ||
845 | |||
846 | switch (maxpacksize) { | ||
847 | default: | ||
848 | dev_err(&dev->dev, | ||
849 | "%u:%d : incorrect wMaxPacketSize for BADD profile\n", | ||
850 | iface_no, altno); | ||
851 | return NULL; | ||
852 | case UAC3_BADD_EP_MAXPSIZE_SYNC_MONO_16: | ||
853 | case UAC3_BADD_EP_MAXPSIZE_ASYNC_MONO_16: | ||
854 | badd_formats = SNDRV_PCM_FMTBIT_S16_LE; | ||
855 | num_channels = 1; | ||
856 | break; | ||
857 | case UAC3_BADD_EP_MAXPSIZE_SYNC_MONO_24: | ||
858 | case UAC3_BADD_EP_MAXPSIZE_ASYNC_MONO_24: | ||
859 | badd_formats = SNDRV_PCM_FMTBIT_S24_3LE; | ||
860 | num_channels = 1; | ||
861 | break; | ||
862 | case UAC3_BADD_EP_MAXPSIZE_SYNC_STEREO_16: | ||
863 | case UAC3_BADD_EP_MAXPSIZE_ASYNC_STEREO_16: | ||
864 | badd_formats = SNDRV_PCM_FMTBIT_S16_LE; | ||
865 | num_channels = 2; | ||
866 | break; | ||
867 | case UAC3_BADD_EP_MAXPSIZE_SYNC_STEREO_24: | ||
868 | case UAC3_BADD_EP_MAXPSIZE_ASYNC_STEREO_24: | ||
869 | badd_formats = SNDRV_PCM_FMTBIT_S24_3LE; | ||
870 | num_channels = 2; | ||
871 | break; | ||
872 | } | ||
873 | |||
874 | chmap = kzalloc(sizeof(*chmap), GFP_KERNEL); | ||
875 | if (!chmap) | ||
876 | return ERR_PTR(-ENOMEM); | ||
877 | |||
878 | if (num_channels == 1) { | ||
879 | chmap->map[0] = SNDRV_CHMAP_MONO; | ||
880 | } else { | ||
881 | chmap->map[0] = SNDRV_CHMAP_FL; | ||
882 | chmap->map[1] = SNDRV_CHMAP_FR; | ||
883 | } | ||
884 | |||
885 | chmap->channels = num_channels; | ||
886 | clock = UAC3_BADD_CS_ID9; | ||
887 | goto found_clock; | ||
888 | } | ||
889 | |||
890 | as = snd_usb_find_csint_desc(alts->extra, alts->extralen, | ||
891 | NULL, UAC_AS_GENERAL); | ||
892 | if (!as) { | ||
893 | dev_err(&dev->dev, | ||
894 | "%u:%d : UAC_AS_GENERAL descriptor not found\n", | ||
895 | iface_no, altno); | ||
896 | return NULL; | ||
897 | } | ||
898 | |||
899 | if (as->bLength < sizeof(*as)) { | ||
900 | dev_err(&dev->dev, | ||
901 | "%u:%d : invalid UAC_AS_GENERAL desc\n", | ||
902 | iface_no, altno); | ||
903 | return NULL; | ||
904 | } | ||
905 | |||
906 | cluster_id = le16_to_cpu(as->wClusterDescrID); | ||
907 | if (!cluster_id) { | ||
908 | dev_err(&dev->dev, | ||
909 | "%u:%d : no cluster descriptor\n", | ||
910 | iface_no, altno); | ||
911 | return NULL; | ||
912 | } | ||
913 | |||
914 | /* | ||
915 | * Get number of channels and channel map through | ||
916 | * High Capability Cluster Descriptor | ||
917 | * | ||
918 | * First step: get High Capability header and | ||
919 | * read size of Cluster Descriptor | ||
920 | */ | ||
921 | err = snd_usb_ctl_msg(chip->dev, | ||
922 | usb_rcvctrlpipe(chip->dev, 0), | ||
923 | UAC3_CS_REQ_HIGH_CAPABILITY_DESCRIPTOR, | ||
924 | USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN, | ||
925 | cluster_id, | ||
926 | snd_usb_ctrl_intf(chip), | ||
927 | &hc_header, sizeof(hc_header)); | ||
928 | if (err < 0) | ||
929 | return ERR_PTR(err); | ||
930 | else if (err != sizeof(hc_header)) { | ||
931 | dev_err(&dev->dev, | ||
932 | "%u:%d : can't get High Capability descriptor\n", | ||
933 | iface_no, altno); | ||
934 | return ERR_PTR(-EIO); | ||
935 | } | ||
936 | |||
937 | /* | ||
938 | * Second step: allocate needed amount of memory | ||
939 | * and request Cluster Descriptor | ||
940 | */ | ||
941 | wLength = le16_to_cpu(hc_header.wLength); | ||
942 | cluster = kzalloc(wLength, GFP_KERNEL); | ||
943 | if (!cluster) | ||
944 | return ERR_PTR(-ENOMEM); | ||
945 | err = snd_usb_ctl_msg(chip->dev, | ||
946 | usb_rcvctrlpipe(chip->dev, 0), | ||
947 | UAC3_CS_REQ_HIGH_CAPABILITY_DESCRIPTOR, | ||
948 | USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN, | ||
949 | cluster_id, | ||
950 | snd_usb_ctrl_intf(chip), | ||
951 | cluster, wLength); | ||
952 | if (err < 0) { | ||
953 | kfree(cluster); | ||
954 | return ERR_PTR(err); | ||
955 | } else if (err != wLength) { | ||
956 | dev_err(&dev->dev, | ||
957 | "%u:%d : can't get Cluster Descriptor\n", | ||
958 | iface_no, altno); | ||
959 | kfree(cluster); | ||
960 | return ERR_PTR(-EIO); | ||
961 | } | ||
962 | |||
963 | num_channels = cluster->bNrChannels; | ||
964 | chmap = convert_chmap_v3(cluster); | ||
965 | kfree(cluster); | ||
966 | |||
967 | /* | ||
968 | * lookup the terminal associated to this interface | ||
969 | * to extract the clock | ||
970 | */ | ||
971 | input_term = snd_usb_find_input_terminal_descriptor(chip->ctrl_intf, | ||
972 | as->bTerminalLink); | ||
973 | if (input_term) { | ||
974 | clock = input_term->bCSourceID; | ||
975 | goto found_clock; | ||
976 | } | ||
977 | |||
978 | output_term = snd_usb_find_output_terminal_descriptor(chip->ctrl_intf, | ||
979 | as->bTerminalLink); | ||
980 | if (output_term) { | ||
981 | clock = output_term->bCSourceID; | ||
982 | goto found_clock; | ||
983 | } | ||
984 | |||
985 | dev_err(&dev->dev, "%u:%d : bogus bTerminalLink %d\n", | ||
986 | iface_no, altno, as->bTerminalLink); | ||
987 | kfree(chmap); | ||
988 | return NULL; | ||
989 | |||
990 | found_clock: | ||
991 | fp = audio_format_alloc_init(chip, alts, UAC_VERSION_3, iface_no, | ||
992 | altset_idx, altno, num_channels, clock); | ||
993 | if (!fp) { | ||
994 | kfree(chmap); | ||
995 | return ERR_PTR(-ENOMEM); | ||
996 | } | ||
997 | |||
998 | fp->chmap = chmap; | ||
999 | |||
1000 | if (badd_profile >= UAC3_FUNCTION_SUBCLASS_GENERIC_IO) { | ||
1001 | fp->attributes = 0; /* No attributes */ | ||
1002 | |||
1003 | fp->fmt_type = UAC_FORMAT_TYPE_I; | ||
1004 | fp->formats = badd_formats; | ||
1005 | |||
1006 | fp->nr_rates = 0; /* SNDRV_PCM_RATE_CONTINUOUS */ | ||
1007 | fp->rate_min = UAC3_BADD_SAMPLING_RATE; | ||
1008 | fp->rate_max = UAC3_BADD_SAMPLING_RATE; | ||
1009 | fp->rates = SNDRV_PCM_RATE_CONTINUOUS; | ||
1010 | |||
1011 | } else { | ||
1012 | fp->attributes = parse_uac_endpoint_attributes(chip, alts, | ||
1013 | UAC_VERSION_3, | ||
1014 | iface_no); | ||
1015 | /* ok, let's parse further... */ | ||
1016 | if (snd_usb_parse_audio_format_v3(chip, fp, as, stream) < 0) { | ||
1017 | kfree(fp->chmap); | ||
1018 | kfree(fp->rate_table); | ||
1019 | kfree(fp); | ||
1020 | return NULL; | ||
1021 | } | ||
1022 | } | ||
1023 | |||
1024 | return fp; | ||
1025 | } | ||
1026 | |||
636 | int snd_usb_parse_audio_interface(struct snd_usb_audio *chip, int iface_no) | 1027 | int snd_usb_parse_audio_interface(struct snd_usb_audio *chip, int iface_no) |
637 | { | 1028 | { |
638 | struct usb_device *dev; | 1029 | struct usb_device *dev; |
@@ -640,13 +1031,8 @@ int snd_usb_parse_audio_interface(struct snd_usb_audio *chip, int iface_no) | |||
640 | struct usb_host_interface *alts; | 1031 | struct usb_host_interface *alts; |
641 | struct usb_interface_descriptor *altsd; | 1032 | struct usb_interface_descriptor *altsd; |
642 | int i, altno, err, stream; | 1033 | int i, altno, err, stream; |
643 | u64 format = 0; | ||
644 | unsigned int num_channels = 0; | ||
645 | struct audioformat *fp = NULL; | 1034 | struct audioformat *fp = NULL; |
646 | int num, protocol, clock = 0; | 1035 | int num, protocol; |
647 | struct uac_format_type_i_continuous_descriptor *fmt = NULL; | ||
648 | struct snd_pcm_chmap_elem *chmap_v3 = NULL; | ||
649 | unsigned int chconfig; | ||
650 | 1036 | ||
651 | dev = chip->dev; | 1037 | dev = chip->dev; |
652 | 1038 | ||
@@ -695,303 +1081,48 @@ int snd_usb_parse_audio_interface(struct snd_usb_audio *chip, int iface_no) | |||
695 | protocol <= 2) | 1081 | protocol <= 2) |
696 | protocol = UAC_VERSION_1; | 1082 | protocol = UAC_VERSION_1; |
697 | 1083 | ||
698 | chconfig = 0; | ||
699 | /* get audio formats */ | ||
700 | switch (protocol) { | 1084 | switch (protocol) { |
701 | default: | 1085 | default: |
702 | dev_dbg(&dev->dev, "%u:%d: unknown interface protocol %#02x, assuming v1\n", | 1086 | dev_dbg(&dev->dev, "%u:%d: unknown interface protocol %#02x, assuming v1\n", |
703 | iface_no, altno, protocol); | 1087 | iface_no, altno, protocol); |
704 | protocol = UAC_VERSION_1; | 1088 | protocol = UAC_VERSION_1; |
705 | /* fall through */ | 1089 | /* fall through */ |
706 | 1090 | case UAC_VERSION_1: | |
707 | case UAC_VERSION_1: { | 1091 | /* fall through */ |
708 | struct uac1_as_header_descriptor *as = | ||
709 | snd_usb_find_csint_desc(alts->extra, alts->extralen, NULL, UAC_AS_GENERAL); | ||
710 | struct uac_input_terminal_descriptor *iterm; | ||
711 | |||
712 | if (!as) { | ||
713 | dev_err(&dev->dev, | ||
714 | "%u:%d : UAC_AS_GENERAL descriptor not found\n", | ||
715 | iface_no, altno); | ||
716 | continue; | ||
717 | } | ||
718 | |||
719 | if (as->bLength < sizeof(*as)) { | ||
720 | dev_err(&dev->dev, | ||
721 | "%u:%d : invalid UAC_AS_GENERAL desc\n", | ||
722 | iface_no, altno); | ||
723 | continue; | ||
724 | } | ||
725 | |||
726 | format = le16_to_cpu(as->wFormatTag); /* remember the format value */ | ||
727 | |||
728 | iterm = snd_usb_find_input_terminal_descriptor(chip->ctrl_intf, | ||
729 | as->bTerminalLink); | ||
730 | if (iterm) { | ||
731 | num_channels = iterm->bNrChannels; | ||
732 | chconfig = le16_to_cpu(iterm->wChannelConfig); | ||
733 | } | ||
734 | |||
735 | break; | ||
736 | } | ||
737 | |||
738 | case UAC_VERSION_2: { | 1092 | case UAC_VERSION_2: { |
739 | struct uac2_input_terminal_descriptor *input_term; | 1093 | int bm_quirk = 0; |
740 | struct uac2_output_terminal_descriptor *output_term; | ||
741 | struct uac2_as_header_descriptor *as = | ||
742 | snd_usb_find_csint_desc(alts->extra, alts->extralen, NULL, UAC_AS_GENERAL); | ||
743 | |||
744 | if (!as) { | ||
745 | dev_err(&dev->dev, | ||
746 | "%u:%d : UAC_AS_GENERAL descriptor not found\n", | ||
747 | iface_no, altno); | ||
748 | continue; | ||
749 | } | ||
750 | |||
751 | if (as->bLength < sizeof(*as)) { | ||
752 | dev_err(&dev->dev, | ||
753 | "%u:%d : invalid UAC_AS_GENERAL desc\n", | ||
754 | iface_no, altno); | ||
755 | continue; | ||
756 | } | ||
757 | |||
758 | num_channels = as->bNrChannels; | ||
759 | format = le32_to_cpu(as->bmFormats); | ||
760 | chconfig = le32_to_cpu(as->bmChannelConfig); | ||
761 | |||
762 | /* lookup the terminal associated to this interface | ||
763 | * to extract the clock */ | ||
764 | input_term = snd_usb_find_input_terminal_descriptor(chip->ctrl_intf, | ||
765 | as->bTerminalLink); | ||
766 | if (input_term) { | ||
767 | clock = input_term->bCSourceID; | ||
768 | if (!chconfig && (num_channels == input_term->bNrChannels)) | ||
769 | chconfig = le32_to_cpu(input_term->bmChannelConfig); | ||
770 | break; | ||
771 | } | ||
772 | |||
773 | output_term = snd_usb_find_output_terminal_descriptor(chip->ctrl_intf, | ||
774 | as->bTerminalLink); | ||
775 | if (output_term) { | ||
776 | clock = output_term->bCSourceID; | ||
777 | break; | ||
778 | } | ||
779 | |||
780 | dev_err(&dev->dev, | ||
781 | "%u:%d : bogus bTerminalLink %d\n", | ||
782 | iface_no, altno, as->bTerminalLink); | ||
783 | continue; | ||
784 | } | ||
785 | |||
786 | case UAC_VERSION_3: { | ||
787 | struct uac3_input_terminal_descriptor *input_term; | ||
788 | struct uac3_output_terminal_descriptor *output_term; | ||
789 | struct uac3_as_header_descriptor *as; | ||
790 | struct uac3_cluster_header_descriptor *cluster; | ||
791 | struct uac3_hc_descriptor_header hc_header; | ||
792 | u16 cluster_id, wLength; | ||
793 | |||
794 | as = snd_usb_find_csint_desc(alts->extra, | ||
795 | alts->extralen, | ||
796 | NULL, UAC_AS_GENERAL); | ||
797 | |||
798 | if (!as) { | ||
799 | dev_err(&dev->dev, | ||
800 | "%u:%d : UAC_AS_GENERAL descriptor not found\n", | ||
801 | iface_no, altno); | ||
802 | continue; | ||
803 | } | ||
804 | |||
805 | if (as->bLength < sizeof(*as)) { | ||
806 | dev_err(&dev->dev, | ||
807 | "%u:%d : invalid UAC_AS_GENERAL desc\n", | ||
808 | iface_no, altno); | ||
809 | continue; | ||
810 | } | ||
811 | |||
812 | cluster_id = le16_to_cpu(as->wClusterDescrID); | ||
813 | if (!cluster_id) { | ||
814 | dev_err(&dev->dev, | ||
815 | "%u:%d : no cluster descriptor\n", | ||
816 | iface_no, altno); | ||
817 | continue; | ||
818 | } | ||
819 | |||
820 | /* | ||
821 | * Get number of channels and channel map through | ||
822 | * High Capability Cluster Descriptor | ||
823 | * | ||
824 | * First step: get High Capability header and | ||
825 | * read size of Cluster Descriptor | ||
826 | */ | ||
827 | err = snd_usb_ctl_msg(chip->dev, | ||
828 | usb_rcvctrlpipe(chip->dev, 0), | ||
829 | UAC3_CS_REQ_HIGH_CAPABILITY_DESCRIPTOR, | ||
830 | USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN, | ||
831 | cluster_id, | ||
832 | snd_usb_ctrl_intf(chip), | ||
833 | &hc_header, sizeof(hc_header)); | ||
834 | if (err < 0) | ||
835 | return err; | ||
836 | else if (err != sizeof(hc_header)) { | ||
837 | dev_err(&dev->dev, | ||
838 | "%u:%d : can't get High Capability descriptor\n", | ||
839 | iface_no, altno); | ||
840 | return -EIO; | ||
841 | } | ||
842 | |||
843 | /* | ||
844 | * Second step: allocate needed amount of memory | ||
845 | * and request Cluster Descriptor | ||
846 | */ | ||
847 | wLength = le16_to_cpu(hc_header.wLength); | ||
848 | cluster = kzalloc(wLength, GFP_KERNEL); | ||
849 | if (!cluster) | ||
850 | return -ENOMEM; | ||
851 | err = snd_usb_ctl_msg(chip->dev, | ||
852 | usb_rcvctrlpipe(chip->dev, 0), | ||
853 | UAC3_CS_REQ_HIGH_CAPABILITY_DESCRIPTOR, | ||
854 | USB_RECIP_INTERFACE | USB_TYPE_CLASS | USB_DIR_IN, | ||
855 | cluster_id, | ||
856 | snd_usb_ctrl_intf(chip), | ||
857 | cluster, wLength); | ||
858 | if (err < 0) { | ||
859 | kfree(cluster); | ||
860 | return err; | ||
861 | } else if (err != wLength) { | ||
862 | dev_err(&dev->dev, | ||
863 | "%u:%d : can't get Cluster Descriptor\n", | ||
864 | iface_no, altno); | ||
865 | kfree(cluster); | ||
866 | return -EIO; | ||
867 | } | ||
868 | |||
869 | num_channels = cluster->bNrChannels; | ||
870 | chmap_v3 = convert_chmap_v3(cluster); | ||
871 | |||
872 | kfree(cluster); | ||
873 | |||
874 | format = le64_to_cpu(as->bmFormats); | ||
875 | |||
876 | /* lookup the terminal associated to this interface | ||
877 | * to extract the clock */ | ||
878 | input_term = snd_usb_find_input_terminal_descriptor( | ||
879 | chip->ctrl_intf, | ||
880 | as->bTerminalLink); | ||
881 | |||
882 | if (input_term) { | ||
883 | clock = input_term->bCSourceID; | ||
884 | break; | ||
885 | } | ||
886 | |||
887 | output_term = snd_usb_find_output_terminal_descriptor(chip->ctrl_intf, | ||
888 | as->bTerminalLink); | ||
889 | if (output_term) { | ||
890 | clock = output_term->bCSourceID; | ||
891 | break; | ||
892 | } | ||
893 | |||
894 | dev_err(&dev->dev, | ||
895 | "%u:%d : bogus bTerminalLink %d\n", | ||
896 | iface_no, altno, as->bTerminalLink); | ||
897 | continue; | ||
898 | } | ||
899 | } | ||
900 | |||
901 | if (protocol == UAC_VERSION_1 || protocol == UAC_VERSION_2) { | ||
902 | /* get format type */ | ||
903 | fmt = snd_usb_find_csint_desc(alts->extra, | ||
904 | alts->extralen, | ||
905 | NULL, UAC_FORMAT_TYPE); | ||
906 | if (!fmt) { | ||
907 | dev_err(&dev->dev, | ||
908 | "%u:%d : no UAC_FORMAT_TYPE desc\n", | ||
909 | iface_no, altno); | ||
910 | continue; | ||
911 | } | ||
912 | if (((protocol == UAC_VERSION_1) && (fmt->bLength < 8)) | ||
913 | || ((protocol == UAC_VERSION_2) && | ||
914 | (fmt->bLength < 6))) { | ||
915 | dev_err(&dev->dev, | ||
916 | "%u:%d : invalid UAC_FORMAT_TYPE desc\n", | ||
917 | iface_no, altno); | ||
918 | continue; | ||
919 | } | ||
920 | 1094 | ||
921 | /* | 1095 | /* |
922 | * Blue Microphones workaround: The last altsetting is | 1096 | * Blue Microphones workaround: The last altsetting is |
923 | * identical with the previous one, except for a larger | 1097 | * identical with the previous one, except for a larger |
924 | * packet size, but is actually a mislabeled two-channel | 1098 | * packet size, but is actually a mislabeled two-channel |
925 | * setting; ignore it. | 1099 | * setting; ignore it. |
1100 | * | ||
1101 | * Part 1: prepare quirk flag | ||
926 | */ | 1102 | */ |
927 | if (fmt->bNrChannels == 1 && | 1103 | if (altno == 2 && num == 3 && |
928 | fmt->bSubframeSize == 2 && | ||
929 | altno == 2 && num == 3 && | ||
930 | fp && fp->altsetting == 1 && fp->channels == 1 && | 1104 | fp && fp->altsetting == 1 && fp->channels == 1 && |
931 | fp->formats == SNDRV_PCM_FMTBIT_S16_LE && | 1105 | fp->formats == SNDRV_PCM_FMTBIT_S16_LE && |
932 | protocol == UAC_VERSION_1 && | 1106 | protocol == UAC_VERSION_1 && |
933 | le16_to_cpu(get_endpoint(alts, 0)->wMaxPacketSize) == | 1107 | le16_to_cpu(get_endpoint(alts, 0)->wMaxPacketSize) == |
934 | fp->maxpacksize * 2) | 1108 | fp->maxpacksize * 2) |
935 | continue; | 1109 | bm_quirk = 1; |
936 | } | ||
937 | |||
938 | fp = kzalloc(sizeof(*fp), GFP_KERNEL); | ||
939 | if (!fp) | ||
940 | return -ENOMEM; | ||
941 | 1110 | ||
942 | fp->iface = iface_no; | 1111 | fp = snd_usb_get_audioformat_uac12(chip, alts, protocol, |
943 | fp->altsetting = altno; | 1112 | iface_no, i, altno, |
944 | fp->altset_idx = i; | 1113 | stream, bm_quirk); |
945 | fp->endpoint = get_endpoint(alts, 0)->bEndpointAddress; | 1114 | break; |
946 | fp->ep_attr = get_endpoint(alts, 0)->bmAttributes; | 1115 | } |
947 | fp->datainterval = snd_usb_parse_datainterval(chip, alts); | 1116 | case UAC_VERSION_3: |
948 | fp->protocol = protocol; | 1117 | fp = snd_usb_get_audioformat_uac3(chip, alts, |
949 | fp->maxpacksize = le16_to_cpu(get_endpoint(alts, 0)->wMaxPacketSize); | 1118 | iface_no, i, altno, stream); |
950 | fp->channels = num_channels; | 1119 | break; |
951 | if (snd_usb_get_speed(dev) == USB_SPEED_HIGH) | ||
952 | fp->maxpacksize = (((fp->maxpacksize >> 11) & 3) + 1) | ||
953 | * (fp->maxpacksize & 0x7ff); | ||
954 | fp->attributes = parse_uac_endpoint_attributes(chip, alts, protocol, iface_no); | ||
955 | fp->clock = clock; | ||
956 | INIT_LIST_HEAD(&fp->list); | ||
957 | |||
958 | /* some quirks for attributes here */ | ||
959 | snd_usb_audioformat_attributes_quirk(chip, fp, stream); | ||
960 | |||
961 | /* ok, let's parse further... */ | ||
962 | if (protocol == UAC_VERSION_1 || protocol == UAC_VERSION_2) { | ||
963 | if (snd_usb_parse_audio_format(chip, fp, format, | ||
964 | fmt, stream) < 0) { | ||
965 | kfree(fp->rate_table); | ||
966 | kfree(fp); | ||
967 | fp = NULL; | ||
968 | continue; | ||
969 | } | ||
970 | } else { | ||
971 | struct uac3_as_header_descriptor *as; | ||
972 | |||
973 | as = snd_usb_find_csint_desc(alts->extra, | ||
974 | alts->extralen, | ||
975 | NULL, UAC_AS_GENERAL); | ||
976 | |||
977 | if (snd_usb_parse_audio_format_v3(chip, fp, as, | ||
978 | stream) < 0) { | ||
979 | kfree(fp->rate_table); | ||
980 | kfree(fp); | ||
981 | fp = NULL; | ||
982 | continue; | ||
983 | } | ||
984 | } | 1120 | } |
985 | 1121 | ||
986 | /* Create chmap */ | 1122 | if (!fp) |
987 | if (fp->channels != num_channels) | 1123 | continue; |
988 | chconfig = 0; | 1124 | else if (IS_ERR(fp)) |
989 | 1125 | return PTR_ERR(fp); | |
990 | if (protocol == UAC_VERSION_3) | ||
991 | fp->chmap = chmap_v3; | ||
992 | else | ||
993 | fp->chmap = convert_chmap(fp->channels, chconfig, | ||
994 | protocol); | ||
995 | 1126 | ||
996 | dev_dbg(&dev->dev, "%u:%d: add audio endpoint %#x\n", iface_no, altno, fp->endpoint); | 1127 | dev_dbg(&dev->dev, "%u:%d: add audio endpoint %#x\n", iface_no, altno, fp->endpoint); |
997 | err = snd_usb_add_audio_stream(chip, stream, fp); | 1128 | err = snd_usb_add_audio_stream(chip, stream, fp); |
diff --git a/sound/usb/usbaudio.h b/sound/usb/usbaudio.h index 4d5c89a7ba2b..b9faeca645fd 100644 --- a/sound/usb/usbaudio.h +++ b/sound/usb/usbaudio.h | |||
@@ -49,6 +49,8 @@ struct snd_usb_audio { | |||
49 | int num_suspended_intf; | 49 | int num_suspended_intf; |
50 | int sample_rate_read_error; | 50 | int sample_rate_read_error; |
51 | 51 | ||
52 | int badd_profile; /* UAC3 BADD profile */ | ||
53 | |||
52 | struct list_head pcm_list; /* list of pcm streams */ | 54 | struct list_head pcm_list; /* list of pcm streams */ |
53 | struct list_head ep_list; /* list of audio-related endpoints */ | 55 | struct list_head ep_list; /* list of audio-related endpoints */ |
54 | int pcm_devs; | 56 | int pcm_devs; |
@@ -59,6 +61,9 @@ struct snd_usb_audio { | |||
59 | 61 | ||
60 | int setup; /* from the 'device_setup' module param */ | 62 | int setup; /* from the 'device_setup' module param */ |
61 | bool autoclock; /* from the 'autoclock' module param */ | 63 | bool autoclock; /* from the 'autoclock' module param */ |
64 | bool keep_iface; /* keep interface/altset after closing | ||
65 | * or parameter change | ||
66 | */ | ||
62 | 67 | ||
63 | struct usb_host_interface *ctrl_intf; /* the audio control interface */ | 68 | struct usb_host_interface *ctrl_intf; /* the audio control interface */ |
64 | }; | 69 | }; |
@@ -109,6 +114,7 @@ enum quirk_type { | |||
109 | struct snd_usb_audio_quirk { | 114 | struct snd_usb_audio_quirk { |
110 | const char *vendor_name; | 115 | const char *vendor_name; |
111 | const char *product_name; | 116 | const char *product_name; |
117 | const char *profile_name; /* override the card->longname */ | ||
112 | int16_t ifnum; | 118 | int16_t ifnum; |
113 | uint16_t type; | 119 | uint16_t type; |
114 | const void *data; | 120 | const void *data; |
@@ -121,4 +127,6 @@ struct snd_usb_audio_quirk { | |||
121 | int snd_usb_lock_shutdown(struct snd_usb_audio *chip); | 127 | int snd_usb_lock_shutdown(struct snd_usb_audio *chip); |
122 | void snd_usb_unlock_shutdown(struct snd_usb_audio *chip); | 128 | void snd_usb_unlock_shutdown(struct snd_usb_audio *chip); |
123 | 129 | ||
130 | extern bool snd_usb_use_vmalloc; | ||
131 | |||
124 | #endif /* __USBAUDIO_H */ | 132 | #endif /* __USBAUDIO_H */ |
diff --git a/sound/xen/Kconfig b/sound/xen/Kconfig new file mode 100644 index 000000000000..4f1fceea82d2 --- /dev/null +++ b/sound/xen/Kconfig | |||
@@ -0,0 +1,10 @@ | |||
1 | # ALSA Xen drivers | ||
2 | |||
3 | config SND_XEN_FRONTEND | ||
4 | tristate "Xen para-virtualized sound frontend driver" | ||
5 | depends on XEN | ||
6 | select SND_PCM | ||
7 | select XEN_XENBUS_FRONTEND | ||
8 | help | ||
9 | Choose this option if you want to enable a para-virtualized | ||
10 | frontend sound driver for Xen guest OSes. | ||
diff --git a/sound/xen/Makefile b/sound/xen/Makefile new file mode 100644 index 000000000000..1e6470ecc2f2 --- /dev/null +++ b/sound/xen/Makefile | |||
@@ -0,0 +1,9 @@ | |||
1 | # SPDX-License-Identifier: GPL-2.0 OR MIT | ||
2 | |||
3 | snd_xen_front-objs := xen_snd_front.o \ | ||
4 | xen_snd_front_cfg.o \ | ||
5 | xen_snd_front_evtchnl.o \ | ||
6 | xen_snd_front_shbuf.o \ | ||
7 | xen_snd_front_alsa.o | ||
8 | |||
9 | obj-$(CONFIG_SND_XEN_FRONTEND) += snd_xen_front.o | ||
diff --git a/sound/xen/xen_snd_front.c b/sound/xen/xen_snd_front.c new file mode 100644 index 000000000000..b089b13b5160 --- /dev/null +++ b/sound/xen/xen_snd_front.c | |||
@@ -0,0 +1,397 @@ | |||
1 | // SPDX-License-Identifier: GPL-2.0 OR MIT | ||
2 | |||
3 | /* | ||
4 | * Xen para-virtual sound device | ||
5 | * | ||
6 | * Copyright (C) 2016-2018 EPAM Systems Inc. | ||
7 | * | ||
8 | * Author: Oleksandr Andrushchenko <oleksandr_andrushchenko@epam.com> | ||
9 | */ | ||
10 | |||
11 | #include <linux/delay.h> | ||
12 | #include <linux/module.h> | ||
13 | |||
14 | #include <xen/page.h> | ||
15 | #include <xen/platform_pci.h> | ||
16 | #include <xen/xen.h> | ||
17 | #include <xen/xenbus.h> | ||
18 | |||
19 | #include <xen/interface/io/sndif.h> | ||
20 | |||
21 | #include "xen_snd_front.h" | ||
22 | #include "xen_snd_front_alsa.h" | ||
23 | #include "xen_snd_front_evtchnl.h" | ||
24 | #include "xen_snd_front_shbuf.h" | ||
25 | |||
26 | static struct xensnd_req * | ||
27 | be_stream_prepare_req(struct xen_snd_front_evtchnl *evtchnl, u8 operation) | ||
28 | { | ||
29 | struct xensnd_req *req; | ||
30 | |||
31 | req = RING_GET_REQUEST(&evtchnl->u.req.ring, | ||
32 | evtchnl->u.req.ring.req_prod_pvt); | ||
33 | req->operation = operation; | ||
34 | req->id = evtchnl->evt_next_id++; | ||
35 | evtchnl->evt_id = req->id; | ||
36 | return req; | ||
37 | } | ||
38 | |||
39 | static int be_stream_do_io(struct xen_snd_front_evtchnl *evtchnl) | ||
40 | { | ||
41 | if (unlikely(evtchnl->state != EVTCHNL_STATE_CONNECTED)) | ||
42 | return -EIO; | ||
43 | |||
44 | reinit_completion(&evtchnl->u.req.completion); | ||
45 | xen_snd_front_evtchnl_flush(evtchnl); | ||
46 | return 0; | ||
47 | } | ||
48 | |||
49 | static int be_stream_wait_io(struct xen_snd_front_evtchnl *evtchnl) | ||
50 | { | ||
51 | if (wait_for_completion_timeout(&evtchnl->u.req.completion, | ||
52 | msecs_to_jiffies(VSND_WAIT_BACK_MS)) <= 0) | ||
53 | return -ETIMEDOUT; | ||
54 | |||
55 | return evtchnl->u.req.resp_status; | ||
56 | } | ||
57 | |||
58 | int xen_snd_front_stream_query_hw_param(struct xen_snd_front_evtchnl *evtchnl, | ||
59 | struct xensnd_query_hw_param *hw_param_req, | ||
60 | struct xensnd_query_hw_param *hw_param_resp) | ||
61 | { | ||
62 | struct xensnd_req *req; | ||
63 | int ret; | ||
64 | |||
65 | mutex_lock(&evtchnl->u.req.req_io_lock); | ||
66 | |||
67 | mutex_lock(&evtchnl->ring_io_lock); | ||
68 | req = be_stream_prepare_req(evtchnl, XENSND_OP_HW_PARAM_QUERY); | ||
69 | req->op.hw_param = *hw_param_req; | ||
70 | mutex_unlock(&evtchnl->ring_io_lock); | ||
71 | |||
72 | ret = be_stream_do_io(evtchnl); | ||
73 | |||
74 | if (ret == 0) | ||
75 | ret = be_stream_wait_io(evtchnl); | ||
76 | |||
77 | if (ret == 0) | ||
78 | *hw_param_resp = evtchnl->u.req.resp.hw_param; | ||
79 | |||
80 | mutex_unlock(&evtchnl->u.req.req_io_lock); | ||
81 | return ret; | ||
82 | } | ||
83 | |||
84 | int xen_snd_front_stream_prepare(struct xen_snd_front_evtchnl *evtchnl, | ||
85 | struct xen_snd_front_shbuf *sh_buf, | ||
86 | u8 format, unsigned int channels, | ||
87 | unsigned int rate, u32 buffer_sz, | ||
88 | u32 period_sz) | ||
89 | { | ||
90 | struct xensnd_req *req; | ||
91 | int ret; | ||
92 | |||
93 | mutex_lock(&evtchnl->u.req.req_io_lock); | ||
94 | |||
95 | mutex_lock(&evtchnl->ring_io_lock); | ||
96 | req = be_stream_prepare_req(evtchnl, XENSND_OP_OPEN); | ||
97 | req->op.open.pcm_format = format; | ||
98 | req->op.open.pcm_channels = channels; | ||
99 | req->op.open.pcm_rate = rate; | ||
100 | req->op.open.buffer_sz = buffer_sz; | ||
101 | req->op.open.period_sz = period_sz; | ||
102 | req->op.open.gref_directory = xen_snd_front_shbuf_get_dir_start(sh_buf); | ||
103 | mutex_unlock(&evtchnl->ring_io_lock); | ||
104 | |||
105 | ret = be_stream_do_io(evtchnl); | ||
106 | |||
107 | if (ret == 0) | ||
108 | ret = be_stream_wait_io(evtchnl); | ||
109 | |||
110 | mutex_unlock(&evtchnl->u.req.req_io_lock); | ||
111 | return ret; | ||
112 | } | ||
113 | |||
114 | int xen_snd_front_stream_close(struct xen_snd_front_evtchnl *evtchnl) | ||
115 | { | ||
116 | struct xensnd_req *req; | ||
117 | int ret; | ||
118 | |||
119 | mutex_lock(&evtchnl->u.req.req_io_lock); | ||
120 | |||
121 | mutex_lock(&evtchnl->ring_io_lock); | ||
122 | req = be_stream_prepare_req(evtchnl, XENSND_OP_CLOSE); | ||
123 | mutex_unlock(&evtchnl->ring_io_lock); | ||
124 | |||
125 | ret = be_stream_do_io(evtchnl); | ||
126 | |||
127 | if (ret == 0) | ||
128 | ret = be_stream_wait_io(evtchnl); | ||
129 | |||
130 | mutex_unlock(&evtchnl->u.req.req_io_lock); | ||
131 | return ret; | ||
132 | } | ||
133 | |||
134 | int xen_snd_front_stream_write(struct xen_snd_front_evtchnl *evtchnl, | ||
135 | unsigned long pos, unsigned long count) | ||
136 | { | ||
137 | struct xensnd_req *req; | ||
138 | int ret; | ||
139 | |||
140 | mutex_lock(&evtchnl->u.req.req_io_lock); | ||
141 | |||
142 | mutex_lock(&evtchnl->ring_io_lock); | ||
143 | req = be_stream_prepare_req(evtchnl, XENSND_OP_WRITE); | ||
144 | req->op.rw.length = count; | ||
145 | req->op.rw.offset = pos; | ||
146 | mutex_unlock(&evtchnl->ring_io_lock); | ||
147 | |||
148 | ret = be_stream_do_io(evtchnl); | ||
149 | |||
150 | if (ret == 0) | ||
151 | ret = be_stream_wait_io(evtchnl); | ||
152 | |||
153 | mutex_unlock(&evtchnl->u.req.req_io_lock); | ||
154 | return ret; | ||
155 | } | ||
156 | |||
157 | int xen_snd_front_stream_read(struct xen_snd_front_evtchnl *evtchnl, | ||
158 | unsigned long pos, unsigned long count) | ||
159 | { | ||
160 | struct xensnd_req *req; | ||
161 | int ret; | ||
162 | |||
163 | mutex_lock(&evtchnl->u.req.req_io_lock); | ||
164 | |||
165 | mutex_lock(&evtchnl->ring_io_lock); | ||
166 | req = be_stream_prepare_req(evtchnl, XENSND_OP_READ); | ||
167 | req->op.rw.length = count; | ||
168 | req->op.rw.offset = pos; | ||
169 | mutex_unlock(&evtchnl->ring_io_lock); | ||
170 | |||
171 | ret = be_stream_do_io(evtchnl); | ||
172 | |||
173 | if (ret == 0) | ||
174 | ret = be_stream_wait_io(evtchnl); | ||
175 | |||
176 | mutex_unlock(&evtchnl->u.req.req_io_lock); | ||
177 | return ret; | ||
178 | } | ||
179 | |||
180 | int xen_snd_front_stream_trigger(struct xen_snd_front_evtchnl *evtchnl, | ||
181 | int type) | ||
182 | { | ||
183 | struct xensnd_req *req; | ||
184 | int ret; | ||
185 | |||
186 | mutex_lock(&evtchnl->u.req.req_io_lock); | ||
187 | |||
188 | mutex_lock(&evtchnl->ring_io_lock); | ||
189 | req = be_stream_prepare_req(evtchnl, XENSND_OP_TRIGGER); | ||
190 | req->op.trigger.type = type; | ||
191 | mutex_unlock(&evtchnl->ring_io_lock); | ||
192 | |||
193 | ret = be_stream_do_io(evtchnl); | ||
194 | |||
195 | if (ret == 0) | ||
196 | ret = be_stream_wait_io(evtchnl); | ||
197 | |||
198 | mutex_unlock(&evtchnl->u.req.req_io_lock); | ||
199 | return ret; | ||
200 | } | ||
201 | |||
202 | static void xen_snd_drv_fini(struct xen_snd_front_info *front_info) | ||
203 | { | ||
204 | xen_snd_front_alsa_fini(front_info); | ||
205 | xen_snd_front_evtchnl_free_all(front_info); | ||
206 | } | ||
207 | |||
208 | static int sndback_initwait(struct xen_snd_front_info *front_info) | ||
209 | { | ||
210 | int num_streams; | ||
211 | int ret; | ||
212 | |||
213 | ret = xen_snd_front_cfg_card(front_info, &num_streams); | ||
214 | if (ret < 0) | ||
215 | return ret; | ||
216 | |||
217 | /* create event channels for all streams and publish */ | ||
218 | ret = xen_snd_front_evtchnl_create_all(front_info, num_streams); | ||
219 | if (ret < 0) | ||
220 | return ret; | ||
221 | |||
222 | return xen_snd_front_evtchnl_publish_all(front_info); | ||
223 | } | ||
224 | |||
225 | static int sndback_connect(struct xen_snd_front_info *front_info) | ||
226 | { | ||
227 | return xen_snd_front_alsa_init(front_info); | ||
228 | } | ||
229 | |||
230 | static void sndback_disconnect(struct xen_snd_front_info *front_info) | ||
231 | { | ||
232 | xen_snd_drv_fini(front_info); | ||
233 | xenbus_switch_state(front_info->xb_dev, XenbusStateInitialising); | ||
234 | } | ||
235 | |||
236 | static void sndback_changed(struct xenbus_device *xb_dev, | ||
237 | enum xenbus_state backend_state) | ||
238 | { | ||
239 | struct xen_snd_front_info *front_info = dev_get_drvdata(&xb_dev->dev); | ||
240 | int ret; | ||
241 | |||
242 | dev_dbg(&xb_dev->dev, "Backend state is %s, front is %s\n", | ||
243 | xenbus_strstate(backend_state), | ||
244 | xenbus_strstate(xb_dev->state)); | ||
245 | |||
246 | switch (backend_state) { | ||
247 | case XenbusStateReconfiguring: | ||
248 | /* fall through */ | ||
249 | case XenbusStateReconfigured: | ||
250 | /* fall through */ | ||
251 | case XenbusStateInitialised: | ||
252 | /* fall through */ | ||
253 | break; | ||
254 | |||
255 | case XenbusStateInitialising: | ||
256 | /* Recovering after backend unexpected closure. */ | ||
257 | sndback_disconnect(front_info); | ||
258 | break; | ||
259 | |||
260 | case XenbusStateInitWait: | ||
261 | /* Recovering after backend unexpected closure. */ | ||
262 | sndback_disconnect(front_info); | ||
263 | |||
264 | ret = sndback_initwait(front_info); | ||
265 | if (ret < 0) | ||
266 | xenbus_dev_fatal(xb_dev, ret, "initializing frontend"); | ||
267 | else | ||
268 | xenbus_switch_state(xb_dev, XenbusStateInitialised); | ||
269 | break; | ||
270 | |||
271 | case XenbusStateConnected: | ||
272 | if (xb_dev->state != XenbusStateInitialised) | ||
273 | break; | ||
274 | |||
275 | ret = sndback_connect(front_info); | ||
276 | if (ret < 0) | ||
277 | xenbus_dev_fatal(xb_dev, ret, "initializing frontend"); | ||
278 | else | ||
279 | xenbus_switch_state(xb_dev, XenbusStateConnected); | ||
280 | break; | ||
281 | |||
282 | case XenbusStateClosing: | ||
283 | /* | ||
284 | * In this state backend starts freeing resources, | ||
285 | * so let it go into closed state first, so we can also | ||
286 | * remove ours. | ||
287 | */ | ||
288 | break; | ||
289 | |||
290 | case XenbusStateUnknown: | ||
291 | /* fall through */ | ||
292 | case XenbusStateClosed: | ||
293 | if (xb_dev->state == XenbusStateClosed) | ||
294 | break; | ||
295 | |||
296 | sndback_disconnect(front_info); | ||
297 | break; | ||
298 | } | ||
299 | } | ||
300 | |||
301 | static int xen_drv_probe(struct xenbus_device *xb_dev, | ||
302 | const struct xenbus_device_id *id) | ||
303 | { | ||
304 | struct xen_snd_front_info *front_info; | ||
305 | |||
306 | front_info = devm_kzalloc(&xb_dev->dev, | ||
307 | sizeof(*front_info), GFP_KERNEL); | ||
308 | if (!front_info) | ||
309 | return -ENOMEM; | ||
310 | |||
311 | front_info->xb_dev = xb_dev; | ||
312 | dev_set_drvdata(&xb_dev->dev, front_info); | ||
313 | |||
314 | return xenbus_switch_state(xb_dev, XenbusStateInitialising); | ||
315 | } | ||
316 | |||
317 | static int xen_drv_remove(struct xenbus_device *dev) | ||
318 | { | ||
319 | struct xen_snd_front_info *front_info = dev_get_drvdata(&dev->dev); | ||
320 | int to = 100; | ||
321 | |||
322 | xenbus_switch_state(dev, XenbusStateClosing); | ||
323 | |||
324 | /* | ||
325 | * On driver removal it is disconnected from XenBus, | ||
326 | * so no backend state change events come via .otherend_changed | ||
327 | * callback. This prevents us from exiting gracefully, e.g. | ||
328 | * signaling the backend to free event channels, waiting for its | ||
329 | * state to change to XenbusStateClosed and cleaning at our end. | ||
330 | * Normally when front driver removed backend will finally go into | ||
331 | * XenbusStateInitWait state. | ||
332 | * | ||
333 | * Workaround: read backend's state manually and wait with time-out. | ||
334 | */ | ||
335 | while ((xenbus_read_unsigned(front_info->xb_dev->otherend, "state", | ||
336 | XenbusStateUnknown) != XenbusStateInitWait) && | ||
337 | --to) | ||
338 | msleep(10); | ||
339 | |||
340 | if (!to) { | ||
341 | unsigned int state; | ||
342 | |||
343 | state = xenbus_read_unsigned(front_info->xb_dev->otherend, | ||
344 | "state", XenbusStateUnknown); | ||
345 | pr_err("Backend state is %s while removing driver\n", | ||
346 | xenbus_strstate(state)); | ||
347 | } | ||
348 | |||
349 | xen_snd_drv_fini(front_info); | ||
350 | xenbus_frontend_closed(dev); | ||
351 | return 0; | ||
352 | } | ||
353 | |||
354 | static const struct xenbus_device_id xen_drv_ids[] = { | ||
355 | { XENSND_DRIVER_NAME }, | ||
356 | { "" } | ||
357 | }; | ||
358 | |||
359 | static struct xenbus_driver xen_driver = { | ||
360 | .ids = xen_drv_ids, | ||
361 | .probe = xen_drv_probe, | ||
362 | .remove = xen_drv_remove, | ||
363 | .otherend_changed = sndback_changed, | ||
364 | }; | ||
365 | |||
366 | static int __init xen_drv_init(void) | ||
367 | { | ||
368 | if (!xen_domain()) | ||
369 | return -ENODEV; | ||
370 | |||
371 | if (!xen_has_pv_devices()) | ||
372 | return -ENODEV; | ||
373 | |||
374 | /* At the moment we only support case with XEN_PAGE_SIZE == PAGE_SIZE */ | ||
375 | if (XEN_PAGE_SIZE != PAGE_SIZE) { | ||
376 | pr_err(XENSND_DRIVER_NAME ": different kernel and Xen page sizes are not supported: XEN_PAGE_SIZE (%lu) != PAGE_SIZE (%lu)\n", | ||
377 | XEN_PAGE_SIZE, PAGE_SIZE); | ||
378 | return -ENODEV; | ||
379 | } | ||
380 | |||
381 | pr_info("Initialising Xen " XENSND_DRIVER_NAME " frontend driver\n"); | ||
382 | return xenbus_register_frontend(&xen_driver); | ||
383 | } | ||
384 | |||
385 | static void __exit xen_drv_fini(void) | ||
386 | { | ||
387 | pr_info("Unregistering Xen " XENSND_DRIVER_NAME " frontend driver\n"); | ||
388 | xenbus_unregister_driver(&xen_driver); | ||
389 | } | ||
390 | |||
391 | module_init(xen_drv_init); | ||
392 | module_exit(xen_drv_fini); | ||
393 | |||
394 | MODULE_DESCRIPTION("Xen virtual sound device frontend"); | ||
395 | MODULE_LICENSE("GPL"); | ||
396 | MODULE_ALIAS("xen:" XENSND_DRIVER_NAME); | ||
397 | MODULE_SUPPORTED_DEVICE("{{ALSA,Virtual soundcard}}"); | ||
diff --git a/sound/xen/xen_snd_front.h b/sound/xen/xen_snd_front.h new file mode 100644 index 000000000000..a2ea2463bcc5 --- /dev/null +++ b/sound/xen/xen_snd_front.h | |||
@@ -0,0 +1,54 @@ | |||
1 | /* SPDX-License-Identifier: GPL-2.0 OR MIT */ | ||
2 | |||
3 | /* | ||
4 | * Xen para-virtual sound device | ||
5 | * | ||
6 | * Copyright (C) 2016-2018 EPAM Systems Inc. | ||
7 | * | ||
8 | * Author: Oleksandr Andrushchenko <oleksandr_andrushchenko@epam.com> | ||
9 | */ | ||
10 | |||
11 | #ifndef __XEN_SND_FRONT_H | ||
12 | #define __XEN_SND_FRONT_H | ||
13 | |||
14 | #include "xen_snd_front_cfg.h" | ||
15 | |||
16 | struct xen_snd_front_card_info; | ||
17 | struct xen_snd_front_evtchnl; | ||
18 | struct xen_snd_front_evtchnl_pair; | ||
19 | struct xen_snd_front_shbuf; | ||
20 | struct xensnd_query_hw_param; | ||
21 | |||
22 | struct xen_snd_front_info { | ||
23 | struct xenbus_device *xb_dev; | ||
24 | |||
25 | struct xen_snd_front_card_info *card_info; | ||
26 | |||
27 | int num_evt_pairs; | ||
28 | struct xen_snd_front_evtchnl_pair *evt_pairs; | ||
29 | |||
30 | struct xen_front_cfg_card cfg; | ||
31 | }; | ||
32 | |||
33 | int xen_snd_front_stream_query_hw_param(struct xen_snd_front_evtchnl *evtchnl, | ||
34 | struct xensnd_query_hw_param *hw_param_req, | ||
35 | struct xensnd_query_hw_param *hw_param_resp); | ||
36 | |||
37 | int xen_snd_front_stream_prepare(struct xen_snd_front_evtchnl *evtchnl, | ||
38 | struct xen_snd_front_shbuf *sh_buf, | ||
39 | u8 format, unsigned int channels, | ||
40 | unsigned int rate, u32 buffer_sz, | ||
41 | u32 period_sz); | ||
42 | |||
43 | int xen_snd_front_stream_close(struct xen_snd_front_evtchnl *evtchnl); | ||
44 | |||
45 | int xen_snd_front_stream_write(struct xen_snd_front_evtchnl *evtchnl, | ||
46 | unsigned long pos, unsigned long count); | ||
47 | |||
48 | int xen_snd_front_stream_read(struct xen_snd_front_evtchnl *evtchnl, | ||
49 | unsigned long pos, unsigned long count); | ||
50 | |||
51 | int xen_snd_front_stream_trigger(struct xen_snd_front_evtchnl *evtchnl, | ||
52 | int type); | ||
53 | |||
54 | #endif /* __XEN_SND_FRONT_H */ | ||
diff --git a/sound/xen/xen_snd_front_alsa.c b/sound/xen/xen_snd_front_alsa.c new file mode 100644 index 000000000000..5a2bd70a2fa1 --- /dev/null +++ b/sound/xen/xen_snd_front_alsa.c | |||
@@ -0,0 +1,822 @@ | |||
1 | // SPDX-License-Identifier: GPL-2.0 OR MIT | ||
2 | |||
3 | /* | ||
4 | * Xen para-virtual sound device | ||
5 | * | ||
6 | * Copyright (C) 2016-2018 EPAM Systems Inc. | ||
7 | * | ||
8 | * Author: Oleksandr Andrushchenko <oleksandr_andrushchenko@epam.com> | ||
9 | */ | ||
10 | |||
11 | #include <linux/platform_device.h> | ||
12 | |||
13 | #include <sound/core.h> | ||
14 | #include <sound/pcm.h> | ||
15 | #include <sound/pcm_params.h> | ||
16 | |||
17 | #include <xen/xenbus.h> | ||
18 | |||
19 | #include "xen_snd_front.h" | ||
20 | #include "xen_snd_front_alsa.h" | ||
21 | #include "xen_snd_front_cfg.h" | ||
22 | #include "xen_snd_front_evtchnl.h" | ||
23 | #include "xen_snd_front_shbuf.h" | ||
24 | |||
25 | struct xen_snd_front_pcm_stream_info { | ||
26 | struct xen_snd_front_info *front_info; | ||
27 | struct xen_snd_front_evtchnl_pair *evt_pair; | ||
28 | struct xen_snd_front_shbuf sh_buf; | ||
29 | int index; | ||
30 | |||
31 | bool is_open; | ||
32 | struct snd_pcm_hardware pcm_hw; | ||
33 | |||
34 | /* Number of processed frames as reported by the backend. */ | ||
35 | snd_pcm_uframes_t be_cur_frame; | ||
36 | /* Current HW pointer to be reported via .period callback. */ | ||
37 | atomic_t hw_ptr; | ||
38 | /* Modulo of the number of processed frames - for period detection. */ | ||
39 | u32 out_frames; | ||
40 | }; | ||
41 | |||
42 | struct xen_snd_front_pcm_instance_info { | ||
43 | struct xen_snd_front_card_info *card_info; | ||
44 | struct snd_pcm *pcm; | ||
45 | struct snd_pcm_hardware pcm_hw; | ||
46 | int num_pcm_streams_pb; | ||
47 | struct xen_snd_front_pcm_stream_info *streams_pb; | ||
48 | int num_pcm_streams_cap; | ||
49 | struct xen_snd_front_pcm_stream_info *streams_cap; | ||
50 | }; | ||
51 | |||
52 | struct xen_snd_front_card_info { | ||
53 | struct xen_snd_front_info *front_info; | ||
54 | struct snd_card *card; | ||
55 | struct snd_pcm_hardware pcm_hw; | ||
56 | int num_pcm_instances; | ||
57 | struct xen_snd_front_pcm_instance_info *pcm_instances; | ||
58 | }; | ||
59 | |||
60 | struct alsa_sndif_sample_format { | ||
61 | u8 sndif; | ||
62 | snd_pcm_format_t alsa; | ||
63 | }; | ||
64 | |||
65 | struct alsa_sndif_hw_param { | ||
66 | u8 sndif; | ||
67 | snd_pcm_hw_param_t alsa; | ||
68 | }; | ||
69 | |||
70 | static const struct alsa_sndif_sample_format ALSA_SNDIF_FORMATS[] = { | ||
71 | { | ||
72 | .sndif = XENSND_PCM_FORMAT_U8, | ||
73 | .alsa = SNDRV_PCM_FORMAT_U8 | ||
74 | }, | ||
75 | { | ||
76 | .sndif = XENSND_PCM_FORMAT_S8, | ||
77 | .alsa = SNDRV_PCM_FORMAT_S8 | ||
78 | }, | ||
79 | { | ||
80 | .sndif = XENSND_PCM_FORMAT_U16_LE, | ||
81 | .alsa = SNDRV_PCM_FORMAT_U16_LE | ||
82 | }, | ||
83 | { | ||
84 | .sndif = XENSND_PCM_FORMAT_U16_BE, | ||
85 | .alsa = SNDRV_PCM_FORMAT_U16_BE | ||
86 | }, | ||
87 | { | ||
88 | .sndif = XENSND_PCM_FORMAT_S16_LE, | ||
89 | .alsa = SNDRV_PCM_FORMAT_S16_LE | ||
90 | }, | ||
91 | { | ||
92 | .sndif = XENSND_PCM_FORMAT_S16_BE, | ||
93 | .alsa = SNDRV_PCM_FORMAT_S16_BE | ||
94 | }, | ||
95 | { | ||
96 | .sndif = XENSND_PCM_FORMAT_U24_LE, | ||
97 | .alsa = SNDRV_PCM_FORMAT_U24_LE | ||
98 | }, | ||
99 | { | ||
100 | .sndif = XENSND_PCM_FORMAT_U24_BE, | ||
101 | .alsa = SNDRV_PCM_FORMAT_U24_BE | ||
102 | }, | ||
103 | { | ||
104 | .sndif = XENSND_PCM_FORMAT_S24_LE, | ||
105 | .alsa = SNDRV_PCM_FORMAT_S24_LE | ||
106 | }, | ||
107 | { | ||
108 | .sndif = XENSND_PCM_FORMAT_S24_BE, | ||
109 | .alsa = SNDRV_PCM_FORMAT_S24_BE | ||
110 | }, | ||
111 | { | ||
112 | .sndif = XENSND_PCM_FORMAT_U32_LE, | ||
113 | .alsa = SNDRV_PCM_FORMAT_U32_LE | ||
114 | }, | ||
115 | { | ||
116 | .sndif = XENSND_PCM_FORMAT_U32_BE, | ||
117 | .alsa = SNDRV_PCM_FORMAT_U32_BE | ||
118 | }, | ||
119 | { | ||
120 | .sndif = XENSND_PCM_FORMAT_S32_LE, | ||
121 | .alsa = SNDRV_PCM_FORMAT_S32_LE | ||
122 | }, | ||
123 | { | ||
124 | .sndif = XENSND_PCM_FORMAT_S32_BE, | ||
125 | .alsa = SNDRV_PCM_FORMAT_S32_BE | ||
126 | }, | ||
127 | { | ||
128 | .sndif = XENSND_PCM_FORMAT_A_LAW, | ||
129 | .alsa = SNDRV_PCM_FORMAT_A_LAW | ||
130 | }, | ||
131 | { | ||
132 | .sndif = XENSND_PCM_FORMAT_MU_LAW, | ||
133 | .alsa = SNDRV_PCM_FORMAT_MU_LAW | ||
134 | }, | ||
135 | { | ||
136 | .sndif = XENSND_PCM_FORMAT_F32_LE, | ||
137 | .alsa = SNDRV_PCM_FORMAT_FLOAT_LE | ||
138 | }, | ||
139 | { | ||
140 | .sndif = XENSND_PCM_FORMAT_F32_BE, | ||
141 | .alsa = SNDRV_PCM_FORMAT_FLOAT_BE | ||
142 | }, | ||
143 | { | ||
144 | .sndif = XENSND_PCM_FORMAT_F64_LE, | ||
145 | .alsa = SNDRV_PCM_FORMAT_FLOAT64_LE | ||
146 | }, | ||
147 | { | ||
148 | .sndif = XENSND_PCM_FORMAT_F64_BE, | ||
149 | .alsa = SNDRV_PCM_FORMAT_FLOAT64_BE | ||
150 | }, | ||
151 | { | ||
152 | .sndif = XENSND_PCM_FORMAT_IEC958_SUBFRAME_LE, | ||
153 | .alsa = SNDRV_PCM_FORMAT_IEC958_SUBFRAME_LE | ||
154 | }, | ||
155 | { | ||
156 | .sndif = XENSND_PCM_FORMAT_IEC958_SUBFRAME_BE, | ||
157 | .alsa = SNDRV_PCM_FORMAT_IEC958_SUBFRAME_BE | ||
158 | }, | ||
159 | { | ||
160 | .sndif = XENSND_PCM_FORMAT_IMA_ADPCM, | ||
161 | .alsa = SNDRV_PCM_FORMAT_IMA_ADPCM | ||
162 | }, | ||
163 | { | ||
164 | .sndif = XENSND_PCM_FORMAT_MPEG, | ||
165 | .alsa = SNDRV_PCM_FORMAT_MPEG | ||
166 | }, | ||
167 | { | ||
168 | .sndif = XENSND_PCM_FORMAT_GSM, | ||
169 | .alsa = SNDRV_PCM_FORMAT_GSM | ||
170 | }, | ||
171 | }; | ||
172 | |||
173 | static int to_sndif_format(snd_pcm_format_t format) | ||
174 | { | ||
175 | int i; | ||
176 | |||
177 | for (i = 0; i < ARRAY_SIZE(ALSA_SNDIF_FORMATS); i++) | ||
178 | if (ALSA_SNDIF_FORMATS[i].alsa == format) | ||
179 | return ALSA_SNDIF_FORMATS[i].sndif; | ||
180 | |||
181 | return -EINVAL; | ||
182 | } | ||
183 | |||
184 | static u64 to_sndif_formats_mask(u64 alsa_formats) | ||
185 | { | ||
186 | u64 mask; | ||
187 | int i; | ||
188 | |||
189 | mask = 0; | ||
190 | for (i = 0; i < ARRAY_SIZE(ALSA_SNDIF_FORMATS); i++) | ||
191 | if (1 << ALSA_SNDIF_FORMATS[i].alsa & alsa_formats) | ||
192 | mask |= 1 << ALSA_SNDIF_FORMATS[i].sndif; | ||
193 | |||
194 | return mask; | ||
195 | } | ||
196 | |||
197 | static u64 to_alsa_formats_mask(u64 sndif_formats) | ||
198 | { | ||
199 | u64 mask; | ||
200 | int i; | ||
201 | |||
202 | mask = 0; | ||
203 | for (i = 0; i < ARRAY_SIZE(ALSA_SNDIF_FORMATS); i++) | ||
204 | if (1 << ALSA_SNDIF_FORMATS[i].sndif & sndif_formats) | ||
205 | mask |= 1 << ALSA_SNDIF_FORMATS[i].alsa; | ||
206 | |||
207 | return mask; | ||
208 | } | ||
209 | |||
210 | static void stream_clear(struct xen_snd_front_pcm_stream_info *stream) | ||
211 | { | ||
212 | stream->is_open = false; | ||
213 | stream->be_cur_frame = 0; | ||
214 | stream->out_frames = 0; | ||
215 | atomic_set(&stream->hw_ptr, 0); | ||
216 | xen_snd_front_evtchnl_pair_clear(stream->evt_pair); | ||
217 | xen_snd_front_shbuf_clear(&stream->sh_buf); | ||
218 | } | ||
219 | |||
220 | static void stream_free(struct xen_snd_front_pcm_stream_info *stream) | ||
221 | { | ||
222 | xen_snd_front_shbuf_free(&stream->sh_buf); | ||
223 | stream_clear(stream); | ||
224 | } | ||
225 | |||
226 | static struct xen_snd_front_pcm_stream_info * | ||
227 | stream_get(struct snd_pcm_substream *substream) | ||
228 | { | ||
229 | struct xen_snd_front_pcm_instance_info *pcm_instance = | ||
230 | snd_pcm_substream_chip(substream); | ||
231 | struct xen_snd_front_pcm_stream_info *stream; | ||
232 | |||
233 | if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) | ||
234 | stream = &pcm_instance->streams_pb[substream->number]; | ||
235 | else | ||
236 | stream = &pcm_instance->streams_cap[substream->number]; | ||
237 | |||
238 | return stream; | ||
239 | } | ||
240 | |||
241 | static int alsa_hw_rule(struct snd_pcm_hw_params *params, | ||
242 | struct snd_pcm_hw_rule *rule) | ||
243 | { | ||
244 | struct xen_snd_front_pcm_stream_info *stream = rule->private; | ||
245 | struct device *dev = &stream->front_info->xb_dev->dev; | ||
246 | struct snd_mask *formats = | ||
247 | hw_param_mask(params, SNDRV_PCM_HW_PARAM_FORMAT); | ||
248 | struct snd_interval *rates = | ||
249 | hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE); | ||
250 | struct snd_interval *channels = | ||
251 | hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS); | ||
252 | struct snd_interval *period = | ||
253 | hw_param_interval(params, | ||
254 | SNDRV_PCM_HW_PARAM_PERIOD_SIZE); | ||
255 | struct snd_interval *buffer = | ||
256 | hw_param_interval(params, | ||
257 | SNDRV_PCM_HW_PARAM_BUFFER_SIZE); | ||
258 | struct xensnd_query_hw_param req; | ||
259 | struct xensnd_query_hw_param resp; | ||
260 | struct snd_interval interval; | ||
261 | struct snd_mask mask; | ||
262 | u64 sndif_formats; | ||
263 | int changed, ret; | ||
264 | |||
265 | /* Collect all the values we need for the query. */ | ||
266 | |||
267 | req.formats = to_sndif_formats_mask((u64)formats->bits[0] | | ||
268 | (u64)(formats->bits[1]) << 32); | ||
269 | |||
270 | req.rates.min = rates->min; | ||
271 | req.rates.max = rates->max; | ||
272 | |||
273 | req.channels.min = channels->min; | ||
274 | req.channels.max = channels->max; | ||
275 | |||
276 | req.buffer.min = buffer->min; | ||
277 | req.buffer.max = buffer->max; | ||
278 | |||
279 | req.period.min = period->min; | ||
280 | req.period.max = period->max; | ||
281 | |||
282 | ret = xen_snd_front_stream_query_hw_param(&stream->evt_pair->req, | ||
283 | &req, &resp); | ||
284 | if (ret < 0) { | ||
285 | /* Check if this is due to backend communication error. */ | ||
286 | if (ret == -EIO || ret == -ETIMEDOUT) | ||
287 | dev_err(dev, "Failed to query ALSA HW parameters\n"); | ||
288 | return ret; | ||
289 | } | ||
290 | |||
291 | /* Refine HW parameters after the query. */ | ||
292 | changed = 0; | ||
293 | |||
294 | sndif_formats = to_alsa_formats_mask(resp.formats); | ||
295 | snd_mask_none(&mask); | ||
296 | mask.bits[0] = (u32)sndif_formats; | ||
297 | mask.bits[1] = (u32)(sndif_formats >> 32); | ||
298 | ret = snd_mask_refine(formats, &mask); | ||
299 | if (ret < 0) | ||
300 | return ret; | ||
301 | changed |= ret; | ||
302 | |||
303 | interval.openmin = 0; | ||
304 | interval.openmax = 0; | ||
305 | interval.integer = 1; | ||
306 | |||
307 | interval.min = resp.rates.min; | ||
308 | interval.max = resp.rates.max; | ||
309 | ret = snd_interval_refine(rates, &interval); | ||
310 | if (ret < 0) | ||
311 | return ret; | ||
312 | changed |= ret; | ||
313 | |||
314 | interval.min = resp.channels.min; | ||
315 | interval.max = resp.channels.max; | ||
316 | ret = snd_interval_refine(channels, &interval); | ||
317 | if (ret < 0) | ||
318 | return ret; | ||
319 | changed |= ret; | ||
320 | |||
321 | interval.min = resp.buffer.min; | ||
322 | interval.max = resp.buffer.max; | ||
323 | ret = snd_interval_refine(buffer, &interval); | ||
324 | if (ret < 0) | ||
325 | return ret; | ||
326 | changed |= ret; | ||
327 | |||
328 | interval.min = resp.period.min; | ||
329 | interval.max = resp.period.max; | ||
330 | ret = snd_interval_refine(period, &interval); | ||
331 | if (ret < 0) | ||
332 | return ret; | ||
333 | changed |= ret; | ||
334 | |||
335 | return changed; | ||
336 | } | ||
337 | |||
338 | static int alsa_open(struct snd_pcm_substream *substream) | ||
339 | { | ||
340 | struct xen_snd_front_pcm_instance_info *pcm_instance = | ||
341 | snd_pcm_substream_chip(substream); | ||
342 | struct xen_snd_front_pcm_stream_info *stream = stream_get(substream); | ||
343 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
344 | struct xen_snd_front_info *front_info = | ||
345 | pcm_instance->card_info->front_info; | ||
346 | struct device *dev = &front_info->xb_dev->dev; | ||
347 | int ret; | ||
348 | |||
349 | /* | ||
350 | * Return our HW properties: override defaults with those configured | ||
351 | * via XenStore. | ||
352 | */ | ||
353 | runtime->hw = stream->pcm_hw; | ||
354 | runtime->hw.info &= ~(SNDRV_PCM_INFO_MMAP | | ||
355 | SNDRV_PCM_INFO_MMAP_VALID | | ||
356 | SNDRV_PCM_INFO_DOUBLE | | ||
357 | SNDRV_PCM_INFO_BATCH | | ||
358 | SNDRV_PCM_INFO_NONINTERLEAVED | | ||
359 | SNDRV_PCM_INFO_RESUME | | ||
360 | SNDRV_PCM_INFO_PAUSE); | ||
361 | runtime->hw.info |= SNDRV_PCM_INFO_INTERLEAVED; | ||
362 | |||
363 | stream->evt_pair = &front_info->evt_pairs[stream->index]; | ||
364 | |||
365 | stream->front_info = front_info; | ||
366 | |||
367 | stream->evt_pair->evt.u.evt.substream = substream; | ||
368 | |||
369 | stream_clear(stream); | ||
370 | |||
371 | xen_snd_front_evtchnl_pair_set_connected(stream->evt_pair, true); | ||
372 | |||
373 | ret = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_FORMAT, | ||
374 | alsa_hw_rule, stream, | ||
375 | SNDRV_PCM_HW_PARAM_FORMAT, -1); | ||
376 | if (ret) { | ||
377 | dev_err(dev, "Failed to add HW rule for SNDRV_PCM_HW_PARAM_FORMAT\n"); | ||
378 | return ret; | ||
379 | } | ||
380 | |||
381 | ret = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_RATE, | ||
382 | alsa_hw_rule, stream, | ||
383 | SNDRV_PCM_HW_PARAM_RATE, -1); | ||
384 | if (ret) { | ||
385 | dev_err(dev, "Failed to add HW rule for SNDRV_PCM_HW_PARAM_RATE\n"); | ||
386 | return ret; | ||
387 | } | ||
388 | |||
389 | ret = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS, | ||
390 | alsa_hw_rule, stream, | ||
391 | SNDRV_PCM_HW_PARAM_CHANNELS, -1); | ||
392 | if (ret) { | ||
393 | dev_err(dev, "Failed to add HW rule for SNDRV_PCM_HW_PARAM_CHANNELS\n"); | ||
394 | return ret; | ||
395 | } | ||
396 | |||
397 | ret = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_PERIOD_SIZE, | ||
398 | alsa_hw_rule, stream, | ||
399 | SNDRV_PCM_HW_PARAM_PERIOD_SIZE, -1); | ||
400 | if (ret) { | ||
401 | dev_err(dev, "Failed to add HW rule for SNDRV_PCM_HW_PARAM_PERIOD_SIZE\n"); | ||
402 | return ret; | ||
403 | } | ||
404 | |||
405 | ret = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_BUFFER_SIZE, | ||
406 | alsa_hw_rule, stream, | ||
407 | SNDRV_PCM_HW_PARAM_BUFFER_SIZE, -1); | ||
408 | if (ret) { | ||
409 | dev_err(dev, "Failed to add HW rule for SNDRV_PCM_HW_PARAM_BUFFER_SIZE\n"); | ||
410 | return ret; | ||
411 | } | ||
412 | |||
413 | return 0; | ||
414 | } | ||
415 | |||
416 | static int alsa_close(struct snd_pcm_substream *substream) | ||
417 | { | ||
418 | struct xen_snd_front_pcm_stream_info *stream = stream_get(substream); | ||
419 | |||
420 | xen_snd_front_evtchnl_pair_set_connected(stream->evt_pair, false); | ||
421 | return 0; | ||
422 | } | ||
423 | |||
424 | static int alsa_hw_params(struct snd_pcm_substream *substream, | ||
425 | struct snd_pcm_hw_params *params) | ||
426 | { | ||
427 | struct xen_snd_front_pcm_stream_info *stream = stream_get(substream); | ||
428 | int ret; | ||
429 | |||
430 | /* | ||
431 | * This callback may be called multiple times, | ||
432 | * so free the previously allocated shared buffer if any. | ||
433 | */ | ||
434 | stream_free(stream); | ||
435 | |||
436 | ret = xen_snd_front_shbuf_alloc(stream->front_info->xb_dev, | ||
437 | &stream->sh_buf, | ||
438 | params_buffer_bytes(params)); | ||
439 | if (ret < 0) { | ||
440 | stream_free(stream); | ||
441 | dev_err(&stream->front_info->xb_dev->dev, | ||
442 | "Failed to allocate buffers for stream with index %d\n", | ||
443 | stream->index); | ||
444 | return ret; | ||
445 | } | ||
446 | |||
447 | return 0; | ||
448 | } | ||
449 | |||
450 | static int alsa_hw_free(struct snd_pcm_substream *substream) | ||
451 | { | ||
452 | struct xen_snd_front_pcm_stream_info *stream = stream_get(substream); | ||
453 | int ret; | ||
454 | |||
455 | ret = xen_snd_front_stream_close(&stream->evt_pair->req); | ||
456 | stream_free(stream); | ||
457 | return ret; | ||
458 | } | ||
459 | |||
460 | static int alsa_prepare(struct snd_pcm_substream *substream) | ||
461 | { | ||
462 | struct xen_snd_front_pcm_stream_info *stream = stream_get(substream); | ||
463 | |||
464 | if (!stream->is_open) { | ||
465 | struct snd_pcm_runtime *runtime = substream->runtime; | ||
466 | u8 sndif_format; | ||
467 | int ret; | ||
468 | |||
469 | ret = to_sndif_format(runtime->format); | ||
470 | if (ret < 0) { | ||
471 | dev_err(&stream->front_info->xb_dev->dev, | ||
472 | "Unsupported sample format: %d\n", | ||
473 | runtime->format); | ||
474 | return ret; | ||
475 | } | ||
476 | sndif_format = ret; | ||
477 | |||
478 | ret = xen_snd_front_stream_prepare(&stream->evt_pair->req, | ||
479 | &stream->sh_buf, | ||
480 | sndif_format, | ||
481 | runtime->channels, | ||
482 | runtime->rate, | ||
483 | snd_pcm_lib_buffer_bytes(substream), | ||
484 | snd_pcm_lib_period_bytes(substream)); | ||
485 | if (ret < 0) | ||
486 | return ret; | ||
487 | |||
488 | stream->is_open = true; | ||
489 | } | ||
490 | |||
491 | return 0; | ||
492 | } | ||
493 | |||
494 | static int alsa_trigger(struct snd_pcm_substream *substream, int cmd) | ||
495 | { | ||
496 | struct xen_snd_front_pcm_stream_info *stream = stream_get(substream); | ||
497 | int type; | ||
498 | |||
499 | switch (cmd) { | ||
500 | case SNDRV_PCM_TRIGGER_START: | ||
501 | type = XENSND_OP_TRIGGER_START; | ||
502 | break; | ||
503 | |||
504 | case SNDRV_PCM_TRIGGER_RESUME: | ||
505 | type = XENSND_OP_TRIGGER_RESUME; | ||
506 | break; | ||
507 | |||
508 | case SNDRV_PCM_TRIGGER_STOP: | ||
509 | type = XENSND_OP_TRIGGER_STOP; | ||
510 | break; | ||
511 | |||
512 | case SNDRV_PCM_TRIGGER_SUSPEND: | ||
513 | type = XENSND_OP_TRIGGER_PAUSE; | ||
514 | break; | ||
515 | |||
516 | default: | ||
517 | return -EINVAL; | ||
518 | } | ||
519 | |||
520 | return xen_snd_front_stream_trigger(&stream->evt_pair->req, type); | ||
521 | } | ||
522 | |||
523 | void xen_snd_front_alsa_handle_cur_pos(struct xen_snd_front_evtchnl *evtchnl, | ||
524 | u64 pos_bytes) | ||
525 | { | ||
526 | struct snd_pcm_substream *substream = evtchnl->u.evt.substream; | ||
527 | struct xen_snd_front_pcm_stream_info *stream = stream_get(substream); | ||
528 | snd_pcm_uframes_t delta, new_hw_ptr, cur_frame; | ||
529 | |||
530 | cur_frame = bytes_to_frames(substream->runtime, pos_bytes); | ||
531 | |||
532 | delta = cur_frame - stream->be_cur_frame; | ||
533 | stream->be_cur_frame = cur_frame; | ||
534 | |||
535 | new_hw_ptr = (snd_pcm_uframes_t)atomic_read(&stream->hw_ptr); | ||
536 | new_hw_ptr = (new_hw_ptr + delta) % substream->runtime->buffer_size; | ||
537 | atomic_set(&stream->hw_ptr, (int)new_hw_ptr); | ||
538 | |||
539 | stream->out_frames += delta; | ||
540 | if (stream->out_frames > substream->runtime->period_size) { | ||
541 | stream->out_frames %= substream->runtime->period_size; | ||
542 | snd_pcm_period_elapsed(substream); | ||
543 | } | ||
544 | } | ||
545 | |||
546 | static snd_pcm_uframes_t alsa_pointer(struct snd_pcm_substream *substream) | ||
547 | { | ||
548 | struct xen_snd_front_pcm_stream_info *stream = stream_get(substream); | ||
549 | |||
550 | return (snd_pcm_uframes_t)atomic_read(&stream->hw_ptr); | ||
551 | } | ||
552 | |||
553 | static int alsa_pb_copy_user(struct snd_pcm_substream *substream, | ||
554 | int channel, unsigned long pos, void __user *src, | ||
555 | unsigned long count) | ||
556 | { | ||
557 | struct xen_snd_front_pcm_stream_info *stream = stream_get(substream); | ||
558 | |||
559 | if (unlikely(pos + count > stream->sh_buf.buffer_sz)) | ||
560 | return -EINVAL; | ||
561 | |||
562 | if (copy_from_user(stream->sh_buf.buffer + pos, src, count)) | ||
563 | return -EFAULT; | ||
564 | |||
565 | return xen_snd_front_stream_write(&stream->evt_pair->req, pos, count); | ||
566 | } | ||
567 | |||
568 | static int alsa_pb_copy_kernel(struct snd_pcm_substream *substream, | ||
569 | int channel, unsigned long pos, void *src, | ||
570 | unsigned long count) | ||
571 | { | ||
572 | struct xen_snd_front_pcm_stream_info *stream = stream_get(substream); | ||
573 | |||
574 | if (unlikely(pos + count > stream->sh_buf.buffer_sz)) | ||
575 | return -EINVAL; | ||
576 | |||
577 | memcpy(stream->sh_buf.buffer + pos, src, count); | ||
578 | |||
579 | return xen_snd_front_stream_write(&stream->evt_pair->req, pos, count); | ||
580 | } | ||
581 | |||
582 | static int alsa_cap_copy_user(struct snd_pcm_substream *substream, | ||
583 | int channel, unsigned long pos, void __user *dst, | ||
584 | unsigned long count) | ||
585 | { | ||
586 | struct xen_snd_front_pcm_stream_info *stream = stream_get(substream); | ||
587 | int ret; | ||
588 | |||
589 | if (unlikely(pos + count > stream->sh_buf.buffer_sz)) | ||
590 | return -EINVAL; | ||
591 | |||
592 | ret = xen_snd_front_stream_read(&stream->evt_pair->req, pos, count); | ||
593 | if (ret < 0) | ||
594 | return ret; | ||
595 | |||
596 | return copy_to_user(dst, stream->sh_buf.buffer + pos, count) ? | ||
597 | -EFAULT : 0; | ||
598 | } | ||
599 | |||
600 | static int alsa_cap_copy_kernel(struct snd_pcm_substream *substream, | ||
601 | int channel, unsigned long pos, void *dst, | ||
602 | unsigned long count) | ||
603 | { | ||
604 | struct xen_snd_front_pcm_stream_info *stream = stream_get(substream); | ||
605 | int ret; | ||
606 | |||
607 | if (unlikely(pos + count > stream->sh_buf.buffer_sz)) | ||
608 | return -EINVAL; | ||
609 | |||
610 | ret = xen_snd_front_stream_read(&stream->evt_pair->req, pos, count); | ||
611 | if (ret < 0) | ||
612 | return ret; | ||
613 | |||
614 | memcpy(dst, stream->sh_buf.buffer + pos, count); | ||
615 | |||
616 | return 0; | ||
617 | } | ||
618 | |||
619 | static int alsa_pb_fill_silence(struct snd_pcm_substream *substream, | ||
620 | int channel, unsigned long pos, | ||
621 | unsigned long count) | ||
622 | { | ||
623 | struct xen_snd_front_pcm_stream_info *stream = stream_get(substream); | ||
624 | |||
625 | if (unlikely(pos + count > stream->sh_buf.buffer_sz)) | ||
626 | return -EINVAL; | ||
627 | |||
628 | memset(stream->sh_buf.buffer + pos, 0, count); | ||
629 | |||
630 | return xen_snd_front_stream_write(&stream->evt_pair->req, pos, count); | ||
631 | } | ||
632 | |||
633 | /* | ||
634 | * FIXME: The mmaped data transfer is asynchronous and there is no | ||
635 | * ack signal from user-space when it is done. This is the | ||
636 | * reason it is not implemented in the PV driver as we do need | ||
637 | * to know when the buffer can be transferred to the backend. | ||
638 | */ | ||
639 | |||
640 | static struct snd_pcm_ops snd_drv_alsa_playback_ops = { | ||
641 | .open = alsa_open, | ||
642 | .close = alsa_close, | ||
643 | .ioctl = snd_pcm_lib_ioctl, | ||
644 | .hw_params = alsa_hw_params, | ||
645 | .hw_free = alsa_hw_free, | ||
646 | .prepare = alsa_prepare, | ||
647 | .trigger = alsa_trigger, | ||
648 | .pointer = alsa_pointer, | ||
649 | .copy_user = alsa_pb_copy_user, | ||
650 | .copy_kernel = alsa_pb_copy_kernel, | ||
651 | .fill_silence = alsa_pb_fill_silence, | ||
652 | }; | ||
653 | |||
654 | static struct snd_pcm_ops snd_drv_alsa_capture_ops = { | ||
655 | .open = alsa_open, | ||
656 | .close = alsa_close, | ||
657 | .ioctl = snd_pcm_lib_ioctl, | ||
658 | .hw_params = alsa_hw_params, | ||
659 | .hw_free = alsa_hw_free, | ||
660 | .prepare = alsa_prepare, | ||
661 | .trigger = alsa_trigger, | ||
662 | .pointer = alsa_pointer, | ||
663 | .copy_user = alsa_cap_copy_user, | ||
664 | .copy_kernel = alsa_cap_copy_kernel, | ||
665 | }; | ||
666 | |||
667 | static int new_pcm_instance(struct xen_snd_front_card_info *card_info, | ||
668 | struct xen_front_cfg_pcm_instance *instance_cfg, | ||
669 | struct xen_snd_front_pcm_instance_info *pcm_instance_info) | ||
670 | { | ||
671 | struct snd_pcm *pcm; | ||
672 | int ret, i; | ||
673 | |||
674 | dev_dbg(&card_info->front_info->xb_dev->dev, | ||
675 | "New PCM device \"%s\" with id %d playback %d capture %d", | ||
676 | instance_cfg->name, | ||
677 | instance_cfg->device_id, | ||
678 | instance_cfg->num_streams_pb, | ||
679 | instance_cfg->num_streams_cap); | ||
680 | |||
681 | pcm_instance_info->card_info = card_info; | ||
682 | |||
683 | pcm_instance_info->pcm_hw = instance_cfg->pcm_hw; | ||
684 | |||
685 | if (instance_cfg->num_streams_pb) { | ||
686 | pcm_instance_info->streams_pb = | ||
687 | devm_kcalloc(&card_info->card->card_dev, | ||
688 | instance_cfg->num_streams_pb, | ||
689 | sizeof(struct xen_snd_front_pcm_stream_info), | ||
690 | GFP_KERNEL); | ||
691 | if (!pcm_instance_info->streams_pb) | ||
692 | return -ENOMEM; | ||
693 | } | ||
694 | |||
695 | if (instance_cfg->num_streams_cap) { | ||
696 | pcm_instance_info->streams_cap = | ||
697 | devm_kcalloc(&card_info->card->card_dev, | ||
698 | instance_cfg->num_streams_cap, | ||
699 | sizeof(struct xen_snd_front_pcm_stream_info), | ||
700 | GFP_KERNEL); | ||
701 | if (!pcm_instance_info->streams_cap) | ||
702 | return -ENOMEM; | ||
703 | } | ||
704 | |||
705 | pcm_instance_info->num_pcm_streams_pb = | ||
706 | instance_cfg->num_streams_pb; | ||
707 | pcm_instance_info->num_pcm_streams_cap = | ||
708 | instance_cfg->num_streams_cap; | ||
709 | |||
710 | for (i = 0; i < pcm_instance_info->num_pcm_streams_pb; i++) { | ||
711 | pcm_instance_info->streams_pb[i].pcm_hw = | ||
712 | instance_cfg->streams_pb[i].pcm_hw; | ||
713 | pcm_instance_info->streams_pb[i].index = | ||
714 | instance_cfg->streams_pb[i].index; | ||
715 | } | ||
716 | |||
717 | for (i = 0; i < pcm_instance_info->num_pcm_streams_cap; i++) { | ||
718 | pcm_instance_info->streams_cap[i].pcm_hw = | ||
719 | instance_cfg->streams_cap[i].pcm_hw; | ||
720 | pcm_instance_info->streams_cap[i].index = | ||
721 | instance_cfg->streams_cap[i].index; | ||
722 | } | ||
723 | |||
724 | ret = snd_pcm_new(card_info->card, instance_cfg->name, | ||
725 | instance_cfg->device_id, | ||
726 | instance_cfg->num_streams_pb, | ||
727 | instance_cfg->num_streams_cap, | ||
728 | &pcm); | ||
729 | if (ret < 0) | ||
730 | return ret; | ||
731 | |||
732 | pcm->private_data = pcm_instance_info; | ||
733 | pcm->info_flags = 0; | ||
734 | /* we want to handle all PCM operations in non-atomic context */ | ||
735 | pcm->nonatomic = true; | ||
736 | strncpy(pcm->name, "Virtual card PCM", sizeof(pcm->name)); | ||
737 | |||
738 | if (instance_cfg->num_streams_pb) | ||
739 | snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_PLAYBACK, | ||
740 | &snd_drv_alsa_playback_ops); | ||
741 | |||
742 | if (instance_cfg->num_streams_cap) | ||
743 | snd_pcm_set_ops(pcm, SNDRV_PCM_STREAM_CAPTURE, | ||
744 | &snd_drv_alsa_capture_ops); | ||
745 | |||
746 | pcm_instance_info->pcm = pcm; | ||
747 | return 0; | ||
748 | } | ||
749 | |||
750 | int xen_snd_front_alsa_init(struct xen_snd_front_info *front_info) | ||
751 | { | ||
752 | struct device *dev = &front_info->xb_dev->dev; | ||
753 | struct xen_front_cfg_card *cfg = &front_info->cfg; | ||
754 | struct xen_snd_front_card_info *card_info; | ||
755 | struct snd_card *card; | ||
756 | int ret, i; | ||
757 | |||
758 | dev_dbg(dev, "Creating virtual sound card\n"); | ||
759 | |||
760 | ret = snd_card_new(dev, 0, XENSND_DRIVER_NAME, THIS_MODULE, | ||
761 | sizeof(struct xen_snd_front_card_info), &card); | ||
762 | if (ret < 0) | ||
763 | return ret; | ||
764 | |||
765 | card_info = card->private_data; | ||
766 | card_info->front_info = front_info; | ||
767 | front_info->card_info = card_info; | ||
768 | card_info->card = card; | ||
769 | card_info->pcm_instances = | ||
770 | devm_kcalloc(dev, cfg->num_pcm_instances, | ||
771 | sizeof(struct xen_snd_front_pcm_instance_info), | ||
772 | GFP_KERNEL); | ||
773 | if (!card_info->pcm_instances) { | ||
774 | ret = -ENOMEM; | ||
775 | goto fail; | ||
776 | } | ||
777 | |||
778 | card_info->num_pcm_instances = cfg->num_pcm_instances; | ||
779 | card_info->pcm_hw = cfg->pcm_hw; | ||
780 | |||
781 | for (i = 0; i < cfg->num_pcm_instances; i++) { | ||
782 | ret = new_pcm_instance(card_info, &cfg->pcm_instances[i], | ||
783 | &card_info->pcm_instances[i]); | ||
784 | if (ret < 0) | ||
785 | goto fail; | ||
786 | } | ||
787 | |||
788 | strncpy(card->driver, XENSND_DRIVER_NAME, sizeof(card->driver)); | ||
789 | strncpy(card->shortname, cfg->name_short, sizeof(card->shortname)); | ||
790 | strncpy(card->longname, cfg->name_long, sizeof(card->longname)); | ||
791 | |||
792 | ret = snd_card_register(card); | ||
793 | if (ret < 0) | ||
794 | goto fail; | ||
795 | |||
796 | return 0; | ||
797 | |||
798 | fail: | ||
799 | snd_card_free(card); | ||
800 | return ret; | ||
801 | } | ||
802 | |||
803 | void xen_snd_front_alsa_fini(struct xen_snd_front_info *front_info) | ||
804 | { | ||
805 | struct xen_snd_front_card_info *card_info; | ||
806 | struct snd_card *card; | ||
807 | |||
808 | card_info = front_info->card_info; | ||
809 | if (!card_info) | ||
810 | return; | ||
811 | |||
812 | card = card_info->card; | ||
813 | if (!card) | ||
814 | return; | ||
815 | |||
816 | dev_dbg(&front_info->xb_dev->dev, "Removing virtual sound card %d\n", | ||
817 | card->number); | ||
818 | snd_card_free(card); | ||
819 | |||
820 | /* Card_info will be freed when destroying front_info->xb_dev->dev. */ | ||
821 | card_info->card = NULL; | ||
822 | } | ||
diff --git a/sound/xen/xen_snd_front_alsa.h b/sound/xen/xen_snd_front_alsa.h new file mode 100644 index 000000000000..18abd9eec967 --- /dev/null +++ b/sound/xen/xen_snd_front_alsa.h | |||
@@ -0,0 +1,23 @@ | |||
1 | /* SPDX-License-Identifier: GPL-2.0 OR MIT */ | ||
2 | |||
3 | /* | ||
4 | * Xen para-virtual sound device | ||
5 | * | ||
6 | * Copyright (C) 2016-2018 EPAM Systems Inc. | ||
7 | * | ||
8 | * Author: Oleksandr Andrushchenko <oleksandr_andrushchenko@epam.com> | ||
9 | */ | ||
10 | |||
11 | #ifndef __XEN_SND_FRONT_ALSA_H | ||
12 | #define __XEN_SND_FRONT_ALSA_H | ||
13 | |||
14 | struct xen_snd_front_info; | ||
15 | |||
16 | int xen_snd_front_alsa_init(struct xen_snd_front_info *front_info); | ||
17 | |||
18 | void xen_snd_front_alsa_fini(struct xen_snd_front_info *front_info); | ||
19 | |||
20 | void xen_snd_front_alsa_handle_cur_pos(struct xen_snd_front_evtchnl *evtchnl, | ||
21 | u64 pos_bytes); | ||
22 | |||
23 | #endif /* __XEN_SND_FRONT_ALSA_H */ | ||
diff --git a/sound/xen/xen_snd_front_cfg.c b/sound/xen/xen_snd_front_cfg.c new file mode 100644 index 000000000000..eda077c8087a --- /dev/null +++ b/sound/xen/xen_snd_front_cfg.c | |||
@@ -0,0 +1,519 @@ | |||
1 | // SPDX-License-Identifier: GPL-2.0 OR MIT | ||
2 | |||
3 | /* | ||
4 | * Xen para-virtual sound device | ||
5 | * | ||
6 | * Copyright (C) 2016-2018 EPAM Systems Inc. | ||
7 | * | ||
8 | * Author: Oleksandr Andrushchenko <oleksandr_andrushchenko@epam.com> | ||
9 | */ | ||
10 | |||
11 | #include <xen/xenbus.h> | ||
12 | |||
13 | #include <xen/interface/io/sndif.h> | ||
14 | |||
15 | #include "xen_snd_front.h" | ||
16 | #include "xen_snd_front_cfg.h" | ||
17 | |||
18 | /* Maximum number of supported streams. */ | ||
19 | #define VSND_MAX_STREAM 8 | ||
20 | |||
21 | struct cfg_hw_sample_rate { | ||
22 | const char *name; | ||
23 | unsigned int mask; | ||
24 | unsigned int value; | ||
25 | }; | ||
26 | |||
27 | static const struct cfg_hw_sample_rate CFG_HW_SUPPORTED_RATES[] = { | ||
28 | { .name = "5512", .mask = SNDRV_PCM_RATE_5512, .value = 5512 }, | ||
29 | { .name = "8000", .mask = SNDRV_PCM_RATE_8000, .value = 8000 }, | ||
30 | { .name = "11025", .mask = SNDRV_PCM_RATE_11025, .value = 11025 }, | ||
31 | { .name = "16000", .mask = SNDRV_PCM_RATE_16000, .value = 16000 }, | ||
32 | { .name = "22050", .mask = SNDRV_PCM_RATE_22050, .value = 22050 }, | ||
33 | { .name = "32000", .mask = SNDRV_PCM_RATE_32000, .value = 32000 }, | ||
34 | { .name = "44100", .mask = SNDRV_PCM_RATE_44100, .value = 44100 }, | ||
35 | { .name = "48000", .mask = SNDRV_PCM_RATE_48000, .value = 48000 }, | ||
36 | { .name = "64000", .mask = SNDRV_PCM_RATE_64000, .value = 64000 }, | ||
37 | { .name = "96000", .mask = SNDRV_PCM_RATE_96000, .value = 96000 }, | ||
38 | { .name = "176400", .mask = SNDRV_PCM_RATE_176400, .value = 176400 }, | ||
39 | { .name = "192000", .mask = SNDRV_PCM_RATE_192000, .value = 192000 }, | ||
40 | }; | ||
41 | |||
42 | struct cfg_hw_sample_format { | ||
43 | const char *name; | ||
44 | u64 mask; | ||
45 | }; | ||
46 | |||
47 | static const struct cfg_hw_sample_format CFG_HW_SUPPORTED_FORMATS[] = { | ||
48 | { | ||
49 | .name = XENSND_PCM_FORMAT_U8_STR, | ||
50 | .mask = SNDRV_PCM_FMTBIT_U8 | ||
51 | }, | ||
52 | { | ||
53 | .name = XENSND_PCM_FORMAT_S8_STR, | ||
54 | .mask = SNDRV_PCM_FMTBIT_S8 | ||
55 | }, | ||
56 | { | ||
57 | .name = XENSND_PCM_FORMAT_U16_LE_STR, | ||
58 | .mask = SNDRV_PCM_FMTBIT_U16_LE | ||
59 | }, | ||
60 | { | ||
61 | .name = XENSND_PCM_FORMAT_U16_BE_STR, | ||
62 | .mask = SNDRV_PCM_FMTBIT_U16_BE | ||
63 | }, | ||
64 | { | ||
65 | .name = XENSND_PCM_FORMAT_S16_LE_STR, | ||
66 | .mask = SNDRV_PCM_FMTBIT_S16_LE | ||
67 | }, | ||
68 | { | ||
69 | .name = XENSND_PCM_FORMAT_S16_BE_STR, | ||
70 | .mask = SNDRV_PCM_FMTBIT_S16_BE | ||
71 | }, | ||
72 | { | ||
73 | .name = XENSND_PCM_FORMAT_U24_LE_STR, | ||
74 | .mask = SNDRV_PCM_FMTBIT_U24_LE | ||
75 | }, | ||
76 | { | ||
77 | .name = XENSND_PCM_FORMAT_U24_BE_STR, | ||
78 | .mask = SNDRV_PCM_FMTBIT_U24_BE | ||
79 | }, | ||
80 | { | ||
81 | .name = XENSND_PCM_FORMAT_S24_LE_STR, | ||
82 | .mask = SNDRV_PCM_FMTBIT_S24_LE | ||
83 | }, | ||
84 | { | ||
85 | .name = XENSND_PCM_FORMAT_S24_BE_STR, | ||
86 | .mask = SNDRV_PCM_FMTBIT_S24_BE | ||
87 | }, | ||
88 | { | ||
89 | .name = XENSND_PCM_FORMAT_U32_LE_STR, | ||
90 | .mask = SNDRV_PCM_FMTBIT_U32_LE | ||
91 | }, | ||
92 | { | ||
93 | .name = XENSND_PCM_FORMAT_U32_BE_STR, | ||
94 | .mask = SNDRV_PCM_FMTBIT_U32_BE | ||
95 | }, | ||
96 | { | ||
97 | .name = XENSND_PCM_FORMAT_S32_LE_STR, | ||
98 | .mask = SNDRV_PCM_FMTBIT_S32_LE | ||
99 | }, | ||
100 | { | ||
101 | .name = XENSND_PCM_FORMAT_S32_BE_STR, | ||
102 | .mask = SNDRV_PCM_FMTBIT_S32_BE | ||
103 | }, | ||
104 | { | ||
105 | .name = XENSND_PCM_FORMAT_A_LAW_STR, | ||
106 | .mask = SNDRV_PCM_FMTBIT_A_LAW | ||
107 | }, | ||
108 | { | ||
109 | .name = XENSND_PCM_FORMAT_MU_LAW_STR, | ||
110 | .mask = SNDRV_PCM_FMTBIT_MU_LAW | ||
111 | }, | ||
112 | { | ||
113 | .name = XENSND_PCM_FORMAT_F32_LE_STR, | ||
114 | .mask = SNDRV_PCM_FMTBIT_FLOAT_LE | ||
115 | }, | ||
116 | { | ||
117 | .name = XENSND_PCM_FORMAT_F32_BE_STR, | ||
118 | .mask = SNDRV_PCM_FMTBIT_FLOAT_BE | ||
119 | }, | ||
120 | { | ||
121 | .name = XENSND_PCM_FORMAT_F64_LE_STR, | ||
122 | .mask = SNDRV_PCM_FMTBIT_FLOAT64_LE | ||
123 | }, | ||
124 | { | ||
125 | .name = XENSND_PCM_FORMAT_F64_BE_STR, | ||
126 | .mask = SNDRV_PCM_FMTBIT_FLOAT64_BE | ||
127 | }, | ||
128 | { | ||
129 | .name = XENSND_PCM_FORMAT_IEC958_SUBFRAME_LE_STR, | ||
130 | .mask = SNDRV_PCM_FMTBIT_IEC958_SUBFRAME_LE | ||
131 | }, | ||
132 | { | ||
133 | .name = XENSND_PCM_FORMAT_IEC958_SUBFRAME_BE_STR, | ||
134 | .mask = SNDRV_PCM_FMTBIT_IEC958_SUBFRAME_BE | ||
135 | }, | ||
136 | { | ||
137 | .name = XENSND_PCM_FORMAT_IMA_ADPCM_STR, | ||
138 | .mask = SNDRV_PCM_FMTBIT_IMA_ADPCM | ||
139 | }, | ||
140 | { | ||
141 | .name = XENSND_PCM_FORMAT_MPEG_STR, | ||
142 | .mask = SNDRV_PCM_FMTBIT_MPEG | ||
143 | }, | ||
144 | { | ||
145 | .name = XENSND_PCM_FORMAT_GSM_STR, | ||
146 | .mask = SNDRV_PCM_FMTBIT_GSM | ||
147 | }, | ||
148 | }; | ||
149 | |||
150 | static void cfg_hw_rates(char *list, unsigned int len, | ||
151 | const char *path, struct snd_pcm_hardware *pcm_hw) | ||
152 | { | ||
153 | char *cur_rate; | ||
154 | unsigned int cur_mask; | ||
155 | unsigned int cur_value; | ||
156 | unsigned int rates; | ||
157 | unsigned int rate_min; | ||
158 | unsigned int rate_max; | ||
159 | int i; | ||
160 | |||
161 | rates = 0; | ||
162 | rate_min = -1; | ||
163 | rate_max = 0; | ||
164 | while ((cur_rate = strsep(&list, XENSND_LIST_SEPARATOR))) { | ||
165 | for (i = 0; i < ARRAY_SIZE(CFG_HW_SUPPORTED_RATES); i++) | ||
166 | if (!strncasecmp(cur_rate, | ||
167 | CFG_HW_SUPPORTED_RATES[i].name, | ||
168 | XENSND_SAMPLE_RATE_MAX_LEN)) { | ||
169 | cur_mask = CFG_HW_SUPPORTED_RATES[i].mask; | ||
170 | cur_value = CFG_HW_SUPPORTED_RATES[i].value; | ||
171 | rates |= cur_mask; | ||
172 | if (rate_min > cur_value) | ||
173 | rate_min = cur_value; | ||
174 | if (rate_max < cur_value) | ||
175 | rate_max = cur_value; | ||
176 | } | ||
177 | } | ||
178 | |||
179 | if (rates) { | ||
180 | pcm_hw->rates = rates; | ||
181 | pcm_hw->rate_min = rate_min; | ||
182 | pcm_hw->rate_max = rate_max; | ||
183 | } | ||
184 | } | ||
185 | |||
186 | static void cfg_formats(char *list, unsigned int len, | ||
187 | const char *path, struct snd_pcm_hardware *pcm_hw) | ||
188 | { | ||
189 | u64 formats; | ||
190 | char *cur_format; | ||
191 | int i; | ||
192 | |||
193 | formats = 0; | ||
194 | while ((cur_format = strsep(&list, XENSND_LIST_SEPARATOR))) { | ||
195 | for (i = 0; i < ARRAY_SIZE(CFG_HW_SUPPORTED_FORMATS); i++) | ||
196 | if (!strncasecmp(cur_format, | ||
197 | CFG_HW_SUPPORTED_FORMATS[i].name, | ||
198 | XENSND_SAMPLE_FORMAT_MAX_LEN)) | ||
199 | formats |= CFG_HW_SUPPORTED_FORMATS[i].mask; | ||
200 | } | ||
201 | |||
202 | if (formats) | ||
203 | pcm_hw->formats = formats; | ||
204 | } | ||
205 | |||
206 | #define MAX_BUFFER_SIZE (64 * 1024) | ||
207 | #define MIN_PERIOD_SIZE 64 | ||
208 | #define MAX_PERIOD_SIZE MAX_BUFFER_SIZE | ||
209 | #define USE_FORMATS (SNDRV_PCM_FMTBIT_U8 | \ | ||
210 | SNDRV_PCM_FMTBIT_S16_LE) | ||
211 | #define USE_RATE (SNDRV_PCM_RATE_CONTINUOUS | \ | ||
212 | SNDRV_PCM_RATE_8000_48000) | ||
213 | #define USE_RATE_MIN 5512 | ||
214 | #define USE_RATE_MAX 48000 | ||
215 | #define USE_CHANNELS_MIN 1 | ||
216 | #define USE_CHANNELS_MAX 2 | ||
217 | #define USE_PERIODS_MIN 2 | ||
218 | #define USE_PERIODS_MAX (MAX_BUFFER_SIZE / MIN_PERIOD_SIZE) | ||
219 | |||
220 | static const struct snd_pcm_hardware SND_DRV_PCM_HW_DEFAULT = { | ||
221 | .info = (SNDRV_PCM_INFO_MMAP | | ||
222 | SNDRV_PCM_INFO_INTERLEAVED | | ||
223 | SNDRV_PCM_INFO_RESUME | | ||
224 | SNDRV_PCM_INFO_MMAP_VALID), | ||
225 | .formats = USE_FORMATS, | ||
226 | .rates = USE_RATE, | ||
227 | .rate_min = USE_RATE_MIN, | ||
228 | .rate_max = USE_RATE_MAX, | ||
229 | .channels_min = USE_CHANNELS_MIN, | ||
230 | .channels_max = USE_CHANNELS_MAX, | ||
231 | .buffer_bytes_max = MAX_BUFFER_SIZE, | ||
232 | .period_bytes_min = MIN_PERIOD_SIZE, | ||
233 | .period_bytes_max = MAX_PERIOD_SIZE, | ||
234 | .periods_min = USE_PERIODS_MIN, | ||
235 | .periods_max = USE_PERIODS_MAX, | ||
236 | .fifo_size = 0, | ||
237 | }; | ||
238 | |||
239 | static void cfg_read_pcm_hw(const char *path, | ||
240 | struct snd_pcm_hardware *parent_pcm_hw, | ||
241 | struct snd_pcm_hardware *pcm_hw) | ||
242 | { | ||
243 | char *list; | ||
244 | int val; | ||
245 | size_t buf_sz; | ||
246 | unsigned int len; | ||
247 | |||
248 | /* Inherit parent's PCM HW and read overrides from XenStore. */ | ||
249 | if (parent_pcm_hw) | ||
250 | *pcm_hw = *parent_pcm_hw; | ||
251 | else | ||
252 | *pcm_hw = SND_DRV_PCM_HW_DEFAULT; | ||
253 | |||
254 | val = xenbus_read_unsigned(path, XENSND_FIELD_CHANNELS_MIN, 0); | ||
255 | if (val) | ||
256 | pcm_hw->channels_min = val; | ||
257 | |||
258 | val = xenbus_read_unsigned(path, XENSND_FIELD_CHANNELS_MAX, 0); | ||
259 | if (val) | ||
260 | pcm_hw->channels_max = val; | ||
261 | |||
262 | list = xenbus_read(XBT_NIL, path, XENSND_FIELD_SAMPLE_RATES, &len); | ||
263 | if (!IS_ERR(list)) { | ||
264 | cfg_hw_rates(list, len, path, pcm_hw); | ||
265 | kfree(list); | ||
266 | } | ||
267 | |||
268 | list = xenbus_read(XBT_NIL, path, XENSND_FIELD_SAMPLE_FORMATS, &len); | ||
269 | if (!IS_ERR(list)) { | ||
270 | cfg_formats(list, len, path, pcm_hw); | ||
271 | kfree(list); | ||
272 | } | ||
273 | |||
274 | buf_sz = xenbus_read_unsigned(path, XENSND_FIELD_BUFFER_SIZE, 0); | ||
275 | if (buf_sz) | ||
276 | pcm_hw->buffer_bytes_max = buf_sz; | ||
277 | |||
278 | /* Update configuration to match new values. */ | ||
279 | if (pcm_hw->channels_min > pcm_hw->channels_max) | ||
280 | pcm_hw->channels_min = pcm_hw->channels_max; | ||
281 | |||
282 | if (pcm_hw->rate_min > pcm_hw->rate_max) | ||
283 | pcm_hw->rate_min = pcm_hw->rate_max; | ||
284 | |||
285 | pcm_hw->period_bytes_max = pcm_hw->buffer_bytes_max; | ||
286 | |||
287 | pcm_hw->periods_max = pcm_hw->period_bytes_max / | ||
288 | pcm_hw->period_bytes_min; | ||
289 | } | ||
290 | |||
291 | static int cfg_get_stream_type(const char *path, int index, | ||
292 | int *num_pb, int *num_cap) | ||
293 | { | ||
294 | char *str = NULL; | ||
295 | char *stream_path; | ||
296 | int ret; | ||
297 | |||
298 | *num_pb = 0; | ||
299 | *num_cap = 0; | ||
300 | stream_path = kasprintf(GFP_KERNEL, "%s/%d", path, index); | ||
301 | if (!stream_path) { | ||
302 | ret = -ENOMEM; | ||
303 | goto fail; | ||
304 | } | ||
305 | |||
306 | str = xenbus_read(XBT_NIL, stream_path, XENSND_FIELD_TYPE, NULL); | ||
307 | if (IS_ERR(str)) { | ||
308 | ret = PTR_ERR(str); | ||
309 | str = NULL; | ||
310 | goto fail; | ||
311 | } | ||
312 | |||
313 | if (!strncasecmp(str, XENSND_STREAM_TYPE_PLAYBACK, | ||
314 | sizeof(XENSND_STREAM_TYPE_PLAYBACK))) { | ||
315 | (*num_pb)++; | ||
316 | } else if (!strncasecmp(str, XENSND_STREAM_TYPE_CAPTURE, | ||
317 | sizeof(XENSND_STREAM_TYPE_CAPTURE))) { | ||
318 | (*num_cap)++; | ||
319 | } else { | ||
320 | ret = -EINVAL; | ||
321 | goto fail; | ||
322 | } | ||
323 | ret = 0; | ||
324 | |||
325 | fail: | ||
326 | kfree(stream_path); | ||
327 | kfree(str); | ||
328 | return ret; | ||
329 | } | ||
330 | |||
331 | static int cfg_stream(struct xen_snd_front_info *front_info, | ||
332 | struct xen_front_cfg_pcm_instance *pcm_instance, | ||
333 | const char *path, int index, int *cur_pb, int *cur_cap, | ||
334 | int *stream_cnt) | ||
335 | { | ||
336 | char *str = NULL; | ||
337 | char *stream_path; | ||
338 | struct xen_front_cfg_stream *stream; | ||
339 | int ret; | ||
340 | |||
341 | stream_path = devm_kasprintf(&front_info->xb_dev->dev, | ||
342 | GFP_KERNEL, "%s/%d", path, index); | ||
343 | if (!stream_path) { | ||
344 | ret = -ENOMEM; | ||
345 | goto fail; | ||
346 | } | ||
347 | |||
348 | str = xenbus_read(XBT_NIL, stream_path, XENSND_FIELD_TYPE, NULL); | ||
349 | if (IS_ERR(str)) { | ||
350 | ret = PTR_ERR(str); | ||
351 | str = NULL; | ||
352 | goto fail; | ||
353 | } | ||
354 | |||
355 | if (!strncasecmp(str, XENSND_STREAM_TYPE_PLAYBACK, | ||
356 | sizeof(XENSND_STREAM_TYPE_PLAYBACK))) { | ||
357 | stream = &pcm_instance->streams_pb[(*cur_pb)++]; | ||
358 | } else if (!strncasecmp(str, XENSND_STREAM_TYPE_CAPTURE, | ||
359 | sizeof(XENSND_STREAM_TYPE_CAPTURE))) { | ||
360 | stream = &pcm_instance->streams_cap[(*cur_cap)++]; | ||
361 | } else { | ||
362 | ret = -EINVAL; | ||
363 | goto fail; | ||
364 | } | ||
365 | |||
366 | /* Get next stream index. */ | ||
367 | stream->index = (*stream_cnt)++; | ||
368 | stream->xenstore_path = stream_path; | ||
369 | /* | ||
370 | * Check XenStore if PCM HW configuration exists for this stream | ||
371 | * and update if so, e.g. we inherit all values from device's PCM HW, | ||
372 | * but can still override some of the values for the stream. | ||
373 | */ | ||
374 | cfg_read_pcm_hw(stream->xenstore_path, | ||
375 | &pcm_instance->pcm_hw, &stream->pcm_hw); | ||
376 | ret = 0; | ||
377 | |||
378 | fail: | ||
379 | kfree(str); | ||
380 | return ret; | ||
381 | } | ||
382 | |||
383 | static int cfg_device(struct xen_snd_front_info *front_info, | ||
384 | struct xen_front_cfg_pcm_instance *pcm_instance, | ||
385 | struct snd_pcm_hardware *parent_pcm_hw, | ||
386 | const char *path, int node_index, int *stream_cnt) | ||
387 | { | ||
388 | char *str; | ||
389 | char *device_path; | ||
390 | int ret, i, num_streams; | ||
391 | int num_pb, num_cap; | ||
392 | int cur_pb, cur_cap; | ||
393 | char node[3]; | ||
394 | |||
395 | device_path = kasprintf(GFP_KERNEL, "%s/%d", path, node_index); | ||
396 | if (!device_path) | ||
397 | return -ENOMEM; | ||
398 | |||
399 | str = xenbus_read(XBT_NIL, device_path, XENSND_FIELD_DEVICE_NAME, NULL); | ||
400 | if (!IS_ERR(str)) { | ||
401 | strlcpy(pcm_instance->name, str, sizeof(pcm_instance->name)); | ||
402 | kfree(str); | ||
403 | } | ||
404 | |||
405 | pcm_instance->device_id = node_index; | ||
406 | |||
407 | /* | ||
408 | * Check XenStore if PCM HW configuration exists for this device | ||
409 | * and update if so, e.g. we inherit all values from card's PCM HW, | ||
410 | * but can still override some of the values for the device. | ||
411 | */ | ||
412 | cfg_read_pcm_hw(device_path, parent_pcm_hw, &pcm_instance->pcm_hw); | ||
413 | |||
414 | /* Find out how many streams were configured in Xen store. */ | ||
415 | num_streams = 0; | ||
416 | do { | ||
417 | snprintf(node, sizeof(node), "%d", num_streams); | ||
418 | if (!xenbus_exists(XBT_NIL, device_path, node)) | ||
419 | break; | ||
420 | |||
421 | num_streams++; | ||
422 | } while (num_streams < VSND_MAX_STREAM); | ||
423 | |||
424 | pcm_instance->num_streams_pb = 0; | ||
425 | pcm_instance->num_streams_cap = 0; | ||
426 | /* Get number of playback and capture streams. */ | ||
427 | for (i = 0; i < num_streams; i++) { | ||
428 | ret = cfg_get_stream_type(device_path, i, &num_pb, &num_cap); | ||
429 | if (ret < 0) | ||
430 | goto fail; | ||
431 | |||
432 | pcm_instance->num_streams_pb += num_pb; | ||
433 | pcm_instance->num_streams_cap += num_cap; | ||
434 | } | ||
435 | |||
436 | if (pcm_instance->num_streams_pb) { | ||
437 | pcm_instance->streams_pb = | ||
438 | devm_kcalloc(&front_info->xb_dev->dev, | ||
439 | pcm_instance->num_streams_pb, | ||
440 | sizeof(struct xen_front_cfg_stream), | ||
441 | GFP_KERNEL); | ||
442 | if (!pcm_instance->streams_pb) { | ||
443 | ret = -ENOMEM; | ||
444 | goto fail; | ||
445 | } | ||
446 | } | ||
447 | |||
448 | if (pcm_instance->num_streams_cap) { | ||
449 | pcm_instance->streams_cap = | ||
450 | devm_kcalloc(&front_info->xb_dev->dev, | ||
451 | pcm_instance->num_streams_cap, | ||
452 | sizeof(struct xen_front_cfg_stream), | ||
453 | GFP_KERNEL); | ||
454 | if (!pcm_instance->streams_cap) { | ||
455 | ret = -ENOMEM; | ||
456 | goto fail; | ||
457 | } | ||
458 | } | ||
459 | |||
460 | cur_pb = 0; | ||
461 | cur_cap = 0; | ||
462 | for (i = 0; i < num_streams; i++) { | ||
463 | ret = cfg_stream(front_info, pcm_instance, device_path, i, | ||
464 | &cur_pb, &cur_cap, stream_cnt); | ||
465 | if (ret < 0) | ||
466 | goto fail; | ||
467 | } | ||
468 | ret = 0; | ||
469 | |||
470 | fail: | ||
471 | kfree(device_path); | ||
472 | return ret; | ||
473 | } | ||
474 | |||
475 | int xen_snd_front_cfg_card(struct xen_snd_front_info *front_info, | ||
476 | int *stream_cnt) | ||
477 | { | ||
478 | struct xenbus_device *xb_dev = front_info->xb_dev; | ||
479 | struct xen_front_cfg_card *cfg = &front_info->cfg; | ||
480 | int ret, num_devices, i; | ||
481 | char node[3]; | ||
482 | |||
483 | *stream_cnt = 0; | ||
484 | num_devices = 0; | ||
485 | do { | ||
486 | snprintf(node, sizeof(node), "%d", num_devices); | ||
487 | if (!xenbus_exists(XBT_NIL, xb_dev->nodename, node)) | ||
488 | break; | ||
489 | |||
490 | num_devices++; | ||
491 | } while (num_devices < SNDRV_PCM_DEVICES); | ||
492 | |||
493 | if (!num_devices) { | ||
494 | dev_warn(&xb_dev->dev, | ||
495 | "No devices configured for sound card at %s\n", | ||
496 | xb_dev->nodename); | ||
497 | return -ENODEV; | ||
498 | } | ||
499 | |||
500 | /* Start from default PCM HW configuration for the card. */ | ||
501 | cfg_read_pcm_hw(xb_dev->nodename, NULL, &cfg->pcm_hw); | ||
502 | |||
503 | cfg->pcm_instances = | ||
504 | devm_kcalloc(&front_info->xb_dev->dev, num_devices, | ||
505 | sizeof(struct xen_front_cfg_pcm_instance), | ||
506 | GFP_KERNEL); | ||
507 | if (!cfg->pcm_instances) | ||
508 | return -ENOMEM; | ||
509 | |||
510 | for (i = 0; i < num_devices; i++) { | ||
511 | ret = cfg_device(front_info, &cfg->pcm_instances[i], | ||
512 | &cfg->pcm_hw, xb_dev->nodename, i, stream_cnt); | ||
513 | if (ret < 0) | ||
514 | return ret; | ||
515 | } | ||
516 | cfg->num_pcm_instances = num_devices; | ||
517 | return 0; | ||
518 | } | ||
519 | |||
diff --git a/sound/xen/xen_snd_front_cfg.h b/sound/xen/xen_snd_front_cfg.h new file mode 100644 index 000000000000..2353fcc74889 --- /dev/null +++ b/sound/xen/xen_snd_front_cfg.h | |||
@@ -0,0 +1,46 @@ | |||
1 | /* SPDX-License-Identifier: GPL-2.0 OR MIT */ | ||
2 | |||
3 | /* | ||
4 | * Xen para-virtual sound device | ||
5 | * | ||
6 | * Copyright (C) 2016-2018 EPAM Systems Inc. | ||
7 | * | ||
8 | * Author: Oleksandr Andrushchenko <oleksandr_andrushchenko@epam.com> | ||
9 | */ | ||
10 | |||
11 | #ifndef __XEN_SND_FRONT_CFG_H | ||
12 | #define __XEN_SND_FRONT_CFG_H | ||
13 | |||
14 | #include <sound/core.h> | ||
15 | #include <sound/pcm.h> | ||
16 | |||
17 | struct xen_snd_front_info; | ||
18 | |||
19 | struct xen_front_cfg_stream { | ||
20 | int index; | ||
21 | char *xenstore_path; | ||
22 | struct snd_pcm_hardware pcm_hw; | ||
23 | }; | ||
24 | |||
25 | struct xen_front_cfg_pcm_instance { | ||
26 | char name[80]; | ||
27 | int device_id; | ||
28 | struct snd_pcm_hardware pcm_hw; | ||
29 | int num_streams_pb; | ||
30 | struct xen_front_cfg_stream *streams_pb; | ||
31 | int num_streams_cap; | ||
32 | struct xen_front_cfg_stream *streams_cap; | ||
33 | }; | ||
34 | |||
35 | struct xen_front_cfg_card { | ||
36 | char name_short[32]; | ||
37 | char name_long[80]; | ||
38 | struct snd_pcm_hardware pcm_hw; | ||
39 | int num_pcm_instances; | ||
40 | struct xen_front_cfg_pcm_instance *pcm_instances; | ||
41 | }; | ||
42 | |||
43 | int xen_snd_front_cfg_card(struct xen_snd_front_info *front_info, | ||
44 | int *stream_cnt); | ||
45 | |||
46 | #endif /* __XEN_SND_FRONT_CFG_H */ | ||
diff --git a/sound/xen/xen_snd_front_evtchnl.c b/sound/xen/xen_snd_front_evtchnl.c new file mode 100644 index 000000000000..102d6e096cc8 --- /dev/null +++ b/sound/xen/xen_snd_front_evtchnl.c | |||
@@ -0,0 +1,494 @@ | |||
1 | // SPDX-License-Identifier: GPL-2.0 OR MIT | ||
2 | |||
3 | /* | ||
4 | * Xen para-virtual sound device | ||
5 | * | ||
6 | * Copyright (C) 2016-2018 EPAM Systems Inc. | ||
7 | * | ||
8 | * Author: Oleksandr Andrushchenko <oleksandr_andrushchenko@epam.com> | ||
9 | */ | ||
10 | |||
11 | #include <xen/events.h> | ||
12 | #include <xen/grant_table.h> | ||
13 | #include <xen/xen.h> | ||
14 | #include <xen/xenbus.h> | ||
15 | |||
16 | #include "xen_snd_front.h" | ||
17 | #include "xen_snd_front_alsa.h" | ||
18 | #include "xen_snd_front_cfg.h" | ||
19 | #include "xen_snd_front_evtchnl.h" | ||
20 | |||
21 | static irqreturn_t evtchnl_interrupt_req(int irq, void *dev_id) | ||
22 | { | ||
23 | struct xen_snd_front_evtchnl *channel = dev_id; | ||
24 | struct xen_snd_front_info *front_info = channel->front_info; | ||
25 | struct xensnd_resp *resp; | ||
26 | RING_IDX i, rp; | ||
27 | |||
28 | if (unlikely(channel->state != EVTCHNL_STATE_CONNECTED)) | ||
29 | return IRQ_HANDLED; | ||
30 | |||
31 | mutex_lock(&channel->ring_io_lock); | ||
32 | |||
33 | again: | ||
34 | rp = channel->u.req.ring.sring->rsp_prod; | ||
35 | /* Ensure we see queued responses up to rp. */ | ||
36 | rmb(); | ||
37 | |||
38 | /* | ||
39 | * Assume that the backend is trusted to always write sane values | ||
40 | * to the ring counters, so no overflow checks on frontend side | ||
41 | * are required. | ||
42 | */ | ||
43 | for (i = channel->u.req.ring.rsp_cons; i != rp; i++) { | ||
44 | resp = RING_GET_RESPONSE(&channel->u.req.ring, i); | ||
45 | if (resp->id != channel->evt_id) | ||
46 | continue; | ||
47 | switch (resp->operation) { | ||
48 | case XENSND_OP_OPEN: | ||
49 | /* fall through */ | ||
50 | case XENSND_OP_CLOSE: | ||
51 | /* fall through */ | ||
52 | case XENSND_OP_READ: | ||
53 | /* fall through */ | ||
54 | case XENSND_OP_WRITE: | ||
55 | /* fall through */ | ||
56 | case XENSND_OP_TRIGGER: | ||
57 | channel->u.req.resp_status = resp->status; | ||
58 | complete(&channel->u.req.completion); | ||
59 | break; | ||
60 | case XENSND_OP_HW_PARAM_QUERY: | ||
61 | channel->u.req.resp_status = resp->status; | ||
62 | channel->u.req.resp.hw_param = | ||
63 | resp->resp.hw_param; | ||
64 | complete(&channel->u.req.completion); | ||
65 | break; | ||
66 | |||
67 | default: | ||
68 | dev_err(&front_info->xb_dev->dev, | ||
69 | "Operation %d is not supported\n", | ||
70 | resp->operation); | ||
71 | break; | ||
72 | } | ||
73 | } | ||
74 | |||
75 | channel->u.req.ring.rsp_cons = i; | ||
76 | if (i != channel->u.req.ring.req_prod_pvt) { | ||
77 | int more_to_do; | ||
78 | |||
79 | RING_FINAL_CHECK_FOR_RESPONSES(&channel->u.req.ring, | ||
80 | more_to_do); | ||
81 | if (more_to_do) | ||
82 | goto again; | ||
83 | } else { | ||
84 | channel->u.req.ring.sring->rsp_event = i + 1; | ||
85 | } | ||
86 | |||
87 | mutex_unlock(&channel->ring_io_lock); | ||
88 | return IRQ_HANDLED; | ||
89 | } | ||
90 | |||
91 | static irqreturn_t evtchnl_interrupt_evt(int irq, void *dev_id) | ||
92 | { | ||
93 | struct xen_snd_front_evtchnl *channel = dev_id; | ||
94 | struct xensnd_event_page *page = channel->u.evt.page; | ||
95 | u32 cons, prod; | ||
96 | |||
97 | if (unlikely(channel->state != EVTCHNL_STATE_CONNECTED)) | ||
98 | return IRQ_HANDLED; | ||
99 | |||
100 | mutex_lock(&channel->ring_io_lock); | ||
101 | |||
102 | prod = page->in_prod; | ||
103 | /* Ensure we see ring contents up to prod. */ | ||
104 | virt_rmb(); | ||
105 | if (prod == page->in_cons) | ||
106 | goto out; | ||
107 | |||
108 | /* | ||
109 | * Assume that the backend is trusted to always write sane values | ||
110 | * to the ring counters, so no overflow checks on frontend side | ||
111 | * are required. | ||
112 | */ | ||
113 | for (cons = page->in_cons; cons != prod; cons++) { | ||
114 | struct xensnd_evt *event; | ||
115 | |||
116 | event = &XENSND_IN_RING_REF(page, cons); | ||
117 | if (unlikely(event->id != channel->evt_id++)) | ||
118 | continue; | ||
119 | |||
120 | switch (event->type) { | ||
121 | case XENSND_EVT_CUR_POS: | ||
122 | xen_snd_front_alsa_handle_cur_pos(channel, | ||
123 | event->op.cur_pos.position); | ||
124 | break; | ||
125 | } | ||
126 | } | ||
127 | |||
128 | page->in_cons = cons; | ||
129 | /* Ensure ring contents. */ | ||
130 | virt_wmb(); | ||
131 | |||
132 | out: | ||
133 | mutex_unlock(&channel->ring_io_lock); | ||
134 | return IRQ_HANDLED; | ||
135 | } | ||
136 | |||
137 | void xen_snd_front_evtchnl_flush(struct xen_snd_front_evtchnl *channel) | ||
138 | { | ||
139 | int notify; | ||
140 | |||
141 | channel->u.req.ring.req_prod_pvt++; | ||
142 | RING_PUSH_REQUESTS_AND_CHECK_NOTIFY(&channel->u.req.ring, notify); | ||
143 | if (notify) | ||
144 | notify_remote_via_irq(channel->irq); | ||
145 | } | ||
146 | |||
147 | static void evtchnl_free(struct xen_snd_front_info *front_info, | ||
148 | struct xen_snd_front_evtchnl *channel) | ||
149 | { | ||
150 | unsigned long page = 0; | ||
151 | |||
152 | if (channel->type == EVTCHNL_TYPE_REQ) | ||
153 | page = (unsigned long)channel->u.req.ring.sring; | ||
154 | else if (channel->type == EVTCHNL_TYPE_EVT) | ||
155 | page = (unsigned long)channel->u.evt.page; | ||
156 | |||
157 | if (!page) | ||
158 | return; | ||
159 | |||
160 | channel->state = EVTCHNL_STATE_DISCONNECTED; | ||
161 | if (channel->type == EVTCHNL_TYPE_REQ) { | ||
162 | /* Release all who still waits for response if any. */ | ||
163 | channel->u.req.resp_status = -EIO; | ||
164 | complete_all(&channel->u.req.completion); | ||
165 | } | ||
166 | |||
167 | if (channel->irq) | ||
168 | unbind_from_irqhandler(channel->irq, channel); | ||
169 | |||
170 | if (channel->port) | ||
171 | xenbus_free_evtchn(front_info->xb_dev, channel->port); | ||
172 | |||
173 | /* End access and free the page. */ | ||
174 | if (channel->gref != GRANT_INVALID_REF) | ||
175 | gnttab_end_foreign_access(channel->gref, 0, page); | ||
176 | else | ||
177 | free_page(page); | ||
178 | |||
179 | memset(channel, 0, sizeof(*channel)); | ||
180 | } | ||
181 | |||
182 | void xen_snd_front_evtchnl_free_all(struct xen_snd_front_info *front_info) | ||
183 | { | ||
184 | int i; | ||
185 | |||
186 | if (!front_info->evt_pairs) | ||
187 | return; | ||
188 | |||
189 | for (i = 0; i < front_info->num_evt_pairs; i++) { | ||
190 | evtchnl_free(front_info, &front_info->evt_pairs[i].req); | ||
191 | evtchnl_free(front_info, &front_info->evt_pairs[i].evt); | ||
192 | } | ||
193 | |||
194 | kfree(front_info->evt_pairs); | ||
195 | front_info->evt_pairs = NULL; | ||
196 | } | ||
197 | |||
198 | static int evtchnl_alloc(struct xen_snd_front_info *front_info, int index, | ||
199 | struct xen_snd_front_evtchnl *channel, | ||
200 | enum xen_snd_front_evtchnl_type type) | ||
201 | { | ||
202 | struct xenbus_device *xb_dev = front_info->xb_dev; | ||
203 | unsigned long page; | ||
204 | grant_ref_t gref; | ||
205 | irq_handler_t handler; | ||
206 | char *handler_name = NULL; | ||
207 | int ret; | ||
208 | |||
209 | memset(channel, 0, sizeof(*channel)); | ||
210 | channel->type = type; | ||
211 | channel->index = index; | ||
212 | channel->front_info = front_info; | ||
213 | channel->state = EVTCHNL_STATE_DISCONNECTED; | ||
214 | channel->gref = GRANT_INVALID_REF; | ||
215 | page = get_zeroed_page(GFP_KERNEL); | ||
216 | if (!page) { | ||
217 | ret = -ENOMEM; | ||
218 | goto fail; | ||
219 | } | ||
220 | |||
221 | handler_name = kasprintf(GFP_KERNEL, "%s-%s", XENSND_DRIVER_NAME, | ||
222 | type == EVTCHNL_TYPE_REQ ? | ||
223 | XENSND_FIELD_RING_REF : | ||
224 | XENSND_FIELD_EVT_RING_REF); | ||
225 | if (!handler_name) { | ||
226 | ret = -ENOMEM; | ||
227 | goto fail; | ||
228 | } | ||
229 | |||
230 | mutex_init(&channel->ring_io_lock); | ||
231 | |||
232 | if (type == EVTCHNL_TYPE_REQ) { | ||
233 | struct xen_sndif_sring *sring = (struct xen_sndif_sring *)page; | ||
234 | |||
235 | init_completion(&channel->u.req.completion); | ||
236 | mutex_init(&channel->u.req.req_io_lock); | ||
237 | SHARED_RING_INIT(sring); | ||
238 | FRONT_RING_INIT(&channel->u.req.ring, sring, XEN_PAGE_SIZE); | ||
239 | |||
240 | ret = xenbus_grant_ring(xb_dev, sring, 1, &gref); | ||
241 | if (ret < 0) { | ||
242 | channel->u.req.ring.sring = NULL; | ||
243 | goto fail; | ||
244 | } | ||
245 | |||
246 | handler = evtchnl_interrupt_req; | ||
247 | } else { | ||
248 | ret = gnttab_grant_foreign_access(xb_dev->otherend_id, | ||
249 | virt_to_gfn((void *)page), 0); | ||
250 | if (ret < 0) | ||
251 | goto fail; | ||
252 | |||
253 | channel->u.evt.page = (struct xensnd_event_page *)page; | ||
254 | gref = ret; | ||
255 | handler = evtchnl_interrupt_evt; | ||
256 | } | ||
257 | |||
258 | channel->gref = gref; | ||
259 | |||
260 | ret = xenbus_alloc_evtchn(xb_dev, &channel->port); | ||
261 | if (ret < 0) | ||
262 | goto fail; | ||
263 | |||
264 | ret = bind_evtchn_to_irq(channel->port); | ||
265 | if (ret < 0) { | ||
266 | dev_err(&xb_dev->dev, | ||
267 | "Failed to bind IRQ for domid %d port %d: %d\n", | ||
268 | front_info->xb_dev->otherend_id, channel->port, ret); | ||
269 | goto fail; | ||
270 | } | ||
271 | |||
272 | channel->irq = ret; | ||
273 | |||
274 | ret = request_threaded_irq(channel->irq, NULL, handler, | ||
275 | IRQF_ONESHOT, handler_name, channel); | ||
276 | if (ret < 0) { | ||
277 | dev_err(&xb_dev->dev, "Failed to request IRQ %d: %d\n", | ||
278 | channel->irq, ret); | ||
279 | goto fail; | ||
280 | } | ||
281 | |||
282 | kfree(handler_name); | ||
283 | return 0; | ||
284 | |||
285 | fail: | ||
286 | if (page) | ||
287 | free_page(page); | ||
288 | kfree(handler_name); | ||
289 | dev_err(&xb_dev->dev, "Failed to allocate ring: %d\n", ret); | ||
290 | return ret; | ||
291 | } | ||
292 | |||
293 | int xen_snd_front_evtchnl_create_all(struct xen_snd_front_info *front_info, | ||
294 | int num_streams) | ||
295 | { | ||
296 | struct xen_front_cfg_card *cfg = &front_info->cfg; | ||
297 | struct device *dev = &front_info->xb_dev->dev; | ||
298 | int d, ret = 0; | ||
299 | |||
300 | front_info->evt_pairs = | ||
301 | kcalloc(num_streams, | ||
302 | sizeof(struct xen_snd_front_evtchnl_pair), | ||
303 | GFP_KERNEL); | ||
304 | if (!front_info->evt_pairs) | ||
305 | return -ENOMEM; | ||
306 | |||
307 | /* Iterate over devices and their streams and create event channels. */ | ||
308 | for (d = 0; d < cfg->num_pcm_instances; d++) { | ||
309 | struct xen_front_cfg_pcm_instance *pcm_instance; | ||
310 | int s, index; | ||
311 | |||
312 | pcm_instance = &cfg->pcm_instances[d]; | ||
313 | |||
314 | for (s = 0; s < pcm_instance->num_streams_pb; s++) { | ||
315 | index = pcm_instance->streams_pb[s].index; | ||
316 | |||
317 | ret = evtchnl_alloc(front_info, index, | ||
318 | &front_info->evt_pairs[index].req, | ||
319 | EVTCHNL_TYPE_REQ); | ||
320 | if (ret < 0) { | ||
321 | dev_err(dev, "Error allocating control channel\n"); | ||
322 | goto fail; | ||
323 | } | ||
324 | |||
325 | ret = evtchnl_alloc(front_info, index, | ||
326 | &front_info->evt_pairs[index].evt, | ||
327 | EVTCHNL_TYPE_EVT); | ||
328 | if (ret < 0) { | ||
329 | dev_err(dev, "Error allocating in-event channel\n"); | ||
330 | goto fail; | ||
331 | } | ||
332 | } | ||
333 | |||
334 | for (s = 0; s < pcm_instance->num_streams_cap; s++) { | ||
335 | index = pcm_instance->streams_cap[s].index; | ||
336 | |||
337 | ret = evtchnl_alloc(front_info, index, | ||
338 | &front_info->evt_pairs[index].req, | ||
339 | EVTCHNL_TYPE_REQ); | ||
340 | if (ret < 0) { | ||
341 | dev_err(dev, "Error allocating control channel\n"); | ||
342 | goto fail; | ||
343 | } | ||
344 | |||
345 | ret = evtchnl_alloc(front_info, index, | ||
346 | &front_info->evt_pairs[index].evt, | ||
347 | EVTCHNL_TYPE_EVT); | ||
348 | if (ret < 0) { | ||
349 | dev_err(dev, "Error allocating in-event channel\n"); | ||
350 | goto fail; | ||
351 | } | ||
352 | } | ||
353 | } | ||
354 | |||
355 | front_info->num_evt_pairs = num_streams; | ||
356 | return 0; | ||
357 | |||
358 | fail: | ||
359 | xen_snd_front_evtchnl_free_all(front_info); | ||
360 | return ret; | ||
361 | } | ||
362 | |||
363 | static int evtchnl_publish(struct xenbus_transaction xbt, | ||
364 | struct xen_snd_front_evtchnl *channel, | ||
365 | const char *path, const char *node_ring, | ||
366 | const char *node_chnl) | ||
367 | { | ||
368 | struct xenbus_device *xb_dev = channel->front_info->xb_dev; | ||
369 | int ret; | ||
370 | |||
371 | /* Write control channel ring reference. */ | ||
372 | ret = xenbus_printf(xbt, path, node_ring, "%u", channel->gref); | ||
373 | if (ret < 0) { | ||
374 | dev_err(&xb_dev->dev, "Error writing ring-ref: %d\n", ret); | ||
375 | return ret; | ||
376 | } | ||
377 | |||
378 | /* Write event channel ring reference. */ | ||
379 | ret = xenbus_printf(xbt, path, node_chnl, "%u", channel->port); | ||
380 | if (ret < 0) { | ||
381 | dev_err(&xb_dev->dev, "Error writing event channel: %d\n", ret); | ||
382 | return ret; | ||
383 | } | ||
384 | |||
385 | return 0; | ||
386 | } | ||
387 | |||
388 | int xen_snd_front_evtchnl_publish_all(struct xen_snd_front_info *front_info) | ||
389 | { | ||
390 | struct xen_front_cfg_card *cfg = &front_info->cfg; | ||
391 | struct xenbus_transaction xbt; | ||
392 | int ret, d; | ||
393 | |||
394 | again: | ||
395 | ret = xenbus_transaction_start(&xbt); | ||
396 | if (ret < 0) { | ||
397 | xenbus_dev_fatal(front_info->xb_dev, ret, | ||
398 | "starting transaction"); | ||
399 | return ret; | ||
400 | } | ||
401 | |||
402 | for (d = 0; d < cfg->num_pcm_instances; d++) { | ||
403 | struct xen_front_cfg_pcm_instance *pcm_instance; | ||
404 | int s, index; | ||
405 | |||
406 | pcm_instance = &cfg->pcm_instances[d]; | ||
407 | |||
408 | for (s = 0; s < pcm_instance->num_streams_pb; s++) { | ||
409 | index = pcm_instance->streams_pb[s].index; | ||
410 | |||
411 | ret = evtchnl_publish(xbt, | ||
412 | &front_info->evt_pairs[index].req, | ||
413 | pcm_instance->streams_pb[s].xenstore_path, | ||
414 | XENSND_FIELD_RING_REF, | ||
415 | XENSND_FIELD_EVT_CHNL); | ||
416 | if (ret < 0) | ||
417 | goto fail; | ||
418 | |||
419 | ret = evtchnl_publish(xbt, | ||
420 | &front_info->evt_pairs[index].evt, | ||
421 | pcm_instance->streams_pb[s].xenstore_path, | ||
422 | XENSND_FIELD_EVT_RING_REF, | ||
423 | XENSND_FIELD_EVT_EVT_CHNL); | ||
424 | if (ret < 0) | ||
425 | goto fail; | ||
426 | } | ||
427 | |||
428 | for (s = 0; s < pcm_instance->num_streams_cap; s++) { | ||
429 | index = pcm_instance->streams_cap[s].index; | ||
430 | |||
431 | ret = evtchnl_publish(xbt, | ||
432 | &front_info->evt_pairs[index].req, | ||
433 | pcm_instance->streams_cap[s].xenstore_path, | ||
434 | XENSND_FIELD_RING_REF, | ||
435 | XENSND_FIELD_EVT_CHNL); | ||
436 | if (ret < 0) | ||
437 | goto fail; | ||
438 | |||
439 | ret = evtchnl_publish(xbt, | ||
440 | &front_info->evt_pairs[index].evt, | ||
441 | pcm_instance->streams_cap[s].xenstore_path, | ||
442 | XENSND_FIELD_EVT_RING_REF, | ||
443 | XENSND_FIELD_EVT_EVT_CHNL); | ||
444 | if (ret < 0) | ||
445 | goto fail; | ||
446 | } | ||
447 | } | ||
448 | ret = xenbus_transaction_end(xbt, 0); | ||
449 | if (ret < 0) { | ||
450 | if (ret == -EAGAIN) | ||
451 | goto again; | ||
452 | |||
453 | xenbus_dev_fatal(front_info->xb_dev, ret, | ||
454 | "completing transaction"); | ||
455 | goto fail_to_end; | ||
456 | } | ||
457 | return 0; | ||
458 | fail: | ||
459 | xenbus_transaction_end(xbt, 1); | ||
460 | fail_to_end: | ||
461 | xenbus_dev_fatal(front_info->xb_dev, ret, "writing XenStore"); | ||
462 | return ret; | ||
463 | } | ||
464 | |||
465 | void xen_snd_front_evtchnl_pair_set_connected(struct xen_snd_front_evtchnl_pair *evt_pair, | ||
466 | bool is_connected) | ||
467 | { | ||
468 | enum xen_snd_front_evtchnl_state state; | ||
469 | |||
470 | if (is_connected) | ||
471 | state = EVTCHNL_STATE_CONNECTED; | ||
472 | else | ||
473 | state = EVTCHNL_STATE_DISCONNECTED; | ||
474 | |||
475 | mutex_lock(&evt_pair->req.ring_io_lock); | ||
476 | evt_pair->req.state = state; | ||
477 | mutex_unlock(&evt_pair->req.ring_io_lock); | ||
478 | |||
479 | mutex_lock(&evt_pair->evt.ring_io_lock); | ||
480 | evt_pair->evt.state = state; | ||
481 | mutex_unlock(&evt_pair->evt.ring_io_lock); | ||
482 | } | ||
483 | |||
484 | void xen_snd_front_evtchnl_pair_clear(struct xen_snd_front_evtchnl_pair *evt_pair) | ||
485 | { | ||
486 | mutex_lock(&evt_pair->req.ring_io_lock); | ||
487 | evt_pair->req.evt_next_id = 0; | ||
488 | mutex_unlock(&evt_pair->req.ring_io_lock); | ||
489 | |||
490 | mutex_lock(&evt_pair->evt.ring_io_lock); | ||
491 | evt_pair->evt.evt_next_id = 0; | ||
492 | mutex_unlock(&evt_pair->evt.ring_io_lock); | ||
493 | } | ||
494 | |||
diff --git a/sound/xen/xen_snd_front_evtchnl.h b/sound/xen/xen_snd_front_evtchnl.h new file mode 100644 index 000000000000..cbe51fd1ec15 --- /dev/null +++ b/sound/xen/xen_snd_front_evtchnl.h | |||
@@ -0,0 +1,95 @@ | |||
1 | /* SPDX-License-Identifier: GPL-2.0 OR MIT */ | ||
2 | |||
3 | /* | ||
4 | * Xen para-virtual sound device | ||
5 | * | ||
6 | * Copyright (C) 2016-2018 EPAM Systems Inc. | ||
7 | * | ||
8 | * Author: Oleksandr Andrushchenko <oleksandr_andrushchenko@epam.com> | ||
9 | */ | ||
10 | |||
11 | #ifndef __XEN_SND_FRONT_EVTCHNL_H | ||
12 | #define __XEN_SND_FRONT_EVTCHNL_H | ||
13 | |||
14 | #include <xen/interface/io/sndif.h> | ||
15 | |||
16 | struct xen_snd_front_info; | ||
17 | |||
18 | #ifndef GRANT_INVALID_REF | ||
19 | /* | ||
20 | * FIXME: usage of grant reference 0 as invalid grant reference: | ||
21 | * grant reference 0 is valid, but never exposed to a PV driver, | ||
22 | * because of the fact it is already in use/reserved by the PV console. | ||
23 | */ | ||
24 | #define GRANT_INVALID_REF 0 | ||
25 | #endif | ||
26 | |||
27 | /* Timeout in ms to wait for backend to respond. */ | ||
28 | #define VSND_WAIT_BACK_MS 3000 | ||
29 | |||
30 | enum xen_snd_front_evtchnl_state { | ||
31 | EVTCHNL_STATE_DISCONNECTED, | ||
32 | EVTCHNL_STATE_CONNECTED, | ||
33 | }; | ||
34 | |||
35 | enum xen_snd_front_evtchnl_type { | ||
36 | EVTCHNL_TYPE_REQ, | ||
37 | EVTCHNL_TYPE_EVT, | ||
38 | }; | ||
39 | |||
40 | struct xen_snd_front_evtchnl { | ||
41 | struct xen_snd_front_info *front_info; | ||
42 | int gref; | ||
43 | int port; | ||
44 | int irq; | ||
45 | int index; | ||
46 | /* State of the event channel. */ | ||
47 | enum xen_snd_front_evtchnl_state state; | ||
48 | enum xen_snd_front_evtchnl_type type; | ||
49 | /* Either response id or incoming event id. */ | ||
50 | u16 evt_id; | ||
51 | /* Next request id or next expected event id. */ | ||
52 | u16 evt_next_id; | ||
53 | /* Shared ring access lock. */ | ||
54 | struct mutex ring_io_lock; | ||
55 | union { | ||
56 | struct { | ||
57 | struct xen_sndif_front_ring ring; | ||
58 | struct completion completion; | ||
59 | /* Serializer for backend IO: request/response. */ | ||
60 | struct mutex req_io_lock; | ||
61 | |||
62 | /* Latest response status. */ | ||
63 | int resp_status; | ||
64 | union { | ||
65 | struct xensnd_query_hw_param hw_param; | ||
66 | } resp; | ||
67 | } req; | ||
68 | struct { | ||
69 | struct xensnd_event_page *page; | ||
70 | /* This is needed to handle XENSND_EVT_CUR_POS event. */ | ||
71 | struct snd_pcm_substream *substream; | ||
72 | } evt; | ||
73 | } u; | ||
74 | }; | ||
75 | |||
76 | struct xen_snd_front_evtchnl_pair { | ||
77 | struct xen_snd_front_evtchnl req; | ||
78 | struct xen_snd_front_evtchnl evt; | ||
79 | }; | ||
80 | |||
81 | int xen_snd_front_evtchnl_create_all(struct xen_snd_front_info *front_info, | ||
82 | int num_streams); | ||
83 | |||
84 | void xen_snd_front_evtchnl_free_all(struct xen_snd_front_info *front_info); | ||
85 | |||
86 | int xen_snd_front_evtchnl_publish_all(struct xen_snd_front_info *front_info); | ||
87 | |||
88 | void xen_snd_front_evtchnl_flush(struct xen_snd_front_evtchnl *evtchnl); | ||
89 | |||
90 | void xen_snd_front_evtchnl_pair_set_connected(struct xen_snd_front_evtchnl_pair *evt_pair, | ||
91 | bool is_connected); | ||
92 | |||
93 | void xen_snd_front_evtchnl_pair_clear(struct xen_snd_front_evtchnl_pair *evt_pair); | ||
94 | |||
95 | #endif /* __XEN_SND_FRONT_EVTCHNL_H */ | ||
diff --git a/sound/xen/xen_snd_front_shbuf.c b/sound/xen/xen_snd_front_shbuf.c new file mode 100644 index 000000000000..07ac176a41ba --- /dev/null +++ b/sound/xen/xen_snd_front_shbuf.c | |||
@@ -0,0 +1,194 @@ | |||
1 | // SPDX-License-Identifier: GPL-2.0 OR MIT | ||
2 | |||
3 | /* | ||
4 | * Xen para-virtual sound device | ||
5 | * | ||
6 | * Copyright (C) 2016-2018 EPAM Systems Inc. | ||
7 | * | ||
8 | * Author: Oleksandr Andrushchenko <oleksandr_andrushchenko@epam.com> | ||
9 | */ | ||
10 | |||
11 | #include <linux/kernel.h> | ||
12 | #include <xen/xen.h> | ||
13 | #include <xen/xenbus.h> | ||
14 | |||
15 | #include "xen_snd_front_shbuf.h" | ||
16 | |||
17 | grant_ref_t xen_snd_front_shbuf_get_dir_start(struct xen_snd_front_shbuf *buf) | ||
18 | { | ||
19 | if (!buf->grefs) | ||
20 | return GRANT_INVALID_REF; | ||
21 | |||
22 | return buf->grefs[0]; | ||
23 | } | ||
24 | |||
25 | void xen_snd_front_shbuf_clear(struct xen_snd_front_shbuf *buf) | ||
26 | { | ||
27 | memset(buf, 0, sizeof(*buf)); | ||
28 | } | ||
29 | |||
30 | void xen_snd_front_shbuf_free(struct xen_snd_front_shbuf *buf) | ||
31 | { | ||
32 | int i; | ||
33 | |||
34 | if (buf->grefs) { | ||
35 | for (i = 0; i < buf->num_grefs; i++) | ||
36 | if (buf->grefs[i] != GRANT_INVALID_REF) | ||
37 | gnttab_end_foreign_access(buf->grefs[i], | ||
38 | 0, 0UL); | ||
39 | kfree(buf->grefs); | ||
40 | } | ||
41 | kfree(buf->directory); | ||
42 | free_pages_exact(buf->buffer, buf->buffer_sz); | ||
43 | xen_snd_front_shbuf_clear(buf); | ||
44 | } | ||
45 | |||
46 | /* | ||
47 | * number of grant references a page can hold with respect to the | ||
48 | * xensnd_page_directory header | ||
49 | */ | ||
50 | #define XENSND_NUM_GREFS_PER_PAGE ((XEN_PAGE_SIZE - \ | ||
51 | offsetof(struct xensnd_page_directory, gref)) / \ | ||
52 | sizeof(grant_ref_t)) | ||
53 | |||
54 | static void fill_page_dir(struct xen_snd_front_shbuf *buf, | ||
55 | int num_pages_dir) | ||
56 | { | ||
57 | struct xensnd_page_directory *page_dir; | ||
58 | unsigned char *ptr; | ||
59 | int i, cur_gref, grefs_left, to_copy; | ||
60 | |||
61 | ptr = buf->directory; | ||
62 | grefs_left = buf->num_grefs - num_pages_dir; | ||
63 | /* | ||
64 | * skip grant references at the beginning, they are for pages granted | ||
65 | * for the page directory itself | ||
66 | */ | ||
67 | cur_gref = num_pages_dir; | ||
68 | for (i = 0; i < num_pages_dir; i++) { | ||
69 | page_dir = (struct xensnd_page_directory *)ptr; | ||
70 | if (grefs_left <= XENSND_NUM_GREFS_PER_PAGE) { | ||
71 | to_copy = grefs_left; | ||
72 | page_dir->gref_dir_next_page = GRANT_INVALID_REF; | ||
73 | } else { | ||
74 | to_copy = XENSND_NUM_GREFS_PER_PAGE; | ||
75 | page_dir->gref_dir_next_page = buf->grefs[i + 1]; | ||
76 | } | ||
77 | |||
78 | memcpy(&page_dir->gref, &buf->grefs[cur_gref], | ||
79 | to_copy * sizeof(grant_ref_t)); | ||
80 | |||
81 | ptr += XEN_PAGE_SIZE; | ||
82 | grefs_left -= to_copy; | ||
83 | cur_gref += to_copy; | ||
84 | } | ||
85 | } | ||
86 | |||
87 | static int grant_references(struct xenbus_device *xb_dev, | ||
88 | struct xen_snd_front_shbuf *buf, | ||
89 | int num_pages_dir, int num_pages_buffer, | ||
90 | int num_grefs) | ||
91 | { | ||
92 | grant_ref_t priv_gref_head; | ||
93 | unsigned long frame; | ||
94 | int ret, i, j, cur_ref; | ||
95 | int otherend_id; | ||
96 | |||
97 | ret = gnttab_alloc_grant_references(num_grefs, &priv_gref_head); | ||
98 | if (ret) | ||
99 | return ret; | ||
100 | |||
101 | buf->num_grefs = num_grefs; | ||
102 | otherend_id = xb_dev->otherend_id; | ||
103 | j = 0; | ||
104 | |||
105 | for (i = 0; i < num_pages_dir; i++) { | ||
106 | cur_ref = gnttab_claim_grant_reference(&priv_gref_head); | ||
107 | if (cur_ref < 0) { | ||
108 | ret = cur_ref; | ||
109 | goto fail; | ||
110 | } | ||
111 | |||
112 | frame = xen_page_to_gfn(virt_to_page(buf->directory + | ||
113 | XEN_PAGE_SIZE * i)); | ||
114 | gnttab_grant_foreign_access_ref(cur_ref, otherend_id, frame, 0); | ||
115 | buf->grefs[j++] = cur_ref; | ||
116 | } | ||
117 | |||
118 | for (i = 0; i < num_pages_buffer; i++) { | ||
119 | cur_ref = gnttab_claim_grant_reference(&priv_gref_head); | ||
120 | if (cur_ref < 0) { | ||
121 | ret = cur_ref; | ||
122 | goto fail; | ||
123 | } | ||
124 | |||
125 | frame = xen_page_to_gfn(virt_to_page(buf->buffer + | ||
126 | XEN_PAGE_SIZE * i)); | ||
127 | gnttab_grant_foreign_access_ref(cur_ref, otherend_id, frame, 0); | ||
128 | buf->grefs[j++] = cur_ref; | ||
129 | } | ||
130 | |||
131 | gnttab_free_grant_references(priv_gref_head); | ||
132 | fill_page_dir(buf, num_pages_dir); | ||
133 | return 0; | ||
134 | |||
135 | fail: | ||
136 | gnttab_free_grant_references(priv_gref_head); | ||
137 | return ret; | ||
138 | } | ||
139 | |||
140 | static int alloc_int_buffers(struct xen_snd_front_shbuf *buf, | ||
141 | int num_pages_dir, int num_pages_buffer, | ||
142 | int num_grefs) | ||
143 | { | ||
144 | buf->grefs = kcalloc(num_grefs, sizeof(*buf->grefs), GFP_KERNEL); | ||
145 | if (!buf->grefs) | ||
146 | return -ENOMEM; | ||
147 | |||
148 | buf->directory = kcalloc(num_pages_dir, XEN_PAGE_SIZE, GFP_KERNEL); | ||
149 | if (!buf->directory) | ||
150 | goto fail; | ||
151 | |||
152 | buf->buffer_sz = num_pages_buffer * XEN_PAGE_SIZE; | ||
153 | buf->buffer = alloc_pages_exact(buf->buffer_sz, GFP_KERNEL); | ||
154 | if (!buf->buffer) | ||
155 | goto fail; | ||
156 | |||
157 | return 0; | ||
158 | |||
159 | fail: | ||
160 | kfree(buf->grefs); | ||
161 | buf->grefs = NULL; | ||
162 | kfree(buf->directory); | ||
163 | buf->directory = NULL; | ||
164 | return -ENOMEM; | ||
165 | } | ||
166 | |||
167 | int xen_snd_front_shbuf_alloc(struct xenbus_device *xb_dev, | ||
168 | struct xen_snd_front_shbuf *buf, | ||
169 | unsigned int buffer_sz) | ||
170 | { | ||
171 | int num_pages_buffer, num_pages_dir, num_grefs; | ||
172 | int ret; | ||
173 | |||
174 | xen_snd_front_shbuf_clear(buf); | ||
175 | |||
176 | num_pages_buffer = DIV_ROUND_UP(buffer_sz, XEN_PAGE_SIZE); | ||
177 | /* number of pages the page directory consumes itself */ | ||
178 | num_pages_dir = DIV_ROUND_UP(num_pages_buffer, | ||
179 | XENSND_NUM_GREFS_PER_PAGE); | ||
180 | num_grefs = num_pages_buffer + num_pages_dir; | ||
181 | |||
182 | ret = alloc_int_buffers(buf, num_pages_dir, | ||
183 | num_pages_buffer, num_grefs); | ||
184 | if (ret < 0) | ||
185 | return ret; | ||
186 | |||
187 | ret = grant_references(xb_dev, buf, num_pages_dir, num_pages_buffer, | ||
188 | num_grefs); | ||
189 | if (ret < 0) | ||
190 | return ret; | ||
191 | |||
192 | fill_page_dir(buf, num_pages_dir); | ||
193 | return 0; | ||
194 | } | ||
diff --git a/sound/xen/xen_snd_front_shbuf.h b/sound/xen/xen_snd_front_shbuf.h new file mode 100644 index 000000000000..d28e97c47b2c --- /dev/null +++ b/sound/xen/xen_snd_front_shbuf.h | |||
@@ -0,0 +1,36 @@ | |||
1 | /* SPDX-License-Identifier: GPL-2.0 OR MIT */ | ||
2 | |||
3 | /* | ||
4 | * Xen para-virtual sound device | ||
5 | * | ||
6 | * Copyright (C) 2016-2018 EPAM Systems Inc. | ||
7 | * | ||
8 | * Author: Oleksandr Andrushchenko <oleksandr_andrushchenko@epam.com> | ||
9 | */ | ||
10 | |||
11 | #ifndef __XEN_SND_FRONT_SHBUF_H | ||
12 | #define __XEN_SND_FRONT_SHBUF_H | ||
13 | |||
14 | #include <xen/grant_table.h> | ||
15 | |||
16 | #include "xen_snd_front_evtchnl.h" | ||
17 | |||
18 | struct xen_snd_front_shbuf { | ||
19 | int num_grefs; | ||
20 | grant_ref_t *grefs; | ||
21 | u8 *directory; | ||
22 | u8 *buffer; | ||
23 | size_t buffer_sz; | ||
24 | }; | ||
25 | |||
26 | grant_ref_t xen_snd_front_shbuf_get_dir_start(struct xen_snd_front_shbuf *buf); | ||
27 | |||
28 | int xen_snd_front_shbuf_alloc(struct xenbus_device *xb_dev, | ||
29 | struct xen_snd_front_shbuf *buf, | ||
30 | unsigned int buffer_sz); | ||
31 | |||
32 | void xen_snd_front_shbuf_clear(struct xen_snd_front_shbuf *buf); | ||
33 | |||
34 | void xen_snd_front_shbuf_free(struct xen_snd_front_shbuf *buf); | ||
35 | |||
36 | #endif /* __XEN_SND_FRONT_SHBUF_H */ | ||