sound updates for 6.12-rc1

A fairly big update at this time, both in core and driver sides.
 
 The core received rewrites in PCM buffer allocation handling and
 locking optimizations, PCM rate updates followed by lots of cleanups.
 
 In ASoC side, the legacy Intel drivers have been deprecated by AVS
 drivers which leaded to the significant amount of code reduction.
 SoundWire driver updates and other cleanups contributed more code
 reduction, too.
 
 USB-audio driver received a large cleanup of its big quirk table, and
 the old snd_print*() API usages in many legacy drivers are replaced
 with the standard print API.
 
 Here are some highlights:
 
 Core:
 - More optimized locking in ALSA control code
 - Rewrites of memalloc helpers for better DMA API usage
 - Drop of obsoleted vmalloc PCM buffer helper API
 - Continued MIDI2 UMP updates
 - Support of a new user-space driven timer instance
 - Update for more PCM support rates and cleanups
 - Xrun counter report in the proc files
 
 ASoC:
 - Continued simplification and cleanup works for ASoC
 - Extensive cleanups and refactoring of the Soundwire drivers
 - Removal of Intel machine support obsoleted by the AVS driver
 - Lots of DT schema conversions
 - Machine support for many AMD and Intel x86 platforms
 - Support for AMD ACP 7.1, Mediatek MT6367 and MT8365, Realtek RTL1320
   SoundWire and rev C, and Texas Instruments TAS2563
 
 USB-audio:
 - Add support of multiple control interfaces
 - A large rewrite of quirk table with macros
 - Support for RME Digiface USB
 
 HD-audio:
 - Cleanup of quirk code for Samsung Galaxy laptops
 - Clean up of detection of Cirrus codecs
 - C-Media CM9825 HD-audio codec support
 
 Others:
 - Rewrites to standard print API in a lot of legacy drivers
 -----BEGIN PGP SIGNATURE-----
 
 iQJCBAABCAAsFiEEIXTw5fNLNI7mMiVaLtJE4w1nLE8FAmblvDMOHHRpd2FpQHN1
 c2UuZGUACgkQLtJE4w1nLE823BAAktHgwGbgu+s/U4osgk5M+x1IAzbbRFDEEhuG
 Pck6K1NikgUGXg/x/m6O0/M4CmLcGv7NeebD4ihJJPxdK7fpsEOcIeCiPoWfpumN
 whtrzf6DP6gMxrE/ov4qUydItuCGVNWcEF/bWv7inEcoJ+qtqiRAWLGvpwQurrvn
 NwO+9V/L8NSTWiZVX5ve1+hVVxpLoEQEhRpvMfrVyPXgX0zXgSexka9pwSdb+3xD
 vkIKQ1ju1JD8HG6JLfsIOBQYndrz3KLYWhozzrPKh+hGz3vOkhUPrfhYz5hyoWO9
 Ep95ZHF4ynAIV0pHlsQTH79BmkxmAJKVQImYHOnOWDvL4T6OVpoY6bzIMXzE9IHJ
 p/5JkG422qguoqIEBhM1mkggdXXIjwARFEtqQs+NvUErAd2Pnckl38TSrBtswa1c
 FcEjVq8MfIMFroDIPbEt6UY5K5GLWjwFG8rYFYbbEI4qIMLYSi4pbGtedpGxVZ4P
 eZGbAlAL6cpzXhTh90maA+NXSyeZUl9Tg8aHF48WjkU8LsEi9fHW/YU8JYyMfyQ3
 nYWAZocvXOlIpul8MOPVOg1vXpFKhSVXITKXolQQK1e/C3PirfWsrDxbdF8HduTi
 tfVGPiHprwPw2PE0E7ZqjBO1nRLMGcCqv2Iz69lFisPprDJr75C4voPDK+rjo7We
 YIhyUMU=
 =HLUp
 -----END PGP SIGNATURE-----

Merge tag 'sound-6.12-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound

Pull sound updates from Takashi Iwai:
 "A fairly big update at this time, both in core and driver sides.

  The core received rewrites in PCM buffer allocation handling and
  locking optimizations, PCM rate updates followed by lots of cleanups.

  In ASoC side, the legacy Intel drivers have been deprecated by AVS
  drivers which leaded to the significant amount of code reduction.
  SoundWire driver updates and other cleanups contributed more code
  reduction, too.

  USB-audio driver received a large cleanup of its big quirk table, and
  the old snd_print*() API usages in many legacy drivers are replaced
  with the standard print API.

  Here are some highlights:

  Core:
   - More optimized locking in ALSA control code
   - Rewrites of memalloc helpers for better DMA API usage
   - Drop of obsoleted vmalloc PCM buffer helper API
   - Continued MIDI2 UMP updates
   - Support of a new user-space driven timer instance
   - Update for more PCM support rates and cleanups
   - Xrun counter report in the proc files

  ASoC:
   - Continued simplification and cleanup works for ASoC
   - Extensive cleanups and refactoring of the Soundwire drivers
   - Removal of Intel machine support obsoleted by the AVS driver
   - Lots of DT schema conversions
   - Machine support for many AMD and Intel x86 platforms
   - Support for AMD ACP 7.1, Mediatek MT6367 and MT8365, Realtek
     RTL1320 SoundWire and rev C, and Texas Instruments TAS2563

  USB-audio:
   - Add support of multiple control interfaces
   - A large rewrite of quirk table with macros
   - Support for RME Digiface USB

  HD-audio:
   - Cleanup of quirk code for Samsung Galaxy laptops
   - Clean up of detection of Cirrus codecs
   - C-Media CM9825 HD-audio codec support

  Others:
   - Rewrites to standard print API in a lot of legacy drivers"

* tag 'sound-6.12-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound: (410 commits)
  ASoC: topology: Fix redundant logical jump
  ASoC: tas2781: Add Calibration Kcontrols for Chromebook
  ASoC: amd: acp: refactor SoundWire machine driver code
  ASoC: sdw_utils/intel: move soundwire endpoint parsing helper functions
  ASoC: sdw_util/intel: move soundwire endpoint and dai link structures
  ASoC: intel: sof_sdw: rename soundwire parsing helper functions
  ASoC: intel: sof_sdw: rename soundwire endpoint and dailink structures
  ASoC: atmel: mchp-pdmc: Retain Non-Runtime Controls
  ALSA: hda/realtek: Add support for Galaxy Book2 Pro (NP950XEE)
  ASoC: mediatek: mt7986-afe-pcm: Remove redundant error message
  ALSA: memalloc: Use proper DMA mapping API for x86 S/G buffer allocations
  ALSA: memalloc: Use proper DMA mapping API for x86 WC buffer allocations
  ALSA: usb-audio: Add logitech Audio profile quirk
  ASoc: mediatek: mt8365: Remove unneeded assignment
  ASoC: Intel: ARL: Add entry for HDMI-In capture support to non-I2S codec boards.
  ASoC: Intel: sof_rt5682: Add HDMI-In capture with rt5682 support for ARL.
  ASoC: SOF: Intel: hda: remove common_hdmi_codec_drv
  ASoC: Intel: sof_pcm512x: do not check common_hdmi_codec_drv
  ASoC: Intel: ehl_rt5660: do not check common_hdmi_codec_drv
  ASoC: Intel: skl_hda_dsp_generic: use common module for DAI links
  ...
This commit is contained in:
Linus Torvalds 2024-09-17 17:03:43 +02:00
commit 2f27fce671
648 changed files with 25012 additions and 32651 deletions

View File

@ -37,6 +37,24 @@ properties:
"#interrupt-cells": "#interrupt-cells":
const: 2 const: 2
mediatek,hp-pull-down:
description:
Earphone driver positive output stage short to
the audio reference ground.
type: boolean
mediatek,micbias0-microvolt:
description: Selects MIC Bias 0 output voltage.
enum: [1700000, 1800000, 1900000, 2000000,
2100000, 2500000, 2600000, 2700000]
default: 1700000
mediatek,micbias1-microvolt:
description: Selects MIC Bias 1 output voltage.
enum: [1700000, 1800000, 1900000, 2000000,
2100000, 2500000, 2600000, 2700000]
default: 1700000
regulators: regulators:
type: object type: object
$ref: /schemas/regulator/mediatek,mt6357-regulator.yaml $ref: /schemas/regulator/mediatek,mt6357-regulator.yaml
@ -83,6 +101,9 @@ examples:
interrupt-controller; interrupt-controller;
#interrupt-cells = <2>; #interrupt-cells = <2>;
mediatek,micbias0-microvolt = <1700000>;
mediatek,micbias1-microvolt = <1700000>;
regulators { regulators {
mt6357_vproc_reg: buck-vproc { mt6357_vproc_reg: buck-vproc {
regulator-name = "vproc"; regulator-name = "vproc";

View File

@ -26,6 +26,13 @@ properties:
A list off component DAPM widget. Each entry is a pair of strings, A list off component DAPM widget. Each entry is a pair of strings,
the first being the widget type, the second being the widget name the first being the widget type, the second being the widget name
clocks:
minItems: 1
maxItems: 3
description:
Base PLL clocks of audio susbsytem, used to configure base clock
frequencies for different audio use-cases.
patternProperties: patternProperties:
"^dai-link-[0-9]+$": "^dai-link-[0-9]+$":
type: object type: object

View File

@ -27,6 +27,13 @@ properties:
A list off component DAPM widget. Each entry is a pair of strings, A list off component DAPM widget. Each entry is a pair of strings,
the first being the widget type, the second being the widget name the first being the widget type, the second being the widget name
clocks:
minItems: 1
maxItems: 3
description:
Base PLL clocks of audio susbsytem, used to configure base clock
frequencies for different audio use-cases.
patternProperties: patternProperties:
"^dai-link-[0-9]+$": "^dai-link-[0-9]+$":
type: object type: object

View File

@ -0,0 +1,101 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/sound/cirrus,cs4271.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Cirrus Logic CS4271 audio CODEC
maintainers:
- Alexander Sverdlin <alexander.sverdlin@gmail.com>
- Nikita Shubin <nikita.shubin@maquefel.me>
description:
The CS4271 is a stereo audio codec. This device supports both the I2C
and the SPI bus.
allOf:
- $ref: dai-common.yaml#
- $ref: /schemas/spi/spi-peripheral-props.yaml#
properties:
compatible:
const: cirrus,cs4271
reg:
maxItems: 1
spi-cpha: true
spi-cpol: true
'#sound-dai-cells':
const: 0
reset-gpios:
description:
This pin will be deasserted before communication to the codec starts.
maxItems: 1
va-supply:
description: Analog power supply.
vd-supply:
description: Digital power supply.
vl-supply:
description: Serial Control Port power supply.
port:
$ref: audio-graph-port.yaml#
unevaluatedProperties: false
cirrus,amuteb-eq-bmutec:
description:
When given, the Codec's AMUTEB=BMUTEC flag is enabled.
type: boolean
cirrus,enable-soft-reset:
description: |
The CS4271 requires its LRCLK and MCLK to be stable before its RESET
line is de-asserted. That also means that clocks cannot be changed
without putting the chip back into hardware reset, which also requires
a complete re-initialization of all registers.
One (undocumented) workaround is to assert and de-assert the PDN bit
in the MODE2 register. This workaround can be enabled with this DT
property.
Note that this is not needed in case the clocks are stable
throughout the entire runtime of the codec.
type: boolean
required:
- compatible
- reg
unevaluatedProperties: false
examples:
- |
#include <dt-bindings/gpio/gpio.h>
spi {
#address-cells = <1>;
#size-cells = <0>;
codec@0 {
compatible = "cirrus,cs4271";
reg = <0>;
#sound-dai-cells = <0>;
spi-max-frequency = <6000000>;
spi-cpol;
spi-cpha;
reset-gpios = <&gpio0 1 GPIO_ACTIVE_LOW>;
port {
endpoint {
remote-endpoint = <&i2s_ep>;
};
};
};
};
...

View File

@ -1,57 +0,0 @@
Cirrus Logic CS4271 DT bindings
This driver supports both the I2C and the SPI bus.
Required properties:
- compatible: "cirrus,cs4271"
For required properties on SPI, please consult
Documentation/devicetree/bindings/spi/spi-bus.txt
Required properties on I2C:
- reg: the i2c address
Optional properties:
- reset-gpio: a GPIO spec to define which pin is connected to the chip's
!RESET pin
- cirrus,amuteb-eq-bmutec: When given, the Codec's AMUTEB=BMUTEC flag
is enabled.
- cirrus,enable-soft-reset:
The CS4271 requires its LRCLK and MCLK to be stable before its RESET
line is de-asserted. That also means that clocks cannot be changed
without putting the chip back into hardware reset, which also requires
a complete re-initialization of all registers.
One (undocumented) workaround is to assert and de-assert the PDN bit
in the MODE2 register. This workaround can be enabled with this DT
property.
Note that this is not needed in case the clocks are stable
throughout the entire runtime of the codec.
- vd-supply: Digital power
- vl-supply: Logic power
- va-supply: Analog Power
Examples:
codec_i2c: cs4271@10 {
compatible = "cirrus,cs4271";
reg = <0x10>;
reset-gpio = <&gpio 23 0>;
vd-supply = <&vdd_3v3_reg>;
vl-supply = <&vdd_3v3_reg>;
va-supply = <&vdd_3v3_reg>;
};
codec_spi: cs4271@0 {
compatible = "cirrus,cs4271";
reg = <0x0>;
reset-gpio = <&gpio 23 0>;
spi-max-frequency = <6000000>;
};

View File

@ -1,45 +0,0 @@
Dialog Semiconductor DA7212/DA7213 Audio Codec bindings
======
Required properties:
- compatible : Should be "dlg,da7212" or "dlg,da7213"
- reg: Specifies the I2C slave address
Optional properties:
- clocks : phandle and clock specifier for codec MCLK.
- clock-names : Clock name string for 'clocks' attribute, should be "mclk".
- dlg,micbias1-lvl : Voltage (mV) for Mic Bias 1
[<1600>, <2200>, <2500>, <3000>]
- dlg,micbias2-lvl : Voltage (mV) for Mic Bias 2
[<1600>, <2200>, <2500>, <3000>]
- dlg,dmic-data-sel : DMIC channel select based on clock edge.
["lrise_rfall", "lfall_rrise"]
- dlg,dmic-samplephase : When to sample audio from DMIC.
["on_clkedge", "between_clkedge"]
- dlg,dmic-clkrate : DMIC clock frequency (Hz).
[<1500000>, <3000000>]
- VDDA-supply : Regulator phandle for Analogue power supply
- VDDMIC-supply : Regulator phandle for Mic Bias
- VDDIO-supply : Regulator phandle for I/O power supply
======
Example:
codec_i2c: da7213@1a {
compatible = "dlg,da7213";
reg = <0x1a>;
clocks = <&clks 201>;
clock-names = "mclk";
dlg,micbias1-lvl = <2500>;
dlg,micbias2-lvl = <2500>;
dlg,dmic-data-sel = "lrise_rfall";
dlg,dmic-samplephase = "between_clkedge";
dlg,dmic-clkrate = <3000000>;
};

View File

@ -0,0 +1,103 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/sound/dlg,da7213.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Dialog Semiconductor DA7212/DA7213 Audio Codec
maintainers:
- Support Opensource <support.opensource@diasemi.com>
allOf:
- $ref: dai-common.yaml#
properties:
compatible:
enum:
- dlg,da7212
- dlg,da7213
reg:
maxItems: 1
clocks:
maxItems: 1
clock-names:
const: mclk
"#sound-dai-cells":
const: 0
dlg,micbias1-lvl:
description: Voltage (mV) for Mic Bias 1
$ref: /schemas/types.yaml#/definitions/uint32
enum: [ 1600, 2200, 2500, 3000 ]
dlg,micbias2-lvl:
description: Voltage (mV) for Mic Bias 2
$ref: /schemas/types.yaml#/definitions/uint32
enum: [ 1600, 2200, 2500, 3000 ]
dlg,dmic-data-sel:
description: DMIC channel select based on clock edge
enum: [ lrise_rfall, lfall_rrise ]
dlg,dmic-samplephase:
description: When to sample audio from DMIC
enum: [ on_clkedge, between_clkedge ]
dlg,dmic-clkrate:
description: DMIC clock frequency (Hz)
$ref: /schemas/types.yaml#/definitions/uint32
enum: [ 1500000, 3000000 ]
VDDA-supply:
description: Analogue power supply
VDDIO-supply:
description: I/O power supply
VDDMIC-supply:
description: Mic Bias
VDDSP-supply:
description: Speaker supply
ports:
$ref: audio-graph-port.yaml#/definitions/ports
port:
$ref: audio-graph-port.yaml#
unevaluatedProperties: false
required:
- compatible
- reg
unevaluatedProperties: false
examples:
- |
i2c {
#address-cells = <1>;
#size-cells = <0>;
codec@1a {
compatible = "dlg,da7213";
reg = <0x1a>;
clocks = <&clks 201>;
clock-names = "mclk";
#sound-dai-cells = <0>;
dlg,micbias1-lvl = <2500>;
dlg,micbias2-lvl = <2500>;
dlg,dmic-data-sel = "lrise_rfall";
dlg,dmic-samplephase = "between_clkedge";
dlg,dmic-clkrate = <3000000>;
};
};

View File

@ -0,0 +1,111 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/sound/fsl,imx-audio-es8328.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Freescale i.MX audio complex with ES8328 codec
maintainers:
- Shawn Guo <shawnguo@kernel.org>
- Sascha Hauer <s.hauer@pengutronix.de>
allOf:
- $ref: sound-card-common.yaml#
properties:
compatible:
const: fsl,imx-audio-es8328
model:
$ref: /schemas/types.yaml#/definitions/string
description: The user-visible name of this sound complex
ssi-controller:
$ref: /schemas/types.yaml#/definitions/phandle
description: The phandle of the i.MX SSI controller
jack-gpio:
description: Optional GPIO for headphone jack
maxItems: 1
audio-amp-supply:
description: Power regulator for speaker amps
audio-codec:
$ref: /schemas/types.yaml#/definitions/phandle
description: The phandle to the ES8328 audio codec
audio-routing:
$ref: /schemas/types.yaml#/definitions/non-unique-string-array
description: |
A list of the connections between audio components. Each entry
is a pair of strings, the first being the connection's sink, the second
being the connection's source. Valid names could be power supplies,
ES8328 pins, and the jacks on the board:
Power supplies:
* audio-amp
ES8328 pins:
* LOUT1
* LOUT2
* ROUT1
* ROUT2
* LINPUT1
* LINPUT2
* RINPUT1
* RINPUT2
* Mic PGA
Board connectors:
* Headphone
* Speaker
* Mic Jack
mux-int-port:
$ref: /schemas/types.yaml#/definitions/uint32
description: The internal port of the i.MX audio muxer (AUDMUX)
enum: [1, 2, 7]
default: 1
mux-ext-port:
$ref: /schemas/types.yaml#/definitions/uint32
description: The external port of the i.MX audio muxer (AUDMIX)
enum: [3, 4, 5, 6]
default: 3
required:
- compatible
- model
- ssi-controller
- jack-gpio
- audio-amp-supply
- audio-codec
- audio-routing
- mux-int-port
- mux-ext-port
unevaluatedProperties: false
examples:
- |
sound {
compatible = "fsl,imx-audio-es8328";
model = "imx-audio-es8328";
ssi-controller = <&ssi1>;
audio-codec = <&codec>;
jack-gpio = <&gpio5 15 0>;
audio-amp-supply = <&reg_audio_amp>;
audio-routing =
"Speaker", "LOUT2",
"Speaker", "ROUT2",
"Speaker", "audio-amp",
"Headphone", "ROUT1",
"Headphone", "LOUT1",
"LINPUT1", "Mic Jack",
"RINPUT1", "Mic Jack",
"Mic Jack", "Mic Bias";
mux-int-port = <1>;
mux-ext-port = <3>;
};

View File

@ -0,0 +1,83 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/sound/fsl,saif.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Freescale MXS Serial Audio Interface (SAIF)
maintainers:
- Lukasz Majewski <lukma@denx.de>
allOf:
- $ref: dai-common.yaml#
description:
The SAIF is based on I2S module that is used to communicate with audio codecs,
but only with half-duplex manner (i.e. it can either transmit or receive PCM
audio).
properties:
compatible:
const: fsl,imx28-saif
reg:
maxItems: 1
"#sound-dai-cells":
const: 0
interrupts:
maxItems: 1
dmas:
maxItems: 1
dma-names:
const: rx-tx
"#clock-cells":
description: Configure the I2S device as MCLK clock provider.
const: 0
clocks:
maxItems: 1
fsl,saif-master:
description: Indicate that saif is a slave and its phandle points to master
$ref: /schemas/types.yaml#/definitions/phandle
required:
- compatible
- reg
- "#sound-dai-cells"
- interrupts
- dmas
- dma-names
- clocks
unevaluatedProperties: false
examples:
- |
saif0: saif@80042000 {
compatible = "fsl,imx28-saif";
reg = <0x80042000 2000>;
#sound-dai-cells = <0>;
interrupts = <59>;
dmas = <&dma_apbx 4>;
dma-names = "rx-tx";
#clock-cells = <0>;
clocks = <&clks 53>;
};
- |
saif1: saif@80046000 {
compatible = "fsl,imx28-saif";
reg = <0x80046000 2000>;
#sound-dai-cells = <0>;
interrupts = <58>;
dmas = <&dma_apbx 5>;
dma-names = "rx-tx";
clocks = <&clks 53>;
fsl,saif-master = <&saif0>;
};

View File

@ -1,60 +0,0 @@
Freescale i.MX audio complex with ES8328 codec
Required properties:
- compatible : "fsl,imx-audio-es8328"
- model : The user-visible name of this sound complex
- ssi-controller : The phandle of the i.MX SSI controller
- jack-gpio : Optional GPIO for headphone jack
- audio-amp-supply : Power regulator for speaker amps
- audio-codec : The phandle of the ES8328 audio codec
- audio-routing : A list of the connections between audio components.
Each entry is a pair of strings, the first being the
connection's sink, the second being the connection's
source. Valid names could be power supplies, ES8328
pins, and the jacks on the board:
Power supplies:
* audio-amp
ES8328 pins:
* LOUT1
* LOUT2
* ROUT1
* ROUT2
* LINPUT1
* LINPUT2
* RINPUT1
* RINPUT2
* Mic PGA
Board connectors:
* Headphone
* Speaker
* Mic Jack
- mux-int-port : The internal port of the i.MX audio muxer (AUDMUX)
- mux-ext-port : The external port of the i.MX audio muxer (AUDMIX)
Note: The AUDMUX port numbering should start at 1, which is consistent with
hardware manual.
Example:
sound {
compatible = "fsl,imx-audio-es8328";
model = "imx-audio-es8328";
ssi-controller = <&ssi1>;
audio-codec = <&codec>;
jack-gpio = <&gpio5 15 0>;
audio-amp-supply = <&reg_audio_amp>;
audio-routing =
"Speaker", "LOUT2",
"Speaker", "ROUT2",
"Speaker", "audio-amp",
"Headphone", "ROUT1",
"Headphone", "LOUT1",
"LINPUT1", "Mic Jack",
"RINPUT1", "Mic Jack",
"Mic Jack", "Mic Bias";
mux-int-port = <1>;
mux-ext-port = <3>;
};

View File

@ -0,0 +1,130 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/sound/mediatek,mt8365-afe.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: MediaTek Audio Front End PCM controller for MT8365
maintainers:
- Alexandre Mergnat <amergnat@baylibre.com>
properties:
compatible:
const: mediatek,mt8365-afe-pcm
reg:
maxItems: 1
"#sound-dai-cells":
const: 0
clocks:
items:
- description: 26M clock
- description: mux for audio clock
- description: audio i2s0 mck
- description: audio i2s1 mck
- description: audio i2s2 mck
- description: audio i2s3 mck
- description: engen 1 clock
- description: engen 2 clock
- description: audio 1 clock
- description: audio 2 clock
- description: mux for i2s0
- description: mux for i2s1
- description: mux for i2s2
- description: mux for i2s3
clock-names:
items:
- const: top_clk26m_clk
- const: top_audio_sel
- const: audio_i2s0_m
- const: audio_i2s1_m
- const: audio_i2s2_m
- const: audio_i2s3_m
- const: engen1
- const: engen2
- const: aud1
- const: aud2
- const: i2s0_m_sel
- const: i2s1_m_sel
- const: i2s2_m_sel
- const: i2s3_m_sel
interrupts:
maxItems: 1
power-domains:
maxItems: 1
mediatek,dmic-mode:
$ref: /schemas/types.yaml#/definitions/uint32
description:
Indicates how many data pins are used to transmit two channels of PDM
signal. 1 means two wires, 0 means one wire. Default value is 0.
enum:
- 0 # one wire
- 1 # two wires
required:
- compatible
- reg
- clocks
- clock-names
- interrupts
- power-domains
additionalProperties: false
examples:
- |
#include <dt-bindings/clock/mediatek,mt8365-clk.h>
#include <dt-bindings/interrupt-controller/arm-gic.h>
#include <dt-bindings/interrupt-controller/irq.h>
#include <dt-bindings/power/mediatek,mt8365-power.h>
soc {
#address-cells = <2>;
#size-cells = <2>;
audio-controller@11220000 {
compatible = "mediatek,mt8365-afe-pcm";
reg = <0 0x11220000 0 0x1000>;
#sound-dai-cells = <0>;
clocks = <&clk26m>,
<&topckgen CLK_TOP_AUDIO_SEL>,
<&topckgen CLK_TOP_AUD_I2S0_M>,
<&topckgen CLK_TOP_AUD_I2S1_M>,
<&topckgen CLK_TOP_AUD_I2S2_M>,
<&topckgen CLK_TOP_AUD_I2S3_M>,
<&topckgen CLK_TOP_AUD_ENGEN1_SEL>,
<&topckgen CLK_TOP_AUD_ENGEN2_SEL>,
<&topckgen CLK_TOP_AUD_1_SEL>,
<&topckgen CLK_TOP_AUD_2_SEL>,
<&topckgen CLK_TOP_APLL_I2S0_SEL>,
<&topckgen CLK_TOP_APLL_I2S1_SEL>,
<&topckgen CLK_TOP_APLL_I2S2_SEL>,
<&topckgen CLK_TOP_APLL_I2S3_SEL>;
clock-names = "top_clk26m_clk",
"top_audio_sel",
"audio_i2s0_m",
"audio_i2s1_m",
"audio_i2s2_m",
"audio_i2s3_m",
"engen1",
"engen2",
"aud1",
"aud2",
"i2s0_m_sel",
"i2s1_m_sel",
"i2s2_m_sel",
"i2s3_m_sel";
interrupts = <GIC_SPI 97 IRQ_TYPE_LEVEL_LOW>;
power-domains = <&spm MT8365_POWER_DOMAIN_AUDIO>;
mediatek,dmic-mode = <1>;
};
};
...

View File

@ -0,0 +1,107 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/sound/mediatek,mt8365-mt6357.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: MediaTek MT8365 ASoC sound card
maintainers:
- Alexandre Mergnat <amergnat@baylibre.com>
properties:
compatible:
const: mediatek,mt8365-mt6357
pinctrl-names:
minItems: 1
items:
- const: default
- const: dmic
- const: miso_off
- const: miso_on
- const: mosi_off
- const: mosi_on
mediatek,platform:
$ref: /schemas/types.yaml#/definitions/phandle
description: The phandle of MT8365 ASoC platform.
patternProperties:
"^dai-link-[0-9]+$":
type: object
description:
Container for dai-link level properties and CODEC sub-nodes.
properties:
codec:
type: object
description: Holds subnode which indicates codec dai.
properties:
sound-dai:
maxItems: 1
description: phandle of the codec DAI
additionalProperties: false
link-name:
description: Indicates dai-link name and PCM stream name
enum:
- I2S_IN_BE
- I2S_OUT_BE
- PCM1_BE
- PDM1_BE
- PDM2_BE
- PDM3_BE
- PDM4_BE
- SPDIF_IN_BE
- SPDIF_OUT_BE
- TDM_IN_BE
- TDM_OUT_BE
sound-dai:
maxItems: 1
description: phandle of the CPU DAI
required:
- link-name
- sound-dai
additionalProperties: false
required:
- compatible
- pinctrl-names
- mediatek,platform
additionalProperties: false
examples:
- |
sound {
compatible = "mediatek,mt8365-mt6357";
pinctrl-names = "default",
"dmic",
"miso_off",
"miso_on",
"mosi_off",
"mosi_on";
pinctrl-0 = <&aud_default_pins>;
pinctrl-1 = <&aud_dmic_pins>;
pinctrl-2 = <&aud_miso_off_pins>;
pinctrl-3 = <&aud_miso_on_pins>;
pinctrl-4 = <&aud_mosi_off_pins>;
pinctrl-5 = <&aud_mosi_on_pins>;
mediatek,platform = <&afe>;
/* hdmi interface */
dai-link-0 {
link-name = "I2S_OUT_BE";
sound-dai = <&afe>;
codec {
sound-dai = <&it66121hdmitx>;
};
};
};

View File

@ -13,6 +13,9 @@ description:
The Microchip Sony/Philips Digital Interface Receiver is a serial port The Microchip Sony/Philips Digital Interface Receiver is a serial port
compliant with the IEC-60958 standard. compliant with the IEC-60958 standard.
allOf:
- $ref: dai-common.yaml#
properties: properties:
"#sound-dai-cells": "#sound-dai-cells":
const: 0 const: 0
@ -53,7 +56,7 @@ required:
- dmas - dmas
- dma-names - dma-names
additionalProperties: false unevaluatedProperties: false
examples: examples:
- | - |

View File

@ -1,41 +0,0 @@
* Freescale MXS Serial Audio Interface (SAIF)
Required properties:
- compatible: Should be "fsl,<chip>-saif"
- reg: Should contain registers location and length
- interrupts: Should contain ERROR interrupt number
- dmas: DMA specifier, consisting of a phandle to DMA controller node
and SAIF DMA channel ID.
Refer to dma.txt and fsl-mxs-dma.txt for details.
- dma-names: Must be "rx-tx".
Optional properties:
- fsl,saif-master: phandle to the master SAIF. It's only required for
the slave SAIF.
Note: Each SAIF controller should have an alias correctly numbered
in "aliases" node.
Example:
aliases {
saif0 = &saif0;
saif1 = &saif1;
};
saif0: saif@80042000 {
compatible = "fsl,imx28-saif";
reg = <0x80042000 2000>;
interrupts = <59>;
dmas = <&dma_apbx 4>;
dma-names = "rx-tx";
};
saif1: saif@80046000 {
compatible = "fsl,imx28-saif";
reg = <0x80046000 2000>;
interrupts = <58>;
dmas = <&dma_apbx 5>;
dma-names = "rx-tx";
fsl,saif-master = <&saif0>;
};

View File

@ -1,53 +0,0 @@
PCM512x and TAS575x audio CODECs/amplifiers
These devices support both I2C and SPI (configured with pin strapping
on the board). The TAS575x devices only support I2C.
Required properties:
- compatible : One of "ti,pcm5121", "ti,pcm5122", "ti,pcm5141",
"ti,pcm5142", "ti,pcm5242", "ti,tas5754" or "ti,tas5756"
- reg : the I2C address of the device for I2C, the chip select
number for SPI.
- AVDD-supply, DVDD-supply, and CPVDD-supply : power supplies for the
device, as covered in bindings/regulator/regulator.txt
Optional properties:
- clocks : A clock specifier for the clock connected as SCLK. If this
is absent the device will be configured to clock from BCLK. If pll-in
and pll-out are specified in addition to a clock, the device is
configured to accept clock input on a specified gpio pin.
- pll-in, pll-out : gpio pins used to connect the pll using <1>
through <6>. The device will be configured for clock input on the
given pll-in pin and PLL output on the given pll-out pin. An
external connection from the pll-out pin to the SCLK pin is assumed.
Caution: the TAS-desvices only support gpios 1,2 and 3
Examples:
pcm5122: pcm5122@4c {
compatible = "ti,pcm5122";
reg = <0x4c>;
AVDD-supply = <&reg_3v3_analog>;
DVDD-supply = <&reg_1v8>;
CPVDD-supply = <&reg_3v3>;
};
pcm5142: pcm5142@4c {
compatible = "ti,pcm5142";
reg = <0x4c>;
AVDD-supply = <&reg_3v3_analog>;
DVDD-supply = <&reg_1v8>;
CPVDD-supply = <&reg_3v3>;
clocks = <&sck>;
pll-in = <3>;
pll-out = <6>;
};

View File

@ -0,0 +1,205 @@
# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
%YAML 1.2
---
$id: http://devicetree.org/schemas/sound/qcom,apq8016-sbc-sndcard.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Qualcomm APQ8016 and similar sound cards
maintainers:
- Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
- Stephan Gerhold <stephan@gerhold.net>
properties:
compatible:
enum:
- qcom,apq8016-sbc-sndcard
- qcom,msm8916-qdsp6-sndcard
reg:
items:
- description: Microphone I/O mux register address
- description: Speaker I/O mux register address
reg-names:
items:
- const: mic-iomux
- const: spkr-iomux
audio-routing:
$ref: /schemas/types.yaml#/definitions/non-unique-string-array
description:
A list of the connections between audio components. Each entry is a
pair of strings, the first being the connection's sink, the second
being the connection's source. Valid names could be power supplies,
MicBias of codec and the jacks on the board.
aux-devs:
$ref: /schemas/types.yaml#/definitions/phandle-array
description: |
List of phandles pointing to auxiliary devices, such
as amplifiers, to be added to the sound card.
model:
$ref: /schemas/types.yaml#/definitions/string
description: User visible long sound card name
pin-switches:
description: List of widget names for which pin switches should be created.
$ref: /schemas/types.yaml#/definitions/string-array
widgets:
description: User specified audio sound widgets.
$ref: /schemas/types.yaml#/definitions/non-unique-string-array
patternProperties:
".*-dai-link$":
description:
Each subnode represents a dai link. Subnodes of each dai links would be
cpu/codec dais.
type: object
properties:
link-name:
description: Indicates dai-link name and PCM stream name.
$ref: /schemas/types.yaml#/definitions/string
maxItems: 1
cpu:
description: Holds subnode which indicates cpu dai.
type: object
additionalProperties: false
properties:
sound-dai:
maxItems: 1
platform:
description: Holds subnode which indicates platform dai.
type: object
additionalProperties: false
properties:
sound-dai:
maxItems: 1
codec:
description: Holds subnode which indicates codec dai.
type: object
additionalProperties: false
properties:
sound-dai:
minItems: 1
maxItems: 8
required:
- link-name
- cpu
additionalProperties: false
required:
- compatible
- reg
- reg-names
- model
additionalProperties: false
examples:
- |
#include <dt-bindings/sound/qcom,lpass.h>
sound@7702000 {
compatible = "qcom,apq8016-sbc-sndcard";
reg = <0x07702000 0x4>, <0x07702004 0x4>;
reg-names = "mic-iomux", "spkr-iomux";
model = "DB410c";
audio-routing =
"AMIC2", "MIC BIAS Internal2",
"AMIC3", "MIC BIAS External1";
pinctrl-0 = <&cdc_pdm_lines_act &ext_sec_tlmm_lines_act &ext_mclk_tlmm_lines_act>;
pinctrl-1 = <&cdc_pdm_lines_sus &ext_sec_tlmm_lines_sus &ext_mclk_tlmm_lines_sus>;
pinctrl-names = "default", "sleep";
quaternary-dai-link {
link-name = "ADV7533";
cpu {
sound-dai = <&lpass MI2S_QUATERNARY>;
};
codec {
sound-dai = <&adv_bridge 0>;
};
};
primary-dai-link {
link-name = "WCD";
cpu {
sound-dai = <&lpass MI2S_PRIMARY>;
};
codec {
sound-dai = <&lpass_codec 0>, <&wcd_codec 0>;
};
};
tertiary-dai-link {
link-name = "WCD-Capture";
cpu {
sound-dai = <&lpass MI2S_TERTIARY>;
};
codec {
sound-dai = <&lpass_codec 1>, <&wcd_codec 1>;
};
};
};
- |
#include <dt-bindings/sound/qcom,q6afe.h>
#include <dt-bindings/sound/qcom,q6asm.h>
sound@7702000 {
compatible = "qcom,msm8916-qdsp6-sndcard";
reg = <0x07702000 0x4>, <0x07702004 0x4>;
reg-names = "mic-iomux", "spkr-iomux";
model = "msm8916";
widgets =
"Speaker", "Speaker",
"Headphone", "Headphones";
pin-switches = "Speaker";
audio-routing =
"Speaker", "Speaker Amp OUT",
"Speaker Amp IN", "HPH_R",
"Headphones", "HPH_L",
"Headphones", "HPH_R",
"AMIC1", "MIC BIAS Internal1",
"AMIC2", "MIC BIAS Internal2",
"AMIC3", "MIC BIAS Internal3";
aux-devs = <&speaker_amp>;
pinctrl-names = "default", "sleep";
pinctrl-0 = <&cdc_pdm_lines_act>;
pinctrl-1 = <&cdc_pdm_lines_sus>;
mm1-dai-link {
link-name = "MultiMedia1";
cpu {
sound-dai = <&q6asmdai MSM_FRONTEND_DAI_MULTIMEDIA1>;
};
};
primary-dai-link {
link-name = "Primary MI2S";
cpu {
sound-dai = <&q6afedai PRIMARY_MI2S_RX>;
};
platform {
sound-dai = <&q6routing>;
};
codec {
sound-dai = <&lpass_codec 0>, <&wcd_codec 0>;
};
};
};

View File

@ -64,6 +64,7 @@ allOf:
compatible: compatible:
enum: enum:
- qcom,sc7280-lpass-wsa-macro - qcom,sc7280-lpass-wsa-macro
- qcom,sm8250-lpass-wsa-macro
- qcom,sm8450-lpass-wsa-macro - qcom,sm8450-lpass-wsa-macro
- qcom,sc8280xp-lpass-wsa-macro - qcom,sc8280xp-lpass-wsa-macro
then: then:
@ -79,24 +80,6 @@ allOf:
- const: dcodec - const: dcodec
- const: fsgen - const: fsgen
- if:
properties:
compatible:
enum:
- qcom,sm8250-lpass-wsa-macro
then:
properties:
clocks:
minItems: 6
clock-names:
items:
- const: mclk
- const: npl
- const: macro
- const: dcodec
- const: va
- const: fsgen
- if: - if:
properties: properties:
compatible: compatible:
@ -130,8 +113,7 @@ examples:
<&audiocc 0>, <&audiocc 0>,
<&q6afecc LPASS_HW_MACRO_VOTE LPASS_CLK_ATTRIBUTE_COUPLE_NO>, <&q6afecc LPASS_HW_MACRO_VOTE LPASS_CLK_ATTRIBUTE_COUPLE_NO>,
<&q6afecc LPASS_HW_DCODEC_VOTE LPASS_CLK_ATTRIBUTE_COUPLE_NO>, <&q6afecc LPASS_HW_DCODEC_VOTE LPASS_CLK_ATTRIBUTE_COUPLE_NO>,
<&aoncc LPASS_CDC_VA_MCLK>,
<&vamacro>; <&vamacro>;
clock-names = "mclk", "npl", "macro", "dcodec", "va", "fsgen"; clock-names = "mclk", "npl", "macro", "dcodec", "fsgen";
clock-output-names = "mclk"; clock-output-names = "mclk";
}; };

View File

@ -27,9 +27,7 @@ properties:
- qcom,sm8650-sndcard - qcom,sm8650-sndcard
- const: qcom,sm8450-sndcard - const: qcom,sm8450-sndcard
- enum: - enum:
- qcom,apq8016-sbc-sndcard
- qcom,apq8096-sndcard - qcom,apq8096-sndcard
- qcom,msm8916-qdsp6-sndcard
- qcom,qcm6490-idp-sndcard - qcom,qcm6490-idp-sndcard
- qcom,qcs6490-rb3gen2-sndcard - qcom,qcs6490-rb3gen2-sndcard
- qcom,qrb5165-rb5-sndcard - qcom,qrb5165-rb5-sndcard
@ -58,18 +56,6 @@ properties:
$ref: /schemas/types.yaml#/definitions/string $ref: /schemas/types.yaml#/definitions/string
description: User visible long sound card name description: User visible long sound card name
pin-switches:
description: List of widget names for which pin switches should be created.
$ref: /schemas/types.yaml#/definitions/string-array
widgets:
description: User specified audio sound widgets.
$ref: /schemas/types.yaml#/definitions/non-unique-string-array
# Only valid for some compatibles (see allOf if below)
reg: true
reg-names: true
patternProperties: patternProperties:
".*-dai-link$": ".*-dai-link$":
description: description:
@ -122,34 +108,6 @@ required:
- compatible - compatible
- model - model
allOf:
- if:
properties:
compatible:
contains:
enum:
- qcom,apq8016-sbc-sndcard
- qcom,msm8916-qdsp6-sndcard
then:
properties:
reg:
items:
- description: Microphone I/O mux register address
- description: Speaker I/O mux register address
reg-names:
items:
- const: mic-iomux
- const: spkr-iomux
required:
- compatible
- model
- reg
- reg-names
else:
properties:
reg: false
reg-names: false
additionalProperties: false additionalProperties: false
examples: examples:
@ -231,98 +189,3 @@ examples:
}; };
}; };
}; };
- |
#include <dt-bindings/sound/qcom,lpass.h>
sound@7702000 {
compatible = "qcom,apq8016-sbc-sndcard";
reg = <0x07702000 0x4>, <0x07702004 0x4>;
reg-names = "mic-iomux", "spkr-iomux";
model = "DB410c";
audio-routing =
"AMIC2", "MIC BIAS Internal2",
"AMIC3", "MIC BIAS External1";
pinctrl-0 = <&cdc_pdm_lines_act &ext_sec_tlmm_lines_act &ext_mclk_tlmm_lines_act>;
pinctrl-1 = <&cdc_pdm_lines_sus &ext_sec_tlmm_lines_sus &ext_mclk_tlmm_lines_sus>;
pinctrl-names = "default", "sleep";
quaternary-dai-link {
link-name = "ADV7533";
cpu {
sound-dai = <&lpass MI2S_QUATERNARY>;
};
codec {
sound-dai = <&adv_bridge 0>;
};
};
primary-dai-link {
link-name = "WCD";
cpu {
sound-dai = <&lpass MI2S_PRIMARY>;
};
codec {
sound-dai = <&lpass_codec 0>, <&wcd_codec 0>;
};
};
tertiary-dai-link {
link-name = "WCD-Capture";
cpu {
sound-dai = <&lpass MI2S_TERTIARY>;
};
codec {
sound-dai = <&lpass_codec 1>, <&wcd_codec 1>;
};
};
};
- |
#include <dt-bindings/sound/qcom,q6afe.h>
#include <dt-bindings/sound/qcom,q6asm.h>
sound@7702000 {
compatible = "qcom,msm8916-qdsp6-sndcard";
reg = <0x07702000 0x4>, <0x07702004 0x4>;
reg-names = "mic-iomux", "spkr-iomux";
model = "msm8916";
widgets =
"Speaker", "Speaker",
"Headphone", "Headphones";
pin-switches = "Speaker";
audio-routing =
"Speaker", "Speaker Amp OUT",
"Speaker Amp IN", "HPH_R",
"Headphones", "HPH_L",
"Headphones", "HPH_R",
"AMIC1", "MIC BIAS Internal1",
"AMIC2", "MIC BIAS Internal2",
"AMIC3", "MIC BIAS Internal3";
aux-devs = <&speaker_amp>;
pinctrl-names = "default", "sleep";
pinctrl-0 = <&cdc_pdm_lines_act>;
pinctrl-1 = <&cdc_pdm_lines_sus>;
mm1-dai-link {
link-name = "MultiMedia1";
cpu {
sound-dai = <&q6asmdai MSM_FRONTEND_DAI_MULTIMEDIA1>;
};
};
primary-dai-link {
link-name = "Primary MI2S";
cpu {
sound-dai = <&q6afedai PRIMARY_MI2S_RX>;
};
platform {
sound-dai = <&q6routing>;
};
codec {
sound-dai = <&lpass_codec 0>, <&wcd_codec 0>;
};
};
};

View File

@ -30,6 +30,18 @@ properties:
reg: reg:
maxItems: 1 maxItems: 1
clocks:
items:
- description: Master clock to the CODEC
clock-names:
items:
- const: mclk
port:
$ref: audio-graph-port.yaml#
unevaluatedProperties: false
required: required:
- compatible - compatible
- reg - reg

View File

@ -112,6 +112,12 @@ properties:
description: List of necessary clock names. description: List of necessary clock names.
# details are defined below # details are defined below
post-init-providers:
description: At least if rsnd is using DPCM connection on Audio-Graph-Card2,
fw_devlink might doesn't have enough information to break the cycle. rsnd
driver will not be probed in such case. Same problem might occur with
Multi-CPU/Codec or Codec2Codec.
# ports is below # ports is below
port: port:
$ref: audio-graph-port.yaml#/definitions/port-base $ref: audio-graph-port.yaml#/definitions/port-base

View File

@ -87,6 +87,10 @@ properties:
'#sound-dai-cells': '#sound-dai-cells':
const: 0 const: 0
port:
$ref: audio-graph-port.yaml#/definitions/port-base
description: Connection to controller providing I2S signals
required: required:
- compatible - compatible
- reg - reg

View File

@ -27,11 +27,6 @@ properties:
- const: samsung,odroid-xu4-audio - const: samsung,odroid-xu4-audio
deprecated: true deprecated: true
assigned-clock-parents: true
assigned-clock-rates: true
assigned-clocks: true
clocks: true
cpu: cpu:
type: object type: object
additionalProperties: false additionalProperties: false

View File

@ -0,0 +1,101 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/sound/ti,pcm512x.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: PCM512x and TAS575x audio CODECs/amplifiers
maintainers:
- Animesh Agarwal <animeshagarwal28@gmail.com>
allOf:
- $ref: dai-common.yaml#
properties:
compatible:
enum:
- ti,pcm5121
- ti,pcm5122
- ti,pcm5141
- ti,pcm5142
- ti,pcm5242
- ti,tas5754
- ti,tas5756
reg:
maxItems: 1
AVDD-supply: true
DVDD-supply: true
CPVDD-supply: true
clocks:
maxItems: 1
description: A clock specifier for the clock connected as SCLK. If this is
absent the device will be configured to clock from BCLK. If pll-in and
pll-out are specified in addition to a clock, the device is configured to
accept clock input on a specified gpio pin.
'#sound-dai-cells':
const: 0
pll-in:
description: GPIO pin used to connect the pll using <1> through <6>. The
device will be configured for clock input on the given pll-in pin.
$ref: /schemas/types.yaml#/definitions/uint32
minimum: 1
maximum: 6
pll-out:
description: GPIO pin used to connect the pll using <1> through <6>. The
device will be configured for PLL output on the given pll-out pin. An
external connection from the pll-out pin to the SCLK pin is assumed.
$ref: /schemas/types.yaml#/definitions/uint32
minimum: 1
maximum: 6
required:
- compatible
- reg
- AVDD-supply
- DVDD-supply
- CPVDD-supply
if:
properties:
compatible:
contains:
enum:
- ti,tas5754
- ti,tas5756
then:
properties:
pll-in:
maximum: 3
pll-out:
maximum: 3
unevaluatedProperties: false
examples:
- |
i2c {
#address-cells = <1>;
#size-cells = <0>;
codec@4c {
compatible = "ti,pcm5142";
reg = <0x4c>;
AVDD-supply = <&reg_3v3_analog>;
DVDD-supply = <&reg_1v8>;
CPVDD-supply = <&reg_3v3>;
#sound-dai-cells = <0>;
clocks = <&sck>;
pll-in = <3>;
pll-out = <6>;
};
};

View File

@ -0,0 +1,127 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/sound/ti,tlv320dac3100.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Texas Instruments - tlv320aic31xx Codec module
maintainers:
- Shenghao Ding <shenghao-ding@ti.com>
description: |
CODEC output pins:
* HPL
* HPR
* SPL, devices with stereo speaker amp
* SPR, devices with stereo speaker amp
* SPK, devices with mono speaker amp
* MICBIAS
CODEC input pins:
* MIC1LP, devices with ADC
* MIC1RP, devices with ADC
* MIC1LM, devices with ADC
* AIN1, devices without ADC
* AIN2, devices without ADC
The pins can be used in referring sound node's audio-routing property.
properties:
compatible:
enum:
- ti,tlv320aic310x # - Generic TLV320AIC31xx with mono speaker amp
- ti,tlv320aic311x # - Generic TLV320AIC31xx with stereo speaker amp
- ti,tlv320aic3100 # - TLV320AIC3100 (mono speaker amp, no MiniDSP)
- ti,tlv320aic3110 # - TLV320AIC3110 (stereo speaker amp, no MiniDSP)
- ti,tlv320aic3120 # - TLV320AIC3120 (mono speaker amp, MiniDSP)
- ti,tlv320aic3111 # - TLV320AIC3111 (stereo speaker amp, MiniDSP)
- ti,tlv320dac3100 # - TLV320DAC3100 (no ADC, mono speaker amp, no MiniDSP)
- ti,tlv320dac3101 # - TLV320DAC3101 (no ADC, stereo speaker amp, no MiniDSP)
reg:
maxItems: 1
'#sound-dai-cells':
const: 0
HPVDD-supply: true
SPRVDD-supply: true
SPLVDD-supply: true
AVDD-supply: true
IOVDD-supply: true
DVDD-supply: true
reset-gpios:
description: GPIO specification for the active low RESET input.
ai31xx-micbias-vg:
$ref: /schemas/types.yaml#/definitions/uint32
default: 1
enum: [1, 2, 3]
description: |
MicBias Voltage setting
1 or MICBIAS_2_0V - MICBIAS output is powered to 2.0V
2 or MICBIAS_2_5V - MICBIAS output is powered to 2.5V
3 or MICBIAS_AVDD - MICBIAS output is connected to AVDD
ai31xx-ocmv:
$ref: /schemas/types.yaml#/definitions/uint32
enum: [0, 1, 2, 3]
description: |
output common-mode voltage setting
0 - 1.35V,
1 - 1.5V,
2 - 1.65V,
3 - 1.8V
gpio-reset:
description: gpio pin number used for codec reset
deprecated: true
required:
- compatible
- reg
- HPVDD-supply
- SPRVDD-supply
- SPLVDD-supply
- AVDD-supply
- IOVDD-supply
- DVDD-supply
allOf:
- $ref: dai-common.yaml#
unevaluatedProperties: false
examples:
- |
#include <dt-bindings/gpio/gpio.h>
#include <dt-bindings/sound/tlv320aic31xx.h>
i2c {
#address-cells = <1>;
#size-cells = <0>;
sound@18 {
compatible = "ti,tlv320aic311x";
reg = <0x18>;
ai31xx-micbias-vg = <MICBIAS_2_0V>;
reset-gpios = <&gpio1 17 GPIO_ACTIVE_LOW>;
HPVDD-supply = <&regulator>;
SPRVDD-supply = <&regulator>;
SPLVDD-supply = <&regulator>;
AVDD-supply = <&regulator>;
IOVDD-supply = <&regulator>;
DVDD-supply = <&regulator>;
};
};

View File

@ -0,0 +1,55 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/sound/ti,tpa6130a2.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Texas Instruments - tpa6130a2 Codec module
maintainers:
- Sebastian Reichel <sre@kernel.org>
description:
Stereo, analog input headphone amplifier
properties:
compatible:
enum:
- ti,tpa6130a2
- ti,tpa6140a2
reg:
maxItems: 1
Vdd-supply:
description: power supply regulator
power-gpio:
description: gpio pin to power the device
required:
- compatible
- reg
- Vdd-supply
allOf:
- $ref: dai-common.yaml#
unevaluatedProperties: false
examples:
- |
#include <dt-bindings/gpio/gpio.h>
i2c {
#address-cells = <1>;
#size-cells = <0>;
amplifier@60 {
compatible = "ti,tpa6130a2";
reg = <0x60>;
Vdd-supply = <&vmmc2>;
power-gpio = <&gpio4 2 GPIO_ACTIVE_HIGH>;
};
};

View File

@ -1,77 +0,0 @@
Texas Instruments - tlv320aic31xx Codec module
The tlv320aic31xx serial control bus communicates through I2C protocols
Required properties:
- compatible - "string" - One of:
"ti,tlv320aic310x" - Generic TLV320AIC31xx with mono speaker amp
"ti,tlv320aic311x" - Generic TLV320AIC31xx with stereo speaker amp
"ti,tlv320aic3100" - TLV320AIC3100 (mono speaker amp, no MiniDSP)
"ti,tlv320aic3110" - TLV320AIC3110 (stereo speaker amp, no MiniDSP)
"ti,tlv320aic3120" - TLV320AIC3120 (mono speaker amp, MiniDSP)
"ti,tlv320aic3111" - TLV320AIC3111 (stereo speaker amp, MiniDSP)
"ti,tlv320dac3100" - TLV320DAC3100 (no ADC, mono speaker amp, no MiniDSP)
"ti,tlv320dac3101" - TLV320DAC3101 (no ADC, stereo speaker amp, no MiniDSP)
- reg - <int> - I2C slave address
- HPVDD-supply, SPRVDD-supply, SPLVDD-supply, AVDD-supply, IOVDD-supply,
DVDD-supply : power supplies for the device as covered in
Documentation/devicetree/bindings/regulator/regulator.txt
Optional properties:
- reset-gpios - GPIO specification for the active low RESET input.
- ai31xx-micbias-vg - MicBias Voltage setting
1 or MICBIAS_2_0V - MICBIAS output is powered to 2.0V
2 or MICBIAS_2_5V - MICBIAS output is powered to 2.5V
3 or MICBIAS_AVDD - MICBIAS output is connected to AVDD
If this node is not mentioned or if the value is unknown, then
micbias is set to 2.0V.
- ai31xx-ocmv - output common-mode voltage setting
0 - 1.35V,
1 - 1.5V,
2 - 1.65V,
3 - 1.8V
Deprecated properties:
- gpio-reset - gpio pin number used for codec reset
CODEC output pins:
* HPL
* HPR
* SPL, devices with stereo speaker amp
* SPR, devices with stereo speaker amp
* SPK, devices with mono speaker amp
* MICBIAS
CODEC input pins:
* MIC1LP, devices with ADC
* MIC1RP, devices with ADC
* MIC1LM, devices with ADC
* AIN1, devices without ADC
* AIN2, devices without ADC
The pins can be used in referring sound node's audio-routing property.
Example:
#include <dt-bindings/gpio/gpio.h>
#include <dt-bindings/sound/tlv320aic31xx.h>
tlv320aic31xx: tlv320aic31xx@18 {
compatible = "ti,tlv320aic311x";
reg = <0x18>;
ai31xx-micbias-vg = <MICBIAS_OFF>;
reset-gpios = <&gpio1 17 GPIO_ACTIVE_LOW>;
HPVDD-supply = <&regulator>;
SPRVDD-supply = <&regulator>;
SPLVDD-supply = <&regulator>;
AVDD-supply = <&regulator>;
IOVDD-supply = <&regulator>;
DVDD-supply = <&regulator>;
};

View File

@ -1,27 +0,0 @@
Texas Instruments - tpa6130a2 Codec module
The tpa6130a2 serial control bus communicates through I2C protocols
Required properties:
- compatible - "string" - One of:
"ti,tpa6130a2" - TPA6130A2
"ti,tpa6140a2" - TPA6140A2
- reg - <int> - I2C slave address
- Vdd-supply - <phandle> - power supply regulator
Optional properties:
- power-gpio - gpio pin to power the device
Example:
tpa6130a2: tpa6130a2@60 {
compatible = "ti,tpa6130a2";
reg = <0x60>;
Vdd-supply = <&vmmc2>;
power-gpio = <&gpio4 2 GPIO_ACTIVE_HIGH>;
};

View File

@ -1059,6 +1059,9 @@ power_save
Automatic power-saving timeout (in second, 0 = disable) Automatic power-saving timeout (in second, 0 = disable)
power_save_controller power_save_controller
Reset HD-audio controller in power-saving mode (default = on) Reset HD-audio controller in power-saving mode (default = on)
pm_blacklist
Enable / disable power-management deny-list (default = look up PM
deny-list, 0 = skip PM deny-list, 1 = force to turn off runtime PM)
align_buffer_size align_buffer_size
Force rounding of buffer/period sizes to multiples of 128 bytes. Force rounding of buffer/period sizes to multiples of 128 bytes.
This is more efficient in terms of memory access but isn't This is more efficient in terms of memory access but isn't

View File

@ -321,12 +321,6 @@ Kernel Configuration
-------------------- --------------------
In general, I recommend you to enable the sound debug option, In general, I recommend you to enable the sound debug option,
``CONFIG_SND_DEBUG=y``, no matter whether you are debugging or not. ``CONFIG_SND_DEBUG=y``, no matter whether you are debugging or not.
This enables snd_printd() macro and others, and you'll get additional
kernel messages at probing.
In addition, you can enable ``CONFIG_SND_DEBUG_VERBOSE=y``. But this
will give you far more messages. Thus turn this on only when you are
sure to want it.
Don't forget to turn on the appropriate ``CONFIG_SND_HDA_CODEC_*`` Don't forget to turn on the appropriate ``CONFIG_SND_HDA_CODEC_*``
options. Note that each of them corresponds to the codec chip, not options. Note that each of them corresponds to the codec chip, not

View File

@ -13,6 +13,7 @@ Sound Subsystem Documentation
alsa-configuration alsa-configuration
hd-audio/index hd-audio/index
cards/index cards/index
utimers
.. only:: subproject and html .. only:: subproject and html

View File

@ -4030,31 +4030,6 @@ located in the new subdirectory, sound/pci/xyz.
Useful Functions Useful Functions
================ ================
:c:func:`snd_printk()` and friends
----------------------------------
.. note:: This subsection describes a few helper functions for
decorating a bit more on the standard :c:func:`printk()` & co.
However, in general, the use of such helpers is no longer recommended.
If possible, try to stick with the standard functions like
:c:func:`dev_err()` or :c:func:`pr_err()`.
ALSA provides a verbose version of the :c:func:`printk()` function.
If a kernel config ``CONFIG_SND_VERBOSE_PRINTK`` is set, this function
prints the given message together with the file name and the line of the
caller. The ``KERN_XXX`` prefix is processed as well as the original
:c:func:`printk()` does, so it's recommended to add this prefix,
e.g. snd_printk(KERN_ERR "Oh my, sorry, it's extremely bad!\\n");
There are also :c:func:`printk()`'s for debugging.
:c:func:`snd_printd()` can be used for general debugging purposes.
If ``CONFIG_SND_DEBUG`` is set, this function is compiled, and works
just like :c:func:`snd_printk()`. If the ALSA is compiled without
the debugging flag, it's ignored.
:c:func:`snd_printdd()` is compiled in only when
``CONFIG_SND_DEBUG_VERBOSE`` is set.
:c:func:`snd_BUG()` :c:func:`snd_BUG()`
------------------- -------------------

View File

@ -0,0 +1,126 @@
.. SPDX-License-Identifier: GPL-2.0
=======================
Userspace-driven timers
=======================
:Author: Ivan Orlov <ivan.orlov0322@gmail.com>
Preface
=======
This document describes the userspace-driven timers: virtual ALSA timers
which could be created and controlled by userspace applications using
IOCTL calls. Such timers could be useful when synchronizing audio
stream with timer sources which we don't have ALSA timers exported for
(e.g. PTP clocks), and when synchronizing the audio stream going through
two virtual sound devices using ``snd-aloop`` (for instance, when
we have a network application sending frames to one snd-aloop device,
and another sound application listening on the other end of snd-aloop).
Enabling userspace-driven timers
================================
The userspace-driven timers could be enabled in the kernel using the
``CONFIG_SND_UTIMER`` configuration option. It depends on the
``CONFIG_SND_TIMER`` option, so it also should be enabled.
Userspace-driven timers API
===========================
Userspace application can create a userspace-driven ALSA timer by
executing the ``SNDRV_TIMER_IOCTL_CREATE`` ioctl call on the
``/dev/snd/timer`` device file descriptor. The ``snd_timer_uinfo``
structure should be passed as an ioctl argument:
::
struct snd_timer_uinfo {
__u64 resolution;
int fd;
unsigned int id;
unsigned char reserved[16];
}
The ``resolution`` field sets the desired resolution in nanoseconds for
the virtual timer. ``resolution`` field simply provides an information
about the virtual timer, but does not affect the timing itself. ``id``
field gets overwritten by the ioctl, and the identifier you get in this
field after the call can be used as a timer subdevice number when
passing the timer to ``snd-aloop`` kernel module or other userspace
applications. There could be up to 128 userspace-driven timers in the
system at one moment of time, thus the id value ranges from 0 to 127.
Besides from overwriting the ``snd_timer_uinfo`` struct, ioctl stores
a timer file descriptor, which can be used to trigger the timer, in the
``fd`` field of the ``snd_timer_uinfo`` struct. Allocation of a file
descriptor for the timer guarantees that the timer can only be triggered
by the process which created it. The timer then can be triggered with
``SNDRV_TIMER_IOCTL_TRIGGER`` ioctl call on the timer file descriptor.
So, the example code for creating and triggering the timer would be:
::
static struct snd_timer_uinfo utimer_info = {
/* Timer is going to tick (presumably) every 1000000 ns */
.resolution = 1000000ULL,
.id = -1,
};
int timer_device_fd = open("/dev/snd/timer", O_RDWR | O_CLOEXEC);
if (ioctl(timer_device_fd, SNDRV_TIMER_IOCTL_CREATE, &utimer_info)) {
perror("Failed to create the timer");
return -1;
}
...
/*
* Now we want to trigger the timer. Callbacks of all of the
* timer instances binded to this timer will be executed after
* this call.
*/
ioctl(utimer_info.fd, SNDRV_TIMER_IOCTL_TRIGGER, NULL);
...
/* Now, destroy the timer */
close(timer_info.fd);
More detailed example of creating and ticking the timer could be found
in the utimer ALSA selftest.
Userspace-driven timers and snd-aloop
-------------------------------------
Userspace-driven timers could be easily used with ``snd-aloop`` module
when synchronizing two sound applications on both ends of the virtual
sound loopback. For instance, if one of the applications receives sound
frames from network and sends them to snd-aloop pcm device, and another
application listens for frames on the other snd-aloop pcm device, it
makes sense that the ALSA middle layer should initiate a data
transaction when the new period of data is received through network, but
not when the certain amount of jiffies elapses. Userspace-driven ALSA
timers could be used to achieve this.
To use userspace-driven ALSA timer as a timer source of snd-aloop, pass
the following string as the snd-aloop ``timer_source`` parameter:
::
# modprobe snd-aloop timer_source="-1.4.<utimer_id>"
Where ``utimer_id`` is the id of the timer you created with
``SNDRV_TIMER_IOCTL_CREATE``, and ``4`` is the number of
userspace-driven timers device (``SNDRV_TIMER_GLOBAL_UDRIVEN``).
``resolution`` for the userspace-driven ALSA timer used with snd-aloop
should be calculated as ``1000000000ULL / frame_rate * period_size`` as
the timer is going to tick every time a new period of frames is ready.
After that, each time you trigger the timer with
``SNDRV_TIMER_IOCTL_TRIGGER`` the new period of data will be transferred
from one snd-aloop device to another.

View File

@ -6542,6 +6542,7 @@ F: Documentation/devicetree/bindings/regulator/da92*.txt
F: Documentation/devicetree/bindings/regulator/dlg,da9*.yaml F: Documentation/devicetree/bindings/regulator/dlg,da9*.yaml
F: Documentation/devicetree/bindings/regulator/dlg,slg51000.yaml F: Documentation/devicetree/bindings/regulator/dlg,slg51000.yaml
F: Documentation/devicetree/bindings/sound/da[79]*.txt F: Documentation/devicetree/bindings/sound/da[79]*.txt
F: Documentation/devicetree/bindings/sound/dlg,da7213.yaml
F: Documentation/devicetree/bindings/thermal/dlg,da9062-thermal.yaml F: Documentation/devicetree/bindings/thermal/dlg,da9062-thermal.yaml
F: Documentation/devicetree/bindings/watchdog/dlg,da9062-watchdog.yaml F: Documentation/devicetree/bindings/watchdog/dlg,da9062-watchdog.yaml
F: Documentation/hwmon/da90??.rst F: Documentation/hwmon/da90??.rst
@ -22725,12 +22726,11 @@ F: Documentation/devicetree/bindings/sound/tas2552.txt
F: Documentation/devicetree/bindings/sound/ti,tas2562.yaml F: Documentation/devicetree/bindings/sound/ti,tas2562.yaml
F: Documentation/devicetree/bindings/sound/ti,tas2770.yaml F: Documentation/devicetree/bindings/sound/ti,tas2770.yaml
F: Documentation/devicetree/bindings/sound/ti,tas27xx.yaml F: Documentation/devicetree/bindings/sound/ti,tas27xx.yaml
F: Documentation/devicetree/bindings/sound/ti,tpa6130a2.yaml
F: Documentation/devicetree/bindings/sound/ti,pcm1681.yaml F: Documentation/devicetree/bindings/sound/ti,pcm1681.yaml
F: Documentation/devicetree/bindings/sound/ti,pcm3168a.yaml F: Documentation/devicetree/bindings/sound/ti,pcm3168a.yaml
F: Documentation/devicetree/bindings/sound/ti,tlv320*.yaml F: Documentation/devicetree/bindings/sound/ti,tlv320*.yaml
F: Documentation/devicetree/bindings/sound/ti,tlv320adcx140.yaml F: Documentation/devicetree/bindings/sound/ti,tlv320adcx140.yaml
F: Documentation/devicetree/bindings/sound/tlv320aic31xx.txt
F: Documentation/devicetree/bindings/sound/tpa6130a2.txt
F: include/sound/tas2*.h F: include/sound/tas2*.h
F: include/sound/tlv320*.h F: include/sound/tlv320*.h
F: include/sound/tpa6130a2-plat.h F: include/sound/tpa6130a2-plat.h

View File

@ -8,6 +8,7 @@
#include <linux/interrupt.h> #include <linux/interrupt.h>
#include <linux/module.h> #include <linux/module.h>
#include <linux/platform_device.h> #include <linux/platform_device.h>
#include <linux/vmalloc.h>
#include <drm/bridge/dw_hdmi.h> #include <drm/bridge/dw_hdmi.h>
#include <drm/drm_edid.h> #include <drm/drm_edid.h>
@ -388,15 +389,36 @@ static int dw_hdmi_close(struct snd_pcm_substream *substream)
static int dw_hdmi_hw_free(struct snd_pcm_substream *substream) static int dw_hdmi_hw_free(struct snd_pcm_substream *substream)
{ {
return snd_pcm_lib_free_vmalloc_buffer(substream); struct snd_pcm_runtime *runtime = substream->runtime;
vfree(runtime->dma_area);
runtime->dma_area = NULL;
return 0;
} }
static int dw_hdmi_hw_params(struct snd_pcm_substream *substream, static int dw_hdmi_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params) struct snd_pcm_hw_params *params)
{ {
struct snd_pcm_runtime *runtime = substream->runtime;
size_t size = params_buffer_bytes(params);
/* Allocate the PCM runtime buffer, which is exposed to userspace. */ /* Allocate the PCM runtime buffer, which is exposed to userspace. */
return snd_pcm_lib_alloc_vmalloc_buffer(substream, if (runtime->dma_area) {
params_buffer_bytes(params)); if (runtime->dma_bytes >= size)
return 0; /* already large enough */
vfree(runtime->dma_area);
}
runtime->dma_area = vzalloc(size);
if (!runtime->dma_area)
return -ENOMEM;
runtime->dma_bytes = size;
return 1;
}
static struct page *dw_hdmi_get_page(struct snd_pcm_substream *substream,
unsigned long offset)
{
return vmalloc_to_page(substream->runtime->dma_area + offset);
} }
static int dw_hdmi_prepare(struct snd_pcm_substream *substream) static int dw_hdmi_prepare(struct snd_pcm_substream *substream)
@ -515,7 +537,7 @@ static const struct snd_pcm_ops snd_dw_hdmi_ops = {
.prepare = dw_hdmi_prepare, .prepare = dw_hdmi_prepare,
.trigger = dw_hdmi_trigger, .trigger = dw_hdmi_trigger,
.pointer = dw_hdmi_pointer, .pointer = dw_hdmi_pointer,
.page = snd_pcm_lib_get_vmalloc_page, .page = dw_hdmi_get_page,
}; };
static int snd_dw_hdmi_probe(struct platform_device *pdev) static int snd_dw_hdmi_probe(struct platform_device *pdev)

View File

@ -222,6 +222,13 @@ static inline bool sdw_intel_sync_check_cmdsync_unlocked(struct sdw_intel *sdw)
return false; return false;
} }
static inline int sdw_intel_get_link_count(struct sdw_intel *sdw)
{
if (SDW_INTEL_CHECK_OPS(sdw, get_link_count))
return SDW_INTEL_OPS(sdw, get_link_count)(sdw);
return 4; /* default on older generations */
}
/* common bus management */ /* common bus management */
int intel_start_bus(struct sdw_intel *sdw); int intel_start_bus(struct sdw_intel *sdw);
int intel_start_bus_after_reset(struct sdw_intel *sdw); int intel_start_bus_after_reset(struct sdw_intel *sdw);

View File

@ -706,10 +706,30 @@ static void intel_program_sdi(struct sdw_intel *sdw, int dev_num)
__func__, sdw->instance, dev_num); __func__, sdw->instance, dev_num);
} }
static int intel_get_link_count(struct sdw_intel *sdw)
{
int ret;
ret = hdac_bus_eml_get_count(sdw->link_res->hbus, true, AZX_REG_ML_LEPTR_ID_SDW);
if (!ret) {
dev_err(sdw->cdns.dev, "%s: could not retrieve link count\n", __func__);
return -ENODEV;
}
if (ret > SDW_INTEL_MAX_LINKS) {
dev_err(sdw->cdns.dev, "%s: link count %d exceed max %d\n", __func__, ret, SDW_INTEL_MAX_LINKS);
return -EINVAL;
}
return ret;
}
const struct sdw_intel_hw_ops sdw_intel_lnl_hw_ops = { const struct sdw_intel_hw_ops sdw_intel_lnl_hw_ops = {
.debugfs_init = intel_ace2x_debugfs_init, .debugfs_init = intel_ace2x_debugfs_init,
.debugfs_exit = intel_ace2x_debugfs_exit, .debugfs_exit = intel_ace2x_debugfs_exit,
.get_link_count = intel_get_link_count,
.register_dai = intel_register_dai, .register_dai = intel_register_dai,
.check_clock_stop = intel_check_clock_stop, .check_clock_stop = intel_check_clock_stop,

View File

@ -317,6 +317,20 @@ static int intel_link_probe(struct auxiliary_device *auxdev,
bus->link_id = auxdev->id; bus->link_id = auxdev->id;
bus->clk_stop_timeout = 1; bus->clk_stop_timeout = 1;
/*
* paranoia check: make sure ACPI-reported number of links is aligned with
* hardware capabilities.
*/
ret = sdw_intel_get_link_count(sdw);
if (ret < 0) {
dev_err(dev, "%s: sdw_intel_get_link_count failed: %d\n", __func__, ret);
return ret;
}
if (ret <= sdw->instance) {
dev_err(dev, "%s: invalid link id %d, link count %d\n", __func__, auxdev->id, ret);
return -EINVAL;
}
sdw_cdns_probe(cdns); sdw_cdns_probe(cdns);
/* Set ops */ /* Set ops */

View File

@ -388,6 +388,7 @@ struct sdw_intel;
/* struct intel_sdw_hw_ops - SoundWire ops for Intel platforms. /* struct intel_sdw_hw_ops - SoundWire ops for Intel platforms.
* @debugfs_init: initialize all debugfs capabilities * @debugfs_init: initialize all debugfs capabilities
* @debugfs_exit: close and cleanup debugfs capabilities * @debugfs_exit: close and cleanup debugfs capabilities
* @get_link_count: fetch link count from hardware registers
* @register_dai: read all PDI information and register DAIs * @register_dai: read all PDI information and register DAIs
* @check_clock_stop: throw error message if clock is not stopped. * @check_clock_stop: throw error message if clock is not stopped.
* @start_bus: normal start * @start_bus: normal start
@ -412,6 +413,8 @@ struct sdw_intel_hw_ops {
void (*debugfs_init)(struct sdw_intel *sdw); void (*debugfs_init)(struct sdw_intel *sdw);
void (*debugfs_exit)(struct sdw_intel *sdw); void (*debugfs_exit)(struct sdw_intel *sdw);
int (*get_link_count)(struct sdw_intel *sdw);
int (*register_dai)(struct sdw_intel *sdw); int (*register_dai)(struct sdw_intel *sdw);
void (*check_clock_stop)(struct sdw_intel *sdw); void (*check_clock_stop)(struct sdw_intel *sdw);
@ -447,4 +450,9 @@ extern const struct sdw_intel_hw_ops sdw_intel_lnl_hw_ops;
#define SDW_INTEL_DEV_NUM_IDA_MIN 6 #define SDW_INTEL_DEV_NUM_IDA_MIN 6
/*
* Max number of links supported in hardware
*/
#define SDW_INTEL_MAX_LINKS 5
#endif #endif

View File

@ -72,6 +72,7 @@
#define ACI_SET_EQ7 0x46 /* ... to Treble */ #define ACI_SET_EQ7 0x46 /* ... to Treble */
struct snd_miro_aci { struct snd_miro_aci {
struct snd_card *card;
unsigned long aci_port; unsigned long aci_port;
int aci_vendor; int aci_vendor;
int aci_product; int aci_product;

View File

@ -110,18 +110,22 @@
#define IEC958_AES2_CON_SOURCE_UNSPEC (0<<0) /* unspecified */ #define IEC958_AES2_CON_SOURCE_UNSPEC (0<<0) /* unspecified */
#define IEC958_AES2_CON_CHANNEL (15<<4) /* mask - channel number */ #define IEC958_AES2_CON_CHANNEL (15<<4) /* mask - channel number */
#define IEC958_AES2_CON_CHANNEL_UNSPEC (0<<4) /* unspecified */ #define IEC958_AES2_CON_CHANNEL_UNSPEC (0<<4) /* unspecified */
#define IEC958_AES3_CON_FS (15<<0) /* mask - sample frequency */ #define IEC958_AES3_CON_FS ((1<<7) | (15<<0)) /* mask - sample frequency */
#define IEC958_AES3_CON_FS_44100 (0<<0) /* 44.1kHz */ #define IEC958_AES3_CON_FS_44100 (0<<0) /* 44.1kHz */
#define IEC958_AES3_CON_FS_NOTID (1<<0) /* non indicated */ #define IEC958_AES3_CON_FS_NOTID (1<<0) /* non indicated */
#define IEC958_AES3_CON_FS_48000 (2<<0) /* 48kHz */ #define IEC958_AES3_CON_FS_48000 (2<<0) /* 48kHz */
#define IEC958_AES3_CON_FS_32000 (3<<0) /* 32kHz */ #define IEC958_AES3_CON_FS_32000 (3<<0) /* 32kHz */
#define IEC958_AES3_CON_FS_22050 (4<<0) /* 22.05kHz */ #define IEC958_AES3_CON_FS_22050 (4<<0) /* 22.05kHz */
#define IEC958_AES3_CON_FS_384000 (5<<0) /* 384kHz */
#define IEC958_AES3_CON_FS_24000 (6<<0) /* 24kHz */ #define IEC958_AES3_CON_FS_24000 (6<<0) /* 24kHz */
#define IEC958_AES3_CON_FS_88200 (8<<0) /* 88.2kHz */ #define IEC958_AES3_CON_FS_88200 (8<<0) /* 88.2kHz */
#define IEC958_AES3_CON_FS_768000 (9<<0) /* 768kHz */ #define IEC958_AES3_CON_FS_768000 (9<<0) /* 768kHz */
#define IEC958_AES3_CON_FS_96000 (10<<0) /* 96kHz */ #define IEC958_AES3_CON_FS_96000 (10<<0) /* 96kHz */
#define IEC958_AES3_CON_FS_176400 (12<<0) /* 176.4kHz */ #define IEC958_AES3_CON_FS_176400 (12<<0) /* 176.4kHz */
#define IEC958_AES3_CON_FS_352400 (13<<0) /* 352.4kHz */
#define IEC958_AES3_CON_FS_192000 (14<<0) /* 192kHz */ #define IEC958_AES3_CON_FS_192000 (14<<0) /* 192kHz */
#define IEC958_AES3_CON_FS_128000 ((1<<7) | (11<<0)) /* 128kHz */
#define IEC958_AES3_CON_FS_705600 ((1<<7) | (13<<0)) /* 705.6kHz */
#define IEC958_AES3_CON_CLOCK (3<<4) /* mask - clock accuracy */ #define IEC958_AES3_CON_CLOCK (3<<4) /* mask - clock accuracy */
#define IEC958_AES3_CON_CLOCK_1000PPM (0<<4) /* 1000 ppm */ #define IEC958_AES3_CON_CLOCK_1000PPM (0<<4) /* 1000 ppm */
#define IEC958_AES3_CON_CLOCK_50PPM (1<<4) /* 50 ppm */ #define IEC958_AES3_CON_CLOCK_50PPM (1<<4) /* 50 ppm */

View File

@ -81,7 +81,7 @@ struct snd_kcontrol {
unsigned long private_value; unsigned long private_value;
void *private_data; void *private_data;
void (*private_free)(struct snd_kcontrol *kcontrol); void (*private_free)(struct snd_kcontrol *kcontrol);
struct snd_kcontrol_volatile vd[]; /* volatile data */ struct snd_kcontrol_volatile vd[] __counted_by(count); /* volatile data */
}; };
#define snd_kcontrol(n) list_entry(n, struct snd_kcontrol, list) #define snd_kcontrol(n) list_entry(n, struct snd_kcontrol, list)
@ -140,9 +140,7 @@ int snd_ctl_remove_id(struct snd_card * card, struct snd_ctl_elem_id *id);
int snd_ctl_rename_id(struct snd_card * card, struct snd_ctl_elem_id *src_id, struct snd_ctl_elem_id *dst_id); int snd_ctl_rename_id(struct snd_card * card, struct snd_ctl_elem_id *src_id, struct snd_ctl_elem_id *dst_id);
void snd_ctl_rename(struct snd_card *card, struct snd_kcontrol *kctl, const char *name); void snd_ctl_rename(struct snd_card *card, struct snd_kcontrol *kctl, const char *name);
int snd_ctl_activate_id(struct snd_card *card, struct snd_ctl_elem_id *id, int active); int snd_ctl_activate_id(struct snd_card *card, struct snd_ctl_elem_id *id, int active);
struct snd_kcontrol *snd_ctl_find_numid_locked(struct snd_card *card, unsigned int numid);
struct snd_kcontrol *snd_ctl_find_numid(struct snd_card *card, unsigned int numid); struct snd_kcontrol *snd_ctl_find_numid(struct snd_card *card, unsigned int numid);
struct snd_kcontrol *snd_ctl_find_id_locked(struct snd_card *card, const struct snd_ctl_elem_id *id);
struct snd_kcontrol *snd_ctl_find_id(struct snd_card *card, const struct snd_ctl_elem_id *id); struct snd_kcontrol *snd_ctl_find_id(struct snd_card *card, const struct snd_ctl_elem_id *id);
/** /**
@ -167,29 +165,6 @@ snd_ctl_find_id_mixer(struct snd_card *card, const char *name)
return snd_ctl_find_id(card, &id); return snd_ctl_find_id(card, &id);
} }
/**
* snd_ctl_find_id_mixer_locked - find the control instance with the given name string
* @card: the card instance
* @name: the name string
*
* Finds the control instance with the given name and
* @SNDRV_CTL_ELEM_IFACE_MIXER. Other fields are set to zero.
*
* This is merely a wrapper to snd_ctl_find_id_locked().
* The caller must down card->controls_rwsem before calling this function.
*
* Return: The pointer of the instance if found, or %NULL if not.
*/
static inline struct snd_kcontrol *
snd_ctl_find_id_mixer_locked(struct snd_card *card, const char *name)
{
struct snd_ctl_elem_id id = {};
id.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
strscpy(id.name, name, sizeof(id.name));
return snd_ctl_find_id_locked(card, &id);
}
int snd_ctl_create(struct snd_card *card); int snd_ctl_create(struct snd_card *card);
int snd_ctl_register_ioctl(snd_kctl_ioctl_func_t fcn); int snd_ctl_register_ioctl(snd_kctl_ioctl_func_t fcn);

View File

@ -99,7 +99,7 @@ struct snd_card {
struct device *ctl_dev; /* control device */ struct device *ctl_dev; /* control device */
unsigned int last_numid; /* last used numeric ID */ unsigned int last_numid; /* last used numeric ID */
struct rw_semaphore controls_rwsem; /* controls lock (list and values) */ struct rw_semaphore controls_rwsem; /* controls lock (list and values) */
rwlock_t ctl_files_rwlock; /* ctl_files list lock */ rwlock_t controls_rwlock; /* lock for lookup and ctl_files list */
int controls_count; /* count of all controls */ int controls_count; /* count of all controls */
size_t user_ctl_alloc_size; // current memory allocation by user controls. size_t user_ctl_alloc_size; // current memory allocation by user controls.
struct list_head controls; /* all controls for this card */ struct list_head controls; /* all controls for this card */
@ -345,45 +345,7 @@ void release_and_free_resource(struct resource *res);
/* --- */ /* --- */
/* sound printk debug levels */
enum {
SND_PR_ALWAYS,
SND_PR_DEBUG,
SND_PR_VERBOSE,
};
#if defined(CONFIG_SND_DEBUG) || defined(CONFIG_SND_VERBOSE_PRINTK)
__printf(4, 5)
void __snd_printk(unsigned int level, const char *file, int line,
const char *format, ...);
#else
#define __snd_printk(level, file, line, format, ...) \
printk(format, ##__VA_ARGS__)
#endif
/**
* snd_printk - printk wrapper
* @fmt: format string
*
* Works like printk() but prints the file and the line of the caller
* when configured with CONFIG_SND_VERBOSE_PRINTK.
*/
#define snd_printk(fmt, ...) \
__snd_printk(0, __FILE__, __LINE__, fmt, ##__VA_ARGS__)
#ifdef CONFIG_SND_DEBUG #ifdef CONFIG_SND_DEBUG
/**
* snd_printd - debug printk
* @fmt: format string
*
* Works like snd_printk() for debugging purposes.
* Ignored when CONFIG_SND_DEBUG is not set.
*/
#define snd_printd(fmt, ...) \
__snd_printk(1, __FILE__, __LINE__, fmt, ##__VA_ARGS__)
#define _snd_printd(level, fmt, ...) \
__snd_printk(level, __FILE__, __LINE__, fmt, ##__VA_ARGS__)
/** /**
* snd_BUG - give a BUG warning message and stack trace * snd_BUG - give a BUG warning message and stack trace
* *
@ -392,12 +354,6 @@ void __snd_printk(unsigned int level, const char *file, int line,
*/ */
#define snd_BUG() WARN(1, "BUG?\n") #define snd_BUG() WARN(1, "BUG?\n")
/**
* snd_printd_ratelimit - Suppress high rates of output when
* CONFIG_SND_DEBUG is enabled.
*/
#define snd_printd_ratelimit() printk_ratelimit()
/** /**
* snd_BUG_ON - debugging check macro * snd_BUG_ON - debugging check macro
* @cond: condition to evaluate * @cond: condition to evaluate
@ -409,11 +365,6 @@ void __snd_printk(unsigned int level, const char *file, int line,
#else /* !CONFIG_SND_DEBUG */ #else /* !CONFIG_SND_DEBUG */
__printf(1, 2)
static inline void snd_printd(const char *format, ...) {}
__printf(2, 3)
static inline void _snd_printd(int level, const char *format, ...) {}
#define snd_BUG() do { } while (0) #define snd_BUG() do { } while (0)
#define snd_BUG_ON(condition) ({ \ #define snd_BUG_ON(condition) ({ \
@ -421,26 +372,8 @@ static inline void _snd_printd(int level, const char *format, ...) {}
unlikely(__ret_warn_on); \ unlikely(__ret_warn_on); \
}) })
static inline bool snd_printd_ratelimit(void) { return false; }
#endif /* CONFIG_SND_DEBUG */ #endif /* CONFIG_SND_DEBUG */
#ifdef CONFIG_SND_DEBUG_VERBOSE
/**
* snd_printdd - debug printk
* @format: format string
*
* Works like snd_printk() for debugging purposes.
* Ignored when CONFIG_SND_DEBUG_VERBOSE is not set.
*/
#define snd_printdd(format, ...) \
__snd_printk(2, __FILE__, __LINE__, format, ##__VA_ARGS__)
#else
__printf(1, 2)
static inline void snd_printdd(const char *format, ...) {}
#endif
#define SNDRV_OSS_VERSION ((3<<16)|(8<<8)|(1<<4)|(0)) /* 3.8.1a */ #define SNDRV_OSS_VERSION ((3<<16)|(8<<8)|(1<<4)|(0)) /* 3.8.1a */
/* for easier backward-porting */ /* for easier backward-porting */

View File

@ -282,9 +282,9 @@ static inline bool cs35l56_is_otp_register(unsigned int reg)
return (reg >> 16) == 3; return (reg >> 16) == 3;
} }
extern struct regmap_config cs35l56_regmap_i2c; extern const struct regmap_config cs35l56_regmap_i2c;
extern struct regmap_config cs35l56_regmap_spi; extern const struct regmap_config cs35l56_regmap_spi;
extern struct regmap_config cs35l56_regmap_sdw; extern const struct regmap_config cs35l56_regmap_sdw;
extern const struct cirrus_amp_cal_controls cs35l56_calibration_controls; extern const struct cirrus_amp_cal_controls cs35l56_calibration_controls;

View File

@ -17,6 +17,7 @@
#define ES1688_HW_UNDEF 0x0003 #define ES1688_HW_UNDEF 0x0003
struct snd_es1688 { struct snd_es1688 {
struct snd_card *card;
unsigned long port; /* port of ESS chip */ unsigned long port; /* port of ESS chip */
struct resource *res_port; struct resource *res_port;
unsigned long mpu_port; /* MPU-401 port of ESS chip */ unsigned long mpu_port; /* MPU-401 port of ESS chip */

View File

@ -42,17 +42,12 @@ struct snd_dma_device {
#define SNDRV_DMA_TYPE_NONCONTIG 8 /* non-coherent SG buffer */ #define SNDRV_DMA_TYPE_NONCONTIG 8 /* non-coherent SG buffer */
#define SNDRV_DMA_TYPE_NONCOHERENT 9 /* non-coherent buffer */ #define SNDRV_DMA_TYPE_NONCOHERENT 9 /* non-coherent buffer */
#ifdef CONFIG_SND_DMA_SGBUF #ifdef CONFIG_SND_DMA_SGBUF
#define SNDRV_DMA_TYPE_DEV_SG SNDRV_DMA_TYPE_NONCONTIG #define SNDRV_DMA_TYPE_DEV_SG 3 /* S/G pages */
#define SNDRV_DMA_TYPE_DEV_WC_SG 6 /* SG write-combined */ #define SNDRV_DMA_TYPE_DEV_WC_SG 6 /* SG write-combined */
#else #else
#define SNDRV_DMA_TYPE_DEV_SG SNDRV_DMA_TYPE_DEV /* no SG-buf support */ #define SNDRV_DMA_TYPE_DEV_SG SNDRV_DMA_TYPE_DEV /* no SG-buf support */
#define SNDRV_DMA_TYPE_DEV_WC_SG SNDRV_DMA_TYPE_DEV_WC #define SNDRV_DMA_TYPE_DEV_WC_SG SNDRV_DMA_TYPE_DEV_WC
#endif #endif
/* fallback types, don't use those directly */
#ifdef CONFIG_SND_DMA_SGBUF
#define SNDRV_DMA_TYPE_DEV_SG_FALLBACK 10
#define SNDRV_DMA_TYPE_DEV_WC_SG_FALLBACK 11
#endif
/* /*
* info for buffer allocation * info for buffer allocation

View File

@ -123,6 +123,10 @@ struct snd_pcm_ops {
#define SNDRV_PCM_RATE_384000 (1U<<14) /* 384000Hz */ #define SNDRV_PCM_RATE_384000 (1U<<14) /* 384000Hz */
#define SNDRV_PCM_RATE_705600 (1U<<15) /* 705600Hz */ #define SNDRV_PCM_RATE_705600 (1U<<15) /* 705600Hz */
#define SNDRV_PCM_RATE_768000 (1U<<16) /* 768000Hz */ #define SNDRV_PCM_RATE_768000 (1U<<16) /* 768000Hz */
/* extended rates since 6.12 */
#define SNDRV_PCM_RATE_12000 (1U<<17) /* 12000Hz */
#define SNDRV_PCM_RATE_24000 (1U<<18) /* 24000Hz */
#define SNDRV_PCM_RATE_128000 (1U<<19) /* 128000Hz */
#define SNDRV_PCM_RATE_CONTINUOUS (1U<<30) /* continuous range */ #define SNDRV_PCM_RATE_CONTINUOUS (1U<<30) /* continuous range */
#define SNDRV_PCM_RATE_KNOT (1U<<31) /* supports more non-continuous rates */ #define SNDRV_PCM_RATE_KNOT (1U<<31) /* supports more non-continuous rates */
@ -498,6 +502,9 @@ struct snd_pcm_substream {
/* misc flags */ /* misc flags */
unsigned int hw_opened: 1; unsigned int hw_opened: 1;
unsigned int managed_buffer_alloc:1; unsigned int managed_buffer_alloc:1;
#ifdef CONFIG_SND_PCM_XRUN_DEBUG
unsigned int xrun_counter; /* number of times xrun happens */
#endif /* CONFIG_SND_PCM_XRUN_DEBUG */
}; };
#define SUBSTREAM_BUSY(substream) ((substream)->ref_count > 0) #define SUBSTREAM_BUSY(substream) ((substream)->ref_count > 0)
@ -1355,48 +1362,6 @@ snd_pcm_set_fixed_buffer_all(struct snd_pcm *pcm, int type,
return snd_pcm_set_managed_buffer_all(pcm, type, data, size, 0); return snd_pcm_set_managed_buffer_all(pcm, type, data, size, 0);
} }
int _snd_pcm_lib_alloc_vmalloc_buffer(struct snd_pcm_substream *substream,
size_t size, gfp_t gfp_flags);
int snd_pcm_lib_free_vmalloc_buffer(struct snd_pcm_substream *substream);
struct page *snd_pcm_lib_get_vmalloc_page(struct snd_pcm_substream *substream,
unsigned long offset);
/**
* snd_pcm_lib_alloc_vmalloc_buffer - allocate virtual DMA buffer
* @substream: the substream to allocate the buffer to
* @size: the requested buffer size, in bytes
*
* Allocates the PCM substream buffer using vmalloc(), i.e., the memory is
* contiguous in kernel virtual space, but not in physical memory. Use this
* if the buffer is accessed by kernel code but not by device DMA.
*
* Return: 1 if the buffer was changed, 0 if not changed, or a negative error
* code.
*/
static inline int snd_pcm_lib_alloc_vmalloc_buffer
(struct snd_pcm_substream *substream, size_t size)
{
return _snd_pcm_lib_alloc_vmalloc_buffer(substream, size,
GFP_KERNEL | __GFP_HIGHMEM | __GFP_ZERO);
}
/**
* snd_pcm_lib_alloc_vmalloc_32_buffer - allocate 32-bit-addressable buffer
* @substream: the substream to allocate the buffer to
* @size: the requested buffer size, in bytes
*
* This function works like snd_pcm_lib_alloc_vmalloc_buffer(), but uses
* vmalloc_32(), i.e., the pages are allocated from 32-bit-addressable memory.
*
* Return: 1 if the buffer was changed, 0 if not changed, or a negative error
* code.
*/
static inline int snd_pcm_lib_alloc_vmalloc_32_buffer
(struct snd_pcm_substream *substream, size_t size)
{
return _snd_pcm_lib_alloc_vmalloc_buffer(substream, size,
GFP_KERNEL | GFP_DMA32 | __GFP_ZERO);
}
#define snd_pcm_get_dma_buf(substream) ((substream)->runtime->dma_buffer_p) #define snd_pcm_get_dma_buf(substream) ((substream)->runtime->dma_buffer_p)
/** /**

View File

@ -86,10 +86,6 @@ static inline size_t snd_seq_event_packet_size(struct snd_seq_event *ev)
/* interface for OSS emulation */ /* interface for OSS emulation */
int snd_seq_set_queue_tempo(int client, struct snd_seq_queue_tempo *tempo); int snd_seq_set_queue_tempo(int client, struct snd_seq_queue_tempo *tempo);
/* port callback routines */
void snd_port_init_callback(struct snd_seq_port_callback *p);
struct snd_seq_port_callback *snd_port_alloc_callback(void);
/* port attach/detach */ /* port attach/detach */
int snd_seq_event_port_attach(int client, struct snd_seq_port_callback *pcbp, int snd_seq_event_port_attach(int client, struct snd_seq_port_callback *pcbp,
int cap, int type, int midi_channels, int midi_voices, char *portname); int cap, int type, int midi_channels, int midi_voices, char *portname);

View File

@ -137,8 +137,4 @@ extern int snd_wavefront_fx_ioctl (struct snd_hwdep *,
extern int snd_wavefront_fx_open (struct snd_hwdep *, struct file *); extern int snd_wavefront_fx_open (struct snd_hwdep *, struct file *);
extern int snd_wavefront_fx_release (struct snd_hwdep *, struct file *); extern int snd_wavefront_fx_release (struct snd_hwdep *, struct file *);
/* prefix in all snd_printk() delivered messages */
#define LOGNAME "WaveFront: "
#endif /* __SOUND_SND_WAVEFRONT_H__ */ #endif /* __SOUND_SND_WAVEFRONT_H__ */

View File

@ -33,6 +33,7 @@ extern struct snd_soc_acpi_mach snd_soc_acpi_intel_rpl_machines[];
extern struct snd_soc_acpi_mach snd_soc_acpi_intel_mtl_machines[]; extern struct snd_soc_acpi_mach snd_soc_acpi_intel_mtl_machines[];
extern struct snd_soc_acpi_mach snd_soc_acpi_intel_lnl_machines[]; extern struct snd_soc_acpi_mach snd_soc_acpi_intel_lnl_machines[];
extern struct snd_soc_acpi_mach snd_soc_acpi_intel_arl_machines[]; extern struct snd_soc_acpi_mach snd_soc_acpi_intel_arl_machines[];
extern struct snd_soc_acpi_mach snd_soc_acpi_intel_ptl_machines[];
extern struct snd_soc_acpi_mach snd_soc_acpi_intel_cnl_sdw_machines[]; extern struct snd_soc_acpi_mach snd_soc_acpi_intel_cnl_sdw_machines[];
extern struct snd_soc_acpi_mach snd_soc_acpi_intel_cfl_sdw_machines[]; extern struct snd_soc_acpi_mach snd_soc_acpi_intel_cfl_sdw_machines[];
@ -44,6 +45,7 @@ extern struct snd_soc_acpi_mach snd_soc_acpi_intel_rpl_sdw_machines[];
extern struct snd_soc_acpi_mach snd_soc_acpi_intel_mtl_sdw_machines[]; extern struct snd_soc_acpi_mach snd_soc_acpi_intel_mtl_sdw_machines[];
extern struct snd_soc_acpi_mach snd_soc_acpi_intel_lnl_sdw_machines[]; extern struct snd_soc_acpi_mach snd_soc_acpi_intel_lnl_sdw_machines[];
extern struct snd_soc_acpi_mach snd_soc_acpi_intel_arl_sdw_machines[]; extern struct snd_soc_acpi_mach snd_soc_acpi_intel_arl_sdw_machines[];
extern struct snd_soc_acpi_mach snd_soc_acpi_intel_ptl_sdw_machines[];
/* /*
* generic table used for HDA codec-based platforms, possibly with * generic table used for HDA codec-based platforms, possibly with

View File

@ -62,7 +62,6 @@ static inline struct snd_soc_acpi_mach *snd_soc_acpi_codec_list(void *arg)
* @platform: string used for HDAudio codec support * @platform: string used for HDAudio codec support
* @codec_mask: used for HDAudio support * @codec_mask: used for HDAudio support
* @dmic_num: number of SoC- or chipset-attached PDM digital microphones * @dmic_num: number of SoC- or chipset-attached PDM digital microphones
* @common_hdmi_codec_drv: use commom HDAudio HDMI codec driver
* @link_mask: SoundWire links enabled on the board * @link_mask: SoundWire links enabled on the board
* @links: array of SoundWire link _ADR descriptors, null terminated * @links: array of SoundWire link _ADR descriptors, null terminated
* @i2s_link_mask: I2S/TDM links enabled on the board * @i2s_link_mask: I2S/TDM links enabled on the board
@ -70,15 +69,16 @@ static inline struct snd_soc_acpi_mach *snd_soc_acpi_codec_list(void *arg)
* @dai_drivers: pointer to dai_drivers, used e.g. in nocodec mode * @dai_drivers: pointer to dai_drivers, used e.g. in nocodec mode
* @subsystem_vendor: optional PCI SSID vendor value * @subsystem_vendor: optional PCI SSID vendor value
* @subsystem_device: optional PCI SSID device value * @subsystem_device: optional PCI SSID device value
* @subsystem_rev: optional PCI SSID revision value
* @subsystem_id_set: true if a value has been written to * @subsystem_id_set: true if a value has been written to
* subsystem_vendor and subsystem_device. * subsystem_vendor and subsystem_device.
* @bt_link_mask: BT offload link enabled on the board
*/ */
struct snd_soc_acpi_mach_params { struct snd_soc_acpi_mach_params {
u32 acpi_ipc_irq_index; u32 acpi_ipc_irq_index;
const char *platform; const char *platform;
u32 codec_mask; u32 codec_mask;
u32 dmic_num; u32 dmic_num;
bool common_hdmi_codec_drv;
u32 link_mask; u32 link_mask;
const struct snd_soc_acpi_link_adr *links; const struct snd_soc_acpi_link_adr *links;
u32 i2s_link_mask; u32 i2s_link_mask;
@ -86,7 +86,9 @@ struct snd_soc_acpi_mach_params {
struct snd_soc_dai_driver *dai_drivers; struct snd_soc_dai_driver *dai_drivers;
unsigned short subsystem_vendor; unsigned short subsystem_vendor;
unsigned short subsystem_device; unsigned short subsystem_device;
unsigned short subsystem_rev;
bool subsystem_id_set; bool subsystem_id_set;
u32 bt_link_mask;
}; };
/** /**

View File

@ -30,8 +30,6 @@ static inline void snd_soc_card_mutex_unlock(struct snd_soc_card *card)
struct snd_kcontrol *snd_soc_card_get_kcontrol(struct snd_soc_card *soc_card, struct snd_kcontrol *snd_soc_card_get_kcontrol(struct snd_soc_card *soc_card,
const char *name); const char *name);
struct snd_kcontrol *snd_soc_card_get_kcontrol_locked(struct snd_soc_card *soc_card,
const char *name);
int snd_soc_card_jack_new(struct snd_soc_card *card, const char *id, int type, int snd_soc_card_jack_new(struct snd_soc_card *card, const char *id, int type,
struct snd_soc_jack *jack); struct snd_soc_jack *jack);
int snd_soc_card_jack_new_pins(struct snd_soc_card *card, const char *id, int snd_soc_card_jack_new_pins(struct snd_soc_card *card, const char *id,

View File

@ -464,9 +464,6 @@ int snd_soc_component_force_enable_pin_unlocked(
/* component controls */ /* component controls */
struct snd_kcontrol *snd_soc_component_get_kcontrol(struct snd_soc_component *component, struct snd_kcontrol *snd_soc_component_get_kcontrol(struct snd_soc_component *component,
const char * const ctl); const char * const ctl);
struct snd_kcontrol *
snd_soc_component_get_kcontrol_locked(struct snd_soc_component *component,
const char * const ctl);
int snd_soc_component_notify_control(struct snd_soc_component *component, int snd_soc_component_notify_control(struct snd_soc_component *component,
const char * const ctl); const char * const ctl);

View File

@ -219,7 +219,6 @@ void snd_soc_dai_resume(struct snd_soc_dai *dai);
int snd_soc_dai_compress_new(struct snd_soc_dai *dai, int snd_soc_dai_compress_new(struct snd_soc_dai *dai,
struct snd_soc_pcm_runtime *rtd, int num); struct snd_soc_pcm_runtime *rtd, int num);
bool snd_soc_dai_stream_valid(const struct snd_soc_dai *dai, int stream); bool snd_soc_dai_stream_valid(const struct snd_soc_dai *dai, int stream);
void snd_soc_dai_link_set_capabilities(struct snd_soc_dai_link *dai_link);
void snd_soc_dai_action(struct snd_soc_dai *dai, void snd_soc_dai_action(struct snd_soc_dai *dai,
int stream, int action); int stream, int action);
static inline void snd_soc_dai_activate(struct snd_soc_dai *dai, static inline void snd_soc_dai_activate(struct snd_soc_dai *dai,
@ -240,8 +239,6 @@ int snd_soc_pcm_dai_new(struct snd_soc_pcm_runtime *rtd);
int snd_soc_pcm_dai_prepare(struct snd_pcm_substream *substream); int snd_soc_pcm_dai_prepare(struct snd_pcm_substream *substream);
int snd_soc_pcm_dai_trigger(struct snd_pcm_substream *substream, int cmd, int snd_soc_pcm_dai_trigger(struct snd_pcm_substream *substream, int cmd,
int rollback); int rollback);
int snd_soc_pcm_dai_bespoke_trigger(struct snd_pcm_substream *substream,
int cmd);
void snd_soc_pcm_dai_delay(struct snd_pcm_substream *substream, void snd_soc_pcm_dai_delay(struct snd_pcm_substream *substream,
snd_pcm_sframes_t *cpu_delay, snd_pcm_sframes_t *codec_delay); snd_pcm_sframes_t *cpu_delay, snd_pcm_sframes_t *codec_delay);
@ -345,8 +342,7 @@ struct snd_soc_dai_ops {
*/ */
int (*trigger)(struct snd_pcm_substream *, int, int (*trigger)(struct snd_pcm_substream *, int,
struct snd_soc_dai *); struct snd_soc_dai *);
int (*bespoke_trigger)(struct snd_pcm_substream *, int,
struct snd_soc_dai *);
/* /*
* For hardware based FIFO caused delay reporting. * For hardware based FIFO caused delay reporting.
* Optional. * Optional.

View File

@ -58,7 +58,6 @@ enum snd_soc_dpcm_state {
enum snd_soc_dpcm_trigger { enum snd_soc_dpcm_trigger {
SND_SOC_DPCM_TRIGGER_PRE = 0, SND_SOC_DPCM_TRIGGER_PRE = 0,
SND_SOC_DPCM_TRIGGER_POST, SND_SOC_DPCM_TRIGGER_POST,
SND_SOC_DPCM_TRIGGER_BESPOKE,
}; };
/* /*
@ -114,24 +113,6 @@ struct snd_soc_dpcm_runtime {
#define for_each_dpcm_be_rollback(fe, stream, _dpcm) \ #define for_each_dpcm_be_rollback(fe, stream, _dpcm) \
list_for_each_entry_continue_reverse(_dpcm, &(fe)->dpcm[stream].be_clients, list_be) list_for_each_entry_continue_reverse(_dpcm, &(fe)->dpcm[stream].be_clients, list_be)
/* can this BE stop and free */
int snd_soc_dpcm_can_be_free_stop(struct snd_soc_pcm_runtime *fe,
struct snd_soc_pcm_runtime *be, int stream);
/* can this BE perform a hw_params() */
int snd_soc_dpcm_can_be_params(struct snd_soc_pcm_runtime *fe,
struct snd_soc_pcm_runtime *be, int stream);
/* can this BE perform prepare */
int snd_soc_dpcm_can_be_prepared(struct snd_soc_pcm_runtime *fe,
struct snd_soc_pcm_runtime *be, int stream);
/* is the current PCM operation for this FE ? */
int snd_soc_dpcm_fe_can_update(struct snd_soc_pcm_runtime *fe, int stream);
/* is the current PCM operation for this BE ? */
int snd_soc_dpcm_be_can_update(struct snd_soc_pcm_runtime *fe,
struct snd_soc_pcm_runtime *be, int stream);
/* get the substream for this BE */ /* get the substream for this BE */
struct snd_pcm_substream * struct snd_pcm_substream *

View File

@ -815,6 +815,7 @@ struct snd_soc_dai_link {
/* This DAI link can route to other DAI links at runtime (Frontend)*/ /* This DAI link can route to other DAI links at runtime (Frontend)*/
unsigned int dynamic:1; unsigned int dynamic:1;
/* REMOVE ME */
/* DPCM capture and Playback support */ /* DPCM capture and Playback support */
unsigned int dpcm_capture:1; unsigned int dpcm_capture:1;
unsigned int dpcm_playback:1; unsigned int dpcm_playback:1;
@ -1206,11 +1207,11 @@ struct snd_soc_pcm_runtime {
/* bit field */ /* bit field */
unsigned int pop_wait:1; unsigned int pop_wait:1;
unsigned int fe_compr:1; /* for Dynamic PCM */ unsigned int fe_compr:1; /* for Dynamic PCM */
unsigned int initialized:1;
bool initialized; /* CPU/Codec/Platform */
int num_components; int num_components;
struct snd_soc_component *components[]; /* CPU/Codec/Platform */ struct snd_soc_component *components[] __counted_by(num_components);
}; };
/* see soc_new_pcm_runtime() */ /* see soc_new_pcm_runtime() */

View File

@ -0,0 +1,247 @@
/* SPDX-License-Identifier: GPL-2.0-only */
/*
* This file incorporates work covered by the following copyright notice:
* Copyright (c) 2020 Intel Corporation
* Copyright(c) 2024 Advanced Micro Devices, Inc.
*
*/
#ifndef SOC_SDW_UTILS_H
#define SOC_SDW_UTILS_H
#include <sound/soc.h>
#include <sound/soc-acpi.h>
#define SOC_SDW_MAX_DAI_NUM 8
#define SOC_SDW_MAX_NO_PROPS 2
#define SOC_SDW_JACK_JDSRC(quirk) ((quirk) & GENMASK(3, 0))
/* If a CODEC has an optional speaker output, this quirk will enable it */
#define SOC_SDW_CODEC_SPKR BIT(15)
/*
* If the CODEC has additional devices attached directly to it.
*
* For the cs42l43:
* - 0 - No speaker output
* - SOC_SDW_CODEC_SPKR - CODEC internal speaker
* - SOC_SDW_SIDECAR_AMPS - 2x Sidecar amplifiers + CODEC internal speaker
* - SOC_SDW_CODEC_SPKR | SOF_SIDECAR_AMPS - Not currently supported
*/
#define SOC_SDW_SIDECAR_AMPS BIT(16)
#define SOC_SDW_UNUSED_DAI_ID -1
#define SOC_SDW_JACK_OUT_DAI_ID 0
#define SOC_SDW_JACK_IN_DAI_ID 1
#define SOC_SDW_AMP_OUT_DAI_ID 2
#define SOC_SDW_AMP_IN_DAI_ID 3
#define SOC_SDW_DMIC_DAI_ID 4
#define SOC_SDW_DAI_TYPE_JACK 0
#define SOC_SDW_DAI_TYPE_AMP 1
#define SOC_SDW_DAI_TYPE_MIC 2
struct asoc_sdw_codec_info;
struct asoc_sdw_dai_info {
const bool direction[2]; /* playback & capture support */
const char *dai_name;
const int dai_type;
const int dailink[2]; /* dailink id for each direction */
const struct snd_kcontrol_new *controls;
const int num_controls;
const struct snd_soc_dapm_widget *widgets;
const int num_widgets;
int (*init)(struct snd_soc_card *card,
struct snd_soc_dai_link *dai_links,
struct asoc_sdw_codec_info *info,
bool playback);
int (*exit)(struct snd_soc_card *card, struct snd_soc_dai_link *dai_link);
int (*rtd_init)(struct snd_soc_pcm_runtime *rtd, struct snd_soc_dai *dai);
bool rtd_init_done; /* Indicate that the rtd_init callback is done */
unsigned long quirk;
};
struct asoc_sdw_codec_info {
const int part_id;
const int version_id;
const char *codec_name;
int amp_num;
const u8 acpi_id[ACPI_ID_LEN];
const bool ignore_internal_dmic;
const struct snd_soc_ops *ops;
struct asoc_sdw_dai_info dais[SOC_SDW_MAX_DAI_NUM];
const int dai_num;
int (*codec_card_late_probe)(struct snd_soc_card *card);
int (*count_sidecar)(struct snd_soc_card *card,
int *num_dais, int *num_devs);
int (*add_sidecar)(struct snd_soc_card *card,
struct snd_soc_dai_link **dai_links,
struct snd_soc_codec_conf **codec_conf);
};
struct asoc_sdw_mc_private {
struct snd_soc_card card;
struct snd_soc_jack sdw_headset;
struct device *headset_codec_dev; /* only one headset per card */
struct device *amp_dev1, *amp_dev2;
bool append_dai_type;
bool ignore_internal_dmic;
void *private;
unsigned long mc_quirk;
int codec_info_list_count;
};
struct asoc_sdw_endpoint {
struct list_head list;
u32 link_mask;
const char *codec_name;
const char *name_prefix;
bool include_sidecar;
struct asoc_sdw_codec_info *codec_info;
const struct asoc_sdw_dai_info *dai_info;
};
struct asoc_sdw_dailink {
bool initialised;
u8 group_id;
u32 link_mask[SNDRV_PCM_STREAM_LAST + 1];
int num_devs[SNDRV_PCM_STREAM_LAST + 1];
struct list_head endpoints;
};
extern struct asoc_sdw_codec_info codec_info_list[];
int asoc_sdw_get_codec_info_list_count(void);
int asoc_sdw_startup(struct snd_pcm_substream *substream);
int asoc_sdw_prepare(struct snd_pcm_substream *substream);
int asoc_sdw_prepare(struct snd_pcm_substream *substream);
int asoc_sdw_trigger(struct snd_pcm_substream *substream, int cmd);
int asoc_sdw_hw_params(struct snd_pcm_substream *substream,
struct snd_pcm_hw_params *params);
int asoc_sdw_hw_free(struct snd_pcm_substream *substream);
void asoc_sdw_shutdown(struct snd_pcm_substream *substream);
const char *asoc_sdw_get_codec_name(struct device *dev,
const struct asoc_sdw_codec_info *codec_info,
const struct snd_soc_acpi_link_adr *adr_link,
int adr_index);
struct asoc_sdw_codec_info *asoc_sdw_find_codec_info_part(const u64 adr);
struct asoc_sdw_codec_info *asoc_sdw_find_codec_info_acpi(const u8 *acpi_id);
struct asoc_sdw_codec_info *asoc_sdw_find_codec_info_dai(const char *dai_name,
int *dai_index);
struct snd_soc_dai_link *asoc_sdw_mc_find_codec_dai_used(struct snd_soc_card *card,
const char *dai_name);
void asoc_sdw_mc_dailink_exit_loop(struct snd_soc_card *card);
int asoc_sdw_card_late_probe(struct snd_soc_card *card);
void asoc_sdw_init_dai_link(struct device *dev, struct snd_soc_dai_link *dai_links,
int *be_id, char *name, int playback, int capture,
struct snd_soc_dai_link_component *cpus, int cpus_num,
struct snd_soc_dai_link_component *platform_component,
int num_platforms, struct snd_soc_dai_link_component *codecs,
int codecs_num, int (*init)(struct snd_soc_pcm_runtime *rtd),
const struct snd_soc_ops *ops);
int asoc_sdw_init_simple_dai_link(struct device *dev, struct snd_soc_dai_link *dai_links,
int *be_id, char *name, int playback, int capture,
const char *cpu_dai_name, const char *platform_comp_name,
int num_platforms, const char *codec_name,
const char *codec_dai_name,
int (*init)(struct snd_soc_pcm_runtime *rtd),
const struct snd_soc_ops *ops);
int asoc_sdw_count_sdw_endpoints(struct snd_soc_card *card, int *num_devs, int *num_ends);
struct asoc_sdw_dailink *asoc_sdw_find_dailink(struct asoc_sdw_dailink *dailinks,
const struct snd_soc_acpi_endpoint *new);
int asoc_sdw_parse_sdw_endpoints(struct snd_soc_card *card,
struct asoc_sdw_dailink *soc_dais,
struct asoc_sdw_endpoint *soc_ends,
int *num_devs);
int asoc_sdw_rtd_init(struct snd_soc_pcm_runtime *rtd);
/* DMIC support */
int asoc_sdw_dmic_init(struct snd_soc_pcm_runtime *rtd);
/* RT711 support */
int asoc_sdw_rt711_init(struct snd_soc_card *card,
struct snd_soc_dai_link *dai_links,
struct asoc_sdw_codec_info *info,
bool playback);
int asoc_sdw_rt711_exit(struct snd_soc_card *card, struct snd_soc_dai_link *dai_link);
/* RT711-SDCA support */
int asoc_sdw_rt_sdca_jack_init(struct snd_soc_card *card,
struct snd_soc_dai_link *dai_links,
struct asoc_sdw_codec_info *info,
bool playback);
int asoc_sdw_rt_sdca_jack_exit(struct snd_soc_card *card, struct snd_soc_dai_link *dai_link);
/* RT1308 I2S support */
extern const struct snd_soc_ops soc_sdw_rt1308_i2s_ops;
/* generic amp support */
int asoc_sdw_rt_amp_init(struct snd_soc_card *card,
struct snd_soc_dai_link *dai_links,
struct asoc_sdw_codec_info *info,
bool playback);
int asoc_sdw_rt_amp_exit(struct snd_soc_card *card, struct snd_soc_dai_link *dai_link);
/* CS42L43 support */
int asoc_sdw_cs42l43_spk_init(struct snd_soc_card *card,
struct snd_soc_dai_link *dai_links,
struct asoc_sdw_codec_info *info,
bool playback);
/* CS AMP support */
int asoc_sdw_bridge_cs35l56_count_sidecar(struct snd_soc_card *card,
int *num_dais, int *num_devs);
int asoc_sdw_bridge_cs35l56_add_sidecar(struct snd_soc_card *card,
struct snd_soc_dai_link **dai_links,
struct snd_soc_codec_conf **codec_conf);
int asoc_sdw_bridge_cs35l56_spk_init(struct snd_soc_card *card,
struct snd_soc_dai_link *dai_links,
struct asoc_sdw_codec_info *info,
bool playback);
int asoc_sdw_cs_amp_init(struct snd_soc_card *card,
struct snd_soc_dai_link *dai_links,
struct asoc_sdw_codec_info *info,
bool playback);
/* MAXIM codec support */
int asoc_sdw_maxim_init(struct snd_soc_card *card,
struct snd_soc_dai_link *dai_links,
struct asoc_sdw_codec_info *info,
bool playback);
/* dai_link init callbacks */
int asoc_sdw_rt_dmic_rtd_init(struct snd_soc_pcm_runtime *rtd, struct snd_soc_dai *dai);
int asoc_sdw_rt_sdca_jack_rtd_init(struct snd_soc_pcm_runtime *rtd, struct snd_soc_dai *dai);
int asoc_sdw_rt_amp_spk_rtd_init(struct snd_soc_pcm_runtime *rtd, struct snd_soc_dai *dai);
int asoc_sdw_rt700_rtd_init(struct snd_soc_pcm_runtime *rtd, struct snd_soc_dai *dai);
int asoc_sdw_rt711_rtd_init(struct snd_soc_pcm_runtime *rtd, struct snd_soc_dai *dai);
int asoc_sdw_rt712_spk_rtd_init(struct snd_soc_pcm_runtime *rtd, struct snd_soc_dai *dai);
int asoc_sdw_rt722_spk_rtd_init(struct snd_soc_pcm_runtime *rtd, struct snd_soc_dai *dai);
int asoc_sdw_rt5682_rtd_init(struct snd_soc_pcm_runtime *rtd, struct snd_soc_dai *dai);
int asoc_sdw_cs42l42_rtd_init(struct snd_soc_pcm_runtime *rtd, struct snd_soc_dai *dai);
int asoc_sdw_cs42l43_hs_rtd_init(struct snd_soc_pcm_runtime *rtd, struct snd_soc_dai *dai);
int asoc_sdw_cs42l43_spk_rtd_init(struct snd_soc_pcm_runtime *rtd, struct snd_soc_dai *dai);
int asoc_sdw_cs42l43_dmic_rtd_init(struct snd_soc_pcm_runtime *rtd, struct snd_soc_dai *dai);
int asoc_sdw_cs_spk_rtd_init(struct snd_soc_pcm_runtime *rtd, struct snd_soc_dai *dai);
int asoc_sdw_maxim_spk_rtd_init(struct snd_soc_pcm_runtime *rtd, struct snd_soc_dai *dai);
#endif

View File

@ -86,9 +86,11 @@ struct snd_sf_list {
}; };
/* Prototypes for soundfont.c */ /* Prototypes for soundfont.c */
int snd_soundfont_load(struct snd_sf_list *sflist, const void __user *data, int snd_soundfont_load(struct snd_card *card,
struct snd_sf_list *sflist, const void __user *data,
long count, int client); long count, int client);
int snd_soundfont_load_guspatch(struct snd_sf_list *sflist, const char __user *data, int snd_soundfont_load_guspatch(struct snd_card *card,
struct snd_sf_list *sflist, const char __user *data,
long count); long count);
int snd_soundfont_close_check(struct snd_sf_list *sflist, int client); int snd_soundfont_close_check(struct snd_sf_list *sflist, int client);

279
include/sound/tas2563-tlv.h Normal file
View File

@ -0,0 +1,279 @@
/* SPDX-License-Identifier: GPL-2.0 */
//
// ALSA SoC Texas Instruments TAS2563 Audio Smart Amplifier
//
// Copyright (C) 2022 - 2024 Texas Instruments Incorporated
// https://www.ti.com
//
// The TAS2563 driver implements a flexible and configurable
// algo coefficient setting for one, two, or even multiple
// TAS2563 chips.
//
// Author: Shenghao Ding <shenghao-ding@ti.com>
//
#ifndef __TAS2563_TLV_H__
#define __TAS2563_TLV_H__
static const __maybe_unused DECLARE_TLV_DB_SCALE(tas2563_dvc_tlv, -12150, 50, 1);
/* pow(10, db/20) * pow(2,30) */
static const __maybe_unused unsigned char tas2563_dvc_table[][4] = {
{ 0X00, 0X00, 0X00, 0X00 }, /* -121.5db */
{ 0X00, 0X00, 0X03, 0XBC }, /* -121.0db */
{ 0X00, 0X00, 0X03, 0XF5 }, /* -120.5db */
{ 0X00, 0X00, 0X04, 0X31 }, /* -120.0db */
{ 0X00, 0X00, 0X04, 0X71 }, /* -119.5db */
{ 0X00, 0X00, 0X04, 0XB4 }, /* -119.0db */
{ 0X00, 0X00, 0X04, 0XFC }, /* -118.5db */
{ 0X00, 0X00, 0X05, 0X47 }, /* -118.0db */
{ 0X00, 0X00, 0X05, 0X97 }, /* -117.5db */
{ 0X00, 0X00, 0X05, 0XEC }, /* -117.0db */
{ 0X00, 0X00, 0X06, 0X46 }, /* -116.5db */
{ 0X00, 0X00, 0X06, 0XA5 }, /* -116.0db */
{ 0X00, 0X00, 0X07, 0X0A }, /* -115.5db */
{ 0X00, 0X00, 0X07, 0X75 }, /* -115.0db */
{ 0X00, 0X00, 0X07, 0XE6 }, /* -114.5db */
{ 0X00, 0X00, 0X08, 0X5E }, /* -114.0db */
{ 0X00, 0X00, 0X08, 0XDD }, /* -113.5db */
{ 0X00, 0X00, 0X09, 0X63 }, /* -113.0db */
{ 0X00, 0X00, 0X09, 0XF2 }, /* -112.5db */
{ 0X00, 0X00, 0X0A, 0X89 }, /* -112.0db */
{ 0X00, 0X00, 0X0B, 0X28 }, /* -111.5db */
{ 0X00, 0X00, 0X0B, 0XD2 }, /* -111.0db */
{ 0X00, 0X00, 0X0C, 0X85 }, /* -110.5db */
{ 0X00, 0X00, 0X0D, 0X43 }, /* -110.0db */
{ 0X00, 0X00, 0X0E, 0X0C }, /* -109.5db */
{ 0X00, 0X00, 0X0E, 0XE1 }, /* -109.0db */
{ 0X00, 0X00, 0X0F, 0XC3 }, /* -108.5db */
{ 0X00, 0X00, 0X10, 0XB2 }, /* -108.0db */
{ 0X00, 0X00, 0X11, 0XAF }, /* -107.5db */
{ 0X00, 0X00, 0X12, 0XBC }, /* -107.0db */
{ 0X00, 0X00, 0X13, 0XD8 }, /* -106.5db */
{ 0X00, 0X00, 0X15, 0X05 }, /* -106.0db */
{ 0X00, 0X00, 0X16, 0X44 }, /* -105.5db */
{ 0X00, 0X00, 0X17, 0X96 }, /* -105.0db */
{ 0X00, 0X00, 0X18, 0XFB }, /* -104.5db */
{ 0X00, 0X00, 0X1A, 0X76 }, /* -104.0db */
{ 0X00, 0X00, 0X1C, 0X08 }, /* -103.5db */
{ 0X00, 0X00, 0X1D, 0XB1 }, /* -103.0db */
{ 0X00, 0X00, 0X1F, 0X73 }, /* -102.5db */
{ 0X00, 0X00, 0X21, 0X51 }, /* -102.0db */
{ 0X00, 0X00, 0X23, 0X4A }, /* -101.5db */
{ 0X00, 0X00, 0X25, 0X61 }, /* -101.0db */
{ 0X00, 0X00, 0X27, 0X98 }, /* -100.5db */
{ 0X00, 0X00, 0X29, 0XF1 }, /* -100.0db */
{ 0X00, 0X00, 0X2C, 0X6D }, /* -99.5db */
{ 0X00, 0X00, 0X2F, 0X0F }, /* -99.0db */
{ 0X00, 0X00, 0X31, 0XD9 }, /* -98.5db */
{ 0X00, 0X00, 0X34, 0XCD }, /* -98.0db */
{ 0X00, 0X00, 0X37, 0XEE }, /* -97.5db */
{ 0X00, 0X00, 0X3B, 0X3F }, /* -97.0db */
{ 0X00, 0X00, 0X3E, 0XC1 }, /* -96.5db */
{ 0X00, 0X00, 0X42, 0X79 }, /* -96.0db */
{ 0X00, 0X00, 0X46, 0X6A }, /* -95.5db */
{ 0X00, 0X00, 0X4A, 0X96 }, /* -95.0db */
{ 0X00, 0X00, 0X4F, 0X01 }, /* -94.5db */
{ 0X00, 0X00, 0X53, 0XAF }, /* -94.0db */
{ 0X00, 0X00, 0X58, 0XA5 }, /* -93.5db */
{ 0X00, 0X00, 0X5D, 0XE6 }, /* -93.0db */
{ 0X00, 0X00, 0X63, 0X76 }, /* -92.5db */
{ 0X00, 0X00, 0X69, 0X5B }, /* -92.0db */
{ 0X00, 0X00, 0X6F, 0X99 }, /* -91.5db */
{ 0X00, 0X00, 0X76, 0X36 }, /* -91.0db */
{ 0X00, 0X00, 0X7D, 0X37 }, /* -90.5db */
{ 0X00, 0X00, 0X84, 0XA2 }, /* -90.0db */
{ 0X00, 0X00, 0X8C, 0X7E }, /* -89.5db */
{ 0X00, 0X00, 0X94, 0XD1 }, /* -89.0db */
{ 0X00, 0X00, 0X9D, 0XA3 }, /* -88.5db */
{ 0X00, 0X00, 0XA6, 0XFA }, /* -88.0db */
{ 0X00, 0X00, 0XB0, 0XDF }, /* -87.5db */
{ 0X00, 0X00, 0XBB, 0X5A }, /* -87.0db */
{ 0X00, 0X00, 0XC6, 0X74 }, /* -86.5db */
{ 0X00, 0X00, 0XD2, 0X36 }, /* -86.0db */
{ 0X00, 0X00, 0XDE, 0XAB }, /* -85.5db */
{ 0X00, 0X00, 0XEB, 0XDC }, /* -85.0db */
{ 0X00, 0X00, 0XF9, 0XD6 }, /* -84.5db */
{ 0X00, 0X01, 0X08, 0XA4 }, /* -84.0db */
{ 0X00, 0X01, 0X18, 0X52 }, /* -83.5db */
{ 0X00, 0X01, 0X28, 0XEF }, /* -83.0db */
{ 0X00, 0X01, 0X3A, 0X87 }, /* -82.5db */
{ 0X00, 0X01, 0X4D, 0X2A }, /* -82.0db */
{ 0X00, 0X01, 0X60, 0XE8 }, /* -81.5db */
{ 0X00, 0X01, 0X75, 0XD1 }, /* -81.0db */
{ 0X00, 0X01, 0X8B, 0XF7 }, /* -80.5db */
{ 0X00, 0X01, 0XA3, 0X6E }, /* -80.0db */
{ 0X00, 0X01, 0XBC, 0X48 }, /* -79.5db */
{ 0X00, 0X01, 0XD6, 0X9B }, /* -79.0db */
{ 0X00, 0X01, 0XF2, 0X7E }, /* -78.5db */
{ 0X00, 0X02, 0X10, 0X08 }, /* -78.0db */
{ 0X00, 0X02, 0X2F, 0X51 }, /* -77.5db */
{ 0X00, 0X02, 0X50, 0X76 }, /* -77.0db */
{ 0X00, 0X02, 0X73, 0X91 }, /* -76.5db */
{ 0X00, 0X02, 0X98, 0XC0 }, /* -76.0db */
{ 0X00, 0X02, 0XC0, 0X24 }, /* -75.5db */
{ 0X00, 0X02, 0XE9, 0XDD }, /* -75.0db */
{ 0X00, 0X03, 0X16, 0X0F }, /* -74.5db */
{ 0X00, 0X03, 0X44, 0XDF }, /* -74.0db */
{ 0X00, 0X03, 0X76, 0X76 }, /* -73.5db */
{ 0X00, 0X03, 0XAA, 0XFC }, /* -73.0db */
{ 0X00, 0X03, 0XE2, 0XA0 }, /* -72.5db */
{ 0X00, 0X04, 0X1D, 0X8F }, /* -72.0db */
{ 0X00, 0X04, 0X5B, 0XFD }, /* -71.5db */
{ 0X00, 0X04, 0X9E, 0X1D }, /* -71.0db */
{ 0X00, 0X04, 0XE4, 0X29 }, /* -70.5db */
{ 0X00, 0X05, 0X2E, 0X5A }, /* -70.0db */
{ 0X00, 0X05, 0X7C, 0XF2 }, /* -69.5db */
{ 0X00, 0X05, 0XD0, 0X31 }, /* -69.0db */
{ 0X00, 0X06, 0X28, 0X60 }, /* -68.5db */
{ 0X00, 0X06, 0X85, 0XC8 }, /* -68.0db */
{ 0X00, 0X06, 0XE8, 0XB9 }, /* -67.5db */
{ 0X00, 0X07, 0X51, 0X86 }, /* -67.0db */
{ 0X00, 0X07, 0XC0, 0X8A }, /* -66.5db */
{ 0X00, 0X08, 0X36, 0X21 }, /* -66.0db */
{ 0X00, 0X08, 0XB2, 0XB0 }, /* -65.5db */
{ 0X00, 0X09, 0X36, 0XA1 }, /* -65.0db */
{ 0X00, 0X09, 0XC2, 0X63 }, /* -64.5db */
{ 0X00, 0X0A, 0X56, 0X6D }, /* -64.0db */
{ 0X00, 0X0A, 0XF3, 0X3C }, /* -63.5db */
{ 0X00, 0X0B, 0X99, 0X56 }, /* -63.0db */
{ 0X00, 0X0C, 0X49, 0X48 }, /* -62.5db */
{ 0X00, 0X0D, 0X03, 0XA7 }, /* -62.0db */
{ 0X00, 0X0D, 0XC9, 0X11 }, /* -61.5db */
{ 0X00, 0X0E, 0X9A, 0X2D }, /* -61.0db */
{ 0X00, 0X0F, 0X77, 0XAD }, /* -60.5db */
{ 0X00, 0X10, 0X62, 0X4D }, /* -60.0db */
{ 0X00, 0X11, 0X5A, 0XD5 }, /* -59.5db */
{ 0X00, 0X12, 0X62, 0X16 }, /* -59.0db */
{ 0X00, 0X13, 0X78, 0XF0 }, /* -58.5db */
{ 0X00, 0X14, 0XA0, 0X50 }, /* -58.0db */
{ 0X00, 0X15, 0XD9, 0X31 }, /* -57.5db */
{ 0X00, 0X17, 0X24, 0X9C }, /* -57.0db */
{ 0X00, 0X18, 0X83, 0XAA }, /* -56.5db */
{ 0X00, 0X19, 0XF7, 0X86 }, /* -56.0db */
{ 0X00, 0X1B, 0X81, 0X6A }, /* -55.5db */
{ 0X00, 0X1D, 0X22, 0XA4 }, /* -55.0db */
{ 0X00, 0X1E, 0XDC, 0X98 }, /* -54.5db */
{ 0X00, 0X20, 0XB0, 0XBC }, /* -54.0db */
{ 0X00, 0X22, 0XA0, 0X9D }, /* -53.5db */
{ 0X00, 0X24, 0XAD, 0XE0 }, /* -53.0db */
{ 0X00, 0X26, 0XDA, 0X43 }, /* -52.5db */
{ 0X00, 0X29, 0X27, 0X9D }, /* -52.0db */
{ 0X00, 0X2B, 0X97, 0XE3 }, /* -51.5db */
{ 0X00, 0X2E, 0X2D, 0X27 }, /* -51.0db */
{ 0X00, 0X30, 0XE9, 0X9A }, /* -50.5db */
{ 0X00, 0X33, 0XCF, 0X8D }, /* -50.0db */
{ 0X00, 0X36, 0XE1, 0X78 }, /* -49.5db */
{ 0X00, 0X3A, 0X21, 0XF3 }, /* -49.0db */
{ 0X00, 0X3D, 0X93, 0XC3 }, /* -48.5db */
{ 0X00, 0X41, 0X39, 0XD3 }, /* -48.0db */
{ 0X00, 0X45, 0X17, 0X3B }, /* -47.5db */
{ 0X00, 0X49, 0X2F, 0X44 }, /* -47.0db */
{ 0X00, 0X4D, 0X85, 0X66 }, /* -46.5db */
{ 0X00, 0X52, 0X1D, 0X50 }, /* -46.0db */
{ 0X00, 0X56, 0XFA, 0XE8 }, /* -45.5db */
{ 0X00, 0X5C, 0X22, 0X4E }, /* -45.0db */
{ 0X00, 0X61, 0X97, 0XE1 }, /* -44.5db */
{ 0X00, 0X67, 0X60, 0X44 }, /* -44.0db */
{ 0X00, 0X6D, 0X80, 0X60 }, /* -43.5db */
{ 0X00, 0X73, 0XFD, 0X65 }, /* -43.0db */
{ 0X00, 0X7A, 0XDC, 0XD7 }, /* -42.5db */
{ 0X00, 0X82, 0X24, 0X8A }, /* -42.0db */
{ 0X00, 0X89, 0XDA, 0XAB }, /* -41.5db */
{ 0X00, 0X92, 0X05, 0XC6 }, /* -41.0db */
{ 0X00, 0X9A, 0XAC, 0XC8 }, /* -40.5db */
{ 0X00, 0XA3, 0XD7, 0X0A }, /* -40.0db */
{ 0X00, 0XAD, 0X8C, 0X52 }, /* -39.5db */
{ 0X00, 0XB7, 0XD4, 0XDD }, /* -39.0db */
{ 0X00, 0XC2, 0XB9, 0X65 }, /* -38.5db */
{ 0X00, 0XCE, 0X43, 0X28 }, /* -38.0db */
{ 0X00, 0XDA, 0X7B, 0XF1 }, /* -37.5db */
{ 0X00, 0XE7, 0X6E, 0X1E }, /* -37.0db */
{ 0X00, 0XF5, 0X24, 0XAC }, /* -36.5db */
{ 0X01, 0X03, 0XAB, 0X3D }, /* -36.0db */
{ 0X01, 0X13, 0X0E, 0X24 }, /* -35.5db */
{ 0X01, 0X23, 0X5A, 0X71 }, /* -35.0db */
{ 0X01, 0X34, 0X9D, 0XF8 }, /* -34.5db */
{ 0X01, 0X46, 0XE7, 0X5D }, /* -34.0db */
{ 0X01, 0X5A, 0X46, 0X27 }, /* -33.5db */
{ 0X01, 0X6E, 0XCA, 0XC5 }, /* -33.0db */
{ 0X01, 0X84, 0X86, 0X9F }, /* -32.5db */
{ 0X01, 0X9B, 0X8C, 0X27 }, /* -32.0db */
{ 0X01, 0XB3, 0XEE, 0XE5 }, /* -31.5db */
{ 0X01, 0XCD, 0XC3, 0X8C }, /* -31.0db */
{ 0X01, 0XE9, 0X20, 0X05 }, /* -30.5db */
{ 0X02, 0X06, 0X1B, 0X89 }, /* -30.0db */
{ 0X02, 0X24, 0XCE, 0XB0 }, /* -29.5db */
{ 0X02, 0X45, 0X53, 0X85 }, /* -29.0db */
{ 0X02, 0X67, 0XC5, 0XA2 }, /* -28.5db */
{ 0X02, 0X8C, 0X42, 0X3F }, /* -28.0db */
{ 0X02, 0XB2, 0XE8, 0X55 }, /* -27.5db */
{ 0X02, 0XDB, 0XD8, 0XAD }, /* -27.0db */
{ 0X03, 0X07, 0X36, 0X05 }, /* -26.5db */
{ 0X03, 0X35, 0X25, 0X29 }, /* -26.0db */
{ 0X03, 0X65, 0XCD, 0X13 }, /* -25.5db */
{ 0X03, 0X99, 0X57, 0X0C }, /* -25.0db */
{ 0X03, 0XCF, 0XEE, 0XCF }, /* -24.5db */
{ 0X04, 0X09, 0XC2, 0XB0 }, /* -24.0db */
{ 0X04, 0X47, 0X03, 0XC1 }, /* -23.5db */
{ 0X04, 0X87, 0XE5, 0XFB }, /* -23.0db */
{ 0X04, 0XCC, 0XA0, 0X6D }, /* -22.5db */
{ 0X05, 0X15, 0X6D, 0X68 }, /* -22.0db */
{ 0X05, 0X62, 0X8A, 0XB3 }, /* -21.5db */
{ 0X05, 0XB4, 0X39, 0XBC }, /* -21.0db */
{ 0X06, 0X0A, 0XBF, 0XD4 }, /* -20.5db */
{ 0X06, 0X66, 0X66, 0X66 }, /* -20.0db */
{ 0X06, 0XC7, 0X7B, 0X36 }, /* -19.5db */
{ 0X07, 0X2E, 0X50, 0XA6 }, /* -19.0db */
{ 0X07, 0X9B, 0X3D, 0XF6 }, /* -18.5db */
{ 0X08, 0X0E, 0X9F, 0X96 }, /* -18.0db */
{ 0X08, 0X88, 0XD7, 0X6D }, /* -17.5db */
{ 0X09, 0X0A, 0X4D, 0X2F }, /* -17.0db */
{ 0X09, 0X93, 0X6E, 0XB8 }, /* -16.5db */
{ 0X0A, 0X24, 0XB0, 0X62 }, /* -16.0db */
{ 0X0A, 0XBE, 0X8D, 0X70 }, /* -15.5db */
{ 0X0B, 0X61, 0X88, 0X71 }, /* -15.0db */
{ 0X0C, 0X0E, 0X2B, 0XB0 }, /* -14.5db */
{ 0X0C, 0XC5, 0X09, 0XAB }, /* -14.0db */
{ 0X0D, 0X86, 0XBD, 0X8D }, /* -13.5db */
{ 0X0E, 0X53, 0XEB, 0XB3 }, /* -13.0db */
{ 0X0F, 0X2D, 0X42, 0X38 }, /* -12.5db */
{ 0X10, 0X13, 0X79, 0X87 }, /* -12.0db */
{ 0X11, 0X07, 0X54, 0XF9 }, /* -11.5db */
{ 0X12, 0X09, 0XA3, 0X7A }, /* -11.0db */
{ 0X13, 0X1B, 0X40, 0X39 }, /* -10.5db */
{ 0X14, 0X3D, 0X13, 0X62 }, /* -10.0db */
{ 0X15, 0X70, 0X12, 0XE1 }, /* -9.5db */
{ 0X16, 0XB5, 0X43, 0X37 }, /* -9.0db */
{ 0X18, 0X0D, 0XB8, 0X54 }, /* -8.5db */
{ 0X19, 0X7A, 0X96, 0X7F }, /* -8.0db */
{ 0X1A, 0XFD, 0X13, 0X54 }, /* -7.5db */
{ 0X1C, 0X96, 0X76, 0XC6 }, /* -7.0db */
{ 0X1E, 0X48, 0X1C, 0X37 }, /* -6.5db */
{ 0X20, 0X13, 0X73, 0X9E }, /* -6.0db */
{ 0X21, 0XFA, 0X02, 0XBF }, /* -5.5db */
{ 0X23, 0XFD, 0X66, 0X78 }, /* -5.0db */
{ 0X26, 0X1F, 0X54, 0X1C }, /* -4.5db */
{ 0X28, 0X61, 0X9A, 0XE9 }, /* -4.0db */
{ 0X2A, 0XC6, 0X25, 0X91 }, /* -3.5db */
{ 0X2D, 0X4E, 0XFB, 0XD5 }, /* -3.0db */
{ 0X2F, 0XFE, 0X44, 0X48 }, /* -2.5db */
{ 0X32, 0XD6, 0X46, 0X17 }, /* -2.0db */
{ 0X35, 0XD9, 0X6B, 0X02 }, /* -1.5db */
{ 0X39, 0X0A, 0X41, 0X5F }, /* -1.0db */
{ 0X3C, 0X6B, 0X7E, 0X4F }, /* -0.5db */
{ 0X40, 0X00, 0X00, 0X00 }, /* 0.0db */
{ 0X43, 0XCA, 0XD0, 0X22 }, /* 0.5db */
{ 0X47, 0XCF, 0X26, 0X7D }, /* 1.0db */
{ 0X4C, 0X10, 0X6B, 0XA5 }, /* 1.5db */
{ 0X50, 0X92, 0X3B, 0XE3 }, /* 2.0db */
{ 0X55, 0X58, 0X6A, 0X46 }, /* 2.5db */
{ 0X5A, 0X67, 0X03, 0XDF }, /* 3.0db */
{ 0X5F, 0XC2, 0X53, 0X32 }, /* 3.5db */
{ 0X65, 0X6E, 0XE3, 0XDB }, /* 4.0db */
{ 0X6B, 0X71, 0X86, 0X68 }, /* 4.5db */
{ 0X71, 0XCF, 0X54, 0X71 }, /* 5.0db */
{ 0X78, 0X8D, 0XB4, 0XE9 }, /* 5.5db */
{ 0X7F, 0XFF, 0XFF, 0XFF }, /* 6.0db */
};
#endif

View File

@ -17,265 +17,5 @@
static const __maybe_unused DECLARE_TLV_DB_SCALE(dvc_tlv, -10000, 100, 0); static const __maybe_unused DECLARE_TLV_DB_SCALE(dvc_tlv, -10000, 100, 0);
static const __maybe_unused DECLARE_TLV_DB_SCALE(amp_vol_tlv, 1100, 50, 0); static const __maybe_unused DECLARE_TLV_DB_SCALE(amp_vol_tlv, 1100, 50, 0);
static const __maybe_unused DECLARE_TLV_DB_SCALE(tas2563_dvc_tlv, -12150, 50, 1);
/* pow(10, db/20) * pow(2,30) */
static const __maybe_unused unsigned char tas2563_dvc_table[][4] = {
{ 0X00, 0X00, 0X00, 0X00 }, /* -121.5db */
{ 0X00, 0X00, 0X03, 0XBC }, /* -121.0db */
{ 0X00, 0X00, 0X03, 0XF5 }, /* -120.5db */
{ 0X00, 0X00, 0X04, 0X31 }, /* -120.0db */
{ 0X00, 0X00, 0X04, 0X71 }, /* -119.5db */
{ 0X00, 0X00, 0X04, 0XB4 }, /* -119.0db */
{ 0X00, 0X00, 0X04, 0XFC }, /* -118.5db */
{ 0X00, 0X00, 0X05, 0X47 }, /* -118.0db */
{ 0X00, 0X00, 0X05, 0X97 }, /* -117.5db */
{ 0X00, 0X00, 0X05, 0XEC }, /* -117.0db */
{ 0X00, 0X00, 0X06, 0X46 }, /* -116.5db */
{ 0X00, 0X00, 0X06, 0XA5 }, /* -116.0db */
{ 0X00, 0X00, 0X07, 0X0A }, /* -115.5db */
{ 0X00, 0X00, 0X07, 0X75 }, /* -115.0db */
{ 0X00, 0X00, 0X07, 0XE6 }, /* -114.5db */
{ 0X00, 0X00, 0X08, 0X5E }, /* -114.0db */
{ 0X00, 0X00, 0X08, 0XDD }, /* -113.5db */
{ 0X00, 0X00, 0X09, 0X63 }, /* -113.0db */
{ 0X00, 0X00, 0X09, 0XF2 }, /* -112.5db */
{ 0X00, 0X00, 0X0A, 0X89 }, /* -112.0db */
{ 0X00, 0X00, 0X0B, 0X28 }, /* -111.5db */
{ 0X00, 0X00, 0X0B, 0XD2 }, /* -111.0db */
{ 0X00, 0X00, 0X0C, 0X85 }, /* -110.5db */
{ 0X00, 0X00, 0X0D, 0X43 }, /* -110.0db */
{ 0X00, 0X00, 0X0E, 0X0C }, /* -109.5db */
{ 0X00, 0X00, 0X0E, 0XE1 }, /* -109.0db */
{ 0X00, 0X00, 0X0F, 0XC3 }, /* -108.5db */
{ 0X00, 0X00, 0X10, 0XB2 }, /* -108.0db */
{ 0X00, 0X00, 0X11, 0XAF }, /* -107.5db */
{ 0X00, 0X00, 0X12, 0XBC }, /* -107.0db */
{ 0X00, 0X00, 0X13, 0XD8 }, /* -106.5db */
{ 0X00, 0X00, 0X15, 0X05 }, /* -106.0db */
{ 0X00, 0X00, 0X16, 0X44 }, /* -105.5db */
{ 0X00, 0X00, 0X17, 0X96 }, /* -105.0db */
{ 0X00, 0X00, 0X18, 0XFB }, /* -104.5db */
{ 0X00, 0X00, 0X1A, 0X76 }, /* -104.0db */
{ 0X00, 0X00, 0X1C, 0X08 }, /* -103.5db */
{ 0X00, 0X00, 0X1D, 0XB1 }, /* -103.0db */
{ 0X00, 0X00, 0X1F, 0X73 }, /* -102.5db */
{ 0X00, 0X00, 0X21, 0X51 }, /* -102.0db */
{ 0X00, 0X00, 0X23, 0X4A }, /* -101.5db */
{ 0X00, 0X00, 0X25, 0X61 }, /* -101.0db */
{ 0X00, 0X00, 0X27, 0X98 }, /* -100.5db */
{ 0X00, 0X00, 0X29, 0XF1 }, /* -100.0db */
{ 0X00, 0X00, 0X2C, 0X6D }, /* -99.5db */
{ 0X00, 0X00, 0X2F, 0X0F }, /* -99.0db */
{ 0X00, 0X00, 0X31, 0XD9 }, /* -98.5db */
{ 0X00, 0X00, 0X34, 0XCD }, /* -98.0db */
{ 0X00, 0X00, 0X37, 0XEE }, /* -97.5db */
{ 0X00, 0X00, 0X3B, 0X3F }, /* -97.0db */
{ 0X00, 0X00, 0X3E, 0XC1 }, /* -96.5db */
{ 0X00, 0X00, 0X42, 0X79 }, /* -96.0db */
{ 0X00, 0X00, 0X46, 0X6A }, /* -95.5db */
{ 0X00, 0X00, 0X4A, 0X96 }, /* -95.0db */
{ 0X00, 0X00, 0X4F, 0X01 }, /* -94.5db */
{ 0X00, 0X00, 0X53, 0XAF }, /* -94.0db */
{ 0X00, 0X00, 0X58, 0XA5 }, /* -93.5db */
{ 0X00, 0X00, 0X5D, 0XE6 }, /* -93.0db */
{ 0X00, 0X00, 0X63, 0X76 }, /* -92.5db */
{ 0X00, 0X00, 0X69, 0X5B }, /* -92.0db */
{ 0X00, 0X00, 0X6F, 0X99 }, /* -91.5db */
{ 0X00, 0X00, 0X76, 0X36 }, /* -91.0db */
{ 0X00, 0X00, 0X7D, 0X37 }, /* -90.5db */
{ 0X00, 0X00, 0X84, 0XA2 }, /* -90.0db */
{ 0X00, 0X00, 0X8C, 0X7E }, /* -89.5db */
{ 0X00, 0X00, 0X94, 0XD1 }, /* -89.0db */
{ 0X00, 0X00, 0X9D, 0XA3 }, /* -88.5db */
{ 0X00, 0X00, 0XA6, 0XFA }, /* -88.0db */
{ 0X00, 0X00, 0XB0, 0XDF }, /* -87.5db */
{ 0X00, 0X00, 0XBB, 0X5A }, /* -87.0db */
{ 0X00, 0X00, 0XC6, 0X74 }, /* -86.5db */
{ 0X00, 0X00, 0XD2, 0X36 }, /* -86.0db */
{ 0X00, 0X00, 0XDE, 0XAB }, /* -85.5db */
{ 0X00, 0X00, 0XEB, 0XDC }, /* -85.0db */
{ 0X00, 0X00, 0XF9, 0XD6 }, /* -84.5db */
{ 0X00, 0X01, 0X08, 0XA4 }, /* -84.0db */
{ 0X00, 0X01, 0X18, 0X52 }, /* -83.5db */
{ 0X00, 0X01, 0X28, 0XEF }, /* -83.0db */
{ 0X00, 0X01, 0X3A, 0X87 }, /* -82.5db */
{ 0X00, 0X01, 0X4D, 0X2A }, /* -82.0db */
{ 0X00, 0X01, 0X60, 0XE8 }, /* -81.5db */
{ 0X00, 0X01, 0X75, 0XD1 }, /* -81.0db */
{ 0X00, 0X01, 0X8B, 0XF7 }, /* -80.5db */
{ 0X00, 0X01, 0XA3, 0X6E }, /* -80.0db */
{ 0X00, 0X01, 0XBC, 0X48 }, /* -79.5db */
{ 0X00, 0X01, 0XD6, 0X9B }, /* -79.0db */
{ 0X00, 0X01, 0XF2, 0X7E }, /* -78.5db */
{ 0X00, 0X02, 0X10, 0X08 }, /* -78.0db */
{ 0X00, 0X02, 0X2F, 0X51 }, /* -77.5db */
{ 0X00, 0X02, 0X50, 0X76 }, /* -77.0db */
{ 0X00, 0X02, 0X73, 0X91 }, /* -76.5db */
{ 0X00, 0X02, 0X98, 0XC0 }, /* -76.0db */
{ 0X00, 0X02, 0XC0, 0X24 }, /* -75.5db */
{ 0X00, 0X02, 0XE9, 0XDD }, /* -75.0db */
{ 0X00, 0X03, 0X16, 0X0F }, /* -74.5db */
{ 0X00, 0X03, 0X44, 0XDF }, /* -74.0db */
{ 0X00, 0X03, 0X76, 0X76 }, /* -73.5db */
{ 0X00, 0X03, 0XAA, 0XFC }, /* -73.0db */
{ 0X00, 0X03, 0XE2, 0XA0 }, /* -72.5db */
{ 0X00, 0X04, 0X1D, 0X8F }, /* -72.0db */
{ 0X00, 0X04, 0X5B, 0XFD }, /* -71.5db */
{ 0X00, 0X04, 0X9E, 0X1D }, /* -71.0db */
{ 0X00, 0X04, 0XE4, 0X29 }, /* -70.5db */
{ 0X00, 0X05, 0X2E, 0X5A }, /* -70.0db */
{ 0X00, 0X05, 0X7C, 0XF2 }, /* -69.5db */
{ 0X00, 0X05, 0XD0, 0X31 }, /* -69.0db */
{ 0X00, 0X06, 0X28, 0X60 }, /* -68.5db */
{ 0X00, 0X06, 0X85, 0XC8 }, /* -68.0db */
{ 0X00, 0X06, 0XE8, 0XB9 }, /* -67.5db */
{ 0X00, 0X07, 0X51, 0X86 }, /* -67.0db */
{ 0X00, 0X07, 0XC0, 0X8A }, /* -66.5db */
{ 0X00, 0X08, 0X36, 0X21 }, /* -66.0db */
{ 0X00, 0X08, 0XB2, 0XB0 }, /* -65.5db */
{ 0X00, 0X09, 0X36, 0XA1 }, /* -65.0db */
{ 0X00, 0X09, 0XC2, 0X63 }, /* -64.5db */
{ 0X00, 0X0A, 0X56, 0X6D }, /* -64.0db */
{ 0X00, 0X0A, 0XF3, 0X3C }, /* -63.5db */
{ 0X00, 0X0B, 0X99, 0X56 }, /* -63.0db */
{ 0X00, 0X0C, 0X49, 0X48 }, /* -62.5db */
{ 0X00, 0X0D, 0X03, 0XA7 }, /* -62.0db */
{ 0X00, 0X0D, 0XC9, 0X11 }, /* -61.5db */
{ 0X00, 0X0E, 0X9A, 0X2D }, /* -61.0db */
{ 0X00, 0X0F, 0X77, 0XAD }, /* -60.5db */
{ 0X00, 0X10, 0X62, 0X4D }, /* -60.0db */
{ 0X00, 0X11, 0X5A, 0XD5 }, /* -59.5db */
{ 0X00, 0X12, 0X62, 0X16 }, /* -59.0db */
{ 0X00, 0X13, 0X78, 0XF0 }, /* -58.5db */
{ 0X00, 0X14, 0XA0, 0X50 }, /* -58.0db */
{ 0X00, 0X15, 0XD9, 0X31 }, /* -57.5db */
{ 0X00, 0X17, 0X24, 0X9C }, /* -57.0db */
{ 0X00, 0X18, 0X83, 0XAA }, /* -56.5db */
{ 0X00, 0X19, 0XF7, 0X86 }, /* -56.0db */
{ 0X00, 0X1B, 0X81, 0X6A }, /* -55.5db */
{ 0X00, 0X1D, 0X22, 0XA4 }, /* -55.0db */
{ 0X00, 0X1E, 0XDC, 0X98 }, /* -54.5db */
{ 0X00, 0X20, 0XB0, 0XBC }, /* -54.0db */
{ 0X00, 0X22, 0XA0, 0X9D }, /* -53.5db */
{ 0X00, 0X24, 0XAD, 0XE0 }, /* -53.0db */
{ 0X00, 0X26, 0XDA, 0X43 }, /* -52.5db */
{ 0X00, 0X29, 0X27, 0X9D }, /* -52.0db */
{ 0X00, 0X2B, 0X97, 0XE3 }, /* -51.5db */
{ 0X00, 0X2E, 0X2D, 0X27 }, /* -51.0db */
{ 0X00, 0X30, 0XE9, 0X9A }, /* -50.5db */
{ 0X00, 0X33, 0XCF, 0X8D }, /* -50.0db */
{ 0X00, 0X36, 0XE1, 0X78 }, /* -49.5db */
{ 0X00, 0X3A, 0X21, 0XF3 }, /* -49.0db */
{ 0X00, 0X3D, 0X93, 0XC3 }, /* -48.5db */
{ 0X00, 0X41, 0X39, 0XD3 }, /* -48.0db */
{ 0X00, 0X45, 0X17, 0X3B }, /* -47.5db */
{ 0X00, 0X49, 0X2F, 0X44 }, /* -47.0db */
{ 0X00, 0X4D, 0X85, 0X66 }, /* -46.5db */
{ 0X00, 0X52, 0X1D, 0X50 }, /* -46.0db */
{ 0X00, 0X56, 0XFA, 0XE8 }, /* -45.5db */
{ 0X00, 0X5C, 0X22, 0X4E }, /* -45.0db */
{ 0X00, 0X61, 0X97, 0XE1 }, /* -44.5db */
{ 0X00, 0X67, 0X60, 0X44 }, /* -44.0db */
{ 0X00, 0X6D, 0X80, 0X60 }, /* -43.5db */
{ 0X00, 0X73, 0XFD, 0X65 }, /* -43.0db */
{ 0X00, 0X7A, 0XDC, 0XD7 }, /* -42.5db */
{ 0X00, 0X82, 0X24, 0X8A }, /* -42.0db */
{ 0X00, 0X89, 0XDA, 0XAB }, /* -41.5db */
{ 0X00, 0X92, 0X05, 0XC6 }, /* -41.0db */
{ 0X00, 0X9A, 0XAC, 0XC8 }, /* -40.5db */
{ 0X00, 0XA3, 0XD7, 0X0A }, /* -40.0db */
{ 0X00, 0XAD, 0X8C, 0X52 }, /* -39.5db */
{ 0X00, 0XB7, 0XD4, 0XDD }, /* -39.0db */
{ 0X00, 0XC2, 0XB9, 0X65 }, /* -38.5db */
{ 0X00, 0XCE, 0X43, 0X28 }, /* -38.0db */
{ 0X00, 0XDA, 0X7B, 0XF1 }, /* -37.5db */
{ 0X00, 0XE7, 0X6E, 0X1E }, /* -37.0db */
{ 0X00, 0XF5, 0X24, 0XAC }, /* -36.5db */
{ 0X01, 0X03, 0XAB, 0X3D }, /* -36.0db */
{ 0X01, 0X13, 0X0E, 0X24 }, /* -35.5db */
{ 0X01, 0X23, 0X5A, 0X71 }, /* -35.0db */
{ 0X01, 0X34, 0X9D, 0XF8 }, /* -34.5db */
{ 0X01, 0X46, 0XE7, 0X5D }, /* -34.0db */
{ 0X01, 0X5A, 0X46, 0X27 }, /* -33.5db */
{ 0X01, 0X6E, 0XCA, 0XC5 }, /* -33.0db */
{ 0X01, 0X84, 0X86, 0X9F }, /* -32.5db */
{ 0X01, 0X9B, 0X8C, 0X27 }, /* -32.0db */
{ 0X01, 0XB3, 0XEE, 0XE5 }, /* -31.5db */
{ 0X01, 0XCD, 0XC3, 0X8C }, /* -31.0db */
{ 0X01, 0XE9, 0X20, 0X05 }, /* -30.5db */
{ 0X02, 0X06, 0X1B, 0X89 }, /* -30.0db */
{ 0X02, 0X24, 0XCE, 0XB0 }, /* -29.5db */
{ 0X02, 0X45, 0X53, 0X85 }, /* -29.0db */
{ 0X02, 0X67, 0XC5, 0XA2 }, /* -28.5db */
{ 0X02, 0X8C, 0X42, 0X3F }, /* -28.0db */
{ 0X02, 0XB2, 0XE8, 0X55 }, /* -27.5db */
{ 0X02, 0XDB, 0XD8, 0XAD }, /* -27.0db */
{ 0X03, 0X07, 0X36, 0X05 }, /* -26.5db */
{ 0X03, 0X35, 0X25, 0X29 }, /* -26.0db */
{ 0X03, 0X65, 0XCD, 0X13 }, /* -25.5db */
{ 0X03, 0X99, 0X57, 0X0C }, /* -25.0db */
{ 0X03, 0XCF, 0XEE, 0XCF }, /* -24.5db */
{ 0X04, 0X09, 0XC2, 0XB0 }, /* -24.0db */
{ 0X04, 0X47, 0X03, 0XC1 }, /* -23.5db */
{ 0X04, 0X87, 0XE5, 0XFB }, /* -23.0db */
{ 0X04, 0XCC, 0XA0, 0X6D }, /* -22.5db */
{ 0X05, 0X15, 0X6D, 0X68 }, /* -22.0db */
{ 0X05, 0X62, 0X8A, 0XB3 }, /* -21.5db */
{ 0X05, 0XB4, 0X39, 0XBC }, /* -21.0db */
{ 0X06, 0X0A, 0XBF, 0XD4 }, /* -20.5db */
{ 0X06, 0X66, 0X66, 0X66 }, /* -20.0db */
{ 0X06, 0XC7, 0X7B, 0X36 }, /* -19.5db */
{ 0X07, 0X2E, 0X50, 0XA6 }, /* -19.0db */
{ 0X07, 0X9B, 0X3D, 0XF6 }, /* -18.5db */
{ 0X08, 0X0E, 0X9F, 0X96 }, /* -18.0db */
{ 0X08, 0X88, 0XD7, 0X6D }, /* -17.5db */
{ 0X09, 0X0A, 0X4D, 0X2F }, /* -17.0db */
{ 0X09, 0X93, 0X6E, 0XB8 }, /* -16.5db */
{ 0X0A, 0X24, 0XB0, 0X62 }, /* -16.0db */
{ 0X0A, 0XBE, 0X8D, 0X70 }, /* -15.5db */
{ 0X0B, 0X61, 0X88, 0X71 }, /* -15.0db */
{ 0X0C, 0X0E, 0X2B, 0XB0 }, /* -14.5db */
{ 0X0C, 0XC5, 0X09, 0XAB }, /* -14.0db */
{ 0X0D, 0X86, 0XBD, 0X8D }, /* -13.5db */
{ 0X0E, 0X53, 0XEB, 0XB3 }, /* -13.0db */
{ 0X0F, 0X2D, 0X42, 0X38 }, /* -12.5db */
{ 0X10, 0X13, 0X79, 0X87 }, /* -12.0db */
{ 0X11, 0X07, 0X54, 0XF9 }, /* -11.5db */
{ 0X12, 0X09, 0XA3, 0X7A }, /* -11.0db */
{ 0X13, 0X1B, 0X40, 0X39 }, /* -10.5db */
{ 0X14, 0X3D, 0X13, 0X62 }, /* -10.0db */
{ 0X15, 0X70, 0X12, 0XE1 }, /* -9.5db */
{ 0X16, 0XB5, 0X43, 0X37 }, /* -9.0db */
{ 0X18, 0X0D, 0XB8, 0X54 }, /* -8.5db */
{ 0X19, 0X7A, 0X96, 0X7F }, /* -8.0db */
{ 0X1A, 0XFD, 0X13, 0X54 }, /* -7.5db */
{ 0X1C, 0X96, 0X76, 0XC6 }, /* -7.0db */
{ 0X1E, 0X48, 0X1C, 0X37 }, /* -6.5db */
{ 0X20, 0X13, 0X73, 0X9E }, /* -6.0db */
{ 0X21, 0XFA, 0X02, 0XBF }, /* -5.5db */
{ 0X23, 0XFD, 0X66, 0X78 }, /* -5.0db */
{ 0X26, 0X1F, 0X54, 0X1C }, /* -4.5db */
{ 0X28, 0X61, 0X9A, 0XE9 }, /* -4.0db */
{ 0X2A, 0XC6, 0X25, 0X91 }, /* -3.5db */
{ 0X2D, 0X4E, 0XFB, 0XD5 }, /* -3.0db */
{ 0X2F, 0XFE, 0X44, 0X48 }, /* -2.5db */
{ 0X32, 0XD6, 0X46, 0X17 }, /* -2.0db */
{ 0X35, 0XD9, 0X6B, 0X02 }, /* -1.5db */
{ 0X39, 0X0A, 0X41, 0X5F }, /* -1.0db */
{ 0X3C, 0X6B, 0X7E, 0X4F }, /* -0.5db */
{ 0X40, 0X00, 0X00, 0X00 }, /* 0.0db */
{ 0X43, 0XCA, 0XD0, 0X22 }, /* 0.5db */
{ 0X47, 0XCF, 0X26, 0X7D }, /* 1.0db */
{ 0X4C, 0X10, 0X6B, 0XA5 }, /* 1.5db */
{ 0X50, 0X92, 0X3B, 0XE3 }, /* 2.0db */
{ 0X55, 0X58, 0X6A, 0X46 }, /* 2.5db */
{ 0X5A, 0X67, 0X03, 0XDF }, /* 3.0db */
{ 0X5F, 0XC2, 0X53, 0X32 }, /* 3.5db */
{ 0X65, 0X6E, 0XE3, 0XDB }, /* 4.0db */
{ 0X6B, 0X71, 0X86, 0X68 }, /* 4.5db */
{ 0X71, 0XCF, 0X54, 0X71 }, /* 5.0db */
{ 0X78, 0X8D, 0XB4, 0XE9 }, /* 5.5db */
{ 0XFF, 0XFF, 0XFF, 0XFF }, /* 6.0db */
};
#endif #endif

View File

@ -49,12 +49,59 @@
/*I2C Checksum */ /*I2C Checksum */
#define TASDEVICE_I2CChecksum TASDEVICE_REG(0x0, 0x0, 0x7E) #define TASDEVICE_I2CChecksum TASDEVICE_REG(0x0, 0x0, 0x7E)
/* XM_340 */
#define TASDEVICE_XM_A1_REG TASDEVICE_REG(0x64, 0x63, 0x3c)
/* XM_341 */
#define TASDEVICE_XM_A2_REG TASDEVICE_REG(0x64, 0x63, 0x38)
/* Volume control */ /* Volume control */
#define TAS2563_DVC_LVL TASDEVICE_REG(0x00, 0x02, 0x0C) #define TAS2563_DVC_LVL TASDEVICE_REG(0x00, 0x02, 0x0C)
#define TAS2781_DVC_LVL TASDEVICE_REG(0x0, 0x0, 0x1A) #define TAS2781_DVC_LVL TASDEVICE_REG(0x0, 0x0, 0x1A)
#define TAS2781_AMP_LEVEL TASDEVICE_REG(0x0, 0x0, 0x03) #define TAS2781_AMP_LEVEL TASDEVICE_REG(0x0, 0x0, 0x03)
#define TAS2781_AMP_LEVEL_MASK GENMASK(5, 1) #define TAS2781_AMP_LEVEL_MASK GENMASK(5, 1)
#define TAS2563_IDLE TASDEVICE_REG(0x00, 0x00, 0x3e)
#define TAS2563_PRM_R0_REG TASDEVICE_REG(0x00, 0x0f, 0x34)
#define TAS2563_RUNTIME_RE_REG_TF TASDEVICE_REG(0x64, 0x02, 0x70)
#define TAS2563_RUNTIME_RE_REG TASDEVICE_REG(0x64, 0x02, 0x48)
#define TAS2563_PRM_ENFF_REG TASDEVICE_REG(0x00, 0x0d, 0x54)
#define TAS2563_PRM_DISTCK_REG TASDEVICE_REG(0x00, 0x0d, 0x58)
#define TAS2563_PRM_TE_SCTHR_REG TASDEVICE_REG(0x00, 0x0f, 0x60)
#define TAS2563_PRM_PLT_FLAG_REG TASDEVICE_REG(0x00, 0x0d, 0x74)
#define TAS2563_PRM_SINEGAIN_REG TASDEVICE_REG(0x00, 0x0d, 0x7c)
/* prm_Int_B0 */
#define TAS2563_TE_TA1_REG TASDEVICE_REG(0x00, 0x10, 0x0c)
/* prm_Int_A1 */
#define TAS2563_TE_TA1_AT_REG TASDEVICE_REG(0x00, 0x10, 0x10)
/* prm_TE_Beta */
#define TAS2563_TE_TA2_REG TASDEVICE_REG(0x00, 0x0f, 0x64)
/* prm_TE_Beta1 */
#define TAS2563_TE_AT_REG TASDEVICE_REG(0x00, 0x0f, 0x68)
/* prm_TE_1_Beta1 */
#define TAS2563_TE_DT_REG TASDEVICE_REG(0x00, 0x0f, 0x70)
#define TAS2781_PRM_INT_MASK_REG TASDEVICE_REG(0x00, 0x00, 0x3b)
#define TAS2781_PRM_CLK_CFG_REG TASDEVICE_REG(0x00, 0x00, 0x5c)
#define TAS2781_PRM_RSVD_REG TASDEVICE_REG(0x00, 0x01, 0x19)
#define TAS2781_PRM_TEST_57_REG TASDEVICE_REG(0x00, 0xfd, 0x39)
#define TAS2781_PRM_TEST_62_REG TASDEVICE_REG(0x00, 0xfd, 0x3e)
#define TAS2781_PRM_PVDD_UVLO_REG TASDEVICE_REG(0x00, 0x00, 0x71)
#define TAS2781_PRM_CHNL_0_REG TASDEVICE_REG(0x00, 0x00, 0x03)
#define TAS2781_PRM_NG_CFG0_REG TASDEVICE_REG(0x00, 0x00, 0x35)
#define TAS2781_PRM_IDLE_CH_DET_REG TASDEVICE_REG(0x00, 0x00, 0x66)
#define TAS2781_PRM_PLT_FLAG_REG TASDEVICE_REG(0x00, 0x14, 0x38)
#define TAS2781_PRM_SINEGAIN_REG TASDEVICE_REG(0x00, 0x14, 0x40)
#define TAS2781_PRM_SINEGAIN2_REG TASDEVICE_REG(0x00, 0x14, 0x44)
#define TAS2781_TEST_UNLOCK_REG TASDEVICE_REG(0x00, 0xFD, 0x0D)
#define TAS2781_TEST_PAGE_UNLOCK 0x0D
#define TAS2781_RUNTIME_LATCH_RE_REG TASDEVICE_REG(0x00, 0x00, 0x49)
#define TAS2781_RUNTIME_RE_REG_TF TASDEVICE_REG(0x64, 0x62, 0x48)
#define TAS2781_RUNTIME_RE_REG TASDEVICE_REG(0x64, 0x63, 0x44)
#define TASDEVICE_CMD_SING_W 0x1 #define TASDEVICE_CMD_SING_W 0x1
#define TASDEVICE_CMD_BURST 0x2 #define TASDEVICE_CMD_BURST 0x2
#define TASDEVICE_CMD_DELAY 0x3 #define TASDEVICE_CMD_DELAY 0x3
@ -70,7 +117,15 @@ enum device_catlog_id {
OTHERS OTHERS
}; };
struct bulk_reg_val {
int reg;
unsigned char val[4];
unsigned char val_len;
bool is_locked;
};
struct tasdevice { struct tasdevice {
struct bulk_reg_val *cali_data_backup;
struct tasdevice_fw *cali_data_fmw; struct tasdevice_fw *cali_data_fmw;
unsigned int dev_addr; unsigned int dev_addr;
unsigned int err_code; unsigned int err_code;
@ -81,19 +136,23 @@ struct tasdevice {
bool is_loaderr; bool is_loaderr;
}; };
struct tasdevice_irqinfo { struct cali_reg {
int irq_gpio; unsigned int r0_reg;
int irq; unsigned int r0_low_reg;
unsigned int invr0_reg;
unsigned int pow_reg;
unsigned int tlimit_reg;
}; };
struct calidata { struct calidata {
unsigned char *data; unsigned char *data;
unsigned long total_sz; unsigned long total_sz;
struct cali_reg cali_reg_array;
unsigned int cali_dat_sz_per_dev;
}; };
struct tasdevice_priv { struct tasdevice_priv {
struct tasdevice tasdevice[TASDEVICE_MAX_CHANNELS]; struct tasdevice tasdevice[TASDEVICE_MAX_CHANNELS];
struct tasdevice_irqinfo irq_info;
struct tasdevice_rca rcabin; struct tasdevice_rca rcabin;
struct calidata cali_data; struct calidata cali_data;
struct tasdevice_fw *fmw; struct tasdevice_fw *fmw;
@ -115,6 +174,7 @@ struct tasdevice_priv {
unsigned int chip_id; unsigned int chip_id;
unsigned int sysclk; unsigned int sysclk;
int irq;
int cur_prog; int cur_prog;
int cur_conf; int cur_conf;
int fw_state; int fw_state;
@ -124,6 +184,7 @@ struct tasdevice_priv {
bool force_fwload_status; bool force_fwload_status;
bool playback_started; bool playback_started;
bool isacpi; bool isacpi;
bool is_user_space_calidata;
unsigned int global_addr; unsigned int global_addr;
int (*fw_parse_variable_header)(struct tasdevice_priv *tas_priv, int (*fw_parse_variable_header)(struct tasdevice_priv *tas_priv,
@ -150,6 +211,8 @@ int tasdevice_init(struct tasdevice_priv *tas_priv);
void tasdevice_remove(struct tasdevice_priv *tas_priv); void tasdevice_remove(struct tasdevice_priv *tas_priv);
int tasdevice_save_calibration(struct tasdevice_priv *tas_priv); int tasdevice_save_calibration(struct tasdevice_priv *tas_priv);
void tasdevice_apply_calibration(struct tasdevice_priv *tas_priv); void tasdevice_apply_calibration(struct tasdevice_priv *tas_priv);
int tasdev_chn_switch(struct tasdevice_priv *tas_priv,
unsigned short chn);
int tasdevice_dev_read(struct tasdevice_priv *tas_priv, int tasdevice_dev_read(struct tasdevice_priv *tas_priv,
unsigned short chn, unsigned int reg, unsigned int *value); unsigned short chn, unsigned int reg, unsigned int *value);
int tasdevice_dev_write(struct tasdevice_priv *tas_priv, int tasdevice_dev_write(struct tasdevice_priv *tas_priv,

View File

@ -13,6 +13,15 @@ struct snd_ump_ops;
struct ump_cvt_to_ump; struct ump_cvt_to_ump;
struct snd_seq_ump_ops; struct snd_seq_ump_ops;
struct snd_ump_group {
int group; /* group index (0-based) */
unsigned int dir_bits; /* directions */
bool active; /* activeness */
bool valid; /* valid group (referred by blocks) */
bool is_midi1; /* belongs to a MIDI1 FB */
char name[64]; /* group name */
};
struct snd_ump_endpoint { struct snd_ump_endpoint {
struct snd_rawmidi core; /* raw UMP access */ struct snd_rawmidi core; /* raw UMP access */
@ -41,6 +50,8 @@ struct snd_ump_endpoint {
struct mutex open_mutex; struct mutex open_mutex;
struct snd_ump_group groups[SNDRV_UMP_MAX_GROUPS]; /* table of groups */
#if IS_ENABLED(CONFIG_SND_UMP_LEGACY_RAWMIDI) #if IS_ENABLED(CONFIG_SND_UMP_LEGACY_RAWMIDI)
spinlock_t legacy_locks[2]; spinlock_t legacy_locks[2];
struct snd_rawmidi *legacy_rmidi; struct snd_rawmidi *legacy_rmidi;
@ -112,6 +123,7 @@ static inline int snd_ump_attach_legacy_rawmidi(struct snd_ump_endpoint *ump,
int snd_ump_receive_ump_val(struct snd_ump_endpoint *ump, u32 val); int snd_ump_receive_ump_val(struct snd_ump_endpoint *ump, u32 val);
int snd_ump_switch_protocol(struct snd_ump_endpoint *ump, unsigned int protocol); int snd_ump_switch_protocol(struct snd_ump_endpoint *ump, unsigned int protocol);
void snd_ump_update_group_attrs(struct snd_ump_endpoint *ump);
/* /*
* Some definitions for UMP * Some definitions for UMP

View File

@ -155,7 +155,6 @@ struct vx_core {
unsigned int chip_status; unsigned int chip_status;
unsigned int pcm_running; unsigned int pcm_running;
struct device *dev;
struct snd_hwdep *hwdep; struct snd_hwdep *hwdep;
struct vx_rmh irq_rmh; /* RMH used in interrupts */ struct vx_rmh irq_rmh; /* RMH used in interrupts */

View File

@ -8,6 +8,7 @@
#include <linux/ktime.h> #include <linux/ktime.h>
#include <linux/tracepoint.h> #include <linux/tracepoint.h>
#include <sound/jack.h> #include <sound/jack.h>
#include <sound/pcm.h>
#define DAPM_DIRECT "(direct)" #define DAPM_DIRECT "(direct)"
#define DAPM_ARROW(dir) (((dir) == SND_SOC_DAPM_DIR_OUT) ? "->" : "<-") #define DAPM_ARROW(dir) (((dir) == SND_SOC_DAPM_DIR_OUT) ? "->" : "<-")
@ -212,7 +213,7 @@ TRACE_EVENT(snd_soc_dapm_connected,
), ),
TP_printk("%s: found %d paths", TP_printk("%s: found %d paths",
__entry->stream ? "capture" : "playback", __entry->paths) snd_pcm_direction_name(__entry->stream), __entry->paths)
); );
TRACE_EVENT(snd_soc_jack_irq, TRACE_EVENT(snd_soc_jack_irq,

View File

@ -461,6 +461,8 @@ struct snd_seq_remove_events {
#define SNDRV_SEQ_PORT_FLG_TIMESTAMP (1<<1) #define SNDRV_SEQ_PORT_FLG_TIMESTAMP (1<<1)
#define SNDRV_SEQ_PORT_FLG_TIME_REAL (1<<2) #define SNDRV_SEQ_PORT_FLG_TIME_REAL (1<<2)
#define SNDRV_SEQ_PORT_FLG_IS_MIDI1 (1<<3) /* Keep MIDI 1.0 protocol */
/* port direction */ /* port direction */
#define SNDRV_SEQ_PORT_DIR_UNKNOWN 0 #define SNDRV_SEQ_PORT_DIR_UNKNOWN 0
#define SNDRV_SEQ_PORT_DIR_INPUT 1 #define SNDRV_SEQ_PORT_DIR_INPUT 1

View File

@ -869,7 +869,7 @@ struct snd_ump_block_info {
* Timer section - /dev/snd/timer * Timer section - /dev/snd/timer
*/ */
#define SNDRV_TIMER_VERSION SNDRV_PROTOCOL_VERSION(2, 0, 7) #define SNDRV_TIMER_VERSION SNDRV_PROTOCOL_VERSION(2, 0, 8)
enum { enum {
SNDRV_TIMER_CLASS_NONE = -1, SNDRV_TIMER_CLASS_NONE = -1,
@ -894,6 +894,7 @@ enum {
#define SNDRV_TIMER_GLOBAL_RTC 1 /* unused */ #define SNDRV_TIMER_GLOBAL_RTC 1 /* unused */
#define SNDRV_TIMER_GLOBAL_HPET 2 #define SNDRV_TIMER_GLOBAL_HPET 2
#define SNDRV_TIMER_GLOBAL_HRTIMER 3 #define SNDRV_TIMER_GLOBAL_HRTIMER 3
#define SNDRV_TIMER_GLOBAL_UDRIVEN 4
/* info flags */ /* info flags */
#define SNDRV_TIMER_FLG_SLAVE (1<<0) /* cannot be controlled */ #define SNDRV_TIMER_FLG_SLAVE (1<<0) /* cannot be controlled */
@ -974,6 +975,18 @@ struct snd_timer_status {
}; };
#endif #endif
/*
* This structure describes the userspace-driven timer. Such timers are purely virtual,
* and can only be triggered from software (for instance, by userspace application).
*/
struct snd_timer_uinfo {
/* To pretend being a normal timer, we need to know the resolution in ns. */
__u64 resolution;
int fd;
unsigned int id;
unsigned char reserved[16];
};
#define SNDRV_TIMER_IOCTL_PVERSION _IOR('T', 0x00, int) #define SNDRV_TIMER_IOCTL_PVERSION _IOR('T', 0x00, int)
#define SNDRV_TIMER_IOCTL_NEXT_DEVICE _IOWR('T', 0x01, struct snd_timer_id) #define SNDRV_TIMER_IOCTL_NEXT_DEVICE _IOWR('T', 0x01, struct snd_timer_id)
#define SNDRV_TIMER_IOCTL_TREAD_OLD _IOW('T', 0x02, int) #define SNDRV_TIMER_IOCTL_TREAD_OLD _IOW('T', 0x02, int)
@ -990,6 +1003,8 @@ struct snd_timer_status {
#define SNDRV_TIMER_IOCTL_CONTINUE _IO('T', 0xa2) #define SNDRV_TIMER_IOCTL_CONTINUE _IO('T', 0xa2)
#define SNDRV_TIMER_IOCTL_PAUSE _IO('T', 0xa3) #define SNDRV_TIMER_IOCTL_PAUSE _IO('T', 0xa3)
#define SNDRV_TIMER_IOCTL_TREAD64 _IOW('T', 0xa4, int) #define SNDRV_TIMER_IOCTL_TREAD64 _IOW('T', 0xa4, int)
#define SNDRV_TIMER_IOCTL_CREATE _IOWR('T', 0xa5, struct snd_timer_uinfo)
#define SNDRV_TIMER_IOCTL_TRIGGER _IO('T', 0xa6)
#if __BITS_PER_LONG == 64 #if __BITS_PER_LONG == 64
#define SNDRV_TIMER_IOCTL_TREAD SNDRV_TIMER_IOCTL_TREAD_OLD #define SNDRV_TIMER_IOCTL_TREAD SNDRV_TIMER_IOCTL_TREAD_OLD

View File

@ -335,7 +335,7 @@ static int i2sbus_add_dev(struct macio_dev *macio,
static int i2sbus_probe(struct macio_dev* dev, const struct of_device_id *match) static int i2sbus_probe(struct macio_dev* dev, const struct of_device_id *match)
{ {
struct device_node *np = NULL; struct device_node *np;
int got = 0, err; int got = 0, err;
struct i2sbus_control *control = NULL; struct i2sbus_control *control = NULL;
@ -347,7 +347,7 @@ static int i2sbus_probe(struct macio_dev* dev, const struct of_device_id *match)
return -ENODEV; return -ENODEV;
} }
while ((np = of_get_next_child(dev->ofdev.dev.of_node, np))) { for_each_child_of_node(dev->ofdev.dev.of_node, np) {
if (of_device_is_compatible(np, "i2sbus") || if (of_device_is_compatible(np, "i2sbus") ||
of_device_is_compatible(np, "i2s-modem")) { of_device_is_compatible(np, "i2s-modem")) {
got += i2sbus_add_dev(dev, control, np); got += i2sbus_add_dev(dev, control, np);

View File

@ -175,15 +175,6 @@ config SND_VERBOSE_PROCFS
useful information to developers when a problem occurs). On the useful information to developers when a problem occurs). On the
other side, it makes the ALSA subsystem larger. other side, it makes the ALSA subsystem larger.
config SND_VERBOSE_PRINTK
bool "Verbose printk"
help
Say Y here to enable verbose log messages. These messages
will help to identify source file and position containing
printed messages.
You don't need this unless you're debugging ALSA.
config SND_CTL_FAST_LOOKUP config SND_CTL_FAST_LOOKUP
bool "Fast lookup of control elements" if EXPERT bool "Fast lookup of control elements" if EXPERT
default y default y
@ -251,6 +242,16 @@ config SND_JACK_INJECTION_DEBUG
Say Y if you are debugging via jack injection interface. Say Y if you are debugging via jack injection interface.
If unsure select "N". If unsure select "N".
config SND_UTIMER
bool "Enable support for userspace-controlled virtual timers"
depends on SND_TIMER
help
Say Y to enable the support of userspace-controlled timers. These
timers are purely virtual, and they are supposed to be triggered
from userspace. They could be quite useful when synchronizing the
sound timing with userspace applications (for instance, when sending
data through snd-aloop).
config SND_VMASTER config SND_VMASTER
bool bool

View File

@ -581,7 +581,7 @@ snd_compr_set_params(struct snd_compr_stream *stream, unsigned long arg)
*/ */
params = memdup_user((void __user *)arg, sizeof(*params)); params = memdup_user((void __user *)arg, sizeof(*params));
if (IS_ERR(params)) if (IS_ERR(params))
return PTR_ERR(no_free_ptr(params)); return PTR_ERR(params);
retval = snd_compress_check_input(params); retval = snd_compress_check_input(params);
if (retval) if (retval)

View File

@ -79,7 +79,7 @@ static int snd_ctl_open(struct inode *inode, struct file *file)
ctl->preferred_subdevice[i] = -1; ctl->preferred_subdevice[i] = -1;
ctl->pid = get_pid(task_pid(current)); ctl->pid = get_pid(task_pid(current));
file->private_data = ctl; file->private_data = ctl;
scoped_guard(write_lock_irqsave, &card->ctl_files_rwlock) scoped_guard(write_lock_irqsave, &card->controls_rwlock)
list_add_tail(&ctl->list, &card->ctl_files); list_add_tail(&ctl->list, &card->ctl_files);
snd_card_unref(card); snd_card_unref(card);
return 0; return 0;
@ -117,7 +117,7 @@ static int snd_ctl_release(struct inode *inode, struct file *file)
file->private_data = NULL; file->private_data = NULL;
card = ctl->card; card = ctl->card;
scoped_guard(write_lock_irqsave, &card->ctl_files_rwlock) scoped_guard(write_lock_irqsave, &card->controls_rwlock)
list_del(&ctl->list); list_del(&ctl->list);
scoped_guard(rwsem_write, &card->controls_rwsem) { scoped_guard(rwsem_write, &card->controls_rwsem) {
@ -157,7 +157,7 @@ void snd_ctl_notify(struct snd_card *card, unsigned int mask,
if (card->shutdown) if (card->shutdown)
return; return;
guard(read_lock_irqsave)(&card->ctl_files_rwlock); guard(read_lock_irqsave)(&card->controls_rwlock);
#if IS_ENABLED(CONFIG_SND_MIXER_OSS) #if IS_ENABLED(CONFIG_SND_MIXER_OSS)
card->mixer_oss_change_count++; card->mixer_oss_change_count++;
#endif #endif
@ -237,11 +237,11 @@ static int snd_ctl_new(struct snd_kcontrol **kctl, unsigned int count,
if (!*kctl) if (!*kctl)
return -ENOMEM; return -ENOMEM;
(*kctl)->count = count;
for (idx = 0; idx < count; idx++) { for (idx = 0; idx < count; idx++) {
(*kctl)->vd[idx].access = access; (*kctl)->vd[idx].access = access;
(*kctl)->vd[idx].owner = file; (*kctl)->vd[idx].owner = file;
} }
(*kctl)->count = count;
return 0; return 0;
} }
@ -470,7 +470,7 @@ static int __snd_ctl_add_replace(struct snd_card *card,
if (id.index > UINT_MAX - kcontrol->count) if (id.index > UINT_MAX - kcontrol->count)
return -EINVAL; return -EINVAL;
old = snd_ctl_find_id_locked(card, &id); old = snd_ctl_find_id(card, &id);
if (!old) { if (!old) {
if (mode == CTL_REPLACE) if (mode == CTL_REPLACE)
return -EINVAL; return -EINVAL;
@ -491,10 +491,12 @@ static int __snd_ctl_add_replace(struct snd_card *card,
if (snd_ctl_find_hole(card, kcontrol->count) < 0) if (snd_ctl_find_hole(card, kcontrol->count) < 0)
return -ENOMEM; return -ENOMEM;
list_add_tail(&kcontrol->list, &card->controls); scoped_guard(write_lock_irq, &card->controls_rwlock) {
card->controls_count += kcontrol->count; list_add_tail(&kcontrol->list, &card->controls);
kcontrol->id.numid = card->last_numid + 1; card->controls_count += kcontrol->count;
card->last_numid += kcontrol->count; kcontrol->id.numid = card->last_numid + 1;
card->last_numid += kcontrol->count;
}
add_hash_entries(card, kcontrol); add_hash_entries(card, kcontrol);
@ -579,12 +581,15 @@ static int __snd_ctl_remove(struct snd_card *card,
if (snd_BUG_ON(!card || !kcontrol)) if (snd_BUG_ON(!card || !kcontrol))
return -EINVAL; return -EINVAL;
list_del(&kcontrol->list);
if (remove_hash) if (remove_hash)
remove_hash_entries(card, kcontrol); remove_hash_entries(card, kcontrol);
card->controls_count -= kcontrol->count; scoped_guard(write_lock_irq, &card->controls_rwlock) {
list_del(&kcontrol->list);
card->controls_count -= kcontrol->count;
}
for (idx = 0; idx < kcontrol->count; idx++) for (idx = 0; idx < kcontrol->count; idx++)
snd_ctl_notify_one(card, SNDRV_CTL_EVENT_MASK_REMOVE, kcontrol, idx); snd_ctl_notify_one(card, SNDRV_CTL_EVENT_MASK_REMOVE, kcontrol, idx);
snd_ctl_free_one(kcontrol); snd_ctl_free_one(kcontrol);
@ -634,7 +639,7 @@ int snd_ctl_remove_id(struct snd_card *card, struct snd_ctl_elem_id *id)
struct snd_kcontrol *kctl; struct snd_kcontrol *kctl;
guard(rwsem_write)(&card->controls_rwsem); guard(rwsem_write)(&card->controls_rwsem);
kctl = snd_ctl_find_id_locked(card, id); kctl = snd_ctl_find_id(card, id);
if (kctl == NULL) if (kctl == NULL)
return -ENOENT; return -ENOENT;
return snd_ctl_remove_locked(card, kctl); return snd_ctl_remove_locked(card, kctl);
@ -659,7 +664,7 @@ static int snd_ctl_remove_user_ctl(struct snd_ctl_file * file,
int idx; int idx;
guard(rwsem_write)(&card->controls_rwsem); guard(rwsem_write)(&card->controls_rwsem);
kctl = snd_ctl_find_id_locked(card, id); kctl = snd_ctl_find_id(card, id);
if (kctl == NULL) if (kctl == NULL)
return -ENOENT; return -ENOENT;
if (!(kctl->vd[0].access & SNDRV_CTL_ELEM_ACCESS_USER)) if (!(kctl->vd[0].access & SNDRV_CTL_ELEM_ACCESS_USER))
@ -691,7 +696,7 @@ int snd_ctl_activate_id(struct snd_card *card, struct snd_ctl_elem_id *id,
int ret; int ret;
down_write(&card->controls_rwsem); down_write(&card->controls_rwsem);
kctl = snd_ctl_find_id_locked(card, id); kctl = snd_ctl_find_id(card, id);
if (kctl == NULL) { if (kctl == NULL) {
ret = -ENOENT; ret = -ENOENT;
goto unlock; goto unlock;
@ -745,7 +750,7 @@ int snd_ctl_rename_id(struct snd_card *card, struct snd_ctl_elem_id *src_id,
int saved_numid; int saved_numid;
guard(rwsem_write)(&card->controls_rwsem); guard(rwsem_write)(&card->controls_rwsem);
kctl = snd_ctl_find_id_locked(card, src_id); kctl = snd_ctl_find_id(card, src_id);
if (kctl == NULL) if (kctl == NULL)
return -ENOENT; return -ENOENT;
saved_numid = kctl->id.numid; saved_numid = kctl->id.numid;
@ -787,6 +792,7 @@ snd_ctl_find_numid_slow(struct snd_card *card, unsigned int numid)
{ {
struct snd_kcontrol *kctl; struct snd_kcontrol *kctl;
guard(read_lock_irqsave)(&card->controls_rwlock);
list_for_each_entry(kctl, &card->controls, list) { list_for_each_entry(kctl, &card->controls, list) {
if (kctl->id.numid <= numid && kctl->id.numid + kctl->count > numid) if (kctl->id.numid <= numid && kctl->id.numid + kctl->count > numid)
return kctl; return kctl;
@ -795,32 +801,6 @@ snd_ctl_find_numid_slow(struct snd_card *card, unsigned int numid)
} }
#endif /* !CONFIG_SND_CTL_FAST_LOOKUP */ #endif /* !CONFIG_SND_CTL_FAST_LOOKUP */
/**
* snd_ctl_find_numid_locked - find the control instance with the given number-id
* @card: the card instance
* @numid: the number-id to search
*
* Finds the control instance with the given number-id from the card.
*
* The caller must down card->controls_rwsem before calling this function
* (if the race condition can happen).
*
* Return: The pointer of the instance if found, or %NULL if not.
*/
struct snd_kcontrol *
snd_ctl_find_numid_locked(struct snd_card *card, unsigned int numid)
{
if (snd_BUG_ON(!card || !numid))
return NULL;
lockdep_assert_held(&card->controls_rwsem);
#ifdef CONFIG_SND_CTL_FAST_LOOKUP
return xa_load(&card->ctl_numids, numid);
#else
return snd_ctl_find_numid_slow(card, numid);
#endif
}
EXPORT_SYMBOL(snd_ctl_find_numid_locked);
/** /**
* snd_ctl_find_numid - find the control instance with the given number-id * snd_ctl_find_numid - find the control instance with the given number-id
* @card: the card instance * @card: the card instance
@ -830,54 +810,22 @@ EXPORT_SYMBOL(snd_ctl_find_numid_locked);
* *
* Return: The pointer of the instance if found, or %NULL if not. * Return: The pointer of the instance if found, or %NULL if not.
* *
* Note that this function takes card->controls_rwsem lock internally. * Note that this function takes card->controls_rwlock lock internally.
*/ */
struct snd_kcontrol *snd_ctl_find_numid(struct snd_card *card, struct snd_kcontrol *snd_ctl_find_numid(struct snd_card *card,
unsigned int numid) unsigned int numid)
{ {
guard(rwsem_read)(&card->controls_rwsem); if (snd_BUG_ON(!card || !numid))
return snd_ctl_find_numid_locked(card, numid); return NULL;
#ifdef CONFIG_SND_CTL_FAST_LOOKUP
return xa_load(&card->ctl_numids, numid);
#else
return snd_ctl_find_numid_slow(card, numid);
#endif
} }
EXPORT_SYMBOL(snd_ctl_find_numid); EXPORT_SYMBOL(snd_ctl_find_numid);
/**
* snd_ctl_find_id_locked - find the control instance with the given id
* @card: the card instance
* @id: the id to search
*
* Finds the control instance with the given id from the card.
*
* The caller must down card->controls_rwsem before calling this function
* (if the race condition can happen).
*
* Return: The pointer of the instance if found, or %NULL if not.
*/
struct snd_kcontrol *snd_ctl_find_id_locked(struct snd_card *card,
const struct snd_ctl_elem_id *id)
{
struct snd_kcontrol *kctl;
if (snd_BUG_ON(!card || !id))
return NULL;
lockdep_assert_held(&card->controls_rwsem);
if (id->numid != 0)
return snd_ctl_find_numid_locked(card, id->numid);
#ifdef CONFIG_SND_CTL_FAST_LOOKUP
kctl = xa_load(&card->ctl_hash, get_ctl_id_hash(id));
if (kctl && elem_id_matches(kctl, id))
return kctl;
if (!card->ctl_hash_collision)
return NULL; /* we can rely on only hash table */
#endif
/* no matching in hash table - try all as the last resort */
list_for_each_entry(kctl, &card->controls, list)
if (elem_id_matches(kctl, id))
return kctl;
return NULL;
}
EXPORT_SYMBOL(snd_ctl_find_id_locked);
/** /**
* snd_ctl_find_id - find the control instance with the given id * snd_ctl_find_id - find the control instance with the given id
* @card: the card instance * @card: the card instance
@ -887,13 +835,32 @@ EXPORT_SYMBOL(snd_ctl_find_id_locked);
* *
* Return: The pointer of the instance if found, or %NULL if not. * Return: The pointer of the instance if found, or %NULL if not.
* *
* Note that this function takes card->controls_rwsem lock internally. * Note that this function takes card->controls_rwlock lock internally.
*/ */
struct snd_kcontrol *snd_ctl_find_id(struct snd_card *card, struct snd_kcontrol *snd_ctl_find_id(struct snd_card *card,
const struct snd_ctl_elem_id *id) const struct snd_ctl_elem_id *id)
{ {
guard(rwsem_read)(&card->controls_rwsem); struct snd_kcontrol *kctl;
return snd_ctl_find_id_locked(card, id);
if (snd_BUG_ON(!card || !id))
return NULL;
if (id->numid != 0)
return snd_ctl_find_numid(card, id->numid);
#ifdef CONFIG_SND_CTL_FAST_LOOKUP
kctl = xa_load(&card->ctl_hash, get_ctl_id_hash(id));
if (kctl && elem_id_matches(kctl, id))
return kctl;
if (!card->ctl_hash_collision)
return NULL; /* we can rely on only hash table */
#endif
/* no matching in hash table - try all as the last resort */
guard(read_lock_irqsave)(&card->controls_rwlock);
list_for_each_entry(kctl, &card->controls, list)
if (elem_id_matches(kctl, id))
return kctl;
return NULL;
} }
EXPORT_SYMBOL(snd_ctl_find_id); EXPORT_SYMBOL(snd_ctl_find_id);
@ -1167,10 +1134,7 @@ static int __snd_ctl_elem_info(struct snd_card *card,
#ifdef CONFIG_SND_DEBUG #ifdef CONFIG_SND_DEBUG
info->access = 0; info->access = 0;
#endif #endif
result = snd_power_ref_and_wait(card); result = kctl->info(kctl, info);
if (!result)
result = kctl->info(kctl, info);
snd_power_unref(card);
if (result >= 0) { if (result >= 0) {
snd_BUG_ON(info->access); snd_BUG_ON(info->access);
index_offset = snd_ctl_get_ioff(kctl, &info->id); index_offset = snd_ctl_get_ioff(kctl, &info->id);
@ -1199,7 +1163,7 @@ static int snd_ctl_elem_info(struct snd_ctl_file *ctl,
struct snd_kcontrol *kctl; struct snd_kcontrol *kctl;
guard(rwsem_read)(&card->controls_rwsem); guard(rwsem_read)(&card->controls_rwsem);
kctl = snd_ctl_find_id_locked(card, &info->id); kctl = snd_ctl_find_id(card, &info->id);
if (!kctl) if (!kctl)
return -ENOENT; return -ENOENT;
return __snd_ctl_elem_info(card, kctl, info, ctl); return __snd_ctl_elem_info(card, kctl, info, ctl);
@ -1208,12 +1172,17 @@ static int snd_ctl_elem_info(struct snd_ctl_file *ctl,
static int snd_ctl_elem_info_user(struct snd_ctl_file *ctl, static int snd_ctl_elem_info_user(struct snd_ctl_file *ctl,
struct snd_ctl_elem_info __user *_info) struct snd_ctl_elem_info __user *_info)
{ {
struct snd_card *card = ctl->card;
struct snd_ctl_elem_info info; struct snd_ctl_elem_info info;
int result; int result;
if (copy_from_user(&info, _info, sizeof(info))) if (copy_from_user(&info, _info, sizeof(info)))
return -EFAULT; return -EFAULT;
result = snd_power_ref_and_wait(card);
if (result)
return result;
result = snd_ctl_elem_info(ctl, &info); result = snd_ctl_elem_info(ctl, &info);
snd_power_unref(card);
if (result < 0) if (result < 0)
return result; return result;
/* drop internal access flags */ /* drop internal access flags */
@ -1235,7 +1204,7 @@ static int snd_ctl_elem_read(struct snd_card *card,
int ret; int ret;
guard(rwsem_read)(&card->controls_rwsem); guard(rwsem_read)(&card->controls_rwsem);
kctl = snd_ctl_find_id_locked(card, &control->id); kctl = snd_ctl_find_id(card, &control->id);
if (!kctl) if (!kctl)
return -ENOENT; return -ENOENT;
@ -1257,10 +1226,7 @@ static int snd_ctl_elem_read(struct snd_card *card,
if (!snd_ctl_skip_validation(&info)) if (!snd_ctl_skip_validation(&info))
fill_remaining_elem_value(control, &info, pattern); fill_remaining_elem_value(control, &info, pattern);
ret = snd_power_ref_and_wait(card); ret = kctl->get(kctl, control);
if (!ret)
ret = kctl->get(kctl, control);
snd_power_unref(card);
if (ret < 0) if (ret < 0)
return ret; return ret;
if (!snd_ctl_skip_validation(&info) && if (!snd_ctl_skip_validation(&info) &&
@ -1283,9 +1249,13 @@ static int snd_ctl_elem_read_user(struct snd_card *card,
control = memdup_user(_control, sizeof(*control)); control = memdup_user(_control, sizeof(*control));
if (IS_ERR(control)) if (IS_ERR(control))
return PTR_ERR(no_free_ptr(control)); return PTR_ERR(control);
result = snd_power_ref_and_wait(card);
if (result)
return result;
result = snd_ctl_elem_read(card, control); result = snd_ctl_elem_read(card, control);
snd_power_unref(card);
if (result < 0) if (result < 0)
return result; return result;
@ -1300,10 +1270,10 @@ static int snd_ctl_elem_write(struct snd_card *card, struct snd_ctl_file *file,
struct snd_kcontrol *kctl; struct snd_kcontrol *kctl;
struct snd_kcontrol_volatile *vd; struct snd_kcontrol_volatile *vd;
unsigned int index_offset; unsigned int index_offset;
int result; int result = 0;
down_write(&card->controls_rwsem); down_write(&card->controls_rwsem);
kctl = snd_ctl_find_id_locked(card, &control->id); kctl = snd_ctl_find_id(card, &control->id);
if (kctl == NULL) { if (kctl == NULL) {
up_write(&card->controls_rwsem); up_write(&card->controls_rwsem);
return -ENOENT; return -ENOENT;
@ -1318,9 +1288,8 @@ static int snd_ctl_elem_write(struct snd_card *card, struct snd_ctl_file *file,
} }
snd_ctl_build_ioff(&control->id, kctl, index_offset); snd_ctl_build_ioff(&control->id, kctl, index_offset);
result = snd_power_ref_and_wait(card);
/* validate input values */ /* validate input values */
if (IS_ENABLED(CONFIG_SND_CTL_INPUT_VALIDATION) && !result) { if (IS_ENABLED(CONFIG_SND_CTL_INPUT_VALIDATION)) {
struct snd_ctl_elem_info info; struct snd_ctl_elem_info info;
memset(&info, 0, sizeof(info)); memset(&info, 0, sizeof(info));
@ -1332,7 +1301,6 @@ static int snd_ctl_elem_write(struct snd_card *card, struct snd_ctl_file *file,
} }
if (!result) if (!result)
result = kctl->put(kctl, control); result = kctl->put(kctl, control);
snd_power_unref(card);
if (result < 0) { if (result < 0) {
up_write(&card->controls_rwsem); up_write(&card->controls_rwsem);
return result; return result;
@ -1358,10 +1326,14 @@ static int snd_ctl_elem_write_user(struct snd_ctl_file *file,
control = memdup_user(_control, sizeof(*control)); control = memdup_user(_control, sizeof(*control));
if (IS_ERR(control)) if (IS_ERR(control))
return PTR_ERR(no_free_ptr(control)); return PTR_ERR(control);
card = file->card; card = file->card;
result = snd_power_ref_and_wait(card);
if (result < 0)
return result;
result = snd_ctl_elem_write(card, file, control); result = snd_ctl_elem_write(card, file, control);
snd_power_unref(card);
if (result < 0) if (result < 0)
return result; return result;
@ -1381,7 +1353,7 @@ static int snd_ctl_elem_lock(struct snd_ctl_file *file,
if (copy_from_user(&id, _id, sizeof(id))) if (copy_from_user(&id, _id, sizeof(id)))
return -EFAULT; return -EFAULT;
guard(rwsem_write)(&card->controls_rwsem); guard(rwsem_write)(&card->controls_rwsem);
kctl = snd_ctl_find_id_locked(card, &id); kctl = snd_ctl_find_id(card, &id);
if (!kctl) if (!kctl)
return -ENOENT; return -ENOENT;
vd = &kctl->vd[snd_ctl_get_ioff(kctl, &id)]; vd = &kctl->vd[snd_ctl_get_ioff(kctl, &id)];
@ -1402,7 +1374,7 @@ static int snd_ctl_elem_unlock(struct snd_ctl_file *file,
if (copy_from_user(&id, _id, sizeof(id))) if (copy_from_user(&id, _id, sizeof(id)))
return -EFAULT; return -EFAULT;
guard(rwsem_write)(&card->controls_rwsem); guard(rwsem_write)(&card->controls_rwsem);
kctl = snd_ctl_find_id_locked(card, &id); kctl = snd_ctl_find_id(card, &id);
if (!kctl) if (!kctl)
return -ENOENT; return -ENOENT;
vd = &kctl->vd[snd_ctl_get_ioff(kctl, &id)]; vd = &kctl->vd[snd_ctl_get_ioff(kctl, &id)];
@ -1830,7 +1802,7 @@ static int call_tlv_handler(struct snd_ctl_file *file, int op_flag,
{SNDRV_CTL_TLV_OP_CMD, SNDRV_CTL_ELEM_ACCESS_TLV_COMMAND}, {SNDRV_CTL_TLV_OP_CMD, SNDRV_CTL_ELEM_ACCESS_TLV_COMMAND},
}; };
struct snd_kcontrol_volatile *vd = &kctl->vd[snd_ctl_get_ioff(kctl, id)]; struct snd_kcontrol_volatile *vd = &kctl->vd[snd_ctl_get_ioff(kctl, id)];
int i, ret; int i;
/* Check support of the request for this element. */ /* Check support of the request for this element. */
for (i = 0; i < ARRAY_SIZE(pairs); ++i) { for (i = 0; i < ARRAY_SIZE(pairs); ++i) {
@ -1848,11 +1820,7 @@ static int call_tlv_handler(struct snd_ctl_file *file, int op_flag,
vd->owner != NULL && vd->owner != file) vd->owner != NULL && vd->owner != file)
return -EPERM; return -EPERM;
ret = snd_power_ref_and_wait(file->card); return kctl->tlv.c(kctl, op_flag, size, buf);
if (!ret)
ret = kctl->tlv.c(kctl, op_flag, size, buf);
snd_power_unref(file->card);
return ret;
} }
static int read_tlv_buf(struct snd_kcontrol *kctl, struct snd_ctl_elem_id *id, static int read_tlv_buf(struct snd_kcontrol *kctl, struct snd_ctl_elem_id *id,
@ -1903,7 +1871,7 @@ static int snd_ctl_tlv_ioctl(struct snd_ctl_file *file,
container_size = header.length; container_size = header.length;
container = buf->tlv; container = buf->tlv;
kctl = snd_ctl_find_numid_locked(file->card, header.numid); kctl = snd_ctl_find_numid(file->card, header.numid);
if (kctl == NULL) if (kctl == NULL)
return -ENOENT; return -ENOENT;
@ -1965,16 +1933,28 @@ static long snd_ctl_ioctl(struct file *file, unsigned int cmd, unsigned long arg
case SNDRV_CTL_IOCTL_SUBSCRIBE_EVENTS: case SNDRV_CTL_IOCTL_SUBSCRIBE_EVENTS:
return snd_ctl_subscribe_events(ctl, ip); return snd_ctl_subscribe_events(ctl, ip);
case SNDRV_CTL_IOCTL_TLV_READ: case SNDRV_CTL_IOCTL_TLV_READ:
scoped_guard(rwsem_read, &ctl->card->controls_rwsem) err = snd_power_ref_and_wait(card);
if (err < 0)
return err;
scoped_guard(rwsem_read, &card->controls_rwsem)
err = snd_ctl_tlv_ioctl(ctl, argp, SNDRV_CTL_TLV_OP_READ); err = snd_ctl_tlv_ioctl(ctl, argp, SNDRV_CTL_TLV_OP_READ);
snd_power_unref(card);
return err; return err;
case SNDRV_CTL_IOCTL_TLV_WRITE: case SNDRV_CTL_IOCTL_TLV_WRITE:
scoped_guard(rwsem_write, &ctl->card->controls_rwsem) err = snd_power_ref_and_wait(card);
if (err < 0)
return err;
scoped_guard(rwsem_write, &card->controls_rwsem)
err = snd_ctl_tlv_ioctl(ctl, argp, SNDRV_CTL_TLV_OP_WRITE); err = snd_ctl_tlv_ioctl(ctl, argp, SNDRV_CTL_TLV_OP_WRITE);
snd_power_unref(card);
return err; return err;
case SNDRV_CTL_IOCTL_TLV_COMMAND: case SNDRV_CTL_IOCTL_TLV_COMMAND:
scoped_guard(rwsem_write, &ctl->card->controls_rwsem) err = snd_power_ref_and_wait(card);
if (err < 0)
return err;
scoped_guard(rwsem_write, &card->controls_rwsem)
err = snd_ctl_tlv_ioctl(ctl, argp, SNDRV_CTL_TLV_OP_CMD); err = snd_ctl_tlv_ioctl(ctl, argp, SNDRV_CTL_TLV_OP_CMD);
snd_power_unref(card);
return err; return err;
case SNDRV_CTL_IOCTL_POWER: case SNDRV_CTL_IOCTL_POWER:
return -ENOPROTOOPT; return -ENOPROTOOPT;
@ -2178,7 +2158,7 @@ int snd_ctl_get_preferred_subdevice(struct snd_card *card, int type)
struct snd_ctl_file *kctl; struct snd_ctl_file *kctl;
int subdevice = -1; int subdevice = -1;
guard(read_lock_irqsave)(&card->ctl_files_rwlock); guard(read_lock_irqsave)(&card->controls_rwlock);
list_for_each_entry(kctl, &card->ctl_files, list) { list_for_each_entry(kctl, &card->ctl_files, list) {
if (kctl->pid == task_pid(current)) { if (kctl->pid == task_pid(current)) {
subdevice = kctl->preferred_subdevice[type]; subdevice = kctl->preferred_subdevice[type];
@ -2328,7 +2308,7 @@ static int snd_ctl_dev_disconnect(struct snd_device *device)
struct snd_card *card = device->device_data; struct snd_card *card = device->device_data;
struct snd_ctl_file *ctl; struct snd_ctl_file *ctl;
scoped_guard(read_lock_irqsave, &card->ctl_files_rwlock) { scoped_guard(read_lock_irqsave, &card->controls_rwlock) {
list_for_each_entry(ctl, &card->ctl_files, list) { list_for_each_entry(ctl, &card->ctl_files, list) {
wake_up(&ctl->change_sleep); wake_up(&ctl->change_sleep);
snd_kill_fasync(ctl->fasync, SIGIO, POLL_ERR); snd_kill_fasync(ctl->fasync, SIGIO, POLL_ERR);

View File

@ -79,6 +79,7 @@ struct snd_ctl_elem_info32 {
static int snd_ctl_elem_info_compat(struct snd_ctl_file *ctl, static int snd_ctl_elem_info_compat(struct snd_ctl_file *ctl,
struct snd_ctl_elem_info32 __user *data32) struct snd_ctl_elem_info32 __user *data32)
{ {
struct snd_card *card = ctl->card;
struct snd_ctl_elem_info *data __free(kfree) = NULL; struct snd_ctl_elem_info *data __free(kfree) = NULL;
int err; int err;
@ -95,7 +96,11 @@ static int snd_ctl_elem_info_compat(struct snd_ctl_file *ctl,
if (get_user(data->value.enumerated.item, &data32->value.enumerated.item)) if (get_user(data->value.enumerated.item, &data32->value.enumerated.item))
return -EFAULT; return -EFAULT;
err = snd_power_ref_and_wait(card);
if (err < 0)
return err;
err = snd_ctl_elem_info(ctl, data); err = snd_ctl_elem_info(ctl, data);
snd_power_unref(card);
if (err < 0) if (err < 0)
return err; return err;
/* restore info to 32bit */ /* restore info to 32bit */
@ -168,17 +173,14 @@ static int get_ctl_type(struct snd_card *card, struct snd_ctl_elem_id *id,
int err; int err;
guard(rwsem_read)(&card->controls_rwsem); guard(rwsem_read)(&card->controls_rwsem);
kctl = snd_ctl_find_id_locked(card, id); kctl = snd_ctl_find_id(card, id);
if (!kctl) if (!kctl)
return -ENOENT; return -ENOENT;
info = kzalloc(sizeof(*info), GFP_KERNEL); info = kzalloc(sizeof(*info), GFP_KERNEL);
if (info == NULL) if (info == NULL)
return -ENOMEM; return -ENOMEM;
info->id = *id; info->id = *id;
err = snd_power_ref_and_wait(card); err = kctl->info(kctl, info);
if (!err)
err = kctl->info(kctl, info);
snd_power_unref(card);
if (err >= 0) { if (err >= 0) {
err = info->type; err = info->type;
*countp = info->count; *countp = info->count;
@ -275,8 +277,8 @@ static int copy_ctl_value_to_user(void __user *userdata,
return 0; return 0;
} }
static int ctl_elem_read_user(struct snd_card *card, static int __ctl_elem_read_user(struct snd_card *card,
void __user *userdata, void __user *valuep) void __user *userdata, void __user *valuep)
{ {
struct snd_ctl_elem_value *data __free(kfree) = NULL; struct snd_ctl_elem_value *data __free(kfree) = NULL;
int err, type, count; int err, type, count;
@ -296,8 +298,21 @@ static int ctl_elem_read_user(struct snd_card *card,
return copy_ctl_value_to_user(userdata, valuep, data, type, count); return copy_ctl_value_to_user(userdata, valuep, data, type, count);
} }
static int ctl_elem_write_user(struct snd_ctl_file *file, static int ctl_elem_read_user(struct snd_card *card,
void __user *userdata, void __user *valuep) void __user *userdata, void __user *valuep)
{
int err;
err = snd_power_ref_and_wait(card);
if (err < 0)
return err;
err = __ctl_elem_read_user(card, userdata, valuep);
snd_power_unref(card);
return err;
}
static int __ctl_elem_write_user(struct snd_ctl_file *file,
void __user *userdata, void __user *valuep)
{ {
struct snd_ctl_elem_value *data __free(kfree) = NULL; struct snd_ctl_elem_value *data __free(kfree) = NULL;
struct snd_card *card = file->card; struct snd_card *card = file->card;
@ -318,6 +333,20 @@ static int ctl_elem_write_user(struct snd_ctl_file *file,
return copy_ctl_value_to_user(userdata, valuep, data, type, count); return copy_ctl_value_to_user(userdata, valuep, data, type, count);
} }
static int ctl_elem_write_user(struct snd_ctl_file *file,
void __user *userdata, void __user *valuep)
{
struct snd_card *card = file->card;
int err;
err = snd_power_ref_and_wait(card);
if (err < 0)
return err;
err = __ctl_elem_write_user(file, userdata, valuep);
snd_power_unref(card);
return err;
}
static int snd_ctl_elem_read_user_compat(struct snd_card *card, static int snd_ctl_elem_read_user_compat(struct snd_card *card,
struct snd_ctl_elem_value32 __user *data32) struct snd_ctl_elem_value32 __user *data32)
{ {

View File

@ -254,7 +254,7 @@ static int snd_ctl_led_set_id(int card_number, struct snd_ctl_elem_id *id,
if (!card) if (!card)
return -ENXIO; return -ENXIO;
guard(rwsem_write)(&card->controls_rwsem); guard(rwsem_write)(&card->controls_rwsem);
kctl = snd_ctl_find_id_locked(card, id); kctl = snd_ctl_find_id(card, id);
if (!kctl) if (!kctl)
return -ENOENT; return -ENOENT;
ioff = snd_ctl_get_ioff(kctl, id); ioff = snd_ctl_get_ioff(kctl, id);
@ -677,7 +677,7 @@ static void snd_ctl_led_sysfs_add(struct snd_card *card)
cerr: cerr:
put_device(&led_card->dev); put_device(&led_card->dev);
cerr2: cerr2:
printk(KERN_ERR "snd_ctl_led: unable to add card%d", card->number); dev_err(card->dev, "snd_ctl_led: unable to add card%d", card->number);
} }
} }

View File

@ -315,7 +315,7 @@ static int snd_card_init(struct snd_card *card, struct device *parent,
card->module = module; card->module = module;
INIT_LIST_HEAD(&card->devices); INIT_LIST_HEAD(&card->devices);
init_rwsem(&card->controls_rwsem); init_rwsem(&card->controls_rwsem);
rwlock_init(&card->ctl_files_rwlock); rwlock_init(&card->controls_rwlock);
INIT_LIST_HEAD(&card->controls); INIT_LIST_HEAD(&card->controls);
INIT_LIST_HEAD(&card->ctl_files); INIT_LIST_HEAD(&card->ctl_files);
#ifdef CONFIG_SND_CTL_FAST_LOOKUP #ifdef CONFIG_SND_CTL_FAST_LOOKUP

View File

@ -17,7 +17,17 @@
#include <asm/set_memory.h> #include <asm/set_memory.h>
#endif #endif
#include <sound/memalloc.h> #include <sound/memalloc.h>
#include "memalloc_local.h"
struct snd_malloc_ops {
void *(*alloc)(struct snd_dma_buffer *dmab, size_t size);
void (*free)(struct snd_dma_buffer *dmab);
dma_addr_t (*get_addr)(struct snd_dma_buffer *dmab, size_t offset);
struct page *(*get_page)(struct snd_dma_buffer *dmab, size_t offset);
unsigned int (*get_chunk_size)(struct snd_dma_buffer *dmab,
unsigned int ofs, unsigned int size);
int (*mmap)(struct snd_dma_buffer *dmab, struct vm_area_struct *area);
void (*sync)(struct snd_dma_buffer *dmab, enum snd_dma_sync_mode mode);
};
#define DEFAULT_GFP \ #define DEFAULT_GFP \
(GFP_KERNEL | \ (GFP_KERNEL | \
@ -26,10 +36,6 @@
static const struct snd_malloc_ops *snd_dma_get_ops(struct snd_dma_buffer *dmab); static const struct snd_malloc_ops *snd_dma_get_ops(struct snd_dma_buffer *dmab);
#ifdef CONFIG_SND_DMA_SGBUF
static void *snd_dma_sg_fallback_alloc(struct snd_dma_buffer *dmab, size_t size);
#endif
static void *__snd_dma_alloc_pages(struct snd_dma_buffer *dmab, size_t size) static void *__snd_dma_alloc_pages(struct snd_dma_buffer *dmab, size_t size)
{ {
const struct snd_malloc_ops *ops = snd_dma_get_ops(dmab); const struct snd_malloc_ops *ops = snd_dma_get_ops(dmab);
@ -490,15 +496,26 @@ static const struct snd_malloc_ops snd_dma_dev_ops = {
/* /*
* Write-combined pages * Write-combined pages
*/ */
/* x86-specific allocations */
#ifdef CONFIG_SND_DMA_SGBUF #ifdef CONFIG_SND_DMA_SGBUF
/* x86-specific allocations */
static void *snd_dma_wc_alloc(struct snd_dma_buffer *dmab, size_t size) static void *snd_dma_wc_alloc(struct snd_dma_buffer *dmab, size_t size)
{ {
return do_alloc_pages(dmab->dev.dev, size, &dmab->addr, true); void *p = do_alloc_pages(dmab->dev.dev, size, &dmab->addr, true);
if (!p)
return NULL;
dmab->addr = dma_map_single(dmab->dev.dev, p, size, DMA_BIDIRECTIONAL);
if (dmab->addr == DMA_MAPPING_ERROR) {
do_free_pages(dmab->area, size, true);
return NULL;
}
return p;
} }
static void snd_dma_wc_free(struct snd_dma_buffer *dmab) static void snd_dma_wc_free(struct snd_dma_buffer *dmab)
{ {
dma_unmap_single(dmab->dev.dev, dmab->addr, dmab->bytes,
DMA_BIDIRECTIONAL);
do_free_pages(dmab->area, dmab->bytes, true); do_free_pages(dmab->area, dmab->bytes, true);
} }
@ -506,7 +523,8 @@ static int snd_dma_wc_mmap(struct snd_dma_buffer *dmab,
struct vm_area_struct *area) struct vm_area_struct *area)
{ {
area->vm_page_prot = pgprot_writecombine(area->vm_page_prot); area->vm_page_prot = pgprot_writecombine(area->vm_page_prot);
return snd_dma_continuous_mmap(dmab, area); return dma_mmap_coherent(dmab->dev.dev, area,
dmab->area, dmab->addr, dmab->bytes);
} }
#else #else
static void *snd_dma_wc_alloc(struct snd_dma_buffer *dmab, size_t size) static void *snd_dma_wc_alloc(struct snd_dma_buffer *dmab, size_t size)
@ -525,7 +543,7 @@ static int snd_dma_wc_mmap(struct snd_dma_buffer *dmab,
return dma_mmap_wc(dmab->dev.dev, area, return dma_mmap_wc(dmab->dev.dev, area,
dmab->area, dmab->addr, dmab->bytes); dmab->area, dmab->addr, dmab->bytes);
} }
#endif /* CONFIG_SND_DMA_SGBUF */ #endif
static const struct snd_malloc_ops snd_dma_wc_ops = { static const struct snd_malloc_ops snd_dma_wc_ops = {
.alloc = snd_dma_wc_alloc, .alloc = snd_dma_wc_alloc,
@ -541,16 +559,8 @@ static void *snd_dma_noncontig_alloc(struct snd_dma_buffer *dmab, size_t size)
struct sg_table *sgt; struct sg_table *sgt;
void *p; void *p;
#ifdef CONFIG_SND_DMA_SGBUF
if (cpu_feature_enabled(X86_FEATURE_XENPV))
return snd_dma_sg_fallback_alloc(dmab, size);
#endif
sgt = dma_alloc_noncontiguous(dmab->dev.dev, size, dmab->dev.dir, sgt = dma_alloc_noncontiguous(dmab->dev.dev, size, dmab->dev.dir,
DEFAULT_GFP, 0); DEFAULT_GFP, 0);
#ifdef CONFIG_SND_DMA_SGBUF
if (!sgt && !get_dma_ops(dmab->dev.dev))
return snd_dma_sg_fallback_alloc(dmab, size);
#endif
if (!sgt) if (!sgt)
return NULL; return NULL;
@ -667,125 +677,64 @@ static const struct snd_malloc_ops snd_dma_noncontig_ops = {
.get_chunk_size = snd_dma_noncontig_get_chunk_size, .get_chunk_size = snd_dma_noncontig_get_chunk_size,
}; };
/* x86-specific SG-buffer with WC pages */
#ifdef CONFIG_SND_DMA_SGBUF #ifdef CONFIG_SND_DMA_SGBUF
#define sg_wc_address(it) ((unsigned long)page_address(sg_page_iter_page(it)))
static void *snd_dma_sg_wc_alloc(struct snd_dma_buffer *dmab, size_t size)
{
void *p = snd_dma_noncontig_alloc(dmab, size);
struct sg_table *sgt = dmab->private_data;
struct sg_page_iter iter;
if (!p)
return NULL;
if (dmab->dev.type != SNDRV_DMA_TYPE_DEV_WC_SG)
return p;
for_each_sgtable_page(sgt, &iter, 0)
set_memory_wc(sg_wc_address(&iter), 1);
return p;
}
static void snd_dma_sg_wc_free(struct snd_dma_buffer *dmab)
{
struct sg_table *sgt = dmab->private_data;
struct sg_page_iter iter;
for_each_sgtable_page(sgt, &iter, 0)
set_memory_wb(sg_wc_address(&iter), 1);
snd_dma_noncontig_free(dmab);
}
static int snd_dma_sg_wc_mmap(struct snd_dma_buffer *dmab,
struct vm_area_struct *area)
{
area->vm_page_prot = pgprot_writecombine(area->vm_page_prot);
return dma_mmap_noncontiguous(dmab->dev.dev, area,
dmab->bytes, dmab->private_data);
}
static const struct snd_malloc_ops snd_dma_sg_wc_ops = {
.alloc = snd_dma_sg_wc_alloc,
.free = snd_dma_sg_wc_free,
.mmap = snd_dma_sg_wc_mmap,
.sync = snd_dma_noncontig_sync,
.get_addr = snd_dma_noncontig_get_addr,
.get_page = snd_dma_noncontig_get_page,
.get_chunk_size = snd_dma_noncontig_get_chunk_size,
};
/* Fallback SG-buffer allocations for x86 */ /* Fallback SG-buffer allocations for x86 */
struct snd_dma_sg_fallback { struct snd_dma_sg_fallback {
bool use_dma_alloc_coherent; struct sg_table sgt; /* used by get_addr - must be the first item */
size_t count; size_t count;
struct page **pages; struct page **pages;
/* DMA address array; the first page contains #pages in ~PAGE_MASK */ unsigned int *npages;
dma_addr_t *addrs;
}; };
static void __snd_dma_sg_fallback_free(struct snd_dma_buffer *dmab, static void __snd_dma_sg_fallback_free(struct snd_dma_buffer *dmab,
struct snd_dma_sg_fallback *sgbuf) struct snd_dma_sg_fallback *sgbuf)
{ {
bool wc = dmab->dev.type == SNDRV_DMA_TYPE_DEV_WC_SG;
size_t i, size; size_t i, size;
if (sgbuf->pages && sgbuf->addrs) { if (sgbuf->pages && sgbuf->npages) {
i = 0; i = 0;
while (i < sgbuf->count) { while (i < sgbuf->count) {
if (!sgbuf->pages[i] || !sgbuf->addrs[i]) size = sgbuf->npages[i];
if (!size)
break; break;
size = sgbuf->addrs[i] & ~PAGE_MASK; do_free_pages(page_address(sgbuf->pages[i]),
if (WARN_ON(!size)) size << PAGE_SHIFT, wc);
break;
if (sgbuf->use_dma_alloc_coherent)
dma_free_coherent(dmab->dev.dev, size << PAGE_SHIFT,
page_address(sgbuf->pages[i]),
sgbuf->addrs[i] & PAGE_MASK);
else
do_free_pages(page_address(sgbuf->pages[i]),
size << PAGE_SHIFT, false);
i += size; i += size;
} }
} }
kvfree(sgbuf->pages); kvfree(sgbuf->pages);
kvfree(sgbuf->addrs); kvfree(sgbuf->npages);
kfree(sgbuf); kfree(sgbuf);
} }
/* fallback manual S/G buffer allocations */
static void *snd_dma_sg_fallback_alloc(struct snd_dma_buffer *dmab, size_t size) static void *snd_dma_sg_fallback_alloc(struct snd_dma_buffer *dmab, size_t size)
{ {
bool wc = dmab->dev.type == SNDRV_DMA_TYPE_DEV_WC_SG;
struct snd_dma_sg_fallback *sgbuf; struct snd_dma_sg_fallback *sgbuf;
struct page **pagep, *curp; struct page **pagep, *curp;
size_t chunk, npages; size_t chunk;
dma_addr_t *addrp;
dma_addr_t addr; dma_addr_t addr;
unsigned int idx, npages;
void *p; void *p;
/* correct the type */
if (dmab->dev.type == SNDRV_DMA_TYPE_DEV_SG)
dmab->dev.type = SNDRV_DMA_TYPE_DEV_SG_FALLBACK;
else if (dmab->dev.type == SNDRV_DMA_TYPE_DEV_WC_SG)
dmab->dev.type = SNDRV_DMA_TYPE_DEV_WC_SG_FALLBACK;
sgbuf = kzalloc(sizeof(*sgbuf), GFP_KERNEL); sgbuf = kzalloc(sizeof(*sgbuf), GFP_KERNEL);
if (!sgbuf) if (!sgbuf)
return NULL; return NULL;
sgbuf->use_dma_alloc_coherent = cpu_feature_enabled(X86_FEATURE_XENPV);
size = PAGE_ALIGN(size); size = PAGE_ALIGN(size);
sgbuf->count = size >> PAGE_SHIFT; sgbuf->count = size >> PAGE_SHIFT;
sgbuf->pages = kvcalloc(sgbuf->count, sizeof(*sgbuf->pages), GFP_KERNEL); sgbuf->pages = kvcalloc(sgbuf->count, sizeof(*sgbuf->pages), GFP_KERNEL);
sgbuf->addrs = kvcalloc(sgbuf->count, sizeof(*sgbuf->addrs), GFP_KERNEL); sgbuf->npages = kvcalloc(sgbuf->count, sizeof(*sgbuf->npages), GFP_KERNEL);
if (!sgbuf->pages || !sgbuf->addrs) if (!sgbuf->pages || !sgbuf->npages)
goto error; goto error;
pagep = sgbuf->pages; pagep = sgbuf->pages;
addrp = sgbuf->addrs; chunk = size;
chunk = (PAGE_SIZE - 1) << PAGE_SHIFT; /* to fit in low bits in addrs */ idx = 0;
while (size > 0) { while (size > 0) {
chunk = min(size, chunk); chunk = min(size, chunk);
if (sgbuf->use_dma_alloc_coherent) p = do_alloc_pages(dmab->dev.dev, chunk, &addr, wc);
p = dma_alloc_coherent(dmab->dev.dev, chunk, &addr, DEFAULT_GFP);
else
p = do_alloc_pages(dmab->dev.dev, chunk, &addr, false);
if (!p) { if (!p) {
if (chunk <= PAGE_SIZE) if (chunk <= PAGE_SIZE)
goto error; goto error;
@ -797,27 +746,33 @@ static void *snd_dma_sg_fallback_alloc(struct snd_dma_buffer *dmab, size_t size)
size -= chunk; size -= chunk;
/* fill pages */ /* fill pages */
npages = chunk >> PAGE_SHIFT; npages = chunk >> PAGE_SHIFT;
*addrp = npages; /* store in lower bits */ sgbuf->npages[idx] = npages;
idx += npages;
curp = virt_to_page(p); curp = virt_to_page(p);
while (npages--) { while (npages--)
*pagep++ = curp++; *pagep++ = curp++;
*addrp++ |= addr;
addr += PAGE_SIZE;
}
} }
if (sg_alloc_table_from_pages(&sgbuf->sgt, sgbuf->pages, sgbuf->count,
0, sgbuf->count << PAGE_SHIFT, GFP_KERNEL))
goto error;
if (dma_map_sgtable(dmab->dev.dev, &sgbuf->sgt, DMA_BIDIRECTIONAL, 0))
goto error_dma_map;
p = vmap(sgbuf->pages, sgbuf->count, VM_MAP, PAGE_KERNEL); p = vmap(sgbuf->pages, sgbuf->count, VM_MAP, PAGE_KERNEL);
if (!p) if (!p)
goto error; goto error_vmap;
if (dmab->dev.type == SNDRV_DMA_TYPE_DEV_WC_SG_FALLBACK)
set_pages_array_wc(sgbuf->pages, sgbuf->count);
dmab->private_data = sgbuf; dmab->private_data = sgbuf;
/* store the first page address for convenience */ /* store the first page address for convenience */
dmab->addr = sgbuf->addrs[0] & PAGE_MASK; dmab->addr = snd_sgbuf_get_addr(dmab, 0);
return p; return p;
error_vmap:
dma_unmap_sgtable(dmab->dev.dev, &sgbuf->sgt, DMA_BIDIRECTIONAL, 0);
error_dma_map:
sg_free_table(&sgbuf->sgt);
error: error:
__snd_dma_sg_fallback_free(dmab, sgbuf); __snd_dma_sg_fallback_free(dmab, sgbuf);
return NULL; return NULL;
@ -827,36 +782,46 @@ static void snd_dma_sg_fallback_free(struct snd_dma_buffer *dmab)
{ {
struct snd_dma_sg_fallback *sgbuf = dmab->private_data; struct snd_dma_sg_fallback *sgbuf = dmab->private_data;
if (dmab->dev.type == SNDRV_DMA_TYPE_DEV_WC_SG_FALLBACK)
set_pages_array_wb(sgbuf->pages, sgbuf->count);
vunmap(dmab->area); vunmap(dmab->area);
dma_unmap_sgtable(dmab->dev.dev, &sgbuf->sgt, DMA_BIDIRECTIONAL, 0);
sg_free_table(&sgbuf->sgt);
__snd_dma_sg_fallback_free(dmab, dmab->private_data); __snd_dma_sg_fallback_free(dmab, dmab->private_data);
} }
static dma_addr_t snd_dma_sg_fallback_get_addr(struct snd_dma_buffer *dmab,
size_t offset)
{
struct snd_dma_sg_fallback *sgbuf = dmab->private_data;
size_t index = offset >> PAGE_SHIFT;
return (sgbuf->addrs[index] & PAGE_MASK) | (offset & ~PAGE_MASK);
}
static int snd_dma_sg_fallback_mmap(struct snd_dma_buffer *dmab, static int snd_dma_sg_fallback_mmap(struct snd_dma_buffer *dmab,
struct vm_area_struct *area) struct vm_area_struct *area)
{ {
struct snd_dma_sg_fallback *sgbuf = dmab->private_data; struct snd_dma_sg_fallback *sgbuf = dmab->private_data;
if (dmab->dev.type == SNDRV_DMA_TYPE_DEV_WC_SG_FALLBACK) if (dmab->dev.type == SNDRV_DMA_TYPE_DEV_WC_SG)
area->vm_page_prot = pgprot_writecombine(area->vm_page_prot); area->vm_page_prot = pgprot_writecombine(area->vm_page_prot);
return vm_map_pages(area, sgbuf->pages, sgbuf->count); return vm_map_pages(area, sgbuf->pages, sgbuf->count);
} }
static const struct snd_malloc_ops snd_dma_sg_fallback_ops = { static void *snd_dma_sg_alloc(struct snd_dma_buffer *dmab, size_t size)
.alloc = snd_dma_sg_fallback_alloc, {
int type = dmab->dev.type;
void *p;
/* try the standard DMA API allocation at first */
if (type == SNDRV_DMA_TYPE_DEV_WC_SG)
dmab->dev.type = SNDRV_DMA_TYPE_DEV_WC;
else
dmab->dev.type = SNDRV_DMA_TYPE_DEV;
p = __snd_dma_alloc_pages(dmab, size);
if (p)
return p;
dmab->dev.type = type; /* restore the type */
return snd_dma_sg_fallback_alloc(dmab, size);
}
static const struct snd_malloc_ops snd_dma_sg_ops = {
.alloc = snd_dma_sg_alloc,
.free = snd_dma_sg_fallback_free, .free = snd_dma_sg_fallback_free,
.mmap = snd_dma_sg_fallback_mmap, .mmap = snd_dma_sg_fallback_mmap,
.get_addr = snd_dma_sg_fallback_get_addr, /* reuse noncontig helper */
.get_addr = snd_dma_noncontig_get_addr,
/* reuse vmalloc helpers */ /* reuse vmalloc helpers */
.get_page = snd_dma_vmalloc_get_page, .get_page = snd_dma_vmalloc_get_page,
.get_chunk_size = snd_dma_vmalloc_get_chunk_size, .get_chunk_size = snd_dma_vmalloc_get_chunk_size,
@ -927,15 +892,12 @@ static const struct snd_malloc_ops *snd_dma_ops[] = {
[SNDRV_DMA_TYPE_NONCONTIG] = &snd_dma_noncontig_ops, [SNDRV_DMA_TYPE_NONCONTIG] = &snd_dma_noncontig_ops,
[SNDRV_DMA_TYPE_NONCOHERENT] = &snd_dma_noncoherent_ops, [SNDRV_DMA_TYPE_NONCOHERENT] = &snd_dma_noncoherent_ops,
#ifdef CONFIG_SND_DMA_SGBUF #ifdef CONFIG_SND_DMA_SGBUF
[SNDRV_DMA_TYPE_DEV_WC_SG] = &snd_dma_sg_wc_ops, [SNDRV_DMA_TYPE_DEV_SG] = &snd_dma_sg_ops,
[SNDRV_DMA_TYPE_DEV_WC_SG] = &snd_dma_sg_ops,
#endif #endif
#ifdef CONFIG_GENERIC_ALLOCATOR #ifdef CONFIG_GENERIC_ALLOCATOR
[SNDRV_DMA_TYPE_DEV_IRAM] = &snd_dma_iram_ops, [SNDRV_DMA_TYPE_DEV_IRAM] = &snd_dma_iram_ops,
#endif /* CONFIG_GENERIC_ALLOCATOR */ #endif /* CONFIG_GENERIC_ALLOCATOR */
#ifdef CONFIG_SND_DMA_SGBUF
[SNDRV_DMA_TYPE_DEV_SG_FALLBACK] = &snd_dma_sg_fallback_ops,
[SNDRV_DMA_TYPE_DEV_WC_SG_FALLBACK] = &snd_dma_sg_fallback_ops,
#endif
#endif /* CONFIG_HAS_DMA */ #endif /* CONFIG_HAS_DMA */
}; };

View File

@ -1,16 +0,0 @@
// SPDX-License-Identifier: GPL-2.0-only
#ifndef __MEMALLOC_LOCAL_H
#define __MEMALLOC_LOCAL_H
struct snd_malloc_ops {
void *(*alloc)(struct snd_dma_buffer *dmab, size_t size);
void (*free)(struct snd_dma_buffer *dmab);
dma_addr_t (*get_addr)(struct snd_dma_buffer *dmab, size_t offset);
struct page *(*get_page)(struct snd_dma_buffer *dmab, size_t offset);
unsigned int (*get_chunk_size)(struct snd_dma_buffer *dmab,
unsigned int ofs, unsigned int size);
int (*mmap)(struct snd_dma_buffer *dmab, struct vm_area_struct *area);
void (*sync)(struct snd_dma_buffer *dmab, enum snd_dma_sync_mode mode);
};
#endif /* __MEMALLOC_LOCAL_H */

View File

@ -13,20 +13,6 @@
#include <linux/fs.h> #include <linux/fs.h>
#include <sound/core.h> #include <sound/core.h>
#ifdef CONFIG_SND_DEBUG
#ifdef CONFIG_SND_DEBUG_VERBOSE
#define DEFAULT_DEBUG_LEVEL 2
#else
#define DEFAULT_DEBUG_LEVEL 1
#endif
static int debug = DEFAULT_DEBUG_LEVEL;
module_param(debug, int, 0644);
MODULE_PARM_DESC(debug, "Debug level (0 = disable)");
#endif /* CONFIG_SND_DEBUG */
void release_and_free_resource(struct resource *res) void release_and_free_resource(struct resource *res)
{ {
if (res) { if (res) {
@ -36,63 +22,6 @@ void release_and_free_resource(struct resource *res)
} }
EXPORT_SYMBOL(release_and_free_resource); EXPORT_SYMBOL(release_and_free_resource);
#ifdef CONFIG_SND_VERBOSE_PRINTK
/* strip the leading path if the given path is absolute */
static const char *sanity_file_name(const char *path)
{
if (*path == '/')
return strrchr(path, '/') + 1;
else
return path;
}
#endif
#if defined(CONFIG_SND_DEBUG) || defined(CONFIG_SND_VERBOSE_PRINTK)
void __snd_printk(unsigned int level, const char *path, int line,
const char *format, ...)
{
va_list args;
#ifdef CONFIG_SND_VERBOSE_PRINTK
int kern_level;
struct va_format vaf;
char verbose_fmt[] = KERN_DEFAULT "ALSA %s:%d %pV";
bool level_found = false;
#endif
#ifdef CONFIG_SND_DEBUG
if (debug < level)
return;
#endif
va_start(args, format);
#ifdef CONFIG_SND_VERBOSE_PRINTK
vaf.fmt = format;
vaf.va = &args;
while ((kern_level = printk_get_level(vaf.fmt)) != 0) {
const char *end_of_header = printk_skip_level(vaf.fmt);
/* Ignore KERN_CONT. We print filename:line for each piece. */
if (kern_level >= '0' && kern_level <= '7') {
memcpy(verbose_fmt, vaf.fmt, end_of_header - vaf.fmt);
level_found = true;
}
vaf.fmt = end_of_header;
}
if (!level_found && level)
memcpy(verbose_fmt, KERN_DEBUG, sizeof(KERN_DEBUG) - 1);
printk(verbose_fmt, sanity_file_name(path), line, &vaf);
#else
vprintk(format, args);
#endif
va_end(args);
}
EXPORT_SYMBOL_GPL(__snd_printk);
#endif
#ifdef CONFIG_PCI #ifdef CONFIG_PCI
#include <linux/pci.h> #include <linux/pci.h>
/** /**

View File

@ -510,7 +510,7 @@ static struct snd_kcontrol *snd_mixer_oss_test_id(struct snd_mixer_oss *mixer, c
id.iface = SNDRV_CTL_ELEM_IFACE_MIXER; id.iface = SNDRV_CTL_ELEM_IFACE_MIXER;
strscpy(id.name, name, sizeof(id.name)); strscpy(id.name, name, sizeof(id.name));
id.index = index; id.index = index;
return snd_ctl_find_id_locked(card, &id); return snd_ctl_find_id(card, &id);
} }
static void snd_mixer_oss_get_volume1_vol(struct snd_mixer_oss_file *fmixer, static void snd_mixer_oss_get_volume1_vol(struct snd_mixer_oss_file *fmixer,
@ -526,7 +526,7 @@ static void snd_mixer_oss_get_volume1_vol(struct snd_mixer_oss_file *fmixer,
if (numid == ID_UNKNOWN) if (numid == ID_UNKNOWN)
return; return;
guard(rwsem_read)(&card->controls_rwsem); guard(rwsem_read)(&card->controls_rwsem);
kctl = snd_ctl_find_numid_locked(card, numid); kctl = snd_ctl_find_numid(card, numid);
if (!kctl) if (!kctl)
return; return;
uinfo = kzalloc(sizeof(*uinfo), GFP_KERNEL); uinfo = kzalloc(sizeof(*uinfo), GFP_KERNEL);
@ -559,7 +559,7 @@ static void snd_mixer_oss_get_volume1_sw(struct snd_mixer_oss_file *fmixer,
if (numid == ID_UNKNOWN) if (numid == ID_UNKNOWN)
return; return;
guard(rwsem_read)(&card->controls_rwsem); guard(rwsem_read)(&card->controls_rwsem);
kctl = snd_ctl_find_numid_locked(card, numid); kctl = snd_ctl_find_numid(card, numid);
if (!kctl) if (!kctl)
return; return;
uinfo = kzalloc(sizeof(*uinfo), GFP_KERNEL); uinfo = kzalloc(sizeof(*uinfo), GFP_KERNEL);
@ -619,7 +619,7 @@ static void snd_mixer_oss_put_volume1_vol(struct snd_mixer_oss_file *fmixer,
if (numid == ID_UNKNOWN) if (numid == ID_UNKNOWN)
return; return;
guard(rwsem_read)(&card->controls_rwsem); guard(rwsem_read)(&card->controls_rwsem);
kctl = snd_ctl_find_numid_locked(card, numid); kctl = snd_ctl_find_numid(card, numid);
if (!kctl) if (!kctl)
return; return;
uinfo = kzalloc(sizeof(*uinfo), GFP_KERNEL); uinfo = kzalloc(sizeof(*uinfo), GFP_KERNEL);
@ -656,7 +656,7 @@ static void snd_mixer_oss_put_volume1_sw(struct snd_mixer_oss_file *fmixer,
if (numid == ID_UNKNOWN) if (numid == ID_UNKNOWN)
return; return;
guard(rwsem_read)(&card->controls_rwsem); guard(rwsem_read)(&card->controls_rwsem);
kctl = snd_ctl_find_numid_locked(card, numid); kctl = snd_ctl_find_numid(card, numid);
if (!kctl) if (!kctl)
return; return;
uinfo = kzalloc(sizeof(*uinfo), GFP_KERNEL); uinfo = kzalloc(sizeof(*uinfo), GFP_KERNEL);

View File

@ -74,7 +74,6 @@ int snd_pcm_plugin_build(struct snd_pcm_substream *handle,
size_t extra, size_t extra,
struct snd_pcm_plugin **ret); struct snd_pcm_plugin **ret);
int snd_pcm_plugin_free(struct snd_pcm_plugin *plugin); int snd_pcm_plugin_free(struct snd_pcm_plugin *plugin);
int snd_pcm_plugin_clear(struct snd_pcm_plugin **first);
int snd_pcm_plug_alloc(struct snd_pcm_substream *plug, snd_pcm_uframes_t frames); int snd_pcm_plug_alloc(struct snd_pcm_substream *plug, snd_pcm_uframes_t frames);
snd_pcm_sframes_t snd_pcm_plug_client_size(struct snd_pcm_substream *handle, snd_pcm_uframes_t drv_size); snd_pcm_sframes_t snd_pcm_plug_client_size(struct snd_pcm_substream *handle, snd_pcm_uframes_t drv_size);
snd_pcm_sframes_t snd_pcm_plug_slave_size(struct snd_pcm_substream *handle, snd_pcm_uframes_t clt_size); snd_pcm_sframes_t snd_pcm_plug_slave_size(struct snd_pcm_substream *handle, snd_pcm_uframes_t clt_size);
@ -139,8 +138,6 @@ int snd_pcm_area_copy(const struct snd_pcm_channel_area *src_channel,
size_t dst_offset, size_t dst_offset,
size_t samples, snd_pcm_format_t format); size_t samples, snd_pcm_format_t format);
void *snd_pcm_plug_buf_alloc(struct snd_pcm_substream *plug, snd_pcm_uframes_t size);
void snd_pcm_plug_buf_unlock(struct snd_pcm_substream *plug, void *ptr);
#else #else
static inline snd_pcm_sframes_t snd_pcm_plug_client_size(struct snd_pcm_substream *handle, snd_pcm_uframes_t drv_size) { return drv_size; } static inline snd_pcm_sframes_t snd_pcm_plug_client_size(struct snd_pcm_substream *handle, snd_pcm_uframes_t drv_size) { return drv_size; }
@ -160,7 +157,7 @@ snd_pcm_sframes_t snd_pcm_oss_readv3(struct snd_pcm_substream *substream,
void **bufs, snd_pcm_uframes_t frames); void **bufs, snd_pcm_uframes_t frames);
#ifdef PLUGIN_DEBUG #ifdef PLUGIN_DEBUG
#define pdprintf(fmt, args...) printk(KERN_DEBUG "plugin: " fmt, ##args) #define pdprintf(fmt, args...) pr_debug("plugin: " fmt, ##args)
#else #else
#define pdprintf(fmt, args...) #define pdprintf(fmt, args...)
#endif #endif

View File

@ -462,6 +462,9 @@ static void snd_pcm_substream_proc_status_read(struct snd_info_entry *entry,
snd_iprintf(buffer, "-----\n"); snd_iprintf(buffer, "-----\n");
snd_iprintf(buffer, "hw_ptr : %ld\n", runtime->status->hw_ptr); snd_iprintf(buffer, "hw_ptr : %ld\n", runtime->status->hw_ptr);
snd_iprintf(buffer, "appl_ptr : %ld\n", runtime->control->appl_ptr); snd_iprintf(buffer, "appl_ptr : %ld\n", runtime->control->appl_ptr);
#ifdef CONFIG_SND_PCM_XRUN_DEBUG
snd_iprintf(buffer, "xrun_counter: %d\n", substream->xrun_counter);
#endif
} }
#ifdef CONFIG_SND_PCM_XRUN_DEBUG #ifdef CONFIG_SND_PCM_XRUN_DEBUG
@ -970,6 +973,9 @@ int snd_pcm_attach_substream(struct snd_pcm *pcm, int stream,
substream->pid = get_pid(task_pid(current)); substream->pid = get_pid(task_pid(current));
pstr->substream_opened++; pstr->substream_opened++;
*rsubstream = substream; *rsubstream = substream;
#ifdef CONFIG_SND_PCM_XRUN_DEBUG
substream->xrun_counter = 0;
#endif /* CONFIG_SND_PCM_XRUN_DEBUG */
return 0; return 0;
} }

View File

@ -184,6 +184,9 @@ void __snd_pcm_xrun(struct snd_pcm_substream *substream)
pcm_warn(substream->pcm, "XRUN: %s\n", name); pcm_warn(substream->pcm, "XRUN: %s\n", name);
dump_stack_on_xrun(substream); dump_stack_on_xrun(substream);
} }
#ifdef CONFIG_SND_PCM_XRUN_DEBUG
substream->xrun_counter++;
#endif
} }
#ifdef CONFIG_SND_PCM_XRUN_DEBUG #ifdef CONFIG_SND_PCM_XRUN_DEBUG

View File

@ -9,7 +9,6 @@
#include <linux/init.h> #include <linux/init.h>
#include <linux/slab.h> #include <linux/slab.h>
#include <linux/moduleparam.h> #include <linux/moduleparam.h>
#include <linux/vmalloc.h>
#include <linux/export.h> #include <linux/export.h>
#include <sound/core.h> #include <sound/core.h>
#include <sound/pcm.h> #include <sound/pcm.h>
@ -184,7 +183,7 @@ static void snd_pcm_lib_preallocate_proc_write(struct snd_info_entry *entry,
struct snd_pcm_substream *substream = entry->private_data; struct snd_pcm_substream *substream = entry->private_data;
struct snd_card *card = substream->pcm->card; struct snd_card *card = substream->pcm->card;
char line[64], str[64]; char line[64], str[64];
size_t size; unsigned long size;
struct snd_dma_buffer new_dmab; struct snd_dma_buffer new_dmab;
guard(mutex)(&substream->pcm->open_mutex); guard(mutex)(&substream->pcm->open_mutex);
@ -194,7 +193,10 @@ static void snd_pcm_lib_preallocate_proc_write(struct snd_info_entry *entry,
} }
if (!snd_info_get_line(buffer, line, sizeof(line))) { if (!snd_info_get_line(buffer, line, sizeof(line))) {
snd_info_get_str(str, line, sizeof(str)); snd_info_get_str(str, line, sizeof(str));
size = simple_strtoul(str, NULL, 10) * 1024; buffer->error = kstrtoul(str, 10, &size);
if (buffer->error != 0)
return;
size *= 1024;
if ((size != 0 && size < 8192) || size > substream->dma_max) { if ((size != 0 && size < 8192) || size > substream->dma_max) {
buffer->error = -EINVAL; buffer->error = -EINVAL;
return; return;
@ -210,7 +212,7 @@ static void snd_pcm_lib_preallocate_proc_write(struct snd_info_entry *entry,
substream->stream, substream->stream,
size, &new_dmab) < 0) { size, &new_dmab) < 0) {
buffer->error = -ENOMEM; buffer->error = -ENOMEM;
pr_debug("ALSA pcmC%dD%d%c,%d:%s: cannot preallocate for size %zu\n", pr_debug("ALSA pcmC%dD%d%c,%d:%s: cannot preallocate for size %lu\n",
substream->pcm->card->number, substream->pcm->device, substream->pcm->card->number, substream->pcm->device,
substream->stream ? 'c' : 'p', substream->number, substream->stream ? 'c' : 'p', substream->number,
substream->pcm->name, size); substream->pcm->name, size);
@ -497,61 +499,3 @@ int snd_pcm_lib_free_pages(struct snd_pcm_substream *substream)
return 0; return 0;
} }
EXPORT_SYMBOL(snd_pcm_lib_free_pages); EXPORT_SYMBOL(snd_pcm_lib_free_pages);
int _snd_pcm_lib_alloc_vmalloc_buffer(struct snd_pcm_substream *substream,
size_t size, gfp_t gfp_flags)
{
struct snd_pcm_runtime *runtime;
if (PCM_RUNTIME_CHECK(substream))
return -EINVAL;
runtime = substream->runtime;
if (runtime->dma_area) {
if (runtime->dma_bytes >= size)
return 0; /* already large enough */
vfree(runtime->dma_area);
}
runtime->dma_area = __vmalloc(size, gfp_flags);
if (!runtime->dma_area)
return -ENOMEM;
runtime->dma_bytes = size;
return 1;
}
EXPORT_SYMBOL(_snd_pcm_lib_alloc_vmalloc_buffer);
/**
* snd_pcm_lib_free_vmalloc_buffer - free vmalloc buffer
* @substream: the substream with a buffer allocated by
* snd_pcm_lib_alloc_vmalloc_buffer()
*
* Return: Zero if successful, or a negative error code on failure.
*/
int snd_pcm_lib_free_vmalloc_buffer(struct snd_pcm_substream *substream)
{
struct snd_pcm_runtime *runtime;
if (PCM_RUNTIME_CHECK(substream))
return -EINVAL;
runtime = substream->runtime;
vfree(runtime->dma_area);
runtime->dma_area = NULL;
return 0;
}
EXPORT_SYMBOL(snd_pcm_lib_free_vmalloc_buffer);
/**
* snd_pcm_lib_get_vmalloc_page - map vmalloc buffer offset to page struct
* @substream: the substream with a buffer allocated by
* snd_pcm_lib_alloc_vmalloc_buffer()
* @offset: offset in the buffer
*
* This function is to be used as the page callback in the PCM ops.
*
* Return: The page struct, or %NULL on failure.
*/
struct page *snd_pcm_lib_get_vmalloc_page(struct snd_pcm_substream *substream,
unsigned long offset)
{
return vmalloc_to_page(substream->runtime->dma_area + offset);
}
EXPORT_SYMBOL(snd_pcm_lib_get_vmalloc_page);

View File

@ -494,18 +494,20 @@ EXPORT_SYMBOL(snd_pcm_format_set_silence);
int snd_pcm_hw_limit_rates(struct snd_pcm_hardware *hw) int snd_pcm_hw_limit_rates(struct snd_pcm_hardware *hw)
{ {
int i; int i;
unsigned int rmin, rmax;
rmin = UINT_MAX;
rmax = 0;
for (i = 0; i < (int)snd_pcm_known_rates.count; i++) { for (i = 0; i < (int)snd_pcm_known_rates.count; i++) {
if (hw->rates & (1 << i)) { if (hw->rates & (1 << i)) {
hw->rate_min = snd_pcm_known_rates.list[i]; rmin = min(rmin, snd_pcm_known_rates.list[i]);
break; rmax = max(rmax, snd_pcm_known_rates.list[i]);
}
}
for (i = (int)snd_pcm_known_rates.count - 1; i >= 0; i--) {
if (hw->rates & (1 << i)) {
hw->rate_max = snd_pcm_known_rates.list[i];
break;
} }
} }
if (rmin > rmax)
return -EINVAL;
hw->rate_min = rmin;
hw->rate_max = rmax;
return 0; return 0;
} }
EXPORT_SYMBOL(snd_pcm_hw_limit_rates); EXPORT_SYMBOL(snd_pcm_hw_limit_rates);

View File

@ -582,7 +582,7 @@ static int snd_pcm_hw_refine_user(struct snd_pcm_substream *substream,
params = memdup_user(_params, sizeof(*params)); params = memdup_user(_params, sizeof(*params));
if (IS_ERR(params)) if (IS_ERR(params))
return PTR_ERR(no_free_ptr(params)); return PTR_ERR(params);
err = snd_pcm_hw_refine(substream, params); err = snd_pcm_hw_refine(substream, params);
if (err < 0) if (err < 0)
@ -872,7 +872,7 @@ static int snd_pcm_hw_params_user(struct snd_pcm_substream *substream,
params = memdup_user(_params, sizeof(*params)); params = memdup_user(_params, sizeof(*params));
if (IS_ERR(params)) if (IS_ERR(params))
return PTR_ERR(no_free_ptr(params)); return PTR_ERR(params);
err = snd_pcm_hw_params(substream, params); err = snd_pcm_hw_params(substream, params);
if (err < 0) if (err < 0)
@ -2418,13 +2418,17 @@ static int snd_pcm_hw_rule_sample_bits(struct snd_pcm_hw_params *params,
return snd_interval_refine(hw_param_interval(params, rule->var), &t); return snd_interval_refine(hw_param_interval(params, rule->var), &t);
} }
#if SNDRV_PCM_RATE_5512 != 1 << 0 || SNDRV_PCM_RATE_192000 != 1 << 12 #if SNDRV_PCM_RATE_5512 != 1 << 0 || SNDRV_PCM_RATE_192000 != 1 << 12 ||\
SNDRV_PCM_RATE_128000 != 1 << 19
#error "Change this table" #error "Change this table"
#endif #endif
/* NOTE: the list is unsorted! */
static const unsigned int rates[] = { static const unsigned int rates[] = {
5512, 8000, 11025, 16000, 22050, 32000, 44100, 5512, 8000, 11025, 16000, 22050, 32000, 44100,
48000, 64000, 88200, 96000, 176400, 192000, 352800, 384000, 705600, 768000 48000, 64000, 88200, 96000, 176400, 192000, 352800, 384000, 705600, 768000,
/* extended */
12000, 24000, 128000
}; };
const struct snd_pcm_hw_constraint_list snd_pcm_known_rates = { const struct snd_pcm_hw_constraint_list snd_pcm_known_rates = {
@ -3243,7 +3247,7 @@ static int snd_pcm_xfern_frames_ioctl(struct snd_pcm_substream *substream,
bufs = memdup_user(xfern.bufs, sizeof(void *) * runtime->channels); bufs = memdup_user(xfern.bufs, sizeof(void *) * runtime->channels);
if (IS_ERR(bufs)) if (IS_ERR(bufs))
return PTR_ERR(no_free_ptr(bufs)); return PTR_ERR(bufs);
if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK) if (substream->stream == SNDRV_PCM_STREAM_PLAYBACK)
result = snd_pcm_lib_writev(substream, bufs, xfern.frames); result = snd_pcm_lib_writev(substream, bufs, xfern.frames);
else else
@ -4032,7 +4036,7 @@ static int snd_pcm_hw_refine_old_user(struct snd_pcm_substream *substream,
oparams = memdup_user(_oparams, sizeof(*oparams)); oparams = memdup_user(_oparams, sizeof(*oparams));
if (IS_ERR(oparams)) if (IS_ERR(oparams))
return PTR_ERR(no_free_ptr(oparams)); return PTR_ERR(oparams);
snd_pcm_hw_convert_from_old_params(params, oparams); snd_pcm_hw_convert_from_old_params(params, oparams);
err = snd_pcm_hw_refine(substream, params); err = snd_pcm_hw_refine(substream, params);
if (err < 0) if (err < 0)
@ -4061,7 +4065,7 @@ static int snd_pcm_hw_params_old_user(struct snd_pcm_substream *substream,
oparams = memdup_user(_oparams, sizeof(*oparams)); oparams = memdup_user(_oparams, sizeof(*oparams));
if (IS_ERR(oparams)) if (IS_ERR(oparams))
return PTR_ERR(no_free_ptr(oparams)); return PTR_ERR(oparams);
snd_pcm_hw_convert_from_old_params(params, oparams); snd_pcm_hw_convert_from_old_params(params, oparams);
err = snd_pcm_hw_params(substream, params); err = snd_pcm_hw_params(substream, params);

View File

@ -108,8 +108,7 @@ void snd_pcm_timer_init(struct snd_pcm_substream *substream)
if (snd_timer_new(substream->pcm->card, "PCM", &tid, &timer) < 0) if (snd_timer_new(substream->pcm->card, "PCM", &tid, &timer) < 0)
return; return;
sprintf(timer->name, "PCM %s %i-%i-%i", sprintf(timer->name, "PCM %s %i-%i-%i",
substream->stream == SNDRV_PCM_STREAM_CAPTURE ? snd_pcm_direction_name(substream->stream),
"capture" : "playback",
tid.card, tid.device, tid.subdevice); tid.card, tid.device, tid.subdevice);
timer->hw = snd_pcm_timer; timer->hw = snd_pcm_timer;
if (snd_device_register(timer->card, timer) < 0) { if (snd_device_register(timer->card, timer) < 0) {

View File

@ -116,10 +116,6 @@ __poll_t snd_seq_oss_poll(struct seq_oss_devinfo *dp, struct file *file, poll_ta
void snd_seq_oss_reset(struct seq_oss_devinfo *dp); void snd_seq_oss_reset(struct seq_oss_devinfo *dp);
/* */
void snd_seq_oss_process_queue(struct seq_oss_devinfo *dp, abstime_t time);
/* proc interface */ /* proc interface */
void snd_seq_oss_system_info_read(struct snd_info_buffer *buf); void snd_seq_oss_system_info_read(struct snd_info_buffer *buf);
void snd_seq_oss_midi_info_read(struct snd_info_buffer *buf); void snd_seq_oss_midi_info_read(struct snd_info_buffer *buf);

View File

@ -70,7 +70,7 @@ static int bounce_error_event(struct snd_seq_client *client,
int err, int atomic, int hop); int err, int atomic, int hop);
static int snd_seq_deliver_single_event(struct snd_seq_client *client, static int snd_seq_deliver_single_event(struct snd_seq_client *client,
struct snd_seq_event *event, struct snd_seq_event *event,
int filter, int atomic, int hop); int atomic, int hop);
#if IS_ENABLED(CONFIG_SND_SEQ_UMP) #if IS_ENABLED(CONFIG_SND_SEQ_UMP)
static void free_ump_info(struct snd_seq_client *client); static void free_ump_info(struct snd_seq_client *client);
@ -525,10 +525,8 @@ static int check_port_perm(struct snd_seq_client_port *port, unsigned int flags)
/* /*
* check if the destination client is available, and return the pointer * check if the destination client is available, and return the pointer
* if filter is non-zero, client filter bitmap is tested.
*/ */
static struct snd_seq_client *get_event_dest_client(struct snd_seq_event *event, static struct snd_seq_client *get_event_dest_client(struct snd_seq_event *event)
int filter)
{ {
struct snd_seq_client *dest; struct snd_seq_client *dest;
@ -543,8 +541,6 @@ static struct snd_seq_client *get_event_dest_client(struct snd_seq_event *event,
if ((dest->filter & SNDRV_SEQ_FILTER_USE_EVENT) && if ((dest->filter & SNDRV_SEQ_FILTER_USE_EVENT) &&
! test_bit(event->type, dest->event_filter)) ! test_bit(event->type, dest->event_filter))
goto __not_avail; goto __not_avail;
if (filter && !(dest->filter & filter))
goto __not_avail;
return dest; /* ok - accessible */ return dest; /* ok - accessible */
__not_avail: __not_avail:
@ -588,7 +584,7 @@ static int bounce_error_event(struct snd_seq_client *client,
bounce_ev.data.quote.origin = event->dest; bounce_ev.data.quote.origin = event->dest;
bounce_ev.data.quote.event = event; bounce_ev.data.quote.event = event;
bounce_ev.data.quote.value = -err; /* use positive value */ bounce_ev.data.quote.value = -err; /* use positive value */
result = snd_seq_deliver_single_event(NULL, &bounce_ev, 0, atomic, hop + 1); result = snd_seq_deliver_single_event(NULL, &bounce_ev, atomic, hop + 1);
if (result < 0) { if (result < 0) {
client->event_lost++; client->event_lost++;
return result; return result;
@ -655,7 +651,7 @@ int __snd_seq_deliver_single_event(struct snd_seq_client *dest,
*/ */
static int snd_seq_deliver_single_event(struct snd_seq_client *client, static int snd_seq_deliver_single_event(struct snd_seq_client *client,
struct snd_seq_event *event, struct snd_seq_event *event,
int filter, int atomic, int hop) int atomic, int hop)
{ {
struct snd_seq_client *dest = NULL; struct snd_seq_client *dest = NULL;
struct snd_seq_client_port *dest_port = NULL; struct snd_seq_client_port *dest_port = NULL;
@ -664,7 +660,7 @@ static int snd_seq_deliver_single_event(struct snd_seq_client *client,
direct = snd_seq_ev_is_direct(event); direct = snd_seq_ev_is_direct(event);
dest = get_event_dest_client(event, filter); dest = get_event_dest_client(event);
if (dest == NULL) if (dest == NULL)
goto __skip; goto __skip;
dest_port = snd_seq_port_use_ptr(dest, event->dest.port); dest_port = snd_seq_port_use_ptr(dest, event->dest.port);
@ -744,8 +740,7 @@ static int __deliver_to_subscribers(struct snd_seq_client *client,
/* convert time according to flag with subscription */ /* convert time according to flag with subscription */
update_timestamp_of_queue(event, subs->info.queue, update_timestamp_of_queue(event, subs->info.queue,
subs->info.flags & SNDRV_SEQ_PORT_SUBS_TIME_REAL); subs->info.flags & SNDRV_SEQ_PORT_SUBS_TIME_REAL);
err = snd_seq_deliver_single_event(client, event, err = snd_seq_deliver_single_event(client, event, atomic, hop);
0, atomic, hop);
if (err < 0) { if (err < 0) {
/* save first error that occurs and continue */ /* save first error that occurs and continue */
if (!result) if (!result)
@ -818,7 +813,7 @@ static int snd_seq_deliver_event(struct snd_seq_client *client, struct snd_seq_e
event->dest.client == SNDRV_SEQ_ADDRESS_SUBSCRIBERS) event->dest.client == SNDRV_SEQ_ADDRESS_SUBSCRIBERS)
result = deliver_to_subscribers(client, event, atomic, hop); result = deliver_to_subscribers(client, event, atomic, hop);
else else
result = snd_seq_deliver_single_event(client, event, 0, atomic, hop); result = snd_seq_deliver_single_event(client, event, atomic, hop);
return result; return result;
} }
@ -2636,13 +2631,18 @@ static void snd_seq_info_dump_ports(struct snd_info_buffer *buffer,
list_for_each_entry(p, &client->ports_list_head, list) { list_for_each_entry(p, &client->ports_list_head, list) {
if (p->capability & SNDRV_SEQ_PORT_CAP_INACTIVE) if (p->capability & SNDRV_SEQ_PORT_CAP_INACTIVE)
continue; continue;
snd_iprintf(buffer, " Port %3d : \"%s\" (%c%c%c%c) [%s]\n", snd_iprintf(buffer, " Port %3d : \"%s\" (%c%c%c%c) [%s]",
p->addr.port, p->name, p->addr.port, p->name,
FLAG_PERM_RD(p->capability), FLAG_PERM_RD(p->capability),
FLAG_PERM_WR(p->capability), FLAG_PERM_WR(p->capability),
FLAG_PERM_EX(p->capability), FLAG_PERM_EX(p->capability),
FLAG_PERM_DUPLEX(p->capability), FLAG_PERM_DUPLEX(p->capability),
port_direction_name(p->direction)); port_direction_name(p->direction));
#if IS_ENABLED(CONFIG_SND_SEQ_UMP)
if (snd_seq_client_is_midi2(client) && p->is_midi1)
snd_iprintf(buffer, " [MIDI1]");
#endif
snd_iprintf(buffer, "\n");
snd_seq_info_dump_subscribers(buffer, &p->c_src, 1, " Connecting To: "); snd_seq_info_dump_subscribers(buffer, &p->c_src, 1, " Connecting To: ");
snd_seq_info_dump_subscribers(buffer, &p->c_dest, 0, " Connected From: "); snd_seq_info_dump_subscribers(buffer, &p->c_dest, 0, " Connected From: ");
} }

View File

@ -362,6 +362,8 @@ int snd_seq_set_port_info(struct snd_seq_client_port * port,
port->direction |= SNDRV_SEQ_PORT_DIR_OUTPUT; port->direction |= SNDRV_SEQ_PORT_DIR_OUTPUT;
} }
port->is_midi1 = !!(info->flags & SNDRV_SEQ_PORT_FLG_IS_MIDI1);
return 0; return 0;
} }
@ -399,6 +401,9 @@ int snd_seq_get_port_info(struct snd_seq_client_port * port,
info->time_queue = port->time_queue; info->time_queue = port->time_queue;
} }
if (port->is_midi1)
info->flags |= SNDRV_SEQ_PORT_FLG_IS_MIDI1;
/* UMP direction and group */ /* UMP direction and group */
info->direction = port->direction; info->direction = port->direction;
info->ump_group = port->ump_group; info->ump_group = port->ump_group;

View File

@ -77,6 +77,8 @@ struct snd_seq_client_port {
unsigned char direction; unsigned char direction;
unsigned char ump_group; unsigned char ump_group;
bool is_midi1; /* keep MIDI 1.0 protocol */
#if IS_ENABLED(CONFIG_SND_SEQ_UMP) #if IS_ENABLED(CONFIG_SND_SEQ_UMP)
struct ump_cvt_to_ump_bank midi2_bank[16]; /* per channel */ struct ump_cvt_to_ump_bank midi2_bank[16]; /* per channel */
#endif #endif

View File

@ -84,7 +84,6 @@ void snd_seq_check_queue(struct snd_seq_queue *q, int atomic, int hop);
int snd_seq_queue_check_access(int queueid, int client); int snd_seq_queue_check_access(int queueid, int client);
int snd_seq_queue_timer_set_tempo(int queueid, int client, struct snd_seq_queue_tempo *info); int snd_seq_queue_timer_set_tempo(int queueid, int client, struct snd_seq_queue_tempo *info);
int snd_seq_queue_set_owner(int queueid, int client, int locked); int snd_seq_queue_set_owner(int queueid, int client, int locked);
int snd_seq_queue_set_locked(int queueid, int client, int locked);
int snd_seq_queue_timer_open(int queueid); int snd_seq_queue_timer_open(int queueid);
int snd_seq_queue_timer_close(int queueid); int snd_seq_queue_timer_close(int queueid);
int snd_seq_queue_use(int queueid, int client, int use); int snd_seq_queue_use(int queueid, int client, int use);

View File

@ -109,8 +109,6 @@ static inline void snd_seq_inc_time_nsec(snd_seq_real_time_t *tm, unsigned long
struct snd_seq_queue; struct snd_seq_queue;
int snd_seq_timer_open(struct snd_seq_queue *q); int snd_seq_timer_open(struct snd_seq_queue *q);
int snd_seq_timer_close(struct snd_seq_queue *q); int snd_seq_timer_close(struct snd_seq_queue *q);
int snd_seq_timer_midi_open(struct snd_seq_queue *q);
int snd_seq_timer_midi_close(struct snd_seq_queue *q);
void snd_seq_timer_defaults(struct snd_seq_timer *tmr); void snd_seq_timer_defaults(struct snd_seq_timer *tmr);
void snd_seq_timer_reset(struct snd_seq_timer *tmr); void snd_seq_timer_reset(struct snd_seq_timer *tmr);
int snd_seq_timer_stop(struct snd_seq_timer *tmr); int snd_seq_timer_stop(struct snd_seq_timer *tmr);

View File

@ -23,15 +23,6 @@ enum {
STR_OUT = SNDRV_RAWMIDI_STREAM_OUTPUT STR_OUT = SNDRV_RAWMIDI_STREAM_OUTPUT
}; };
/* object per UMP group; corresponding to a sequencer port */
struct seq_ump_group {
int group; /* group index (0-based) */
unsigned int dir_bits; /* directions */
bool active; /* activeness */
bool valid; /* valid group (referred by blocks) */
char name[64]; /* seq port name */
};
/* context for UMP input parsing, per EP */ /* context for UMP input parsing, per EP */
struct seq_ump_input_buffer { struct seq_ump_input_buffer {
unsigned char len; /* total length in words */ unsigned char len; /* total length in words */
@ -48,7 +39,6 @@ struct seq_ump_client {
int opened[2]; /* current opens for each direction */ int opened[2]; /* current opens for each direction */
struct snd_rawmidi_file out_rfile; /* rawmidi for output */ struct snd_rawmidi_file out_rfile; /* rawmidi for output */
struct seq_ump_input_buffer input; /* input parser context */ struct seq_ump_input_buffer input; /* input parser context */
struct seq_ump_group groups[SNDRV_UMP_MAX_GROUPS]; /* table of groups */
void *ump_info[SNDRV_UMP_MAX_BLOCKS + 1]; /* shadow of seq client ump_info */ void *ump_info[SNDRV_UMP_MAX_BLOCKS + 1]; /* shadow of seq client ump_info */
struct work_struct group_notify_work; /* FB change notification */ struct work_struct group_notify_work; /* FB change notification */
}; };
@ -175,7 +165,7 @@ static int seq_ump_unuse(void *pdata, struct snd_seq_port_subscribe *info)
/* fill port_info from the given UMP EP and group info */ /* fill port_info from the given UMP EP and group info */
static void fill_port_info(struct snd_seq_port_info *port, static void fill_port_info(struct snd_seq_port_info *port,
struct seq_ump_client *client, struct seq_ump_client *client,
struct seq_ump_group *group) struct snd_ump_group *group)
{ {
unsigned int rawmidi_info = client->ump->core.info_flags; unsigned int rawmidi_info = client->ump->core.info_flags;
@ -199,6 +189,8 @@ static void fill_port_info(struct snd_seq_port_info *port,
port->ump_group = group->group + 1; port->ump_group = group->group + 1;
if (!group->active) if (!group->active)
port->capability |= SNDRV_SEQ_PORT_CAP_INACTIVE; port->capability |= SNDRV_SEQ_PORT_CAP_INACTIVE;
if (group->is_midi1)
port->flags |= SNDRV_SEQ_PORT_FLG_IS_MIDI1;
port->type = SNDRV_SEQ_PORT_TYPE_MIDI_GENERIC | port->type = SNDRV_SEQ_PORT_TYPE_MIDI_GENERIC |
SNDRV_SEQ_PORT_TYPE_MIDI_UMP | SNDRV_SEQ_PORT_TYPE_MIDI_UMP |
SNDRV_SEQ_PORT_TYPE_HARDWARE | SNDRV_SEQ_PORT_TYPE_HARDWARE |
@ -212,7 +204,7 @@ static void fill_port_info(struct snd_seq_port_info *port,
} }
/* skip non-existing group for static blocks */ /* skip non-existing group for static blocks */
static bool skip_group(struct seq_ump_client *client, struct seq_ump_group *group) static bool skip_group(struct seq_ump_client *client, struct snd_ump_group *group)
{ {
return !group->valid && return !group->valid &&
(client->ump->info.flags & SNDRV_UMP_EP_INFO_STATIC_BLOCKS); (client->ump->info.flags & SNDRV_UMP_EP_INFO_STATIC_BLOCKS);
@ -221,7 +213,7 @@ static bool skip_group(struct seq_ump_client *client, struct seq_ump_group *grou
/* create a new sequencer port per UMP group */ /* create a new sequencer port per UMP group */
static int seq_ump_group_init(struct seq_ump_client *client, int group_index) static int seq_ump_group_init(struct seq_ump_client *client, int group_index)
{ {
struct seq_ump_group *group = &client->groups[group_index]; struct snd_ump_group *group = &client->ump->groups[group_index];
struct snd_seq_port_info *port __free(kfree) = NULL; struct snd_seq_port_info *port __free(kfree) = NULL;
struct snd_seq_port_callback pcallbacks; struct snd_seq_port_callback pcallbacks;
@ -233,7 +225,7 @@ static int seq_ump_group_init(struct seq_ump_client *client, int group_index)
return -ENOMEM; return -ENOMEM;
fill_port_info(port, client, group); fill_port_info(port, client, group);
port->flags = SNDRV_SEQ_PORT_FLG_GIVEN_PORT; port->flags |= SNDRV_SEQ_PORT_FLG_GIVEN_PORT;
memset(&pcallbacks, 0, sizeof(pcallbacks)); memset(&pcallbacks, 0, sizeof(pcallbacks));
pcallbacks.owner = THIS_MODULE; pcallbacks.owner = THIS_MODULE;
pcallbacks.private_data = client; pcallbacks.private_data = client;
@ -261,7 +253,7 @@ static void update_port_infos(struct seq_ump_client *client)
return; return;
for (i = 0; i < SNDRV_UMP_MAX_GROUPS; i++) { for (i = 0; i < SNDRV_UMP_MAX_GROUPS; i++) {
if (skip_group(client, &client->groups[i])) if (skip_group(client, &client->ump->groups[i]))
continue; continue;
old->addr.client = client->seq_client; old->addr.client = client->seq_client;
@ -271,7 +263,7 @@ static void update_port_infos(struct seq_ump_client *client)
old); old);
if (err < 0) if (err < 0)
return; return;
fill_port_info(new, client, &client->groups[i]); fill_port_info(new, client, &client->ump->groups[i]);
if (old->capability == new->capability && if (old->capability == new->capability &&
!strcmp(old->name, new->name)) !strcmp(old->name, new->name))
continue; continue;
@ -285,57 +277,6 @@ static void update_port_infos(struct seq_ump_client *client)
} }
} }
/* update dir_bits and active flag for all groups in the client */
static void update_group_attrs(struct seq_ump_client *client)
{
struct snd_ump_block *fb;
struct seq_ump_group *group;
int i;
for (i = 0; i < SNDRV_UMP_MAX_GROUPS; i++) {
group = &client->groups[i];
*group->name = 0;
group->dir_bits = 0;
group->active = 0;
group->group = i;
group->valid = false;
}
list_for_each_entry(fb, &client->ump->block_list, list) {
if (fb->info.first_group + fb->info.num_groups > SNDRV_UMP_MAX_GROUPS)
break;
group = &client->groups[fb->info.first_group];
for (i = 0; i < fb->info.num_groups; i++, group++) {
group->valid = true;
if (fb->info.active)
group->active = 1;
switch (fb->info.direction) {
case SNDRV_UMP_DIR_INPUT:
group->dir_bits |= (1 << STR_IN);
break;
case SNDRV_UMP_DIR_OUTPUT:
group->dir_bits |= (1 << STR_OUT);
break;
case SNDRV_UMP_DIR_BIDIRECTION:
group->dir_bits |= (1 << STR_OUT) | (1 << STR_IN);
break;
}
if (!*fb->info.name)
continue;
if (!*group->name) {
/* store the first matching name */
strscpy(group->name, fb->info.name,
sizeof(group->name));
} else {
/* when overlapping, concat names */
strlcat(group->name, ", ", sizeof(group->name));
strlcat(group->name, fb->info.name,
sizeof(group->name));
}
}
}
}
/* create a UMP Endpoint port */ /* create a UMP Endpoint port */
static int create_ump_endpoint_port(struct seq_ump_client *client) static int create_ump_endpoint_port(struct seq_ump_client *client)
{ {
@ -432,7 +373,7 @@ static void setup_client_group_filter(struct seq_ump_client *client)
return; return;
filter = ~(1U << 0); /* always allow groupless messages */ filter = ~(1U << 0); /* always allow groupless messages */
for (p = 0; p < SNDRV_UMP_MAX_GROUPS; p++) { for (p = 0; p < SNDRV_UMP_MAX_GROUPS; p++) {
if (client->groups[p].active) if (client->ump->groups[p].active)
filter &= ~(1U << (p + 1)); filter &= ~(1U << (p + 1));
} }
cptr->group_filter = filter; cptr->group_filter = filter;
@ -445,7 +386,6 @@ static void handle_group_notify(struct work_struct *work)
struct seq_ump_client *client = struct seq_ump_client *client =
container_of(work, struct seq_ump_client, group_notify_work); container_of(work, struct seq_ump_client, group_notify_work);
update_group_attrs(client);
update_port_infos(client); update_port_infos(client);
setup_client_group_filter(client); setup_client_group_filter(client);
} }
@ -508,7 +448,6 @@ static int snd_seq_ump_probe(struct device *_dev)
client->ump_info[fb->info.block_id + 1] = &fb->info; client->ump_info[fb->info.block_id + 1] = &fb->info;
setup_client_midi_version(client); setup_client_midi_version(client);
update_group_attrs(client);
for (p = 0; p < SNDRV_UMP_MAX_GROUPS; p++) { for (p = 0; p < SNDRV_UMP_MAX_GROUPS; p++) {
err = seq_ump_group_init(client, p); err = seq_ump_group_init(client, p);

View File

@ -595,12 +595,13 @@ int snd_seq_deliver_from_ump(struct snd_seq_client *source,
type = ump_message_type(ump_ev->ump[0]); type = ump_message_type(ump_ev->ump[0]);
if (snd_seq_client_is_ump(dest)) { if (snd_seq_client_is_ump(dest)) {
if (snd_seq_client_is_midi2(dest) && bool is_midi2 = snd_seq_client_is_midi2(dest) &&
type == UMP_MSG_TYPE_MIDI1_CHANNEL_VOICE) !dest_port->is_midi1;
if (is_midi2 && type == UMP_MSG_TYPE_MIDI1_CHANNEL_VOICE)
return cvt_ump_midi1_to_midi2(dest, dest_port, return cvt_ump_midi1_to_midi2(dest, dest_port,
event, atomic, hop); event, atomic, hop);
else if (!snd_seq_client_is_midi2(dest) && else if (!is_midi2 && type == UMP_MSG_TYPE_MIDI2_CHANNEL_VOICE)
type == UMP_MSG_TYPE_MIDI2_CHANNEL_VOICE)
return cvt_ump_midi2_to_midi1(dest, dest_port, return cvt_ump_midi2_to_midi1(dest, dest_port,
event, atomic, hop); event, atomic, hop);
/* non-EP port and different group is set? */ /* non-EP port and different group is set? */
@ -1279,7 +1280,7 @@ int snd_seq_deliver_to_ump(struct snd_seq_client *source,
return 0; /* group filtered - skip the event */ return 0; /* group filtered - skip the event */
if (event->type == SNDRV_SEQ_EVENT_SYSEX) if (event->type == SNDRV_SEQ_EVENT_SYSEX)
return cvt_sysex_to_ump(dest, dest_port, event, atomic, hop); return cvt_sysex_to_ump(dest, dest_port, event, atomic, hop);
else if (snd_seq_client_is_midi2(dest)) else if (snd_seq_client_is_midi2(dest) && !dest_port->is_midi1)
return cvt_to_ump_midi2(dest, dest_port, event, atomic, hop); return cvt_to_ump_midi2(dest, dest_port, event, atomic, hop);
else else
return cvt_to_ump_midi1(dest, dest_port, event, atomic, hop); return cvt_to_ump_midi1(dest, dest_port, event, atomic, hop);

View File

@ -13,6 +13,8 @@
#include <linux/module.h> #include <linux/module.h>
#include <linux/string.h> #include <linux/string.h>
#include <linux/sched/signal.h> #include <linux/sched/signal.h>
#include <linux/anon_inodes.h>
#include <linux/idr.h>
#include <sound/core.h> #include <sound/core.h>
#include <sound/timer.h> #include <sound/timer.h>
#include <sound/control.h> #include <sound/control.h>
@ -109,6 +111,16 @@ struct snd_timer_status64 {
unsigned char reserved[64]; /* reserved */ unsigned char reserved[64]; /* reserved */
}; };
#ifdef CONFIG_SND_UTIMER
#define SNDRV_UTIMERS_MAX_COUNT 128
/* Internal data structure for keeping the state of the userspace-driven timer */
struct snd_utimer {
char *name;
struct snd_timer *timer;
unsigned int id;
};
#endif
#define SNDRV_TIMER_IOCTL_STATUS64 _IOR('T', 0x14, struct snd_timer_status64) #define SNDRV_TIMER_IOCTL_STATUS64 _IOR('T', 0x14, struct snd_timer_status64)
/* list of timers */ /* list of timers */
@ -1162,7 +1174,7 @@ static int snd_timer_s_close(struct snd_timer *timer)
static const struct snd_timer_hardware snd_timer_system = static const struct snd_timer_hardware snd_timer_system =
{ {
.flags = SNDRV_TIMER_HW_FIRST | SNDRV_TIMER_HW_WORK, .flags = SNDRV_TIMER_HW_FIRST | SNDRV_TIMER_HW_WORK,
.resolution = 1000000000L / HZ, .resolution = NSEC_PER_SEC / HZ,
.ticks = 10000000L, .ticks = 10000000L,
.close = snd_timer_s_close, .close = snd_timer_s_close,
.start = snd_timer_s_start, .start = snd_timer_s_start,
@ -1603,7 +1615,7 @@ static int snd_timer_user_ginfo(struct file *file,
ginfo = memdup_user(_ginfo, sizeof(*ginfo)); ginfo = memdup_user(_ginfo, sizeof(*ginfo));
if (IS_ERR(ginfo)) if (IS_ERR(ginfo))
return PTR_ERR(no_free_ptr(ginfo)); return PTR_ERR(ginfo);
tid = ginfo->tid; tid = ginfo->tid;
memset(ginfo, 0, sizeof(*ginfo)); memset(ginfo, 0, sizeof(*ginfo));
@ -2009,6 +2021,217 @@ enum {
SNDRV_TIMER_IOCTL_PAUSE_OLD = _IO('T', 0x23), SNDRV_TIMER_IOCTL_PAUSE_OLD = _IO('T', 0x23),
}; };
#ifdef CONFIG_SND_UTIMER
/*
* Since userspace-driven timers are passed to userspace, we need to have an identifier
* which will allow us to use them (basically, the subdevice number of udriven timer).
*/
static DEFINE_IDA(snd_utimer_ids);
static void snd_utimer_put_id(struct snd_utimer *utimer)
{
int timer_id = utimer->id;
snd_BUG_ON(timer_id < 0 || timer_id >= SNDRV_UTIMERS_MAX_COUNT);
ida_free(&snd_utimer_ids, timer_id);
}
static int snd_utimer_take_id(void)
{
return ida_alloc_max(&snd_utimer_ids, SNDRV_UTIMERS_MAX_COUNT - 1, GFP_KERNEL);
}
static void snd_utimer_free(struct snd_utimer *utimer)
{
snd_timer_free(utimer->timer);
snd_utimer_put_id(utimer);
kfree(utimer->name);
kfree(utimer);
}
static int snd_utimer_release(struct inode *inode, struct file *file)
{
struct snd_utimer *utimer = (struct snd_utimer *)file->private_data;
snd_utimer_free(utimer);
return 0;
}
static int snd_utimer_trigger(struct file *file)
{
struct snd_utimer *utimer = (struct snd_utimer *)file->private_data;
snd_timer_interrupt(utimer->timer, utimer->timer->sticks);
return 0;
}
static long snd_utimer_ioctl(struct file *file, unsigned int ioctl, unsigned long arg)
{
switch (ioctl) {
case SNDRV_TIMER_IOCTL_TRIGGER:
return snd_utimer_trigger(file);
}
return -ENOTTY;
}
static const struct file_operations snd_utimer_fops = {
.llseek = noop_llseek,
.release = snd_utimer_release,
.unlocked_ioctl = snd_utimer_ioctl,
};
static int snd_utimer_start(struct snd_timer *t)
{
return 0;
}
static int snd_utimer_stop(struct snd_timer *t)
{
return 0;
}
static int snd_utimer_open(struct snd_timer *t)
{
return 0;
}
static int snd_utimer_close(struct snd_timer *t)
{
return 0;
}
static const struct snd_timer_hardware timer_hw = {
.flags = SNDRV_TIMER_HW_AUTO | SNDRV_TIMER_HW_WORK,
.open = snd_utimer_open,
.close = snd_utimer_close,
.start = snd_utimer_start,
.stop = snd_utimer_stop,
};
static int snd_utimer_create(struct snd_timer_uinfo *utimer_info,
struct snd_utimer **r_utimer)
{
struct snd_utimer *utimer;
struct snd_timer *timer;
struct snd_timer_id tid;
int utimer_id;
int err = 0;
if (!utimer_info || utimer_info->resolution == 0)
return -EINVAL;
utimer = kzalloc(sizeof(*utimer), GFP_KERNEL);
if (!utimer)
return -ENOMEM;
/* We hold the ioctl lock here so we won't get a race condition when allocating id */
utimer_id = snd_utimer_take_id();
if (utimer_id < 0) {
err = utimer_id;
goto err_take_id;
}
utimer->name = kasprintf(GFP_KERNEL, "snd-utimer%d", utimer_id);
if (!utimer->name) {
err = -ENOMEM;
goto err_get_name;
}
utimer->id = utimer_id;
tid.dev_sclass = SNDRV_TIMER_SCLASS_APPLICATION;
tid.dev_class = SNDRV_TIMER_CLASS_GLOBAL;
tid.card = -1;
tid.device = SNDRV_TIMER_GLOBAL_UDRIVEN;
tid.subdevice = utimer_id;
err = snd_timer_new(NULL, utimer->name, &tid, &timer);
if (err < 0) {
pr_err("Can't create userspace-driven timer\n");
goto err_timer_new;
}
timer->module = THIS_MODULE;
timer->hw = timer_hw;
timer->hw.resolution = utimer_info->resolution;
timer->hw.ticks = 1;
timer->max_instances = MAX_SLAVE_INSTANCES;
utimer->timer = timer;
err = snd_timer_global_register(timer);
if (err < 0) {
pr_err("Can't register a userspace-driven timer\n");
goto err_timer_reg;
}
*r_utimer = utimer;
return 0;
err_timer_reg:
snd_timer_free(timer);
err_timer_new:
kfree(utimer->name);
err_get_name:
snd_utimer_put_id(utimer);
err_take_id:
kfree(utimer);
return err;
}
static int snd_utimer_ioctl_create(struct file *file,
struct snd_timer_uinfo __user *_utimer_info)
{
struct snd_utimer *utimer;
struct snd_timer_uinfo *utimer_info __free(kfree) = NULL;
int err, timer_fd;
utimer_info = memdup_user(_utimer_info, sizeof(*utimer_info));
if (IS_ERR(utimer_info))
return PTR_ERR(utimer_info);
err = snd_utimer_create(utimer_info, &utimer);
if (err < 0)
return err;
utimer_info->id = utimer->id;
timer_fd = anon_inode_getfd(utimer->name, &snd_utimer_fops, utimer, O_RDWR | O_CLOEXEC);
if (timer_fd < 0) {
snd_utimer_free(utimer);
return timer_fd;
}
utimer_info->fd = timer_fd;
err = copy_to_user(_utimer_info, utimer_info, sizeof(*utimer_info));
if (err) {
/*
* "Leak" the fd, as there is nothing we can do about it.
* It might have been closed already since anon_inode_getfd
* makes it available for userspace.
*
* We have to rely on the process exit path to do any
* necessary cleanup (e.g. releasing the file).
*/
return -EFAULT;
}
return 0;
}
#else
static int snd_utimer_ioctl_create(struct file *file,
struct snd_timer_uinfo __user *_utimer_info)
{
return -ENOTTY;
}
#endif
static long __snd_timer_user_ioctl(struct file *file, unsigned int cmd, static long __snd_timer_user_ioctl(struct file *file, unsigned int cmd,
unsigned long arg, bool compat) unsigned long arg, bool compat)
{ {
@ -2053,6 +2276,8 @@ static long __snd_timer_user_ioctl(struct file *file, unsigned int cmd,
case SNDRV_TIMER_IOCTL_PAUSE: case SNDRV_TIMER_IOCTL_PAUSE:
case SNDRV_TIMER_IOCTL_PAUSE_OLD: case SNDRV_TIMER_IOCTL_PAUSE_OLD:
return snd_timer_user_pause(file); return snd_timer_user_pause(file);
case SNDRV_TIMER_IOCTL_CREATE:
return snd_utimer_ioctl_create(file, argp);
} }
return -ENOTTY; return -ENOTTY;
} }

View File

@ -489,11 +489,7 @@ static void snd_ump_proc_read(struct snd_info_entry *entry,
ump->info.manufacturer_id); ump->info.manufacturer_id);
snd_iprintf(buffer, "Family ID: 0x%04x\n", ump->info.family_id); snd_iprintf(buffer, "Family ID: 0x%04x\n", ump->info.family_id);
snd_iprintf(buffer, "Model ID: 0x%04x\n", ump->info.model_id); snd_iprintf(buffer, "Model ID: 0x%04x\n", ump->info.model_id);
snd_iprintf(buffer, "SW Revision: 0x%02x%02x%02x%02x\n", snd_iprintf(buffer, "SW Revision: 0x%4phN\n", ump->info.sw_revision);
ump->info.sw_revision[0],
ump->info.sw_revision[1],
ump->info.sw_revision[2],
ump->info.sw_revision[3]);
} }
snd_iprintf(buffer, "Static Blocks: %s\n", snd_iprintf(buffer, "Static Blocks: %s\n",
(ump->info.flags & SNDRV_UMP_EP_INFO_STATIC_BLOCKS) ? "Yes" : "No"); (ump->info.flags & SNDRV_UMP_EP_INFO_STATIC_BLOCKS) ? "Yes" : "No");
@ -524,6 +520,62 @@ static void snd_ump_proc_read(struct snd_info_entry *entry,
} }
} }
/* update dir_bits and active flag for all groups in the client */
void snd_ump_update_group_attrs(struct snd_ump_endpoint *ump)
{
struct snd_ump_block *fb;
struct snd_ump_group *group;
int i;
for (i = 0; i < SNDRV_UMP_MAX_GROUPS; i++) {
group = &ump->groups[i];
*group->name = 0;
group->dir_bits = 0;
group->active = 0;
group->group = i;
group->valid = false;
group->is_midi1 = false;
}
list_for_each_entry(fb, &ump->block_list, list) {
if (fb->info.first_group + fb->info.num_groups > SNDRV_UMP_MAX_GROUPS)
break;
group = &ump->groups[fb->info.first_group];
for (i = 0; i < fb->info.num_groups; i++, group++) {
group->valid = true;
if (fb->info.active)
group->active = 1;
if (fb->info.flags & SNDRV_UMP_BLOCK_IS_MIDI1)
group->is_midi1 = true;
switch (fb->info.direction) {
case SNDRV_UMP_DIR_INPUT:
group->dir_bits |= (1 << SNDRV_RAWMIDI_STREAM_INPUT);
break;
case SNDRV_UMP_DIR_OUTPUT:
group->dir_bits |= (1 << SNDRV_RAWMIDI_STREAM_OUTPUT);
break;
case SNDRV_UMP_DIR_BIDIRECTION:
group->dir_bits |= (1 << SNDRV_RAWMIDI_STREAM_INPUT) |
(1 << SNDRV_RAWMIDI_STREAM_OUTPUT);
break;
}
if (!*fb->info.name)
continue;
if (!*group->name) {
/* store the first matching name */
strscpy(group->name, fb->info.name,
sizeof(group->name));
} else {
/* when overlapping, concat names */
strlcat(group->name, ", ", sizeof(group->name));
strlcat(group->name, fb->info.name,
sizeof(group->name));
}
}
}
}
EXPORT_SYMBOL_GPL(snd_ump_update_group_attrs);
/* /*
* UMP endpoint and function block handling * UMP endpoint and function block handling
*/ */
@ -602,6 +654,17 @@ static int ump_append_string(struct snd_ump_endpoint *ump, char *dest,
format == UMP_STREAM_MSG_FORMAT_END); format == UMP_STREAM_MSG_FORMAT_END);
} }
/* Choose the default protocol */
static void choose_default_protocol(struct snd_ump_endpoint *ump)
{
if (ump->info.protocol & SNDRV_UMP_EP_INFO_PROTO_MIDI_MASK)
return;
if (ump->info.protocol_caps & SNDRV_UMP_EP_INFO_PROTO_MIDI2)
ump->info.protocol |= SNDRV_UMP_EP_INFO_PROTO_MIDI2;
else
ump->info.protocol |= SNDRV_UMP_EP_INFO_PROTO_MIDI1;
}
/* handle EP info stream message; update the UMP attributes */ /* handle EP info stream message; update the UMP attributes */
static int ump_handle_ep_info_msg(struct snd_ump_endpoint *ump, static int ump_handle_ep_info_msg(struct snd_ump_endpoint *ump,
const union snd_ump_stream_msg *buf) const union snd_ump_stream_msg *buf)
@ -623,6 +686,10 @@ static int ump_handle_ep_info_msg(struct snd_ump_endpoint *ump,
ump_dbg(ump, "EP info: version=%x, num_blocks=%x, proto_caps=%x\n", ump_dbg(ump, "EP info: version=%x, num_blocks=%x, proto_caps=%x\n",
ump->info.version, ump->info.num_blocks, ump->info.protocol_caps); ump->info.version, ump->info.num_blocks, ump->info.protocol_caps);
ump->info.protocol &= ump->info.protocol_caps;
choose_default_protocol(ump);
return 1; /* finished */ return 1; /* finished */
} }
@ -639,14 +706,11 @@ static int ump_handle_device_info_msg(struct snd_ump_endpoint *ump,
ump->info.sw_revision[1] = (buf->device_info.sw_revision >> 16) & 0x7f; ump->info.sw_revision[1] = (buf->device_info.sw_revision >> 16) & 0x7f;
ump->info.sw_revision[2] = (buf->device_info.sw_revision >> 8) & 0x7f; ump->info.sw_revision[2] = (buf->device_info.sw_revision >> 8) & 0x7f;
ump->info.sw_revision[3] = buf->device_info.sw_revision & 0x7f; ump->info.sw_revision[3] = buf->device_info.sw_revision & 0x7f;
ump_dbg(ump, "EP devinfo: manid=%08x, family=%04x, model=%04x, sw=%02x%02x%02x%02x\n", ump_dbg(ump, "EP devinfo: manid=%08x, family=%04x, model=%04x, sw=%4phN\n",
ump->info.manufacturer_id, ump->info.manufacturer_id,
ump->info.family_id, ump->info.family_id,
ump->info.model_id, ump->info.model_id,
ump->info.sw_revision[0], ump->info.sw_revision);
ump->info.sw_revision[1],
ump->info.sw_revision[2],
ump->info.sw_revision[3]);
return 1; /* finished */ return 1; /* finished */
} }
@ -792,8 +856,10 @@ static int ump_handle_fb_info_msg(struct snd_ump_endpoint *ump,
if (fb) { if (fb) {
fill_fb_info(ump, &fb->info, buf); fill_fb_info(ump, &fb->info, buf);
if (ump->parsed) if (ump->parsed) {
snd_ump_update_group_attrs(ump);
seq_notify_fb_change(ump, fb); seq_notify_fb_change(ump, fb);
}
} }
return 1; /* finished */ return 1; /* finished */
@ -822,8 +888,10 @@ static int ump_handle_fb_name_msg(struct snd_ump_endpoint *ump,
ret = ump_append_string(ump, fb->info.name, sizeof(fb->info.name), ret = ump_append_string(ump, fb->info.name, sizeof(fb->info.name),
buf->raw, 3); buf->raw, 3);
/* notify the FB name update to sequencer, too */ /* notify the FB name update to sequencer, too */
if (ret > 0 && ump->parsed) if (ret > 0 && ump->parsed) {
snd_ump_update_group_attrs(ump);
seq_notify_fb_change(ump, fb); seq_notify_fb_change(ump, fb);
}
return ret; return ret;
} }
@ -981,12 +1049,7 @@ int snd_ump_parse_endpoint(struct snd_ump_endpoint *ump)
ump_dbg(ump, "Unable to get UMP EP stream config\n"); ump_dbg(ump, "Unable to get UMP EP stream config\n");
/* If no protocol is set by some reason, assume the valid one */ /* If no protocol is set by some reason, assume the valid one */
if (!(ump->info.protocol & SNDRV_UMP_EP_INFO_PROTO_MIDI_MASK)) { choose_default_protocol(ump);
if (ump->info.protocol_caps & SNDRV_UMP_EP_INFO_PROTO_MIDI2)
ump->info.protocol |= SNDRV_UMP_EP_INFO_PROTO_MIDI2;
else if (ump->info.protocol_caps & SNDRV_UMP_EP_INFO_PROTO_MIDI1)
ump->info.protocol |= SNDRV_UMP_EP_INFO_PROTO_MIDI1;
}
/* Query and create blocks from Function Blocks */ /* Query and create blocks from Function Blocks */
for (blk = 0; blk < ump->info.num_blocks; blk++) { for (blk = 0; blk < ump->info.num_blocks; blk++) {
@ -995,6 +1058,9 @@ int snd_ump_parse_endpoint(struct snd_ump_endpoint *ump)
continue; continue;
} }
/* initialize group attributions */
snd_ump_update_group_attrs(ump);
error: error:
ump->parsed = true; ump->parsed = true;
ump_request_close(ump); ump_request_close(ump);
@ -1097,6 +1163,7 @@ static int process_legacy_output(struct snd_ump_endpoint *ump,
struct snd_rawmidi_substream *substream; struct snd_rawmidi_substream *substream;
struct ump_cvt_to_ump *ctx; struct ump_cvt_to_ump *ctx;
const int dir = SNDRV_RAWMIDI_STREAM_OUTPUT; const int dir = SNDRV_RAWMIDI_STREAM_OUTPUT;
unsigned int protocol;
unsigned char c; unsigned char c;
int group, size = 0; int group, size = 0;
@ -1109,9 +1176,13 @@ static int process_legacy_output(struct snd_ump_endpoint *ump,
if (!substream) if (!substream)
continue; continue;
ctx = &ump->out_cvts[group]; ctx = &ump->out_cvts[group];
protocol = ump->info.protocol;
if ((protocol & SNDRV_UMP_EP_INFO_PROTO_MIDI2) &&
ump->groups[group].is_midi1)
protocol = SNDRV_UMP_EP_INFO_PROTO_MIDI1;
while (!ctx->ump_bytes && while (!ctx->ump_bytes &&
snd_rawmidi_transmit(substream, &c, 1) > 0) snd_rawmidi_transmit(substream, &c, 1) > 0)
snd_ump_convert_to_ump(ctx, group, ump->info.protocol, c); snd_ump_convert_to_ump(ctx, group, protocol, c);
if (ctx->ump_bytes && ctx->ump_bytes <= count) { if (ctx->ump_bytes && ctx->ump_bytes <= count) {
size = ctx->ump_bytes; size = ctx->ump_bytes;
memcpy(buffer, ctx->ump, size); memcpy(buffer, ctx->ump, size);
@ -1172,10 +1243,17 @@ static void fill_substream_names(struct snd_ump_endpoint *ump,
struct snd_rawmidi *rmidi, int dir) struct snd_rawmidi *rmidi, int dir)
{ {
struct snd_rawmidi_substream *s; struct snd_rawmidi_substream *s;
const char *name;
int idx;
list_for_each_entry(s, &rmidi->streams[dir].substreams, list) list_for_each_entry(s, &rmidi->streams[dir].substreams, list) {
idx = ump->legacy_mapping[s->number];
name = ump->groups[idx].name;
if (!*name)
name = ump->info.name;
snprintf(s->name, sizeof(s->name), "Group %d (%.16s)", snprintf(s->name, sizeof(s->name), "Group %d (%.16s)",
ump->legacy_mapping[s->number] + 1, ump->info.name); idx + 1, name);
}
} }
int snd_ump_attach_legacy_rawmidi(struct snd_ump_endpoint *ump, int snd_ump_attach_legacy_rawmidi(struct snd_ump_endpoint *ump,

View File

@ -900,8 +900,7 @@ static void loopback_snd_timer_dpcm_info(struct loopback_pcm *dpcm,
cable->snd_timer.id.device, cable->snd_timer.id.device,
cable->snd_timer.id.subdevice); cable->snd_timer.id.subdevice);
snd_iprintf(buffer, " timer open:\t\t%s\n", snd_iprintf(buffer, " timer open:\t\t%s\n",
(cable->snd_timer.stream == SNDRV_PCM_STREAM_CAPTURE) ? snd_pcm_direction_name(cable->snd_timer.stream));
"capture" : "playback");
} }
static snd_pcm_uframes_t loopback_pointer(struct snd_pcm_substream *substream) static snd_pcm_uframes_t loopback_pointer(struct snd_pcm_substream *substream)
@ -1130,6 +1129,8 @@ static int loopback_parse_timer_id(const char *str,
} }
} }
} }
if (card_idx == -1)
tid->dev_class = SNDRV_TIMER_CLASS_GLOBAL;
if (!err && tid) { if (!err && tid) {
tid->card = card_idx; tid->card = card_idx;
tid->device = dev; tid->device = dev;
@ -1897,7 +1898,7 @@ static int __init alsa_card_loopback_init(void)
} }
if (!cards) { if (!cards) {
#ifdef MODULE #ifdef MODULE
printk(KERN_ERR "aloop: No loopback enabled\n"); pr_err("aloop: No loopback enabled\n");
#endif #endif
loopback_unregister_all(); loopback_unregister_all();
return -ENODEV; return -ENODEV;

View File

@ -1033,8 +1033,7 @@ static int snd_dummy_probe(struct platform_device *devptr)
dummy->card = card; dummy->card = card;
for (mdl = dummy_models; *mdl && model[dev]; mdl++) { for (mdl = dummy_models; *mdl && model[dev]; mdl++) {
if (strcmp(model[dev], (*mdl)->name) == 0) { if (strcmp(model[dev], (*mdl)->name) == 0) {
printk(KERN_INFO pr_info("snd-dummy: Using model '%s' for card %i\n",
"snd-dummy: Using model '%s' for card %i\n",
(*mdl)->name, card->number); (*mdl)->name, card->number);
m = dummy->model = *mdl; m = dummy->model = *mdl;
break; break;
@ -1168,7 +1167,7 @@ static int __init alsa_card_dummy_init(void)
} }
if (!cards) { if (!cards) {
#ifdef MODULE #ifdef MODULE
printk(KERN_ERR "Dummy soundcard not found or device busy\n"); pr_err("Dummy soundcard not found or device busy\n");
#endif #endif
snd_dummy_unregister_all(); snd_dummy_unregister_all();
return -ENODEV; return -ENODEV;

View File

@ -56,7 +56,7 @@ static int snd_mpu401_create(struct device *devptr, int dev,
int err; int err;
if (!uart_enter[dev]) if (!uart_enter[dev])
snd_printk(KERN_ERR "the uart_enter option is obsolete; remove it\n"); dev_err(devptr, "the uart_enter option is obsolete; remove it\n");
*rcard = NULL; *rcard = NULL;
err = snd_devm_card_new(devptr, index[dev], id[dev], THIS_MODULE, err = snd_devm_card_new(devptr, index[dev], id[dev], THIS_MODULE,
@ -75,7 +75,7 @@ static int snd_mpu401_create(struct device *devptr, int dev,
err = snd_mpu401_uart_new(card, 0, MPU401_HW_MPU401, port[dev], 0, err = snd_mpu401_uart_new(card, 0, MPU401_HW_MPU401, port[dev], 0,
irq[dev], NULL); irq[dev], NULL);
if (err < 0) { if (err < 0) {
printk(KERN_ERR "MPU401 not detected at 0x%lx\n", port[dev]); dev_err(devptr, "MPU401 not detected at 0x%lx\n", port[dev]);
return err; return err;
} }
@ -90,11 +90,11 @@ static int snd_mpu401_probe(struct platform_device *devptr)
struct snd_card *card; struct snd_card *card;
if (port[dev] == SNDRV_AUTO_PORT) { if (port[dev] == SNDRV_AUTO_PORT) {
snd_printk(KERN_ERR "specify port\n"); dev_err(&devptr->dev, "specify port\n");
return -EINVAL; return -EINVAL;
} }
if (irq[dev] == SNDRV_AUTO_IRQ) { if (irq[dev] == SNDRV_AUTO_IRQ) {
snd_printk(KERN_ERR "specify or disable IRQ\n"); dev_err(&devptr->dev, "specify or disable IRQ\n");
return -EINVAL; return -EINVAL;
} }
err = snd_mpu401_create(&devptr->dev, dev, &card); err = snd_mpu401_create(&devptr->dev, dev, &card);
@ -133,11 +133,11 @@ static int snd_mpu401_pnp(int dev, struct pnp_dev *device,
{ {
if (!pnp_port_valid(device, 0) || if (!pnp_port_valid(device, 0) ||
pnp_port_flags(device, 0) & IORESOURCE_DISABLED) { pnp_port_flags(device, 0) & IORESOURCE_DISABLED) {
snd_printk(KERN_ERR "no PnP port\n"); dev_err(&device->dev, "no PnP port\n");
return -ENODEV; return -ENODEV;
} }
if (pnp_port_len(device, 0) < IO_EXTENT) { if (pnp_port_len(device, 0) < IO_EXTENT) {
snd_printk(KERN_ERR "PnP port length is %llu, expected %d\n", dev_err(&device->dev, "PnP port length is %llu, expected %d\n",
(unsigned long long)pnp_port_len(device, 0), (unsigned long long)pnp_port_len(device, 0),
IO_EXTENT); IO_EXTENT);
return -ENODEV; return -ENODEV;
@ -146,7 +146,7 @@ static int snd_mpu401_pnp(int dev, struct pnp_dev *device,
if (!pnp_irq_valid(device, 0) || if (!pnp_irq_valid(device, 0) ||
pnp_irq_flags(device, 0) & IORESOURCE_DISABLED) { pnp_irq_flags(device, 0) & IORESOURCE_DISABLED) {
snd_printk(KERN_WARNING "no PnP irq, using polling\n"); dev_warn(&device->dev, "no PnP irq, using polling\n");
irq[dev] = -1; irq[dev] = -1;
} else { } else {
irq[dev] = pnp_irq(device, 0); irq[dev] = pnp_irq(device, 0);
@ -234,7 +234,7 @@ static int __init alsa_card_mpu401_init(void)
if (!snd_mpu401_devices) { if (!snd_mpu401_devices) {
#ifdef MODULE #ifdef MODULE
printk(KERN_ERR "MPU-401 device not found or device busy\n"); pr_err("MPU-401 device not found or device busy\n");
#endif #endif
snd_mpu401_unregister_all(); snd_mpu401_unregister_all();
return -ENODEV; return -ENODEV;

View File

@ -73,8 +73,9 @@ static void snd_mpu401_uart_clear_rx(struct snd_mpu401 *mpu)
mpu->read(mpu, MPU401D(mpu)); mpu->read(mpu, MPU401D(mpu));
#ifdef CONFIG_SND_DEBUG #ifdef CONFIG_SND_DEBUG
if (timeout <= 0) if (timeout <= 0)
snd_printk(KERN_ERR "cmd: clear rx timeout (status = 0x%x)\n", dev_err(mpu->rmidi->dev,
mpu->read(mpu, MPU401C(mpu))); "cmd: clear rx timeout (status = 0x%x)\n",
mpu->read(mpu, MPU401C(mpu)));
#endif #endif
} }
@ -224,8 +225,9 @@ static int snd_mpu401_uart_cmd(struct snd_mpu401 * mpu, unsigned char cmd,
udelay(10); udelay(10);
#ifdef CONFIG_SND_DEBUG #ifdef CONFIG_SND_DEBUG
if (!timeout) if (!timeout)
snd_printk(KERN_ERR "cmd: tx timeout (status = 0x%x)\n", dev_err(mpu->rmidi->dev,
mpu->read(mpu, MPU401C(mpu))); "cmd: tx timeout (status = 0x%x)\n",
mpu->read(mpu, MPU401C(mpu)));
#endif #endif
} }
mpu->write(mpu, cmd, MPU401C(mpu)); mpu->write(mpu, cmd, MPU401C(mpu));
@ -244,10 +246,11 @@ static int snd_mpu401_uart_cmd(struct snd_mpu401 * mpu, unsigned char cmd,
ok = 1; ok = 1;
spin_unlock_irqrestore(&mpu->input_lock, flags); spin_unlock_irqrestore(&mpu->input_lock, flags);
if (!ok) { if (!ok) {
snd_printk(KERN_ERR "cmd: 0x%x failed at 0x%lx " dev_err(mpu->rmidi->dev,
"(status = 0x%x, data = 0x%x)\n", cmd, mpu->port, "cmd: 0x%x failed at 0x%lx (status = 0x%x, data = 0x%x)\n",
mpu->read(mpu, MPU401C(mpu)), cmd, mpu->port,
mpu->read(mpu, MPU401D(mpu))); mpu->read(mpu, MPU401C(mpu)),
mpu->read(mpu, MPU401D(mpu)));
return 1; return 1;
} }
return 0; return 0;
@ -546,13 +549,14 @@ int snd_mpu401_uart_new(struct snd_card *card, int device,
spin_lock_init(&mpu->timer_lock); spin_lock_init(&mpu->timer_lock);
mpu->hardware = hardware; mpu->hardware = hardware;
mpu->irq = -1; mpu->irq = -1;
mpu->rmidi = rmidi;
if (! (info_flags & MPU401_INFO_INTEGRATED)) { if (! (info_flags & MPU401_INFO_INTEGRATED)) {
int res_size = hardware == MPU401_HW_PC98II ? 4 : 2; int res_size = hardware == MPU401_HW_PC98II ? 4 : 2;
mpu->res = request_region(port, res_size, "MPU401 UART"); mpu->res = request_region(port, res_size, "MPU401 UART");
if (!mpu->res) { if (!mpu->res) {
snd_printk(KERN_ERR "mpu401_uart: " dev_err(rmidi->dev,
"unable to grab port 0x%lx size %d\n", "mpu401_uart: unable to grab port 0x%lx size %d\n",
port, res_size); port, res_size);
err = -EBUSY; err = -EBUSY;
goto free_device; goto free_device;
} }
@ -572,8 +576,8 @@ int snd_mpu401_uart_new(struct snd_card *card, int device,
if (irq >= 0) { if (irq >= 0) {
if (request_irq(irq, snd_mpu401_uart_interrupt, 0, if (request_irq(irq, snd_mpu401_uart_interrupt, 0,
"MPU401 UART", (void *) mpu)) { "MPU401 UART", (void *) mpu)) {
snd_printk(KERN_ERR "mpu401_uart: " dev_err(rmidi->dev,
"unable to grab IRQ %d\n", irq); "mpu401_uart: unable to grab IRQ %d\n", irq);
err = -EBUSY; err = -EBUSY;
goto free_device; goto free_device;
} }
@ -599,7 +603,6 @@ int snd_mpu401_uart_new(struct snd_card *card, int device,
if (out_enable) if (out_enable)
rmidi->info_flags |= SNDRV_RAWMIDI_INFO_DUPLEX; rmidi->info_flags |= SNDRV_RAWMIDI_INFO_DUPLEX;
} }
mpu->rmidi = rmidi;
if (rrawmidi) if (rrawmidi)
*rrawmidi = rmidi; *rrawmidi = rmidi;
return 0; return 0;

View File

@ -285,10 +285,6 @@ static void snd_mtpav_output_port_write(struct mtpav *mtp_card,
snd_mtpav_send_byte(mtp_card, 0xf5); snd_mtpav_send_byte(mtp_card, 0xf5);
snd_mtpav_send_byte(mtp_card, portp->hwport); snd_mtpav_send_byte(mtp_card, portp->hwport);
/*
snd_printk(KERN_DEBUG "new outport: 0x%x\n",
(unsigned int) portp->hwport);
*/
if (!(outbyte & 0x80) && portp->running_status) if (!(outbyte & 0x80) && portp->running_status)
snd_mtpav_send_byte(mtp_card, portp->running_status); snd_mtpav_send_byte(mtp_card, portp->running_status);
} }
@ -522,8 +518,6 @@ static void snd_mtpav_read_bytes(struct mtpav *mcrd)
u8 sbyt = snd_mtpav_getreg(mcrd, SREG); u8 sbyt = snd_mtpav_getreg(mcrd, SREG);
/* printk(KERN_DEBUG "snd_mtpav_read_bytes() sbyt: 0x%x\n", sbyt); */
if (!(sbyt & SIGS_BYTE)) if (!(sbyt & SIGS_BYTE))
return; return;
@ -569,13 +563,13 @@ static int snd_mtpav_get_ISA(struct mtpav *mcard)
mcard->res_port = devm_request_region(mcard->card->dev, port, 3, mcard->res_port = devm_request_region(mcard->card->dev, port, 3,
"MotuMTPAV MIDI"); "MotuMTPAV MIDI");
if (!mcard->res_port) { if (!mcard->res_port) {
snd_printk(KERN_ERR "MTVAP port 0x%lx is busy\n", port); dev_err(mcard->card->dev, "MTVAP port 0x%lx is busy\n", port);
return -EBUSY; return -EBUSY;
} }
mcard->port = port; mcard->port = port;
if (devm_request_irq(mcard->card->dev, irq, snd_mtpav_irqh, 0, if (devm_request_irq(mcard->card->dev, irq, snd_mtpav_irqh, 0,
"MOTU MTPAV", mcard)) { "MOTU MTPAV", mcard)) {
snd_printk(KERN_ERR "MTVAP IRQ %d busy\n", irq); dev_err(mcard->card->dev, "MTVAP IRQ %d busy\n", irq);
return -EBUSY; return -EBUSY;
} }
mcard->irq = irq; mcard->irq = irq;
@ -717,7 +711,9 @@ static int snd_mtpav_probe(struct platform_device *dev)
card->private_free = snd_mtpav_free; card->private_free = snd_mtpav_free;
platform_set_drvdata(dev, card); platform_set_drvdata(dev, card);
printk(KERN_INFO "Motu MidiTimePiece on parallel port irq: %d ioport: 0x%lx\n", irq, port); dev_info(card->dev,
"Motu MidiTimePiece on parallel port irq: %d ioport: 0x%lx\n",
irq, port);
return 0; return 0;
} }

View File

@ -652,8 +652,8 @@ static int snd_mts64_ctl_create(struct snd_card *card,
for (i = 0; control[i]; ++i) { for (i = 0; control[i]; ++i) {
err = snd_ctl_add(card, snd_ctl_new1(control[i], mts)); err = snd_ctl_add(card, snd_ctl_new1(control[i], mts));
if (err < 0) { if (err < 0) {
snd_printd("Cannot create control: %s\n", dev_dbg(card->dev, "Cannot create control: %s\n",
control[i]->name); control[i]->name);
return err; return err;
} }
} }
@ -926,7 +926,7 @@ static int snd_mts64_probe(struct platform_device *pdev)
err = snd_card_new(&pdev->dev, index[dev], id[dev], THIS_MODULE, err = snd_card_new(&pdev->dev, index[dev], id[dev], THIS_MODULE,
0, &card); 0, &card);
if (err < 0) { if (err < 0) {
snd_printd("Cannot create card\n"); dev_dbg(&pdev->dev, "Cannot create card\n");
return err; return err;
} }
strcpy(card->driver, DRIVER_NAME); strcpy(card->driver, DRIVER_NAME);
@ -940,21 +940,21 @@ static int snd_mts64_probe(struct platform_device *pdev)
&mts64_cb, /* callbacks */ &mts64_cb, /* callbacks */
pdev->id); /* device number */ pdev->id); /* device number */
if (!pardev) { if (!pardev) {
snd_printd("Cannot register pardevice\n"); dev_dbg(card->dev, "Cannot register pardevice\n");
err = -EIO; err = -EIO;
goto __err; goto __err;
} }
/* claim parport */ /* claim parport */
if (parport_claim(pardev)) { if (parport_claim(pardev)) {
snd_printd("Cannot claim parport 0x%lx\n", pardev->port->base); dev_dbg(card->dev, "Cannot claim parport 0x%lx\n", pardev->port->base);
err = -EIO; err = -EIO;
goto free_pardev; goto free_pardev;
} }
err = snd_mts64_create(card, pardev, &mts); err = snd_mts64_create(card, pardev, &mts);
if (err < 0) { if (err < 0) {
snd_printd("Cannot create main component\n"); dev_dbg(card->dev, "Cannot create main component\n");
goto release_pardev; goto release_pardev;
} }
card->private_data = mts; card->private_data = mts;
@ -968,7 +968,7 @@ static int snd_mts64_probe(struct platform_device *pdev)
err = snd_mts64_rawmidi_create(card); err = snd_mts64_rawmidi_create(card);
if (err < 0) { if (err < 0) {
snd_printd("Creating Rawmidi component failed\n"); dev_dbg(card->dev, "Creating Rawmidi component failed\n");
goto __err; goto __err;
} }
@ -982,11 +982,11 @@ static int snd_mts64_probe(struct platform_device *pdev)
/* At this point card will be usable */ /* At this point card will be usable */
err = snd_card_register(card); err = snd_card_register(card);
if (err < 0) { if (err < 0) {
snd_printd("Cannot register card\n"); dev_dbg(card->dev, "Cannot register card\n");
goto __err; goto __err;
} }
snd_printk(KERN_INFO "ESI Miditerminal 4140 on 0x%lx\n", p->base); dev_info(card->dev, "ESI Miditerminal 4140 on 0x%lx\n", p->base);
return 0; return 0;
release_pardev: release_pardev:

View File

@ -92,7 +92,7 @@ static int snd_opl3_detect(struct snd_opl3 * opl3)
opl3->command(opl3, OPL3_LEFT | OPL3_REG_TIMER_CONTROL, OPL3_IRQ_RESET); opl3->command(opl3, OPL3_LEFT | OPL3_REG_TIMER_CONTROL, OPL3_IRQ_RESET);
signature = stat1 = inb(opl3->l_port); /* Status register */ signature = stat1 = inb(opl3->l_port); /* Status register */
if ((stat1 & 0xe0) != 0x00) { /* Should be 0x00 */ if ((stat1 & 0xe0) != 0x00) { /* Should be 0x00 */
snd_printd("OPL3: stat1 = 0x%x\n", stat1); dev_dbg(opl3->card->dev, "OPL3: stat1 = 0x%x\n", stat1);
return -ENODEV; return -ENODEV;
} }
/* Set timer1 to 0xff */ /* Set timer1 to 0xff */
@ -108,7 +108,7 @@ static int snd_opl3_detect(struct snd_opl3 * opl3)
/* Reset the IRQ of the FM chip */ /* Reset the IRQ of the FM chip */
opl3->command(opl3, OPL3_LEFT | OPL3_REG_TIMER_CONTROL, OPL3_IRQ_RESET); opl3->command(opl3, OPL3_LEFT | OPL3_REG_TIMER_CONTROL, OPL3_IRQ_RESET);
if ((stat2 & 0xe0) != 0xc0) { /* There is no YM3812 */ if ((stat2 & 0xe0) != 0xc0) { /* There is no YM3812 */
snd_printd("OPL3: stat2 = 0x%x\n", stat2); dev_dbg(opl3->card->dev, "OPL3: stat2 = 0x%x\n", stat2);
return -ENODEV; return -ENODEV;
} }
@ -289,9 +289,6 @@ void snd_opl3_interrupt(struct snd_hwdep * hw)
opl3 = hw->private_data; opl3 = hw->private_data;
status = inb(opl3->l_port); status = inb(opl3->l_port);
#if 0
snd_printk(KERN_DEBUG "AdLib IRQ status = 0x%x\n", status);
#endif
if (!(status & 0x80)) if (!(status & 0x80))
return; return;
@ -365,7 +362,8 @@ EXPORT_SYMBOL(snd_opl3_new);
int snd_opl3_init(struct snd_opl3 *opl3) int snd_opl3_init(struct snd_opl3 *opl3)
{ {
if (! opl3->command) { if (! opl3->command) {
printk(KERN_ERR "snd_opl3_init: command not defined!\n"); dev_err(opl3->card->dev,
"snd_opl3_init: command not defined!\n");
return -EINVAL; return -EINVAL;
} }
@ -405,14 +403,14 @@ int snd_opl3_create(struct snd_card *card,
if (! integrated) { if (! integrated) {
opl3->res_l_port = request_region(l_port, 2, "OPL2/3 (left)"); opl3->res_l_port = request_region(l_port, 2, "OPL2/3 (left)");
if (!opl3->res_l_port) { if (!opl3->res_l_port) {
snd_printk(KERN_ERR "opl3: can't grab left port 0x%lx\n", l_port); dev_err(card->dev, "opl3: can't grab left port 0x%lx\n", l_port);
snd_device_free(card, opl3); snd_device_free(card, opl3);
return -EBUSY; return -EBUSY;
} }
if (r_port != 0) { if (r_port != 0) {
opl3->res_r_port = request_region(r_port, 2, "OPL2/3 (right)"); opl3->res_r_port = request_region(r_port, 2, "OPL2/3 (right)");
if (!opl3->res_r_port) { if (!opl3->res_r_port) {
snd_printk(KERN_ERR "opl3: can't grab right port 0x%lx\n", r_port); dev_err(card->dev, "opl3: can't grab right port 0x%lx\n", r_port);
snd_device_free(card, opl3); snd_device_free(card, opl3);
return -EBUSY; return -EBUSY;
} }
@ -432,8 +430,8 @@ int snd_opl3_create(struct snd_card *card,
opl3->command = &snd_opl2_command; opl3->command = &snd_opl2_command;
err = snd_opl3_detect(opl3); err = snd_opl3_detect(opl3);
if (err < 0) { if (err < 0) {
snd_printd("OPL2/3 chip not detected at 0x%lx/0x%lx\n", dev_dbg(card->dev, "OPL2/3 chip not detected at 0x%lx/0x%lx\n",
opl3->l_port, opl3->r_port); opl3->l_port, opl3->r_port);
snd_device_free(card, opl3); snd_device_free(card, opl3);
return err; return err;
} }

Some files were not shown because too many files have changed in this diff Show More