mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-11-11 12:28:41 +08:00
sound updates for 4.2-rc1
It was a busy development cycle at this time, as you can see a wide range of changes in diffstat. There are no big changes but many refactoring and improvements. Here we go some highlights: * ALSA core: - Procfs codes were cleaned up to use seq_file - Procfs can be opt out via Kconfig (only for EXPERT) - Two types of jack API were unified finally; now both kctl and input jack devs are handled via a single function call. * HD-audio - Continued code restructuring for the future ASoC driver; now HDA controller driver is split to a core helper module. - Preliminary codes for Skylake audio support in HDA core. - Proper i915 gfx power well management for SKL & co - Enabled runtime PM as default for Intel HDMI/DP codecs - Newer Tegra chip supports - More quirks for Dell headsets, Alienware (with CA0132), etc. - A couple of DRM ELD helper API functions * ASoC - Support for loading ASoC topology maps from firmware, intended to be used to allow self-describing DSP firmware images to be built which can map controls added by the DSP to userspace without the kernel needing to know about individual DSP firmwares - Lots of refactoring to avoid direct access to snd_soc_codec where it's not needed supporting future refactoring - Big refactoring, cleanup and enhancement for the Wolfson ADSP driver - Cleanup series for TI TAS2552 and R-CAR drivers - Fixes and improvements on RT56xx codecs - Support for TI TAS571x power amplifiers - Support for Qualcomm APQ8016 and ZTE ZX296702 SoCs - Support for x86 systems with RT5650 and Qualcomm Storm - Support for Mediatek AFE (Audio Front End) unit - Other various small fixes to ASoC codec drivers * Firewire - Enhanced to allow non-blocking streams to use timestamp synchronization - Improve support for DM1500 and BeBoBv3 * Misc - Cleanup of old pci API functions over all PCI sound drivers - Fix long-standing regression of the old powermac i2c setup -----BEGIN PGP SIGNATURE----- Version: GnuPG v2 iQIcBAABCAAGBQJVitjmAAoJEGwxgFQ9KSmksW8P/2ngNzNpo/bmmGh6xjB7GWU9 RDAkqhKd6yvcClQojGS9n4a9CJ8nk5tdqTr9rMp58N7DRv6GYCPdq0A+lLOih+yC UPcTkTMBKm6UtvJjEcaasMxhvs5xno345oo5KrBdvlfv1rXe83dTtzEsybWYkaVD dJbbr5QFaiyj5cTp9nanK5kyTyDDXCdP+vjBGv5u9+GbVxQ6Eenyts89uSqEZs1F ltoBrl4VotXyqHKneJ0ttUKEimcVIgu8rCXH0sTtCg0SZVJFi+UXzI/VkkS+expL x9bNN6bw5UT9LA8+qybFRETx+8qchFsffzeUEle4wkIpVKXt/VqjP3GIvp6umlF5 RhU5Wumf2KuIVjgVsYxd7bUkmHr4ywpqS3vSWMWU90FApJay7exatzLPyUVN0AxH pdAizc8NWFk1kVtWq8jr9agEdxDt2l+E9UXij+ViGyouMZL1oSvOo9NgovfwvfC6 qKUisUkq53p1uPOW/U5gvF7bee2enEXMI9YUY1Z8MHx7nloq+25Nqma8P0gYthB8 6Qk+t1oqC2p7ZMSkyVHH9nySQmoLITZHZmsHqqpLW+jFtanhuckDI75AvmrScs+r 3+2YZXxPI0caZZ1qxMCd7Clmh7ZcSeRe73HXSXmF0xrLffISM3Yg3ZN10cbWQRj2 D6TiHCspLpn+pcYLcWJ2 =D78E -----END PGP SIGNATURE----- Merge tag 'sound-4.2-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound Pull sound updates from Takashi Iwai: "It was a busy development cycle at this time, as you can see a wide range of changes in diffstat. There are no big changes but many refactoring and improvements. Here we go some highlights: ALSA core: - Procfs codes were cleaned up to use seq_file - Procfs can be opt out via Kconfig (only for EXPERT) - Two types of jack API were unified finally; now both kctl and input jack devs are handled via a single function call. HD-audio: - Continued code restructuring for the future ASoC driver; now HDA controller driver is split to a core helper module. - Preliminary codes for Skylake audio support in HDA core. - Proper i915 gfx power well management for SKL & co - Enabled runtime PM as default for Intel HDMI/DP codecs - Newer Tegra chip supports - More quirks for Dell headsets, Alienware (with CA0132), etc. - A couple of DRM ELD helper API functions ASoC: - Support for loading ASoC topology maps from firmware, intended to be used to allow self-describing DSP firmware images to be built which can map controls added by the DSP to userspace without the kernel needing to know about individual DSP firmwares - Lots of refactoring to avoid direct access to snd_soc_codec where it's not needed supporting future refactoring - Big refactoring, cleanup and enhancement for the Wolfson ADSP driver - Cleanup series for TI TAS2552 and R-CAR drivers - Fixes and improvements on RT56xx codecs - Support for TI TAS571x power amplifiers - Support for Qualcomm APQ8016 and ZTE ZX296702 SoCs - Support for x86 systems with RT5650 and Qualcomm Storm - Support for Mediatek AFE (Audio Front End) unit - Other various small fixes to ASoC codec drivers Firewire: - Enhanced to allow non-blocking streams to use timestamp synchronization - Improve support for DM1500 and BeBoBv3 Misc: - Cleanup of old pci API functions over all PCI sound drivers - Fix long-standing regression of the old powermac i2c setup" * tag 'sound-4.2-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound: (533 commits) ALSA: pcm: Fix pcm_class sysfs output ALSA: hda-beep: Update authors dead email address ASoC: wm_adsp: Move DSP Rate controls into the codec ASoC: wm8995: Fix setting sysclk for WM8995_SYSCLK_MCLK2 case ALSA: hda: provide default bus io ops extended hdac ALSA: hda: add hda link cleanup routine ALSA: hda: add hdac_ext stream creation and cleanup routines ASoC: rsrc-card: remove unused ret ALSA: HDAC: move SND_HDA_PREALLOC_SIZE to core ASoC: mediatek: Add machine driver for rt5650 rt5676 codec ASoC: mediatek: Add machine driver for MAX98090 codec ASoC: mediatek: Add AFE platform driver ASoC: rsnd: remove io from rsnd_mod ASoC: rsnd: move rsnd_mod_is_working() to rsnd_io_is_working() ASoC: rsnd: don't use rsnd_mod_to_io() on snd_kcontrol ASoC: rsnd: don't use rsnd_mod_to_io() on rsnd_src_xxx() ASoC: rsnd: don't use rsnd_mod_to_io() on rsnd_ssi_xxx() ASoC: rsnd: don't use rsnd_mod_to_io() on rsnd_dma_xxx() ASoC: rsnd: don't use rsnd_mod_to_io() on rsnd_get_adinr() ASoC: rsnd: add common interrupt handler for SSI/SRC/DMA ...
This commit is contained in:
commit
4570a37169
@ -20,6 +20,8 @@ Optional properties:
|
||||
pin configurations as described in the datasheet,
|
||||
table 53. Note that the value of this property has
|
||||
to be prefixed with '/bits/ 8'.
|
||||
- avdd-supply: Power supply for AVDD, providing 3.3V
|
||||
- dvdd-supply: Power supply for DVDD, providing 3.3V
|
||||
|
||||
Examples:
|
||||
|
||||
@ -28,6 +30,8 @@ Examples:
|
||||
compatible = "adi,adau1701";
|
||||
reg = <0x34>;
|
||||
reset-gpio = <&gpio 23 0>;
|
||||
avdd-supply = <&vdd_3v3_reg>;
|
||||
dvdd-supply = <&vdd_3v3_reg>;
|
||||
adi,pll-mode-gpios = <&gpio 24 0 &gpio 25 0>;
|
||||
adi,pin-config = /bits/ 8 <0x4 0x7 0x5 0x5 0x4 0x4
|
||||
0x4 0x4 0x4 0x4 0x4 0x4>;
|
||||
|
13
Documentation/devicetree/bindings/sound/bt-sco.txt
Normal file
13
Documentation/devicetree/bindings/sound/bt-sco.txt
Normal file
@ -0,0 +1,13 @@
|
||||
Bluetooth-SCO audio CODEC
|
||||
|
||||
This device support generic Bluetooth SCO link.
|
||||
|
||||
Required properties:
|
||||
|
||||
- compatible : "delta,dfbmcs320"
|
||||
|
||||
Example:
|
||||
|
||||
codec: bt_sco {
|
||||
compatible = "delta,dfbmcs320";
|
||||
};
|
13
Documentation/devicetree/bindings/sound/gtm601.txt
Normal file
13
Documentation/devicetree/bindings/sound/gtm601.txt
Normal file
@ -0,0 +1,13 @@
|
||||
GTM601 UMTS modem audio interface CODEC
|
||||
|
||||
This device has no configuration interface. Sample rate is fixed - 8kHz.
|
||||
|
||||
Required properties:
|
||||
|
||||
- compatible : "option,gtm601"
|
||||
|
||||
Example:
|
||||
|
||||
codec: gtm601_codec {
|
||||
compatible = "option,gtm601";
|
||||
};
|
@ -18,6 +18,12 @@ Optional properties:
|
||||
|
||||
- maxim,dmic-freq: Frequency at which to clock DMIC
|
||||
|
||||
- maxim,micbias: Micbias voltage applies to the analog mic, valid voltages value are:
|
||||
0 - 2.2v
|
||||
1 - 2.55v
|
||||
2 - 2.4v
|
||||
3 - 2.8v
|
||||
|
||||
Pins on the device (for linking into audio routes):
|
||||
|
||||
* MIC1
|
||||
|
13
Documentation/devicetree/bindings/sound/mt8173-max98090.txt
Normal file
13
Documentation/devicetree/bindings/sound/mt8173-max98090.txt
Normal file
@ -0,0 +1,13 @@
|
||||
MT8173 with MAX98090 CODEC
|
||||
|
||||
Required properties:
|
||||
- compatible : "mediatek,mt8173-max98090"
|
||||
- mediatek,audio-codec: the phandle of the MAX98090 audio codec
|
||||
|
||||
Example:
|
||||
|
||||
sound {
|
||||
compatible = "mediatek,mt8173-max98090";
|
||||
mediatek,audio-codec = <&max98090>;
|
||||
};
|
||||
|
@ -0,0 +1,13 @@
|
||||
MT8173 with RT5650 RT5676 CODECS
|
||||
|
||||
Required properties:
|
||||
- compatible : "mediatek,mt8173-rt5650-rt5676"
|
||||
- mediatek,audio-codec: the phandles of rt5650 and rt5676 codecs
|
||||
|
||||
Example:
|
||||
|
||||
sound {
|
||||
compatible = "mediatek,mt8173-rt5650-rt5676";
|
||||
mediatek,audio-codec = <&rt5650 &rt5676>;
|
||||
};
|
||||
|
45
Documentation/devicetree/bindings/sound/mtk-afe-pcm.txt
Normal file
45
Documentation/devicetree/bindings/sound/mtk-afe-pcm.txt
Normal file
@ -0,0 +1,45 @@
|
||||
Mediatek AFE PCM controller
|
||||
|
||||
Required properties:
|
||||
- compatible = "mediatek,mt8173-afe-pcm";
|
||||
- reg: register location and size
|
||||
- interrupts: Should contain AFE interrupt
|
||||
- clock-names: should have these clock names:
|
||||
"infra_sys_audio_clk",
|
||||
"top_pdn_audio",
|
||||
"top_pdn_aud_intbus",
|
||||
"bck0",
|
||||
"bck1",
|
||||
"i2s0_m",
|
||||
"i2s1_m",
|
||||
"i2s2_m",
|
||||
"i2s3_m",
|
||||
"i2s3_b";
|
||||
|
||||
Example:
|
||||
|
||||
afe: mt8173-afe-pcm@11220000 {
|
||||
compatible = "mediatek,mt8173-afe-pcm";
|
||||
reg = <0 0x11220000 0 0x1000>;
|
||||
interrupts = <GIC_SPI 134 IRQ_TYPE_EDGE_FALLING>;
|
||||
clocks = <&infracfg INFRA_AUDIO>,
|
||||
<&topckgen TOP_AUDIO_SEL>,
|
||||
<&topckgen TOP_AUD_INTBUS_SEL>,
|
||||
<&topckgen TOP_APLL1_DIV0>,
|
||||
<&topckgen TOP_APLL2_DIV0>,
|
||||
<&topckgen TOP_I2S0_M_CK_SEL>,
|
||||
<&topckgen TOP_I2S1_M_CK_SEL>,
|
||||
<&topckgen TOP_I2S2_M_CK_SEL>,
|
||||
<&topckgen TOP_I2S3_M_CK_SEL>,
|
||||
<&topckgen TOP_I2S3_B_CK_SEL>;
|
||||
clock-names = "infra_sys_audio_clk",
|
||||
"top_pdn_audio",
|
||||
"top_pdn_aud_intbus",
|
||||
"bck0",
|
||||
"bck1",
|
||||
"i2s0_m",
|
||||
"i2s1_m",
|
||||
"i2s2_m",
|
||||
"i2s3_m",
|
||||
"i2s3_b";
|
||||
};
|
60
Documentation/devicetree/bindings/sound/qcom,apq8016-sbc.txt
Normal file
60
Documentation/devicetree/bindings/sound/qcom,apq8016-sbc.txt
Normal file
@ -0,0 +1,60 @@
|
||||
* Qualcomm Technologies APQ8016 SBC ASoC machine driver
|
||||
|
||||
This node models the Qualcomm Technologies APQ8016 SBC ASoC machine driver
|
||||
|
||||
Required properties:
|
||||
|
||||
- compatible : "qcom,apq8016-sbc-sndcard"
|
||||
|
||||
- pinctrl-N : One property must exist for each entry in
|
||||
pinctrl-names. See ../pinctrl/pinctrl-bindings.txt
|
||||
for details of the property values.
|
||||
- pinctrl-names : Must contain a "default" entry.
|
||||
- reg : Must contain an address for each entry in reg-names.
|
||||
- reg-names : A list which must include the following entries:
|
||||
* "mic-iomux"
|
||||
* "spkr-iomux"
|
||||
- qcom,model : Name of the sound card.
|
||||
|
||||
Dai-link subnode properties and subnodes:
|
||||
|
||||
Required dai-link subnodes:
|
||||
|
||||
- cpu : CPU sub-node
|
||||
- codec : CODEC sub-node
|
||||
|
||||
Required CPU/CODEC subnodes properties:
|
||||
|
||||
-link-name : Name of the dai link.
|
||||
-sound-dai : phandle and port of CPU/CODEC
|
||||
-capture-dai : phandle and port of CPU/CODEC
|
||||
|
||||
Example:
|
||||
|
||||
sound: sound {
|
||||
compatible = "qcom,apq8016-sbc-sndcard";
|
||||
reg = <0x07702000 0x4>, <0x07702004 0x4>;
|
||||
reg-names = "mic-iomux", "spkr-iomux";
|
||||
qcom,model = "DB410c";
|
||||
|
||||
/* I2S - Internal codec */
|
||||
internal-dai-link@0 {
|
||||
cpu { /* PRIMARY */
|
||||
sound-dai = <&lpass MI2S_PRIMARY>;
|
||||
};
|
||||
codec {
|
||||
sound-dai = <&wcd_codec 0>;
|
||||
};
|
||||
};
|
||||
|
||||
/* External Primary or External Secondary -ADV7533 HDMI */
|
||||
external-dai-link@0 {
|
||||
link-name = "ADV7533";
|
||||
cpu { /* QUAT */
|
||||
sound-dai = <&lpass MI2S_QUATERNARY>;
|
||||
};
|
||||
codec {
|
||||
sound-dai = <&adv_bridge 0>;
|
||||
};
|
||||
};
|
||||
};
|
@ -4,12 +4,21 @@ This node models the Qualcomm Technologies Low-Power Audio SubSystem (LPASS).
|
||||
|
||||
Required properties:
|
||||
|
||||
- compatible : "qcom,lpass-cpu"
|
||||
- compatible : "qcom,lpass-cpu" or "qcom,apq8016-lpass-cpu"
|
||||
- clocks : Must contain an entry for each entry in clock-names.
|
||||
- clock-names : A list which must include the following entries:
|
||||
* "ahbix-clk"
|
||||
* "mi2s-osr-clk"
|
||||
* "mi2s-bit-clk"
|
||||
: required clocks for "qcom,lpass-cpu-apq8016"
|
||||
* "ahbix-clk"
|
||||
* "mi2s-bit-clk0"
|
||||
* "mi2s-bit-clk1"
|
||||
* "mi2s-bit-clk2"
|
||||
* "mi2s-bit-clk3"
|
||||
* "pcnoc-mport-clk"
|
||||
* "pcnoc-sway-clk"
|
||||
|
||||
- interrupts : Must contain an entry for each entry in
|
||||
interrupt-names.
|
||||
- interrupt-names : A list which must include the following entries:
|
||||
@ -22,6 +31,8 @@ Required properties:
|
||||
- reg-names : A list which must include the following entries:
|
||||
* "lpass-lpaif"
|
||||
|
||||
|
||||
|
||||
Optional properties:
|
||||
|
||||
- qcom,adsp : Phandle for the audio DSP node
|
||||
|
@ -5,6 +5,7 @@ Required properties:
|
||||
"renesas,rcar_sound-gen1" if generation1, and
|
||||
"renesas,rcar_sound-gen2" if generation2
|
||||
Examples with soctypes are:
|
||||
- "renesas,rcar_sound-r8a7778" (R-Car M1A)
|
||||
- "renesas,rcar_sound-r8a7790" (R-Car H2)
|
||||
- "renesas,rcar_sound-r8a7791" (R-Car M2-W)
|
||||
- reg : Should contain the register physical address.
|
||||
@ -47,7 +48,7 @@ DAI subnode properties:
|
||||
|
||||
Example:
|
||||
|
||||
rcar_sound: rcar_sound@ec500000 {
|
||||
rcar_sound: sound@ec500000 {
|
||||
#sound-dai-cells = <1>;
|
||||
compatible = "renesas,rcar_sound-r8a7791", "renesas,rcar_sound-gen2";
|
||||
reg = <0 0xec500000 0 0x1000>, /* SCU */
|
||||
|
72
Documentation/devicetree/bindings/sound/rt5645.txt
Normal file
72
Documentation/devicetree/bindings/sound/rt5645.txt
Normal file
@ -0,0 +1,72 @@
|
||||
RT5650/RT5645 audio CODEC
|
||||
|
||||
This device supports I2C only.
|
||||
|
||||
Required properties:
|
||||
|
||||
- compatible : One of "realtek,rt5645" or "realtek,rt5650".
|
||||
|
||||
- reg : The I2C address of the device.
|
||||
|
||||
- interrupts : The CODEC's interrupt output.
|
||||
|
||||
Optional properties:
|
||||
|
||||
- hp-detect-gpios:
|
||||
a GPIO spec for the external headphone detect pin. If jd-mode = 0,
|
||||
we will get the JD status by getting the value of hp-detect-gpios.
|
||||
|
||||
- realtek,in2-differential
|
||||
Boolean. Indicate MIC2 input are differential, rather than single-ended.
|
||||
|
||||
- realtek,dmic1-data-pin
|
||||
0: dmic1 is not used
|
||||
1: using IN2P pin as dmic1 data pin
|
||||
2: using GPIO6 pin as dmic1 data pin
|
||||
3: using GPIO10 pin as dmic1 data pin
|
||||
4: using GPIO12 pin as dmic1 data pin
|
||||
|
||||
- realtek,dmic2-data-pin
|
||||
0: dmic2 is not used
|
||||
1: using IN2N pin as dmic2 data pin
|
||||
2: using GPIO5 pin as dmic2 data pin
|
||||
3: using GPIO11 pin as dmic2 data pin
|
||||
|
||||
-- realtek,jd-mode : The JD mode of rt5645/rt5650
|
||||
0 : rt5645/rt5650 JD function is not used
|
||||
1 : Mode-0 (VDD=3.3V), two port jack detection
|
||||
2 : Mode-1 (VDD=3.3V), one port jack detection
|
||||
3 : Mode-2 (VDD=1.8V), one port jack detection
|
||||
|
||||
Pins on the device (for linking into audio routes) for RT5645/RT5650:
|
||||
|
||||
* DMIC L1
|
||||
* DMIC R1
|
||||
* DMIC L2
|
||||
* DMIC R2
|
||||
* IN1P
|
||||
* IN1N
|
||||
* IN2P
|
||||
* IN2N
|
||||
* Haptic Generator
|
||||
* HPOL
|
||||
* HPOR
|
||||
* LOUTL
|
||||
* LOUTR
|
||||
* PDM1L
|
||||
* PDM1R
|
||||
* SPOL
|
||||
* SPOR
|
||||
|
||||
Example:
|
||||
|
||||
codec: rt5650@1a {
|
||||
compatible = "realtek,rt5650";
|
||||
reg = <0x1a>;
|
||||
hp-detect-gpios = <&gpio 19 0>;
|
||||
interrupt-parent = <&gpio>;
|
||||
interrupts = <7 IRQ_TYPE_EDGE_FALLING>;
|
||||
realtek,dmic-en = "true";
|
||||
realtek,en-jd-func = "true";
|
||||
realtek,jd-mode = <3>;
|
||||
};
|
@ -18,6 +18,7 @@ Required properties:
|
||||
Optional properties:
|
||||
|
||||
- realtek,pow-ldo2-gpio : The GPIO that controls the CODEC's POW_LDO2 pin.
|
||||
- realtek,reset-gpio : The GPIO that controls the CODEC's RESET pin.
|
||||
|
||||
- realtek,in1-differential
|
||||
- realtek,in2-differential
|
||||
@ -70,6 +71,7 @@ rt5677 {
|
||||
|
||||
realtek,pow-ldo2-gpio =
|
||||
<&gpio TEGRA_GPIO(V, 3) GPIO_ACTIVE_HIGH>;
|
||||
realtek,reset-gpio = <&gpio TEGRA_GPIO(BB, 3) GPIO_ACTIVE_LOW>;
|
||||
realtek,in1-differential = "true";
|
||||
realtek,gpio-config = /bits/ 8 <0 0 0 0 0 2>; /* pull up GPIO6 */
|
||||
realtek,jd2-gpio = <3>; /* Enables Jack detection for GPIO6 */
|
||||
|
@ -16,7 +16,8 @@ Optional properties:
|
||||
connection's sink, the second being the connection's
|
||||
source.
|
||||
- simple-audio-card,mclk-fs : Multiplication factor between stream rate and codec
|
||||
mclk.
|
||||
mclk. When defined, mclk-fs property defined in
|
||||
dai-link sub nodes are ignored.
|
||||
- simple-audio-card,hp-det-gpio : Reference to GPIO that signals when
|
||||
headphones are attached.
|
||||
- simple-audio-card,mic-det-gpio : Reference to GPIO that signals when
|
||||
@ -55,6 +56,9 @@ Optional dai-link subnode properties:
|
||||
dai-link uses bit clock inversion.
|
||||
- frame-inversion : bool property. Add this if the
|
||||
dai-link uses frame clock inversion.
|
||||
- mclk-fs : Multiplication factor between stream
|
||||
rate and codec mclk, applied only for
|
||||
the dai-link.
|
||||
|
||||
For backward compatibility the frame-master and bitclock-master
|
||||
properties can be used as booleans in codec subnode to indicate if the
|
||||
|
@ -14,6 +14,12 @@ Required properties:
|
||||
Optional properties:
|
||||
- enable-gpio - gpio pin to enable/disable the device
|
||||
|
||||
tas2552 can receive it's reference clock via MCLK, BCLK, IVCLKIN pin or use the
|
||||
internal 1.8MHz. This CLKIN is used by the PLL. In addition to PLL, the PDM
|
||||
reference clock is also selectable: PLL, IVCLKIN, BCLK or MCLK.
|
||||
For system integration the dt-bindings/sound/tas2552.h header file provides
|
||||
defined values to selct and configure the PLL and PDM reference clocks.
|
||||
|
||||
Example:
|
||||
|
||||
tas2552: tas2552@41 {
|
||||
|
41
Documentation/devicetree/bindings/sound/tas571x.txt
Normal file
41
Documentation/devicetree/bindings/sound/tas571x.txt
Normal file
@ -0,0 +1,41 @@
|
||||
Texas Instruments TAS5711/TAS5717/TAS5719 stereo power amplifiers
|
||||
|
||||
The codec is controlled through an I2C interface. It also has two other
|
||||
signals that can be wired up to GPIOs: reset (strongly recommended), and
|
||||
powerdown (optional).
|
||||
|
||||
Required properties:
|
||||
|
||||
- compatible: "ti,tas5711", "ti,tas5717", or "ti,tas5719"
|
||||
- reg: The I2C address of the device
|
||||
- #sound-dai-cells: must be equal to 0
|
||||
|
||||
Optional properties:
|
||||
|
||||
- reset-gpios: GPIO specifier for the TAS571x's active low reset line
|
||||
- pdn-gpios: GPIO specifier for the TAS571x's active low powerdown line
|
||||
- clocks: clock phandle for the MCLK input
|
||||
- clock-names: should be "mclk"
|
||||
- AVDD-supply: regulator phandle for the AVDD supply (all chips)
|
||||
- DVDD-supply: regulator phandle for the DVDD supply (all chips)
|
||||
- HPVDD-supply: regulator phandle for the HPVDD supply (5717/5719)
|
||||
- PVDD_AB-supply: regulator phandle for the PVDD_AB supply (5717/5719)
|
||||
- PVDD_CD-supply: regulator phandle for the PVDD_CD supply (5717/5719)
|
||||
- PVDD_A-supply: regulator phandle for the PVDD_A supply (5711)
|
||||
- PVDD_B-supply: regulator phandle for the PVDD_B supply (5711)
|
||||
- PVDD_C-supply: regulator phandle for the PVDD_C supply (5711)
|
||||
- PVDD_D-supply: regulator phandle for the PVDD_D supply (5711)
|
||||
|
||||
Example:
|
||||
|
||||
tas5717: audio-codec@2a {
|
||||
compatible = "ti,tas5717";
|
||||
reg = <0x2a>;
|
||||
#sound-dai-cells = <0>;
|
||||
|
||||
reset-gpios = <&gpio5 1 GPIO_ACTIVE_LOW>;
|
||||
pdn-gpios = <&gpio5 2 GPIO_ACTIVE_LOW>;
|
||||
|
||||
clocks = <&clk_core CLK_I2S>;
|
||||
clock-names = "mclk";
|
||||
};
|
@ -10,9 +10,20 @@ Required properties:
|
||||
- reg : the I2C address of the device for I2C, the chip select
|
||||
number for SPI.
|
||||
|
||||
Optional properties:
|
||||
|
||||
- diff-mode: Differential output mode configuration. Default value for field
|
||||
DIFF in register R8 (MODE_CONTROL_2). If absent, the default is 0, shall be:
|
||||
0 = stereo
|
||||
1 = mono left
|
||||
2 = stereo reversed
|
||||
3 = mono right
|
||||
|
||||
Example:
|
||||
|
||||
codec: wm8741@1a {
|
||||
compatible = "wlf,wm8741";
|
||||
reg = <0x1a>;
|
||||
|
||||
diff-mode = <3>;
|
||||
};
|
||||
|
44
Documentation/devicetree/bindings/sound/zte,zx-i2s.txt
Normal file
44
Documentation/devicetree/bindings/sound/zte,zx-i2s.txt
Normal file
@ -0,0 +1,44 @@
|
||||
ZTE ZX296702 I2S controller
|
||||
|
||||
Required properties:
|
||||
- compatible : Must be "zte,zx296702-i2s"
|
||||
- reg : Must contain I2S core's registers location and length
|
||||
- clocks : Pairs of phandle and specifier referencing the controller's clocks.
|
||||
- clock-names: "tx" for the clock to the I2S interface.
|
||||
- dmas: Pairs of phandle and specifier for the DMA channel that is used by
|
||||
the core. The core expects two dma channels for transmit.
|
||||
- dma-names : Must be "tx" and "rx"
|
||||
|
||||
For more details on the 'dma', 'dma-names', 'clock' and 'clock-names' properties
|
||||
please check:
|
||||
* resource-names.txt
|
||||
* clock/clock-bindings.txt
|
||||
* dma/dma.txt
|
||||
|
||||
Example:
|
||||
i2s0: i2s0@0b005000 {
|
||||
#sound-dai-cells = <0>;
|
||||
compatible = "zte,zx296702-i2s";
|
||||
reg = <0x0b005000 0x1000>;
|
||||
clocks = <&lsp0clk ZX296702_I2S0_DIV>;
|
||||
clock-names = "tx";
|
||||
interrupts = <GIC_SPI 22 IRQ_TYPE_LEVEL_HIGH>;
|
||||
dmas = <&dma 5>, <&dma 6>;
|
||||
dma-names = "tx", "rx";
|
||||
status = "okay";
|
||||
};
|
||||
|
||||
sound {
|
||||
compatible = "simple-audio-card";
|
||||
simple-audio-card,name = "zx296702_snd";
|
||||
simple-audio-card,format = "left_j";
|
||||
simple-audio-card,bitclock-master = <&sndcodec>;
|
||||
simple-audio-card,frame-master = <&sndcodec>;
|
||||
sndcpu: simple-audio-card,cpu {
|
||||
sound-dai = <&i2s0>;
|
||||
};
|
||||
|
||||
sndcodec: simple-audio-card,codec {
|
||||
sound-dai = <&acodec>;
|
||||
};
|
||||
};
|
28
Documentation/devicetree/bindings/sound/zte,zx-spdif.txt
Normal file
28
Documentation/devicetree/bindings/sound/zte,zx-spdif.txt
Normal file
@ -0,0 +1,28 @@
|
||||
ZTE ZX296702 SPDIF controller
|
||||
|
||||
Required properties:
|
||||
- compatible : Must be "zte,zx296702-spdif"
|
||||
- reg : Must contain SPDIF core's registers location and length
|
||||
- clocks : Pairs of phandle and specifier referencing the controller's clocks.
|
||||
- clock-names: "tx" for the clock to the SPDIF interface.
|
||||
- dmas: Pairs of phandle and specifier for the DMA channel that is used by
|
||||
the core. The core expects one dma channel for transmit.
|
||||
- dma-names : Must be "tx"
|
||||
|
||||
For more details on the 'dma', 'dma-names', 'clock' and 'clock-names' properties
|
||||
please check:
|
||||
* resource-names.txt
|
||||
* clock/clock-bindings.txt
|
||||
* dma/dma.txt
|
||||
|
||||
Example:
|
||||
spdif0: spdif0@0b004000 {
|
||||
compatible = "zte,zx296702-spdif";
|
||||
reg = <0x0b004000 0x1000>;
|
||||
clocks = <&lsp0clk ZX296702_SPDIF0_DIV>;
|
||||
clock-names = "tx";
|
||||
interrupts = <GIC_SPI 21 IRQ_TYPE_LEVEL_HIGH>;
|
||||
dmas = <&dma 4>;
|
||||
dma-names = "tx";
|
||||
status = "okay";
|
||||
};
|
@ -54,6 +54,7 @@ cosmic Cosmic Circuits
|
||||
crystalfontz Crystalfontz America, Inc.
|
||||
dallas Maxim Integrated Products (formerly Dallas Semiconductor)
|
||||
davicom DAVICOM Semiconductor, Inc.
|
||||
delta Delta Electronics, Inc.
|
||||
denx Denx Software Engineering
|
||||
digi Digi International Inc.
|
||||
digilent Diglent, Inc.
|
||||
|
@ -11,7 +11,10 @@ ALC880
|
||||
|
||||
ALC260
|
||||
======
|
||||
N/A
|
||||
gpio1 Enable GPIO1
|
||||
coef Enable EAPD via COEF table
|
||||
fujitsu Quirk for FSC S7020
|
||||
fujitsu-jwse Quirk for FSC S7020 with jack modes and HP mic support
|
||||
|
||||
ALC262
|
||||
======
|
||||
@ -20,8 +23,9 @@ ALC262
|
||||
ALC267/268
|
||||
==========
|
||||
inv-dmic Inverted internal mic workaround
|
||||
hp-eapd Disable HP EAPD on NID 0x15
|
||||
|
||||
ALC269/270/275/276/28x/29x
|
||||
ALC22x/23x/25x/269/27x/28x/29x (and vendor-specific ALC3xxx models)
|
||||
======
|
||||
laptop-amic Laptops with analog-mic input
|
||||
laptop-dmic Laptops with digital-mic input
|
||||
@ -29,9 +33,15 @@ ALC269/270/275/276/28x/29x
|
||||
alc271-dmic Enable ALC271X digital mic workaround
|
||||
inv-dmic Inverted internal mic workaround
|
||||
headset-mic Indicates a combined headset (headphone+mic) jack
|
||||
headset-mode More comprehensive headset support for ALC269 & co
|
||||
headset-mode-no-hp-mic Headset mode support without headphone mic
|
||||
lenovo-dock Enables docking station I/O for some Lenovos
|
||||
hp-gpio-led GPIO LED support on HP laptops
|
||||
dell-headset-multi Headset jack, which can also be used as mic-in
|
||||
dell-headset-dock Headset jack (without mic-in), and also dock I/O
|
||||
alc283-dac-wcaps Fixups for Chromebook with ALC283
|
||||
alc283-sense-combo Combo jack sensing on ALC283
|
||||
tpt440-dock Pin configs for Lenovo Thinkpad Dock support
|
||||
|
||||
ALC66x/67x/892
|
||||
==============
|
||||
|
43
Documentation/sound/alsa/Jack-Controls.txt
Normal file
43
Documentation/sound/alsa/Jack-Controls.txt
Normal file
@ -0,0 +1,43 @@
|
||||
Why we need Jack kcontrols
|
||||
==========================
|
||||
|
||||
ALSA uses kcontrols to export audio controls(switch, volume, Mux, ...)
|
||||
to user space. This means userspace applications like pulseaudio can
|
||||
switch off headphones and switch on speakers when no headphones are
|
||||
pluged in.
|
||||
|
||||
The old ALSA jack code only created input devices for each registered
|
||||
jack. These jack input devices are not readable by userspace devices
|
||||
that run as non root.
|
||||
|
||||
The new jack code creates embedded jack kcontrols for each jack that
|
||||
can be read by any process.
|
||||
|
||||
This can be combined with UCM to allow userspace to route audio more
|
||||
intelligently based on jack insertion or removal events.
|
||||
|
||||
Jack Kcontrol Internals
|
||||
=======================
|
||||
|
||||
Each jack will have a kcontrol list, so that we can create a kcontrol
|
||||
and attach it to the jack, at jack creation stage. We can also add a
|
||||
kcontrol to an existing jack, at anytime when required.
|
||||
|
||||
Those kcontrols will be freed automatically when the Jack is freed.
|
||||
|
||||
How to use jack kcontrols
|
||||
=========================
|
||||
|
||||
In order to keep compatibility, snd_jack_new() has been modified by
|
||||
adding two params :-
|
||||
|
||||
- @initial_kctl: if true, create a kcontrol and add it to the jack
|
||||
list.
|
||||
- @phantom_jack: Don't create a input device for phantom jacks.
|
||||
|
||||
HDA jacks can set phantom_jack to true in order to create a phantom
|
||||
jack and set initial_kctl to true to create an initial kcontrol with
|
||||
the correct id.
|
||||
|
||||
ASoC jacks should set initial_kctl as false. The pin name will be
|
||||
assigned as the jack kcontrol name.
|
@ -41,7 +41,7 @@ pss_no_sound
|
||||
|
||||
This module parameter is a flag that can be used to tell the driver to
|
||||
just configure non-sound components. 0 configures all components, a non-0
|
||||
value will only attept to configure the CDROM and joystick ports. This
|
||||
value will only attempt to configure the CDROM and joystick ports. This
|
||||
parameter can be used by a user who only wished to use the builtin joystick
|
||||
and/or CDROM port(s) of his PSS sound card. If this driver is loaded with this
|
||||
parameter and with the parameter below set to true then a user can safely unload
|
||||
|
@ -1346,7 +1346,7 @@ implement nice real-time signal processing audio effect software and
|
||||
network telephones. The ACI mixer has to be switched into the "solo"
|
||||
mode for duplex operation in order to avoid feedback caused by the
|
||||
mixer (input hears output signal). You can de-/activate this mode
|
||||
through toggleing the record button for the wave controller with an
|
||||
through toggling the record button for the wave controller with an
|
||||
OSS-mixer.
|
||||
|
||||
The PCM20 contains a radio tuner, which is also controlled by
|
||||
|
@ -29,7 +29,7 @@ Driver Status
|
||||
|
||||
Still somewhat experimental. The driver should work stable, i.e. it
|
||||
should'nt crash your box. It might not work as expected, have bugs,
|
||||
not being fully OSS API compilant, ...
|
||||
not being fully OSS API compliant, ...
|
||||
|
||||
Latest versions are available from http://bytesex.org/bttv/, the
|
||||
driver is in the bttv tarball. Kernel patches might be available too,
|
||||
|
@ -10037,6 +10037,12 @@ L: netdev@vger.kernel.org
|
||||
S: Maintained
|
||||
F: drivers/net/ethernet/ti/netcp*
|
||||
|
||||
TI TAS571X FAMILY ASoC CODEC DRIVER
|
||||
M: Kevin Cernekee <cernekee@chromium.org>
|
||||
L: alsa-devel@alsa-project.org (moderated for non-subscribers)
|
||||
S: Odd Fixes
|
||||
F: sound/soc/codecs/tas571x*
|
||||
|
||||
TI TWL4030 SERIES SOC CODEC DRIVER
|
||||
M: Peter Ujfalusi <peter.ujfalusi@ti.com>
|
||||
L: alsa-devel@alsa-project.org (moderated for non-subscribers)
|
||||
|
@ -465,6 +465,7 @@ static dma_cookie_t rcar_dmac_tx_submit(struct dma_async_tx_descriptor *tx)
|
||||
static int rcar_dmac_desc_alloc(struct rcar_dmac_chan *chan, gfp_t gfp)
|
||||
{
|
||||
struct rcar_dmac_desc_page *page;
|
||||
unsigned long flags;
|
||||
LIST_HEAD(list);
|
||||
unsigned int i;
|
||||
|
||||
@ -482,10 +483,10 @@ static int rcar_dmac_desc_alloc(struct rcar_dmac_chan *chan, gfp_t gfp)
|
||||
list_add_tail(&desc->node, &list);
|
||||
}
|
||||
|
||||
spin_lock_irq(&chan->lock);
|
||||
spin_lock_irqsave(&chan->lock, flags);
|
||||
list_splice_tail(&list, &chan->desc.free);
|
||||
list_add_tail(&page->node, &chan->desc.pages);
|
||||
spin_unlock_irq(&chan->lock);
|
||||
spin_unlock_irqrestore(&chan->lock, flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -516,6 +517,7 @@ static void rcar_dmac_desc_put(struct rcar_dmac_chan *chan,
|
||||
static void rcar_dmac_desc_recycle_acked(struct rcar_dmac_chan *chan)
|
||||
{
|
||||
struct rcar_dmac_desc *desc, *_desc;
|
||||
unsigned long flags;
|
||||
LIST_HEAD(list);
|
||||
|
||||
/*
|
||||
@ -524,9 +526,9 @@ static void rcar_dmac_desc_recycle_acked(struct rcar_dmac_chan *chan)
|
||||
* list_for_each_entry_safe, isn't safe if we release the channel lock
|
||||
* around the rcar_dmac_desc_put() call.
|
||||
*/
|
||||
spin_lock_irq(&chan->lock);
|
||||
spin_lock_irqsave(&chan->lock, flags);
|
||||
list_splice_init(&chan->desc.wait, &list);
|
||||
spin_unlock_irq(&chan->lock);
|
||||
spin_unlock_irqrestore(&chan->lock, flags);
|
||||
|
||||
list_for_each_entry_safe(desc, _desc, &list, node) {
|
||||
if (async_tx_test_ack(&desc->async_tx)) {
|
||||
@ -539,9 +541,9 @@ static void rcar_dmac_desc_recycle_acked(struct rcar_dmac_chan *chan)
|
||||
return;
|
||||
|
||||
/* Put the remaining descriptors back in the wait list. */
|
||||
spin_lock_irq(&chan->lock);
|
||||
spin_lock_irqsave(&chan->lock, flags);
|
||||
list_splice(&list, &chan->desc.wait);
|
||||
spin_unlock_irq(&chan->lock);
|
||||
spin_unlock_irqrestore(&chan->lock, flags);
|
||||
}
|
||||
|
||||
/*
|
||||
@ -556,12 +558,13 @@ static void rcar_dmac_desc_recycle_acked(struct rcar_dmac_chan *chan)
|
||||
static struct rcar_dmac_desc *rcar_dmac_desc_get(struct rcar_dmac_chan *chan)
|
||||
{
|
||||
struct rcar_dmac_desc *desc;
|
||||
unsigned long flags;
|
||||
int ret;
|
||||
|
||||
/* Recycle acked descriptors before attempting allocation. */
|
||||
rcar_dmac_desc_recycle_acked(chan);
|
||||
|
||||
spin_lock_irq(&chan->lock);
|
||||
spin_lock_irqsave(&chan->lock, flags);
|
||||
|
||||
while (list_empty(&chan->desc.free)) {
|
||||
/*
|
||||
@ -570,17 +573,17 @@ static struct rcar_dmac_desc *rcar_dmac_desc_get(struct rcar_dmac_chan *chan)
|
||||
* allocated descriptors. If the allocation fails return an
|
||||
* error.
|
||||
*/
|
||||
spin_unlock_irq(&chan->lock);
|
||||
spin_unlock_irqrestore(&chan->lock, flags);
|
||||
ret = rcar_dmac_desc_alloc(chan, GFP_NOWAIT);
|
||||
if (ret < 0)
|
||||
return NULL;
|
||||
spin_lock_irq(&chan->lock);
|
||||
spin_lock_irqsave(&chan->lock, flags);
|
||||
}
|
||||
|
||||
desc = list_first_entry(&chan->desc.free, struct rcar_dmac_desc, node);
|
||||
list_del(&desc->node);
|
||||
|
||||
spin_unlock_irq(&chan->lock);
|
||||
spin_unlock_irqrestore(&chan->lock, flags);
|
||||
|
||||
return desc;
|
||||
}
|
||||
@ -593,6 +596,7 @@ static struct rcar_dmac_desc *rcar_dmac_desc_get(struct rcar_dmac_chan *chan)
|
||||
static int rcar_dmac_xfer_chunk_alloc(struct rcar_dmac_chan *chan, gfp_t gfp)
|
||||
{
|
||||
struct rcar_dmac_desc_page *page;
|
||||
unsigned long flags;
|
||||
LIST_HEAD(list);
|
||||
unsigned int i;
|
||||
|
||||
@ -606,10 +610,10 @@ static int rcar_dmac_xfer_chunk_alloc(struct rcar_dmac_chan *chan, gfp_t gfp)
|
||||
list_add_tail(&chunk->node, &list);
|
||||
}
|
||||
|
||||
spin_lock_irq(&chan->lock);
|
||||
spin_lock_irqsave(&chan->lock, flags);
|
||||
list_splice_tail(&list, &chan->desc.chunks_free);
|
||||
list_add_tail(&page->node, &chan->desc.pages);
|
||||
spin_unlock_irq(&chan->lock);
|
||||
spin_unlock_irqrestore(&chan->lock, flags);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@ -627,9 +631,10 @@ static struct rcar_dmac_xfer_chunk *
|
||||
rcar_dmac_xfer_chunk_get(struct rcar_dmac_chan *chan)
|
||||
{
|
||||
struct rcar_dmac_xfer_chunk *chunk;
|
||||
unsigned long flags;
|
||||
int ret;
|
||||
|
||||
spin_lock_irq(&chan->lock);
|
||||
spin_lock_irqsave(&chan->lock, flags);
|
||||
|
||||
while (list_empty(&chan->desc.chunks_free)) {
|
||||
/*
|
||||
@ -638,18 +643,18 @@ rcar_dmac_xfer_chunk_get(struct rcar_dmac_chan *chan)
|
||||
* allocated descriptors. If the allocation fails return an
|
||||
* error.
|
||||
*/
|
||||
spin_unlock_irq(&chan->lock);
|
||||
spin_unlock_irqrestore(&chan->lock, flags);
|
||||
ret = rcar_dmac_xfer_chunk_alloc(chan, GFP_NOWAIT);
|
||||
if (ret < 0)
|
||||
return NULL;
|
||||
spin_lock_irq(&chan->lock);
|
||||
spin_lock_irqsave(&chan->lock, flags);
|
||||
}
|
||||
|
||||
chunk = list_first_entry(&chan->desc.chunks_free,
|
||||
struct rcar_dmac_xfer_chunk, node);
|
||||
list_del(&chunk->node);
|
||||
|
||||
spin_unlock_irq(&chan->lock);
|
||||
spin_unlock_irqrestore(&chan->lock, flags);
|
||||
|
||||
return chunk;
|
||||
}
|
||||
|
@ -6479,6 +6479,9 @@ enum skl_disp_power_wells {
|
||||
#define AUDIO_CP_READY(trans) ((1 << 1) << ((trans) * 4))
|
||||
#define AUDIO_ELD_VALID(trans) ((1 << 0) << ((trans) * 4))
|
||||
|
||||
#define HSW_AUD_CHICKENBIT 0x65f10
|
||||
#define SKL_AUD_CODEC_WAKE_SIGNAL (1 << 15)
|
||||
|
||||
/* HSW Power Wells */
|
||||
#define HSW_PWR_WELL_BIOS 0x45400 /* CTL1 */
|
||||
#define HSW_PWR_WELL_DRIVER 0x45404 /* CTL2 */
|
||||
|
@ -475,6 +475,32 @@ static void i915_audio_component_put_power(struct device *dev)
|
||||
intel_display_power_put(dev_to_i915(dev), POWER_DOMAIN_AUDIO);
|
||||
}
|
||||
|
||||
static void i915_audio_component_codec_wake_override(struct device *dev,
|
||||
bool enable)
|
||||
{
|
||||
struct drm_i915_private *dev_priv = dev_to_i915(dev);
|
||||
u32 tmp;
|
||||
|
||||
if (!IS_SKYLAKE(dev_priv))
|
||||
return;
|
||||
|
||||
/*
|
||||
* Enable/disable generating the codec wake signal, overriding the
|
||||
* internal logic to generate the codec wake to controller.
|
||||
*/
|
||||
tmp = I915_READ(HSW_AUD_CHICKENBIT);
|
||||
tmp &= ~SKL_AUD_CODEC_WAKE_SIGNAL;
|
||||
I915_WRITE(HSW_AUD_CHICKENBIT, tmp);
|
||||
usleep_range(1000, 1500);
|
||||
|
||||
if (enable) {
|
||||
tmp = I915_READ(HSW_AUD_CHICKENBIT);
|
||||
tmp |= SKL_AUD_CODEC_WAKE_SIGNAL;
|
||||
I915_WRITE(HSW_AUD_CHICKENBIT, tmp);
|
||||
usleep_range(1000, 1500);
|
||||
}
|
||||
}
|
||||
|
||||
/* Get CDCLK in kHz */
|
||||
static int i915_audio_component_get_cdclk_freq(struct device *dev)
|
||||
{
|
||||
@ -495,6 +521,7 @@ static const struct i915_audio_component_ops i915_audio_component_ops = {
|
||||
.owner = THIS_MODULE,
|
||||
.get_power = i915_audio_component_get_power,
|
||||
.put_power = i915_audio_component_put_power,
|
||||
.codec_wake_override = i915_audio_component_codec_wake_override,
|
||||
.get_cdclk_freq = i915_audio_component_get_cdclk_freq,
|
||||
};
|
||||
|
||||
|
@ -78,11 +78,6 @@ static int arizona_ldo1_hc_set_voltage_sel(struct regulator_dev *rdev,
|
||||
if (ret != 0)
|
||||
return ret;
|
||||
|
||||
ret = regmap_update_bits(regmap, ARIZONA_DYNAMIC_FREQUENCY_SCALING_1,
|
||||
ARIZONA_SUBSYS_MAX_FREQ, val);
|
||||
if (ret != 0)
|
||||
return ret;
|
||||
|
||||
if (val)
|
||||
return 0;
|
||||
|
||||
|
@ -31,6 +31,7 @@ struct i915_audio_component {
|
||||
struct module *owner;
|
||||
void (*get_power)(struct device *);
|
||||
void (*put_power)(struct device *);
|
||||
void (*codec_wake_override)(struct device *, bool enable);
|
||||
int (*get_cdclk_freq)(struct device *);
|
||||
} *ops;
|
||||
};
|
||||
|
9
include/dt-bindings/sound/apq8016-lpass.h
Normal file
9
include/dt-bindings/sound/apq8016-lpass.h
Normal file
@ -0,0 +1,9 @@
|
||||
#ifndef __DT_APQ8016_LPASS_H
|
||||
#define __DT_APQ8016_LPASS_H
|
||||
|
||||
#define MI2S_PRIMARY 0
|
||||
#define MI2S_SECONDARY 1
|
||||
#define MI2S_TERTIARY 2
|
||||
#define MI2S_QUATERNARY 3
|
||||
|
||||
#endif /* __DT_APQ8016_LPASS_H */
|
9
include/dt-bindings/sound/audio-jack-events.h
Normal file
9
include/dt-bindings/sound/audio-jack-events.h
Normal file
@ -0,0 +1,9 @@
|
||||
#ifndef __AUDIO_JACK_EVENTS_H
|
||||
#define __AUDIO_JACK_EVENTS_H
|
||||
|
||||
#define JACK_HEADPHONE 1
|
||||
#define JACK_MICROPHONE 2
|
||||
#define JACK_LINEOUT 3
|
||||
#define JACK_LINEIN 4
|
||||
|
||||
#endif /* __AUDIO_JACK_EVENTS_H */
|
18
include/dt-bindings/sound/tas2552.h
Normal file
18
include/dt-bindings/sound/tas2552.h
Normal file
@ -0,0 +1,18 @@
|
||||
#ifndef __DT_TAS2552_H
|
||||
#define __DT_TAS2552_H
|
||||
|
||||
#define TAS2552_PLL_CLKIN (0)
|
||||
#define TAS2552_PDM_CLK (1)
|
||||
#define TAS2552_CLK_TARGET_MASK (1)
|
||||
|
||||
#define TAS2552_PLL_CLKIN_MCLK ((0 << 1) | TAS2552_PLL_CLKIN)
|
||||
#define TAS2552_PLL_CLKIN_BCLK ((1 << 1) | TAS2552_PLL_CLKIN)
|
||||
#define TAS2552_PLL_CLKIN_IVCLKIN ((2 << 1) | TAS2552_PLL_CLKIN)
|
||||
#define TAS2552_PLL_CLKIN_1_8_FIXED ((3 << 1) | TAS2552_PLL_CLKIN)
|
||||
|
||||
#define TAS2552_PDM_CLK_PLL ((0 << 1) | TAS2552_PDM_CLK)
|
||||
#define TAS2552_PDM_CLK_IVCLKIN ((1 << 1) | TAS2552_PDM_CLK)
|
||||
#define TAS2552_PDM_CLK_BCLK ((2 << 1) | TAS2552_PDM_CLK)
|
||||
#define TAS2552_PDM_CLK_MCLK ((3 << 1) | TAS2552_PDM_CLK)
|
||||
|
||||
#endif /* __DT_TAS2552_H */
|
@ -252,7 +252,7 @@ void snd_ctl_sync_vmaster(struct snd_kcontrol *kctl, bool hook_only);
|
||||
* Helper functions for jack-detection controls
|
||||
*/
|
||||
struct snd_kcontrol *
|
||||
snd_kctl_jack_new(const char *name, int idx, void *private_data);
|
||||
snd_kctl_jack_new(const char *name, struct snd_card *card);
|
||||
void snd_kctl_jack_report(struct snd_card *card,
|
||||
struct snd_kcontrol *kctl, bool status);
|
||||
|
||||
|
@ -224,16 +224,13 @@ void *snd_lookup_oss_minor_data(unsigned int minor, int type);
|
||||
#endif
|
||||
|
||||
int snd_minor_info_init(void);
|
||||
int snd_minor_info_done(void);
|
||||
|
||||
/* sound_oss.c */
|
||||
|
||||
#ifdef CONFIG_SND_OSSEMUL
|
||||
int snd_minor_info_oss_init(void);
|
||||
int snd_minor_info_oss_done(void);
|
||||
#else
|
||||
static inline int snd_minor_info_oss_init(void) { return 0; }
|
||||
static inline int snd_minor_info_oss_done(void) { return 0; }
|
||||
#endif
|
||||
|
||||
/* memory.c */
|
||||
@ -262,7 +259,6 @@ int snd_card_free_when_closed(struct snd_card *card);
|
||||
void snd_card_set_id(struct snd_card *card, const char *id);
|
||||
int snd_card_register(struct snd_card *card);
|
||||
int snd_card_info_init(void);
|
||||
int snd_card_info_done(void);
|
||||
int snd_card_add_dev_attr(struct snd_card *card,
|
||||
const struct attribute_group *group);
|
||||
int snd_component_add(struct snd_card *card, const char *component);
|
||||
|
@ -90,11 +90,6 @@ void snd_dmaengine_pcm_set_config_from_dai_data(
|
||||
* makes sense if SND_DMAENGINE_PCM_FLAG_COMPAT is set as well.
|
||||
*/
|
||||
#define SND_DMAENGINE_PCM_FLAG_NO_DT BIT(1)
|
||||
/*
|
||||
* The platforms dmaengine driver does not support reporting the amount of
|
||||
* bytes that are still left to transfer.
|
||||
*/
|
||||
#define SND_DMAENGINE_PCM_FLAG_NO_RESIDUE BIT(2)
|
||||
/*
|
||||
* The PCM is half duplex and the DMA channel is shared between capture and
|
||||
* playback.
|
||||
|
@ -125,7 +125,7 @@ struct snd_emux {
|
||||
|
||||
struct snd_util_memhdr *memhdr; /* memory chunk information */
|
||||
|
||||
#ifdef CONFIG_PROC_FS
|
||||
#ifdef CONFIG_SND_PROC_FS
|
||||
struct snd_info_entry *proc;
|
||||
#endif
|
||||
|
||||
|
36
include/sound/hda_i915.h
Normal file
36
include/sound/hda_i915.h
Normal file
@ -0,0 +1,36 @@
|
||||
/*
|
||||
* HD-Audio helpers to sync with i915 driver
|
||||
*/
|
||||
#ifndef __SOUND_HDA_I915_H
|
||||
#define __SOUND_HDA_I915_H
|
||||
|
||||
#ifdef CONFIG_SND_HDA_I915
|
||||
int snd_hdac_set_codec_wakeup(struct hdac_bus *bus, bool enable);
|
||||
int snd_hdac_display_power(struct hdac_bus *bus, bool enable);
|
||||
int snd_hdac_get_display_clk(struct hdac_bus *bus);
|
||||
int snd_hdac_i915_init(struct hdac_bus *bus);
|
||||
int snd_hdac_i915_exit(struct hdac_bus *bus);
|
||||
#else
|
||||
static int snd_hdac_set_codec_wakeup(struct hdac_bus *bus, bool enable)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
static inline int snd_hdac_display_power(struct hdac_bus *bus, bool enable)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
static inline int snd_hdac_get_display_clk(struct hdac_bus *bus)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
static inline int snd_hdac_i915_init(struct hdac_bus *bus)
|
||||
{
|
||||
return -ENODEV;
|
||||
}
|
||||
static inline int snd_hdac_i915_exit(struct hdac_bus *bus)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
||||
#endif /* __SOUND_HDA_I915_H */
|
244
include/sound/hda_register.h
Normal file
244
include/sound/hda_register.h
Normal file
@ -0,0 +1,244 @@
|
||||
/*
|
||||
* HD-audio controller (Azalia) registers and helpers
|
||||
*
|
||||
* For traditional reasons, we still use azx_ prefix here
|
||||
*/
|
||||
|
||||
#ifndef __SOUND_HDA_REGISTER_H
|
||||
#define __SOUND_HDA_REGISTER_H
|
||||
|
||||
#include <linux/io.h>
|
||||
#include <sound/hdaudio.h>
|
||||
|
||||
#define AZX_REG_GCAP 0x00
|
||||
#define AZX_GCAP_64OK (1 << 0) /* 64bit address support */
|
||||
#define AZX_GCAP_NSDO (3 << 1) /* # of serial data out signals */
|
||||
#define AZX_GCAP_BSS (31 << 3) /* # of bidirectional streams */
|
||||
#define AZX_GCAP_ISS (15 << 8) /* # of input streams */
|
||||
#define AZX_GCAP_OSS (15 << 12) /* # of output streams */
|
||||
#define AZX_REG_VMIN 0x02
|
||||
#define AZX_REG_VMAJ 0x03
|
||||
#define AZX_REG_OUTPAY 0x04
|
||||
#define AZX_REG_INPAY 0x06
|
||||
#define AZX_REG_GCTL 0x08
|
||||
#define AZX_GCTL_RESET (1 << 0) /* controller reset */
|
||||
#define AZX_GCTL_FCNTRL (1 << 1) /* flush control */
|
||||
#define AZX_GCTL_UNSOL (1 << 8) /* accept unsol. response enable */
|
||||
#define AZX_REG_WAKEEN 0x0c
|
||||
#define AZX_REG_STATESTS 0x0e
|
||||
#define AZX_REG_GSTS 0x10
|
||||
#define AZX_GSTS_FSTS (1 << 1) /* flush status */
|
||||
#define AZX_REG_GCAP2 0x12
|
||||
#define AZX_REG_LLCH 0x14
|
||||
#define AZX_REG_OUTSTRMPAY 0x18
|
||||
#define AZX_REG_INSTRMPAY 0x1A
|
||||
#define AZX_REG_INTCTL 0x20
|
||||
#define AZX_REG_INTSTS 0x24
|
||||
#define AZX_REG_WALLCLK 0x30 /* 24Mhz source */
|
||||
#define AZX_REG_OLD_SSYNC 0x34 /* SSYNC for old ICH */
|
||||
#define AZX_REG_SSYNC 0x38
|
||||
#define AZX_REG_CORBLBASE 0x40
|
||||
#define AZX_REG_CORBUBASE 0x44
|
||||
#define AZX_REG_CORBWP 0x48
|
||||
#define AZX_REG_CORBRP 0x4a
|
||||
#define AZX_CORBRP_RST (1 << 15) /* read pointer reset */
|
||||
#define AZX_REG_CORBCTL 0x4c
|
||||
#define AZX_CORBCTL_RUN (1 << 1) /* enable DMA */
|
||||
#define AZX_CORBCTL_CMEIE (1 << 0) /* enable memory error irq */
|
||||
#define AZX_REG_CORBSTS 0x4d
|
||||
#define AZX_CORBSTS_CMEI (1 << 0) /* memory error indication */
|
||||
#define AZX_REG_CORBSIZE 0x4e
|
||||
|
||||
#define AZX_REG_RIRBLBASE 0x50
|
||||
#define AZX_REG_RIRBUBASE 0x54
|
||||
#define AZX_REG_RIRBWP 0x58
|
||||
#define AZX_RIRBWP_RST (1 << 15) /* write pointer reset */
|
||||
#define AZX_REG_RINTCNT 0x5a
|
||||
#define AZX_REG_RIRBCTL 0x5c
|
||||
#define AZX_RBCTL_IRQ_EN (1 << 0) /* enable IRQ */
|
||||
#define AZX_RBCTL_DMA_EN (1 << 1) /* enable DMA */
|
||||
#define AZX_RBCTL_OVERRUN_EN (1 << 2) /* enable overrun irq */
|
||||
#define AZX_REG_RIRBSTS 0x5d
|
||||
#define AZX_RBSTS_IRQ (1 << 0) /* response irq */
|
||||
#define AZX_RBSTS_OVERRUN (1 << 2) /* overrun irq */
|
||||
#define AZX_REG_RIRBSIZE 0x5e
|
||||
|
||||
#define AZX_REG_IC 0x60
|
||||
#define AZX_REG_IR 0x64
|
||||
#define AZX_REG_IRS 0x68
|
||||
#define AZX_IRS_VALID (1<<1)
|
||||
#define AZX_IRS_BUSY (1<<0)
|
||||
|
||||
#define AZX_REG_DPLBASE 0x70
|
||||
#define AZX_REG_DPUBASE 0x74
|
||||
#define AZX_DPLBASE_ENABLE 0x1 /* Enable position buffer */
|
||||
|
||||
/* SD offset: SDI0=0x80, SDI1=0xa0, ... SDO3=0x160 */
|
||||
enum { SDI0, SDI1, SDI2, SDI3, SDO0, SDO1, SDO2, SDO3 };
|
||||
|
||||
/* stream register offsets from stream base */
|
||||
#define AZX_REG_SD_CTL 0x00
|
||||
#define AZX_REG_SD_STS 0x03
|
||||
#define AZX_REG_SD_LPIB 0x04
|
||||
#define AZX_REG_SD_CBL 0x08
|
||||
#define AZX_REG_SD_LVI 0x0c
|
||||
#define AZX_REG_SD_FIFOW 0x0e
|
||||
#define AZX_REG_SD_FIFOSIZE 0x10
|
||||
#define AZX_REG_SD_FORMAT 0x12
|
||||
#define AZX_REG_SD_FIFOL 0x14
|
||||
#define AZX_REG_SD_BDLPL 0x18
|
||||
#define AZX_REG_SD_BDLPU 0x1c
|
||||
|
||||
/* Haswell/Broadwell display HD-A controller Extended Mode registers */
|
||||
#define AZX_REG_HSW_EM4 0x100c
|
||||
#define AZX_REG_HSW_EM5 0x1010
|
||||
|
||||
/* PCI space */
|
||||
#define AZX_PCIREG_TCSEL 0x44
|
||||
|
||||
/*
|
||||
* other constants
|
||||
*/
|
||||
|
||||
/* max number of fragments - we may use more if allocating more pages for BDL */
|
||||
#define BDL_SIZE 4096
|
||||
#define AZX_MAX_BDL_ENTRIES (BDL_SIZE / 16)
|
||||
#define AZX_MAX_FRAG 32
|
||||
/* max buffer size - no h/w limit, you can increase as you like */
|
||||
#define AZX_MAX_BUF_SIZE (1024*1024*1024)
|
||||
|
||||
/* RIRB int mask: overrun[2], response[0] */
|
||||
#define RIRB_INT_RESPONSE 0x01
|
||||
#define RIRB_INT_OVERRUN 0x04
|
||||
#define RIRB_INT_MASK 0x05
|
||||
|
||||
/* STATESTS int mask: S3,SD2,SD1,SD0 */
|
||||
#define STATESTS_INT_MASK ((1 << HDA_MAX_CODECS) - 1)
|
||||
|
||||
/* SD_CTL bits */
|
||||
#define SD_CTL_STREAM_RESET 0x01 /* stream reset bit */
|
||||
#define SD_CTL_DMA_START 0x02 /* stream DMA start bit */
|
||||
#define SD_CTL_STRIPE (3 << 16) /* stripe control */
|
||||
#define SD_CTL_TRAFFIC_PRIO (1 << 18) /* traffic priority */
|
||||
#define SD_CTL_DIR (1 << 19) /* bi-directional stream */
|
||||
#define SD_CTL_STREAM_TAG_MASK (0xf << 20)
|
||||
#define SD_CTL_STREAM_TAG_SHIFT 20
|
||||
|
||||
/* SD_CTL and SD_STS */
|
||||
#define SD_INT_DESC_ERR 0x10 /* descriptor error interrupt */
|
||||
#define SD_INT_FIFO_ERR 0x08 /* FIFO error interrupt */
|
||||
#define SD_INT_COMPLETE 0x04 /* completion interrupt */
|
||||
#define SD_INT_MASK (SD_INT_DESC_ERR|SD_INT_FIFO_ERR|\
|
||||
SD_INT_COMPLETE)
|
||||
|
||||
/* SD_STS */
|
||||
#define SD_STS_FIFO_READY 0x20 /* FIFO ready */
|
||||
|
||||
/* INTCTL and INTSTS */
|
||||
#define AZX_INT_ALL_STREAM 0xff /* all stream interrupts */
|
||||
#define AZX_INT_CTRL_EN 0x40000000 /* controller interrupt enable bit */
|
||||
#define AZX_INT_GLOBAL_EN 0x80000000 /* global interrupt enable bit */
|
||||
|
||||
/* below are so far hardcoded - should read registers in future */
|
||||
#define AZX_MAX_CORB_ENTRIES 256
|
||||
#define AZX_MAX_RIRB_ENTRIES 256
|
||||
|
||||
/* Capability header Structure */
|
||||
#define AZX_REG_CAP_HDR 0x0
|
||||
#define AZX_CAP_HDR_VER_OFF 28
|
||||
#define AZX_CAP_HDR_VER_MASK (0xF << AZX_CAP_HDR_VER_OFF)
|
||||
#define AZX_CAP_HDR_ID_OFF 16
|
||||
#define AZX_CAP_HDR_ID_MASK (0xFFF << AZX_CAP_HDR_ID_OFF)
|
||||
#define AZX_CAP_HDR_NXT_PTR_MASK 0xFFFF
|
||||
|
||||
/* registers of Software Position Based FIFO Capability Structure */
|
||||
#define AZX_SPB_CAP_ID 0x4
|
||||
#define AZX_REG_SPB_BASE_ADDR 0x700
|
||||
#define AZX_REG_SPB_SPBFCH 0x00
|
||||
#define AZX_REG_SPB_SPBFCCTL 0x04
|
||||
/* Base used to calculate the iterating register offset */
|
||||
#define AZX_SPB_BASE 0x08
|
||||
/* Interval used to calculate the iterating register offset */
|
||||
#define AZX_SPB_INTERVAL 0x08
|
||||
|
||||
/* registers of Global Time Synchronization Capability Structure */
|
||||
#define AZX_GTS_CAP_ID 0x1
|
||||
#define AZX_REG_GTS_GTSCH 0x00
|
||||
#define AZX_REG_GTS_GTSCD 0x04
|
||||
#define AZX_REG_GTS_GTSCTLAC 0x0C
|
||||
#define AZX_GTS_BASE 0x20
|
||||
#define AZX_GTS_INTERVAL 0x20
|
||||
|
||||
/* registers for Processing Pipe Capability Structure */
|
||||
#define AZX_PP_CAP_ID 0x3
|
||||
#define AZX_REG_PP_PPCH 0x10
|
||||
#define AZX_REG_PP_PPCTL 0x04
|
||||
#define AZX_PPCTL_PIE (1<<31)
|
||||
#define AZX_PPCTL_GPROCEN (1<<30)
|
||||
/* _X_ = dma engine # and cannot * exceed 29 (per spec max 30 dma engines) */
|
||||
#define AZX_PPCTL_PROCEN(_X_) (1<<(_X_))
|
||||
|
||||
#define AZX_REG_PP_PPSTS 0x08
|
||||
|
||||
#define AZX_PPHC_BASE 0x10
|
||||
#define AZX_PPHC_INTERVAL 0x10
|
||||
|
||||
#define AZX_REG_PPHCLLPL 0x0
|
||||
#define AZX_REG_PPHCLLPU 0x4
|
||||
#define AZX_REG_PPHCLDPL 0x8
|
||||
#define AZX_REG_PPHCLDPU 0xC
|
||||
|
||||
#define AZX_PPLC_BASE 0x10
|
||||
#define AZX_PPLC_MULTI 0x10
|
||||
#define AZX_PPLC_INTERVAL 0x10
|
||||
|
||||
#define AZX_REG_PPLCCTL 0x0
|
||||
#define AZX_PPLCCTL_STRM_BITS 4
|
||||
#define AZX_PPLCCTL_STRM_SHIFT 20
|
||||
#define AZX_REG_MASK(bit_num, offset) \
|
||||
(((1 << (bit_num)) - 1) << (offset))
|
||||
#define AZX_PPLCCTL_STRM_MASK \
|
||||
AZX_REG_MASK(AZX_PPLCCTL_STRM_BITS, AZX_PPLCCTL_STRM_SHIFT)
|
||||
#define AZX_PPLCCTL_RUN (1<<1)
|
||||
#define AZX_PPLCCTL_STRST (1<<0)
|
||||
|
||||
#define AZX_REG_PPLCFMT 0x4
|
||||
#define AZX_REG_PPLCLLPL 0x8
|
||||
#define AZX_REG_PPLCLLPU 0xC
|
||||
|
||||
/* registers for Multiple Links Capability Structure */
|
||||
#define AZX_ML_CAP_ID 0x2
|
||||
#define AZX_REG_ML_MLCH 0x00
|
||||
#define AZX_REG_ML_MLCD 0x04
|
||||
#define AZX_ML_BASE 0x40
|
||||
#define AZX_ML_INTERVAL 0x40
|
||||
|
||||
#define AZX_REG_ML_LCAP 0x00
|
||||
#define AZX_REG_ML_LCTL 0x04
|
||||
#define AZX_REG_ML_LOSIDV 0x08
|
||||
#define AZX_REG_ML_LSDIID 0x0C
|
||||
#define AZX_REG_ML_LPSOO 0x10
|
||||
#define AZX_REG_ML_LPSIO 0x12
|
||||
#define AZX_REG_ML_LWALFC 0x18
|
||||
#define AZX_REG_ML_LOUTPAY 0x20
|
||||
#define AZX_REG_ML_LINPAY 0x30
|
||||
|
||||
#define AZX_MLCTL_SPA (1<<16)
|
||||
#define AZX_MLCTL_CPA 23
|
||||
|
||||
/*
|
||||
* helpers to read the stream position
|
||||
*/
|
||||
static inline unsigned int
|
||||
snd_hdac_stream_get_pos_lpib(struct hdac_stream *stream)
|
||||
{
|
||||
return snd_hdac_stream_readl(stream, SD_LPIB);
|
||||
}
|
||||
|
||||
static inline unsigned int
|
||||
snd_hdac_stream_get_pos_posbuf(struct hdac_stream *stream)
|
||||
{
|
||||
return le32_to_cpu(*stream->posbuf);
|
||||
}
|
||||
|
||||
#endif /* __SOUND_HDA_REGISTER_H */
|
@ -6,12 +6,18 @@
|
||||
#define __SOUND_HDAUDIO_H
|
||||
|
||||
#include <linux/device.h>
|
||||
#include <linux/interrupt.h>
|
||||
#include <linux/timecounter.h>
|
||||
#include <sound/core.h>
|
||||
#include <sound/memalloc.h>
|
||||
#include <sound/hda_verbs.h>
|
||||
#include <drm/i915_component.h>
|
||||
|
||||
/* codec node id */
|
||||
typedef u16 hda_nid_t;
|
||||
|
||||
struct hdac_bus;
|
||||
struct hdac_stream;
|
||||
struct hdac_device;
|
||||
struct hdac_driver;
|
||||
struct hdac_widget_tree;
|
||||
@ -21,6 +27,16 @@ struct hdac_widget_tree;
|
||||
*/
|
||||
extern struct bus_type snd_hda_bus_type;
|
||||
|
||||
/*
|
||||
* HDA device table
|
||||
*/
|
||||
struct hda_device_id {
|
||||
__u32 vendor_id;
|
||||
__u32 rev_id;
|
||||
const char *name;
|
||||
unsigned long driver_data;
|
||||
};
|
||||
|
||||
/*
|
||||
* generic arrays
|
||||
*/
|
||||
@ -69,6 +85,7 @@ struct hdac_device {
|
||||
|
||||
/* misc flags */
|
||||
atomic_t in_pm; /* suspend/resume being performed */
|
||||
bool link_power_control:1;
|
||||
|
||||
/* sysfs */
|
||||
struct hdac_widget_tree *widgets;
|
||||
@ -85,6 +102,7 @@ struct hdac_device {
|
||||
enum {
|
||||
HDA_DEV_CORE,
|
||||
HDA_DEV_LEGACY,
|
||||
HDA_DEV_ASOC,
|
||||
};
|
||||
|
||||
/* direction */
|
||||
@ -118,6 +136,15 @@ int snd_hdac_get_connections(struct hdac_device *codec, hda_nid_t nid,
|
||||
hda_nid_t *conn_list, int max_conns);
|
||||
int snd_hdac_get_sub_nodes(struct hdac_device *codec, hda_nid_t nid,
|
||||
hda_nid_t *start_id);
|
||||
unsigned int snd_hdac_calc_stream_format(unsigned int rate,
|
||||
unsigned int channels,
|
||||
unsigned int format,
|
||||
unsigned int maxbps,
|
||||
unsigned short spdif_ctls);
|
||||
int snd_hdac_query_supported_pcm(struct hdac_device *codec, hda_nid_t nid,
|
||||
u32 *ratesp, u64 *formatsp, unsigned int *bpsp);
|
||||
bool snd_hdac_is_supported_format(struct hdac_device *codec, hda_nid_t nid,
|
||||
unsigned int format);
|
||||
|
||||
/**
|
||||
* snd_hdac_read_parm - read a codec parameter
|
||||
@ -154,14 +181,18 @@ static inline void snd_hdac_power_down_pm(struct hdac_device *codec) {}
|
||||
struct hdac_driver {
|
||||
struct device_driver driver;
|
||||
int type;
|
||||
const struct hda_device_id *id_table;
|
||||
int (*match)(struct hdac_device *dev, struct hdac_driver *drv);
|
||||
void (*unsol_event)(struct hdac_device *dev, unsigned int event);
|
||||
};
|
||||
|
||||
#define drv_to_hdac_driver(_drv) container_of(_drv, struct hdac_driver, driver)
|
||||
|
||||
const struct hda_device_id *
|
||||
hdac_get_device_id(struct hdac_device *hdev, struct hdac_driver *drv);
|
||||
|
||||
/*
|
||||
* HD-audio bus base driver
|
||||
* Bus verb operators
|
||||
*/
|
||||
struct hdac_bus_ops {
|
||||
/* send a single command */
|
||||
@ -169,13 +200,59 @@ struct hdac_bus_ops {
|
||||
/* get a response from the last command */
|
||||
int (*get_response)(struct hdac_bus *bus, unsigned int addr,
|
||||
unsigned int *res);
|
||||
/* control the link power */
|
||||
int (*link_power)(struct hdac_bus *bus, bool enable);
|
||||
};
|
||||
|
||||
/*
|
||||
* Lowlevel I/O operators
|
||||
*/
|
||||
struct hdac_io_ops {
|
||||
/* mapped register accesses */
|
||||
void (*reg_writel)(u32 value, u32 __iomem *addr);
|
||||
u32 (*reg_readl)(u32 __iomem *addr);
|
||||
void (*reg_writew)(u16 value, u16 __iomem *addr);
|
||||
u16 (*reg_readw)(u16 __iomem *addr);
|
||||
void (*reg_writeb)(u8 value, u8 __iomem *addr);
|
||||
u8 (*reg_readb)(u8 __iomem *addr);
|
||||
/* Allocation ops */
|
||||
int (*dma_alloc_pages)(struct hdac_bus *bus, int type, size_t size,
|
||||
struct snd_dma_buffer *buf);
|
||||
void (*dma_free_pages)(struct hdac_bus *bus,
|
||||
struct snd_dma_buffer *buf);
|
||||
};
|
||||
|
||||
#define HDA_UNSOL_QUEUE_SIZE 64
|
||||
#define HDA_MAX_CODECS 8 /* limit by controller side */
|
||||
|
||||
/* HD Audio class code */
|
||||
#define PCI_CLASS_MULTIMEDIA_HD_AUDIO 0x0403
|
||||
|
||||
/*
|
||||
* CORB/RIRB
|
||||
*
|
||||
* Each CORB entry is 4byte, RIRB is 8byte
|
||||
*/
|
||||
struct hdac_rb {
|
||||
__le32 *buf; /* virtual address of CORB/RIRB buffer */
|
||||
dma_addr_t addr; /* physical address of CORB/RIRB buffer */
|
||||
unsigned short rp, wp; /* RIRB read/write pointers */
|
||||
int cmds[HDA_MAX_CODECS]; /* number of pending requests */
|
||||
u32 res[HDA_MAX_CODECS]; /* last read value */
|
||||
};
|
||||
|
||||
/*
|
||||
* HD-audio bus base driver
|
||||
*/
|
||||
struct hdac_bus {
|
||||
struct device *dev;
|
||||
const struct hdac_bus_ops *ops;
|
||||
const struct hdac_io_ops *io_ops;
|
||||
|
||||
/* h/w resources */
|
||||
unsigned long addr;
|
||||
void __iomem *remap_addr;
|
||||
int irq;
|
||||
|
||||
/* codec linked list */
|
||||
struct list_head codec_list;
|
||||
@ -189,18 +266,49 @@ struct hdac_bus {
|
||||
unsigned int unsol_rp, unsol_wp;
|
||||
struct work_struct unsol_work;
|
||||
|
||||
/* bit flags of detected codecs */
|
||||
unsigned long codec_mask;
|
||||
|
||||
/* bit flags of powered codecs */
|
||||
unsigned long codec_powered;
|
||||
|
||||
/* flags */
|
||||
/* CORB/RIRB */
|
||||
struct hdac_rb corb;
|
||||
struct hdac_rb rirb;
|
||||
unsigned int last_cmd[HDA_MAX_CODECS]; /* last sent command */
|
||||
|
||||
/* CORB/RIRB and position buffers */
|
||||
struct snd_dma_buffer rb;
|
||||
struct snd_dma_buffer posbuf;
|
||||
|
||||
/* hdac_stream linked list */
|
||||
struct list_head stream_list;
|
||||
|
||||
/* operation state */
|
||||
bool chip_init:1; /* h/w initialized */
|
||||
|
||||
/* behavior flags */
|
||||
bool sync_write:1; /* sync after verb write */
|
||||
bool use_posbuf:1; /* use position buffer */
|
||||
bool snoop:1; /* enable snooping */
|
||||
bool align_bdle_4k:1; /* BDLE align 4K boundary */
|
||||
bool reverse_assign:1; /* assign devices in reverse order */
|
||||
bool corbrp_self_clear:1; /* CORBRP clears itself after reset */
|
||||
|
||||
int bdl_pos_adj; /* BDL position adjustment */
|
||||
|
||||
/* locks */
|
||||
spinlock_t reg_lock;
|
||||
struct mutex cmd_mutex;
|
||||
|
||||
/* i915 component interface */
|
||||
struct i915_audio_component *audio_component;
|
||||
int i915_power_refcount;
|
||||
};
|
||||
|
||||
int snd_hdac_bus_init(struct hdac_bus *bus, struct device *dev,
|
||||
const struct hdac_bus_ops *ops);
|
||||
const struct hdac_bus_ops *ops,
|
||||
const struct hdac_io_ops *io_ops);
|
||||
void snd_hdac_bus_exit(struct hdac_bus *bus);
|
||||
int snd_hdac_bus_exec_verb(struct hdac_bus *bus, unsigned int addr,
|
||||
unsigned int cmd, unsigned int *res);
|
||||
@ -222,6 +330,201 @@ static inline void snd_hdac_codec_link_down(struct hdac_device *codec)
|
||||
clear_bit(codec->addr, &codec->bus->codec_powered);
|
||||
}
|
||||
|
||||
int snd_hdac_bus_send_cmd(struct hdac_bus *bus, unsigned int val);
|
||||
int snd_hdac_bus_get_response(struct hdac_bus *bus, unsigned int addr,
|
||||
unsigned int *res);
|
||||
int snd_hdac_link_power(struct hdac_device *codec, bool enable);
|
||||
|
||||
bool snd_hdac_bus_init_chip(struct hdac_bus *bus, bool full_reset);
|
||||
void snd_hdac_bus_stop_chip(struct hdac_bus *bus);
|
||||
void snd_hdac_bus_init_cmd_io(struct hdac_bus *bus);
|
||||
void snd_hdac_bus_stop_cmd_io(struct hdac_bus *bus);
|
||||
void snd_hdac_bus_enter_link_reset(struct hdac_bus *bus);
|
||||
void snd_hdac_bus_exit_link_reset(struct hdac_bus *bus);
|
||||
|
||||
void snd_hdac_bus_update_rirb(struct hdac_bus *bus);
|
||||
void snd_hdac_bus_handle_stream_irq(struct hdac_bus *bus, unsigned int status,
|
||||
void (*ack)(struct hdac_bus *,
|
||||
struct hdac_stream *));
|
||||
|
||||
int snd_hdac_bus_alloc_stream_pages(struct hdac_bus *bus);
|
||||
void snd_hdac_bus_free_stream_pages(struct hdac_bus *bus);
|
||||
|
||||
/*
|
||||
* macros for easy use
|
||||
*/
|
||||
#define _snd_hdac_chip_write(type, chip, reg, value) \
|
||||
((chip)->io_ops->reg_write ## type(value, (chip)->remap_addr + (reg)))
|
||||
#define _snd_hdac_chip_read(type, chip, reg) \
|
||||
((chip)->io_ops->reg_read ## type((chip)->remap_addr + (reg)))
|
||||
|
||||
/* read/write a register, pass without AZX_REG_ prefix */
|
||||
#define snd_hdac_chip_writel(chip, reg, value) \
|
||||
_snd_hdac_chip_write(l, chip, AZX_REG_ ## reg, value)
|
||||
#define snd_hdac_chip_writew(chip, reg, value) \
|
||||
_snd_hdac_chip_write(w, chip, AZX_REG_ ## reg, value)
|
||||
#define snd_hdac_chip_writeb(chip, reg, value) \
|
||||
_snd_hdac_chip_write(b, chip, AZX_REG_ ## reg, value)
|
||||
#define snd_hdac_chip_readl(chip, reg) \
|
||||
_snd_hdac_chip_read(l, chip, AZX_REG_ ## reg)
|
||||
#define snd_hdac_chip_readw(chip, reg) \
|
||||
_snd_hdac_chip_read(w, chip, AZX_REG_ ## reg)
|
||||
#define snd_hdac_chip_readb(chip, reg) \
|
||||
_snd_hdac_chip_read(b, chip, AZX_REG_ ## reg)
|
||||
|
||||
/* update a register, pass without AZX_REG_ prefix */
|
||||
#define snd_hdac_chip_updatel(chip, reg, mask, val) \
|
||||
snd_hdac_chip_writel(chip, reg, \
|
||||
(snd_hdac_chip_readl(chip, reg) & ~(mask)) | (val))
|
||||
#define snd_hdac_chip_updatew(chip, reg, mask, val) \
|
||||
snd_hdac_chip_writew(chip, reg, \
|
||||
(snd_hdac_chip_readw(chip, reg) & ~(mask)) | (val))
|
||||
#define snd_hdac_chip_updateb(chip, reg, mask, val) \
|
||||
snd_hdac_chip_writeb(chip, reg, \
|
||||
(snd_hdac_chip_readb(chip, reg) & ~(mask)) | (val))
|
||||
|
||||
/*
|
||||
* HD-audio stream
|
||||
*/
|
||||
struct hdac_stream {
|
||||
struct hdac_bus *bus;
|
||||
struct snd_dma_buffer bdl; /* BDL buffer */
|
||||
__le32 *posbuf; /* position buffer pointer */
|
||||
int direction; /* playback / capture (SNDRV_PCM_STREAM_*) */
|
||||
|
||||
unsigned int bufsize; /* size of the play buffer in bytes */
|
||||
unsigned int period_bytes; /* size of the period in bytes */
|
||||
unsigned int frags; /* number for period in the play buffer */
|
||||
unsigned int fifo_size; /* FIFO size */
|
||||
|
||||
void __iomem *sd_addr; /* stream descriptor pointer */
|
||||
|
||||
u32 sd_int_sta_mask; /* stream int status mask */
|
||||
|
||||
/* pcm support */
|
||||
struct snd_pcm_substream *substream; /* assigned substream,
|
||||
* set in PCM open
|
||||
*/
|
||||
unsigned int format_val; /* format value to be set in the
|
||||
* controller and the codec
|
||||
*/
|
||||
unsigned char stream_tag; /* assigned stream */
|
||||
unsigned char index; /* stream index */
|
||||
int assigned_key; /* last device# key assigned to */
|
||||
|
||||
bool opened:1;
|
||||
bool running:1;
|
||||
bool prepared:1;
|
||||
bool no_period_wakeup:1;
|
||||
bool locked:1;
|
||||
|
||||
/* timestamp */
|
||||
unsigned long start_wallclk; /* start + minimum wallclk */
|
||||
unsigned long period_wallclk; /* wallclk for period */
|
||||
struct timecounter tc;
|
||||
struct cyclecounter cc;
|
||||
int delay_negative_threshold;
|
||||
|
||||
struct list_head list;
|
||||
#ifdef CONFIG_SND_HDA_DSP_LOADER
|
||||
/* DSP access mutex */
|
||||
struct mutex dsp_mutex;
|
||||
#endif
|
||||
};
|
||||
|
||||
void snd_hdac_stream_init(struct hdac_bus *bus, struct hdac_stream *azx_dev,
|
||||
int idx, int direction, int tag);
|
||||
struct hdac_stream *snd_hdac_stream_assign(struct hdac_bus *bus,
|
||||
struct snd_pcm_substream *substream);
|
||||
void snd_hdac_stream_release(struct hdac_stream *azx_dev);
|
||||
|
||||
int snd_hdac_stream_setup(struct hdac_stream *azx_dev);
|
||||
void snd_hdac_stream_cleanup(struct hdac_stream *azx_dev);
|
||||
int snd_hdac_stream_setup_periods(struct hdac_stream *azx_dev);
|
||||
int snd_hdac_stream_set_params(struct hdac_stream *azx_dev,
|
||||
unsigned int format_val);
|
||||
void snd_hdac_stream_start(struct hdac_stream *azx_dev, bool fresh_start);
|
||||
void snd_hdac_stream_clear(struct hdac_stream *azx_dev);
|
||||
void snd_hdac_stream_stop(struct hdac_stream *azx_dev);
|
||||
void snd_hdac_stream_reset(struct hdac_stream *azx_dev);
|
||||
void snd_hdac_stream_sync_trigger(struct hdac_stream *azx_dev, bool set,
|
||||
unsigned int streams, unsigned int reg);
|
||||
void snd_hdac_stream_sync(struct hdac_stream *azx_dev, bool start,
|
||||
unsigned int streams);
|
||||
void snd_hdac_stream_timecounter_init(struct hdac_stream *azx_dev,
|
||||
unsigned int streams);
|
||||
/*
|
||||
* macros for easy use
|
||||
*/
|
||||
#define _snd_hdac_stream_write(type, dev, reg, value) \
|
||||
((dev)->bus->io_ops->reg_write ## type(value, (dev)->sd_addr + (reg)))
|
||||
#define _snd_hdac_stream_read(type, dev, reg) \
|
||||
((dev)->bus->io_ops->reg_read ## type((dev)->sd_addr + (reg)))
|
||||
|
||||
/* read/write a register, pass without AZX_REG_ prefix */
|
||||
#define snd_hdac_stream_writel(dev, reg, value) \
|
||||
_snd_hdac_stream_write(l, dev, AZX_REG_ ## reg, value)
|
||||
#define snd_hdac_stream_writew(dev, reg, value) \
|
||||
_snd_hdac_stream_write(w, dev, AZX_REG_ ## reg, value)
|
||||
#define snd_hdac_stream_writeb(dev, reg, value) \
|
||||
_snd_hdac_stream_write(b, dev, AZX_REG_ ## reg, value)
|
||||
#define snd_hdac_stream_readl(dev, reg) \
|
||||
_snd_hdac_stream_read(l, dev, AZX_REG_ ## reg)
|
||||
#define snd_hdac_stream_readw(dev, reg) \
|
||||
_snd_hdac_stream_read(w, dev, AZX_REG_ ## reg)
|
||||
#define snd_hdac_stream_readb(dev, reg) \
|
||||
_snd_hdac_stream_read(b, dev, AZX_REG_ ## reg)
|
||||
|
||||
/* update a register, pass without AZX_REG_ prefix */
|
||||
#define snd_hdac_stream_updatel(dev, reg, mask, val) \
|
||||
snd_hdac_stream_writel(dev, reg, \
|
||||
(snd_hdac_stream_readl(dev, reg) & \
|
||||
~(mask)) | (val))
|
||||
#define snd_hdac_stream_updatew(dev, reg, mask, val) \
|
||||
snd_hdac_stream_writew(dev, reg, \
|
||||
(snd_hdac_stream_readw(dev, reg) & \
|
||||
~(mask)) | (val))
|
||||
#define snd_hdac_stream_updateb(dev, reg, mask, val) \
|
||||
snd_hdac_stream_writeb(dev, reg, \
|
||||
(snd_hdac_stream_readb(dev, reg) & \
|
||||
~(mask)) | (val))
|
||||
|
||||
#ifdef CONFIG_SND_HDA_DSP_LOADER
|
||||
/* DSP lock helpers */
|
||||
#define snd_hdac_dsp_lock_init(dev) mutex_init(&(dev)->dsp_mutex)
|
||||
#define snd_hdac_dsp_lock(dev) mutex_lock(&(dev)->dsp_mutex)
|
||||
#define snd_hdac_dsp_unlock(dev) mutex_unlock(&(dev)->dsp_mutex)
|
||||
#define snd_hdac_stream_is_locked(dev) ((dev)->locked)
|
||||
/* DSP loader helpers */
|
||||
int snd_hdac_dsp_prepare(struct hdac_stream *azx_dev, unsigned int format,
|
||||
unsigned int byte_size, struct snd_dma_buffer *bufp);
|
||||
void snd_hdac_dsp_trigger(struct hdac_stream *azx_dev, bool start);
|
||||
void snd_hdac_dsp_cleanup(struct hdac_stream *azx_dev,
|
||||
struct snd_dma_buffer *dmab);
|
||||
#else /* CONFIG_SND_HDA_DSP_LOADER */
|
||||
#define snd_hdac_dsp_lock_init(dev) do {} while (0)
|
||||
#define snd_hdac_dsp_lock(dev) do {} while (0)
|
||||
#define snd_hdac_dsp_unlock(dev) do {} while (0)
|
||||
#define snd_hdac_stream_is_locked(dev) 0
|
||||
|
||||
static inline int
|
||||
snd_hdac_dsp_prepare(struct hdac_stream *azx_dev, unsigned int format,
|
||||
unsigned int byte_size, struct snd_dma_buffer *bufp)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline void snd_hdac_dsp_trigger(struct hdac_stream *azx_dev, bool start)
|
||||
{
|
||||
}
|
||||
|
||||
static inline void snd_hdac_dsp_cleanup(struct hdac_stream *azx_dev,
|
||||
struct snd_dma_buffer *dmab)
|
||||
{
|
||||
}
|
||||
#endif /* CONFIG_SND_HDA_DSP_LOADER */
|
||||
|
||||
|
||||
/*
|
||||
* generic array helpers
|
||||
*/
|
||||
|
132
include/sound/hdaudio_ext.h
Normal file
132
include/sound/hdaudio_ext.h
Normal file
@ -0,0 +1,132 @@
|
||||
#ifndef __SOUND_HDAUDIO_EXT_H
|
||||
#define __SOUND_HDAUDIO_EXT_H
|
||||
|
||||
#include <sound/hdaudio.h>
|
||||
|
||||
/**
|
||||
* hdac_ext_bus: HDAC extended bus for extended HDA caps
|
||||
*
|
||||
* @bus: hdac bus
|
||||
* @num_streams: streams supported
|
||||
* @ppcap: pp capabilities pointer
|
||||
* @spbcap: SPIB capabilities pointer
|
||||
* @mlcap: MultiLink capabilities pointer
|
||||
* @gtscap: gts capabilities pointer
|
||||
* @hlink_list: link list of HDA links
|
||||
*/
|
||||
struct hdac_ext_bus {
|
||||
struct hdac_bus bus;
|
||||
int num_streams;
|
||||
int idx;
|
||||
|
||||
void __iomem *ppcap;
|
||||
void __iomem *spbcap;
|
||||
void __iomem *mlcap;
|
||||
void __iomem *gtscap;
|
||||
|
||||
struct list_head hlink_list;
|
||||
};
|
||||
|
||||
int snd_hdac_ext_bus_init(struct hdac_ext_bus *sbus, struct device *dev,
|
||||
const struct hdac_bus_ops *ops,
|
||||
const struct hdac_io_ops *io_ops);
|
||||
|
||||
void snd_hdac_ext_bus_exit(struct hdac_ext_bus *sbus);
|
||||
int snd_hdac_ext_bus_device_init(struct hdac_ext_bus *sbus, int addr);
|
||||
void snd_hdac_ext_bus_device_exit(struct hdac_device *hdev);
|
||||
|
||||
#define ebus_to_hbus(ebus) (&(ebus)->bus)
|
||||
#define hbus_to_ebus(_bus) \
|
||||
container_of(_bus, struct hdac_ext_bus, bus)
|
||||
|
||||
int snd_hdac_ext_bus_parse_capabilities(struct hdac_ext_bus *sbus);
|
||||
void snd_hdac_ext_bus_ppcap_enable(struct hdac_ext_bus *chip, bool enable);
|
||||
void snd_hdac_ext_bus_ppcap_int_enable(struct hdac_ext_bus *chip, bool enable);
|
||||
|
||||
void snd_hdac_ext_stream_spbcap_enable(struct hdac_ext_bus *chip,
|
||||
bool enable, int index);
|
||||
|
||||
int snd_hdac_ext_bus_get_ml_capabilities(struct hdac_ext_bus *bus);
|
||||
struct hdac_ext_link *snd_hdac_ext_bus_get_link(struct hdac_ext_bus *bus,
|
||||
const char *codec_name);
|
||||
|
||||
enum hdac_ext_stream_type {
|
||||
HDAC_EXT_STREAM_TYPE_COUPLED = 0,
|
||||
HDAC_EXT_STREAM_TYPE_HOST,
|
||||
HDAC_EXT_STREAM_TYPE_LINK
|
||||
};
|
||||
|
||||
/**
|
||||
* hdac_ext_stream: HDAC extended stream for extended HDA caps
|
||||
*
|
||||
* @hstream: hdac_stream
|
||||
* @pphc_addr: processing pipe host stream pointer
|
||||
* @pplc_addr: processing pipe link stream pointer
|
||||
* @decoupled: stream host and link is decoupled
|
||||
* @link_locked: link is locked
|
||||
* @link_prepared: link is prepared
|
||||
* link_substream: link substream
|
||||
*/
|
||||
struct hdac_ext_stream {
|
||||
struct hdac_stream hstream;
|
||||
|
||||
void __iomem *pphc_addr;
|
||||
void __iomem *pplc_addr;
|
||||
|
||||
bool decoupled:1;
|
||||
bool link_locked:1;
|
||||
bool link_prepared;
|
||||
|
||||
struct snd_pcm_substream *link_substream;
|
||||
};
|
||||
|
||||
#define hdac_stream(s) (&(s)->hstream)
|
||||
#define stream_to_hdac_ext_stream(s) \
|
||||
container_of(s, struct hdac_ext_stream, hstream)
|
||||
|
||||
void snd_hdac_ext_stream_init(struct hdac_ext_bus *bus,
|
||||
struct hdac_ext_stream *stream, int idx,
|
||||
int direction, int tag);
|
||||
int snd_hdac_ext_stream_init_all(struct hdac_ext_bus *ebus, int start_idx,
|
||||
int num_stream, int dir);
|
||||
void snd_hdac_stream_free_all(struct hdac_ext_bus *ebus);
|
||||
void snd_hdac_link_free_all(struct hdac_ext_bus *ebus);
|
||||
struct hdac_ext_stream *snd_hdac_ext_stream_assign(struct hdac_ext_bus *bus,
|
||||
struct snd_pcm_substream *substream,
|
||||
int type);
|
||||
void snd_hdac_ext_stream_release(struct hdac_ext_stream *azx_dev, int type);
|
||||
void snd_hdac_ext_stream_decouple(struct hdac_ext_bus *bus,
|
||||
struct hdac_ext_stream *azx_dev, bool decouple);
|
||||
void snd_hdac_ext_stop_streams(struct hdac_ext_bus *sbus);
|
||||
|
||||
void snd_hdac_ext_link_stream_start(struct hdac_ext_stream *hstream);
|
||||
void snd_hdac_ext_link_stream_clear(struct hdac_ext_stream *hstream);
|
||||
void snd_hdac_ext_link_stream_reset(struct hdac_ext_stream *hstream);
|
||||
int snd_hdac_ext_link_stream_setup(struct hdac_ext_stream *stream, int fmt);
|
||||
|
||||
struct hdac_ext_link {
|
||||
struct hdac_bus *bus;
|
||||
int index;
|
||||
void __iomem *ml_addr; /* link output stream reg pointer */
|
||||
u32 lcaps; /* link capablities */
|
||||
u16 lsdiid; /* link sdi identifier */
|
||||
struct list_head list;
|
||||
};
|
||||
|
||||
int snd_hdac_ext_bus_link_power_up(struct hdac_ext_link *link);
|
||||
int snd_hdac_ext_bus_link_power_down(struct hdac_ext_link *link);
|
||||
void snd_hdac_ext_link_set_stream_id(struct hdac_ext_link *link,
|
||||
int stream);
|
||||
void snd_hdac_ext_link_clear_stream_id(struct hdac_ext_link *link,
|
||||
int stream);
|
||||
|
||||
/* update register macro */
|
||||
#define snd_hdac_updatel(addr, reg, mask, val) \
|
||||
writel(((readl(addr + reg) & ~(mask)) | (val)), \
|
||||
addr + reg)
|
||||
|
||||
#define snd_hdac_updatew(addr, reg, mask, val) \
|
||||
writew(((readw(addr + reg) & ~(mask)) | (val)), \
|
||||
addr + reg)
|
||||
|
||||
#endif /* __SOUND_HDAUDIO_EXT_H */
|
@ -23,6 +23,8 @@
|
||||
*/
|
||||
|
||||
#include <linux/poll.h>
|
||||
#include <linux/seq_file.h>
|
||||
#include <sound/core.h>
|
||||
|
||||
/* buffer for information */
|
||||
struct snd_info_buffer {
|
||||
@ -90,16 +92,14 @@ struct snd_info_entry {
|
||||
struct list_head list;
|
||||
};
|
||||
|
||||
#if defined(CONFIG_SND_OSSEMUL) && defined(CONFIG_PROC_FS)
|
||||
#if defined(CONFIG_SND_OSSEMUL) && defined(CONFIG_SND_PROC_FS)
|
||||
int snd_info_minor_register(void);
|
||||
int snd_info_minor_unregister(void);
|
||||
#else
|
||||
#define snd_info_minor_register() /* NOP */
|
||||
#define snd_info_minor_unregister() /* NOP */
|
||||
#define snd_info_minor_register() 0
|
||||
#endif
|
||||
|
||||
|
||||
#ifdef CONFIG_PROC_FS
|
||||
#ifdef CONFIG_SND_PROC_FS
|
||||
|
||||
extern struct snd_info_entry *snd_seq_root;
|
||||
#ifdef CONFIG_SND_OSSEMUL
|
||||
@ -110,8 +110,18 @@ void snd_card_info_read_oss(struct snd_info_buffer *buffer);
|
||||
static inline void snd_card_info_read_oss(struct snd_info_buffer *buffer) {}
|
||||
#endif
|
||||
|
||||
__printf(2, 3)
|
||||
int snd_iprintf(struct snd_info_buffer *buffer, const char *fmt, ...);
|
||||
/**
|
||||
* snd_iprintf - printf on the procfs buffer
|
||||
* @buf: the procfs buffer
|
||||
* @fmt: the printf format
|
||||
*
|
||||
* Outputs the string on the procfs buffer just like printf().
|
||||
*
|
||||
* Return: zero for success, or a negative error code.
|
||||
*/
|
||||
#define snd_iprintf(buf, fmt, args...) \
|
||||
seq_printf((struct seq_file *)(buf)->buffer, fmt, ##args)
|
||||
|
||||
int snd_info_init(void);
|
||||
int snd_info_done(void);
|
||||
|
||||
@ -135,8 +145,12 @@ void snd_info_card_id_change(struct snd_card *card);
|
||||
int snd_info_register(struct snd_info_entry *entry);
|
||||
|
||||
/* for card drivers */
|
||||
int snd_card_proc_new(struct snd_card *card, const char *name,
|
||||
struct snd_info_entry **entryp);
|
||||
static inline int snd_card_proc_new(struct snd_card *card, const char *name,
|
||||
struct snd_info_entry **entryp)
|
||||
{
|
||||
*entryp = snd_info_create_card_entry(card, name, card->proc_root);
|
||||
return *entryp ? 0 : -ENOMEM;
|
||||
}
|
||||
|
||||
static inline void snd_info_set_text_ops(struct snd_info_entry *entry,
|
||||
void *private_data,
|
||||
@ -175,7 +189,6 @@ static inline int snd_card_proc_new(struct snd_card *card, const char *name,
|
||||
static inline void snd_info_set_text_ops(struct snd_info_entry *entry __attribute__((unused)),
|
||||
void *private_data,
|
||||
void (*read)(struct snd_info_entry *, struct snd_info_buffer *)) {}
|
||||
|
||||
static inline int snd_info_check_reserved_words(const char *str) { return 1; }
|
||||
|
||||
#endif
|
||||
@ -184,7 +197,7 @@ static inline int snd_info_check_reserved_words(const char *str) { return 1; }
|
||||
* OSS info part
|
||||
*/
|
||||
|
||||
#if defined(CONFIG_SND_OSSEMUL) && defined(CONFIG_PROC_FS)
|
||||
#if defined(CONFIG_SND_OSSEMUL) && defined(CONFIG_SND_PROC_FS)
|
||||
|
||||
#define SNDRV_OSS_INFO_DEV_AUDIO 0
|
||||
#define SNDRV_OSS_INFO_DEV_SYNTH 1
|
||||
@ -197,6 +210,6 @@ static inline int snd_info_check_reserved_words(const char *str) { return 1; }
|
||||
int snd_oss_info_register(int dev, int num, char *string);
|
||||
#define snd_oss_info_unregister(dev, num) snd_oss_info_register(dev, num, NULL)
|
||||
|
||||
#endif /* CONFIG_SND_OSSEMUL && CONFIG_PROC_FS */
|
||||
#endif /* CONFIG_SND_OSSEMUL && CONFIG_SND_PROC_FS */
|
||||
|
||||
#endif /* __SOUND_INFO_H */
|
||||
|
@ -73,6 +73,8 @@ enum snd_jack_types {
|
||||
|
||||
struct snd_jack {
|
||||
struct input_dev *input_dev;
|
||||
struct list_head kctl_list;
|
||||
struct snd_card *card;
|
||||
int registered;
|
||||
int type;
|
||||
const char *id;
|
||||
@ -85,7 +87,8 @@ struct snd_jack {
|
||||
#ifdef CONFIG_SND_JACK
|
||||
|
||||
int snd_jack_new(struct snd_card *card, const char *id, int type,
|
||||
struct snd_jack **jack);
|
||||
struct snd_jack **jack, bool initial_kctl, bool phantom_jack);
|
||||
int snd_jack_add_new_kctl(struct snd_jack *jack, const char * name, int mask);
|
||||
void snd_jack_set_parent(struct snd_jack *jack, struct device *parent);
|
||||
int snd_jack_set_key(struct snd_jack *jack, enum snd_jack_types type,
|
||||
int keytype);
|
||||
@ -93,9 +96,13 @@ int snd_jack_set_key(struct snd_jack *jack, enum snd_jack_types type,
|
||||
void snd_jack_report(struct snd_jack *jack, int status);
|
||||
|
||||
#else
|
||||
|
||||
static inline int snd_jack_new(struct snd_card *card, const char *id, int type,
|
||||
struct snd_jack **jack)
|
||||
struct snd_jack **jack, bool initial_kctl, bool phantom_jack)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
static inline int snd_jack_add_new_kctl(struct snd_jack *jack, const char * name, int mask)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
@ -224,9 +224,10 @@ typedef int (*snd_pcm_hw_rule_func_t)(struct snd_pcm_hw_params *params,
|
||||
|
||||
struct snd_pcm_hw_rule {
|
||||
unsigned int cond;
|
||||
snd_pcm_hw_rule_func_t func;
|
||||
int var;
|
||||
int deps[4];
|
||||
|
||||
snd_pcm_hw_rule_func_t func;
|
||||
void *private;
|
||||
};
|
||||
|
||||
@ -273,8 +274,8 @@ struct snd_pcm_hw_constraint_ratdens {
|
||||
};
|
||||
|
||||
struct snd_pcm_hw_constraint_list {
|
||||
unsigned int count;
|
||||
const unsigned int *list;
|
||||
unsigned int count;
|
||||
unsigned int mask;
|
||||
};
|
||||
|
||||
|
6
include/sound/pcm_drm_eld.h
Normal file
6
include/sound/pcm_drm_eld.h
Normal file
@ -0,0 +1,6 @@
|
||||
#ifndef __SOUND_PCM_DRM_ELD_H
|
||||
#define __SOUND_PCM_DRM_ELD_H
|
||||
|
||||
int snd_pcm_hw_constraint_eld(struct snd_pcm_runtime *runtime, void *eld);
|
||||
|
||||
#endif
|
9
include/sound/pcm_iec958.h
Normal file
9
include/sound/pcm_iec958.h
Normal file
@ -0,0 +1,9 @@
|
||||
#ifndef __SOUND_PCM_IEC958_H
|
||||
#define __SOUND_PCM_IEC958_H
|
||||
|
||||
#include <linux/types.h>
|
||||
|
||||
int snd_pcm_create_iec958_consumer(struct snd_pcm_runtime *runtime, u8 *cs,
|
||||
size_t len);
|
||||
|
||||
#endif
|
@ -15,17 +15,11 @@ struct rt5645_platform_data {
|
||||
/* IN2 can optionally be differential */
|
||||
bool in2_diff;
|
||||
|
||||
bool dmic_en;
|
||||
unsigned int dmic1_data_pin;
|
||||
/* 0 = IN2N; 1 = GPIO5; 2 = GPIO11 */
|
||||
unsigned int dmic2_data_pin;
|
||||
/* 0 = IN2P; 1 = GPIO6; 2 = GPIO10; 3 = GPIO12 */
|
||||
|
||||
unsigned int hp_det_gpio;
|
||||
bool gpio_hp_det_active_high;
|
||||
|
||||
/* true if codec's jd function is used */
|
||||
bool en_jd_func;
|
||||
unsigned int jd_mode;
|
||||
};
|
||||
|
||||
|
@ -15,6 +15,8 @@
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <sound/control.h>
|
||||
#include <sound/soc-topology.h>
|
||||
#include <sound/asoc.h>
|
||||
|
||||
struct device;
|
||||
|
||||
@ -107,6 +109,10 @@ struct device;
|
||||
{ .id = snd_soc_dapm_mux, .name = wname, \
|
||||
SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \
|
||||
.kcontrol_news = wcontrols, .num_kcontrols = 1}
|
||||
#define SND_SOC_DAPM_DEMUX(wname, wreg, wshift, winvert, wcontrols) \
|
||||
{ .id = snd_soc_dapm_demux, .name = wname, \
|
||||
SND_SOC_DAPM_INIT_REG_VAL(wreg, wshift, winvert), \
|
||||
.kcontrol_news = wcontrols, .num_kcontrols = 1}
|
||||
|
||||
/* Simplified versions of above macros, assuming wncontrols = ARRAY_SIZE(wcontrols) */
|
||||
#define SOC_PGA_ARRAY(wname, wreg, wshift, winvert,\
|
||||
@ -444,11 +450,15 @@ int snd_soc_dapm_dai_get_connected_widgets(struct snd_soc_dai *dai, int stream,
|
||||
struct snd_soc_dapm_context *snd_soc_dapm_kcontrol_dapm(
|
||||
struct snd_kcontrol *kcontrol);
|
||||
|
||||
int snd_soc_dapm_force_bias_level(struct snd_soc_dapm_context *dapm,
|
||||
enum snd_soc_bias_level level);
|
||||
|
||||
/* dapm widget types */
|
||||
enum snd_soc_dapm_type {
|
||||
snd_soc_dapm_input = 0, /* input pin */
|
||||
snd_soc_dapm_output, /* output pin */
|
||||
snd_soc_dapm_mux, /* selects 1 analog signal from many inputs */
|
||||
snd_soc_dapm_demux, /* connects the input to one of multiple outputs */
|
||||
snd_soc_dapm_mixer, /* mixes several analog signals together */
|
||||
snd_soc_dapm_mixer_named_ctl, /* mixer with named controls */
|
||||
snd_soc_dapm_pga, /* programmable gain/attenuation (volume) */
|
||||
@ -563,6 +573,7 @@ struct snd_soc_dapm_widget {
|
||||
int num_kcontrols;
|
||||
const struct snd_kcontrol_new *kcontrol_news;
|
||||
struct snd_kcontrol **kcontrols;
|
||||
struct snd_soc_dobj dobj;
|
||||
|
||||
/* widget input and outputs */
|
||||
struct list_head sources;
|
||||
@ -585,6 +596,10 @@ struct snd_soc_dapm_update {
|
||||
int val;
|
||||
};
|
||||
|
||||
struct snd_soc_dapm_wcache {
|
||||
struct snd_soc_dapm_widget *widget;
|
||||
};
|
||||
|
||||
/* DAPM context */
|
||||
struct snd_soc_dapm_context {
|
||||
enum snd_soc_bias_level bias_level;
|
||||
@ -606,6 +621,9 @@ struct snd_soc_dapm_context {
|
||||
int (*set_bias_level)(struct snd_soc_dapm_context *dapm,
|
||||
enum snd_soc_bias_level level);
|
||||
|
||||
struct snd_soc_dapm_wcache path_sink_cache;
|
||||
struct snd_soc_dapm_wcache path_source_cache;
|
||||
|
||||
#ifdef CONFIG_DEBUG_FS
|
||||
struct dentry *debugfs_dapm;
|
||||
#endif
|
||||
@ -623,4 +641,35 @@ struct snd_soc_dapm_stats {
|
||||
int neighbour_checks;
|
||||
};
|
||||
|
||||
/**
|
||||
* snd_soc_dapm_init_bias_level() - Initialize DAPM bias level
|
||||
* @dapm: The DAPM context to initialize
|
||||
* @level: The DAPM level to initialize to
|
||||
*
|
||||
* This function only sets the driver internal state of the DAPM level and will
|
||||
* not modify the state of the device. Hence it should not be used during normal
|
||||
* operation, but only to synchronize the internal state to the device state.
|
||||
* E.g. during driver probe to set the DAPM level to the one corresponding with
|
||||
* the power-on reset state of the device.
|
||||
*
|
||||
* To change the DAPM state of the device use snd_soc_dapm_set_bias_level().
|
||||
*/
|
||||
static inline void snd_soc_dapm_init_bias_level(
|
||||
struct snd_soc_dapm_context *dapm, enum snd_soc_bias_level level)
|
||||
{
|
||||
dapm->bias_level = level;
|
||||
}
|
||||
|
||||
/**
|
||||
* snd_soc_dapm_get_bias_level() - Get current DAPM bias level
|
||||
* @dapm: The context for which to get the bias level
|
||||
*
|
||||
* Returns: The current bias level of the passed DAPM context.
|
||||
*/
|
||||
static inline enum snd_soc_bias_level snd_soc_dapm_get_bias_level(
|
||||
struct snd_soc_dapm_context *dapm)
|
||||
{
|
||||
return dapm->bias_level;
|
||||
}
|
||||
|
||||
#endif
|
||||
|
168
include/sound/soc-topology.h
Normal file
168
include/sound/soc-topology.h
Normal file
@ -0,0 +1,168 @@
|
||||
/*
|
||||
* linux/sound/soc-topology.h -- ALSA SoC Firmware Controls and DAPM
|
||||
*
|
||||
* Copyright (C) 2012 Texas Instruments Inc.
|
||||
* Copyright (C) 2015 Intel Corporation.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* Simple file API to load FW that includes mixers, coefficients, DAPM graphs,
|
||||
* algorithms, equalisers, DAIs, widgets, FE caps, BE caps, codec link caps etc.
|
||||
*/
|
||||
|
||||
#ifndef __LINUX_SND_SOC_TPLG_H
|
||||
#define __LINUX_SND_SOC_TPLG_H
|
||||
|
||||
#include <sound/asoc.h>
|
||||
#include <linux/list.h>
|
||||
|
||||
struct firmware;
|
||||
struct snd_kcontrol;
|
||||
struct snd_soc_tplg_pcm_be;
|
||||
struct snd_ctl_elem_value;
|
||||
struct snd_ctl_elem_info;
|
||||
struct snd_soc_dapm_widget;
|
||||
struct snd_soc_component;
|
||||
struct snd_soc_tplg_pcm_fe;
|
||||
struct snd_soc_dapm_context;
|
||||
struct snd_soc_card;
|
||||
|
||||
/* object scan be loaded and unloaded in groups with identfying indexes */
|
||||
#define SND_SOC_TPLG_INDEX_ALL 0 /* ID that matches all FW objects */
|
||||
|
||||
/* dynamic object type */
|
||||
enum snd_soc_dobj_type {
|
||||
SND_SOC_DOBJ_NONE = 0, /* object is not dynamic */
|
||||
SND_SOC_DOBJ_MIXER,
|
||||
SND_SOC_DOBJ_ENUM,
|
||||
SND_SOC_DOBJ_BYTES,
|
||||
SND_SOC_DOBJ_PCM,
|
||||
SND_SOC_DOBJ_DAI_LINK,
|
||||
SND_SOC_DOBJ_CODEC_LINK,
|
||||
SND_SOC_DOBJ_WIDGET,
|
||||
};
|
||||
|
||||
/* dynamic control object */
|
||||
struct snd_soc_dobj_control {
|
||||
struct snd_kcontrol *kcontrol;
|
||||
char **dtexts;
|
||||
unsigned long *dvalues;
|
||||
};
|
||||
|
||||
/* dynamic widget object */
|
||||
struct snd_soc_dobj_widget {
|
||||
unsigned int kcontrol_enum:1; /* this widget is an enum kcontrol */
|
||||
};
|
||||
|
||||
/* dynamic PCM DAI object */
|
||||
struct snd_soc_dobj_pcm_dai {
|
||||
struct snd_soc_tplg_pcm_dai *pd;
|
||||
unsigned int count;
|
||||
};
|
||||
|
||||
/* generic dynamic object - all dynamic objects belong to this struct */
|
||||
struct snd_soc_dobj {
|
||||
enum snd_soc_dobj_type type;
|
||||
unsigned int index; /* objects can belong in different groups */
|
||||
struct list_head list;
|
||||
struct snd_soc_tplg_ops *ops;
|
||||
union {
|
||||
struct snd_soc_dobj_control control;
|
||||
struct snd_soc_dobj_widget widget;
|
||||
struct snd_soc_dobj_pcm_dai pcm_dai;
|
||||
};
|
||||
void *private; /* core does not touch this */
|
||||
};
|
||||
|
||||
/*
|
||||
* Kcontrol operations - used to map handlers onto firmware based controls.
|
||||
*/
|
||||
struct snd_soc_tplg_kcontrol_ops {
|
||||
u32 id;
|
||||
int (*get)(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_value *ucontrol);
|
||||
int (*put)(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_value *ucontrol);
|
||||
int (*info)(struct snd_kcontrol *kcontrol,
|
||||
struct snd_ctl_elem_info *uinfo);
|
||||
};
|
||||
|
||||
/*
|
||||
* DAPM widget event handlers - used to map handlers onto widgets.
|
||||
*/
|
||||
struct snd_soc_tplg_widget_events {
|
||||
u16 type;
|
||||
int (*event_handler)(struct snd_soc_dapm_widget *w,
|
||||
struct snd_kcontrol *k, int event);
|
||||
};
|
||||
|
||||
/*
|
||||
* Public API - Used by component drivers to load and unload dynamic objects
|
||||
* and their resources.
|
||||
*/
|
||||
struct snd_soc_tplg_ops {
|
||||
|
||||
/* external kcontrol init - used for any driver specific init */
|
||||
int (*control_load)(struct snd_soc_component *,
|
||||
struct snd_kcontrol_new *, struct snd_soc_tplg_ctl_hdr *);
|
||||
int (*control_unload)(struct snd_soc_component *,
|
||||
struct snd_soc_dobj *);
|
||||
|
||||
/* external widget init - used for any driver specific init */
|
||||
int (*widget_load)(struct snd_soc_component *,
|
||||
struct snd_soc_dapm_widget *,
|
||||
struct snd_soc_tplg_dapm_widget *);
|
||||
int (*widget_unload)(struct snd_soc_component *,
|
||||
struct snd_soc_dobj *);
|
||||
|
||||
/* FE - used for any driver specific init */
|
||||
int (*pcm_dai_load)(struct snd_soc_component *,
|
||||
struct snd_soc_tplg_pcm_dai *pcm_dai, int num_fe);
|
||||
int (*pcm_dai_unload)(struct snd_soc_component *,
|
||||
struct snd_soc_dobj *);
|
||||
|
||||
/* callback to handle vendor bespoke data */
|
||||
int (*vendor_load)(struct snd_soc_component *,
|
||||
struct snd_soc_tplg_hdr *);
|
||||
int (*vendor_unload)(struct snd_soc_component *,
|
||||
struct snd_soc_tplg_hdr *);
|
||||
|
||||
/* completion - called at completion of firmware loading */
|
||||
void (*complete)(struct snd_soc_component *);
|
||||
|
||||
/* manifest - optional to inform component of manifest */
|
||||
int (*manifest)(struct snd_soc_component *,
|
||||
struct snd_soc_tplg_manifest *);
|
||||
|
||||
/* bespoke kcontrol handlers available for binding */
|
||||
const struct snd_soc_tplg_kcontrol_ops *io_ops;
|
||||
int io_ops_count;
|
||||
};
|
||||
|
||||
/* gets a pointer to data from the firmware block header */
|
||||
static inline const void *snd_soc_tplg_get_data(struct snd_soc_tplg_hdr *hdr)
|
||||
{
|
||||
const void *ptr = hdr;
|
||||
|
||||
return ptr + sizeof(*hdr);
|
||||
}
|
||||
|
||||
/* Dynamic Object loading and removal for component drivers */
|
||||
int snd_soc_tplg_component_load(struct snd_soc_component *comp,
|
||||
struct snd_soc_tplg_ops *ops, const struct firmware *fw,
|
||||
u32 index);
|
||||
int snd_soc_tplg_component_remove(struct snd_soc_component *comp, u32 index);
|
||||
|
||||
/* Widget removal - widgets also removed wth component API */
|
||||
void snd_soc_tplg_widget_remove(struct snd_soc_dapm_widget *w);
|
||||
void snd_soc_tplg_widget_remove_all(struct snd_soc_dapm_context *dapm,
|
||||
u32 index);
|
||||
|
||||
/* Binds event handlers to dynamic widgets */
|
||||
int snd_soc_tplg_widget_bind_event(struct snd_soc_dapm_widget *w,
|
||||
const struct snd_soc_tplg_widget_events *events, int num_events,
|
||||
u16 event_type);
|
||||
|
||||
#endif
|
@ -27,6 +27,7 @@
|
||||
#include <sound/compress_driver.h>
|
||||
#include <sound/control.h>
|
||||
#include <sound/ac97_codec.h>
|
||||
#include <sound/soc-topology.h>
|
||||
|
||||
/*
|
||||
* Convenience kcontrol builders
|
||||
@ -190,8 +191,12 @@
|
||||
#define SOC_VALUE_ENUM_DOUBLE(xreg, xshift_l, xshift_r, xmask, xitems, xtexts, xvalues) \
|
||||
{ .reg = xreg, .shift_l = xshift_l, .shift_r = xshift_r, \
|
||||
.mask = xmask, .items = xitems, .texts = xtexts, .values = xvalues}
|
||||
#define SOC_VALUE_ENUM_SINGLE(xreg, xshift, xmask, xnitmes, xtexts, xvalues) \
|
||||
SOC_VALUE_ENUM_DOUBLE(xreg, xshift, xshift, xmask, xnitmes, xtexts, xvalues)
|
||||
#define SOC_VALUE_ENUM_SINGLE(xreg, xshift, xmask, xitems, xtexts, xvalues) \
|
||||
SOC_VALUE_ENUM_DOUBLE(xreg, xshift, xshift, xmask, xitems, xtexts, xvalues)
|
||||
#define SOC_VALUE_ENUM_SINGLE_AUTODISABLE(xreg, xshift, xmask, xitems, xtexts, xvalues) \
|
||||
{ .reg = xreg, .shift_l = xshift, .shift_r = xshift, \
|
||||
.mask = xmask, .items = xitems, .texts = xtexts, \
|
||||
.values = xvalues, .autodisable = 1}
|
||||
#define SOC_ENUM_SINGLE_VIRT(xitems, xtexts) \
|
||||
SOC_ENUM_SINGLE(SND_SOC_NOPM, 0, xitems, xtexts)
|
||||
#define SOC_ENUM(xname, xenum) \
|
||||
@ -312,6 +317,11 @@
|
||||
ARRAY_SIZE(xtexts), xtexts, xvalues)
|
||||
#define SOC_VALUE_ENUM_SINGLE_DECL(name, xreg, xshift, xmask, xtexts, xvalues) \
|
||||
SOC_VALUE_ENUM_DOUBLE_DECL(name, xreg, xshift, xshift, xmask, xtexts, xvalues)
|
||||
|
||||
#define SOC_VALUE_ENUM_SINGLE_AUTODISABLE_DECL(name, xreg, xshift, xmask, xtexts, xvalues) \
|
||||
const struct soc_enum name = SOC_VALUE_ENUM_SINGLE_AUTODISABLE(xreg, \
|
||||
xshift, xmask, ARRAY_SIZE(xtexts), xtexts, xvalues)
|
||||
|
||||
#define SOC_ENUM_SINGLE_VIRT_DECL(name, xtexts) \
|
||||
const struct soc_enum name = SOC_ENUM_SINGLE_VIRT(ARRAY_SIZE(xtexts), xtexts)
|
||||
|
||||
@ -767,6 +777,9 @@ struct snd_soc_component {
|
||||
|
||||
struct mutex io_mutex;
|
||||
|
||||
/* attached dynamic objects */
|
||||
struct list_head dobj_list;
|
||||
|
||||
#ifdef CONFIG_DEBUG_FS
|
||||
struct dentry *debugfs_root;
|
||||
#endif
|
||||
@ -819,7 +832,7 @@ struct snd_soc_codec {
|
||||
/* component */
|
||||
struct snd_soc_component component;
|
||||
|
||||
/* dapm */
|
||||
/* Don't access this directly, use snd_soc_codec_get_dapm() */
|
||||
struct snd_soc_dapm_context dapm;
|
||||
|
||||
#ifdef CONFIG_DEBUG_FS
|
||||
@ -961,30 +974,6 @@ struct snd_soc_dai_link {
|
||||
|
||||
enum snd_soc_dpcm_trigger trigger[2]; /* trigger type for DPCM */
|
||||
|
||||
/* Keep DAI active over suspend */
|
||||
unsigned int ignore_suspend:1;
|
||||
|
||||
/* Symmetry requirements */
|
||||
unsigned int symmetric_rates:1;
|
||||
unsigned int symmetric_channels:1;
|
||||
unsigned int symmetric_samplebits:1;
|
||||
|
||||
/* Mark this pcm with non atomic ops */
|
||||
bool nonatomic;
|
||||
|
||||
/* Do not create a PCM for this DAI link (Backend link) */
|
||||
unsigned int no_pcm:1;
|
||||
|
||||
/* This DAI link can route to other DAI links at runtime (Frontend)*/
|
||||
unsigned int dynamic:1;
|
||||
|
||||
/* DPCM capture and Playback support */
|
||||
unsigned int dpcm_capture:1;
|
||||
unsigned int dpcm_playback:1;
|
||||
|
||||
/* pmdown_time is ignored at stop */
|
||||
unsigned int ignore_pmdown_time:1;
|
||||
|
||||
/* codec/machine specific init - e.g. add machine controls */
|
||||
int (*init)(struct snd_soc_pcm_runtime *rtd);
|
||||
|
||||
@ -999,6 +988,33 @@ struct snd_soc_dai_link {
|
||||
/* For unidirectional dai links */
|
||||
bool playback_only;
|
||||
bool capture_only;
|
||||
|
||||
/* Mark this pcm with non atomic ops */
|
||||
bool nonatomic;
|
||||
|
||||
/* Keep DAI active over suspend */
|
||||
unsigned int ignore_suspend:1;
|
||||
|
||||
/* Symmetry requirements */
|
||||
unsigned int symmetric_rates:1;
|
||||
unsigned int symmetric_channels:1;
|
||||
unsigned int symmetric_samplebits:1;
|
||||
|
||||
/* Do not create a PCM for this DAI link (Backend link) */
|
||||
unsigned int no_pcm:1;
|
||||
|
||||
/* This DAI link can route to other DAI links at runtime (Frontend)*/
|
||||
unsigned int dynamic:1;
|
||||
|
||||
/* DPCM capture and Playback support */
|
||||
unsigned int dpcm_capture:1;
|
||||
unsigned int dpcm_playback:1;
|
||||
|
||||
/* DPCM used FE & BE merged format */
|
||||
unsigned int dpcm_merged_format:1;
|
||||
|
||||
/* pmdown_time is ignored at stop */
|
||||
unsigned int ignore_pmdown_time:1;
|
||||
};
|
||||
|
||||
struct snd_soc_codec_conf {
|
||||
@ -1111,6 +1127,9 @@ struct snd_soc_card {
|
||||
struct list_head dapm_list;
|
||||
struct list_head dapm_dirty;
|
||||
|
||||
/* attached dynamic objects */
|
||||
struct list_head dobj_list;
|
||||
|
||||
/* Generic DAPM context for the card */
|
||||
struct snd_soc_dapm_context dapm;
|
||||
struct snd_soc_dapm_stats dapm_stats;
|
||||
@ -1170,6 +1189,7 @@ struct soc_mixer_control {
|
||||
unsigned int sign_bit;
|
||||
unsigned int invert:1;
|
||||
unsigned int autodisable:1;
|
||||
struct snd_soc_dobj dobj;
|
||||
};
|
||||
|
||||
struct soc_bytes {
|
||||
@ -1180,6 +1200,8 @@ struct soc_bytes {
|
||||
|
||||
struct soc_bytes_ext {
|
||||
int max;
|
||||
struct snd_soc_dobj dobj;
|
||||
|
||||
/* used for TLV byte control */
|
||||
int (*get)(unsigned int __user *bytes, unsigned int size);
|
||||
int (*put)(const unsigned int __user *bytes, unsigned int size);
|
||||
@ -1200,6 +1222,8 @@ struct soc_enum {
|
||||
unsigned int mask;
|
||||
const char * const *texts;
|
||||
const unsigned int *values;
|
||||
unsigned int autodisable:1;
|
||||
struct snd_soc_dobj dobj;
|
||||
};
|
||||
|
||||
/**
|
||||
@ -1281,6 +1305,58 @@ static inline struct snd_soc_dapm_context *snd_soc_component_get_dapm(
|
||||
return component->dapm_ptr;
|
||||
}
|
||||
|
||||
/**
|
||||
* snd_soc_codec_get_dapm() - Returns the DAPM context for the CODEC
|
||||
* @codec: The CODEC for which to get the DAPM context
|
||||
*
|
||||
* Note: Use this function instead of directly accessing the CODEC's dapm field
|
||||
*/
|
||||
static inline struct snd_soc_dapm_context *snd_soc_codec_get_dapm(
|
||||
struct snd_soc_codec *codec)
|
||||
{
|
||||
return &codec->dapm;
|
||||
}
|
||||
|
||||
/**
|
||||
* snd_soc_dapm_init_bias_level() - Initialize CODEC DAPM bias level
|
||||
* @dapm: The CODEC for which to initialize the DAPM bias level
|
||||
* @level: The DAPM level to initialize to
|
||||
*
|
||||
* Initializes the CODEC DAPM bias level. See snd_soc_dapm_init_bias_level().
|
||||
*/
|
||||
static inline void snd_soc_codec_init_bias_level(struct snd_soc_codec *codec,
|
||||
enum snd_soc_bias_level level)
|
||||
{
|
||||
snd_soc_dapm_init_bias_level(snd_soc_codec_get_dapm(codec), level);
|
||||
}
|
||||
|
||||
/**
|
||||
* snd_soc_dapm_get_bias_level() - Get current CODEC DAPM bias level
|
||||
* @codec: The CODEC for which to get the DAPM bias level
|
||||
*
|
||||
* Returns: The current DAPM bias level of the CODEC.
|
||||
*/
|
||||
static inline enum snd_soc_bias_level snd_soc_codec_get_bias_level(
|
||||
struct snd_soc_codec *codec)
|
||||
{
|
||||
return snd_soc_dapm_get_bias_level(snd_soc_codec_get_dapm(codec));
|
||||
}
|
||||
|
||||
/**
|
||||
* snd_soc_codec_force_bias_level() - Set the CODEC DAPM bias level
|
||||
* @codec: The CODEC for which to set the level
|
||||
* @level: The level to set to
|
||||
*
|
||||
* Forces the CODEC bias level to a specific state. See
|
||||
* snd_soc_dapm_force_bias_level().
|
||||
*/
|
||||
static inline int snd_soc_codec_force_bias_level(struct snd_soc_codec *codec,
|
||||
enum snd_soc_bias_level level)
|
||||
{
|
||||
return snd_soc_dapm_force_bias_level(snd_soc_codec_get_dapm(codec),
|
||||
level);
|
||||
}
|
||||
|
||||
/**
|
||||
* snd_soc_dapm_kcontrol_codec() - Returns the codec associated to a kcontrol
|
||||
* @kcontrol: The kcontrol
|
||||
|
@ -31,12 +31,7 @@
|
||||
* ~(sizeof(unsigned int) - 1)) ....
|
||||
*/
|
||||
|
||||
#define SNDRV_CTL_TLVT_CONTAINER 0 /* one level down - group of TLVs */
|
||||
#define SNDRV_CTL_TLVT_DB_SCALE 1 /* dB scale */
|
||||
#define SNDRV_CTL_TLVT_DB_LINEAR 2 /* linear volume */
|
||||
#define SNDRV_CTL_TLVT_DB_RANGE 3 /* dB range container */
|
||||
#define SNDRV_CTL_TLVT_DB_MINMAX 4 /* dB scale with min/max */
|
||||
#define SNDRV_CTL_TLVT_DB_MINMAX_MUTE 5 /* dB scale with min/max with mute */
|
||||
#include <uapi/sound/tlv.h>
|
||||
|
||||
#define TLV_ITEM(type, ...) \
|
||||
(type), TLV_LENGTH(__VA_ARGS__), __VA_ARGS__
|
||||
@ -90,12 +85,4 @@
|
||||
|
||||
#define TLV_DB_GAIN_MUTE -9999999
|
||||
|
||||
/*
|
||||
* channel-mapping TLV items
|
||||
* TLV length must match with num_channels
|
||||
*/
|
||||
#define SNDRV_CTL_TLVT_CHMAP_FIXED 0x101 /* fixed channel position */
|
||||
#define SNDRV_CTL_TLVT_CHMAP_VAR 0x102 /* channels freely swappable */
|
||||
#define SNDRV_CTL_TLVT_CHMAP_PAIRED 0x103 /* pair-wise swappable */
|
||||
|
||||
#endif /* __SOUND_TLV_H */
|
||||
|
388
include/uapi/sound/asoc.h
Normal file
388
include/uapi/sound/asoc.h
Normal file
@ -0,0 +1,388 @@
|
||||
/*
|
||||
* uapi/sound/asoc.h -- ALSA SoC Firmware Controls and DAPM
|
||||
*
|
||||
* Copyright (C) 2012 Texas Instruments Inc.
|
||||
* Copyright (C) 2015 Intel Corporation.
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*
|
||||
* Simple file API to load FW that includes mixers, coefficients, DAPM graphs,
|
||||
* algorithms, equalisers, DAIs, widgets etc.
|
||||
*/
|
||||
|
||||
#ifndef __LINUX_UAPI_SND_ASOC_H
|
||||
#define __LINUX_UAPI_SND_ASOC_H
|
||||
|
||||
#include <linux/types.h>
|
||||
#include <sound/asound.h>
|
||||
|
||||
/*
|
||||
* Maximum number of channels topology kcontrol can represent.
|
||||
*/
|
||||
#define SND_SOC_TPLG_MAX_CHAN 8
|
||||
|
||||
/*
|
||||
* Maximum number of PCM formats capability
|
||||
*/
|
||||
#define SND_SOC_TPLG_MAX_FORMATS 16
|
||||
|
||||
/*
|
||||
* Maximum number of PCM stream configs
|
||||
*/
|
||||
#define SND_SOC_TPLG_STREAM_CONFIG_MAX 8
|
||||
|
||||
/* individual kcontrol info types - can be mixed with other types */
|
||||
#define SND_SOC_TPLG_CTL_VOLSW 1
|
||||
#define SND_SOC_TPLG_CTL_VOLSW_SX 2
|
||||
#define SND_SOC_TPLG_CTL_VOLSW_XR_SX 3
|
||||
#define SND_SOC_TPLG_CTL_ENUM 4
|
||||
#define SND_SOC_TPLG_CTL_BYTES 5
|
||||
#define SND_SOC_TPLG_CTL_ENUM_VALUE 6
|
||||
#define SND_SOC_TPLG_CTL_RANGE 7
|
||||
#define SND_SOC_TPLG_CTL_STROBE 8
|
||||
|
||||
|
||||
/* individual widget kcontrol info types - can be mixed with other types */
|
||||
#define SND_SOC_TPLG_DAPM_CTL_VOLSW 64
|
||||
#define SND_SOC_TPLG_DAPM_CTL_ENUM_DOUBLE 65
|
||||
#define SND_SOC_TPLG_DAPM_CTL_ENUM_VIRT 66
|
||||
#define SND_SOC_TPLG_DAPM_CTL_ENUM_VALUE 67
|
||||
#define SND_SOC_TPLG_DAPM_CTL_PIN 68
|
||||
|
||||
/* DAPM widget types - add new items to the end */
|
||||
#define SND_SOC_TPLG_DAPM_INPUT 0
|
||||
#define SND_SOC_TPLG_DAPM_OUTPUT 1
|
||||
#define SND_SOC_TPLG_DAPM_MUX 2
|
||||
#define SND_SOC_TPLG_DAPM_MIXER 3
|
||||
#define SND_SOC_TPLG_DAPM_PGA 4
|
||||
#define SND_SOC_TPLG_DAPM_OUT_DRV 5
|
||||
#define SND_SOC_TPLG_DAPM_ADC 6
|
||||
#define SND_SOC_TPLG_DAPM_DAC 7
|
||||
#define SND_SOC_TPLG_DAPM_SWITCH 8
|
||||
#define SND_SOC_TPLG_DAPM_PRE 9
|
||||
#define SND_SOC_TPLG_DAPM_POST 10
|
||||
#define SND_SOC_TPLG_DAPM_AIF_IN 11
|
||||
#define SND_SOC_TPLG_DAPM_AIF_OUT 12
|
||||
#define SND_SOC_TPLG_DAPM_DAI_IN 13
|
||||
#define SND_SOC_TPLG_DAPM_DAI_OUT 14
|
||||
#define SND_SOC_TPLG_DAPM_DAI_LINK 15
|
||||
#define SND_SOC_TPLG_DAPM_LAST SND_SOC_TPLG_DAPM_DAI_LINK
|
||||
|
||||
/* Header magic number and string sizes */
|
||||
#define SND_SOC_TPLG_MAGIC 0x41536F43 /* ASoC */
|
||||
|
||||
/* string sizes */
|
||||
#define SND_SOC_TPLG_NUM_TEXTS 16
|
||||
|
||||
/* ABI version */
|
||||
#define SND_SOC_TPLG_ABI_VERSION 0x2
|
||||
|
||||
/* Max size of TLV data */
|
||||
#define SND_SOC_TPLG_TLV_SIZE 32
|
||||
|
||||
/*
|
||||
* File and Block header data types.
|
||||
* Add new generic and vendor types to end of list.
|
||||
* Generic types are handled by the core whilst vendors types are passed
|
||||
* to the component drivers for handling.
|
||||
*/
|
||||
#define SND_SOC_TPLG_TYPE_MIXER 1
|
||||
#define SND_SOC_TPLG_TYPE_BYTES 2
|
||||
#define SND_SOC_TPLG_TYPE_ENUM 3
|
||||
#define SND_SOC_TPLG_TYPE_DAPM_GRAPH 4
|
||||
#define SND_SOC_TPLG_TYPE_DAPM_WIDGET 5
|
||||
#define SND_SOC_TPLG_TYPE_DAI_LINK 6
|
||||
#define SND_SOC_TPLG_TYPE_PCM 7
|
||||
#define SND_SOC_TPLG_TYPE_MANIFEST 8
|
||||
#define SND_SOC_TPLG_TYPE_CODEC_LINK 9
|
||||
#define SND_SOC_TPLG_TYPE_MAX SND_SOC_TPLG_TYPE_CODEC_LINK
|
||||
|
||||
/* vendor block IDs - please add new vendor types to end */
|
||||
#define SND_SOC_TPLG_TYPE_VENDOR_FW 1000
|
||||
#define SND_SOC_TPLG_TYPE_VENDOR_CONFIG 1001
|
||||
#define SND_SOC_TPLG_TYPE_VENDOR_COEFF 1002
|
||||
#define SND_SOC_TPLG_TYPEVENDOR_CODEC 1003
|
||||
|
||||
#define SND_SOC_TPLG_STREAM_PLAYBACK 0
|
||||
#define SND_SOC_TPLG_STREAM_CAPTURE 1
|
||||
|
||||
/*
|
||||
* Block Header.
|
||||
* This header preceeds all object and object arrays below.
|
||||
*/
|
||||
struct snd_soc_tplg_hdr {
|
||||
__le32 magic; /* magic number */
|
||||
__le32 abi; /* ABI version */
|
||||
__le32 version; /* optional vendor specific version details */
|
||||
__le32 type; /* SND_SOC_TPLG_TYPE_ */
|
||||
__le32 size; /* size of this structure */
|
||||
__le32 vendor_type; /* optional vendor specific type info */
|
||||
__le32 payload_size; /* data bytes, excluding this header */
|
||||
__le32 index; /* identifier for block */
|
||||
__le32 count; /* number of elements in block */
|
||||
} __attribute__((packed));
|
||||
|
||||
/*
|
||||
* Private data.
|
||||
* All topology objects may have private data that can be used by the driver or
|
||||
* firmware. Core will ignore this data.
|
||||
*/
|
||||
struct snd_soc_tplg_private {
|
||||
__le32 size; /* in bytes of private data */
|
||||
char data[0];
|
||||
} __attribute__((packed));
|
||||
|
||||
/*
|
||||
* Kcontrol TLV data.
|
||||
*/
|
||||
struct snd_soc_tplg_ctl_tlv {
|
||||
__le32 size; /* in bytes aligned to 4 */
|
||||
__le32 numid; /* control element numeric identification */
|
||||
__le32 count; /* number of elem in data array */
|
||||
__le32 data[SND_SOC_TPLG_TLV_SIZE];
|
||||
} __attribute__((packed));
|
||||
|
||||
/*
|
||||
* Kcontrol channel data
|
||||
*/
|
||||
struct snd_soc_tplg_channel {
|
||||
__le32 size; /* in bytes of this structure */
|
||||
__le32 reg;
|
||||
__le32 shift;
|
||||
__le32 id; /* ID maps to Left, Right, LFE etc */
|
||||
} __attribute__((packed));
|
||||
|
||||
/*
|
||||
* Kcontrol Operations IDs
|
||||
*/
|
||||
struct snd_soc_tplg_kcontrol_ops_id {
|
||||
__le32 get;
|
||||
__le32 put;
|
||||
__le32 info;
|
||||
} __attribute__((packed));
|
||||
|
||||
/*
|
||||
* kcontrol header
|
||||
*/
|
||||
struct snd_soc_tplg_ctl_hdr {
|
||||
__le32 size; /* in bytes of this structure */
|
||||
__le32 type;
|
||||
char name[SNDRV_CTL_ELEM_ID_NAME_MAXLEN];
|
||||
__le32 access;
|
||||
struct snd_soc_tplg_kcontrol_ops_id ops;
|
||||
__le32 tlv_size; /* non zero means control has TLV data */
|
||||
} __attribute__((packed));
|
||||
|
||||
/*
|
||||
* Stream Capabilities
|
||||
*/
|
||||
struct snd_soc_tplg_stream_caps {
|
||||
__le32 size; /* in bytes of this structure */
|
||||
char name[SNDRV_CTL_ELEM_ID_NAME_MAXLEN];
|
||||
__le64 formats[SND_SOC_TPLG_MAX_FORMATS]; /* supported formats SNDRV_PCM_FMTBIT_* */
|
||||
__le32 rates; /* supported rates SNDRV_PCM_RATE_* */
|
||||
__le32 rate_min; /* min rate */
|
||||
__le32 rate_max; /* max rate */
|
||||
__le32 channels_min; /* min channels */
|
||||
__le32 channels_max; /* max channels */
|
||||
__le32 periods_min; /* min number of periods */
|
||||
__le32 periods_max; /* max number of periods */
|
||||
__le32 period_size_min; /* min period size bytes */
|
||||
__le32 period_size_max; /* max period size bytes */
|
||||
__le32 buffer_size_min; /* min buffer size bytes */
|
||||
__le32 buffer_size_max; /* max buffer size bytes */
|
||||
} __attribute__((packed));
|
||||
|
||||
/*
|
||||
* FE or BE Stream configuration supported by SW/FW
|
||||
*/
|
||||
struct snd_soc_tplg_stream {
|
||||
__le32 size; /* in bytes of this structure */
|
||||
__le64 format; /* SNDRV_PCM_FMTBIT_* */
|
||||
__le32 rate; /* SNDRV_PCM_RATE_* */
|
||||
__le32 period_bytes; /* size of period in bytes */
|
||||
__le32 buffer_bytes; /* size of buffer in bytes */
|
||||
__le32 channels; /* channels */
|
||||
__le32 tdm_slot; /* optional BE bitmask of supported TDM slots */
|
||||
__le32 dai_fmt; /* SND_SOC_DAIFMT_ */
|
||||
} __attribute__((packed));
|
||||
|
||||
/*
|
||||
* Duplex stream configuration supported by SW/FW.
|
||||
*/
|
||||
struct snd_soc_tplg_stream_config {
|
||||
__le32 size; /* in bytes of this structure */
|
||||
char name[SNDRV_CTL_ELEM_ID_NAME_MAXLEN];
|
||||
struct snd_soc_tplg_stream playback;
|
||||
struct snd_soc_tplg_stream capture;
|
||||
} __attribute__((packed));
|
||||
|
||||
/*
|
||||
* Manifest. List totals for each payload type. Not used in parsing, but will
|
||||
* be passed to the component driver before any other objects in order for any
|
||||
* global componnent resource allocations.
|
||||
*
|
||||
* File block representation for manifest :-
|
||||
* +-----------------------------------+----+
|
||||
* | struct snd_soc_tplg_hdr | 1 |
|
||||
* +-----------------------------------+----+
|
||||
* | struct snd_soc_tplg_manifest | 1 |
|
||||
* +-----------------------------------+----+
|
||||
*/
|
||||
struct snd_soc_tplg_manifest {
|
||||
__le32 size; /* in bytes of this structure */
|
||||
__le32 control_elems; /* number of control elements */
|
||||
__le32 widget_elems; /* number of widget elements */
|
||||
__le32 graph_elems; /* number of graph elements */
|
||||
__le32 dai_elems; /* number of DAI elements */
|
||||
__le32 dai_link_elems; /* number of DAI link elements */
|
||||
} __attribute__((packed));
|
||||
|
||||
/*
|
||||
* Mixer kcontrol.
|
||||
*
|
||||
* File block representation for mixer kcontrol :-
|
||||
* +-----------------------------------+----+
|
||||
* | struct snd_soc_tplg_hdr | 1 |
|
||||
* +-----------------------------------+----+
|
||||
* | struct snd_soc_tplg_mixer_control | N |
|
||||
* +-----------------------------------+----+
|
||||
*/
|
||||
struct snd_soc_tplg_mixer_control {
|
||||
struct snd_soc_tplg_ctl_hdr hdr;
|
||||
__le32 size; /* in bytes of this structure */
|
||||
__le32 min;
|
||||
__le32 max;
|
||||
__le32 platform_max;
|
||||
__le32 invert;
|
||||
__le32 num_channels;
|
||||
struct snd_soc_tplg_channel channel[SND_SOC_TPLG_MAX_CHAN];
|
||||
struct snd_soc_tplg_ctl_tlv tlv;
|
||||
struct snd_soc_tplg_private priv;
|
||||
} __attribute__((packed));
|
||||
|
||||
/*
|
||||
* Enumerated kcontrol
|
||||
*
|
||||
* File block representation for enum kcontrol :-
|
||||
* +-----------------------------------+----+
|
||||
* | struct snd_soc_tplg_hdr | 1 |
|
||||
* +-----------------------------------+----+
|
||||
* | struct snd_soc_tplg_enum_control | N |
|
||||
* +-----------------------------------+----+
|
||||
*/
|
||||
struct snd_soc_tplg_enum_control {
|
||||
struct snd_soc_tplg_ctl_hdr hdr;
|
||||
__le32 size; /* in bytes of this structure */
|
||||
__le32 num_channels;
|
||||
struct snd_soc_tplg_channel channel[SND_SOC_TPLG_MAX_CHAN];
|
||||
__le32 items;
|
||||
__le32 mask;
|
||||
__le32 count;
|
||||
char texts[SND_SOC_TPLG_NUM_TEXTS][SNDRV_CTL_ELEM_ID_NAME_MAXLEN];
|
||||
__le32 values[SND_SOC_TPLG_NUM_TEXTS * SNDRV_CTL_ELEM_ID_NAME_MAXLEN / 4];
|
||||
struct snd_soc_tplg_private priv;
|
||||
} __attribute__((packed));
|
||||
|
||||
/*
|
||||
* Bytes kcontrol
|
||||
*
|
||||
* File block representation for bytes kcontrol :-
|
||||
* +-----------------------------------+----+
|
||||
* | struct snd_soc_tplg_hdr | 1 |
|
||||
* +-----------------------------------+----+
|
||||
* | struct snd_soc_tplg_bytes_control | N |
|
||||
* +-----------------------------------+----+
|
||||
*/
|
||||
struct snd_soc_tplg_bytes_control {
|
||||
struct snd_soc_tplg_ctl_hdr hdr;
|
||||
__le32 size; /* in bytes of this structure */
|
||||
__le32 max;
|
||||
__le32 mask;
|
||||
__le32 base;
|
||||
__le32 num_regs;
|
||||
struct snd_soc_tplg_private priv;
|
||||
} __attribute__((packed));
|
||||
|
||||
/*
|
||||
* DAPM Graph Element
|
||||
*
|
||||
* File block representation for DAPM graph elements :-
|
||||
* +-------------------------------------+----+
|
||||
* | struct snd_soc_tplg_hdr | 1 |
|
||||
* +-------------------------------------+----+
|
||||
* | struct snd_soc_tplg_dapm_graph_elem | N |
|
||||
* +-------------------------------------+----+
|
||||
*/
|
||||
struct snd_soc_tplg_dapm_graph_elem {
|
||||
char sink[SNDRV_CTL_ELEM_ID_NAME_MAXLEN];
|
||||
char control[SNDRV_CTL_ELEM_ID_NAME_MAXLEN];
|
||||
char source[SNDRV_CTL_ELEM_ID_NAME_MAXLEN];
|
||||
} __attribute__((packed));
|
||||
|
||||
/*
|
||||
* DAPM Widget.
|
||||
*
|
||||
* File block representation for DAPM widget :-
|
||||
* +-------------------------------------+-----+
|
||||
* | struct snd_soc_tplg_hdr | 1 |
|
||||
* +-------------------------------------+-----+
|
||||
* | struct snd_soc_tplg_dapm_widget | N |
|
||||
* +-------------------------------------+-----+
|
||||
* | struct snd_soc_tplg_enum_control | 0|1 |
|
||||
* | struct snd_soc_tplg_mixer_control | 0|N |
|
||||
* +-------------------------------------+-----+
|
||||
*
|
||||
* Optional enum or mixer control can be appended to the end of each widget
|
||||
* in the block.
|
||||
*/
|
||||
struct snd_soc_tplg_dapm_widget {
|
||||
__le32 size; /* in bytes of this structure */
|
||||
__le32 id; /* SND_SOC_DAPM_CTL */
|
||||
char name[SNDRV_CTL_ELEM_ID_NAME_MAXLEN];
|
||||
char sname[SNDRV_CTL_ELEM_ID_NAME_MAXLEN];
|
||||
|
||||
__le32 reg; /* negative reg = no direct dapm */
|
||||
__le32 shift; /* bits to shift */
|
||||
__le32 mask; /* non-shifted mask */
|
||||
__u32 invert; /* invert the power bit */
|
||||
__u32 ignore_suspend; /* kept enabled over suspend */
|
||||
__u16 event_flags;
|
||||
__u16 event_type;
|
||||
__u16 num_kcontrols;
|
||||
struct snd_soc_tplg_private priv;
|
||||
/*
|
||||
* kcontrols that relate to this widget
|
||||
* follow here after widget private data
|
||||
*/
|
||||
} __attribute__((packed));
|
||||
|
||||
struct snd_soc_tplg_pcm_cfg_caps {
|
||||
struct snd_soc_tplg_stream_caps caps;
|
||||
struct snd_soc_tplg_stream_config configs[SND_SOC_TPLG_STREAM_CONFIG_MAX];
|
||||
__le32 num_configs; /* number of configs */
|
||||
} __attribute__((packed));
|
||||
|
||||
/*
|
||||
* Describes SW/FW specific features of PCM or DAI link.
|
||||
*
|
||||
* File block representation for PCM/DAI-Link :-
|
||||
* +-----------------------------------+-----+
|
||||
* | struct snd_soc_tplg_hdr | 1 |
|
||||
* +-----------------------------------+-----+
|
||||
* | struct snd_soc_tplg_dapm_pcm_dai | N |
|
||||
* +-----------------------------------+-----+
|
||||
*/
|
||||
struct snd_soc_tplg_pcm_dai {
|
||||
__le32 size; /* in bytes of this structure */
|
||||
char name[SNDRV_CTL_ELEM_ID_NAME_MAXLEN];
|
||||
__le32 id; /* unique ID - used to match */
|
||||
__le32 playback; /* supports playback mode */
|
||||
__le32 capture; /* supports capture mode */
|
||||
__le32 compress; /* 1 = compressed; 0 = PCM */
|
||||
struct snd_soc_tplg_pcm_cfg_caps capconf[2]; /* capabilities and configs */
|
||||
} __attribute__((packed));
|
||||
|
||||
#endif
|
31
include/uapi/sound/tlv.h
Normal file
31
include/uapi/sound/tlv.h
Normal file
@ -0,0 +1,31 @@
|
||||
/*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License as published by
|
||||
* the Free Software Foundation; either version 2 of the License, or
|
||||
* (at your option) any later version.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#ifndef __UAPI_SOUND_TLV_H
|
||||
#define __UAPI_SOUND_TLV_H
|
||||
|
||||
#define SNDRV_CTL_TLVT_CONTAINER 0 /* one level down - group of TLVs */
|
||||
#define SNDRV_CTL_TLVT_DB_SCALE 1 /* dB scale */
|
||||
#define SNDRV_CTL_TLVT_DB_LINEAR 2 /* linear volume */
|
||||
#define SNDRV_CTL_TLVT_DB_RANGE 3 /* dB range container */
|
||||
#define SNDRV_CTL_TLVT_DB_MINMAX 4 /* dB scale with min/max */
|
||||
#define SNDRV_CTL_TLVT_DB_MINMAX_MUTE 5 /* dB scale with min/max with mute */
|
||||
|
||||
/*
|
||||
* channel-mapping TLV items
|
||||
* TLV length must match with num_channels
|
||||
*/
|
||||
#define SNDRV_CTL_TLVT_CHMAP_FIXED 0x101 /* fixed channel position */
|
||||
#define SNDRV_CTL_TLVT_CHMAP_VAR 0x102 /* channels freely swappable */
|
||||
#define SNDRV_CTL_TLVT_CHMAP_PAIRED 0x103 /* pair-wise swappable */
|
||||
|
||||
#endif
|
@ -150,6 +150,8 @@ static int soundbus_device_resume(struct device * dev)
|
||||
|
||||
#endif /* CONFIG_PM */
|
||||
|
||||
/* soundbus_dev_attrs is declared in sysfs.c */
|
||||
ATTRIBUTE_GROUPS(soundbus_dev);
|
||||
static struct bus_type soundbus_bus_type = {
|
||||
.name = "aoa-soundbus",
|
||||
.probe = soundbus_probe,
|
||||
@ -160,7 +162,7 @@ static struct bus_type soundbus_bus_type = {
|
||||
.suspend = soundbus_device_suspend,
|
||||
.resume = soundbus_device_resume,
|
||||
#endif
|
||||
.dev_attrs = soundbus_dev_attrs,
|
||||
.dev_groups = soundbus_dev_groups,
|
||||
};
|
||||
|
||||
int soundbus_add_one(struct soundbus_dev *dev)
|
||||
|
@ -199,6 +199,6 @@ struct soundbus_driver {
|
||||
extern int soundbus_register_driver(struct soundbus_driver *drv);
|
||||
extern void soundbus_unregister_driver(struct soundbus_driver *drv);
|
||||
|
||||
extern struct device_attribute soundbus_dev_attrs[];
|
||||
extern struct attribute *soundbus_dev_attrs[];
|
||||
|
||||
#endif /* __SOUNDBUS_H */
|
||||
|
@ -30,13 +30,16 @@ static ssize_t modalias_show(struct device *dev, struct device_attribute *attr,
|
||||
|
||||
return length;
|
||||
}
|
||||
static DEVICE_ATTR_RO(modalias);
|
||||
|
||||
soundbus_config_of_attr (name, "%s\n");
|
||||
static DEVICE_ATTR_RO(name);
|
||||
soundbus_config_of_attr (type, "%s\n");
|
||||
static DEVICE_ATTR_RO(type);
|
||||
|
||||
struct device_attribute soundbus_dev_attrs[] = {
|
||||
__ATTR_RO(name),
|
||||
__ATTR_RO(type),
|
||||
__ATTR_RO(modalias),
|
||||
__ATTR_NULL
|
||||
struct attribute *soundbus_dev_attrs[] = {
|
||||
&dev_attr_name.attr,
|
||||
&dev_attr_type.attr,
|
||||
&dev_attr_modalias.attr,
|
||||
NULL,
|
||||
};
|
||||
|
@ -6,6 +6,12 @@ config SND_PCM
|
||||
tristate
|
||||
select SND_TIMER
|
||||
|
||||
config SND_PCM_ELD
|
||||
bool
|
||||
|
||||
config SND_PCM_IEC958
|
||||
bool
|
||||
|
||||
config SND_DMAENGINE_PCM
|
||||
tristate
|
||||
|
||||
@ -176,9 +182,18 @@ config SND_SUPPORT_OLD_API
|
||||
Say Y here to support the obsolete ALSA PCM API (ver.0.9.0 rc3
|
||||
or older).
|
||||
|
||||
config SND_PROC_FS
|
||||
bool "Sound Proc FS Support" if EXPERT
|
||||
depends on PROC_FS
|
||||
default y
|
||||
help
|
||||
Say 'N' to disable Sound proc FS, which may reduce code size about
|
||||
9KB on x86_64 platform.
|
||||
If unsure say Y.
|
||||
|
||||
config SND_VERBOSE_PROCFS
|
||||
bool "Verbose procfs contents"
|
||||
depends on PROC_FS
|
||||
depends on SND_PROC_FS
|
||||
default y
|
||||
help
|
||||
Say Y here to include code for verbose procfs contents (provides
|
||||
@ -221,9 +236,6 @@ config SND_PCM_XRUN_DEBUG
|
||||
config SND_VMASTER
|
||||
bool
|
||||
|
||||
config SND_KCTL_JACK
|
||||
bool
|
||||
|
||||
config SND_DMA_SGBUF
|
||||
def_bool y
|
||||
depends on X86
|
||||
|
@ -3,16 +3,21 @@
|
||||
# Copyright (c) 1999,2001 by Jaroslav Kysela <perex@perex.cz>
|
||||
#
|
||||
|
||||
snd-y := sound.o init.o memory.o info.o control.o misc.o device.o
|
||||
snd-y := sound.o init.o memory.o control.o misc.o device.o
|
||||
ifneq ($(CONFIG_SND_PROC_FS),)
|
||||
snd-y += info.o
|
||||
snd-$(CONFIG_SND_OSSEMUL) += info_oss.o
|
||||
endif
|
||||
snd-$(CONFIG_ISA_DMA_API) += isadma.o
|
||||
snd-$(CONFIG_SND_OSSEMUL) += sound_oss.o info_oss.o
|
||||
snd-$(CONFIG_SND_OSSEMUL) += sound_oss.o
|
||||
snd-$(CONFIG_SND_VMASTER) += vmaster.o
|
||||
snd-$(CONFIG_SND_KCTL_JACK) += ctljack.o
|
||||
snd-$(CONFIG_SND_JACK) += jack.o
|
||||
snd-$(CONFIG_SND_JACK) += ctljack.o jack.o
|
||||
|
||||
snd-pcm-y := pcm.o pcm_native.o pcm_lib.o pcm_timer.o pcm_misc.o \
|
||||
pcm_memory.o memalloc.o
|
||||
snd-pcm-$(CONFIG_SND_DMA_SGBUF) += sgbuf.o
|
||||
snd-pcm-$(CONFIG_SND_PCM_ELD) += pcm_drm_eld.o
|
||||
snd-pcm-$(CONFIG_SND_PCM_IEC958) += pcm_iec958.o
|
||||
|
||||
# for trace-points
|
||||
CFLAGS_pcm_lib.o := -I$(src)
|
||||
|
@ -31,19 +31,49 @@ static struct snd_kcontrol_new jack_detect_kctl = {
|
||||
.get = jack_detect_kctl_get,
|
||||
};
|
||||
|
||||
static int get_available_index(struct snd_card *card, const char *name)
|
||||
{
|
||||
struct snd_ctl_elem_id sid;
|
||||
|
||||
memset(&sid, 0, sizeof(sid));
|
||||
|
||||
sid.index = 0;
|
||||
sid.iface = SNDRV_CTL_ELEM_IFACE_CARD;
|
||||
strlcpy(sid.name, name, sizeof(sid.name));
|
||||
|
||||
while (snd_ctl_find_id(card, &sid))
|
||||
sid.index++;
|
||||
|
||||
return sid.index;
|
||||
}
|
||||
|
||||
static void jack_kctl_name_gen(char *name, const char *src_name, int size)
|
||||
{
|
||||
size_t count = strlen(src_name);
|
||||
bool need_cat = true;
|
||||
|
||||
/* remove redundant " Jack" from src_name */
|
||||
if (count >= 5)
|
||||
need_cat = strncmp(&src_name[count - 5], " Jack", 5) ? true : false;
|
||||
|
||||
snprintf(name, size, need_cat ? "%s Jack" : "%s", src_name);
|
||||
|
||||
}
|
||||
|
||||
struct snd_kcontrol *
|
||||
snd_kctl_jack_new(const char *name, int idx, void *private_data)
|
||||
snd_kctl_jack_new(const char *name, struct snd_card *card)
|
||||
{
|
||||
struct snd_kcontrol *kctl;
|
||||
kctl = snd_ctl_new1(&jack_detect_kctl, private_data);
|
||||
|
||||
kctl = snd_ctl_new1(&jack_detect_kctl, NULL);
|
||||
if (!kctl)
|
||||
return NULL;
|
||||
snprintf(kctl->id.name, sizeof(kctl->id.name), "%s Jack", name);
|
||||
kctl->id.index = idx;
|
||||
|
||||
jack_kctl_name_gen(kctl->id.name, name, sizeof(kctl->id.name));
|
||||
kctl->id.index = get_available_index(card, kctl->id.name);
|
||||
kctl->private_value = 0;
|
||||
return kctl;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(snd_kctl_jack_new);
|
||||
|
||||
void snd_kctl_jack_report(struct snd_card *card,
|
||||
struct snd_kcontrol *kctl, bool status)
|
||||
@ -53,4 +83,3 @@ void snd_kctl_jack_report(struct snd_card *card,
|
||||
kctl->private_value = status;
|
||||
snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE, &kctl->id);
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(snd_kctl_jack_report);
|
||||
|
@ -484,7 +484,7 @@ static int snd_hwdep_dev_disconnect(struct snd_device *device)
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PROC_FS
|
||||
#ifdef CONFIG_SND_PROC_FS
|
||||
/*
|
||||
* Info interface
|
||||
*/
|
||||
@ -521,10 +521,10 @@ static void __exit snd_hwdep_proc_done(void)
|
||||
{
|
||||
snd_info_free_entry(snd_hwdep_proc_entry);
|
||||
}
|
||||
#else /* !CONFIG_PROC_FS */
|
||||
#else /* !CONFIG_SND_PROC_FS */
|
||||
#define snd_hwdep_proc_init()
|
||||
#define snd_hwdep_proc_done()
|
||||
#endif /* CONFIG_PROC_FS */
|
||||
#endif /* CONFIG_SND_PROC_FS */
|
||||
|
||||
|
||||
/*
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -29,15 +29,12 @@
|
||||
#include <linux/utsname.h>
|
||||
#include <linux/mutex.h>
|
||||
|
||||
#if defined(CONFIG_SND_OSSEMUL) && defined(CONFIG_PROC_FS)
|
||||
|
||||
/*
|
||||
* OSS compatible part
|
||||
*/
|
||||
|
||||
static DEFINE_MUTEX(strings);
|
||||
static char *snd_sndstat_strings[SNDRV_CARDS][SNDRV_OSS_INFO_DEV_COUNT];
|
||||
static struct snd_info_entry *snd_sndstat_proc_entry;
|
||||
|
||||
int snd_oss_info_register(int dev, int num, char *string)
|
||||
{
|
||||
@ -112,27 +109,15 @@ static void snd_sndstat_proc_read(struct snd_info_entry *entry,
|
||||
snd_sndstat_show_strings(buffer, "Mixers", SNDRV_OSS_INFO_DEV_MIXERS);
|
||||
}
|
||||
|
||||
int snd_info_minor_register(void)
|
||||
int __init snd_info_minor_register(void)
|
||||
{
|
||||
struct snd_info_entry *entry;
|
||||
|
||||
memset(snd_sndstat_strings, 0, sizeof(snd_sndstat_strings));
|
||||
if ((entry = snd_info_create_module_entry(THIS_MODULE, "sndstat", snd_oss_root)) != NULL) {
|
||||
entry->c.text.read = snd_sndstat_proc_read;
|
||||
if (snd_info_register(entry) < 0) {
|
||||
snd_info_free_entry(entry);
|
||||
entry = NULL;
|
||||
}
|
||||
}
|
||||
snd_sndstat_proc_entry = entry;
|
||||
return 0;
|
||||
entry = snd_info_create_module_entry(THIS_MODULE, "sndstat",
|
||||
snd_oss_root);
|
||||
if (!entry)
|
||||
return -ENOMEM;
|
||||
entry->c.text.read = snd_sndstat_proc_read;
|
||||
return snd_info_register(entry); /* freed in error path */
|
||||
}
|
||||
|
||||
int snd_info_minor_unregister(void)
|
||||
{
|
||||
snd_info_free_entry(snd_sndstat_proc_entry);
|
||||
snd_sndstat_proc_entry = NULL;
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif /* CONFIG_SND_OSSEMUL */
|
||||
|
@ -100,35 +100,29 @@ int (*snd_mixer_oss_notify_callback)(struct snd_card *card, int free_flag);
|
||||
EXPORT_SYMBOL(snd_mixer_oss_notify_callback);
|
||||
#endif
|
||||
|
||||
#ifdef CONFIG_PROC_FS
|
||||
#ifdef CONFIG_SND_PROC_FS
|
||||
static void snd_card_id_read(struct snd_info_entry *entry,
|
||||
struct snd_info_buffer *buffer)
|
||||
{
|
||||
snd_iprintf(buffer, "%s\n", entry->card->id);
|
||||
}
|
||||
|
||||
static inline int init_info_for_card(struct snd_card *card)
|
||||
static int init_info_for_card(struct snd_card *card)
|
||||
{
|
||||
int err;
|
||||
struct snd_info_entry *entry;
|
||||
|
||||
if ((err = snd_info_card_register(card)) < 0) {
|
||||
dev_dbg(card->dev, "unable to create card info\n");
|
||||
return err;
|
||||
}
|
||||
if ((entry = snd_info_create_card_entry(card, "id", card->proc_root)) == NULL) {
|
||||
entry = snd_info_create_card_entry(card, "id", card->proc_root);
|
||||
if (!entry) {
|
||||
dev_dbg(card->dev, "unable to create card entry\n");
|
||||
return err;
|
||||
}
|
||||
entry->c.text.read = snd_card_id_read;
|
||||
if (snd_info_register(entry) < 0) {
|
||||
snd_info_free_entry(entry);
|
||||
entry = NULL;
|
||||
}
|
||||
card->proc_id = entry;
|
||||
return 0;
|
||||
|
||||
return snd_info_card_register(card);
|
||||
}
|
||||
#else /* !CONFIG_PROC_FS */
|
||||
#else /* !CONFIG_SND_PROC_FS */
|
||||
#define init_info_for_card(card)
|
||||
#endif
|
||||
|
||||
@ -756,7 +750,7 @@ int snd_card_register(struct snd_card *card)
|
||||
if (snd_cards[card->number]) {
|
||||
/* already registered */
|
||||
mutex_unlock(&snd_card_mutex);
|
||||
return 0;
|
||||
return snd_info_card_register(card); /* register pending info */
|
||||
}
|
||||
if (*card->id) {
|
||||
/* make a unique id name from the given string */
|
||||
@ -782,9 +776,7 @@ int snd_card_register(struct snd_card *card)
|
||||
|
||||
EXPORT_SYMBOL(snd_card_register);
|
||||
|
||||
#ifdef CONFIG_PROC_FS
|
||||
static struct snd_info_entry *snd_card_info_entry;
|
||||
|
||||
#ifdef CONFIG_SND_PROC_FS
|
||||
static void snd_card_info_read(struct snd_info_entry *entry,
|
||||
struct snd_info_buffer *buffer)
|
||||
{
|
||||
@ -810,7 +802,6 @@ static void snd_card_info_read(struct snd_info_entry *entry,
|
||||
}
|
||||
|
||||
#ifdef CONFIG_SND_OSSEMUL
|
||||
|
||||
void snd_card_info_read_oss(struct snd_info_buffer *buffer)
|
||||
{
|
||||
int idx, count;
|
||||
@ -832,7 +823,6 @@ void snd_card_info_read_oss(struct snd_info_buffer *buffer)
|
||||
#endif
|
||||
|
||||
#ifdef MODULE
|
||||
static struct snd_info_entry *snd_card_module_info_entry;
|
||||
static void snd_card_module_info_read(struct snd_info_entry *entry,
|
||||
struct snd_info_buffer *buffer)
|
||||
{
|
||||
@ -857,36 +847,21 @@ int __init snd_card_info_init(void)
|
||||
if (! entry)
|
||||
return -ENOMEM;
|
||||
entry->c.text.read = snd_card_info_read;
|
||||
if (snd_info_register(entry) < 0) {
|
||||
snd_info_free_entry(entry);
|
||||
return -ENOMEM;
|
||||
}
|
||||
snd_card_info_entry = entry;
|
||||
if (snd_info_register(entry) < 0)
|
||||
return -ENOMEM; /* freed in error path */
|
||||
|
||||
#ifdef MODULE
|
||||
entry = snd_info_create_module_entry(THIS_MODULE, "modules", NULL);
|
||||
if (entry) {
|
||||
entry->c.text.read = snd_card_module_info_read;
|
||||
if (snd_info_register(entry) < 0)
|
||||
snd_info_free_entry(entry);
|
||||
else
|
||||
snd_card_module_info_entry = entry;
|
||||
}
|
||||
if (!entry)
|
||||
return -ENOMEM;
|
||||
entry->c.text.read = snd_card_module_info_read;
|
||||
if (snd_info_register(entry) < 0)
|
||||
return -ENOMEM; /* freed in error path */
|
||||
#endif
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
int __exit snd_card_info_done(void)
|
||||
{
|
||||
snd_info_free_entry(snd_card_info_entry);
|
||||
#ifdef MODULE
|
||||
snd_info_free_entry(snd_card_module_info_entry);
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
#endif /* CONFIG_PROC_FS */
|
||||
#endif /* CONFIG_SND_PROC_FS */
|
||||
|
||||
/**
|
||||
* snd_component_add - add a component string
|
||||
|
@ -24,6 +24,13 @@
|
||||
#include <linux/module.h>
|
||||
#include <sound/jack.h>
|
||||
#include <sound/core.h>
|
||||
#include <sound/control.h>
|
||||
|
||||
struct snd_jack_kctl {
|
||||
struct snd_kcontrol *kctl;
|
||||
struct list_head list; /* list of controls belong to the same jack */
|
||||
unsigned int mask_bits; /* only masked status bits are reported via kctl */
|
||||
};
|
||||
|
||||
static int jack_switch_types[SND_JACK_SWITCH_TYPES] = {
|
||||
SW_HEADPHONE_INSERT,
|
||||
@ -54,7 +61,13 @@ static int snd_jack_dev_disconnect(struct snd_device *device)
|
||||
static int snd_jack_dev_free(struct snd_device *device)
|
||||
{
|
||||
struct snd_jack *jack = device->device_data;
|
||||
struct snd_card *card = device->card;
|
||||
struct snd_jack_kctl *jack_kctl, *tmp_jack_kctl;
|
||||
|
||||
list_for_each_entry_safe(jack_kctl, tmp_jack_kctl, &jack->kctl_list, list) {
|
||||
list_del_init(&jack_kctl->list);
|
||||
snd_ctl_remove(card, jack_kctl->kctl);
|
||||
}
|
||||
if (jack->private_free)
|
||||
jack->private_free(jack);
|
||||
|
||||
@ -74,6 +87,10 @@ static int snd_jack_dev_register(struct snd_device *device)
|
||||
|
||||
snprintf(jack->name, sizeof(jack->name), "%s %s",
|
||||
card->shortname, jack->id);
|
||||
|
||||
if (!jack->input_dev)
|
||||
return 0;
|
||||
|
||||
jack->input_dev->name = jack->name;
|
||||
|
||||
/* Default to the sound card device. */
|
||||
@ -100,6 +117,77 @@ static int snd_jack_dev_register(struct snd_device *device)
|
||||
return err;
|
||||
}
|
||||
|
||||
static void snd_jack_kctl_private_free(struct snd_kcontrol *kctl)
|
||||
{
|
||||
struct snd_jack_kctl *jack_kctl;
|
||||
|
||||
jack_kctl = kctl->private_data;
|
||||
if (jack_kctl) {
|
||||
list_del(&jack_kctl->list);
|
||||
kfree(jack_kctl);
|
||||
}
|
||||
}
|
||||
|
||||
static void snd_jack_kctl_add(struct snd_jack *jack, struct snd_jack_kctl *jack_kctl)
|
||||
{
|
||||
list_add_tail(&jack_kctl->list, &jack->kctl_list);
|
||||
}
|
||||
|
||||
static struct snd_jack_kctl * snd_jack_kctl_new(struct snd_card *card, const char *name, unsigned int mask)
|
||||
{
|
||||
struct snd_kcontrol *kctl;
|
||||
struct snd_jack_kctl *jack_kctl;
|
||||
int err;
|
||||
|
||||
kctl = snd_kctl_jack_new(name, card);
|
||||
if (!kctl)
|
||||
return NULL;
|
||||
|
||||
err = snd_ctl_add(card, kctl);
|
||||
if (err < 0)
|
||||
return NULL;
|
||||
|
||||
jack_kctl = kzalloc(sizeof(*jack_kctl), GFP_KERNEL);
|
||||
|
||||
if (!jack_kctl)
|
||||
goto error;
|
||||
|
||||
jack_kctl->kctl = kctl;
|
||||
jack_kctl->mask_bits = mask;
|
||||
|
||||
kctl->private_data = jack_kctl;
|
||||
kctl->private_free = snd_jack_kctl_private_free;
|
||||
|
||||
return jack_kctl;
|
||||
error:
|
||||
snd_ctl_free_one(kctl);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
* snd_jack_add_new_kctl - Create a new snd_jack_kctl and add it to jack
|
||||
* @jack: the jack instance which the kctl will attaching to
|
||||
* @name: the name for the snd_kcontrol object
|
||||
* @mask: a bitmask of enum snd_jack_type values that can be detected
|
||||
* by this snd_jack_kctl object.
|
||||
*
|
||||
* Creates a new snd_kcontrol object and adds it to the jack kctl_list.
|
||||
*
|
||||
* Return: Zero if successful, or a negative error code on failure.
|
||||
*/
|
||||
int snd_jack_add_new_kctl(struct snd_jack *jack, const char * name, int mask)
|
||||
{
|
||||
struct snd_jack_kctl *jack_kctl;
|
||||
|
||||
jack_kctl = snd_jack_kctl_new(jack->card, name, mask);
|
||||
if (!jack_kctl)
|
||||
return -ENOMEM;
|
||||
|
||||
snd_jack_kctl_add(jack, jack_kctl);
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL(snd_jack_add_new_kctl);
|
||||
|
||||
/**
|
||||
* snd_jack_new - Create a new jack
|
||||
* @card: the card instance
|
||||
@ -107,6 +195,8 @@ static int snd_jack_dev_register(struct snd_device *device)
|
||||
* @type: a bitmask of enum snd_jack_type values that can be detected by
|
||||
* this jack
|
||||
* @jjack: Used to provide the allocated jack object to the caller.
|
||||
* @initial_kctl: if true, create a kcontrol and add it to the jack list.
|
||||
* @phantom_jack: Don't create a input device for phantom jacks.
|
||||
*
|
||||
* Creates a new jack object.
|
||||
*
|
||||
@ -114,9 +204,10 @@ static int snd_jack_dev_register(struct snd_device *device)
|
||||
* On success @jjack will be initialised.
|
||||
*/
|
||||
int snd_jack_new(struct snd_card *card, const char *id, int type,
|
||||
struct snd_jack **jjack)
|
||||
struct snd_jack **jjack, bool initial_kctl, bool phantom_jack)
|
||||
{
|
||||
struct snd_jack *jack;
|
||||
struct snd_jack_kctl *jack_kctl = NULL;
|
||||
int err;
|
||||
int i;
|
||||
static struct snd_device_ops ops = {
|
||||
@ -125,31 +216,47 @@ int snd_jack_new(struct snd_card *card, const char *id, int type,
|
||||
.dev_disconnect = snd_jack_dev_disconnect,
|
||||
};
|
||||
|
||||
if (initial_kctl) {
|
||||
jack_kctl = snd_jack_kctl_new(card, id, type);
|
||||
if (!jack_kctl)
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
jack = kzalloc(sizeof(struct snd_jack), GFP_KERNEL);
|
||||
if (jack == NULL)
|
||||
return -ENOMEM;
|
||||
|
||||
jack->id = kstrdup(id, GFP_KERNEL);
|
||||
|
||||
jack->input_dev = input_allocate_device();
|
||||
if (jack->input_dev == NULL) {
|
||||
err = -ENOMEM;
|
||||
goto fail_input;
|
||||
/* don't creat input device for phantom jack */
|
||||
if (!phantom_jack) {
|
||||
jack->input_dev = input_allocate_device();
|
||||
if (jack->input_dev == NULL) {
|
||||
err = -ENOMEM;
|
||||
goto fail_input;
|
||||
}
|
||||
|
||||
jack->input_dev->phys = "ALSA";
|
||||
|
||||
jack->type = type;
|
||||
|
||||
for (i = 0; i < SND_JACK_SWITCH_TYPES; i++)
|
||||
if (type & (1 << i))
|
||||
input_set_capability(jack->input_dev, EV_SW,
|
||||
jack_switch_types[i]);
|
||||
|
||||
}
|
||||
|
||||
jack->input_dev->phys = "ALSA";
|
||||
|
||||
jack->type = type;
|
||||
|
||||
for (i = 0; i < SND_JACK_SWITCH_TYPES; i++)
|
||||
if (type & (1 << i))
|
||||
input_set_capability(jack->input_dev, EV_SW,
|
||||
jack_switch_types[i]);
|
||||
|
||||
err = snd_device_new(card, SNDRV_DEV_JACK, jack, &ops);
|
||||
if (err < 0)
|
||||
goto fail_input;
|
||||
|
||||
jack->card = card;
|
||||
INIT_LIST_HEAD(&jack->kctl_list);
|
||||
|
||||
if (initial_kctl)
|
||||
snd_jack_kctl_add(jack, jack_kctl);
|
||||
|
||||
*jjack = jack;
|
||||
|
||||
return 0;
|
||||
@ -175,6 +282,8 @@ EXPORT_SYMBOL(snd_jack_new);
|
||||
void snd_jack_set_parent(struct snd_jack *jack, struct device *parent)
|
||||
{
|
||||
WARN_ON(jack->registered);
|
||||
if (!jack->input_dev)
|
||||
return;
|
||||
|
||||
jack->input_dev->dev.parent = parent;
|
||||
}
|
||||
@ -230,11 +339,19 @@ EXPORT_SYMBOL(snd_jack_set_key);
|
||||
*/
|
||||
void snd_jack_report(struct snd_jack *jack, int status)
|
||||
{
|
||||
struct snd_jack_kctl *jack_kctl;
|
||||
int i;
|
||||
|
||||
if (!jack)
|
||||
return;
|
||||
|
||||
list_for_each_entry(jack_kctl, &jack->kctl_list, list)
|
||||
snd_kctl_jack_report(jack->card, jack_kctl->kctl,
|
||||
status & jack_kctl->mask_bits);
|
||||
|
||||
if (!jack->input_dev)
|
||||
return;
|
||||
|
||||
for (i = 0; i < ARRAY_SIZE(jack->key); i++) {
|
||||
int testbit = SND_JACK_BTN_0 >> i;
|
||||
|
||||
@ -252,9 +369,6 @@ void snd_jack_report(struct snd_jack *jack, int status)
|
||||
}
|
||||
|
||||
input_sync(jack->input_dev);
|
||||
|
||||
}
|
||||
EXPORT_SYMBOL(snd_jack_report);
|
||||
|
||||
MODULE_AUTHOR("Mark Brown <broonie@opensource.wolfsonmicro.com>");
|
||||
MODULE_DESCRIPTION("Jack detection support for ALSA");
|
||||
MODULE_LICENSE("GPL");
|
||||
|
@ -1111,7 +1111,7 @@ static int snd_mixer_oss_build_input(struct snd_mixer_oss *mixer, struct snd_mix
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PROC_FS
|
||||
#ifdef CONFIG_SND_PROC_FS
|
||||
/*
|
||||
*/
|
||||
#define MIXER_VOL(name) [SOUND_MIXER_##name] = #name
|
||||
@ -1255,10 +1255,10 @@ static void snd_mixer_oss_proc_done(struct snd_mixer_oss *mixer)
|
||||
snd_info_free_entry(mixer->proc_entry);
|
||||
mixer->proc_entry = NULL;
|
||||
}
|
||||
#else /* !CONFIG_PROC_FS */
|
||||
#else /* !CONFIG_SND_PROC_FS */
|
||||
#define snd_mixer_oss_proc_init(mix)
|
||||
#define snd_mixer_oss_proc_done(mix)
|
||||
#endif /* CONFIG_PROC_FS */
|
||||
#endif /* CONFIG_SND_PROC_FS */
|
||||
|
||||
static void snd_mixer_oss_build(struct snd_mixer_oss *mixer)
|
||||
{
|
||||
|
@ -1027,7 +1027,8 @@ void snd_pcm_detach_substream(struct snd_pcm_substream *substream)
|
||||
static ssize_t show_pcm_class(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
{
|
||||
struct snd_pcm *pcm;
|
||||
struct snd_pcm_str *pstr = container_of(dev, struct snd_pcm_str, dev);
|
||||
struct snd_pcm *pcm = pstr->pcm;
|
||||
const char *str;
|
||||
static const char *strs[SNDRV_PCM_CLASS_LAST + 1] = {
|
||||
[SNDRV_PCM_CLASS_GENERIC] = "generic",
|
||||
@ -1036,8 +1037,7 @@ static ssize_t show_pcm_class(struct device *dev,
|
||||
[SNDRV_PCM_CLASS_DIGITIZER] = "digitizer",
|
||||
};
|
||||
|
||||
if (! (pcm = dev_get_drvdata(dev)) ||
|
||||
pcm->dev_class > SNDRV_PCM_CLASS_LAST)
|
||||
if (pcm->dev_class > SNDRV_PCM_CLASS_LAST)
|
||||
str = "none";
|
||||
else
|
||||
str = strs[pcm->dev_class];
|
||||
@ -1181,7 +1181,7 @@ int snd_pcm_notify(struct snd_pcm_notify *notify, int nfree)
|
||||
}
|
||||
EXPORT_SYMBOL(snd_pcm_notify);
|
||||
|
||||
#ifdef CONFIG_PROC_FS
|
||||
#ifdef CONFIG_SND_PROC_FS
|
||||
/*
|
||||
* Info interface
|
||||
*/
|
||||
@ -1227,10 +1227,10 @@ static void snd_pcm_proc_done(void)
|
||||
snd_info_free_entry(snd_pcm_proc_entry);
|
||||
}
|
||||
|
||||
#else /* !CONFIG_PROC_FS */
|
||||
#else /* !CONFIG_SND_PROC_FS */
|
||||
#define snd_pcm_proc_init()
|
||||
#define snd_pcm_proc_done()
|
||||
#endif /* CONFIG_PROC_FS */
|
||||
#endif /* CONFIG_SND_PROC_FS */
|
||||
|
||||
|
||||
/*
|
||||
|
99
sound/core/pcm_drm_eld.c
Normal file
99
sound/core/pcm_drm_eld.c
Normal file
@ -0,0 +1,99 @@
|
||||
/*
|
||||
* PCM DRM helpers
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
#include <linux/export.h>
|
||||
#include <drm/drm_edid.h>
|
||||
#include <sound/pcm.h>
|
||||
#include <sound/pcm_drm_eld.h>
|
||||
|
||||
static const unsigned int eld_rates[] = {
|
||||
32000,
|
||||
44100,
|
||||
48000,
|
||||
88200,
|
||||
96000,
|
||||
176400,
|
||||
192000,
|
||||
};
|
||||
|
||||
static unsigned int sad_max_channels(const u8 *sad)
|
||||
{
|
||||
return 1 + (sad[0] & 7);
|
||||
}
|
||||
|
||||
static int eld_limit_rates(struct snd_pcm_hw_params *params,
|
||||
struct snd_pcm_hw_rule *rule)
|
||||
{
|
||||
struct snd_interval *r = hw_param_interval(params, rule->var);
|
||||
struct snd_interval *c;
|
||||
unsigned int rate_mask = 7, i;
|
||||
const u8 *sad, *eld = rule->private;
|
||||
|
||||
sad = drm_eld_sad(eld);
|
||||
if (sad) {
|
||||
c = hw_param_interval(params, SNDRV_PCM_HW_PARAM_CHANNELS);
|
||||
|
||||
for (i = drm_eld_sad_count(eld); i > 0; i--, sad += 3) {
|
||||
unsigned max_channels = sad_max_channels(sad);
|
||||
|
||||
/*
|
||||
* Exclude SADs which do not include the
|
||||
* requested number of channels.
|
||||
*/
|
||||
if (c->min <= max_channels)
|
||||
rate_mask |= sad[1];
|
||||
}
|
||||
}
|
||||
|
||||
return snd_interval_list(r, ARRAY_SIZE(eld_rates), eld_rates,
|
||||
rate_mask);
|
||||
}
|
||||
|
||||
static int eld_limit_channels(struct snd_pcm_hw_params *params,
|
||||
struct snd_pcm_hw_rule *rule)
|
||||
{
|
||||
struct snd_interval *c = hw_param_interval(params, rule->var);
|
||||
struct snd_interval *r;
|
||||
struct snd_interval t = { .min = 1, .max = 2, .integer = 1, };
|
||||
unsigned int i;
|
||||
const u8 *sad, *eld = rule->private;
|
||||
|
||||
sad = drm_eld_sad(eld);
|
||||
if (sad) {
|
||||
unsigned int rate_mask = 0;
|
||||
|
||||
/* Convert the rate interval to a mask */
|
||||
r = hw_param_interval(params, SNDRV_PCM_HW_PARAM_RATE);
|
||||
for (i = 0; i < ARRAY_SIZE(eld_rates); i++)
|
||||
if (r->min <= eld_rates[i] && r->max >= eld_rates[i])
|
||||
rate_mask |= BIT(i);
|
||||
|
||||
for (i = drm_eld_sad_count(eld); i > 0; i--, sad += 3)
|
||||
if (rate_mask & sad[1])
|
||||
t.max = max(t.max, sad_max_channels(sad));
|
||||
}
|
||||
|
||||
return snd_interval_refine(c, &t);
|
||||
}
|
||||
|
||||
int snd_pcm_hw_constraint_eld(struct snd_pcm_runtime *runtime, void *eld)
|
||||
{
|
||||
int ret;
|
||||
|
||||
ret = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_RATE,
|
||||
eld_limit_rates, eld,
|
||||
SNDRV_PCM_HW_PARAM_CHANNELS, -1);
|
||||
if (ret < 0)
|
||||
return ret;
|
||||
|
||||
ret = snd_pcm_hw_rule_add(runtime, 0, SNDRV_PCM_HW_PARAM_CHANNELS,
|
||||
eld_limit_channels, eld,
|
||||
SNDRV_PCM_HW_PARAM_RATE, -1);
|
||||
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(snd_pcm_hw_constraint_eld);
|
95
sound/core/pcm_iec958.c
Normal file
95
sound/core/pcm_iec958.c
Normal file
@ -0,0 +1,95 @@
|
||||
/*
|
||||
* PCM DRM helpers
|
||||
*
|
||||
* This program is free software; you can redistribute it and/or modify
|
||||
* it under the terms of the GNU General Public License version 2 as
|
||||
* published by the Free Software Foundation.
|
||||
*/
|
||||
#include <linux/export.h>
|
||||
#include <linux/types.h>
|
||||
#include <sound/asoundef.h>
|
||||
#include <sound/pcm.h>
|
||||
#include <sound/pcm_iec958.h>
|
||||
|
||||
/**
|
||||
* snd_pcm_create_iec958_consumer - create consumer format IEC958 channel status
|
||||
* @runtime: pcm runtime structure with ->rate filled in
|
||||
* @cs: channel status buffer, at least four bytes
|
||||
* @len: length of channel status buffer
|
||||
*
|
||||
* Create the consumer format channel status data in @cs of maximum size
|
||||
* @len corresponding to the parameters of the PCM runtime @runtime.
|
||||
*
|
||||
* Drivers may wish to tweak the contents of the buffer after creation.
|
||||
*
|
||||
* Returns: length of buffer, or negative error code if something failed.
|
||||
*/
|
||||
int snd_pcm_create_iec958_consumer(struct snd_pcm_runtime *runtime, u8 *cs,
|
||||
size_t len)
|
||||
{
|
||||
unsigned int fs, ws;
|
||||
|
||||
if (len < 4)
|
||||
return -EINVAL;
|
||||
|
||||
switch (runtime->rate) {
|
||||
case 32000:
|
||||
fs = IEC958_AES3_CON_FS_32000;
|
||||
break;
|
||||
case 44100:
|
||||
fs = IEC958_AES3_CON_FS_44100;
|
||||
break;
|
||||
case 48000:
|
||||
fs = IEC958_AES3_CON_FS_48000;
|
||||
break;
|
||||
case 88200:
|
||||
fs = IEC958_AES3_CON_FS_88200;
|
||||
break;
|
||||
case 96000:
|
||||
fs = IEC958_AES3_CON_FS_96000;
|
||||
break;
|
||||
case 176400:
|
||||
fs = IEC958_AES3_CON_FS_176400;
|
||||
break;
|
||||
case 192000:
|
||||
fs = IEC958_AES3_CON_FS_192000;
|
||||
break;
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
|
||||
if (len > 4) {
|
||||
switch (snd_pcm_format_width(runtime->format)) {
|
||||
case 16:
|
||||
ws = IEC958_AES4_CON_WORDLEN_20_16;
|
||||
break;
|
||||
case 18:
|
||||
ws = IEC958_AES4_CON_WORDLEN_22_18;
|
||||
break;
|
||||
case 20:
|
||||
ws = IEC958_AES4_CON_WORDLEN_20_16 |
|
||||
IEC958_AES4_CON_MAX_WORDLEN_24;
|
||||
break;
|
||||
case 24:
|
||||
ws = IEC958_AES4_CON_WORDLEN_24_20 |
|
||||
IEC958_AES4_CON_MAX_WORDLEN_24;
|
||||
break;
|
||||
|
||||
default:
|
||||
return -EINVAL;
|
||||
}
|
||||
}
|
||||
|
||||
memset(cs, 0, len);
|
||||
|
||||
cs[0] = IEC958_AES0_CON_NOT_COPYRIGHT | IEC958_AES0_CON_EMPHASIS_NONE;
|
||||
cs[1] = IEC958_AES1_CON_GENERAL;
|
||||
cs[2] = IEC958_AES2_CON_SOURCE_UNSPEC | IEC958_AES2_CON_CHANNEL_UNSPEC;
|
||||
cs[3] = IEC958_AES3_CON_CLOCK_1000PPM | fs;
|
||||
|
||||
if (len > 4)
|
||||
cs[4] = ws;
|
||||
|
||||
return len;
|
||||
}
|
||||
EXPORT_SYMBOL(snd_pcm_create_iec958_consumer);
|
@ -6,7 +6,8 @@
|
||||
snd-seq-device-objs := seq_device.o
|
||||
snd-seq-objs := seq.o seq_lock.o seq_clientmgr.o seq_memory.o seq_queue.o \
|
||||
seq_fifo.o seq_prioq.o seq_timer.o \
|
||||
seq_system.o seq_ports.o seq_info.o
|
||||
seq_system.o seq_ports.o
|
||||
snd-seq-$(CONFIG_SND_PROC_FS) += seq_info.o
|
||||
snd-seq-midi-objs := seq_midi.o
|
||||
snd-seq-midi-emul-objs := seq_midi_emul.o
|
||||
snd-seq-midi-event-objs := seq_midi_event.o
|
||||
|
@ -45,7 +45,7 @@ MODULE_ALIAS_SNDRV_MINOR(SNDRV_MINOR_OSS_MUSIC);
|
||||
*/
|
||||
static int register_device(void);
|
||||
static void unregister_device(void);
|
||||
#ifdef CONFIG_PROC_FS
|
||||
#ifdef CONFIG_SND_PROC_FS
|
||||
static int register_proc(void);
|
||||
static void unregister_proc(void);
|
||||
#else
|
||||
@ -261,7 +261,7 @@ unregister_device(void)
|
||||
* /proc interface
|
||||
*/
|
||||
|
||||
#ifdef CONFIG_PROC_FS
|
||||
#ifdef CONFIG_SND_PROC_FS
|
||||
|
||||
static struct snd_info_entry *info_entry;
|
||||
|
||||
@ -303,4 +303,4 @@ unregister_proc(void)
|
||||
snd_info_free_entry(info_entry);
|
||||
info_entry = NULL;
|
||||
}
|
||||
#endif /* CONFIG_PROC_FS */
|
||||
#endif /* CONFIG_SND_PROC_FS */
|
||||
|
@ -479,8 +479,7 @@ snd_seq_oss_reset(struct seq_oss_devinfo *dp)
|
||||
snd_seq_oss_timer_stop(dp->timer);
|
||||
}
|
||||
|
||||
|
||||
#ifdef CONFIG_PROC_FS
|
||||
#ifdef CONFIG_SND_PROC_FS
|
||||
/*
|
||||
* misc. functions for proc interface
|
||||
*/
|
||||
@ -531,4 +530,4 @@ snd_seq_oss_system_info_read(struct snd_info_buffer *buf)
|
||||
snd_seq_oss_readq_info_read(dp->readq, buf);
|
||||
}
|
||||
}
|
||||
#endif /* CONFIG_PROC_FS */
|
||||
#endif /* CONFIG_SND_PROC_FS */
|
||||
|
@ -665,7 +665,7 @@ snd_seq_oss_midi_make_info(struct seq_oss_devinfo *dp, int dev, struct midi_info
|
||||
}
|
||||
|
||||
|
||||
#ifdef CONFIG_PROC_FS
|
||||
#ifdef CONFIG_SND_PROC_FS
|
||||
/*
|
||||
* proc interface
|
||||
*/
|
||||
@ -705,4 +705,4 @@ snd_seq_oss_midi_info_read(struct snd_info_buffer *buf)
|
||||
snd_use_lock_free(&mdev->use_lock);
|
||||
}
|
||||
}
|
||||
#endif /* CONFIG_PROC_FS */
|
||||
#endif /* CONFIG_SND_PROC_FS */
|
||||
|
@ -222,7 +222,7 @@ snd_seq_oss_readq_put_timestamp(struct seq_oss_readq *q, unsigned long curt, int
|
||||
}
|
||||
|
||||
|
||||
#ifdef CONFIG_PROC_FS
|
||||
#ifdef CONFIG_SND_PROC_FS
|
||||
/*
|
||||
* proc interface
|
||||
*/
|
||||
@ -233,4 +233,4 @@ snd_seq_oss_readq_info_read(struct seq_oss_readq *q, struct snd_info_buffer *buf
|
||||
(waitqueue_active(&q->midi_sleep) ? "sleeping":"running"),
|
||||
q->qlen, q->input_time);
|
||||
}
|
||||
#endif /* CONFIG_PROC_FS */
|
||||
#endif /* CONFIG_SND_PROC_FS */
|
||||
|
@ -630,7 +630,7 @@ snd_seq_oss_synth_make_info(struct seq_oss_devinfo *dp, int dev, struct synth_in
|
||||
}
|
||||
|
||||
|
||||
#ifdef CONFIG_PROC_FS
|
||||
#ifdef CONFIG_SND_PROC_FS
|
||||
/*
|
||||
* proc interface
|
||||
*/
|
||||
@ -658,4 +658,4 @@ snd_seq_oss_synth_info_read(struct snd_info_buffer *buf)
|
||||
snd_use_lock_free(&rec->use_lock);
|
||||
}
|
||||
}
|
||||
#endif /* CONFIG_PROC_FS */
|
||||
#endif /* CONFIG_SND_PROC_FS */
|
||||
|
@ -2447,7 +2447,7 @@ EXPORT_SYMBOL(snd_seq_kernel_client_write_poll);
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
|
||||
#ifdef CONFIG_PROC_FS
|
||||
#ifdef CONFIG_SND_PROC_FS
|
||||
/*
|
||||
* /proc interface
|
||||
*/
|
||||
@ -2549,7 +2549,7 @@ void snd_seq_info_clients_read(struct snd_info_entry *entry,
|
||||
snd_seq_client_unlock(client);
|
||||
}
|
||||
}
|
||||
#endif /* CONFIG_PROC_FS */
|
||||
#endif /* CONFIG_SND_PROC_FS */
|
||||
|
||||
/*---------------------------------------------------------------------------*/
|
||||
|
||||
|
@ -72,7 +72,7 @@ static struct bus_type snd_seq_bus_type = {
|
||||
/*
|
||||
* proc interface -- just for compatibility
|
||||
*/
|
||||
#ifdef CONFIG_PROC_FS
|
||||
#ifdef CONFIG_SND_PROC_FS
|
||||
static struct snd_info_entry *info_entry;
|
||||
|
||||
static int print_dev_info(struct device *dev, void *data)
|
||||
@ -272,7 +272,7 @@ EXPORT_SYMBOL_GPL(snd_seq_driver_unregister);
|
||||
|
||||
static int __init seq_dev_proc_init(void)
|
||||
{
|
||||
#ifdef CONFIG_PROC_FS
|
||||
#ifdef CONFIG_SND_PROC_FS
|
||||
info_entry = snd_info_create_module_entry(THIS_MODULE, "drivers",
|
||||
snd_seq_root);
|
||||
if (info_entry == NULL)
|
||||
@ -305,7 +305,7 @@ static void __exit alsa_seq_device_exit(void)
|
||||
#ifdef CONFIG_MODULES
|
||||
cancel_work_sync(&autoload_work);
|
||||
#endif
|
||||
#ifdef CONFIG_PROC_FS
|
||||
#ifdef CONFIG_SND_PROC_FS
|
||||
snd_info_free_entry(info_entry);
|
||||
#endif
|
||||
bus_unregister(&snd_seq_bus_type);
|
||||
|
@ -27,7 +27,6 @@
|
||||
#include "seq_clientmgr.h"
|
||||
#include "seq_timer.h"
|
||||
|
||||
#ifdef CONFIG_PROC_FS
|
||||
static struct snd_info_entry *queues_entry;
|
||||
static struct snd_info_entry *clients_entry;
|
||||
static struct snd_info_entry *timer_entry;
|
||||
@ -51,6 +50,13 @@ create_info_entry(char *name, void (*read)(struct snd_info_entry *,
|
||||
return entry;
|
||||
}
|
||||
|
||||
static void free_info_entries(void)
|
||||
{
|
||||
snd_info_free_entry(queues_entry);
|
||||
snd_info_free_entry(clients_entry);
|
||||
snd_info_free_entry(timer_entry);
|
||||
}
|
||||
|
||||
/* create all our /proc entries */
|
||||
int __init snd_seq_info_init(void)
|
||||
{
|
||||
@ -59,14 +65,17 @@ int __init snd_seq_info_init(void)
|
||||
clients_entry = create_info_entry("clients",
|
||||
snd_seq_info_clients_read);
|
||||
timer_entry = create_info_entry("timer", snd_seq_info_timer_read);
|
||||
if (!queues_entry || !clients_entry || !timer_entry)
|
||||
goto error;
|
||||
return 0;
|
||||
|
||||
error:
|
||||
free_info_entries();
|
||||
return -ENOMEM;
|
||||
}
|
||||
|
||||
int __exit snd_seq_info_done(void)
|
||||
{
|
||||
snd_info_free_entry(queues_entry);
|
||||
snd_info_free_entry(clients_entry);
|
||||
snd_info_free_entry(timer_entry);
|
||||
free_info_entries();
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
@ -29,7 +29,7 @@ void snd_seq_info_timer_read(struct snd_info_entry *entry, struct snd_info_buffe
|
||||
void snd_seq_info_queues_read(struct snd_info_entry *entry, struct snd_info_buffer *buffer);
|
||||
|
||||
|
||||
#ifdef CONFIG_PROC_FS
|
||||
#ifdef CONFIG_SND_PROC_FS
|
||||
int snd_seq_info_init( void );
|
||||
int snd_seq_info_done( void );
|
||||
#else
|
||||
|
@ -753,7 +753,7 @@ int snd_seq_control_queue(struct snd_seq_event *ev, int atomic, int hop)
|
||||
|
||||
/*----------------------------------------------------------------*/
|
||||
|
||||
#ifdef CONFIG_PROC_FS
|
||||
#ifdef CONFIG_SND_PROC_FS
|
||||
/* exported to seq_info.c */
|
||||
void snd_seq_info_queues_read(struct snd_info_entry *entry,
|
||||
struct snd_info_buffer *buffer)
|
||||
@ -787,5 +787,5 @@ void snd_seq_info_queues_read(struct snd_info_entry *entry,
|
||||
queuefree(q);
|
||||
}
|
||||
}
|
||||
#endif /* CONFIG_PROC_FS */
|
||||
#endif /* CONFIG_SND_PROC_FS */
|
||||
|
||||
|
@ -422,7 +422,7 @@ snd_seq_tick_time_t snd_seq_timer_get_cur_tick(struct snd_seq_timer *tmr)
|
||||
}
|
||||
|
||||
|
||||
#ifdef CONFIG_PROC_FS
|
||||
#ifdef CONFIG_SND_PROC_FS
|
||||
/* exported to seq_info.c */
|
||||
void snd_seq_info_timer_read(struct snd_info_entry *entry,
|
||||
struct snd_info_buffer *buffer)
|
||||
@ -449,5 +449,5 @@ void snd_seq_info_timer_read(struct snd_info_entry *entry,
|
||||
queuefree(q);
|
||||
}
|
||||
}
|
||||
#endif /* CONFIG_PROC_FS */
|
||||
#endif /* CONFIG_SND_PROC_FS */
|
||||
|
||||
|
@ -330,13 +330,10 @@ int snd_unregister_device(struct device *dev)
|
||||
}
|
||||
EXPORT_SYMBOL(snd_unregister_device);
|
||||
|
||||
#ifdef CONFIG_PROC_FS
|
||||
#ifdef CONFIG_SND_PROC_FS
|
||||
/*
|
||||
* INFO PART
|
||||
*/
|
||||
|
||||
static struct snd_info_entry *snd_minor_info_entry;
|
||||
|
||||
static const char *snd_device_type_name(int type)
|
||||
{
|
||||
switch (type) {
|
||||
@ -389,23 +386,12 @@ int __init snd_minor_info_init(void)
|
||||
struct snd_info_entry *entry;
|
||||
|
||||
entry = snd_info_create_module_entry(THIS_MODULE, "devices", NULL);
|
||||
if (entry) {
|
||||
entry->c.text.read = snd_minor_info_read;
|
||||
if (snd_info_register(entry) < 0) {
|
||||
snd_info_free_entry(entry);
|
||||
entry = NULL;
|
||||
}
|
||||
}
|
||||
snd_minor_info_entry = entry;
|
||||
return 0;
|
||||
if (!entry)
|
||||
return -ENOMEM;
|
||||
entry->c.text.read = snd_minor_info_read;
|
||||
return snd_info_register(entry); /* freed in error path */
|
||||
}
|
||||
|
||||
int __exit snd_minor_info_done(void)
|
||||
{
|
||||
snd_info_free_entry(snd_minor_info_entry);
|
||||
return 0;
|
||||
}
|
||||
#endif /* CONFIG_PROC_FS */
|
||||
#endif /* CONFIG_SND_PROC_FS */
|
||||
|
||||
/*
|
||||
* INIT PART
|
||||
@ -423,7 +409,6 @@ static int __init alsa_sound_init(void)
|
||||
unregister_chrdev(major, "alsa");
|
||||
return -ENOMEM;
|
||||
}
|
||||
snd_info_minor_register();
|
||||
#ifndef MODULE
|
||||
pr_info("Advanced Linux Sound Architecture Driver Initialized.\n");
|
||||
#endif
|
||||
@ -432,7 +417,6 @@ static int __init alsa_sound_init(void)
|
||||
|
||||
static void __exit alsa_sound_exit(void)
|
||||
{
|
||||
snd_info_minor_unregister();
|
||||
snd_info_done();
|
||||
unregister_chrdev(major, "alsa");
|
||||
}
|
||||
|
@ -19,12 +19,6 @@
|
||||
*
|
||||
*/
|
||||
|
||||
#ifdef CONFIG_SND_OSSEMUL
|
||||
|
||||
#if !IS_ENABLED(CONFIG_SOUND)
|
||||
#error "Enable the OSS soundcore multiplexer (CONFIG_SOUND) in the kernel."
|
||||
#endif
|
||||
|
||||
#include <linux/init.h>
|
||||
#include <linux/export.h>
|
||||
#include <linux/slab.h>
|
||||
@ -213,10 +207,7 @@ EXPORT_SYMBOL(snd_unregister_oss_device);
|
||||
* INFO PART
|
||||
*/
|
||||
|
||||
#ifdef CONFIG_PROC_FS
|
||||
|
||||
static struct snd_info_entry *snd_minor_info_oss_entry;
|
||||
|
||||
#ifdef CONFIG_SND_PROC_FS
|
||||
static const char *snd_oss_device_type_name(int type)
|
||||
{
|
||||
switch (type) {
|
||||
@ -263,22 +254,9 @@ int __init snd_minor_info_oss_init(void)
|
||||
struct snd_info_entry *entry;
|
||||
|
||||
entry = snd_info_create_module_entry(THIS_MODULE, "devices", snd_oss_root);
|
||||
if (entry) {
|
||||
entry->c.text.read = snd_minor_info_oss_read;
|
||||
if (snd_info_register(entry) < 0) {
|
||||
snd_info_free_entry(entry);
|
||||
entry = NULL;
|
||||
}
|
||||
}
|
||||
snd_minor_info_oss_entry = entry;
|
||||
return 0;
|
||||
if (!entry)
|
||||
return -ENOMEM;
|
||||
entry->c.text.read = snd_minor_info_oss_read;
|
||||
return snd_info_register(entry); /* freed in error path */
|
||||
}
|
||||
|
||||
int __exit snd_minor_info_oss_done(void)
|
||||
{
|
||||
snd_info_free_entry(snd_minor_info_oss_entry);
|
||||
return 0;
|
||||
}
|
||||
#endif /* CONFIG_PROC_FS */
|
||||
|
||||
#endif /* CONFIG_SND_OSSEMUL */
|
||||
#endif /* CONFIG_SND_PROC_FS */
|
||||
|
@ -1034,7 +1034,7 @@ static int snd_timer_register_system(void)
|
||||
return snd_timer_global_register(timer);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PROC_FS
|
||||
#ifdef CONFIG_SND_PROC_FS
|
||||
/*
|
||||
* Info interface
|
||||
*/
|
||||
@ -1104,7 +1104,7 @@ static void __exit snd_timer_proc_done(void)
|
||||
{
|
||||
snd_info_free_entry(snd_timer_proc_entry);
|
||||
}
|
||||
#else /* !CONFIG_PROC_FS */
|
||||
#else /* !CONFIG_SND_PROC_FS */
|
||||
#define snd_timer_proc_init()
|
||||
#define snd_timer_proc_done()
|
||||
#endif
|
||||
|
@ -1053,8 +1053,6 @@ static int loopback_mixer_new(struct loopback *loopback, int notify)
|
||||
return 0;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PROC_FS
|
||||
|
||||
static void print_dpcm_info(struct snd_info_buffer *buffer,
|
||||
struct loopback_pcm *dpcm,
|
||||
const char *id)
|
||||
@ -1128,12 +1126,6 @@ static int loopback_proc_new(struct loopback *loopback, int cidx)
|
||||
return 0;
|
||||
}
|
||||
|
||||
#else /* !CONFIG_PROC_FS */
|
||||
|
||||
#define loopback_proc_new(loopback, cidx) do { } while (0)
|
||||
|
||||
#endif
|
||||
|
||||
static int loopback_probe(struct platform_device *devptr)
|
||||
{
|
||||
struct snd_card *card;
|
||||
|
@ -156,13 +156,13 @@ static int emu10k1_playback_constraints(struct snd_pcm_runtime *runtime)
|
||||
return 0;
|
||||
}
|
||||
|
||||
struct dummy_model model_emu10k1 = {
|
||||
static struct dummy_model model_emu10k1 = {
|
||||
.name = "emu10k1",
|
||||
.playback_constraints = emu10k1_playback_constraints,
|
||||
.buffer_bytes_max = 128 * 1024,
|
||||
};
|
||||
|
||||
struct dummy_model model_rme9652 = {
|
||||
static struct dummy_model model_rme9652 = {
|
||||
.name = "rme9652",
|
||||
.buffer_bytes_max = 26 * 64 * 1024,
|
||||
.formats = SNDRV_PCM_FMTBIT_S32_LE,
|
||||
@ -172,7 +172,7 @@ struct dummy_model model_rme9652 = {
|
||||
.periods_max = 2,
|
||||
};
|
||||
|
||||
struct dummy_model model_ice1712 = {
|
||||
static struct dummy_model model_ice1712 = {
|
||||
.name = "ice1712",
|
||||
.buffer_bytes_max = 256 * 1024,
|
||||
.formats = SNDRV_PCM_FMTBIT_S32_LE,
|
||||
@ -182,7 +182,7 @@ struct dummy_model model_ice1712 = {
|
||||
.periods_max = 1024,
|
||||
};
|
||||
|
||||
struct dummy_model model_uda1341 = {
|
||||
static struct dummy_model model_uda1341 = {
|
||||
.name = "uda1341",
|
||||
.buffer_bytes_max = 16380,
|
||||
.formats = SNDRV_PCM_FMTBIT_S16_LE,
|
||||
@ -192,7 +192,7 @@ struct dummy_model model_uda1341 = {
|
||||
.periods_max = 255,
|
||||
};
|
||||
|
||||
struct dummy_model model_ac97 = {
|
||||
static struct dummy_model model_ac97 = {
|
||||
.name = "ac97",
|
||||
.formats = SNDRV_PCM_FMTBIT_S16_LE,
|
||||
.channels_min = 2,
|
||||
@ -202,7 +202,7 @@ struct dummy_model model_ac97 = {
|
||||
.rate_max = 48000,
|
||||
};
|
||||
|
||||
struct dummy_model model_ca0106 = {
|
||||
static struct dummy_model model_ca0106 = {
|
||||
.name = "ca0106",
|
||||
.formats = SNDRV_PCM_FMTBIT_S16_LE,
|
||||
.buffer_bytes_max = ((65536-64)*8),
|
||||
@ -216,7 +216,7 @@ struct dummy_model model_ca0106 = {
|
||||
.rate_max = 192000,
|
||||
};
|
||||
|
||||
struct dummy_model *dummy_models[] = {
|
||||
static struct dummy_model *dummy_models[] = {
|
||||
&model_emu10k1,
|
||||
&model_rme9652,
|
||||
&model_ice1712,
|
||||
@ -914,7 +914,7 @@ static int snd_card_dummy_new_mixer(struct snd_dummy *dummy)
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if defined(CONFIG_SND_DEBUG) && defined(CONFIG_PROC_FS)
|
||||
#if defined(CONFIG_SND_DEBUG) && defined(CONFIG_SND_PROC_FS)
|
||||
/*
|
||||
* proc interface
|
||||
*/
|
||||
@ -1042,7 +1042,7 @@ static void dummy_proc_init(struct snd_dummy *chip)
|
||||
}
|
||||
#else
|
||||
#define dummy_proc_init(x)
|
||||
#endif /* CONFIG_SND_DEBUG && CONFIG_PROC_FS */
|
||||
#endif /* CONFIG_SND_DEBUG && CONFIG_SND_PROC_FS */
|
||||
|
||||
static int snd_dummy_probe(struct platform_device *devptr)
|
||||
{
|
||||
|
@ -3,7 +3,8 @@
|
||||
# Copyright (c) 2001 by Jaroslav Kysela <perex@perex.cz>
|
||||
#
|
||||
|
||||
snd-opl4-lib-objs := opl4_lib.o opl4_mixer.o opl4_proc.o
|
||||
snd-opl4-lib-objs := opl4_lib.o opl4_mixer.o
|
||||
snd-opl4-lib-$(CONFIG_SND_PROC_FS) += opl4_proc.o
|
||||
snd-opl4-synth-objs := opl4_seq.o opl4_synth.o yrw801.o
|
||||
|
||||
obj-$(CONFIG_SND_OPL4_LIB) += snd-opl4-lib.o
|
||||
|
@ -176,9 +176,7 @@ static int snd_opl4_create_seq_dev(struct snd_opl4 *opl4, int seq_device)
|
||||
|
||||
static void snd_opl4_free(struct snd_opl4 *opl4)
|
||||
{
|
||||
#ifdef CONFIG_PROC_FS
|
||||
snd_opl4_free_proc(opl4);
|
||||
#endif
|
||||
release_and_free_resource(opl4->res_fm_port);
|
||||
release_and_free_resource(opl4->res_pcm_port);
|
||||
kfree(opl4);
|
||||
@ -249,9 +247,7 @@ int snd_opl4_create(struct snd_card *card,
|
||||
snd_opl4_enable_opl4(opl4);
|
||||
|
||||
snd_opl4_create_mixer(opl4);
|
||||
#ifdef CONFIG_PROC_FS
|
||||
snd_opl4_create_proc(opl4);
|
||||
#endif
|
||||
|
||||
#if defined(CONFIG_SND_SEQUENCER) || (defined(MODULE) && defined(CONFIG_SND_SEQUENCER_MODULE))
|
||||
opl4->seq_client = -1;
|
||||
|
@ -178,7 +178,7 @@ struct snd_opl4 {
|
||||
spinlock_t reg_lock;
|
||||
struct snd_card *card;
|
||||
|
||||
#ifdef CONFIG_PROC_FS
|
||||
#ifdef CONFIG_SND_PROC_FS
|
||||
struct snd_info_entry *proc_entry;
|
||||
int memory_access;
|
||||
#endif
|
||||
@ -207,10 +207,13 @@ void snd_opl4_write_memory(struct snd_opl4 *opl4, const char *buf, int offset, i
|
||||
/* opl4_mixer.c */
|
||||
int snd_opl4_create_mixer(struct snd_opl4 *opl4);
|
||||
|
||||
#ifdef CONFIG_PROC_FS
|
||||
#ifdef CONFIG_SND_PROC_FS
|
||||
/* opl4_proc.c */
|
||||
int snd_opl4_create_proc(struct snd_opl4 *opl4);
|
||||
void snd_opl4_free_proc(struct snd_opl4 *opl4);
|
||||
#else
|
||||
static inline int snd_opl4_create_proc(struct snd_opl4 *opl4) { return 0; }
|
||||
static inline void snd_opl4_free_proc(struct snd_opl4 *opl4) {}
|
||||
#endif
|
||||
|
||||
/* opl4_seq.c */
|
||||
|
@ -22,8 +22,6 @@
|
||||
#include <linux/export.h>
|
||||
#include <sound/info.h>
|
||||
|
||||
#ifdef CONFIG_PROC_FS
|
||||
|
||||
static int snd_opl4_mem_proc_open(struct snd_info_entry *entry,
|
||||
unsigned short mode, void **file_private_data)
|
||||
{
|
||||
@ -129,5 +127,3 @@ void snd_opl4_free_proc(struct snd_opl4 *opl4)
|
||||
{
|
||||
snd_info_free_entry(opl4->proc_entry);
|
||||
}
|
||||
|
||||
#endif /* CONFIG_PROC_FS */
|
||||
|
@ -95,6 +95,7 @@ config SND_BEBOB
|
||||
* Tascam IF-FW/DM
|
||||
* Behringer XENIX UFX 1204/1604
|
||||
* Behringer Digital Mixer X32 series (X-UF Card)
|
||||
* Behringer FCA610/1616
|
||||
* Apogee Rosetta 200/400 (X-FireWire card)
|
||||
* Apogee DA/AD/DD-16X (X-FireWire card)
|
||||
* Apogee Ensemble
|
||||
@ -114,6 +115,7 @@ config SND_BEBOB
|
||||
* M-Audio FireWire410/AudioPhile/Solo
|
||||
* M-Audio Ozonic/NRV10/ProfireLightBridge
|
||||
* M-Audio FireWire 1814/ProjectMix IO
|
||||
* Digidesign Mbox 2 Pro
|
||||
|
||||
To compile this driver as a module, choose M here: the module
|
||||
will be called snd-bebob.
|
||||
|
@ -40,24 +40,28 @@
|
||||
#define TAG_CIP 1
|
||||
|
||||
/* common isochronous packet header parameters */
|
||||
#define CIP_EOH (1u << 31)
|
||||
#define CIP_EOH_SHIFT 31
|
||||
#define CIP_EOH (1u << CIP_EOH_SHIFT)
|
||||
#define CIP_EOH_MASK 0x80000000
|
||||
#define CIP_FMT_AM (0x10 << 24)
|
||||
#define CIP_SID_SHIFT 24
|
||||
#define CIP_SID_MASK 0x3f000000
|
||||
#define CIP_DBS_MASK 0x00ff0000
|
||||
#define CIP_DBS_SHIFT 16
|
||||
#define CIP_DBC_MASK 0x000000ff
|
||||
#define CIP_FMT_SHIFT 24
|
||||
#define CIP_FMT_MASK 0x3f000000
|
||||
#define CIP_FDF_MASK 0x00ff0000
|
||||
#define CIP_FDF_SHIFT 16
|
||||
#define CIP_SYT_MASK 0x0000ffff
|
||||
#define CIP_SYT_NO_INFO 0xffff
|
||||
#define CIP_FDF_MASK 0x00ff0000
|
||||
#define CIP_FDF_SFC_SHIFT 16
|
||||
|
||||
/*
|
||||
* Audio and Music transfer protocol specific parameters
|
||||
* only "Clock-based rate control mode" is supported
|
||||
*/
|
||||
#define AMDTP_FDF_AM824 (0 << (CIP_FDF_SFC_SHIFT + 3))
|
||||
#define CIP_FMT_AM (0x10 << CIP_FMT_SHIFT)
|
||||
#define AMDTP_FDF_AM824 (0 << (CIP_FDF_SHIFT + 3))
|
||||
#define AMDTP_FDF_NO_DATA 0xff
|
||||
#define AMDTP_DBS_MASK 0x00ff0000
|
||||
#define AMDTP_DBS_SHIFT 16
|
||||
#define AMDTP_DBC_MASK 0x000000ff
|
||||
|
||||
/* TODO: make these configurable */
|
||||
#define INTERRUPT_INTERVAL 16
|
||||
@ -251,19 +255,24 @@ EXPORT_SYMBOL(amdtp_stream_set_parameters);
|
||||
*/
|
||||
unsigned int amdtp_stream_get_max_payload(struct amdtp_stream *s)
|
||||
{
|
||||
return 8 + s->syt_interval * s->data_block_quadlets * 4;
|
||||
unsigned int multiplier = 1;
|
||||
|
||||
if (s->flags & CIP_JUMBO_PAYLOAD)
|
||||
multiplier = 5;
|
||||
|
||||
return 8 + s->syt_interval * s->data_block_quadlets * 4 * multiplier;
|
||||
}
|
||||
EXPORT_SYMBOL(amdtp_stream_get_max_payload);
|
||||
|
||||
static void amdtp_write_s16(struct amdtp_stream *s,
|
||||
struct snd_pcm_substream *pcm,
|
||||
__be32 *buffer, unsigned int frames);
|
||||
static void amdtp_write_s32(struct amdtp_stream *s,
|
||||
struct snd_pcm_substream *pcm,
|
||||
__be32 *buffer, unsigned int frames);
|
||||
static void amdtp_read_s32(struct amdtp_stream *s,
|
||||
struct snd_pcm_substream *pcm,
|
||||
__be32 *buffer, unsigned int frames);
|
||||
static void write_pcm_s16(struct amdtp_stream *s,
|
||||
struct snd_pcm_substream *pcm,
|
||||
__be32 *buffer, unsigned int frames);
|
||||
static void write_pcm_s32(struct amdtp_stream *s,
|
||||
struct snd_pcm_substream *pcm,
|
||||
__be32 *buffer, unsigned int frames);
|
||||
static void read_pcm_s32(struct amdtp_stream *s,
|
||||
struct snd_pcm_substream *pcm,
|
||||
__be32 *buffer, unsigned int frames);
|
||||
|
||||
/**
|
||||
* amdtp_stream_set_pcm_format - set the PCM format
|
||||
@ -286,16 +295,16 @@ void amdtp_stream_set_pcm_format(struct amdtp_stream *s,
|
||||
/* fall through */
|
||||
case SNDRV_PCM_FORMAT_S16:
|
||||
if (s->direction == AMDTP_OUT_STREAM) {
|
||||
s->transfer_samples = amdtp_write_s16;
|
||||
s->transfer_samples = write_pcm_s16;
|
||||
break;
|
||||
}
|
||||
WARN_ON(1);
|
||||
/* fall through */
|
||||
case SNDRV_PCM_FORMAT_S32:
|
||||
if (s->direction == AMDTP_OUT_STREAM)
|
||||
s->transfer_samples = amdtp_write_s32;
|
||||
s->transfer_samples = write_pcm_s32;
|
||||
else
|
||||
s->transfer_samples = amdtp_read_s32;
|
||||
s->transfer_samples = read_pcm_s32;
|
||||
break;
|
||||
}
|
||||
}
|
||||
@ -316,17 +325,25 @@ void amdtp_stream_pcm_prepare(struct amdtp_stream *s)
|
||||
}
|
||||
EXPORT_SYMBOL(amdtp_stream_pcm_prepare);
|
||||
|
||||
static unsigned int calculate_data_blocks(struct amdtp_stream *s)
|
||||
static unsigned int calculate_data_blocks(struct amdtp_stream *s,
|
||||
unsigned int syt)
|
||||
{
|
||||
unsigned int phase, data_blocks;
|
||||
|
||||
if (s->flags & CIP_BLOCKING)
|
||||
data_blocks = s->syt_interval;
|
||||
else if (!cip_sfc_is_base_44100(s->sfc)) {
|
||||
/* Sample_rate / 8000 is an integer, and precomputed. */
|
||||
data_blocks = s->data_block_state;
|
||||
/* Blocking mode. */
|
||||
if (s->flags & CIP_BLOCKING) {
|
||||
/* This module generate empty packet for 'no data'. */
|
||||
if (syt == CIP_SYT_NO_INFO)
|
||||
data_blocks = 0;
|
||||
else
|
||||
data_blocks = s->syt_interval;
|
||||
/* Non-blocking mode. */
|
||||
} else {
|
||||
phase = s->data_block_state;
|
||||
if (!cip_sfc_is_base_44100(s->sfc)) {
|
||||
/* Sample_rate / 8000 is an integer, and precomputed. */
|
||||
data_blocks = s->data_block_state;
|
||||
} else {
|
||||
phase = s->data_block_state;
|
||||
|
||||
/*
|
||||
* This calculates the number of data blocks per packet so that
|
||||
@ -336,16 +353,17 @@ static unsigned int calculate_data_blocks(struct amdtp_stream *s)
|
||||
* as possible in the sequence (to prevent underruns of the
|
||||
* device's buffer).
|
||||
*/
|
||||
if (s->sfc == CIP_SFC_44100)
|
||||
/* 6 6 5 6 5 6 5 ... */
|
||||
data_blocks = 5 + ((phase & 1) ^
|
||||
(phase == 0 || phase >= 40));
|
||||
else
|
||||
/* 12 11 11 11 11 ... or 23 22 22 22 22 ... */
|
||||
data_blocks = 11 * (s->sfc >> 1) + (phase == 0);
|
||||
if (++phase >= (80 >> (s->sfc >> 1)))
|
||||
phase = 0;
|
||||
s->data_block_state = phase;
|
||||
if (s->sfc == CIP_SFC_44100)
|
||||
/* 6 6 5 6 5 6 5 ... */
|
||||
data_blocks = 5 + ((phase & 1) ^
|
||||
(phase == 0 || phase >= 40));
|
||||
else
|
||||
/* 12 11 11 11 11 ... or 23 22 22 22 22 ... */
|
||||
data_blocks = 11 * (s->sfc >> 1) + (phase == 0);
|
||||
if (++phase >= (80 >> (s->sfc >> 1)))
|
||||
phase = 0;
|
||||
s->data_block_state = phase;
|
||||
}
|
||||
}
|
||||
|
||||
return data_blocks;
|
||||
@ -394,9 +412,9 @@ static unsigned int calculate_syt(struct amdtp_stream *s,
|
||||
}
|
||||
}
|
||||
|
||||
static void amdtp_write_s32(struct amdtp_stream *s,
|
||||
struct snd_pcm_substream *pcm,
|
||||
__be32 *buffer, unsigned int frames)
|
||||
static void write_pcm_s32(struct amdtp_stream *s,
|
||||
struct snd_pcm_substream *pcm,
|
||||
__be32 *buffer, unsigned int frames)
|
||||
{
|
||||
struct snd_pcm_runtime *runtime = pcm->runtime;
|
||||
unsigned int channels, remaining_frames, i, c;
|
||||
@ -419,9 +437,9 @@ static void amdtp_write_s32(struct amdtp_stream *s,
|
||||
}
|
||||
}
|
||||
|
||||
static void amdtp_write_s16(struct amdtp_stream *s,
|
||||
struct snd_pcm_substream *pcm,
|
||||
__be32 *buffer, unsigned int frames)
|
||||
static void write_pcm_s16(struct amdtp_stream *s,
|
||||
struct snd_pcm_substream *pcm,
|
||||
__be32 *buffer, unsigned int frames)
|
||||
{
|
||||
struct snd_pcm_runtime *runtime = pcm->runtime;
|
||||
unsigned int channels, remaining_frames, i, c;
|
||||
@ -444,9 +462,9 @@ static void amdtp_write_s16(struct amdtp_stream *s,
|
||||
}
|
||||
}
|
||||
|
||||
static void amdtp_read_s32(struct amdtp_stream *s,
|
||||
struct snd_pcm_substream *pcm,
|
||||
__be32 *buffer, unsigned int frames)
|
||||
static void read_pcm_s32(struct amdtp_stream *s,
|
||||
struct snd_pcm_substream *pcm,
|
||||
__be32 *buffer, unsigned int frames)
|
||||
{
|
||||
struct snd_pcm_runtime *runtime = pcm->runtime;
|
||||
unsigned int channels, remaining_frames, i, c;
|
||||
@ -468,8 +486,8 @@ static void amdtp_read_s32(struct amdtp_stream *s,
|
||||
}
|
||||
}
|
||||
|
||||
static void amdtp_fill_pcm_silence(struct amdtp_stream *s,
|
||||
__be32 *buffer, unsigned int frames)
|
||||
static void write_pcm_silence(struct amdtp_stream *s,
|
||||
__be32 *buffer, unsigned int frames)
|
||||
{
|
||||
unsigned int i, c;
|
||||
|
||||
@ -510,8 +528,8 @@ static void midi_rate_use_one_byte(struct amdtp_stream *s, unsigned int port)
|
||||
s->midi_fifo_used[port] += amdtp_rate_table[s->sfc];
|
||||
}
|
||||
|
||||
static void amdtp_fill_midi(struct amdtp_stream *s,
|
||||
__be32 *buffer, unsigned int frames)
|
||||
static void write_midi_messages(struct amdtp_stream *s,
|
||||
__be32 *buffer, unsigned int frames)
|
||||
{
|
||||
unsigned int f, port;
|
||||
u8 *b;
|
||||
@ -537,8 +555,8 @@ static void amdtp_fill_midi(struct amdtp_stream *s,
|
||||
}
|
||||
}
|
||||
|
||||
static void amdtp_pull_midi(struct amdtp_stream *s,
|
||||
__be32 *buffer, unsigned int frames)
|
||||
static void read_midi_messages(struct amdtp_stream *s,
|
||||
__be32 *buffer, unsigned int frames)
|
||||
{
|
||||
unsigned int f, port;
|
||||
int len;
|
||||
@ -633,57 +651,48 @@ static inline int queue_in_packet(struct amdtp_stream *s)
|
||||
amdtp_stream_get_max_payload(s), false);
|
||||
}
|
||||
|
||||
static void handle_out_packet(struct amdtp_stream *s, unsigned int syt)
|
||||
static int handle_out_packet(struct amdtp_stream *s, unsigned int data_blocks,
|
||||
unsigned int syt)
|
||||
{
|
||||
__be32 *buffer;
|
||||
unsigned int data_blocks, payload_length;
|
||||
unsigned int payload_length;
|
||||
struct snd_pcm_substream *pcm;
|
||||
|
||||
if (s->packet_index < 0)
|
||||
return;
|
||||
|
||||
/* this module generate empty packet for 'no data' */
|
||||
if (!(s->flags & CIP_BLOCKING) || (syt != CIP_SYT_NO_INFO))
|
||||
data_blocks = calculate_data_blocks(s);
|
||||
else
|
||||
data_blocks = 0;
|
||||
|
||||
buffer = s->buffer.packets[s->packet_index].buffer;
|
||||
buffer[0] = cpu_to_be32(ACCESS_ONCE(s->source_node_id_field) |
|
||||
(s->data_block_quadlets << AMDTP_DBS_SHIFT) |
|
||||
(s->data_block_quadlets << CIP_DBS_SHIFT) |
|
||||
s->data_block_counter);
|
||||
buffer[1] = cpu_to_be32(CIP_EOH | CIP_FMT_AM | AMDTP_FDF_AM824 |
|
||||
(s->sfc << CIP_FDF_SFC_SHIFT) | syt);
|
||||
(s->sfc << CIP_FDF_SHIFT) | syt);
|
||||
buffer += 2;
|
||||
|
||||
pcm = ACCESS_ONCE(s->pcm);
|
||||
if (pcm)
|
||||
s->transfer_samples(s, pcm, buffer, data_blocks);
|
||||
else
|
||||
amdtp_fill_pcm_silence(s, buffer, data_blocks);
|
||||
write_pcm_silence(s, buffer, data_blocks);
|
||||
if (s->midi_ports)
|
||||
amdtp_fill_midi(s, buffer, data_blocks);
|
||||
write_midi_messages(s, buffer, data_blocks);
|
||||
|
||||
s->data_block_counter = (s->data_block_counter + data_blocks) & 0xff;
|
||||
|
||||
payload_length = 8 + data_blocks * 4 * s->data_block_quadlets;
|
||||
if (queue_out_packet(s, payload_length, false) < 0) {
|
||||
s->packet_index = -1;
|
||||
amdtp_stream_pcm_abort(s);
|
||||
return;
|
||||
}
|
||||
if (queue_out_packet(s, payload_length, false) < 0)
|
||||
return -EIO;
|
||||
|
||||
if (pcm)
|
||||
update_pcm_pointers(s, pcm, data_blocks);
|
||||
|
||||
/* No need to return the number of handled data blocks. */
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void handle_in_packet(struct amdtp_stream *s,
|
||||
unsigned int payload_quadlets,
|
||||
__be32 *buffer)
|
||||
static int handle_in_packet(struct amdtp_stream *s,
|
||||
unsigned int payload_quadlets, __be32 *buffer,
|
||||
unsigned int *data_blocks)
|
||||
{
|
||||
u32 cip_header[2];
|
||||
unsigned int data_blocks, data_block_quadlets, data_block_counter,
|
||||
dbc_interval;
|
||||
unsigned int data_block_quadlets, data_block_counter, dbc_interval;
|
||||
struct snd_pcm_substream *pcm = NULL;
|
||||
bool lost;
|
||||
|
||||
@ -700,33 +709,34 @@ static void handle_in_packet(struct amdtp_stream *s,
|
||||
dev_info_ratelimited(&s->unit->device,
|
||||
"Invalid CIP header for AMDTP: %08X:%08X\n",
|
||||
cip_header[0], cip_header[1]);
|
||||
*data_blocks = 0;
|
||||
goto end;
|
||||
}
|
||||
|
||||
/* Calculate data blocks */
|
||||
if (payload_quadlets < 3 ||
|
||||
((cip_header[1] & CIP_FDF_MASK) ==
|
||||
(AMDTP_FDF_NO_DATA << CIP_FDF_SFC_SHIFT))) {
|
||||
data_blocks = 0;
|
||||
(AMDTP_FDF_NO_DATA << CIP_FDF_SHIFT))) {
|
||||
*data_blocks = 0;
|
||||
} else {
|
||||
data_block_quadlets =
|
||||
(cip_header[0] & AMDTP_DBS_MASK) >> AMDTP_DBS_SHIFT;
|
||||
(cip_header[0] & CIP_DBS_MASK) >> CIP_DBS_SHIFT;
|
||||
/* avoid division by zero */
|
||||
if (data_block_quadlets == 0) {
|
||||
dev_info_ratelimited(&s->unit->device,
|
||||
dev_err(&s->unit->device,
|
||||
"Detect invalid value in dbs field: %08X\n",
|
||||
cip_header[0]);
|
||||
goto err;
|
||||
return -EPROTO;
|
||||
}
|
||||
if (s->flags & CIP_WRONG_DBS)
|
||||
data_block_quadlets = s->data_block_quadlets;
|
||||
|
||||
data_blocks = (payload_quadlets - 2) / data_block_quadlets;
|
||||
*data_blocks = (payload_quadlets - 2) / data_block_quadlets;
|
||||
}
|
||||
|
||||
/* Check data block counter continuity */
|
||||
data_block_counter = cip_header[0] & AMDTP_DBC_MASK;
|
||||
if (data_blocks == 0 && (s->flags & CIP_EMPTY_HAS_WRONG_DBC) &&
|
||||
data_block_counter = cip_header[0] & CIP_DBC_MASK;
|
||||
if (*data_blocks == 0 && (s->flags & CIP_EMPTY_HAS_WRONG_DBC) &&
|
||||
s->data_block_counter != UINT_MAX)
|
||||
data_block_counter = s->data_block_counter;
|
||||
|
||||
@ -736,49 +746,46 @@ static void handle_in_packet(struct amdtp_stream *s,
|
||||
} else if (!(s->flags & CIP_DBC_IS_END_EVENT)) {
|
||||
lost = data_block_counter != s->data_block_counter;
|
||||
} else {
|
||||
if ((data_blocks > 0) && (s->tx_dbc_interval > 0))
|
||||
if ((*data_blocks > 0) && (s->tx_dbc_interval > 0))
|
||||
dbc_interval = s->tx_dbc_interval;
|
||||
else
|
||||
dbc_interval = data_blocks;
|
||||
dbc_interval = *data_blocks;
|
||||
|
||||
lost = data_block_counter !=
|
||||
((s->data_block_counter + dbc_interval) & 0xff);
|
||||
}
|
||||
|
||||
if (lost) {
|
||||
dev_info(&s->unit->device,
|
||||
"Detect discontinuity of CIP: %02X %02X\n",
|
||||
s->data_block_counter, data_block_counter);
|
||||
goto err;
|
||||
dev_err(&s->unit->device,
|
||||
"Detect discontinuity of CIP: %02X %02X\n",
|
||||
s->data_block_counter, data_block_counter);
|
||||
return -EIO;
|
||||
}
|
||||
|
||||
if (data_blocks > 0) {
|
||||
if (*data_blocks > 0) {
|
||||
buffer += 2;
|
||||
|
||||
pcm = ACCESS_ONCE(s->pcm);
|
||||
if (pcm)
|
||||
s->transfer_samples(s, pcm, buffer, data_blocks);
|
||||
s->transfer_samples(s, pcm, buffer, *data_blocks);
|
||||
|
||||
if (s->midi_ports)
|
||||
amdtp_pull_midi(s, buffer, data_blocks);
|
||||
read_midi_messages(s, buffer, *data_blocks);
|
||||
}
|
||||
|
||||
if (s->flags & CIP_DBC_IS_END_EVENT)
|
||||
s->data_block_counter = data_block_counter;
|
||||
else
|
||||
s->data_block_counter =
|
||||
(data_block_counter + data_blocks) & 0xff;
|
||||
(data_block_counter + *data_blocks) & 0xff;
|
||||
end:
|
||||
if (queue_in_packet(s) < 0)
|
||||
goto err;
|
||||
return -EIO;
|
||||
|
||||
if (pcm)
|
||||
update_pcm_pointers(s, pcm, data_blocks);
|
||||
update_pcm_pointers(s, pcm, *data_blocks);
|
||||
|
||||
return;
|
||||
err:
|
||||
s->packet_index = -1;
|
||||
amdtp_stream_pcm_abort(s);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void out_stream_callback(struct fw_iso_context *context, u32 cycle,
|
||||
@ -787,6 +794,10 @@ static void out_stream_callback(struct fw_iso_context *context, u32 cycle,
|
||||
{
|
||||
struct amdtp_stream *s = private_data;
|
||||
unsigned int i, syt, packets = header_length / 4;
|
||||
unsigned int data_blocks;
|
||||
|
||||
if (s->packet_index < 0)
|
||||
return;
|
||||
|
||||
/*
|
||||
* Compute the cycle of the last queued packet.
|
||||
@ -797,8 +808,15 @@ static void out_stream_callback(struct fw_iso_context *context, u32 cycle,
|
||||
|
||||
for (i = 0; i < packets; ++i) {
|
||||
syt = calculate_syt(s, ++cycle);
|
||||
handle_out_packet(s, syt);
|
||||
data_blocks = calculate_data_blocks(s, syt);
|
||||
|
||||
if (handle_out_packet(s, data_blocks, syt) < 0) {
|
||||
s->packet_index = -1;
|
||||
amdtp_stream_pcm_abort(s);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
fw_iso_context_queue_flush(s->context);
|
||||
}
|
||||
|
||||
@ -807,32 +825,55 @@ static void in_stream_callback(struct fw_iso_context *context, u32 cycle,
|
||||
void *private_data)
|
||||
{
|
||||
struct amdtp_stream *s = private_data;
|
||||
unsigned int p, syt, packets, payload_quadlets;
|
||||
unsigned int p, syt, packets;
|
||||
unsigned int payload_quadlets, max_payload_quadlets;
|
||||
unsigned int data_blocks;
|
||||
__be32 *buffer, *headers = header;
|
||||
|
||||
if (s->packet_index < 0)
|
||||
return;
|
||||
|
||||
/* The number of packets in buffer */
|
||||
packets = header_length / IN_PACKET_HEADER_SIZE;
|
||||
|
||||
/* For buffer-over-run prevention. */
|
||||
max_payload_quadlets = amdtp_stream_get_max_payload(s) / 4;
|
||||
|
||||
for (p = 0; p < packets; p++) {
|
||||
if (s->packet_index < 0)
|
||||
break;
|
||||
|
||||
buffer = s->buffer.packets[s->packet_index].buffer;
|
||||
|
||||
/* Process sync slave stream */
|
||||
if (s->sync_slave && s->sync_slave->callbacked) {
|
||||
syt = be32_to_cpu(buffer[1]) & CIP_SYT_MASK;
|
||||
handle_out_packet(s->sync_slave, syt);
|
||||
}
|
||||
|
||||
/* The number of quadlets in this packet */
|
||||
payload_quadlets =
|
||||
(be32_to_cpu(headers[p]) >> ISO_DATA_LENGTH_SHIFT) / 4;
|
||||
handle_in_packet(s, payload_quadlets, buffer);
|
||||
if (payload_quadlets > max_payload_quadlets) {
|
||||
dev_err(&s->unit->device,
|
||||
"Detect jumbo payload: %02x %02x\n",
|
||||
payload_quadlets, max_payload_quadlets);
|
||||
s->packet_index = -1;
|
||||
break;
|
||||
}
|
||||
|
||||
if (handle_in_packet(s, payload_quadlets, buffer,
|
||||
&data_blocks) < 0) {
|
||||
s->packet_index = -1;
|
||||
break;
|
||||
}
|
||||
|
||||
/* Process sync slave stream */
|
||||
if (s->sync_slave && s->sync_slave->callbacked) {
|
||||
syt = be32_to_cpu(buffer[1]) & CIP_SYT_MASK;
|
||||
if (handle_out_packet(s->sync_slave,
|
||||
data_blocks, syt) < 0) {
|
||||
s->packet_index = -1;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Queueing error or detecting discontinuity */
|
||||
if (s->packet_index < 0) {
|
||||
amdtp_stream_pcm_abort(s);
|
||||
|
||||
/* Abort sync slave. */
|
||||
if (s->sync_slave) {
|
||||
s->sync_slave->packet_index = -1;
|
||||
@ -872,7 +913,7 @@ static void amdtp_stream_first_callback(struct fw_iso_context *context,
|
||||
|
||||
if (s->direction == AMDTP_IN_STREAM)
|
||||
context->callback.sc = in_stream_callback;
|
||||
else if ((s->flags & CIP_BLOCKING) && (s->flags & CIP_SYNC_TO_DEVICE))
|
||||
else if (s->flags & CIP_SYNC_TO_DEVICE)
|
||||
context->callback.sc = slave_stream_callback;
|
||||
else
|
||||
context->callback.sc = out_stream_callback;
|
||||
@ -1013,8 +1054,10 @@ EXPORT_SYMBOL(amdtp_stream_pcm_pointer);
|
||||
*/
|
||||
void amdtp_stream_update(struct amdtp_stream *s)
|
||||
{
|
||||
/* Precomputing. */
|
||||
ACCESS_ONCE(s->source_node_id_field) =
|
||||
(fw_parent_device(s->unit)->card->node_id & 0x3f) << 24;
|
||||
(fw_parent_device(s->unit)->card->node_id << CIP_SID_SHIFT) &
|
||||
CIP_SID_MASK;
|
||||
}
|
||||
EXPORT_SYMBOL(amdtp_stream_update);
|
||||
|
||||
|
@ -29,6 +29,9 @@
|
||||
* packet is not continuous from an initial value.
|
||||
* @CIP_EMPTY_HAS_WRONG_DBC: Only for in-stream. The value of dbc in empty
|
||||
* packet is wrong but the others are correct.
|
||||
* @CIP_JUMBO_PAYLOAD: Only for in-stream. The number of data blocks in an
|
||||
* packet is larger than IEC 61883-6 defines. Current implementation
|
||||
* allows 5 times as large as IEC 61883-6 defines.
|
||||
*/
|
||||
enum cip_flags {
|
||||
CIP_NONBLOCKING = 0x00,
|
||||
@ -40,6 +43,7 @@ enum cip_flags {
|
||||
CIP_SKIP_DBC_ZERO_CHECK = 0x20,
|
||||
CIP_SKIP_INIT_DBC_CHECK = 0x40,
|
||||
CIP_EMPTY_HAS_WRONG_DBC = 0x80,
|
||||
CIP_JUMBO_PAYLOAD = 0x100,
|
||||
};
|
||||
|
||||
/**
|
||||
|
@ -33,6 +33,7 @@ static DEFINE_MUTEX(devices_mutex);
|
||||
static DECLARE_BITMAP(devices_used, SNDRV_CARDS);
|
||||
|
||||
/* Offsets from information register. */
|
||||
#define INFO_OFFSET_BEBOB_VERSION 0x08
|
||||
#define INFO_OFFSET_GUID 0x10
|
||||
#define INFO_OFFSET_HW_MODEL_ID 0x18
|
||||
#define INFO_OFFSET_HW_MODEL_REVISION 0x1c
|
||||
@ -57,6 +58,7 @@ static DECLARE_BITMAP(devices_used, SNDRV_CARDS);
|
||||
#define VEN_FOCUSRITE 0x0000130e
|
||||
#define VEN_MAUDIO1 0x00000d6c
|
||||
#define VEN_MAUDIO2 0x000007f5
|
||||
#define VEN_DIGIDESIGN 0x00a07e
|
||||
|
||||
#define MODEL_FOCUSRITE_SAFFIRE_BOTH 0x00000000
|
||||
#define MODEL_MAUDIO_AUDIOPHILE_BOTH 0x00010060
|
||||
@ -72,6 +74,7 @@ name_device(struct snd_bebob *bebob, unsigned int vendor_id)
|
||||
u32 hw_id;
|
||||
u32 data[2] = {0};
|
||||
u32 revision;
|
||||
u32 version;
|
||||
int err;
|
||||
|
||||
/* get vendor name from root directory */
|
||||
@ -104,6 +107,12 @@ name_device(struct snd_bebob *bebob, unsigned int vendor_id)
|
||||
if (err < 0)
|
||||
goto end;
|
||||
|
||||
err = snd_bebob_read_quad(bebob->unit, INFO_OFFSET_BEBOB_VERSION,
|
||||
&version);
|
||||
if (err < 0)
|
||||
goto end;
|
||||
bebob->version = version;
|
||||
|
||||
strcpy(bebob->card->driver, "BeBoB");
|
||||
strcpy(bebob->card->shortname, model);
|
||||
strcpy(bebob->card->mixername, model);
|
||||
@ -364,6 +373,10 @@ static const struct ieee1394_device_id bebob_id_table[] = {
|
||||
SND_BEBOB_DEV_ENTRY(VEN_BEHRINGER, 0x00001604, &spec_normal),
|
||||
/* Behringer, Digital Mixer X32 series (X-UF Card) */
|
||||
SND_BEBOB_DEV_ENTRY(VEN_BEHRINGER, 0x00000006, &spec_normal),
|
||||
/* Behringer, F-Control Audio 1616 */
|
||||
SND_BEBOB_DEV_ENTRY(VEN_BEHRINGER, 0x001616, &spec_normal),
|
||||
/* Behringer, F-Control Audio 610 */
|
||||
SND_BEBOB_DEV_ENTRY(VEN_BEHRINGER, 0x000610, &spec_normal),
|
||||
/* Apogee Electronics, Rosetta 200/400 (X-FireWire card) */
|
||||
/* Apogee Electronics, DA/AD/DD-16X (X-FireWire card) */
|
||||
SND_BEBOB_DEV_ENTRY(VEN_APOGEE, 0x00010048, &spec_normal),
|
||||
@ -433,11 +446,11 @@ static const struct ieee1394_device_id bebob_id_table[] = {
|
||||
/* M-Audio ProjectMix */
|
||||
SND_BEBOB_DEV_ENTRY(VEN_MAUDIO1, MODEL_MAUDIO_PROJECTMIX,
|
||||
&maudio_special_spec),
|
||||
/* Digidesign Mbox 2 Pro */
|
||||
SND_BEBOB_DEV_ENTRY(VEN_DIGIDESIGN, 0x0000a9, &spec_normal),
|
||||
/* IDs are unknown but able to be supported */
|
||||
/* Apogee, Mini-ME Firewire */
|
||||
/* Apogee, Mini-DAC Firewire */
|
||||
/* Behringer, F-Control Audio 1616 */
|
||||
/* Behringer, F-Control Audio 610 */
|
||||
/* Cakawalk, Sonar Power Studio 66 */
|
||||
/* CME, UF400e */
|
||||
/* ESI, Quotafire XL */
|
||||
|
@ -49,10 +49,15 @@ struct snd_bebob_stream_formation {
|
||||
extern const unsigned int snd_bebob_rate_table[SND_BEBOB_STRM_FMT_ENTRIES];
|
||||
|
||||
/* device specific operations */
|
||||
#define SND_BEBOB_CLOCK_INTERNAL "Internal"
|
||||
enum snd_bebob_clock_type {
|
||||
SND_BEBOB_CLOCK_TYPE_INTERNAL = 0,
|
||||
SND_BEBOB_CLOCK_TYPE_EXTERNAL,
|
||||
SND_BEBOB_CLOCK_TYPE_SYT,
|
||||
};
|
||||
struct snd_bebob_clock_spec {
|
||||
unsigned int num;
|
||||
const char *const *labels;
|
||||
enum snd_bebob_clock_type *types;
|
||||
int (*get)(struct snd_bebob *bebob, unsigned int *id);
|
||||
};
|
||||
struct snd_bebob_rate_spec {
|
||||
@ -92,8 +97,7 @@ struct snd_bebob {
|
||||
struct amdtp_stream rx_stream;
|
||||
struct cmp_connection out_conn;
|
||||
struct cmp_connection in_conn;
|
||||
atomic_t capture_substreams;
|
||||
atomic_t playback_substreams;
|
||||
atomic_t substreams_counter;
|
||||
|
||||
struct snd_bebob_stream_formation
|
||||
tx_stream_formations[SND_BEBOB_STRM_FMT_ENTRIES];
|
||||
@ -110,6 +114,9 @@ struct snd_bebob {
|
||||
/* for M-Audio special devices */
|
||||
void *maudio_special_quirk;
|
||||
bool deferred_registration;
|
||||
|
||||
/* For BeBoB version quirk. */
|
||||
unsigned int version;
|
||||
};
|
||||
|
||||
static inline int
|
||||
@ -159,7 +166,8 @@ enum avc_bridgeco_plug_type {
|
||||
AVC_BRIDGECO_PLUG_TYPE_MIDI = 0x02,
|
||||
AVC_BRIDGECO_PLUG_TYPE_SYNC = 0x03,
|
||||
AVC_BRIDGECO_PLUG_TYPE_ANA = 0x04,
|
||||
AVC_BRIDGECO_PLUG_TYPE_DIG = 0x05
|
||||
AVC_BRIDGECO_PLUG_TYPE_DIG = 0x05,
|
||||
AVC_BRIDGECO_PLUG_TYPE_ADDITION = 0x06
|
||||
};
|
||||
static inline void
|
||||
avc_bridgeco_fill_unit_addr(u8 buf[AVC_BRIDGECO_ADDR_BYTES],
|
||||
@ -205,8 +213,8 @@ int avc_bridgeco_get_plug_strm_fmt(struct fw_unit *unit,
|
||||
/* for AMDTP streaming */
|
||||
int snd_bebob_stream_get_rate(struct snd_bebob *bebob, unsigned int *rate);
|
||||
int snd_bebob_stream_set_rate(struct snd_bebob *bebob, unsigned int rate);
|
||||
int snd_bebob_stream_check_internal_clock(struct snd_bebob *bebob,
|
||||
bool *internal);
|
||||
int snd_bebob_stream_get_clock_src(struct snd_bebob *bebob,
|
||||
enum snd_bebob_clock_type *src);
|
||||
int snd_bebob_stream_discover(struct snd_bebob *bebob);
|
||||
int snd_bebob_stream_init_duplex(struct snd_bebob *bebob);
|
||||
int snd_bebob_stream_start_duplex(struct snd_bebob *bebob, unsigned int rate);
|
||||
|
@ -103,11 +103,17 @@ saffire_write_quad(struct snd_bebob *bebob, u64 offset, u32 value)
|
||||
&data, sizeof(__be32), 0);
|
||||
}
|
||||
|
||||
static const char *const saffirepro_10_clk_src_labels[] = {
|
||||
SND_BEBOB_CLOCK_INTERNAL, "S/PDIF", "Word Clock"
|
||||
static enum snd_bebob_clock_type saffirepro_10_clk_src_types[] = {
|
||||
SND_BEBOB_CLOCK_TYPE_INTERNAL,
|
||||
SND_BEBOB_CLOCK_TYPE_EXTERNAL, /* S/PDIF */
|
||||
SND_BEBOB_CLOCK_TYPE_EXTERNAL, /* Word Clock */
|
||||
};
|
||||
static const char *const saffirepro_26_clk_src_labels[] = {
|
||||
SND_BEBOB_CLOCK_INTERNAL, "S/PDIF", "ADAT1", "ADAT2", "Word Clock"
|
||||
static enum snd_bebob_clock_type saffirepro_26_clk_src_types[] = {
|
||||
SND_BEBOB_CLOCK_TYPE_INTERNAL,
|
||||
SND_BEBOB_CLOCK_TYPE_EXTERNAL, /* S/PDIF */
|
||||
SND_BEBOB_CLOCK_TYPE_EXTERNAL, /* ADAT1 */
|
||||
SND_BEBOB_CLOCK_TYPE_EXTERNAL, /* ADAT2 */
|
||||
SND_BEBOB_CLOCK_TYPE_EXTERNAL, /* Word Clock */
|
||||
};
|
||||
/* Value maps between registers and labels for SaffirePro 10/26. */
|
||||
static const signed char saffirepro_clk_maps[][SAFFIREPRO_CLOCK_SOURCE_COUNT] = {
|
||||
@ -178,7 +184,7 @@ saffirepro_both_clk_src_get(struct snd_bebob *bebob, unsigned int *id)
|
||||
goto end;
|
||||
|
||||
/* depending on hardware, use a different mapping */
|
||||
if (bebob->spec->clock->labels == saffirepro_10_clk_src_labels)
|
||||
if (bebob->spec->clock->types == saffirepro_10_clk_src_types)
|
||||
map = saffirepro_clk_maps[0];
|
||||
else
|
||||
map = saffirepro_clk_maps[1];
|
||||
@ -195,8 +201,9 @@ end:
|
||||
}
|
||||
|
||||
struct snd_bebob_spec saffire_le_spec;
|
||||
static const char *const saffire_both_clk_src_labels[] = {
|
||||
SND_BEBOB_CLOCK_INTERNAL, "S/PDIF"
|
||||
static enum snd_bebob_clock_type saffire_both_clk_src_types[] = {
|
||||
SND_BEBOB_CLOCK_TYPE_INTERNAL,
|
||||
SND_BEBOB_CLOCK_TYPE_EXTERNAL,
|
||||
};
|
||||
static int
|
||||
saffire_both_clk_src_get(struct snd_bebob *bebob, unsigned int *id)
|
||||
@ -259,8 +266,8 @@ static struct snd_bebob_rate_spec saffirepro_both_rate_spec = {
|
||||
};
|
||||
/* Saffire Pro 26 I/O */
|
||||
static struct snd_bebob_clock_spec saffirepro_26_clk_spec = {
|
||||
.num = ARRAY_SIZE(saffirepro_26_clk_src_labels),
|
||||
.labels = saffirepro_26_clk_src_labels,
|
||||
.num = ARRAY_SIZE(saffirepro_26_clk_src_types),
|
||||
.types = saffirepro_26_clk_src_types,
|
||||
.get = &saffirepro_both_clk_src_get,
|
||||
};
|
||||
struct snd_bebob_spec saffirepro_26_spec = {
|
||||
@ -270,8 +277,8 @@ struct snd_bebob_spec saffirepro_26_spec = {
|
||||
};
|
||||
/* Saffire Pro 10 I/O */
|
||||
static struct snd_bebob_clock_spec saffirepro_10_clk_spec = {
|
||||
.num = ARRAY_SIZE(saffirepro_10_clk_src_labels),
|
||||
.labels = saffirepro_10_clk_src_labels,
|
||||
.num = ARRAY_SIZE(saffirepro_10_clk_src_types),
|
||||
.types = saffirepro_10_clk_src_types,
|
||||
.get = &saffirepro_both_clk_src_get,
|
||||
};
|
||||
struct snd_bebob_spec saffirepro_10_spec = {
|
||||
@ -285,8 +292,8 @@ static struct snd_bebob_rate_spec saffire_both_rate_spec = {
|
||||
.set = &snd_bebob_stream_set_rate,
|
||||
};
|
||||
static struct snd_bebob_clock_spec saffire_both_clk_spec = {
|
||||
.num = ARRAY_SIZE(saffire_both_clk_src_labels),
|
||||
.labels = saffire_both_clk_src_labels,
|
||||
.num = ARRAY_SIZE(saffire_both_clk_src_types),
|
||||
.types = saffire_both_clk_src_types,
|
||||
.get = &saffire_both_clk_src_get,
|
||||
};
|
||||
/* Saffire LE */
|
||||
|
@ -340,9 +340,12 @@ end:
|
||||
}
|
||||
|
||||
/* Clock source control for special firmware */
|
||||
static const char *const special_clk_labels[] = {
|
||||
SND_BEBOB_CLOCK_INTERNAL " with Digital Mute", "Digital",
|
||||
"Word Clock", SND_BEBOB_CLOCK_INTERNAL};
|
||||
static enum snd_bebob_clock_type special_clk_types[] = {
|
||||
SND_BEBOB_CLOCK_TYPE_INTERNAL, /* With digital mute */
|
||||
SND_BEBOB_CLOCK_TYPE_EXTERNAL, /* SPDIF/ADAT */
|
||||
SND_BEBOB_CLOCK_TYPE_EXTERNAL, /* Word Clock */
|
||||
SND_BEBOB_CLOCK_TYPE_INTERNAL,
|
||||
};
|
||||
static int special_clk_get(struct snd_bebob *bebob, unsigned int *id)
|
||||
{
|
||||
struct special_params *params = bebob->maudio_special_quirk;
|
||||
@ -352,7 +355,13 @@ static int special_clk_get(struct snd_bebob *bebob, unsigned int *id)
|
||||
static int special_clk_ctl_info(struct snd_kcontrol *kctl,
|
||||
struct snd_ctl_elem_info *einf)
|
||||
{
|
||||
return snd_ctl_enum_info(einf, 1, ARRAY_SIZE(special_clk_labels),
|
||||
static const char *const special_clk_labels[] = {
|
||||
"Internal with Digital Mute",
|
||||
"Digital",
|
||||
"Word Clock",
|
||||
"Internal"
|
||||
};
|
||||
return snd_ctl_enum_info(einf, 1, ARRAY_SIZE(special_clk_types),
|
||||
special_clk_labels);
|
||||
}
|
||||
static int special_clk_ctl_get(struct snd_kcontrol *kctl,
|
||||
@ -371,7 +380,7 @@ static int special_clk_ctl_put(struct snd_kcontrol *kctl,
|
||||
int err, id;
|
||||
|
||||
id = uval->value.enumerated.item[0];
|
||||
if (id >= ARRAY_SIZE(special_clk_labels))
|
||||
if (id >= ARRAY_SIZE(special_clk_types))
|
||||
return -EINVAL;
|
||||
|
||||
mutex_lock(&bebob->mutex);
|
||||
@ -708,8 +717,8 @@ static struct snd_bebob_rate_spec special_rate_spec = {
|
||||
.set = &special_set_rate,
|
||||
};
|
||||
static struct snd_bebob_clock_spec special_clk_spec = {
|
||||
.num = ARRAY_SIZE(special_clk_labels),
|
||||
.labels = special_clk_labels,
|
||||
.num = ARRAY_SIZE(special_clk_types),
|
||||
.types = special_clk_types,
|
||||
.get = &special_clk_get,
|
||||
};
|
||||
static struct snd_bebob_meter_spec special_meter_spec = {
|
||||
|
@ -17,7 +17,7 @@ static int midi_capture_open(struct snd_rawmidi_substream *substream)
|
||||
if (err < 0)
|
||||
goto end;
|
||||
|
||||
atomic_inc(&bebob->capture_substreams);
|
||||
atomic_inc(&bebob->substreams_counter);
|
||||
err = snd_bebob_stream_start_duplex(bebob, 0);
|
||||
if (err < 0)
|
||||
snd_bebob_stream_lock_release(bebob);
|
||||
@ -34,7 +34,7 @@ static int midi_playback_open(struct snd_rawmidi_substream *substream)
|
||||
if (err < 0)
|
||||
goto end;
|
||||
|
||||
atomic_inc(&bebob->playback_substreams);
|
||||
atomic_inc(&bebob->substreams_counter);
|
||||
err = snd_bebob_stream_start_duplex(bebob, 0);
|
||||
if (err < 0)
|
||||
snd_bebob_stream_lock_release(bebob);
|
||||
@ -46,7 +46,7 @@ static int midi_capture_close(struct snd_rawmidi_substream *substream)
|
||||
{
|
||||
struct snd_bebob *bebob = substream->rmidi->private_data;
|
||||
|
||||
atomic_dec(&bebob->capture_substreams);
|
||||
atomic_dec(&bebob->substreams_counter);
|
||||
snd_bebob_stream_stop_duplex(bebob);
|
||||
|
||||
snd_bebob_stream_lock_release(bebob);
|
||||
@ -57,7 +57,7 @@ static int midi_playback_close(struct snd_rawmidi_substream *substream)
|
||||
{
|
||||
struct snd_bebob *bebob = substream->rmidi->private_data;
|
||||
|
||||
atomic_dec(&bebob->playback_substreams);
|
||||
atomic_dec(&bebob->substreams_counter);
|
||||
snd_bebob_stream_stop_duplex(bebob);
|
||||
|
||||
snd_bebob_stream_lock_release(bebob);
|
||||
|
@ -157,7 +157,7 @@ pcm_open(struct snd_pcm_substream *substream)
|
||||
struct snd_bebob *bebob = substream->private_data;
|
||||
struct snd_bebob_rate_spec *spec = bebob->spec->rate;
|
||||
unsigned int sampling_rate;
|
||||
bool internal;
|
||||
enum snd_bebob_clock_type src;
|
||||
int err;
|
||||
|
||||
err = snd_bebob_stream_lock_try(bebob);
|
||||
@ -168,7 +168,7 @@ pcm_open(struct snd_pcm_substream *substream)
|
||||
if (err < 0)
|
||||
goto err_locked;
|
||||
|
||||
err = snd_bebob_stream_check_internal_clock(bebob, &internal);
|
||||
err = snd_bebob_stream_get_clock_src(bebob, &src);
|
||||
if (err < 0)
|
||||
goto err_locked;
|
||||
|
||||
@ -176,7 +176,7 @@ pcm_open(struct snd_pcm_substream *substream)
|
||||
* When source of clock is internal or any PCM stream are running,
|
||||
* the available sampling rate is limited at current sampling rate.
|
||||
*/
|
||||
if (!internal ||
|
||||
if (src == SND_BEBOB_CLOCK_TYPE_EXTERNAL ||
|
||||
amdtp_stream_pcm_running(&bebob->tx_stream) ||
|
||||
amdtp_stream_pcm_running(&bebob->rx_stream)) {
|
||||
err = spec->get(bebob, &sampling_rate);
|
||||
@ -213,7 +213,7 @@ pcm_capture_hw_params(struct snd_pcm_substream *substream,
|
||||
struct snd_bebob *bebob = substream->private_data;
|
||||
|
||||
if (substream->runtime->status->state == SNDRV_PCM_STATE_OPEN)
|
||||
atomic_inc(&bebob->capture_substreams);
|
||||
atomic_inc(&bebob->substreams_counter);
|
||||
amdtp_stream_set_pcm_format(&bebob->tx_stream,
|
||||
params_format(hw_params));
|
||||
return snd_pcm_lib_alloc_vmalloc_buffer(substream,
|
||||
@ -226,7 +226,7 @@ pcm_playback_hw_params(struct snd_pcm_substream *substream,
|
||||
struct snd_bebob *bebob = substream->private_data;
|
||||
|
||||
if (substream->runtime->status->state == SNDRV_PCM_STATE_OPEN)
|
||||
atomic_inc(&bebob->playback_substreams);
|
||||
atomic_inc(&bebob->substreams_counter);
|
||||
amdtp_stream_set_pcm_format(&bebob->rx_stream,
|
||||
params_format(hw_params));
|
||||
return snd_pcm_lib_alloc_vmalloc_buffer(substream,
|
||||
@ -239,7 +239,7 @@ pcm_capture_hw_free(struct snd_pcm_substream *substream)
|
||||
struct snd_bebob *bebob = substream->private_data;
|
||||
|
||||
if (substream->runtime->status->state != SNDRV_PCM_STATE_OPEN)
|
||||
atomic_dec(&bebob->capture_substreams);
|
||||
atomic_dec(&bebob->substreams_counter);
|
||||
|
||||
snd_bebob_stream_stop_duplex(bebob);
|
||||
|
||||
@ -251,7 +251,7 @@ pcm_playback_hw_free(struct snd_pcm_substream *substream)
|
||||
struct snd_bebob *bebob = substream->private_data;
|
||||
|
||||
if (substream->runtime->status->state != SNDRV_PCM_STATE_OPEN)
|
||||
atomic_dec(&bebob->playback_substreams);
|
||||
atomic_dec(&bebob->substreams_counter);
|
||||
|
||||
snd_bebob_stream_stop_duplex(bebob);
|
||||
|
||||
|
@ -132,25 +132,27 @@ static void
|
||||
proc_read_clock(struct snd_info_entry *entry,
|
||||
struct snd_info_buffer *buffer)
|
||||
{
|
||||
static const char *const clk_labels[] = {
|
||||
"Internal",
|
||||
"External",
|
||||
"SYT-Match",
|
||||
};
|
||||
struct snd_bebob *bebob = entry->private_data;
|
||||
struct snd_bebob_rate_spec *rate_spec = bebob->spec->rate;
|
||||
struct snd_bebob_clock_spec *clk_spec = bebob->spec->clock;
|
||||
unsigned int rate, id;
|
||||
bool internal;
|
||||
enum snd_bebob_clock_type src;
|
||||
unsigned int rate;
|
||||
|
||||
if (rate_spec->get(bebob, &rate) >= 0)
|
||||
snd_iprintf(buffer, "Sampling rate: %d\n", rate);
|
||||
|
||||
if (clk_spec) {
|
||||
if (clk_spec->get(bebob, &id) >= 0)
|
||||
if (snd_bebob_stream_get_clock_src(bebob, &src) >= 0) {
|
||||
if (clk_spec)
|
||||
snd_iprintf(buffer, "Clock Source: %s\n",
|
||||
clk_spec->labels[id]);
|
||||
} else {
|
||||
if (snd_bebob_stream_check_internal_clock(bebob,
|
||||
&internal) >= 0)
|
||||
clk_labels[src]);
|
||||
else
|
||||
snd_iprintf(buffer, "Clock Source: %s (MSU-dest: %d)\n",
|
||||
(internal) ? "Internal" : "External",
|
||||
bebob->sync_input_plug);
|
||||
clk_labels[src], bebob->sync_input_plug);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -8,7 +8,7 @@
|
||||
|
||||
#include "./bebob.h"
|
||||
|
||||
#define CALLBACK_TIMEOUT 1000
|
||||
#define CALLBACK_TIMEOUT 2000
|
||||
#define FW_ISO_RESOURCE_DELAY 1000
|
||||
|
||||
/*
|
||||
@ -116,16 +116,15 @@ end:
|
||||
return err;
|
||||
}
|
||||
|
||||
int
|
||||
snd_bebob_stream_check_internal_clock(struct snd_bebob *bebob, bool *internal)
|
||||
int snd_bebob_stream_get_clock_src(struct snd_bebob *bebob,
|
||||
enum snd_bebob_clock_type *src)
|
||||
{
|
||||
struct snd_bebob_clock_spec *clk_spec = bebob->spec->clock;
|
||||
u8 addr[AVC_BRIDGECO_ADDR_BYTES], input[7];
|
||||
unsigned int id;
|
||||
enum avc_bridgeco_plug_type type;
|
||||
int err = 0;
|
||||
|
||||
*internal = false;
|
||||
|
||||
/* 1.The device has its own operation to switch source of clock */
|
||||
if (clk_spec) {
|
||||
err = clk_spec->get(bebob, &id);
|
||||
@ -143,10 +142,7 @@ snd_bebob_stream_check_internal_clock(struct snd_bebob *bebob, bool *internal)
|
||||
goto end;
|
||||
}
|
||||
|
||||
if (strncmp(clk_spec->labels[id], SND_BEBOB_CLOCK_INTERNAL,
|
||||
strlen(SND_BEBOB_CLOCK_INTERNAL)) == 0)
|
||||
*internal = true;
|
||||
|
||||
*src = clk_spec->types[id];
|
||||
goto end;
|
||||
}
|
||||
|
||||
@ -155,7 +151,7 @@ snd_bebob_stream_check_internal_clock(struct snd_bebob *bebob, bool *internal)
|
||||
* to use internal clock always
|
||||
*/
|
||||
if (bebob->sync_input_plug < 0) {
|
||||
*internal = true;
|
||||
*src = SND_BEBOB_CLOCK_TYPE_INTERNAL;
|
||||
goto end;
|
||||
}
|
||||
|
||||
@ -178,18 +174,79 @@ snd_bebob_stream_check_internal_clock(struct snd_bebob *bebob, bool *internal)
|
||||
* Here check the first field. This field is used for direction.
|
||||
*/
|
||||
if (input[0] == 0xff) {
|
||||
*internal = true;
|
||||
*src = SND_BEBOB_CLOCK_TYPE_INTERNAL;
|
||||
goto end;
|
||||
}
|
||||
|
||||
/*
|
||||
* If source of clock is internal CSR, Music Sub Unit Sync Input is
|
||||
* a destination of Music Sub Unit Sync Output.
|
||||
*/
|
||||
*internal = ((input[0] == AVC_BRIDGECO_PLUG_DIR_OUT) &&
|
||||
(input[1] == AVC_BRIDGECO_PLUG_MODE_SUBUNIT) &&
|
||||
(input[2] == 0x0c) &&
|
||||
(input[3] == 0x00));
|
||||
/* The source from any output plugs is for one purpose only. */
|
||||
if (input[0] == AVC_BRIDGECO_PLUG_DIR_OUT) {
|
||||
/*
|
||||
* In BeBoB architecture, the source from music subunit may
|
||||
* bypass from oPCR[0]. This means that this source gives
|
||||
* synchronization to IEEE 1394 cycle start packet.
|
||||
*/
|
||||
if (input[1] == AVC_BRIDGECO_PLUG_MODE_SUBUNIT &&
|
||||
input[2] == 0x0c) {
|
||||
*src = SND_BEBOB_CLOCK_TYPE_INTERNAL;
|
||||
goto end;
|
||||
}
|
||||
/* The source from any input units is for several purposes. */
|
||||
} else if (input[1] == AVC_BRIDGECO_PLUG_MODE_UNIT) {
|
||||
if (input[2] == AVC_BRIDGECO_PLUG_UNIT_ISOC) {
|
||||
if (input[3] == 0x00) {
|
||||
/*
|
||||
* This source comes from iPCR[0]. This means
|
||||
* that presentation timestamp calculated by
|
||||
* SYT series of the received packets. In
|
||||
* short, this driver is the master of
|
||||
* synchronization.
|
||||
*/
|
||||
*src = SND_BEBOB_CLOCK_TYPE_SYT;
|
||||
goto end;
|
||||
} else {
|
||||
/*
|
||||
* This source comes from iPCR[1-29]. This
|
||||
* means that the synchronization stream is not
|
||||
* the Audio/MIDI compound stream.
|
||||
*/
|
||||
*src = SND_BEBOB_CLOCK_TYPE_EXTERNAL;
|
||||
goto end;
|
||||
}
|
||||
} else if (input[2] == AVC_BRIDGECO_PLUG_UNIT_EXT) {
|
||||
/* Check type of this plug. */
|
||||
avc_bridgeco_fill_unit_addr(addr,
|
||||
AVC_BRIDGECO_PLUG_DIR_IN,
|
||||
AVC_BRIDGECO_PLUG_UNIT_EXT,
|
||||
input[3]);
|
||||
err = avc_bridgeco_get_plug_type(bebob->unit, addr,
|
||||
&type);
|
||||
if (err < 0)
|
||||
goto end;
|
||||
|
||||
if (type == AVC_BRIDGECO_PLUG_TYPE_DIG) {
|
||||
/*
|
||||
* SPDIF/ADAT or sometimes (not always) word
|
||||
* clock.
|
||||
*/
|
||||
*src = SND_BEBOB_CLOCK_TYPE_EXTERNAL;
|
||||
goto end;
|
||||
} else if (type == AVC_BRIDGECO_PLUG_TYPE_SYNC) {
|
||||
/* Often word clock. */
|
||||
*src = SND_BEBOB_CLOCK_TYPE_EXTERNAL;
|
||||
goto end;
|
||||
} else if (type == AVC_BRIDGECO_PLUG_TYPE_ADDITION) {
|
||||
/*
|
||||
* Not standard.
|
||||
* Mostly, additional internal clock.
|
||||
*/
|
||||
*src = SND_BEBOB_CLOCK_TYPE_INTERNAL;
|
||||
goto end;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/* Not supported. */
|
||||
err = -EIO;
|
||||
end:
|
||||
return err;
|
||||
}
|
||||
@ -417,8 +474,24 @@ destroy_both_connections(struct snd_bebob *bebob)
|
||||
static int
|
||||
get_sync_mode(struct snd_bebob *bebob, enum cip_flags *sync_mode)
|
||||
{
|
||||
/* currently this module doesn't support SYT-Match mode */
|
||||
*sync_mode = CIP_SYNC_TO_DEVICE;
|
||||
enum snd_bebob_clock_type src;
|
||||
int err;
|
||||
|
||||
err = snd_bebob_stream_get_clock_src(bebob, &src);
|
||||
if (err < 0)
|
||||
return err;
|
||||
|
||||
switch (src) {
|
||||
case SND_BEBOB_CLOCK_TYPE_INTERNAL:
|
||||
case SND_BEBOB_CLOCK_TYPE_EXTERNAL:
|
||||
*sync_mode = CIP_SYNC_TO_DEVICE;
|
||||
break;
|
||||
default:
|
||||
case SND_BEBOB_CLOCK_TYPE_SYT:
|
||||
*sync_mode = 0;
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
@ -467,6 +540,17 @@ int snd_bebob_stream_init_duplex(struct snd_bebob *bebob)
|
||||
/* See comments in next function */
|
||||
init_completion(&bebob->bus_reset);
|
||||
bebob->tx_stream.flags |= CIP_SKIP_INIT_DBC_CHECK;
|
||||
|
||||
/*
|
||||
* BeBoB v3 transfers packets with these qurks:
|
||||
* - In the beginning of streaming, the value of dbc is incremented
|
||||
* even if no data blocks are transferred.
|
||||
* - The value of dbc is reset suddenly.
|
||||
*/
|
||||
if (bebob->version > 2)
|
||||
bebob->tx_stream.flags |= CIP_EMPTY_HAS_WRONG_DBC |
|
||||
CIP_SKIP_DBC_ZERO_CHECK;
|
||||
|
||||
/*
|
||||
* At high sampling rate, M-Audio special firmware transmits empty
|
||||
* packet with the value of dbc incremented by 8 but the others are
|
||||
@ -490,7 +574,6 @@ int snd_bebob_stream_start_duplex(struct snd_bebob *bebob, unsigned int rate)
|
||||
{
|
||||
struct snd_bebob_rate_spec *rate_spec = bebob->spec->rate;
|
||||
struct amdtp_stream *master, *slave;
|
||||
atomic_t *slave_substreams;
|
||||
enum cip_flags sync_mode;
|
||||
unsigned int curr_rate;
|
||||
bool updated = false;
|
||||
@ -515,8 +598,7 @@ int snd_bebob_stream_start_duplex(struct snd_bebob *bebob, unsigned int rate)
|
||||
mutex_lock(&bebob->mutex);
|
||||
|
||||
/* Need no substreams */
|
||||
if (atomic_read(&bebob->playback_substreams) == 0 &&
|
||||
atomic_read(&bebob->capture_substreams) == 0)
|
||||
if (atomic_read(&bebob->substreams_counter) == 0)
|
||||
goto end;
|
||||
|
||||
err = get_sync_mode(bebob, &sync_mode);
|
||||
@ -525,11 +607,9 @@ int snd_bebob_stream_start_duplex(struct snd_bebob *bebob, unsigned int rate)
|
||||
if (sync_mode == CIP_SYNC_TO_DEVICE) {
|
||||
master = &bebob->tx_stream;
|
||||
slave = &bebob->rx_stream;
|
||||
slave_substreams = &bebob->playback_substreams;
|
||||
} else {
|
||||
master = &bebob->rx_stream;
|
||||
slave = &bebob->tx_stream;
|
||||
slave_substreams = &bebob->capture_substreams;
|
||||
}
|
||||
|
||||
/*
|
||||
@ -630,7 +710,7 @@ int snd_bebob_stream_start_duplex(struct snd_bebob *bebob, unsigned int rate)
|
||||
}
|
||||
|
||||
/* start slave if needed */
|
||||
if (atomic_read(slave_substreams) > 0 && !amdtp_stream_running(slave)) {
|
||||
if (!amdtp_stream_running(slave)) {
|
||||
err = start_stream(bebob, slave, rate);
|
||||
if (err < 0) {
|
||||
dev_err(&bebob->unit->device,
|
||||
@ -656,31 +736,25 @@ end:
|
||||
void snd_bebob_stream_stop_duplex(struct snd_bebob *bebob)
|
||||
{
|
||||
struct amdtp_stream *master, *slave;
|
||||
atomic_t *master_substreams, *slave_substreams;
|
||||
|
||||
if (bebob->master == &bebob->rx_stream) {
|
||||
slave = &bebob->tx_stream;
|
||||
master = &bebob->rx_stream;
|
||||
slave_substreams = &bebob->capture_substreams;
|
||||
master_substreams = &bebob->playback_substreams;
|
||||
} else {
|
||||
slave = &bebob->rx_stream;
|
||||
master = &bebob->tx_stream;
|
||||
slave_substreams = &bebob->playback_substreams;
|
||||
master_substreams = &bebob->capture_substreams;
|
||||
}
|
||||
|
||||
mutex_lock(&bebob->mutex);
|
||||
|
||||
if (atomic_read(slave_substreams) == 0) {
|
||||
if (atomic_read(&bebob->substreams_counter) == 0) {
|
||||
amdtp_stream_pcm_abort(master);
|
||||
amdtp_stream_stop(master);
|
||||
|
||||
amdtp_stream_pcm_abort(slave);
|
||||
amdtp_stream_stop(slave);
|
||||
|
||||
if (atomic_read(master_substreams) == 0) {
|
||||
amdtp_stream_pcm_abort(master);
|
||||
amdtp_stream_stop(master);
|
||||
break_both_connections(bebob);
|
||||
}
|
||||
break_both_connections(bebob);
|
||||
}
|
||||
|
||||
mutex_unlock(&bebob->mutex);
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user