sound updates for 5.14

As the diffstat scatters over the tree, we've got many tree-wide
 small changes, but also got quite a few intrusive changes in the
 core side.  The only ABI-visible core change is the new rawmidi
 framing mode support while others are kernel-internal, mostly code
 refactoring and/or nice improvements.
 
 Here are some highlights:
 
 Core:
 - A new framing access mode for rawmidi to get timestamps
 - Cleanup / refactoring of buffer memory management helper code
 - Support for automatic negotiation of ASoC DAI formats
 - Revival of software suspend for PCM and control core, as a
   preliminary work for PCI BAR rescan support
 
 ASoC:
 - Accessory detection support for several Qualcomm parts
 - Support for IEC958 control with hdmi-codec
 - Merging of Tegra machine drivers into a single driver
 - Support for AmLogic SM1 TOACODEC, Intel AlderLake-M, several NXP
   i.MX8 variants, NXP TFA1 and TDF9897, Rockchip RK817, Qualcomm
   Quinary MI2S, Texas Instruments TAS2505
 
 USB-audio:
 - Reduction of latency at playback start
 - Code cleanup / fixes of usx2y driver
 - Scarlett2 mixer code fixes and enhancements
 - Quirks for Ozone and Denon devices
 
 HD-audio:
 - A few quirks for HP and ASUS machines
 - Display power management fixes
 
 Others:
 - FireWire code refactoring and enhancements
 - Tree-wide trivial coding-style fixes
 -----BEGIN PGP SIGNATURE-----
 
 iQJCBAABCAAsFiEEIXTw5fNLNI7mMiVaLtJE4w1nLE8FAmDezZ8OHHRpd2FpQHN1
 c2UuZGUACgkQLtJE4w1nLE8kxhAAhWyQBU9HX7xo/132J0SsP0tqT0NhePr217T7
 RSmRre3kD8iNDtpe9P9eziyN5q5TB8+InY52yUiDiWdSxCHOBDKBPwzzDeVRdOGg
 /BdQqCtEAtdgzsnPEsXxvK+y3LayLwlkCyN1kMLCl4KGFfMg8fQgMbXobEOfyKwT
 r23Xgbkb8jIFyjEAmvJnbvPXjkUjv2ew0+RB+cqV80m9h+KdNN/k/8+0wdWaQBEd
 6oRSE8ApYclgyLf4TYCkLAwTP3NQ8SuvYSuZ9tFGy7vjz7l69xPWS/6ndbfrJvEP
 pO615dYWKTWQKi2SjStnjFUH7ODirbPZzyDqU9tvEAGbKj0l07LNXy0JrbwJ8VB2
 JBfsdTlmSwHcAXmj0JB7IhflmG96W9azUKf1a8YNJLw7UgHoXjDZC0NFtOanaB7x
 PEdf+27Ty1pZaNbtJpwdzEyc06UNA8dNRAr6FsSMphRTnBBzcUz2uEAfWbevS7Yl
 Q5IOZd2lqKIUHPB6j2r0iDiCKScXzlHVhFzOLj3vHS4L8vjfbVshxkIkSY0HeA9r
 HINbkby2mpk901oyqaFwTLkoatXBk5zDX2m2ow7rQLLUIdF0hWBXrE5Xrl3c/T/x
 aFXuDxJfZm4YibJiBAOO5xv03DzVBNJz01E020oyum2m0NHhB1xD3RK428pcjshV
 zgXJaZg=
 =IN9G
 -----END PGP SIGNATURE-----

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

Pull sound updates from Takashi Iwai:
 "As the diffstat scatters over the tree, we've got many tree-wide small
  changes, but also got quite a few intrusive changes in the core side.
  The only ABI-visible core change is the new rawmidi framing mode
  support while others are kernel-internal, mostly code refactoring
  and/or nice improvements.

  Here are some highlights:

  Core:
   - A new framing access mode for rawmidi to get timestamps
   - Cleanup / refactoring of buffer memory management helper code
   - Support for automatic negotiation of ASoC DAI formats
   - Revival of software suspend for PCM and control core, as a
     preliminary work for PCI BAR rescan support

  ASoC:
   - Accessory detection support for several Qualcomm parts
   - Support for IEC958 control with hdmi-codec
   - Merging of Tegra machine drivers into a single driver
   - Support for AmLogic SM1 TOACODEC, Intel AlderLake-M, several NXP
     i.MX8 variants, NXP TFA1 and TDF9897, Rockchip RK817, Qualcomm
     Quinary MI2S, Texas Instruments TAS2505

  USB-audio:
   - Reduction of latency at playback start
   - Code cleanup / fixes of usx2y driver
   - Scarlett2 mixer code fixes and enhancements
   - Quirks for Ozone and Denon devices

  HD-audio:
   - A few quirks for HP and ASUS machines
   - Display power management fixes

  Others:
   - FireWire code refactoring and enhancements
   - Tree-wide trivial coding-style fixes"

* tag 'sound-5.14-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound: (594 commits)
  ALSA: usb-audio: scarlett2: Fix for loop increment in scarlett2_usb_get_config
  ALSA: hda/realtek: fix mute/micmute LEDs for HP ProBook 630 G8
  ALSA: hda/realtek: fix mute/micmute LEDs for HP ProBook 445 G8
  ALSA: hda/realtek: fix mute/micmute LEDs for HP ProBook 450 G8
  ALSA: hda/realtek - Add ALC285 HP init procedure
  ALSA: hda/realtek - Add type for ALC287
  ALSA: scarlett2: Fix scarlett2_*_ctl_put() return values again
  ALSA: scarlett2: Fix pad count for 18i8 Gen 3
  ALSA: hda/realtek: fix mute/micmute LEDs for HP EliteBook 830 G8 Notebook PC
  ALSA: firewire-lib: Fix 'amdtp_domain_start()' when no AMDTP_OUT_STREAM stream is found
  ASoC: qcom: lpass-cpu: mark IRQ_CLEAR register as volatile and readable
  ALSA: hda: Release codec display power during shutdown/reboot
  ALSA: hda: Release controller display power during shutdown/reboot
  ALSA: hda/realtek: Apply LED fixup for HP Dragonfly G1, too
  ASoC: fsl: remove unnecessary oom message
  ASoC: tlv320aic32x4: dt-bindings: add TAS2505 to compatible
  ASoC: tlv320aic32x4: add support for TAS2505
  ASoC: tlv320aic32x4: add type to device private data struct
  ASoC: tegra30: ahub: Use devm_platform_get_and_ioremap_resource()
  ASoC: tegra: tegra210_admaif: Use devm_platform_get_and_ioremap_resource()
  ...
This commit is contained in:
Linus Torvalds 2021-07-02 15:25:23 -07:00
commit d6b63b5b7d
559 changed files with 27020 additions and 10754 deletions

View File

@ -23,6 +23,7 @@ Optional properties:
default output clock name
- rockchip,system-power-controller: Telling whether or not this pmic is controlling
the system power.
- wakeup-source: Device can be used as a wakeup source.
Optional RK805 properties:
- vcc1-supply: The input supply for DCDC_REG1
@ -63,8 +64,18 @@ Optional RK809 properties:
- vcc9-supply: The input supply for DCDC_REG5, SWITCH_REG2
Optional RK817 properties:
- clocks: The input clock for the audio codec
- clock-names: The clock name for the codec clock. Should be "mclk".
- #sound-dai-cells: Needed for the interpretation of sound dais. Should be 0.
- vcc8-supply: The input supply for BOOST
- vcc9-supply: The input supply for OTG_SWITCH
- codec: The child node for the codec to hold additional properties.
If no additional properties are required for the codec, this
node can be omitted.
- rockchip,mic-in-differential: Telling if the microphone uses differential
mode. Should be under the codec child node.
Optional RK818 properties:
- vcc1-supply: The input supply for DCDC_REG1
@ -275,3 +286,180 @@ Example:
};
};
};
rk817: pmic@20 {
compatible = "rockchip,rk817";
reg = <0x20>;
interrupt-parent = <&gpio0>;
interrupts = <RK_PB2 IRQ_TYPE_LEVEL_LOW>;
clock-output-names = "rk808-clkout1", "xin32k";
clock-names = "mclk";
clocks = <&cru SCLK_I2S1_OUT>;
pinctrl-names = "default";
pinctrl-0 = <&pmic_int>, <&i2s1_2ch_mclk>;
wakeup-source;
#clock-cells = <1>;
#sound-dai-cells = <0>;
vcc1-supply = <&vccsys>;
vcc2-supply = <&vccsys>;
vcc3-supply = <&vccsys>;
vcc4-supply = <&vccsys>;
vcc5-supply = <&vccsys>;
vcc6-supply = <&vccsys>;
vcc7-supply = <&vccsys>;
regulators {
vdd_logic: DCDC_REG1 {
regulator-name = "vdd_logic";
regulator-min-microvolt = <950000>;
regulator-max-microvolt = <1150000>;
regulator-ramp-delay = <6001>;
regulator-always-on;
regulator-boot-on;
regulator-state-mem {
regulator-on-in-suspend;
regulator-suspend-microvolt = <950000>;
};
};
vdd_arm: DCDC_REG2 {
regulator-name = "vdd_arm";
regulator-min-microvolt = <950000>;
regulator-max-microvolt = <1350000>;
regulator-ramp-delay = <6001>;
regulator-always-on;
regulator-boot-on;
regulator-state-mem {
regulator-off-in-suspend;
regulator-suspend-microvolt = <950000>;
};
};
vcc_ddr: DCDC_REG3 {
regulator-name = "vcc_ddr";
regulator-always-on;
regulator-boot-on;
regulator-state-mem {
regulator-on-in-suspend;
};
};
vcc_3v3: DCDC_REG4 {
regulator-name = "vcc_3v3";
regulator-min-microvolt = <3300000>;
regulator-max-microvolt = <3300000>;
regulator-always-on;
regulator-boot-on;
regulator-state-mem {
regulator-off-in-suspend;
regulator-suspend-microvolt = <3300000>;
};
};
vcc_1v8: LDO_REG2 {
regulator-name = "vcc_1v8";
regulator-min-microvolt = <1800000>;
regulator-max-microvolt = <1800000>;
regulator-always-on;
regulator-boot-on;
regulator-state-mem {
regulator-on-in-suspend;
regulator-suspend-microvolt = <1800000>;
};
};
vdd_1v0: LDO_REG3 {
regulator-name = "vdd_1v0";
regulator-min-microvolt = <1000000>;
regulator-max-microvolt = <1000000>;
regulator-always-on;
regulator-boot-on;
regulator-state-mem {
regulator-on-in-suspend;
regulator-suspend-microvolt = <1000000>;
};
};
vcc3v3_pmu: LDO_REG4 {
regulator-name = "vcc3v3_pmu";
regulator-min-microvolt = <3300000>;
regulator-max-microvolt = <3300000>;
regulator-always-on;
regulator-boot-on;
regulator-state-mem {
regulator-on-in-suspend;
regulator-suspend-microvolt = <3300000>;
};
};
vccio_sd: LDO_REG5 {
regulator-name = "vccio_sd";
regulator-min-microvolt = <1800000>;
regulator-max-microvolt = <3300000>;
regulator-always-on;
regulator-boot-on;
regulator-state-mem {
regulator-on-in-suspend;
regulator-suspend-microvolt = <3300000>;
};
};
vcc_sd: LDO_REG6 {
regulator-name = "vcc_sd";
regulator-min-microvolt = <3300000>;
regulator-max-microvolt = <3300000>;
regulator-boot-on;
regulator-state-mem {
regulator-on-in-suspend;
regulator-suspend-microvolt = <3300000>;
};
};
vcc_bl: LDO_REG7 {
regulator-name = "vcc_bl";
regulator-min-microvolt = <3300000>;
regulator-max-microvolt = <3300000>;
regulator-state-mem {
regulator-off-in-suspend;
regulator-suspend-microvolt = <3300000>;
};
};
vcc_lcd: LDO_REG8 {
regulator-name = "vcc_lcd";
regulator-min-microvolt = <2800000>;
regulator-max-microvolt = <2800000>;
regulator-state-mem {
regulator-off-in-suspend;
regulator-suspend-microvolt = <2800000>;
};
};
vcc_cam: LDO_REG9 {
regulator-name = "vcc_cam";
regulator-min-microvolt = <3000000>;
regulator-max-microvolt = <3000000>;
regulator-state-mem {
regulator-off-in-suspend;
regulator-suspend-microvolt = <3000000>;
};
};
};
rk817_codec: codec {
rockchip,mic-in-differential;
};
};

View File

@ -12,7 +12,11 @@ maintainers:
properties:
"#sound-dai-cells":
const: 0
minimum: 0
maximum: 1
description:
A value of 0 is deprecated. When used, it only allows access to
the ADC/DAC and AIF1 (the CPU DAI), not the other two AIFs/DAIs.
compatible:
oneOf:
@ -50,7 +54,7 @@ additionalProperties: false
examples:
- |
audio-codec@1c22e00 {
#sound-dai-cells = <0>;
#sound-dai-cells = <1>;
compatible = "allwinner,sun8i-a33-codec";
reg = <0x01c22e00 0x400>;
interrupts = <0 29 4>;

View File

@ -81,6 +81,13 @@ Optional properties:
< x1 x2 x3 x4 >
Default = < 15 8 4 1>
- cirrus,hs-bias-sense-disable: This is boolean property. If present the
HSBIAS sense is disabled. Configures HSBIAS output current sense through
the external 2.21-k resistor. HSBIAS_SENSE is hardware feature to reduce
the potential pop noise during the headset plug out slowly. But on some
platforms ESD voltage will affect it causing test to fail, especially
with CTIA headset type. For different hardware setups, a designer might
want to tweak default behavior.
Example:

View File

@ -25,6 +25,7 @@ properties:
- fsl,imx8mq-spdif
- fsl,imx8mm-spdif
- fsl,imx8mn-spdif
- fsl,imx8ulp-spdif
reg:
maxItems: 1

View File

@ -9,8 +9,10 @@ Required properties:
- compatible : Compatible list, contains "fsl,vf610-sai",
"fsl,imx6sx-sai", "fsl,imx6ul-sai",
"fsl,imx7ulp-sai", "fsl,imx8mq-sai" or
"fsl,imx8qm-sai".
"fsl,imx7ulp-sai", "fsl,imx8mq-sai",
"fsl,imx8qm-sai", "fsl,imx8mm-sai",
"fsl,imx8mn-sai", "fsl,imx8mp-sai", or
"fsl,imx8ulp-sai".
- reg : Offset and length of the register set for the device.

View File

@ -0,0 +1,122 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/sound/imx-audio-card.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: NXP i.MX audio sound card.
maintainers:
- Shengjiu Wang <shengjiu.wang@nxp.com>
properties:
compatible:
enum:
- fsl,imx-audio-card
model:
$ref: /schemas/types.yaml#/definitions/string
description: User specified audio sound card name
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.
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
format:
description: audio format.
items:
enum:
- i2s
- dsp_b
dai-tdm-slot-num:
description: see tdm-slot.txt.
$ref: /schemas/types.yaml#/definitions/uint32
dai-tdm-slot-width:
description: see tdm-slot.txt.
$ref: /schemas/types.yaml#/definitions/uint32
cpu:
description: Holds subnode which indicates cpu dai.
type: object
properties:
sound-dai: true
codec:
description: Holds subnode which indicates codec dai.
type: object
properties:
sound-dai: true
fsl,mclk-equal-bclk:
description: Indicates mclk can be equal to bclk, especially for sai interface
$ref: /schemas/types.yaml#/definitions/flag
required:
- link-name
- cpu
additionalProperties: false
required:
- compatible
- model
additionalProperties: false
examples:
- |
sound-ak4458 {
compatible = "fsl,imx-audio-card";
model = "ak4458-audio";
pri-dai-link {
link-name = "akcodec";
format = "i2s";
fsl,mclk-equal-bclk;
cpu {
sound-dai = <&sai1>;
};
codec {
sound-dai = <&ak4458_1>, <&ak4458_2>;
};
};
fe-dai-link {
link-name = "HiFi-ASRC-FE";
format = "i2s";
cpu {
sound-dai = <&easrc>;
};
};
be-dai-link {
link-name = "HiFi-ASRC-BE";
format = "dsp_b";
dai-tdm-slot-num = <8>;
dai-tdm-slot-width = <32>;
fsl,mclk-equal-bclk;
cpu {
sound-dai = <&sai1>;
};
codec {
sound-dai = <&ak4458_1>, <&ak4458_2>;
};
};
};

View File

@ -1,28 +0,0 @@
Freescale Digital Audio Mux (AUDMUX) device
Required properties:
- compatible : "fsl,imx21-audmux" for AUDMUX version firstly used
on i.MX21, or "fsl,imx31-audmux" for the version
firstly used on i.MX31.
- reg : Should contain AUDMUX registers location and length.
An initial configuration can be setup using child nodes.
Required properties of optional child nodes:
- fsl,audmux-port : Integer of the audmux port that is configured by this
child node.
- fsl,port-config : List of configuration options for the specific port.
For imx31-audmux and above, it is a list of tuples
<ptcr pdcr>. For imx21-audmux it is a list of pcr
values.
Example:
audmux@21d8000 {
compatible = "fsl,imx6q-audmux", "fsl,imx31-audmux";
reg = <0x021d8000 0x4000>;
};

View File

@ -0,0 +1,119 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/sound/imx-audmux.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Freescale Digital Audio Mux device
maintainers:
- Oleksij Rempel <o.rempel@pengutronix.de>
properties:
compatible:
oneOf:
- items:
- enum:
- fsl,imx27-audmux
- const: fsl,imx21-audmux
- items:
- enum:
- fsl,imx25-audmux
- fsl,imx35-audmux
- fsl,imx50-audmux
- fsl,imx51-audmux
- fsl,imx53-audmux
- fsl,imx6q-audmux
- fsl,imx6sl-audmux
- fsl,imx6sll-audmux
- fsl,imx6sx-audmux
- const: fsl,imx31-audmux
reg:
maxItems: 1
clocks:
maxItems: 1
clock-names:
items:
- const: audmux
patternProperties:
"^mux-[0-9a-z]*$":
type: object
properties:
fsl,audmux-port:
$ref: /schemas/types.yaml#/definitions/uint32
description: |
Integer of the audmux port that is configured by this child node
fsl,port-config:
$ref: /schemas/types.yaml#/definitions/uint32-array
description: |
List of configuration options for the specific port.
For imx31-audmux and above, it is a list of tuples ptcr pdcr.
For imx21-audmux it is a list of pcr values.
required:
- fsl,audmux-port
- fsl,port-config
additionalProperties: false
required:
- compatible
- reg
additionalProperties: false
examples:
- |
audmux@21d8000 {
compatible = "fsl,imx6q-audmux", "fsl,imx31-audmux";
reg = <0x021d8000 0x4000>;
};
- |
audmux@10016000 {
compatible = "fsl,imx27-audmux", "fsl,imx21-audmux";
reg = <0x10016000 0x1000>;
clocks = <&clks 1>;
clock-names = "audmux";
mux-ssi0 {
fsl,audmux-port = <0>;
fsl,port-config = <0xcb205000>;
};
mux-pins4 {
fsl,audmux-port = <2>;
fsl,port-config = <0x00001000>;
};
};
- |
#include <dt-bindings/sound/fsl-imx-audmux.h>
audmux@21d8000 {
compatible = "fsl,imx6q-audmux", "fsl,imx31-audmux";
reg = <0x021d8000 0x4000>;
pinctrl-names = "default";
pinctrl-0 = <&pinctrl_audmux>;
mux-ssi1 {
fsl,audmux-port = <0>;
fsl,port-config = <
IMX_AUDMUX_V2_PTCR_SYN 0
IMX_AUDMUX_V2_PTCR_TFSEL(2) 0
IMX_AUDMUX_V2_PTCR_TCSEL(2) 0
IMX_AUDMUX_V2_PTCR_TFSDIR 0
IMX_AUDMUX_V2_PTCR_TCLKDIR IMX_AUDMUX_V2_PDCR_RXDSEL(2)
>;
};
mux-pins3 {
fsl,audmux-port = <2>;
fsl,port-config = <
IMX_AUDMUX_V2_PTCR_SYN IMX_AUDMUX_V2_PDCR_RXDSEL(0)
0 IMX_AUDMUX_V2_PDCR_TXRXEN
>;
};
};

View File

@ -0,0 +1,58 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/sound/nxp,tfa989x.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: NXP/Goodix TFA989X (TFA1) Audio Amplifiers
maintainers:
- Stephan Gerhold <stephan@gerhold.net>
properties:
compatible:
enum:
- nxp,tfa9895
- nxp,tfa9897
reg:
maxItems: 1
'#sound-dai-cells':
const: 0
sound-name-prefix:
$ref: /schemas/types.yaml#/definitions/string
description:
Used as prefix for sink/source names of the component. Must be a
unique string among multiple instances of the same component.
vddd-supply:
description: regulator phandle for the VDDD power supply.
required:
- compatible
- reg
- '#sound-dai-cells'
additionalProperties: false
examples:
- |
i2c {
#address-cells = <1>;
#size-cells = <0>;
audio-codec@34 {
compatible = "nxp,tfa9895";
reg = <0x34>;
sound-name-prefix = "Speaker Left";
#sound-dai-cells = <0>;
};
audio-codec@36 {
compatible = "nxp,tfa9895";
reg = <0x36>;
sound-name-prefix = "Speaker Right";
#sound-dai-cells = <0>;
};
};

View File

@ -77,6 +77,31 @@ properties:
minimum: 1800000
maximum: 2850000
qcom,hphl-jack-type-normally-closed:
description: Indicates that HPHL jack switch type is normally closed
type: boolean
qcom,ground-jack-type-normally-closed:
description: Indicates that Headset Ground switch type is normally closed
type: boolean
qcom,mbhc-headset-vthreshold-microvolt:
description: Voltage threshold value for headset detection
minimum: 0
maximum: 2850000
qcom,mbhc-headphone-vthreshold-microvolt:
description: Voltage threshold value for headphone detection
minimum: 0
maximum: 2850000
qcom,mbhc-buttons-vthreshold-microvolt:
description:
Array of 8 Voltage threshold values corresponding to headset
button0 - button7
minItems: 8
maxItems: 8
clock-output-names:
const: mclk
@ -159,6 +184,11 @@ examples:
qcom,micbias2-microvolt = <1800000>;
qcom,micbias3-microvolt = <1800000>;
qcom,micbias4-microvolt = <1800000>;
qcom,hphl-jack-type-normally-closed;
qcom,ground-jack-type-normally-closed;
qcom,mbhc-buttons-vthreshold-microvolt = <75000 150000 237000 500000 500000 500000 500000 500000>;
qcom,mbhc-headset-vthreshold-microvolt = <1700000>;
qcom,mbhc-headphone-vthreshold-microvolt = <50000>;
clock-names = "extclk";
clocks = <&rpmhcc 2>;

View File

@ -0,0 +1,70 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/sound/qcom,wcd938x-sdw.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Bindings for Qualcomm SoundWire Slave devices on WCD9380/WCD9385
maintainers:
- Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
description: |
Qualcomm WCD9380/WCD9385 Codec is a standalone Hi-Fi audio codec IC.
It has RX and TX Soundwire slave devices. This bindings is for the
slave devices.
properties:
compatible:
const: sdw20217010d00
reg:
maxItems: 1
qcom,tx-port-mapping:
description: |
Specifies static port mapping between slave and master tx ports.
In the order of slave port index.
$ref: /schemas/types.yaml#/definitions/uint32-array
minItems: 4
maxItems: 4
qcom,rx-port-mapping:
description: |
Specifies static port mapping between slave and master rx ports.
In the order of slave port index.
$ref: /schemas/types.yaml#/definitions/uint32-array
minItems: 5
maxItems: 5
required:
- compatible
- reg
additionalProperties: false
examples:
- |
soundwire@3210000 {
#address-cells = <2>;
#size-cells = <0>;
reg = <0x03210000 0x2000>;
wcd938x_rx: codec@0,4 {
compatible = "sdw20217010d00";
reg = <0 4>;
qcom,rx-port-mapping = <1 2 3 4 5>;
};
};
soundwire@3230000 {
#address-cells = <2>;
#size-cells = <0>;
reg = <0x03230000 0x2000>;
wcd938x_tx: codec@0,3 {
compatible = "sdw20217010d00";
reg = <0 3>;
qcom,tx-port-mapping = <2 3 4 5>;
};
};
...

View File

@ -0,0 +1,146 @@
# SPDX-License-Identifier: (GPL-2.0-only OR BSD-2-Clause)
%YAML 1.2
---
$id: http://devicetree.org/schemas/sound/qcom,wcd938x.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: Bindings for Qualcomm WCD9380/WCD9385 Audio Codec
maintainers:
- Srinivas Kandagatla <srinivas.kandagatla@linaro.org>
description: |
Qualcomm WCD9380/WCD9385 Codec is a standalone Hi-Fi audio codec IC.
It has RX and TX Soundwire slave devices.
properties:
compatible:
enum:
- qcom,wcd9380-codec
- qcom,wcd9385-codec
reset-gpios:
description: GPIO spec for reset line to use
maxItems: 1
vdd-buck-supply:
description: A reference to the 1.8V buck supply
vdd-rxtx-supply:
description: A reference to the 1.8V rx supply
vdd-io-supply:
description: A reference to the 1.8V I/O supply
qcom,tx-device:
$ref: /schemas/types.yaml#/definitions/phandle-array
description: A reference to Soundwire tx device phandle
qcom,rx-device:
$ref: /schemas/types.yaml#/definitions/phandle-array
description: A reference to Soundwire rx device phandle
qcom,micbias1-microvolt:
description: micbias1 voltage
minimum: 1800000
maximum: 2850000
qcom,micbias2-microvolt:
description: micbias2 voltage
minimum: 1800000
maximum: 2850000
qcom,micbias3-microvolt:
description: micbias3 voltage
minimum: 1800000
maximum: 2850000
qcom,micbias4-microvolt:
description: micbias4 voltage
minimum: 1800000
maximum: 2850000
qcom,hphl-jack-type-normally-closed:
description: Indicates that HPHL jack switch type is normally closed
type: boolean
qcom,ground-jack-type-normally-closed:
description: Indicates that Headset Ground switch type is normally closed
type: boolean
qcom,mbhc-headset-vthreshold-microvolt:
description: Voltage threshold value for headset detection
minimum: 0
maximum: 2850000
qcom,mbhc-headphone-vthreshold-microvolt:
description: Voltage threshold value for headphone detection
minimum: 0
maximum: 2850000
qcom,mbhc-buttons-vthreshold-microvolt:
description:
Array of 8 Voltage threshold values corresponding to headset
button0 - button7
minItems: 8
maxItems: 8
'#sound-dai-cells':
const: 1
required:
- compatible
- reset-gpios
- qcom,tx-device
- qcom,rx-device
- qcom,micbias1-microvolt
- qcom,micbias2-microvolt
- qcom,micbias3-microvolt
- qcom,micbias4-microvolt
- "#sound-dai-cells"
additionalProperties: false
examples:
- |
codec {
compatible = "qcom,wcd9380-codec";
reset-gpios = <&tlmm 32 0>;
#sound-dai-cells = <1>;
qcom,tx-device = <&wcd938x_tx>;
qcom,rx-device = <&wcd938x_rx>;
qcom,micbias1-microvolt = <1800000>;
qcom,micbias2-microvolt = <1800000>;
qcom,micbias3-microvolt = <1800000>;
qcom,micbias4-microvolt = <1800000>;
qcom,hphl-jack-type-normally-closed;
qcom,ground-jack-type-normally-closed;
qcom,mbhc-buttons-vthreshold-microvolt = <75000 150000 237000 500000 500000 500000 500000 500000>;
qcom,mbhc-headphone-vthreshold-microvolt = <50000>;
};
/* ... */
soundwire@3210000 {
#address-cells = <2>;
#size-cells = <0>;
reg = <0x03210000 0x2000>;
wcd938x_rx: codec@0,4 {
compatible = "sdw20217010d00";
reg = <0 4>;
qcom,rx-port-mapping = <1 2 3 4 5>;
};
};
soundwire@3230000 {
#address-cells = <2>;
#size-cells = <0>;
reg = <0x03230000 0x2000>;
wcd938x_tx: codec@0,3 {
compatible = "sdw20217010d00";
reg = <0 3>;
qcom,tx-port-mapping = <2 3 4 5>;
};
};
...

View File

@ -86,9 +86,11 @@ properties:
power-domains: true
resets:
minItems: 1
maxItems: 11
reset-names:
minItems: 1
maxItems: 11
clocks:
@ -110,6 +112,13 @@ properties:
- pattern: '^dvc\.[0-1]$'
- pattern: '^clk_(a|b|c|i)$'
ports:
$ref: /schemas/graph.yaml#/properties/ports
properties:
port(@[0-9a-f]+)?:
$ref: audio-graph-port.yaml#
unevaluatedProperties: false
port:
$ref: audio-graph-port.yaml#
unevaluatedProperties: false
@ -257,7 +266,6 @@ required:
- "#sound-dai-cells"
allOf:
- $ref: audio-graph.yaml#
- if:
properties:
compatible:

View File

@ -75,6 +75,10 @@ properties:
$ref: "/schemas/types.yaml#/definitions/uint32"
enum: [ 0, 1, 2, 3 ]
port:
$ref: audio-graph-port.yaml#
unevaluatedProperties: false
required:
- compatible
- reg

View File

@ -6,6 +6,7 @@ Required properties:
- compatible - "string" - One of:
"ti,tlv320aic32x4" TLV320AIC3204
"ti,tlv320aic32x6" TLV320AIC3206, TLV320AIC3256
"ti,tas2505" TAS2505, TAS2521
- reg: I2C slave address
- supply-*: Required supply regulators are:
"iov" - digital IO power supply

View File

@ -1,18 +0,0 @@
WM8750 and WM8987 audio CODECs
These devices support both I2C and SPI (configured with pin strapping
on the board).
Required properties:
- compatible : "wlf,wm8750" or "wlf,wm8987"
- reg : the I2C address of the device for I2C, the chip select
number for SPI.
Example:
wm8750: codec@1a {
compatible = "wlf,wm8750";
reg = <0x1a>;
};

View File

@ -0,0 +1,42 @@
# SPDX-License-Identifier: GPL-2.0-only OR BSD-2-Clause
%YAML 1.2
---
$id: http://devicetree.org/schemas/sound/wm8750.yaml#
$schema: http://devicetree.org/meta-schemas/core.yaml#
title: WM8750 and WM8987 audio CODECs
description: |
These devices support both I2C and SPI (configured with pin strapping
on the board).
maintainers:
- Mark Brown <broonie@kernel.org>
properties:
compatible:
enum:
- wlf,wm8750
- wlf,wm8987
reg:
description:
The I2C address of the device for I2C, the chip select number for SPI
maxItems: 1
additionalProperties: false
required:
- reg
examples:
- |
i2c {
#address-cells = <1>;
#size-cells = <0>;
codec@1a {
compatible = "wlf,wm8750";
reg = <0x1a>;
};
};

View File

@ -102,7 +102,7 @@ Conexant codecs
---------------
Auto-Mute Mode
See Reatek codecs.
See Realtek codecs.
Analog codecs

View File

@ -3508,14 +3508,15 @@ field must be set, though).
“IEC958 Playback Con Mask” is used to return the bit-mask for the IEC958
status bits of consumer mode. Similarly, “IEC958 Playback Pro Mask”
returns the bitmask for professional mode. They are read-only controls,
and are defined as MIXER controls (iface =
``SNDRV_CTL_ELEM_IFACE_MIXER``).
returns the bitmask for professional mode. They are read-only controls.
Meanwhile, “IEC958 Playback Default” control is defined for getting and
setting the current default IEC958 bits. Note that this one is usually
defined as a PCM control (iface = ``SNDRV_CTL_ELEM_IFACE_PCM``),
although in some places it's defined as a MIXER control.
setting the current default IEC958 bits.
Due to historical reasons, both variants of the Playback Mask and the
Playback Default controls can be implemented on either a
``SNDRV_CTL_ELEM_IFACE_PCM`` or a ``SNDRV_CTL_ELEM_IFACE_MIXER`` iface.
Drivers should expose the mask and default on the same iface though.
In addition, you can define the control switches to enable/disable or to
set the raw bit mode. The implementation will depend on the chip, but

View File

@ -7179,6 +7179,13 @@ L: linux-input@vger.kernel.org
S: Maintained
F: drivers/input/joystick/fsia6b.c
FOCUSRITE SCARLETT GEN 2/3 MIXER DRIVER
M: Geoffrey D. Bennett <g@b4.vu>
L: alsa-devel@alsa-project.org (moderated for non-subscribers)
S: Maintained
T: git git://git.kernel.org/pub/scm/linux/kernel/git/tiwai/sound.git
F: sound/usb/mixer_scarlett_gen2.c
FORCEDETH GIGABIT ETHERNET DRIVER
M: Rain River <rain.1986.08.12@gmail.com>
M: Zhu Yanjun <zyjzyj2000@gmail.com>
@ -13321,6 +13328,13 @@ S: Maintained
F: Documentation/devicetree/bindings/sound/tfa9879.txt
F: sound/soc/codecs/tfa9879*
NXP/Goodix TFA989X (TFA1) DRIVER
M: Stephan Gerhold <stephan@gerhold.net>
L: alsa-devel@alsa-project.org (moderated for non-subscribers)
S: Maintained
F: Documentation/devicetree/bindings/sound/nxp,tfa989x.yaml
F: sound/soc/codecs/tfa989x.c
NXP-NCI NFC DRIVER
R: Charles Gorand <charles.gorand@effinnov.com>
L: linux-nfc@lists.01.org (subscribers-only)

View File

@ -65,6 +65,7 @@ static bool rk817_is_volatile_reg(struct device *dev, unsigned int reg)
switch (reg) {
case RK817_SECONDS_REG ... RK817_WEEKS_REG:
case RK817_RTC_STATUS_REG:
case RK817_CODEC_DTOP_LPT_SRST:
case RK817_INT_STS_REG0:
case RK817_INT_STS_REG1:
case RK817_INT_STS_REG2:
@ -163,6 +164,7 @@ static const struct mfd_cell rk817s[] = {
.num_resources = ARRAY_SIZE(rk817_rtc_resources),
.resources = &rk817_rtc_resources[0],
},
{ .name = "rk817-codec",},
};
static const struct mfd_cell rk818s[] = {
@ -201,6 +203,85 @@ static const struct rk808_reg_data rk808_pre_init_reg[] = {
static const struct rk808_reg_data rk817_pre_init_reg[] = {
{RK817_RTC_CTRL_REG, RTC_STOP, RTC_STOP},
/* Codec specific registers */
{ RK817_CODEC_DTOP_VUCTL, MASK_ALL, 0x03 },
{ RK817_CODEC_DTOP_VUCTIME, MASK_ALL, 0x00 },
{ RK817_CODEC_DTOP_LPT_SRST, MASK_ALL, 0x00 },
{ RK817_CODEC_DTOP_DIGEN_CLKE, MASK_ALL, 0x00 },
/* from vendor driver, CODEC_AREF_RTCFG0 not defined in data sheet */
{ RK817_CODEC_AREF_RTCFG0, MASK_ALL, 0x00 },
{ RK817_CODEC_AREF_RTCFG1, MASK_ALL, 0x06 },
{ RK817_CODEC_AADC_CFG0, MASK_ALL, 0xc8 },
/* from vendor driver, CODEC_AADC_CFG1 not defined in data sheet */
{ RK817_CODEC_AADC_CFG1, MASK_ALL, 0x00 },
{ RK817_CODEC_DADC_VOLL, MASK_ALL, 0x00 },
{ RK817_CODEC_DADC_VOLR, MASK_ALL, 0x00 },
{ RK817_CODEC_DADC_SR_ACL0, MASK_ALL, 0x00 },
{ RK817_CODEC_DADC_ALC1, MASK_ALL, 0x00 },
{ RK817_CODEC_DADC_ALC2, MASK_ALL, 0x00 },
{ RK817_CODEC_DADC_NG, MASK_ALL, 0x00 },
{ RK817_CODEC_DADC_HPF, MASK_ALL, 0x00 },
{ RK817_CODEC_DADC_RVOLL, MASK_ALL, 0xff },
{ RK817_CODEC_DADC_RVOLR, MASK_ALL, 0xff },
{ RK817_CODEC_AMIC_CFG0, MASK_ALL, 0x70 },
{ RK817_CODEC_AMIC_CFG1, MASK_ALL, 0x00 },
{ RK817_CODEC_DMIC_PGA_GAIN, MASK_ALL, 0x66 },
{ RK817_CODEC_DMIC_LMT1, MASK_ALL, 0x00 },
{ RK817_CODEC_DMIC_LMT2, MASK_ALL, 0x00 },
{ RK817_CODEC_DMIC_NG1, MASK_ALL, 0x00 },
{ RK817_CODEC_DMIC_NG2, MASK_ALL, 0x00 },
/* from vendor driver, CODEC_ADAC_CFG0 not defined in data sheet */
{ RK817_CODEC_ADAC_CFG0, MASK_ALL, 0x00 },
{ RK817_CODEC_ADAC_CFG1, MASK_ALL, 0x07 },
{ RK817_CODEC_DDAC_POPD_DACST, MASK_ALL, 0x82 },
{ RK817_CODEC_DDAC_VOLL, MASK_ALL, 0x00 },
{ RK817_CODEC_DDAC_VOLR, MASK_ALL, 0x00 },
{ RK817_CODEC_DDAC_SR_LMT0, MASK_ALL, 0x00 },
{ RK817_CODEC_DDAC_LMT1, MASK_ALL, 0x00 },
{ RK817_CODEC_DDAC_LMT2, MASK_ALL, 0x00 },
{ RK817_CODEC_DDAC_MUTE_MIXCTL, MASK_ALL, 0xa0 },
{ RK817_CODEC_DDAC_RVOLL, MASK_ALL, 0xff },
{ RK817_CODEC_DADC_RVOLR, MASK_ALL, 0xff },
{ RK817_CODEC_AMIC_CFG0, MASK_ALL, 0x70 },
{ RK817_CODEC_AMIC_CFG1, MASK_ALL, 0x00 },
{ RK817_CODEC_DMIC_PGA_GAIN, MASK_ALL, 0x66 },
{ RK817_CODEC_DMIC_LMT1, MASK_ALL, 0x00 },
{ RK817_CODEC_DMIC_LMT2, MASK_ALL, 0x00 },
{ RK817_CODEC_DMIC_NG1, MASK_ALL, 0x00 },
{ RK817_CODEC_DMIC_NG2, MASK_ALL, 0x00 },
/* from vendor driver, CODEC_ADAC_CFG0 not defined in data sheet */
{ RK817_CODEC_ADAC_CFG0, MASK_ALL, 0x00 },
{ RK817_CODEC_ADAC_CFG1, MASK_ALL, 0x07 },
{ RK817_CODEC_DDAC_POPD_DACST, MASK_ALL, 0x82 },
{ RK817_CODEC_DDAC_VOLL, MASK_ALL, 0x00 },
{ RK817_CODEC_DDAC_VOLR, MASK_ALL, 0x00 },
{ RK817_CODEC_DDAC_SR_LMT0, MASK_ALL, 0x00 },
{ RK817_CODEC_DDAC_LMT1, MASK_ALL, 0x00 },
{ RK817_CODEC_DDAC_LMT2, MASK_ALL, 0x00 },
{ RK817_CODEC_DDAC_MUTE_MIXCTL, MASK_ALL, 0xa0 },
{ RK817_CODEC_DDAC_RVOLL, MASK_ALL, 0xff },
{ RK817_CODEC_DDAC_RVOLR, MASK_ALL, 0xff },
{ RK817_CODEC_AHP_ANTI0, MASK_ALL, 0x00 },
{ RK817_CODEC_AHP_ANTI1, MASK_ALL, 0x00 },
{ RK817_CODEC_AHP_CFG0, MASK_ALL, 0xe0 },
{ RK817_CODEC_AHP_CFG1, MASK_ALL, 0x1f },
{ RK817_CODEC_AHP_CP, MASK_ALL, 0x09 },
{ RK817_CODEC_ACLASSD_CFG1, MASK_ALL, 0x69 },
{ RK817_CODEC_ACLASSD_CFG2, MASK_ALL, 0x44 },
{ RK817_CODEC_APLL_CFG0, MASK_ALL, 0x04 },
{ RK817_CODEC_APLL_CFG1, MASK_ALL, 0x00 },
{ RK817_CODEC_APLL_CFG2, MASK_ALL, 0x30 },
{ RK817_CODEC_APLL_CFG3, MASK_ALL, 0x19 },
{ RK817_CODEC_APLL_CFG4, MASK_ALL, 0x65 },
{ RK817_CODEC_APLL_CFG5, MASK_ALL, 0x01 },
{ RK817_CODEC_DI2S_CKM, MASK_ALL, 0x01 },
{ RK817_CODEC_DI2S_RSD, MASK_ALL, 0x00 },
{ RK817_CODEC_DI2S_RXCR1, MASK_ALL, 0x00 },
{ RK817_CODEC_DI2S_RXCR2, MASK_ALL, 0x17 },
{ RK817_CODEC_DI2S_RXCMD_TSD, MASK_ALL, 0x00 },
{ RK817_CODEC_DI2S_TXCR1, MASK_ALL, 0x00 },
{ RK817_CODEC_DI2S_TXCR2, MASK_ALL, 0x17 },
{ RK817_CODEC_DI2S_TXCR3_TXCMD, MASK_ALL, 0x00 },
{RK817_GPIO_INT_CFG, RK817_INT_POL_MSK, RK817_INT_POL_L},
{RK817_SYS_CFG(1), RK817_HOTDIE_TEMP_MSK | RK817_TSD_TEMP_MSK,
RK817_HOTDIE_105 | RK817_TSD_140},

View File

@ -492,7 +492,7 @@ int sdw_read_no_pm(struct sdw_slave *slave, u32 addr)
}
EXPORT_SYMBOL(sdw_read_no_pm);
static int sdw_update_no_pm(struct sdw_slave *slave, u32 addr, u8 mask, u8 val)
int sdw_update_no_pm(struct sdw_slave *slave, u32 addr, u8 mask, u8 val)
{
int tmp;
@ -503,6 +503,21 @@ static int sdw_update_no_pm(struct sdw_slave *slave, u32 addr, u8 mask, u8 val)
tmp = (tmp & ~mask) | val;
return sdw_write_no_pm(slave, addr, tmp);
}
EXPORT_SYMBOL(sdw_update_no_pm);
/* Read-Modify-Write Slave register */
int sdw_update(struct sdw_slave *slave, u32 addr, u8 mask, u8 val)
{
int tmp;
tmp = sdw_read(slave, addr);
if (tmp < 0)
return tmp;
tmp = (tmp & ~mask) | val;
return sdw_write(slave, addr, tmp);
}
EXPORT_SYMBOL(sdw_update);
/**
* sdw_nread() - Read "n" contiguous SDW Slave registers

View File

@ -201,19 +201,6 @@ static inline void sdw_fill_port_params(struct sdw_port_params *params,
params->data_mode = data_mode;
}
/* Read-Modify-Write Slave register */
static inline int sdw_update(struct sdw_slave *slave, u32 addr, u8 mask, u8 val)
{
int tmp;
tmp = sdw_read(slave, addr);
if (tmp < 0)
return tmp;
tmp = (tmp & ~mask) | val;
return sdw_write(slave, addr, tmp);
}
/* broadcast read/write for tests */
int sdw_bread_no_pm_unlocked(struct sdw_bus *bus, u16 dev_num, u32 addr);
int sdw_bwrite_no_pm_unlocked(struct sdw_bus *bus, u16 dev_num, u32 addr, u8 value);

View File

@ -129,6 +129,8 @@
#define TX_CODEC_DMA_TX_5 124
#define RX_CODEC_DMA_RX_6 125
#define RX_CODEC_DMA_RX_7 126
#define QUINARY_MI2S_RX 127
#define QUINARY_MI2S_TX 128
#define LPASS_CLK_ID_PRI_MI2S_IBIT 1
#define LPASS_CLK_ID_PRI_MI2S_EBIT 2

View File

@ -437,6 +437,87 @@ enum rk809_reg_id {
#define RK817_RTC_COMP_LSB_REG 0x10
#define RK817_RTC_COMP_MSB_REG 0x11
/* RK817 Codec Registers */
#define RK817_CODEC_DTOP_VUCTL 0x12
#define RK817_CODEC_DTOP_VUCTIME 0x13
#define RK817_CODEC_DTOP_LPT_SRST 0x14
#define RK817_CODEC_DTOP_DIGEN_CLKE 0x15
#define RK817_CODEC_AREF_RTCFG0 0x16
#define RK817_CODEC_AREF_RTCFG1 0x17
#define RK817_CODEC_AADC_CFG0 0x18
#define RK817_CODEC_AADC_CFG1 0x19
#define RK817_CODEC_DADC_VOLL 0x1a
#define RK817_CODEC_DADC_VOLR 0x1b
#define RK817_CODEC_DADC_SR_ACL0 0x1e
#define RK817_CODEC_DADC_ALC1 0x1f
#define RK817_CODEC_DADC_ALC2 0x20
#define RK817_CODEC_DADC_NG 0x21
#define RK817_CODEC_DADC_HPF 0x22
#define RK817_CODEC_DADC_RVOLL 0x23
#define RK817_CODEC_DADC_RVOLR 0x24
#define RK817_CODEC_AMIC_CFG0 0x27
#define RK817_CODEC_AMIC_CFG1 0x28
#define RK817_CODEC_DMIC_PGA_GAIN 0x29
#define RK817_CODEC_DMIC_LMT1 0x2a
#define RK817_CODEC_DMIC_LMT2 0x2b
#define RK817_CODEC_DMIC_NG1 0x2c
#define RK817_CODEC_DMIC_NG2 0x2d
#define RK817_CODEC_ADAC_CFG0 0x2e
#define RK817_CODEC_ADAC_CFG1 0x2f
#define RK817_CODEC_DDAC_POPD_DACST 0x30
#define RK817_CODEC_DDAC_VOLL 0x31
#define RK817_CODEC_DDAC_VOLR 0x32
#define RK817_CODEC_DDAC_SR_LMT0 0x35
#define RK817_CODEC_DDAC_LMT1 0x36
#define RK817_CODEC_DDAC_LMT2 0x37
#define RK817_CODEC_DDAC_MUTE_MIXCTL 0x38
#define RK817_CODEC_DDAC_RVOLL 0x39
#define RK817_CODEC_DDAC_RVOLR 0x3a
#define RK817_CODEC_AHP_ANTI0 0x3b
#define RK817_CODEC_AHP_ANTI1 0x3c
#define RK817_CODEC_AHP_CFG0 0x3d
#define RK817_CODEC_AHP_CFG1 0x3e
#define RK817_CODEC_AHP_CP 0x3f
#define RK817_CODEC_ACLASSD_CFG1 0x40
#define RK817_CODEC_ACLASSD_CFG2 0x41
#define RK817_CODEC_APLL_CFG0 0x42
#define RK817_CODEC_APLL_CFG1 0x43
#define RK817_CODEC_APLL_CFG2 0x44
#define RK817_CODEC_APLL_CFG3 0x45
#define RK817_CODEC_APLL_CFG4 0x46
#define RK817_CODEC_APLL_CFG5 0x47
#define RK817_CODEC_DI2S_CKM 0x48
#define RK817_CODEC_DI2S_RSD 0x49
#define RK817_CODEC_DI2S_RXCR1 0x4a
#define RK817_CODEC_DI2S_RXCR2 0x4b
#define RK817_CODEC_DI2S_RXCMD_TSD 0x4c
#define RK817_CODEC_DI2S_TXCR1 0x4d
#define RK817_CODEC_DI2S_TXCR2 0x4e
#define RK817_CODEC_DI2S_TXCR3_TXCMD 0x4f
/* RK817_CODEC_DI2S_CKM */
#define RK817_I2S_MODE_MASK (0x1 << 0)
#define RK817_I2S_MODE_MST (0x1 << 0)
#define RK817_I2S_MODE_SLV (0x0 << 0)
/* RK817_CODEC_DDAC_MUTE_MIXCTL */
#define DACMT_MASK (0x1 << 0)
#define DACMT_ENABLE (0x1 << 0)
#define DACMT_DISABLE (0x0 << 0)
/* RK817_CODEC_DI2S_RXCR2 */
#define VDW_RX_24BITS (0x17)
#define VDW_RX_16BITS (0x0f)
/* RK817_CODEC_DI2S_TXCR2 */
#define VDW_TX_24BITS (0x17)
#define VDW_TX_16BITS (0x0f)
/* RK817_CODEC_AMIC_CFG0 */
#define MIC_DIFF_MASK (0x1 << 7)
#define MIC_DIFF_DIS (0x0 << 7)
#define MIC_DIFF_EN (0x1 << 7)
#define RK817_POWER_EN_REG(i) (0xb1 + (i))
#define RK817_POWER_SLP_EN_REG(i) (0xb5 + (i))

View File

@ -18,6 +18,8 @@
#define WCD934X_EFUSE_SENSE_STATE_DEF 0x10
#define WCD934X_EFUSE_SENSE_EN_MASK BIT(0)
#define WCD934X_EFUSE_SENSE_ENABLE BIT(0)
#define WCD934X_CHIP_TIER_CTRL_EFUSE_VAL_OUT1 0x002a
#define WCD934X_CHIP_TIER_CTRL_EFUSE_VAL_OUT2 0x002b
#define WCD934X_CHIP_TIER_CTRL_EFUSE_VAL_OUT14 0x0037
#define WCD934X_CHIP_TIER_CTRL_EFUSE_VAL_OUT15 0x0038
#define WCD934X_CHIP_TIER_CTRL_EFUSE_STATUS 0x0039
@ -103,21 +105,58 @@
#define WCD934X_ANA_AMIC3 0x0610
#define WCD934X_ANA_AMIC4 0x0611
#define WCD934X_ANA_MBHC_MECH 0x0614
#define WCD934X_MBHC_L_DET_EN_MASK BIT(7)
#define WCD934X_MBHC_L_DET_EN BIT(7)
#define WCD934X_MBHC_GND_DET_EN_MASK BIT(6)
#define WCD934X_MBHC_MECH_DETECT_TYPE_MASK BIT(5)
#define WCD934X_MBHC_MECH_DETECT_TYPE_INS 1
#define WCD934X_MBHC_HPHL_PLUG_TYPE_MASK BIT(4)
#define WCD934X_MBHC_HPHL_PLUG_TYPE_NO 1
#define WCD934X_MBHC_GND_PLUG_TYPE_MASK BIT(3)
#define WCD934X_MBHC_GND_PLUG_TYPE_NO 1
#define WCD934X_MBHC_HSL_PULLUP_COMP_EN BIT(2)
#define WCD934X_MBHC_HSG_PULLUP_COMP_EN BIT(1)
#define WCD934X_MBHC_HPHL_100K_TO_GND_EN BIT(0)
#define WCD934X_ANA_MBHC_ELECT 0x0615
#define WCD934X_ANA_MBHC_BIAS_EN_MASK BIT(0)
#define WCD934X_ANA_MBHC_BIAS_EN BIT(0)
#define WCD934X_ANA_MBHC_ZDET 0x0616
#define WCD934X_ANA_MBHC_RESULT_1 0x0617
#define WCD934X_ANA_MBHC_RESULT_2 0x0618
#define WCD934X_ANA_MBHC_RESULT_3 0x0619
#define WCD934X_ANA_MBHC_BTN0 0x061a
#define WCD934X_VTH_MASK GENMASK(7, 2)
#define WCD934X_ANA_MBHC_BTN1 0x061b
#define WCD934X_ANA_MBHC_BTN2 0x061c
#define WCD934X_ANA_MBHC_BTN3 0x061d
#define WCD934X_ANA_MBHC_BTN4 0x061e
#define WCD934X_ANA_MBHC_BTN5 0x061f
#define WCD934X_ANA_MBHC_BTN6 0x0620
#define WCD934X_ANA_MBHC_BTN7 0x0621
#define WCD934X_MBHC_BTN_VTH_MASK GENMASK(7, 2)
#define WCD934X_ANA_MICB1 0x0622
#define WCD934X_MICB_VAL_MASK GENMASK(5, 0)
#define WCD934X_ANA_MICB_EN_MASK GENMASK(7, 6)
#define WCD934X_MICB_DISABLE 0
#define WCD934X_MICB_ENABLE 1
#define WCD934X_MICB_PULL_UP 2
#define WCD934X_MICB_PULL_DOWN 3
#define WCD934X_ANA_MICB_PULL_UP 0x80
#define WCD934X_ANA_MICB_ENABLE 0x40
#define WCD934X_ANA_MICB_DISABLE 0x0
#define WCD934X_ANA_MICB2 0x0623
#define WCD934X_ANA_MICB2_ENABLE BIT(6)
#define WCD934X_ANA_MICB2_ENABLE_MASK GENMASK(7, 6)
#define WCD934X_ANA_MICB2_VOUT_MASK GENMASK(5, 0)
#define WCD934X_ANA_MICB2_RAMP 0x0624
#define WCD934X_RAMP_EN_MASK BIT(7)
#define WCD934X_RAMP_SHIFT_CTRL_MASK GENMASK(4, 2)
#define WCD934X_ANA_MICB3 0x0625
#define WCD934X_ANA_MICB4 0x0626
#define WCD934X_BIAS_VBG_FINE_ADJ 0x0629
#define WCD934X_MBHC_CTL_CLK 0x0656
#define WCD934X_MBHC_CTL_BCS 0x065a
#define WCD934X_MBHC_STATUS_SPARE_1 0x065b
#define WCD934X_MICB1_TEST_CTL_1 0x066b
#define WCD934X_MICB1_TEST_CTL_2 0x066c
#define WCD934X_MICB2_TEST_CTL_1 0x066e
@ -141,7 +180,11 @@
#define WCD934X_HPH_CNP_WG_CTL 0x06cc
#define WCD934X_HPH_GM3_BOOST_EN_MASK BIT(7)
#define WCD934X_HPH_GM3_BOOST_ENABLE BIT(7)
#define WCD934X_HPH_CNP_WG_TIME 0x06cd
#define WCD934X_HPH_OCP_CTL 0x06ce
#define WCD934X_HPH_PA_CTL2 0x06d2
#define WCD934X_HPHPA_GND_R_MASK BIT(6)
#define WCD934X_HPHPA_GND_L_MASK BIT(4)
#define WCD934X_HPH_L_EN 0x06d3
#define WCD934X_HPH_GAIN_SRC_SEL_MASK BIT(5)
#define WCD934X_HPH_GAIN_SRC_SEL_COMPANDER 0
@ -152,6 +195,8 @@
#define WCD934X_HPH_OCP_DET_MASK BIT(0)
#define WCD934X_HPH_OCP_DET_ENABLE BIT(0)
#define WCD934X_HPH_OCP_DET_DISABLE 0
#define WCD934X_HPH_R_ATEST 0x06d8
#define WCD934X_HPHPA_GND_OVR_MASK BIT(1)
#define WCD934X_DIFF_LO_LO2_COMPANDER 0x06ea
#define WCD934X_DIFF_LO_LO1_COMPANDER 0x06eb
#define WCD934X_CLK_SYS_MCLK_PRG 0x0711
@ -172,7 +217,19 @@
#define WCD934X_SIDO_NEW_VOUT_D_FREQ2 0x071e
#define WCD934X_SIDO_RIPPLE_FREQ_EN_MASK BIT(0)
#define WCD934X_SIDO_RIPPLE_FREQ_ENABLE BIT(0)
#define WCD934X_MBHC_NEW_CTL_1 0x0720
#define WCD934X_MBHC_CTL_RCO_EN_MASK BIT(7)
#define WCD935X_MBHC_CTL_RCO_EN BIT(7)
#define WCD934X_MBHC_NEW_CTL_2 0x0721
#define WCD934X_M_RTH_CTL_MASK GENMASK(3, 2)
#define WCD934X_MBHC_NEW_PLUG_DETECT_CTL 0x0722
#define WCD934X_HSDET_PULLUP_C_MASK GENMASK(7, 6)
#define WCD934X_MBHC_NEW_ZDET_ANA_CTL 0x0723
#define WCD934X_ZDET_RANGE_CTL_MASK GENMASK(3, 0)
#define WCD934X_ZDET_MAXV_CTL_MASK GENMASK(6, 4)
#define WCD934X_MBHC_NEW_ZDET_RAMP_CTL 0x0724
#define WCD934X_MBHC_NEW_FSM_STATUS 0x0725
#define WCD934X_MBHC_NEW_ADC_RESULT 0x0726
#define WCD934X_TX_NEW_AMIC_4_5_SEL 0x0727
#define WCD934X_HPH_NEW_INT_RDAC_HD2_CTL_L 0x0733
#define WCD934X_HPH_NEW_INT_RDAC_OVERRIDE_CTL 0x0735

View File

@ -1041,6 +1041,9 @@ int sdw_write_no_pm(struct sdw_slave *slave, u32 addr, u8 value);
int sdw_read_no_pm(struct sdw_slave *slave, u32 addr);
int sdw_nread(struct sdw_slave *slave, u32 addr, size_t count, u8 *val);
int sdw_nwrite(struct sdw_slave *slave, u32 addr, size_t count, u8 *val);
int sdw_update(struct sdw_slave *slave, u32 addr, u8 mask, u8 val);
int sdw_update_no_pm(struct sdw_slave *slave, u32 addr, u8 mask, u8 val);
int sdw_compare_devid(struct sdw_slave *slave, struct sdw_slave_id id);
void sdw_extract_slave_id(struct sdw_bus *bus, u64 addr, struct sdw_slave_id *id);

View File

@ -128,7 +128,9 @@ struct snd_card {
#ifdef CONFIG_PM
unsigned int power_state; /* power state */
atomic_t power_ref;
wait_queue_head_t power_sleep;
wait_queue_head_t power_ref_sleep;
#endif
#if IS_ENABLED(CONFIG_SND_MIXER_OSS)
@ -142,21 +144,61 @@ struct snd_card {
#ifdef CONFIG_PM
static inline unsigned int snd_power_get_state(struct snd_card *card)
{
return card->power_state;
return READ_ONCE(card->power_state);
}
static inline void snd_power_change_state(struct snd_card *card, unsigned int state)
{
card->power_state = state;
WRITE_ONCE(card->power_state, state);
wake_up(&card->power_sleep);
}
/**
* snd_power_ref - Take the reference count for power control
* @card: sound card object
*
* The power_ref reference of the card is used for managing to block
* the snd_power_sync_ref() operation. This function increments the reference.
* The counterpart snd_power_unref() has to be called appropriately later.
*/
static inline void snd_power_ref(struct snd_card *card)
{
atomic_inc(&card->power_ref);
}
/**
* snd_power_unref - Release the reference count for power control
* @card: sound card object
*/
static inline void snd_power_unref(struct snd_card *card)
{
if (atomic_dec_and_test(&card->power_ref))
wake_up(&card->power_ref_sleep);
}
/**
* snd_power_sync_ref - wait until the card power_ref is freed
* @card: sound card object
*
* This function is used to synchronize with the pending power_ref being
* released.
*/
static inline void snd_power_sync_ref(struct snd_card *card)
{
wait_event(card->power_ref_sleep, !atomic_read(&card->power_ref));
}
/* init.c */
int snd_power_wait(struct snd_card *card, unsigned int power_state);
int snd_power_wait(struct snd_card *card);
int snd_power_ref_and_wait(struct snd_card *card);
#else /* ! CONFIG_PM */
static inline int snd_power_wait(struct snd_card *card, unsigned int state) { return 0; }
static inline int snd_power_wait(struct snd_card *card) { return 0; }
static inline void snd_power_ref(struct snd_card *card) {}
static inline void snd_power_unref(struct snd_card *card) {}
static inline int snd_power_ref_and_wait(struct snd_card *card) { return 0; }
static inline void snd_power_sync_ref(struct snd_card *card) {}
#define snd_power_get_state(card) ({ (void)(card); SNDRV_CTL_POWER_D0; })
#define snd_power_change_state(card, state) do { (void)(card); } while (0)

View File

@ -65,12 +65,22 @@ struct hdmi_codec_ops {
/*
* Configures HDMI-encoder for audio stream.
* Mandatory
* Having either prepare or hw_params is mandatory.
*/
int (*hw_params)(struct device *dev, void *data,
struct hdmi_codec_daifmt *fmt,
struct hdmi_codec_params *hparms);
/*
* Configures HDMI-encoder for audio stream. Can be called
* multiple times for each setup.
*
* Having either prepare or hw_params is mandatory.
*/
int (*prepare)(struct device *dev, void *data,
struct hdmi_codec_daifmt *fmt,
struct hdmi_codec_params *hparms);
/*
* Shuts down the audio stream.
* Mandatory

View File

@ -12,6 +12,7 @@
#include <asm/page.h>
struct device;
struct vm_area_struct;
/*
* buffer device info
@ -64,84 +65,19 @@ static inline unsigned int snd_sgbuf_aligned_pages(size_t size)
return (size + PAGE_SIZE - 1) >> PAGE_SHIFT;
}
#ifdef CONFIG_SND_DMA_SGBUF
/*
* Scatter-Gather generic device pages
*/
void *snd_malloc_sgbuf_pages(struct device *device,
size_t size, struct snd_dma_buffer *dmab,
size_t *res_size);
int snd_free_sgbuf_pages(struct snd_dma_buffer *dmab);
struct snd_sg_page {
void *buf;
dma_addr_t addr;
};
struct snd_sg_buf {
int size; /* allocated byte size */
int pages; /* allocated pages */
int tblsize; /* allocated table size */
struct snd_sg_page *table; /* address table */
struct page **page_table; /* page table (for vmap/vunmap) */
struct device *dev;
};
/*
* return the physical address at the corresponding offset
*/
static inline dma_addr_t snd_sgbuf_get_addr(struct snd_dma_buffer *dmab,
size_t offset)
{
struct snd_sg_buf *sgbuf = dmab->private_data;
dma_addr_t addr;
if (!sgbuf)
return dmab->addr + offset;
addr = sgbuf->table[offset >> PAGE_SHIFT].addr;
addr &= ~((dma_addr_t)PAGE_SIZE - 1);
return addr + offset % PAGE_SIZE;
}
/*
* return the virtual address at the corresponding offset
*/
static inline void *snd_sgbuf_get_ptr(struct snd_dma_buffer *dmab,
size_t offset)
{
struct snd_sg_buf *sgbuf = dmab->private_data;
if (!sgbuf)
return dmab->area + offset;
return sgbuf->table[offset >> PAGE_SHIFT].buf + offset % PAGE_SIZE;
}
unsigned int snd_sgbuf_get_chunk_size(struct snd_dma_buffer *dmab,
unsigned int ofs, unsigned int size);
#else
/* non-SG versions */
static inline dma_addr_t snd_sgbuf_get_addr(struct snd_dma_buffer *dmab,
size_t offset)
{
return dmab->addr + offset;
}
static inline void *snd_sgbuf_get_ptr(struct snd_dma_buffer *dmab,
size_t offset)
{
return dmab->area + offset;
}
#define snd_sgbuf_get_chunk_size(dmab, ofs, size) (size)
#endif /* CONFIG_SND_DMA_SGBUF */
/* allocate/release a buffer */
int snd_dma_alloc_pages(int type, struct device *dev, size_t size,
struct snd_dma_buffer *dmab);
int snd_dma_alloc_pages_fallback(int type, struct device *dev, size_t size,
struct snd_dma_buffer *dmab);
void snd_dma_free_pages(struct snd_dma_buffer *dmab);
int snd_dma_buffer_mmap(struct snd_dma_buffer *dmab,
struct vm_area_struct *area);
dma_addr_t snd_sgbuf_get_addr(struct snd_dma_buffer *dmab, size_t offset);
struct page *snd_sgbuf_get_page(struct snd_dma_buffer *dmab, size_t offset);
unsigned int snd_sgbuf_get_chunk_size(struct snd_dma_buffer *dmab,
unsigned int ofs, unsigned int size);
#endif /* __SOUND_MEMALLOC_H */

View File

@ -1066,6 +1066,7 @@ void snd_pcm_set_ops(struct snd_pcm * pcm, int direction,
void snd_pcm_set_sync(struct snd_pcm_substream *substream);
int snd_pcm_lib_ioctl(struct snd_pcm_substream *substream,
unsigned int cmd, void *arg);
void snd_pcm_period_elapsed_under_stream_lock(struct snd_pcm_substream *substream);
void snd_pcm_period_elapsed(struct snd_pcm_substream *substream);
snd_pcm_sframes_t __snd_pcm_lib_xfer(struct snd_pcm_substream *substream,
void *buf, bool interleaved,
@ -1253,14 +1254,6 @@ static inline int snd_pcm_lib_alloc_vmalloc_32_buffer
#define snd_pcm_get_dma_buf(substream) ((substream)->runtime->dma_buffer_p)
#ifdef CONFIG_SND_DMA_SGBUF
/*
* SG-buffer handling
*/
#define snd_pcm_substream_sgbuf(substream) \
snd_pcm_get_dma_buf(substream)->private_data
#endif /* SND_DMA_SGBUF */
/**
* snd_pcm_sgbuf_get_addr - Get the DMA address at the corresponding offset
* @substream: PCM substream
@ -1272,17 +1265,6 @@ snd_pcm_sgbuf_get_addr(struct snd_pcm_substream *substream, unsigned int ofs)
return snd_sgbuf_get_addr(snd_pcm_get_dma_buf(substream), ofs);
}
/**
* snd_pcm_sgbuf_get_ptr - Get the virtual address at the corresponding offset
* @substream: PCM substream
* @ofs: byte offset
*/
static inline void *
snd_pcm_sgbuf_get_ptr(struct snd_pcm_substream *substream, unsigned int ofs)
{
return snd_sgbuf_get_ptr(snd_pcm_get_dma_buf(substream), ofs);
}
/**
* snd_pcm_sgbuf_get_chunk_size - Compute the max size that fits within the
* contig. page from the given size

View File

@ -4,6 +4,14 @@
#include <linux/types.h>
int snd_pcm_create_iec958_consumer_default(u8 *cs, size_t len);
int snd_pcm_fill_iec958_consumer(struct snd_pcm_runtime *runtime, u8 *cs,
size_t len);
int snd_pcm_fill_iec958_consumer_hw_params(struct snd_pcm_hw_params *params,
u8 *cs, size_t len);
int snd_pcm_create_iec958_consumer(struct snd_pcm_runtime *runtime, u8 *cs,
size_t len);

View File

@ -81,6 +81,8 @@ struct snd_rawmidi_substream {
bool opened; /* open flag */
bool append; /* append flag (merge more streams) */
bool active_sensing; /* send active sensing when close */
unsigned int framing; /* whether to frame input data */
unsigned int clock_type; /* clock source to use for input framing */
int use_count; /* use counter (for output) */
size_t bytes;
struct snd_rawmidi *rmidi;

View File

@ -36,6 +36,22 @@ struct snd_compr_stream;
#define SND_SOC_DAIFMT_MSB SND_SOC_DAIFMT_LEFT_J
#define SND_SOC_DAIFMT_LSB SND_SOC_DAIFMT_RIGHT_J
/* Describes the possible PCM format */
/*
* use SND_SOC_DAI_FORMAT_xx as eash shift.
* see
* snd_soc_runtime_get_dai_fmt()
*/
#define SND_SOC_POSSIBLE_DAIFMT_FORMAT_SHIFT 0
#define SND_SOC_POSSIBLE_DAIFMT_FORMAT_MASK (0xFFFF << SND_SOC_POSSIBLE_DAIFMT_FORMAT_SHIFT)
#define SND_SOC_POSSIBLE_DAIFMT_I2S (1 << SND_SOC_DAI_FORMAT_I2S)
#define SND_SOC_POSSIBLE_DAIFMT_RIGHT_J (1 << SND_SOC_DAI_FORMAT_RIGHT_J)
#define SND_SOC_POSSIBLE_DAIFMT_LEFT_J (1 << SND_SOC_DAI_FORMAT_LEFT_J)
#define SND_SOC_POSSIBLE_DAIFMT_DSP_A (1 << SND_SOC_DAI_FORMAT_DSP_A)
#define SND_SOC_POSSIBLE_DAIFMT_DSP_B (1 << SND_SOC_DAI_FORMAT_DSP_B)
#define SND_SOC_POSSIBLE_DAIFMT_AC97 (1 << SND_SOC_DAI_FORMAT_AC97)
#define SND_SOC_POSSIBLE_DAIFMT_PDM (1 << SND_SOC_DAI_FORMAT_PDM)
/*
* DAI Clock gating.
*
@ -45,6 +61,17 @@ struct snd_compr_stream;
#define SND_SOC_DAIFMT_CONT (1 << 4) /* continuous clock */
#define SND_SOC_DAIFMT_GATED (0 << 4) /* clock is gated */
/* Describes the possible PCM format */
/*
* define GATED -> CONT. GATED will be selected if both are selected.
* see
* snd_soc_runtime_get_dai_fmt()
*/
#define SND_SOC_POSSIBLE_DAIFMT_CLOCK_SHIFT 16
#define SND_SOC_POSSIBLE_DAIFMT_CLOCK_MASK (0xFFFF << SND_SOC_POSSIBLE_DAIFMT_CLOCK_SHIFT)
#define SND_SOC_POSSIBLE_DAIFMT_GATED (0x1ULL << SND_SOC_POSSIBLE_DAIFMT_CLOCK_SHIFT)
#define SND_SOC_POSSIBLE_DAIFMT_CONT (0x2ULL << SND_SOC_POSSIBLE_DAIFMT_CLOCK_SHIFT)
/*
* DAI hardware signal polarity.
*
@ -71,6 +98,14 @@ struct snd_compr_stream;
#define SND_SOC_DAIFMT_IB_NF (3 << 8) /* invert BCLK + nor FRM */
#define SND_SOC_DAIFMT_IB_IF (4 << 8) /* invert BCLK + FRM */
/* Describes the possible PCM format */
#define SND_SOC_POSSIBLE_DAIFMT_INV_SHIFT 32
#define SND_SOC_POSSIBLE_DAIFMT_INV_MASK (0xFFFFULL << SND_SOC_POSSIBLE_DAIFMT_INV_SHIFT)
#define SND_SOC_POSSIBLE_DAIFMT_NB_NF (0x1ULL << SND_SOC_POSSIBLE_DAIFMT_INV_SHIFT)
#define SND_SOC_POSSIBLE_DAIFMT_NB_IF (0x2ULL << SND_SOC_POSSIBLE_DAIFMT_INV_SHIFT)
#define SND_SOC_POSSIBLE_DAIFMT_IB_NF (0x4ULL << SND_SOC_POSSIBLE_DAIFMT_INV_SHIFT)
#define SND_SOC_POSSIBLE_DAIFMT_IB_IF (0x8ULL << SND_SOC_POSSIBLE_DAIFMT_INV_SHIFT)
/*
* DAI hardware clock providers/consumers
*
@ -89,6 +124,14 @@ struct snd_compr_stream;
#define SND_SOC_DAIFMT_CBM_CFS SND_SOC_DAIFMT_CBP_CFC
#define SND_SOC_DAIFMT_CBS_CFS SND_SOC_DAIFMT_CBC_CFC
/* Describes the possible PCM format */
#define SND_SOC_POSSIBLE_DAIFMT_CLOCK_PROVIDER_SHIFT 48
#define SND_SOC_POSSIBLE_DAIFMT_CLOCK_PROVIDER_MASK (0xFFFFULL << SND_SOC_POSSIBLE_DAIFMT_CLOCK_PROVIDER_SHIFT)
#define SND_SOC_POSSIBLE_DAIFMT_CBP_CFP (0x1ULL << SND_SOC_POSSIBLE_DAIFMT_CLOCK_PROVIDER_SHIFT)
#define SND_SOC_POSSIBLE_DAIFMT_CBC_CFP (0x2ULL << SND_SOC_POSSIBLE_DAIFMT_CLOCK_PROVIDER_SHIFT)
#define SND_SOC_POSSIBLE_DAIFMT_CBP_CFC (0x4ULL << SND_SOC_POSSIBLE_DAIFMT_CLOCK_PROVIDER_SHIFT)
#define SND_SOC_POSSIBLE_DAIFMT_CBC_CFC (0x8ULL << SND_SOC_POSSIBLE_DAIFMT_CLOCK_PROVIDER_SHIFT)
#define SND_SOC_DAIFMT_FORMAT_MASK 0x000f
#define SND_SOC_DAIFMT_CLOCK_MASK 0x00f0
#define SND_SOC_DAIFMT_INV_MASK 0x0f00
@ -131,6 +174,8 @@ int snd_soc_dai_set_pll(struct snd_soc_dai *dai,
int snd_soc_dai_set_bclk_ratio(struct snd_soc_dai *dai, unsigned int ratio);
/* Digital Audio interface formatting */
int snd_soc_dai_get_fmt_max_priority(struct snd_soc_pcm_runtime *rtd);
u64 snd_soc_dai_get_fmt(struct snd_soc_dai *dai, int priority);
int snd_soc_dai_set_fmt(struct snd_soc_dai *dai, unsigned int fmt);
int snd_soc_dai_set_tdm_slot(struct snd_soc_dai *dai,
@ -292,6 +337,16 @@ struct snd_soc_dai_ops {
snd_pcm_sframes_t (*delay)(struct snd_pcm_substream *,
struct snd_soc_dai *);
/*
* Format list for auto selection.
* Format will be increased if priority format was
* not selected.
* see
* snd_soc_dai_get_fmt()
*/
u64 *auto_selectable_formats;
int num_auto_selectable_formats;
/* bit field */
unsigned int no_capture_mute:1;
};

View File

@ -54,7 +54,7 @@ struct snd_soc_dobj_control {
/* dynamic widget object */
struct snd_soc_dobj_widget {
unsigned int kcontrol_type; /* kcontrol type: mixer, enum, bytes */
unsigned int *kcontrol_type; /* kcontrol type: mixer, enum, bytes */
};
/* generic dynamic object - all dynamic objects belong to this struct */

View File

@ -1232,10 +1232,23 @@ void snd_soc_of_parse_audio_prefix(struct snd_soc_card *card,
int snd_soc_of_parse_audio_routing(struct snd_soc_card *card,
const char *propname);
int snd_soc_of_parse_aux_devs(struct snd_soc_card *card, const char *propname);
unsigned int snd_soc_of_parse_daifmt(struct device_node *np,
const char *prefix,
struct device_node **bitclkmaster,
struct device_node **framemaster);
unsigned int snd_soc_daifmt_clock_provider_fliped(unsigned int dai_fmt);
unsigned int snd_soc_daifmt_clock_provider_from_bitmap(unsigned int bit_frame);
unsigned int snd_soc_daifmt_parse_format(struct device_node *np, const char *prefix);
unsigned int snd_soc_daifmt_parse_clock_provider_raw(struct device_node *np,
const char *prefix,
struct device_node **bitclkmaster,
struct device_node **framemaster);
#define snd_soc_daifmt_parse_clock_provider_as_bitmap(np, prefix) \
snd_soc_daifmt_parse_clock_provider_raw(np, prefix, NULL, NULL)
#define snd_soc_daifmt_parse_clock_provider_as_phandle \
snd_soc_daifmt_parse_clock_provider_raw
#define snd_soc_daifmt_parse_clock_provider_as_flag(np, prefix) \
snd_soc_daifmt_clock_provider_from_bitmap( \
snd_soc_daifmt_parse_clock_provider_as_bitmap(np, prefix))
int snd_soc_get_dai_id(struct device_node *ep);
int snd_soc_get_dai_name(const struct of_phandle_args *args,
const char **dai_name);

View File

@ -710,7 +710,7 @@ enum {
* Raw MIDI section - /dev/snd/midi??
*/
#define SNDRV_RAWMIDI_VERSION SNDRV_PROTOCOL_VERSION(2, 0, 1)
#define SNDRV_RAWMIDI_VERSION SNDRV_PROTOCOL_VERSION(2, 0, 2)
enum {
SNDRV_RAWMIDI_STREAM_OUTPUT = 0,
@ -736,12 +736,38 @@ struct snd_rawmidi_info {
unsigned char reserved[64]; /* reserved for future use */
};
#define SNDRV_RAWMIDI_MODE_FRAMING_MASK (7<<0)
#define SNDRV_RAWMIDI_MODE_FRAMING_SHIFT 0
#define SNDRV_RAWMIDI_MODE_FRAMING_NONE (0<<0)
#define SNDRV_RAWMIDI_MODE_FRAMING_TSTAMP (1<<0)
#define SNDRV_RAWMIDI_MODE_CLOCK_MASK (7<<3)
#define SNDRV_RAWMIDI_MODE_CLOCK_SHIFT 3
#define SNDRV_RAWMIDI_MODE_CLOCK_NONE (0<<3)
#define SNDRV_RAWMIDI_MODE_CLOCK_REALTIME (1<<3)
#define SNDRV_RAWMIDI_MODE_CLOCK_MONOTONIC (2<<3)
#define SNDRV_RAWMIDI_MODE_CLOCK_MONOTONIC_RAW (3<<3)
#define SNDRV_RAWMIDI_FRAMING_DATA_LENGTH 16
struct snd_rawmidi_framing_tstamp {
/* For now, frame_type is always 0. Midi 2.0 is expected to add new
* types here. Applications are expected to skip unknown frame types.
*/
__u8 frame_type;
__u8 length; /* number of valid bytes in data field */
__u8 reserved[2];
__u32 tv_nsec; /* nanoseconds */
__u64 tv_sec; /* seconds */
__u8 data[SNDRV_RAWMIDI_FRAMING_DATA_LENGTH];
} __packed;
struct snd_rawmidi_params {
int stream;
size_t buffer_size; /* queue size in bytes */
size_t avail_min; /* minimum avail bytes for wakeup */
unsigned int no_active_sensing: 1; /* do not send active sensing byte in close() */
unsigned char reserved[16]; /* reserved for future use */
unsigned int mode; /* For input data only, frame incoming data */
unsigned char reserved[12]; /* reserved for future use */
};
#ifndef __KERNEL__

View File

@ -520,7 +520,7 @@ static int ac97_bus_remove(struct device *dev)
struct ac97_codec_driver *adrv = to_ac97_driver(dev->driver);
int ret;
ret = pm_runtime_get_sync(dev);
ret = pm_runtime_resume_and_get(dev);
if (ret < 0)
return ret;

View File

@ -918,10 +918,8 @@ i2sbus_attach_codec(struct soundbus_dev *dev, struct snd_card *card,
}
cii = kzalloc(sizeof(struct codec_info_item), GFP_KERNEL);
if (!cii) {
printk(KERN_DEBUG "i2sbus: failed to allocate cii\n");
if (!cii)
return -ENOMEM;
}
/* use the private data to point to the codec info */
cii->sdev = soundbus_dev_get(dev);

View File

@ -47,9 +47,7 @@ static unsigned short pxa2xx_ac97_legacy_read(struct snd_ac97 *ac97,
static void pxa2xx_ac97_legacy_write(struct snd_ac97 *ac97,
unsigned short reg, unsigned short val)
{
int __always_unused ret;
ret = pxa2xx_ac97_write(ac97->num, reg, val);
pxa2xx_ac97_write(ac97->num, reg, val);
}
static const struct snd_ac97_bus_ops pxa2xx_ac97_ops = {

View File

@ -995,7 +995,10 @@ static int __snd_ctl_elem_info(struct snd_card *card,
#ifdef CONFIG_SND_DEBUG
info->access = 0;
#endif
result = kctl->info(kctl, info);
result = snd_power_ref_and_wait(card);
if (!result)
result = kctl->info(kctl, info);
snd_power_unref(card);
if (result >= 0) {
snd_BUG_ON(info->access);
index_offset = snd_ctl_get_ioff(kctl, &info->id);
@ -1042,9 +1045,6 @@ static int snd_ctl_elem_info_user(struct snd_ctl_file *ctl,
if (copy_from_user(&info, _info, sizeof(info)))
return -EFAULT;
result = snd_power_wait(ctl->card, SNDRV_CTL_POWER_D0);
if (result < 0)
return result;
result = snd_ctl_elem_info(ctl, &info);
if (result < 0)
return result;
@ -1088,7 +1088,10 @@ static int snd_ctl_elem_read(struct snd_card *card,
if (!snd_ctl_skip_validation(&info))
fill_remaining_elem_value(control, &info, pattern);
ret = kctl->get(kctl, control);
ret = snd_power_ref_and_wait(card);
if (!ret)
ret = kctl->get(kctl, control);
snd_power_unref(card);
if (ret < 0)
return ret;
if (!snd_ctl_skip_validation(&info) &&
@ -1113,10 +1116,6 @@ static int snd_ctl_elem_read_user(struct snd_card *card,
if (IS_ERR(control))
return PTR_ERR(control);
result = snd_power_wait(card, SNDRV_CTL_POWER_D0);
if (result < 0)
goto error;
down_read(&card->controls_rwsem);
result = snd_ctl_elem_read(card, control);
up_read(&card->controls_rwsem);
@ -1154,7 +1153,10 @@ static int snd_ctl_elem_write(struct snd_card *card, struct snd_ctl_file *file,
}
snd_ctl_build_ioff(&control->id, kctl, index_offset);
result = kctl->put(kctl, control);
result = snd_power_ref_and_wait(card);
if (!result)
result = kctl->put(kctl, control);
snd_power_unref(card);
if (result < 0) {
up_write(&card->controls_rwsem);
return result;
@ -1183,10 +1185,6 @@ static int snd_ctl_elem_write_user(struct snd_ctl_file *file,
return PTR_ERR(control);
card = file->card;
result = snd_power_wait(card, SNDRV_CTL_POWER_D0);
if (result < 0)
goto error;
result = snd_ctl_elem_write(card, file, control);
if (result < 0)
goto error;
@ -1669,7 +1667,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},
};
struct snd_kcontrol_volatile *vd = &kctl->vd[snd_ctl_get_ioff(kctl, id)];
int i;
int i, ret;
/* Check support of the request for this element. */
for (i = 0; i < ARRAY_SIZE(pairs); ++i) {
@ -1687,7 +1685,11 @@ static int call_tlv_handler(struct snd_ctl_file *file, int op_flag,
vd->owner != NULL && vd->owner != file)
return -EPERM;
return kctl->tlv.c(kctl, op_flag, size, buf);
ret = snd_power_ref_and_wait(file->card);
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,
@ -1815,11 +1817,7 @@ static long snd_ctl_ioctl(struct file *file, unsigned int cmd, unsigned long arg
case SNDRV_CTL_IOCTL_POWER:
return -ENOPROTOOPT;
case SNDRV_CTL_IOCTL_POWER_STATE:
#ifdef CONFIG_PM
return put_user(card->power_state, ip) ? -EFAULT : 0;
#else
return put_user(SNDRV_CTL_POWER_D0, ip) ? -EFAULT : 0;
#endif
}
down_read(&snd_ioctl_rwsem);
list_for_each_entry(p, &snd_control_ioctls, list) {

View File

@ -96,9 +96,6 @@ static int snd_ctl_elem_info_compat(struct snd_ctl_file *ctl,
if (get_user(data->value.enumerated.item, &data32->value.enumerated.item))
goto error;
err = snd_power_wait(ctl->card, SNDRV_CTL_POWER_D0);
if (err < 0)
goto error;
err = snd_ctl_elem_info(ctl, data);
if (err < 0)
goto error;
@ -187,7 +184,10 @@ static int get_ctl_type(struct snd_card *card, struct snd_ctl_elem_id *id,
return -ENOMEM;
}
info->id = *id;
err = kctl->info(kctl, info);
err = snd_power_ref_and_wait(card);
if (!err)
err = kctl->info(kctl, info);
snd_power_unref(card);
up_read(&card->controls_rwsem);
if (err >= 0) {
err = info->type;
@ -298,9 +298,6 @@ static int ctl_elem_read_user(struct snd_card *card,
if (err < 0)
goto error;
err = snd_power_wait(card, SNDRV_CTL_POWER_D0);
if (err < 0)
goto error;
err = snd_ctl_elem_read(card, data);
if (err < 0)
goto error;
@ -326,9 +323,6 @@ static int ctl_elem_write_user(struct snd_ctl_file *file,
if (err < 0)
goto error;
err = snd_power_wait(card, SNDRV_CTL_POWER_D0);
if (err < 0)
goto error;
err = snd_ctl_elem_write(card, file, data);
if (err < 0)
goto error;

View File

@ -393,11 +393,11 @@ static void snd_ctl_led_dev_release(struct device *dev)
* sysfs
*/
static ssize_t show_mode(struct device *dev,
static ssize_t mode_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct snd_ctl_led *led = container_of(dev, struct snd_ctl_led, dev);
const char *str;
const char *str = NULL;
switch (led->mode) {
case MODE_FOLLOW_MUTE: str = "follow-mute"; break;
@ -408,7 +408,8 @@ static ssize_t show_mode(struct device *dev,
return sprintf(buf, "%s\n", str);
}
static ssize_t store_mode(struct device *dev, struct device_attribute *attr,
static ssize_t mode_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
{
struct snd_ctl_led *led = container_of(dev, struct snd_ctl_led, dev);
@ -437,7 +438,7 @@ static ssize_t store_mode(struct device *dev, struct device_attribute *attr,
return count;
}
static ssize_t show_brightness(struct device *dev,
static ssize_t brightness_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct snd_ctl_led *led = container_of(dev, struct snd_ctl_led, dev);
@ -445,8 +446,8 @@ static ssize_t show_brightness(struct device *dev,
return sprintf(buf, "%u\n", ledtrig_audio_get(led->trigger_type));
}
static DEVICE_ATTR(mode, 0644, show_mode, store_mode);
static DEVICE_ATTR(brightness, 0444, show_brightness, NULL);
static DEVICE_ATTR_RW(mode);
static DEVICE_ATTR_RO(brightness);
static struct attribute *snd_ctl_led_dev_attrs[] = {
&dev_attr_mode.attr,
@ -580,22 +581,25 @@ static ssize_t set_led_id(struct snd_ctl_led_card *led_card, const char *buf, si
return count;
}
static ssize_t parse_attach(struct device *dev, struct device_attribute *attr,
static ssize_t attach_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
{
struct snd_ctl_led_card *led_card = container_of(dev, struct snd_ctl_led_card, dev);
return set_led_id(led_card, buf, count, true);
}
static ssize_t parse_detach(struct device *dev, struct device_attribute *attr,
static ssize_t detach_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
{
struct snd_ctl_led_card *led_card = container_of(dev, struct snd_ctl_led_card, dev);
return set_led_id(led_card, buf, count, false);
}
static ssize_t ctl_reset(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
static ssize_t reset_store(struct device *dev,
struct device_attribute *attr,
const char *buf, size_t count)
{
struct snd_ctl_led_card *led_card = container_of(dev, struct snd_ctl_led_card, dev);
int err;
@ -608,8 +612,8 @@ static ssize_t ctl_reset(struct device *dev, struct device_attribute *attr,
return count;
}
static ssize_t ctl_list(struct device *dev,
struct device_attribute *attr, char *buf)
static ssize_t list_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct snd_ctl_led_card *led_card = container_of(dev, struct snd_ctl_led_card, dev);
struct snd_card *card;
@ -642,10 +646,10 @@ static ssize_t ctl_list(struct device *dev,
return buf2 - buf;
}
static DEVICE_ATTR(attach, 0200, NULL, parse_attach);
static DEVICE_ATTR(detach, 0200, NULL, parse_detach);
static DEVICE_ATTR(reset, 0200, NULL, ctl_reset);
static DEVICE_ATTR(list, 0444, ctl_list, NULL);
static DEVICE_ATTR_WO(attach);
static DEVICE_ATTR_WO(detach);
static DEVICE_ATTR_WO(reset);
static DEVICE_ATTR_RO(list);
static struct attribute *snd_ctl_led_card_attrs[] = {
&dev_attr_attach.attr,

View File

@ -195,7 +195,8 @@ static int snd_hwdep_dsp_status(struct snd_hwdep *hw,
return -ENXIO;
memset(&info, 0, sizeof(info));
info.dsp_loaded = hw->dsp_loaded;
if ((err = hw->ops.dsp_status(hw, &info)) < 0)
err = hw->ops.dsp_status(hw, &info);
if (err < 0)
return err;
if (copy_to_user(_info, &info, sizeof(info)))
return -EFAULT;
@ -500,7 +501,8 @@ static void __init snd_hwdep_proc_init(void)
{
struct snd_info_entry *entry;
if ((entry = snd_info_create_module_entry(THIS_MODULE, "hwdep", NULL)) != NULL) {
entry = snd_info_create_module_entry(THIS_MODULE, "hwdep", NULL);
if (entry) {
entry->c.text.read = snd_hwdep_proc_read;
if (snd_info_register(entry) < 0) {
snd_info_free_entry(entry);

View File

@ -31,7 +31,8 @@ int snd_oss_info_register(int dev, int num, char *string)
return -ENXIO;
mutex_lock(&strings);
if (string == NULL) {
if ((x = snd_sndstat_strings[num][dev]) != NULL) {
x = snd_sndstat_strings[num][dev];
if (x) {
kfree(x);
x = NULL;
}

View File

@ -220,6 +220,8 @@ int snd_card_new(struct device *parent, int idx, const char *xid,
mutex_init(&card->memory_mutex);
#ifdef CONFIG_PM
init_waitqueue_head(&card->power_sleep);
init_waitqueue_head(&card->power_ref_sleep);
atomic_set(&card->power_ref, 0);
#endif
init_waitqueue_head(&card->remove_sleep);
card->sync_irq = -1;
@ -442,6 +444,7 @@ int snd_card_disconnect(struct snd_card *card)
#ifdef CONFIG_PM
wake_up(&card->power_sleep);
snd_power_sync_ref(card);
#endif
return 0;
}
@ -662,17 +665,15 @@ void snd_card_set_id(struct snd_card *card, const char *nid)
}
EXPORT_SYMBOL(snd_card_set_id);
static ssize_t
card_id_show_attr(struct device *dev,
struct device_attribute *attr, char *buf)
static ssize_t id_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct snd_card *card = container_of(dev, struct snd_card, card_dev);
return scnprintf(buf, PAGE_SIZE, "%s\n", card->id);
}
static ssize_t
card_id_store_attr(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
static ssize_t id_store(struct device *dev, struct device_attribute *attr,
const char *buf, size_t count)
{
struct snd_card *card = container_of(dev, struct snd_card, card_dev);
char buf1[sizeof(card->id)];
@ -700,17 +701,16 @@ card_id_store_attr(struct device *dev, struct device_attribute *attr,
return count;
}
static DEVICE_ATTR(id, 0644, card_id_show_attr, card_id_store_attr);
static DEVICE_ATTR_RW(id);
static ssize_t
card_number_show_attr(struct device *dev,
struct device_attribute *attr, char *buf)
static ssize_t number_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct snd_card *card = container_of(dev, struct snd_card, card_dev);
return scnprintf(buf, PAGE_SIZE, "%i\n", card->number);
}
static DEVICE_ATTR(number, 0444, card_number_show_attr, NULL);
static DEVICE_ATTR_RO(number);
static struct attribute *card_dev_attrs[] = {
&dev_attr_id.attr,
@ -770,7 +770,8 @@ int snd_card_register(struct snd_card *card)
card->registered = true;
}
if ((err = snd_device_register_all(card)) < 0)
err = snd_device_register_all(card);
if (err < 0)
return err;
mutex_lock(&snd_card_mutex);
if (snd_cards[card->number]) {
@ -813,7 +814,8 @@ static void snd_card_info_read(struct snd_info_entry *entry,
for (idx = count = 0; idx < SNDRV_CARDS; idx++) {
mutex_lock(&snd_card_mutex);
if ((card = snd_cards[idx]) != NULL) {
card = snd_cards[idx];
if (card) {
count++;
snd_iprintf(buffer, "%2i [%-15s]: %s - %s\n",
idx,
@ -837,7 +839,8 @@ void snd_card_info_read_oss(struct snd_info_buffer *buffer)
for (idx = count = 0; idx < SNDRV_CARDS; idx++) {
mutex_lock(&snd_card_mutex);
if ((card = snd_cards[idx]) != NULL) {
card = snd_cards[idx];
if (card) {
count++;
snd_iprintf(buffer, "%s\n", card->longname);
}
@ -859,7 +862,8 @@ static void snd_card_module_info_read(struct snd_info_entry *entry,
for (idx = 0; idx < SNDRV_CARDS; idx++) {
mutex_lock(&snd_card_mutex);
if ((card = snd_cards[idx]) != NULL)
card = snd_cards[idx];
if (card)
snd_iprintf(buffer, "%2i %s\n",
idx, card->module->name);
mutex_unlock(&snd_card_mutex);
@ -1002,21 +1006,28 @@ EXPORT_SYMBOL(snd_card_file_remove);
#ifdef CONFIG_PM
/**
* snd_power_wait - wait until the power-state is changed.
* @card: soundcard structure
* @power_state: expected power state
* snd_power_ref_and_wait - wait until the card gets powered up
* @card: soundcard structure
*
* Waits until the power-state is changed.
* Take the power_ref reference count of the given card, and
* wait until the card gets powered up to SNDRV_CTL_POWER_D0 state.
* The refcount is down again while sleeping until power-up, hence this
* function can be used for syncing the floating control ops accesses,
* typically around calling control ops.
*
* Return: Zero if successful, or a negative error code.
* The caller needs to pull down the refcount via snd_power_unref() later
* no matter whether the error is returned from this function or not.
*
* Return: Zero if successful, or a negative error code.
*/
int snd_power_wait(struct snd_card *card, unsigned int power_state)
int snd_power_ref_and_wait(struct snd_card *card)
{
wait_queue_entry_t wait;
int result = 0;
snd_power_ref(card);
/* fastpath */
if (snd_power_get_state(card) == power_state)
if (snd_power_get_state(card) == SNDRV_CTL_POWER_D0)
return 0;
init_waitqueue_entry(&wait, current);
add_wait_queue(&card->power_sleep, &wait);
@ -1025,13 +1036,33 @@ int snd_power_wait(struct snd_card *card, unsigned int power_state)
result = -ENODEV;
break;
}
if (snd_power_get_state(card) == power_state)
if (snd_power_get_state(card) == SNDRV_CTL_POWER_D0)
break;
snd_power_unref(card);
set_current_state(TASK_UNINTERRUPTIBLE);
schedule_timeout(30 * HZ);
snd_power_ref(card);
}
remove_wait_queue(&card->power_sleep, &wait);
return result;
}
EXPORT_SYMBOL_GPL(snd_power_ref_and_wait);
/**
* snd_power_wait - wait until the card gets powered up (old form)
* @card: soundcard structure
*
* Wait until the card gets powered up to SNDRV_CTL_POWER_D0 state.
*
* Return: Zero if successful, or a negative error code.
*/
int snd_power_wait(struct snd_card *card)
{
int ret;
ret = snd_power_ref_and_wait(card);
snd_power_unref(card);
return ret;
}
EXPORT_SYMBOL(snd_power_wait);
#endif /* CONFIG_PM */

View File

@ -15,99 +15,27 @@
#include <asm/set_memory.h>
#endif
#include <sound/memalloc.h>
#include "memalloc_local.h"
/*
*
* Bus-specific memory allocators
*
*/
static const struct snd_malloc_ops *snd_dma_get_ops(struct snd_dma_buffer *dmab);
#ifdef CONFIG_HAS_DMA
/* allocate the coherent DMA pages */
static void snd_malloc_dev_pages(struct snd_dma_buffer *dmab, size_t size)
{
gfp_t gfp_flags;
gfp_flags = GFP_KERNEL
| __GFP_COMP /* compound page lets parts be mapped */
| __GFP_NORETRY /* don't trigger OOM-killer */
| __GFP_NOWARN; /* no stack trace print - this call is non-critical */
dmab->area = dma_alloc_coherent(dmab->dev.dev, size, &dmab->addr,
gfp_flags);
#ifdef CONFIG_X86
if (dmab->area && dmab->dev.type == SNDRV_DMA_TYPE_DEV_UC)
set_memory_wc((unsigned long)dmab->area,
PAGE_ALIGN(size) >> PAGE_SHIFT);
#endif
}
/* free the coherent DMA pages */
static void snd_free_dev_pages(struct snd_dma_buffer *dmab)
{
#ifdef CONFIG_X86
if (dmab->dev.type == SNDRV_DMA_TYPE_DEV_UC)
set_memory_wb((unsigned long)dmab->area,
PAGE_ALIGN(dmab->bytes) >> PAGE_SHIFT);
#endif
dma_free_coherent(dmab->dev.dev, dmab->bytes, dmab->area, dmab->addr);
}
#ifdef CONFIG_GENERIC_ALLOCATOR
/**
* snd_malloc_dev_iram - allocate memory from on-chip internal ram
* @dmab: buffer allocation record to store the allocated data
* @size: number of bytes to allocate from the iram
*
* This function requires iram phandle provided via of_node
*/
static void snd_malloc_dev_iram(struct snd_dma_buffer *dmab, size_t size)
{
struct device *dev = dmab->dev.dev;
struct gen_pool *pool = NULL;
dmab->area = NULL;
dmab->addr = 0;
if (dev->of_node)
pool = of_gen_pool_get(dev->of_node, "iram", 0);
if (!pool)
return;
/* Assign the pool into private_data field */
dmab->private_data = pool;
dmab->area = gen_pool_dma_alloc_align(pool, size, &dmab->addr,
PAGE_SIZE);
}
/**
* snd_free_dev_iram - free allocated specific memory from on-chip internal ram
* @dmab: buffer allocation record to store the allocated data
*/
static void snd_free_dev_iram(struct snd_dma_buffer *dmab)
{
struct gen_pool *pool = dmab->private_data;
if (pool && dmab->area)
gen_pool_free(pool, (unsigned long)dmab->area, dmab->bytes);
}
#endif /* CONFIG_GENERIC_ALLOCATOR */
#endif /* CONFIG_HAS_DMA */
/*
*
* ALSA generic memory management
*
*/
static inline gfp_t snd_mem_get_gfp_flags(const struct device *dev,
/* a cast to gfp flag from the dev pointer; for CONTINUOUS and VMALLOC types */
static inline gfp_t snd_mem_get_gfp_flags(const struct snd_dma_buffer *dmab,
gfp_t default_gfp)
{
if (!dev)
if (!dmab->dev.dev)
return default_gfp;
else
return (__force gfp_t)(unsigned long)dev;
return (__force gfp_t)(unsigned long)dmab->dev.dev;
}
static int __snd_dma_alloc_pages(struct snd_dma_buffer *dmab, size_t size)
{
const struct snd_malloc_ops *ops = snd_dma_get_ops(dmab);
if (WARN_ON_ONCE(!ops || !ops->alloc))
return -EINVAL;
return ops->alloc(dmab, size);
}
/**
@ -126,7 +54,7 @@ static inline gfp_t snd_mem_get_gfp_flags(const struct device *dev,
int snd_dma_alloc_pages(int type, struct device *device, size_t size,
struct snd_dma_buffer *dmab)
{
gfp_t gfp;
int err;
if (WARN_ON(!size))
return -ENXIO;
@ -140,43 +68,10 @@ int snd_dma_alloc_pages(int type, struct device *device, size_t size,
dmab->area = NULL;
dmab->addr = 0;
dmab->private_data = NULL;
switch (type) {
case SNDRV_DMA_TYPE_CONTINUOUS:
gfp = snd_mem_get_gfp_flags(device, GFP_KERNEL);
dmab->area = alloc_pages_exact(size, gfp);
break;
case SNDRV_DMA_TYPE_VMALLOC:
gfp = snd_mem_get_gfp_flags(device, GFP_KERNEL | __GFP_HIGHMEM);
dmab->area = __vmalloc(size, gfp);
break;
#ifdef CONFIG_HAS_DMA
#ifdef CONFIG_GENERIC_ALLOCATOR
case SNDRV_DMA_TYPE_DEV_IRAM:
snd_malloc_dev_iram(dmab, size);
if (dmab->area)
break;
/* Internal memory might have limited size and no enough space,
* so if we fail to malloc, try to fetch memory traditionally.
*/
dmab->dev.type = SNDRV_DMA_TYPE_DEV;
fallthrough;
#endif /* CONFIG_GENERIC_ALLOCATOR */
case SNDRV_DMA_TYPE_DEV:
case SNDRV_DMA_TYPE_DEV_UC:
snd_malloc_dev_pages(dmab, size);
break;
#endif
#ifdef CONFIG_SND_DMA_SGBUF
case SNDRV_DMA_TYPE_DEV_SG:
case SNDRV_DMA_TYPE_DEV_UC_SG:
snd_malloc_sgbuf_pages(device, size, dmab, NULL);
break;
#endif
default:
pr_err("snd-malloc: invalid device type %d\n", type);
return -ENXIO;
}
if (! dmab->area)
err = __snd_dma_alloc_pages(dmab, size);
if (err < 0)
return err;
if (!dmab->area)
return -ENOMEM;
dmab->bytes = size;
return 0;
@ -217,7 +112,6 @@ int snd_dma_alloc_pages_fallback(int type, struct device *device, size_t size,
}
EXPORT_SYMBOL(snd_dma_alloc_pages_fallback);
/**
* snd_dma_free_pages - release the allocated buffer
* @dmab: the buffer allocation record to release
@ -226,32 +120,288 @@ EXPORT_SYMBOL(snd_dma_alloc_pages_fallback);
*/
void snd_dma_free_pages(struct snd_dma_buffer *dmab)
{
switch (dmab->dev.type) {
case SNDRV_DMA_TYPE_CONTINUOUS:
free_pages_exact(dmab->area, dmab->bytes);
break;
case SNDRV_DMA_TYPE_VMALLOC:
vfree(dmab->area);
break;
#ifdef CONFIG_HAS_DMA
#ifdef CONFIG_GENERIC_ALLOCATOR
case SNDRV_DMA_TYPE_DEV_IRAM:
snd_free_dev_iram(dmab);
break;
#endif /* CONFIG_GENERIC_ALLOCATOR */
case SNDRV_DMA_TYPE_DEV:
case SNDRV_DMA_TYPE_DEV_UC:
snd_free_dev_pages(dmab);
break;
#endif
#ifdef CONFIG_SND_DMA_SGBUF
case SNDRV_DMA_TYPE_DEV_SG:
case SNDRV_DMA_TYPE_DEV_UC_SG:
snd_free_sgbuf_pages(dmab);
break;
#endif
default:
pr_err("snd-malloc: invalid device type %d\n", dmab->dev.type);
}
const struct snd_malloc_ops *ops = snd_dma_get_ops(dmab);
if (ops && ops->free)
ops->free(dmab);
}
EXPORT_SYMBOL(snd_dma_free_pages);
/**
* snd_dma_buffer_mmap - perform mmap of the given DMA buffer
* @dmab: buffer allocation information
* @area: VM area information
*/
int snd_dma_buffer_mmap(struct snd_dma_buffer *dmab,
struct vm_area_struct *area)
{
const struct snd_malloc_ops *ops = snd_dma_get_ops(dmab);
if (ops && ops->mmap)
return ops->mmap(dmab, area);
else
return -ENOENT;
}
EXPORT_SYMBOL(snd_dma_buffer_mmap);
/**
* snd_sgbuf_get_addr - return the physical address at the corresponding offset
* @dmab: buffer allocation information
* @offset: offset in the ring buffer
*/
dma_addr_t snd_sgbuf_get_addr(struct snd_dma_buffer *dmab, size_t offset)
{
const struct snd_malloc_ops *ops = snd_dma_get_ops(dmab);
if (ops && ops->get_addr)
return ops->get_addr(dmab, offset);
else
return dmab->addr + offset;
}
EXPORT_SYMBOL(snd_sgbuf_get_addr);
/**
* snd_sgbuf_get_page - return the physical page at the corresponding offset
* @dmab: buffer allocation information
* @offset: offset in the ring buffer
*/
struct page *snd_sgbuf_get_page(struct snd_dma_buffer *dmab, size_t offset)
{
const struct snd_malloc_ops *ops = snd_dma_get_ops(dmab);
if (ops && ops->get_page)
return ops->get_page(dmab, offset);
else
return virt_to_page(dmab->area + offset);
}
EXPORT_SYMBOL(snd_sgbuf_get_page);
/**
* snd_sgbuf_get_chunk_size - compute the max chunk size with continuous pages
* on sg-buffer
* @dmab: buffer allocation information
* @ofs: offset in the ring buffer
* @size: the requested size
*/
unsigned int snd_sgbuf_get_chunk_size(struct snd_dma_buffer *dmab,
unsigned int ofs, unsigned int size)
{
const struct snd_malloc_ops *ops = snd_dma_get_ops(dmab);
if (ops && ops->get_chunk_size)
return ops->get_chunk_size(dmab, ofs, size);
else
return size;
}
EXPORT_SYMBOL(snd_sgbuf_get_chunk_size);
/*
* Continuous pages allocator
*/
static int snd_dma_continuous_alloc(struct snd_dma_buffer *dmab, size_t size)
{
gfp_t gfp = snd_mem_get_gfp_flags(dmab, GFP_KERNEL);
dmab->area = alloc_pages_exact(size, gfp);
return 0;
}
static void snd_dma_continuous_free(struct snd_dma_buffer *dmab)
{
free_pages_exact(dmab->area, dmab->bytes);
}
static int snd_dma_continuous_mmap(struct snd_dma_buffer *dmab,
struct vm_area_struct *area)
{
return remap_pfn_range(area, area->vm_start,
dmab->addr >> PAGE_SHIFT,
area->vm_end - area->vm_start,
area->vm_page_prot);
}
static const struct snd_malloc_ops snd_dma_continuous_ops = {
.alloc = snd_dma_continuous_alloc,
.free = snd_dma_continuous_free,
.mmap = snd_dma_continuous_mmap,
};
/*
* VMALLOC allocator
*/
static int snd_dma_vmalloc_alloc(struct snd_dma_buffer *dmab, size_t size)
{
gfp_t gfp = snd_mem_get_gfp_flags(dmab, GFP_KERNEL | __GFP_HIGHMEM);
dmab->area = __vmalloc(size, gfp);
return 0;
}
static void snd_dma_vmalloc_free(struct snd_dma_buffer *dmab)
{
vfree(dmab->area);
}
static int snd_dma_vmalloc_mmap(struct snd_dma_buffer *dmab,
struct vm_area_struct *area)
{
return remap_vmalloc_range(area, dmab->area, 0);
}
static dma_addr_t snd_dma_vmalloc_get_addr(struct snd_dma_buffer *dmab,
size_t offset)
{
return page_to_phys(vmalloc_to_page(dmab->area + offset)) +
offset % PAGE_SIZE;
}
static struct page *snd_dma_vmalloc_get_page(struct snd_dma_buffer *dmab,
size_t offset)
{
return vmalloc_to_page(dmab->area + offset);
}
static unsigned int
snd_dma_vmalloc_get_chunk_size(struct snd_dma_buffer *dmab,
unsigned int ofs, unsigned int size)
{
ofs %= PAGE_SIZE;
size += ofs;
if (size > PAGE_SIZE)
size = PAGE_SIZE;
return size - ofs;
}
static const struct snd_malloc_ops snd_dma_vmalloc_ops = {
.alloc = snd_dma_vmalloc_alloc,
.free = snd_dma_vmalloc_free,
.mmap = snd_dma_vmalloc_mmap,
.get_addr = snd_dma_vmalloc_get_addr,
.get_page = snd_dma_vmalloc_get_page,
.get_chunk_size = snd_dma_vmalloc_get_chunk_size,
};
#ifdef CONFIG_HAS_DMA
/*
* IRAM allocator
*/
#ifdef CONFIG_GENERIC_ALLOCATOR
static int snd_dma_iram_alloc(struct snd_dma_buffer *dmab, size_t size)
{
struct device *dev = dmab->dev.dev;
struct gen_pool *pool;
if (dev->of_node) {
pool = of_gen_pool_get(dev->of_node, "iram", 0);
/* Assign the pool into private_data field */
dmab->private_data = pool;
dmab->area = gen_pool_dma_alloc_align(pool, size, &dmab->addr,
PAGE_SIZE);
if (dmab->area)
return 0;
}
/* Internal memory might have limited size and no enough space,
* so if we fail to malloc, try to fetch memory traditionally.
*/
dmab->dev.type = SNDRV_DMA_TYPE_DEV;
return __snd_dma_alloc_pages(dmab, size);
}
static void snd_dma_iram_free(struct snd_dma_buffer *dmab)
{
struct gen_pool *pool = dmab->private_data;
if (pool && dmab->area)
gen_pool_free(pool, (unsigned long)dmab->area, dmab->bytes);
}
static int snd_dma_iram_mmap(struct snd_dma_buffer *dmab,
struct vm_area_struct *area)
{
area->vm_page_prot = pgprot_writecombine(area->vm_page_prot);
return remap_pfn_range(area, area->vm_start,
dmab->addr >> PAGE_SHIFT,
area->vm_end - area->vm_start,
area->vm_page_prot);
}
static const struct snd_malloc_ops snd_dma_iram_ops = {
.alloc = snd_dma_iram_alloc,
.free = snd_dma_iram_free,
.mmap = snd_dma_iram_mmap,
};
#endif /* CONFIG_GENERIC_ALLOCATOR */
/*
* Coherent device pages allocator
*/
static int snd_dma_dev_alloc(struct snd_dma_buffer *dmab, size_t size)
{
gfp_t gfp_flags;
gfp_flags = GFP_KERNEL
| __GFP_COMP /* compound page lets parts be mapped */
| __GFP_NORETRY /* don't trigger OOM-killer */
| __GFP_NOWARN; /* no stack trace print - this call is non-critical */
dmab->area = dma_alloc_coherent(dmab->dev.dev, size, &dmab->addr,
gfp_flags);
#ifdef CONFIG_X86
if (dmab->area && dmab->dev.type == SNDRV_DMA_TYPE_DEV_UC)
set_memory_wc((unsigned long)dmab->area,
PAGE_ALIGN(size) >> PAGE_SHIFT);
#endif
return 0;
}
static void snd_dma_dev_free(struct snd_dma_buffer *dmab)
{
#ifdef CONFIG_X86
if (dmab->dev.type == SNDRV_DMA_TYPE_DEV_UC)
set_memory_wb((unsigned long)dmab->area,
PAGE_ALIGN(dmab->bytes) >> PAGE_SHIFT);
#endif
dma_free_coherent(dmab->dev.dev, dmab->bytes, dmab->area, dmab->addr);
}
static int snd_dma_dev_mmap(struct snd_dma_buffer *dmab,
struct vm_area_struct *area)
{
return dma_mmap_coherent(dmab->dev.dev, area,
dmab->area, dmab->addr, dmab->bytes);
}
static const struct snd_malloc_ops snd_dma_dev_ops = {
.alloc = snd_dma_dev_alloc,
.free = snd_dma_dev_free,
.mmap = snd_dma_dev_mmap,
};
#endif /* CONFIG_HAS_DMA */
/*
* Entry points
*/
static const struct snd_malloc_ops *dma_ops[] = {
[SNDRV_DMA_TYPE_CONTINUOUS] = &snd_dma_continuous_ops,
[SNDRV_DMA_TYPE_VMALLOC] = &snd_dma_vmalloc_ops,
#ifdef CONFIG_HAS_DMA
[SNDRV_DMA_TYPE_DEV] = &snd_dma_dev_ops,
[SNDRV_DMA_TYPE_DEV_UC] = &snd_dma_dev_ops,
#ifdef CONFIG_GENERIC_ALLOCATOR
[SNDRV_DMA_TYPE_DEV_IRAM] = &snd_dma_iram_ops,
#endif /* CONFIG_GENERIC_ALLOCATOR */
#endif /* CONFIG_HAS_DMA */
#ifdef CONFIG_SND_DMA_SGBUF
[SNDRV_DMA_TYPE_DEV_SG] = &snd_dma_sg_ops,
[SNDRV_DMA_TYPE_DEV_UC_SG] = &snd_dma_sg_ops,
#endif
};
static const struct snd_malloc_ops *snd_dma_get_ops(struct snd_dma_buffer *dmab)
{
if (WARN_ON_ONCE(dmab->dev.type <= SNDRV_DMA_TYPE_UNKNOWN ||
dmab->dev.type >= ARRAY_SIZE(dma_ops)))
return NULL;
return dma_ops[dmab->dev.type];
}

View File

@ -0,0 +1,19 @@
// SPDX-License-Identifier: GPL-2.0-only
#ifndef __MEMALLOC_LOCAL_H
#define __MEMALLOC_LOCAL_H
struct snd_malloc_ops {
int (*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);
};
#ifdef CONFIG_SND_DMA_SGBUF
extern const struct snd_malloc_ops snd_dma_sg_ops;
#endif
#endif /* __MEMALLOC_LOCAL_H */

View File

@ -185,7 +185,8 @@ static int snd_mixer_oss_get_recsrc(struct snd_mixer_oss_file *fmixer)
if (mixer->put_recsrc && mixer->get_recsrc) { /* exclusive */
int err;
unsigned int index;
if ((err = mixer->get_recsrc(fmixer, &index)) < 0)
err = mixer->get_recsrc(fmixer, &index);
if (err < 0)
return err;
result = 1 << index;
} else {
@ -517,7 +518,8 @@ static void snd_mixer_oss_get_volume1_vol(struct snd_mixer_oss_file *fmixer,
if (numid == ID_UNKNOWN)
return;
down_read(&card->controls_rwsem);
if ((kctl = snd_ctl_find_numid(card, numid)) == NULL) {
kctl = snd_ctl_find_numid(card, numid);
if (!kctl) {
up_read(&card->controls_rwsem);
return;
}
@ -555,7 +557,8 @@ static void snd_mixer_oss_get_volume1_sw(struct snd_mixer_oss_file *fmixer,
if (numid == ID_UNKNOWN)
return;
down_read(&card->controls_rwsem);
if ((kctl = snd_ctl_find_numid(card, numid)) == NULL) {
kctl = snd_ctl_find_numid(card, numid);
if (!kctl) {
up_read(&card->controls_rwsem);
return;
}
@ -620,7 +623,8 @@ static void snd_mixer_oss_put_volume1_vol(struct snd_mixer_oss_file *fmixer,
if (numid == ID_UNKNOWN)
return;
down_read(&card->controls_rwsem);
if ((kctl = snd_ctl_find_numid(card, numid)) == NULL) {
kctl = snd_ctl_find_numid(card, numid);
if (!kctl) {
up_read(&card->controls_rwsem);
return;
}
@ -636,7 +640,8 @@ static void snd_mixer_oss_put_volume1_vol(struct snd_mixer_oss_file *fmixer,
uctl->value.integer.value[0] = snd_mixer_oss_conv2(left, uinfo->value.integer.min, uinfo->value.integer.max);
if (uinfo->count > 1)
uctl->value.integer.value[1] = snd_mixer_oss_conv2(right, uinfo->value.integer.min, uinfo->value.integer.max);
if ((res = kctl->put(kctl, uctl)) < 0)
res = kctl->put(kctl, uctl);
if (res < 0)
goto __unalloc;
if (res > 0)
snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE, &kctl->id);
@ -661,7 +666,8 @@ static void snd_mixer_oss_put_volume1_sw(struct snd_mixer_oss_file *fmixer,
if (numid == ID_UNKNOWN)
return;
down_read(&card->controls_rwsem);
if ((kctl = snd_ctl_find_numid(card, numid)) == NULL) {
kctl = snd_ctl_find_numid(card, numid);
if (!kctl) {
up_read(&card->controls_rwsem);
return;
}
@ -681,7 +687,8 @@ static void snd_mixer_oss_put_volume1_sw(struct snd_mixer_oss_file *fmixer,
} else {
uctl->value.integer.value[0] = (left > 0 || right > 0) ? 1 : 0;
}
if ((res = kctl->put(kctl, uctl)) < 0)
res = kctl->put(kctl, uctl);
if (res < 0)
goto __unalloc;
if (res > 0)
snd_ctl_notify(card, SNDRV_CTL_EVENT_MASK_VALUE, &kctl->id);
@ -809,9 +816,11 @@ static int snd_mixer_oss_get_recsrc2(struct snd_mixer_oss_file *fmixer, unsigned
err = -ENOENT;
goto __unlock;
}
if ((err = kctl->info(kctl, uinfo)) < 0)
err = kctl->info(kctl, uinfo);
if (err < 0)
goto __unlock;
if ((err = kctl->get(kctl, uctl)) < 0)
err = kctl->get(kctl, uctl);
if (err < 0)
goto __unlock;
for (idx = 0; idx < 32; idx++) {
if (!(mixer->mask_recsrc & (1 << idx)))
@ -860,7 +869,8 @@ static int snd_mixer_oss_put_recsrc2(struct snd_mixer_oss_file *fmixer, unsigned
err = -ENOENT;
goto __unlock;
}
if ((err = kctl->info(kctl, uinfo)) < 0)
err = kctl->info(kctl, uinfo);
if (err < 0)
goto __unlock;
for (idx = 0; idx < 32; idx++) {
if (!(mixer->mask_recsrc & (1 << idx)))
@ -915,7 +925,8 @@ static int snd_mixer_oss_build_test(struct snd_mixer_oss *mixer, struct slot *sl
up_read(&card->controls_rwsem);
return -ENOMEM;
}
if ((err = kcontrol->info(kcontrol, info)) < 0) {
err = kcontrol->info(kcontrol, info);
if (err < 0) {
up_read(&card->controls_rwsem);
kfree(info);
return err;
@ -1036,7 +1047,10 @@ static int snd_mixer_oss_build_input(struct snd_mixer_oss *mixer,
if (snd_mixer_oss_build_test_all(mixer, ptr, &slot))
return 0;
down_read(&mixer->card->controls_rwsem);
if (ptr->index == 0 && (kctl = snd_mixer_oss_test_id(mixer, "Capture Source", 0)) != NULL) {
kctl = NULL;
if (!ptr->index)
kctl = snd_mixer_oss_test_id(mixer, "Capture Source", 0);
if (kctl) {
struct snd_ctl_elem_info *uinfo;
uinfo = kzalloc(sizeof(*uinfo), GFP_KERNEL);
@ -1343,9 +1357,10 @@ static int snd_mixer_oss_notify_handler(struct snd_card *card, int cmd)
if (mixer == NULL)
return -ENOMEM;
mutex_init(&mixer->reg_mutex);
if ((err = snd_register_oss_device(SNDRV_OSS_DEVICE_TYPE_MIXER,
card, 0,
&snd_mixer_oss_f_ops, card)) < 0) {
err = snd_register_oss_device(SNDRV_OSS_DEVICE_TYPE_MIXER,
card, 0,
&snd_mixer_oss_f_ops, card);
if (err < 0) {
dev_err(card->dev,
"unable to register OSS mixer device %i:%i\n",
card->number, 0);

View File

@ -955,9 +955,8 @@ static int snd_pcm_oss_change_params_locked(struct snd_pcm_substream *substream)
if (!direct) {
/* add necessary plugins */
snd_pcm_oss_plugin_clear(substream);
if ((err = snd_pcm_plug_format_plugins(substream,
params,
sparams)) < 0) {
err = snd_pcm_plug_format_plugins(substream, params, sparams);
if (err < 0) {
pcm_dbg(substream->pcm,
"snd_pcm_plug_format_plugins failed: %i\n", err);
snd_pcm_oss_plugin_clear(substream);
@ -965,7 +964,8 @@ static int snd_pcm_oss_change_params_locked(struct snd_pcm_substream *substream)
}
if (runtime->oss.plugin_first) {
struct snd_pcm_plugin *plugin;
if ((err = snd_pcm_plugin_build_io(substream, sparams, &plugin)) < 0) {
err = snd_pcm_plugin_build_io(substream, sparams, &plugin);
if (err < 0) {
pcm_dbg(substream->pcm,
"snd_pcm_plugin_build_io failed: %i\n", err);
snd_pcm_oss_plugin_clear(substream);
@ -1011,7 +1011,8 @@ static int snd_pcm_oss_change_params_locked(struct snd_pcm_substream *substream)
sw_params->silence_size = frames;
}
if ((err = snd_pcm_kernel_ioctl(substream, SNDRV_PCM_IOCTL_SW_PARAMS, sw_params)) < 0) {
err = snd_pcm_kernel_ioctl(substream, SNDRV_PCM_IOCTL_SW_PARAMS, sw_params);
if (err < 0) {
pcm_dbg(substream->pcm, "SW_PARAMS failed: %i\n", err);
goto failure;
}
@ -1573,7 +1574,8 @@ static int snd_pcm_oss_post(struct snd_pcm_oss_file *pcm_oss_file)
substream = pcm_oss_file->streams[SNDRV_PCM_STREAM_PLAYBACK];
if (substream != NULL) {
if ((err = snd_pcm_oss_make_ready(substream)) < 0)
err = snd_pcm_oss_make_ready(substream);
if (err < 0)
return err;
snd_pcm_kernel_ioctl(substream, SNDRV_PCM_IOCTL_START, NULL);
}
@ -1645,7 +1647,8 @@ static int snd_pcm_oss_sync(struct snd_pcm_oss_file *pcm_oss_file)
runtime = substream->runtime;
if (atomic_read(&substream->mmap_count))
goto __direct;
if ((err = snd_pcm_oss_make_ready(substream)) < 0)
err = snd_pcm_oss_make_ready(substream);
if (err < 0)
return err;
atomic_inc(&runtime->oss.rw_ref);
if (mutex_lock_interruptible(&runtime->oss.params_lock)) {
@ -1711,7 +1714,8 @@ unlock:
substream = pcm_oss_file->streams[SNDRV_PCM_STREAM_CAPTURE];
if (substream != NULL) {
if ((err = snd_pcm_oss_make_ready(substream)) < 0)
err = snd_pcm_oss_make_ready(substream);
if (err < 0)
return err;
runtime = substream->runtime;
err = snd_pcm_kernel_ioctl(substream, SNDRV_PCM_IOCTL_DROP, NULL);
@ -1758,7 +1762,8 @@ static int snd_pcm_oss_get_rate(struct snd_pcm_oss_file *pcm_oss_file)
struct snd_pcm_substream *substream;
int err;
if ((err = snd_pcm_oss_get_active_substream(pcm_oss_file, &substream)) < 0)
err = snd_pcm_oss_get_active_substream(pcm_oss_file, &substream);
if (err < 0)
return err;
return substream->runtime->oss.rate;
}
@ -1795,7 +1800,8 @@ static int snd_pcm_oss_get_channels(struct snd_pcm_oss_file *pcm_oss_file)
struct snd_pcm_substream *substream;
int err;
if ((err = snd_pcm_oss_get_active_substream(pcm_oss_file, &substream)) < 0)
err = snd_pcm_oss_get_active_substream(pcm_oss_file, &substream);
if (err < 0)
return err;
return substream->runtime->oss.channels;
}
@ -1805,7 +1811,8 @@ static int snd_pcm_oss_get_block_size(struct snd_pcm_oss_file *pcm_oss_file)
struct snd_pcm_substream *substream;
int err;
if ((err = snd_pcm_oss_get_active_substream(pcm_oss_file, &substream)) < 0)
err = snd_pcm_oss_get_active_substream(pcm_oss_file, &substream);
if (err < 0)
return err;
return substream->runtime->oss.period_bytes;
}
@ -1820,7 +1827,8 @@ static int snd_pcm_oss_get_formats(struct snd_pcm_oss_file *pcm_oss_file)
const struct snd_mask *format_mask;
int fmt;
if ((err = snd_pcm_oss_get_active_substream(pcm_oss_file, &substream)) < 0)
err = snd_pcm_oss_get_active_substream(pcm_oss_file, &substream);
if (err < 0)
return err;
if (atomic_read(&substream->mmap_count))
direct = 1;
@ -1890,7 +1898,8 @@ static int snd_pcm_oss_get_format(struct snd_pcm_oss_file *pcm_oss_file)
struct snd_pcm_substream *substream;
int err;
if ((err = snd_pcm_oss_get_active_substream(pcm_oss_file, &substream)) < 0)
err = snd_pcm_oss_get_active_substream(pcm_oss_file, &substream);
if (err < 0)
return err;
return substream->runtime->oss.format;
}
@ -2050,11 +2059,13 @@ static int snd_pcm_oss_set_trigger(struct snd_pcm_oss_file *pcm_oss_file, int tr
csubstream = pcm_oss_file->streams[SNDRV_PCM_STREAM_CAPTURE];
if (psubstream) {
if ((err = snd_pcm_oss_make_ready(psubstream)) < 0)
err = snd_pcm_oss_make_ready(psubstream);
if (err < 0)
return err;
}
if (csubstream) {
if ((err = snd_pcm_oss_make_ready(csubstream)) < 0)
err = snd_pcm_oss_make_ready(csubstream);
if (err < 0)
return err;
}
if (psubstream) {
@ -2141,7 +2152,8 @@ static int snd_pcm_oss_get_odelay(struct snd_pcm_oss_file *pcm_oss_file)
substream = pcm_oss_file->streams[SNDRV_PCM_STREAM_PLAYBACK];
if (substream == NULL)
return -EINVAL;
if ((err = snd_pcm_oss_make_ready(substream)) < 0)
err = snd_pcm_oss_make_ready(substream);
if (err < 0)
return err;
runtime = substream->runtime;
if (runtime->oss.params || runtime->oss.prepare)
@ -2168,7 +2180,8 @@ static int snd_pcm_oss_get_ptr(struct snd_pcm_oss_file *pcm_oss_file, int stream
substream = pcm_oss_file->streams[stream];
if (substream == NULL)
return -EINVAL;
if ((err = snd_pcm_oss_make_ready(substream)) < 0)
err = snd_pcm_oss_make_ready(substream);
if (err < 0)
return err;
runtime = substream->runtime;
if (runtime->oss.params || runtime->oss.prepare) {
@ -2239,9 +2252,11 @@ static int snd_pcm_oss_get_space(struct snd_pcm_oss_file *pcm_oss_file, int stre
return -EINVAL;
runtime = substream->runtime;
if (runtime->oss.params &&
(err = snd_pcm_oss_change_params(substream, false)) < 0)
return err;
if (runtime->oss.params) {
err = snd_pcm_oss_change_params(substream, false);
if (err < 0)
return err;
}
info.fragsize = runtime->oss.period_bytes;
info.fragstotal = runtime->periods;
@ -2601,7 +2616,8 @@ static long snd_pcm_oss_ioctl(struct file *file, unsigned int cmd, unsigned long
case SNDCTL_DSP_SPEED:
if (get_user(res, p))
return -EFAULT;
if ((res = snd_pcm_oss_set_rate(pcm_oss_file, res))<0)
res = snd_pcm_oss_set_rate(pcm_oss_file, res);
if (res < 0)
return res;
return put_user(res, p);
case SOUND_PCM_READ_RATE:
@ -2613,7 +2629,8 @@ static long snd_pcm_oss_ioctl(struct file *file, unsigned int cmd, unsigned long
if (get_user(res, p))
return -EFAULT;
res = res > 0 ? 2 : 1;
if ((res = snd_pcm_oss_set_channels(pcm_oss_file, res)) < 0)
res = snd_pcm_oss_set_channels(pcm_oss_file, res);
if (res < 0)
return res;
return put_user(--res, p);
case SNDCTL_DSP_GETBLKSIZE:
@ -2829,7 +2846,8 @@ static __poll_t snd_pcm_oss_poll(struct file *file, poll_table * wait)
snd_pcm_state_t ostate;
poll_wait(file, &runtime->sleep, wait);
snd_pcm_stream_lock_irq(csubstream);
if ((ostate = runtime->status->state) != SNDRV_PCM_STATE_RUNNING ||
ostate = runtime->status->state;
if (ostate != SNDRV_PCM_STATE_RUNNING ||
snd_pcm_oss_capture_ready(csubstream))
mask |= EPOLLIN | EPOLLRDNORM;
snd_pcm_stream_unlock_irq(csubstream);
@ -3043,7 +3061,8 @@ static void snd_pcm_oss_proc_init(struct snd_pcm *pcm)
struct snd_pcm_str *pstr = &pcm->streams[stream];
if (pstr->substream_count == 0)
continue;
if ((entry = snd_info_create_card_entry(pcm->card, "oss", pstr->proc_root)) != NULL) {
entry = snd_info_create_card_entry(pcm->card, "oss", pstr->proc_root);
if (entry) {
entry->content = SNDRV_INFO_CONTENT_TEXT;
entry->mode = S_IFREG | 0644;
entry->c.text.read = snd_pcm_oss_proc_read;
@ -3191,7 +3210,8 @@ static int __init alsa_pcm_oss_init(void)
adsp_map[i] = 1;
}
}
if ((err = snd_pcm_notify(&snd_pcm_oss_notify, 0)) < 0)
err = snd_pcm_notify(&snd_pcm_oss_notify, 0);
if (err < 0)
return err;
return 0;
}

View File

@ -59,7 +59,8 @@ static int snd_pcm_plugin_alloc(struct snd_pcm_plugin *plugin, snd_pcm_uframes_t
} else {
format = &plugin->dst_format;
}
if ((width = snd_pcm_format_physical_width(format->format)) < 0)
width = snd_pcm_format_physical_width(format->format);
if (width < 0)
return width;
size = frames * format->channels * width;
if (snd_BUG_ON(size % 8))
@ -572,7 +573,8 @@ snd_pcm_sframes_t snd_pcm_plug_client_channels_buf(struct snd_pcm_substream *plu
}
v = plugin->buf_channels;
*channels = v;
if ((width = snd_pcm_format_physical_width(format->format)) < 0)
width = snd_pcm_format_physical_width(format->format);
if (width < 0)
return width;
nchannels = format->channels;
if (snd_BUG_ON(plugin->access != SNDRV_PCM_ACCESS_RW_INTERLEAVED &&
@ -600,16 +602,17 @@ snd_pcm_sframes_t snd_pcm_plug_write_transfer(struct snd_pcm_substream *plug, st
while (plugin) {
if (frames <= 0)
return frames;
if ((next = plugin->next) != NULL) {
next = plugin->next;
if (next) {
snd_pcm_sframes_t frames1 = frames;
if (plugin->dst_frames) {
frames1 = plugin->dst_frames(plugin, frames);
if (frames1 <= 0)
return frames1;
}
if ((err = next->client_channels(next, frames1, &dst_channels)) < 0) {
err = next->client_channels(next, frames1, &dst_channels);
if (err < 0)
return err;
}
if (err != frames1) {
frames = err;
if (plugin->src_frames) {
@ -621,7 +624,8 @@ snd_pcm_sframes_t snd_pcm_plug_write_transfer(struct snd_pcm_substream *plug, st
} else
dst_channels = NULL;
pdprintf("write plugin: %s, %li\n", plugin->name, frames);
if ((frames = plugin->transfer(plugin, src_channels, dst_channels, frames)) < 0)
frames = plugin->transfer(plugin, src_channels, dst_channels, frames);
if (frames < 0)
return frames;
src_channels = dst_channels;
plugin = next;
@ -643,16 +647,18 @@ snd_pcm_sframes_t snd_pcm_plug_read_transfer(struct snd_pcm_substream *plug, str
src_channels = NULL;
plugin = snd_pcm_plug_first(plug);
while (plugin && frames > 0) {
if ((next = plugin->next) != NULL) {
if ((err = plugin->client_channels(plugin, frames, &dst_channels)) < 0) {
next = plugin->next;
if (next) {
err = plugin->client_channels(plugin, frames, &dst_channels);
if (err < 0)
return err;
}
frames = err;
} else {
dst_channels = dst_channels_final;
}
pdprintf("read plugin: %s, %li\n", plugin->name, frames);
if ((frames = plugin->transfer(plugin, src_channels, dst_channels, frames)) < 0)
frames = plugin->transfer(plugin, src_channels, dst_channels, frames);
if (frames < 0)
return frames;
plugin = next;
src_channels = dst_channels;

View File

@ -1004,7 +1004,7 @@ void snd_pcm_detach_substream(struct snd_pcm_substream *substream)
substream->pstr->substream_opened--;
}
static ssize_t show_pcm_class(struct device *dev,
static ssize_t pcm_class_show(struct device *dev,
struct device_attribute *attr, char *buf)
{
struct snd_pcm_str *pstr = container_of(dev, struct snd_pcm_str, dev);
@ -1024,7 +1024,7 @@ static ssize_t show_pcm_class(struct device *dev,
return sprintf(buf, "%s\n", str);
}
static DEVICE_ATTR(pcm_class, 0444, show_pcm_class, NULL);
static DEVICE_ATTR_RO(pcm_class);
static struct attribute *pcm_dev_attrs[] = {
&dev_attr_pcm_class.attr,
NULL

View File

@ -239,7 +239,8 @@ static int snd_pcm_ioctl_hw_params_compat(struct snd_pcm_substream *substream,
struct snd_pcm_runtime *runtime;
int err;
if (! (runtime = substream->runtime))
runtime = substream->runtime;
if (!runtime)
return -ENOTTY;
data = kmalloc(sizeof(*data), GFP_KERNEL);
@ -343,7 +344,8 @@ static int snd_pcm_ioctl_xfern_compat(struct snd_pcm_substream *substream,
if (substream->runtime->status->state == SNDRV_PCM_STATE_OPEN)
return -EBADFD;
if ((ch = substream->runtime->channels) > 128)
ch = substream->runtime->channels;
if (ch > 128)
return -EINVAL;
if (get_user(buf, &data32->bufs) ||
get_user(frames, &data32->frames))

View File

@ -9,41 +9,85 @@
#include <sound/pcm_params.h>
#include <sound/pcm_iec958.h>
static int create_iec958_consumer(uint rate, uint sample_width,
u8 *cs, size_t len)
/**
* snd_pcm_create_iec958_consumer_default - create default consumer format IEC958 channel status
* @cs: channel status buffer, at least four bytes
* @len: length of channel status buffer
*
* Create the consumer format channel status data in @cs of maximum size
* @len. When relevant, the configuration-dependant bits will be set as
* unspecified.
*
* Drivers should then call einter snd_pcm_fill_iec958_consumer() or
* snd_pcm_fill_iec958_consumer_hw_params() to replace these unspecified
* bits by their actual values.
*
* Drivers may wish to tweak the contents of the buffer after creation.
*
* Returns: length of buffer, or negative error code if something failed.
*/
int snd_pcm_create_iec958_consumer_default(u8 *cs, size_t len)
{
unsigned int fs, ws;
if (len < 4)
return -EINVAL;
switch (rate) {
case 32000:
fs = IEC958_AES3_CON_FS_32000;
break;
case 44100:
fs = IEC958_AES3_CON_FS_44100;
break;
case 48000:
fs = IEC958_AES3_CON_FS_48000;
break;
case 88200:
fs = IEC958_AES3_CON_FS_88200;
break;
case 96000:
fs = IEC958_AES3_CON_FS_96000;
break;
case 176400:
fs = IEC958_AES3_CON_FS_176400;
break;
case 192000:
fs = IEC958_AES3_CON_FS_192000;
break;
default:
memset(cs, 0, len);
cs[0] = IEC958_AES0_CON_NOT_COPYRIGHT | IEC958_AES0_CON_EMPHASIS_NONE;
cs[1] = IEC958_AES1_CON_GENERAL;
cs[2] = IEC958_AES2_CON_SOURCE_UNSPEC | IEC958_AES2_CON_CHANNEL_UNSPEC;
cs[3] = IEC958_AES3_CON_CLOCK_1000PPM | IEC958_AES3_CON_FS_NOTID;
if (len > 4)
cs[4] = IEC958_AES4_CON_WORDLEN_NOTID;
return len;
}
EXPORT_SYMBOL_GPL(snd_pcm_create_iec958_consumer_default);
static int fill_iec958_consumer(uint rate, uint sample_width,
u8 *cs, size_t len)
{
if (len < 4)
return -EINVAL;
if ((cs[3] & IEC958_AES3_CON_FS) == IEC958_AES3_CON_FS_NOTID) {
unsigned int fs;
switch (rate) {
case 32000:
fs = IEC958_AES3_CON_FS_32000;
break;
case 44100:
fs = IEC958_AES3_CON_FS_44100;
break;
case 48000:
fs = IEC958_AES3_CON_FS_48000;
break;
case 88200:
fs = IEC958_AES3_CON_FS_88200;
break;
case 96000:
fs = IEC958_AES3_CON_FS_96000;
break;
case 176400:
fs = IEC958_AES3_CON_FS_176400;
break;
case 192000:
fs = IEC958_AES3_CON_FS_192000;
break;
default:
return -EINVAL;
}
cs[3] &= ~IEC958_AES3_CON_FS;
cs[3] |= fs;
}
if (len > 4) {
if (len > 4 &&
(cs[4] & IEC958_AES4_CON_WORDLEN) == IEC958_AES4_CON_WORDLEN_NOTID) {
unsigned int ws;
switch (sample_width) {
case 16:
ws = IEC958_AES4_CON_WORDLEN_20_16;
@ -64,21 +108,58 @@ static int create_iec958_consumer(uint rate, uint sample_width,
default:
return -EINVAL;
}
cs[4] &= ~IEC958_AES4_CON_WORDLEN;
cs[4] |= ws;
}
memset(cs, 0, len);
cs[0] = IEC958_AES0_CON_NOT_COPYRIGHT | IEC958_AES0_CON_EMPHASIS_NONE;
cs[1] = IEC958_AES1_CON_GENERAL;
cs[2] = IEC958_AES2_CON_SOURCE_UNSPEC | IEC958_AES2_CON_CHANNEL_UNSPEC;
cs[3] = IEC958_AES3_CON_CLOCK_1000PPM | fs;
if (len > 4)
cs[4] = ws;
return len;
}
/**
* snd_pcm_fill_iec958_consumer - Fill consumer format IEC958 channel status
* @runtime: pcm runtime structure with ->rate filled in
* @cs: channel status buffer, at least four bytes
* @len: length of channel status buffer
*
* Fill the unspecified bits in an IEC958 status bits array using the
* parameters of the PCM runtime @runtime.
*
* Drivers may wish to tweak the contents of the buffer after its been
* filled.
*
* Returns: length of buffer, or negative error code if something failed.
*/
int snd_pcm_fill_iec958_consumer(struct snd_pcm_runtime *runtime,
u8 *cs, size_t len)
{
return fill_iec958_consumer(runtime->rate,
snd_pcm_format_width(runtime->format),
cs, len);
}
EXPORT_SYMBOL_GPL(snd_pcm_fill_iec958_consumer);
/**
* snd_pcm_fill_iec958_consumer_hw_params - Fill consumer format IEC958 channel status
* @params: the hw_params instance for extracting rate and sample format
* @cs: channel status buffer, at least four bytes
* @len: length of channel status buffer
*
* Fill the unspecified bits in an IEC958 status bits array using the
* parameters of the PCM hardware parameters @params.
*
* Drivers may wish to tweak the contents of the buffer after its been
* filled..
*
* Returns: length of buffer, or negative error code if something failed.
*/
int snd_pcm_fill_iec958_consumer_hw_params(struct snd_pcm_hw_params *params,
u8 *cs, size_t len)
{
return fill_iec958_consumer(params_rate(params), params_width(params), cs, len);
}
EXPORT_SYMBOL_GPL(snd_pcm_fill_iec958_consumer_hw_params);
/**
* snd_pcm_create_iec958_consumer - create consumer format IEC958 channel status
* @runtime: pcm runtime structure with ->rate filled in
@ -95,9 +176,13 @@ static int create_iec958_consumer(uint rate, uint sample_width,
int snd_pcm_create_iec958_consumer(struct snd_pcm_runtime *runtime, u8 *cs,
size_t len)
{
return create_iec958_consumer(runtime->rate,
snd_pcm_format_width(runtime->format),
cs, len);
int ret;
ret = snd_pcm_create_iec958_consumer_default(cs, len);
if (ret < 0)
return ret;
return snd_pcm_fill_iec958_consumer(runtime, cs, len);
}
EXPORT_SYMBOL(snd_pcm_create_iec958_consumer);
@ -117,7 +202,12 @@ EXPORT_SYMBOL(snd_pcm_create_iec958_consumer);
int snd_pcm_create_iec958_consumer_hw_params(struct snd_pcm_hw_params *params,
u8 *cs, size_t len)
{
return create_iec958_consumer(params_rate(params), params_width(params),
cs, len);
int ret;
ret = snd_pcm_create_iec958_consumer_default(cs, len);
if (ret < 0)
return ret;
return fill_iec958_consumer(params_rate(params), params_width(params), cs, len);
}
EXPORT_SYMBOL(snd_pcm_create_iec958_consumer_hw_params);

View File

@ -1778,27 +1778,38 @@ int snd_pcm_lib_ioctl(struct snd_pcm_substream *substream,
EXPORT_SYMBOL(snd_pcm_lib_ioctl);
/**
* snd_pcm_period_elapsed - update the pcm status for the next period
* @substream: the pcm substream instance
* snd_pcm_period_elapsed_under_stream_lock() - update the status of runtime for the next period
* under acquired lock of PCM substream.
* @substream: the instance of pcm substream.
*
* This function is called from the interrupt handler when the
* PCM has processed the period size. It will update the current
* pointer, wake up sleepers, etc.
* This function is called when the batch of audio data frames as the same size as the period of
* buffer is already processed in audio data transmission.
*
* Even if more than one periods have elapsed since the last call, you
* have to call this only once.
* The call of function updates the status of runtime with the latest position of audio data
* transmission, checks overrun and underrun over buffer, awaken user processes from waiting for
* available audio data frames, sampling audio timestamp, and performs stop or drain the PCM
* substream according to configured threshold.
*
* The function is intended to use for the case that PCM driver operates audio data frames under
* acquired lock of PCM substream; e.g. in callback of any operation of &snd_pcm_ops in process
* context. In any interrupt context, it's preferrable to use ``snd_pcm_period_elapsed()`` instead
* since lock of PCM substream should be acquired in advance.
*
* Developer should pay enough attention that some callbacks in &snd_pcm_ops are done by the call of
* function:
*
* - .pointer - to retrieve current position of audio data transmission by frame count or XRUN state.
* - .trigger - with SNDRV_PCM_TRIGGER_STOP at XRUN or DRAINING state.
* - .get_time_info - to retrieve audio time stamp if needed.
*
* Even if more than one periods have elapsed since the last call, you have to call this only once.
*/
void snd_pcm_period_elapsed(struct snd_pcm_substream *substream)
void snd_pcm_period_elapsed_under_stream_lock(struct snd_pcm_substream *substream)
{
struct snd_pcm_runtime *runtime;
unsigned long flags;
if (snd_BUG_ON(!substream))
return;
snd_pcm_stream_lock_irqsave(substream, flags);
if (PCM_RUNTIME_CHECK(substream))
goto _unlock;
return;
runtime = substream->runtime;
if (!snd_pcm_running(substream) ||
@ -1811,7 +1822,30 @@ void snd_pcm_period_elapsed(struct snd_pcm_substream *substream)
#endif
_end:
kill_fasync(&runtime->fasync, SIGIO, POLL_IN);
_unlock:
}
EXPORT_SYMBOL(snd_pcm_period_elapsed_under_stream_lock);
/**
* snd_pcm_period_elapsed() - update the status of runtime for the next period by acquiring lock of
* PCM substream.
* @substream: the instance of PCM substream.
*
* This function is mostly similar to ``snd_pcm_period_elapsed_under_stream_lock()`` except for
* acquiring lock of PCM substream voluntarily.
*
* It's typically called by any type of IRQ handler when hardware IRQ occurs to notify event that
* the batch of audio data frames as the same size as the period of buffer is already processed in
* audio data transmission.
*/
void snd_pcm_period_elapsed(struct snd_pcm_substream *substream)
{
unsigned long flags;
if (snd_BUG_ON(!substream))
return;
snd_pcm_stream_lock_irqsave(substream, flags);
snd_pcm_period_elapsed_under_stream_lock(substream);
snd_pcm_stream_unlock_irqrestore(substream, flags);
}
EXPORT_SYMBOL(snd_pcm_period_elapsed);

View File

@ -65,11 +65,6 @@ void __snd_pcm_xrun(struct snd_pcm_substream *substream);
void snd_pcm_group_init(struct snd_pcm_group *group);
void snd_pcm_sync_stop(struct snd_pcm_substream *substream, bool sync_irq);
#ifdef CONFIG_SND_DMA_SGBUF
struct page *snd_pcm_sgbuf_ops_page(struct snd_pcm_substream *substream,
unsigned long offset);
#endif
#define PCM_RUNTIME_CHECK(sub) snd_BUG_ON(!(sub) || !(sub)->runtime)
/* loop over all PCM substreams */

View File

@ -337,27 +337,6 @@ void snd_pcm_set_managed_buffer_all(struct snd_pcm *pcm, int type,
}
EXPORT_SYMBOL(snd_pcm_set_managed_buffer_all);
#ifdef CONFIG_SND_DMA_SGBUF
/*
* snd_pcm_sgbuf_ops_page - get the page struct at the given offset
* @substream: the pcm substream instance
* @offset: the buffer offset
*
* Used as the page callback of PCM ops.
*
* Return: The page struct at the given buffer offset. %NULL on failure.
*/
struct page *snd_pcm_sgbuf_ops_page(struct snd_pcm_substream *substream, unsigned long offset)
{
struct snd_sg_buf *sgbuf = snd_pcm_substream_sgbuf(substream);
unsigned int idx = offset >> PAGE_SHIFT;
if (idx >= (unsigned int)sgbuf->pages)
return NULL;
return sgbuf->page_table[idx];
}
#endif /* CONFIG_SND_DMA_SGBUF */
/**
* snd_pcm_lib_malloc_pages - allocate the DMA buffer
* @substream: the substream to allocate the DMA buffer to

View File

@ -266,7 +266,8 @@ int snd_pcm_format_signed(snd_pcm_format_t format)
int val;
if (!valid_format(format))
return -EINVAL;
if ((val = pcm_formats[(INT)format].signd) < 0)
val = pcm_formats[(INT)format].signd;
if (val < 0)
return -EINVAL;
return val;
}
@ -314,7 +315,8 @@ int snd_pcm_format_little_endian(snd_pcm_format_t format)
int val;
if (!valid_format(format))
return -EINVAL;
if ((val = pcm_formats[(INT)format].le) < 0)
val = pcm_formats[(INT)format].le;
if (val < 0)
return -EINVAL;
return val;
}
@ -350,7 +352,8 @@ int snd_pcm_format_width(snd_pcm_format_t format)
int val;
if (!valid_format(format))
return -EINVAL;
if ((val = pcm_formats[(INT)format].width) == 0)
val = pcm_formats[(INT)format].width;
if (!val)
return -EINVAL;
return val;
}
@ -368,7 +371,8 @@ int snd_pcm_format_physical_width(snd_pcm_format_t format)
int val;
if (!valid_format(format))
return -EINVAL;
if ((val = pcm_formats[(INT)format].phys) == 0)
val = pcm_formats[(INT)format].phys;
if (!val)
return -EINVAL;
return val;
}

View File

@ -768,7 +768,8 @@ static int snd_pcm_hw_params(struct snd_pcm_substream *substream,
if (cpu_latency_qos_request_active(&substream->latency_pm_qos_req))
cpu_latency_qos_remove_request(&substream->latency_pm_qos_req);
if ((usecs = period_to_usecs(runtime)) >= 0)
usecs = period_to_usecs(runtime);
if (usecs >= 0)
cpu_latency_qos_add_request(&substream->latency_pm_qos_req,
usecs);
return 0;
@ -2658,7 +2659,8 @@ int snd_pcm_open_substream(struct snd_pcm *pcm, int stream,
goto error;
}
if ((err = substream->ops->open(substream)) < 0)
err = substream->ops->open(substream);
if (err < 0)
goto error;
substream->hw_opened = 1;
@ -2799,6 +2801,10 @@ static int snd_pcm_release(struct inode *inode, struct file *file)
if (snd_BUG_ON(!substream))
return -ENXIO;
pcm = substream->pcm;
/* block until the device gets woken up as it may touch the hardware */
snd_power_wait(pcm->card);
mutex_lock(&pcm->open_mutex);
snd_pcm_release_substream(substream);
kfree(pcm_file);
@ -3193,7 +3199,7 @@ static int snd_pcm_common_ioctl(struct file *file,
if (PCM_RUNTIME_CHECK(substream))
return -ENXIO;
res = snd_power_wait(substream->pcm->card, SNDRV_CTL_POWER_D0);
res = snd_power_wait(substream->pcm->card);
if (res < 0)
return res;
@ -3638,24 +3644,6 @@ static int snd_pcm_mmap_control(struct snd_pcm_substream *substream, struct file
}
#endif /* coherent mmap */
static inline struct page *
snd_pcm_default_page_ops(struct snd_pcm_substream *substream, unsigned long ofs)
{
void *vaddr = substream->runtime->dma_area + ofs;
switch (substream->dma_buffer.dev.type) {
#ifdef CONFIG_SND_DMA_SGBUF
case SNDRV_DMA_TYPE_DEV_SG:
case SNDRV_DMA_TYPE_DEV_UC_SG:
return snd_pcm_sgbuf_ops_page(substream, ofs);
#endif /* CONFIG_SND_DMA_SGBUF */
case SNDRV_DMA_TYPE_VMALLOC:
return vmalloc_to_page(vaddr);
default:
return virt_to_page(vaddr);
}
}
/*
* fault callback for mmapping a RAM page
*/
@ -3677,7 +3665,7 @@ static vm_fault_t snd_pcm_mmap_data_fault(struct vm_fault *vmf)
if (substream->ops->page)
page = substream->ops->page(substream, offset);
else
page = snd_pcm_default_page_ops(substream, offset);
page = snd_sgbuf_get_page(snd_pcm_get_dma_buf(substream), offset);
if (!page)
return VM_FAULT_SIGBUS;
get_page(page);
@ -3712,22 +3700,9 @@ int snd_pcm_lib_default_mmap(struct snd_pcm_substream *substream,
struct vm_area_struct *area)
{
area->vm_flags |= VM_DONTEXPAND | VM_DONTDUMP;
#ifdef CONFIG_GENERIC_ALLOCATOR
if (substream->dma_buffer.dev.type == SNDRV_DMA_TYPE_DEV_IRAM) {
area->vm_page_prot = pgprot_writecombine(area->vm_page_prot);
return remap_pfn_range(area, area->vm_start,
substream->dma_buffer.addr >> PAGE_SHIFT,
area->vm_end - area->vm_start, area->vm_page_prot);
}
#endif /* CONFIG_GENERIC_ALLOCATOR */
if (IS_ENABLED(CONFIG_HAS_DMA) && !substream->ops->page &&
(substream->dma_buffer.dev.type == SNDRV_DMA_TYPE_DEV ||
substream->dma_buffer.dev.type == SNDRV_DMA_TYPE_DEV_UC))
return dma_mmap_coherent(substream->dma_buffer.dev.dev,
area,
substream->runtime->dma_area,
substream->runtime->dma_addr,
substream->runtime->dma_bytes);
if (!substream->ops->page &&
!snd_dma_buffer_mmap(snd_pcm_get_dma_buf(substream), area))
return 0;
/* mmap with fault handler */
area->vm_ops = &snd_pcm_vm_ops_data_fault;
return 0;

View File

@ -680,9 +680,12 @@ static int resize_runtime_buffer(struct snd_rawmidi_runtime *runtime,
bool is_input)
{
char *newbuf, *oldbuf;
unsigned int framing = params->mode & SNDRV_RAWMIDI_MODE_FRAMING_MASK;
if (params->buffer_size < 32 || params->buffer_size > 1024L * 1024L)
return -EINVAL;
if (framing == SNDRV_RAWMIDI_MODE_FRAMING_TSTAMP && (params->buffer_size & 0x1f) != 0)
return -EINVAL;
if (params->avail_min < 1 || params->avail_min > params->buffer_size)
return -EINVAL;
if (params->buffer_size != runtime->buffer_size) {
@ -720,8 +723,24 @@ EXPORT_SYMBOL(snd_rawmidi_output_params);
int snd_rawmidi_input_params(struct snd_rawmidi_substream *substream,
struct snd_rawmidi_params *params)
{
unsigned int framing = params->mode & SNDRV_RAWMIDI_MODE_FRAMING_MASK;
unsigned int clock_type = params->mode & SNDRV_RAWMIDI_MODE_CLOCK_MASK;
int err;
if (framing == SNDRV_RAWMIDI_MODE_FRAMING_NONE && clock_type != SNDRV_RAWMIDI_MODE_CLOCK_NONE)
return -EINVAL;
else if (clock_type > SNDRV_RAWMIDI_MODE_CLOCK_MONOTONIC_RAW)
return -EINVAL;
if (framing > SNDRV_RAWMIDI_MODE_FRAMING_TSTAMP)
return -EINVAL;
snd_rawmidi_drain_input(substream);
return resize_runtime_buffer(substream->runtime, params, true);
err = resize_runtime_buffer(substream->runtime, params, true);
if (err < 0)
return err;
substream->framing = framing;
substream->clock_type = clock_type;
return 0;
}
EXPORT_SYMBOL(snd_rawmidi_input_params);
@ -963,6 +982,62 @@ static int snd_rawmidi_control_ioctl(struct snd_card *card,
return -ENOIOCTLCMD;
}
static int receive_with_tstamp_framing(struct snd_rawmidi_substream *substream,
const unsigned char *buffer, int src_count, const struct timespec64 *tstamp)
{
struct snd_rawmidi_runtime *runtime = substream->runtime;
struct snd_rawmidi_framing_tstamp *dest_ptr;
struct snd_rawmidi_framing_tstamp frame = { .tv_sec = tstamp->tv_sec, .tv_nsec = tstamp->tv_nsec };
int dest_frames = 0;
int orig_count = src_count;
int frame_size = sizeof(struct snd_rawmidi_framing_tstamp);
BUILD_BUG_ON(frame_size != 0x20);
if (snd_BUG_ON((runtime->hw_ptr & 0x1f) != 0))
return -EINVAL;
while (src_count > 0) {
if ((int)(runtime->buffer_size - runtime->avail) < frame_size) {
runtime->xruns += src_count;
break;
}
if (src_count >= SNDRV_RAWMIDI_FRAMING_DATA_LENGTH)
frame.length = SNDRV_RAWMIDI_FRAMING_DATA_LENGTH;
else {
frame.length = src_count;
memset(frame.data, 0, SNDRV_RAWMIDI_FRAMING_DATA_LENGTH);
}
memcpy(frame.data, buffer, frame.length);
buffer += frame.length;
src_count -= frame.length;
dest_ptr = (struct snd_rawmidi_framing_tstamp *) (runtime->buffer + runtime->hw_ptr);
*dest_ptr = frame;
runtime->avail += frame_size;
runtime->hw_ptr += frame_size;
runtime->hw_ptr %= runtime->buffer_size;
dest_frames++;
}
return orig_count - src_count;
}
static struct timespec64 get_framing_tstamp(struct snd_rawmidi_substream *substream)
{
struct timespec64 ts64 = {0, 0};
switch (substream->clock_type) {
case SNDRV_RAWMIDI_MODE_CLOCK_MONOTONIC_RAW:
ktime_get_raw_ts64(&ts64);
break;
case SNDRV_RAWMIDI_MODE_CLOCK_MONOTONIC:
ktime_get_ts64(&ts64);
break;
case SNDRV_RAWMIDI_MODE_CLOCK_REALTIME:
ktime_get_real_ts64(&ts64);
break;
}
return ts64;
}
/**
* snd_rawmidi_receive - receive the input data from the device
* @substream: the rawmidi substream
@ -977,6 +1052,7 @@ int snd_rawmidi_receive(struct snd_rawmidi_substream *substream,
const unsigned char *buffer, int count)
{
unsigned long flags;
struct timespec64 ts64 = get_framing_tstamp(substream);
int result = 0, count1;
struct snd_rawmidi_runtime *runtime = substream->runtime;
@ -987,8 +1063,11 @@ int snd_rawmidi_receive(struct snd_rawmidi_substream *substream,
"snd_rawmidi_receive: input is not active!!!\n");
return -EINVAL;
}
spin_lock_irqsave(&runtime->lock, flags);
if (count == 1) { /* special case, faster code */
if (substream->framing == SNDRV_RAWMIDI_MODE_FRAMING_TSTAMP) {
result = receive_with_tstamp_framing(substream, buffer, count, &ts64);
} else if (count == 1) { /* special case, faster code */
substream->bytes++;
if (runtime->avail < runtime->buffer_size) {
runtime->buffer[runtime->hw_ptr++] = buffer[0];
@ -1541,6 +1620,8 @@ static void snd_rawmidi_proc_info_read(struct snd_info_entry *entry,
struct snd_rawmidi_substream *substream;
struct snd_rawmidi_runtime *runtime;
unsigned long buffer_size, avail, xruns;
unsigned int clock_type;
static const char *clock_names[4] = { "none", "realtime", "monotonic", "monotonic raw" };
rmidi = entry->private_data;
snd_iprintf(buffer, "%s\n\n", rmidi->name);
@ -1596,6 +1677,14 @@ static void snd_rawmidi_proc_info_read(struct snd_info_entry *entry,
" Avail : %lu\n"
" Overruns : %lu\n",
buffer_size, avail, xruns);
if (substream->framing == SNDRV_RAWMIDI_MODE_FRAMING_TSTAMP) {
clock_type = substream->clock_type >> SNDRV_RAWMIDI_MODE_CLOCK_SHIFT;
if (!snd_BUG_ON(clock_type >= ARRAY_SIZE(clock_names)))
snd_iprintf(buffer,
" Framing : tstamp\n"
" Clock type : %s\n",
clock_names[clock_type]);
}
}
}
}

View File

@ -13,7 +13,8 @@ struct snd_rawmidi_params32 {
u32 buffer_size;
u32 avail_min;
unsigned int no_active_sensing; /* avoid bit-field */
unsigned char reserved[16];
unsigned int mode;
unsigned char reserved[12];
} __attribute__((packed));
static int snd_rawmidi_ioctl_params_compat(struct snd_rawmidi_file *rfile,
@ -25,6 +26,7 @@ static int snd_rawmidi_ioctl_params_compat(struct snd_rawmidi_file *rfile,
if (get_user(params.stream, &src->stream) ||
get_user(params.buffer_size, &src->buffer_size) ||
get_user(params.avail_min, &src->avail_min) ||
get_user(params.mode, &src->mode) ||
get_user(val, &src->no_active_sensing))
return -EFAULT;
params.no_active_sensing = val;

View File

@ -67,13 +67,16 @@ static int __init alsa_seq_oss_init(void)
{
int rc;
if ((rc = register_device()) < 0)
rc = register_device();
if (rc < 0)
goto error;
if ((rc = register_proc()) < 0) {
rc = register_proc();
if (rc < 0) {
unregister_device();
goto error;
}
if ((rc = snd_seq_oss_create_client()) < 0) {
rc = snd_seq_oss_create_client();
if (rc < 0) {
unregister_proc();
unregister_device();
goto error;
@ -133,7 +136,8 @@ odev_release(struct inode *inode, struct file *file)
{
struct seq_oss_devinfo *dp;
if ((dp = file->private_data) == NULL)
dp = file->private_data;
if (!dp)
return 0;
mutex_lock(&register_mutex);
@ -226,16 +230,18 @@ register_device(void)
int rc;
mutex_lock(&register_mutex);
if ((rc = snd_register_oss_device(SNDRV_OSS_DEVICE_TYPE_SEQUENCER,
NULL, 0,
&seq_oss_f_ops, NULL)) < 0) {
rc = snd_register_oss_device(SNDRV_OSS_DEVICE_TYPE_SEQUENCER,
NULL, 0,
&seq_oss_f_ops, NULL);
if (rc < 0) {
pr_err("ALSA: seq_oss: can't register device seq\n");
mutex_unlock(&register_mutex);
return rc;
}
if ((rc = snd_register_oss_device(SNDRV_OSS_DEVICE_TYPE_MUSIC,
NULL, 0,
&seq_oss_f_ops, NULL)) < 0) {
rc = snd_register_oss_device(SNDRV_OSS_DEVICE_TYPE_MUSIC,
NULL, 0,
&seq_oss_f_ops, NULL);
if (rc < 0) {
pr_err("ALSA: seq_oss: can't register device music\n");
snd_unregister_oss_device(SNDRV_OSS_DEVICE_TYPE_SEQUENCER, NULL, 0);
mutex_unlock(&register_mutex);

View File

@ -94,10 +94,10 @@ snd_seq_oss_create_client(void)
port_callback.event_input = receive_announce;
port->kernel = &port_callback;
call_ctl(SNDRV_SEQ_IOCTL_CREATE_PORT, port);
if ((system_port = port->addr.port) >= 0) {
if (call_ctl(SNDRV_SEQ_IOCTL_CREATE_PORT, port) >= 0) {
struct snd_seq_port_subscribe subs;
system_port = port->addr.port;
memset(&subs, 0, sizeof(subs));
subs.sender.client = SNDRV_SEQ_CLIENT_SYSTEM;
subs.sender.port = SNDRV_SEQ_PORT_SYSTEM_ANNOUNCE;
@ -354,7 +354,8 @@ alloc_seq_queue(struct seq_oss_devinfo *dp)
qinfo.owner = system_client;
qinfo.locked = 1;
strcpy(qinfo.name, "OSS Sequencer Emulation");
if ((rc = call_ctl(SNDRV_SEQ_IOCTL_CREATE_QUEUE, &qinfo)) < 0)
rc = call_ctl(SNDRV_SEQ_IOCTL_CREATE_QUEUE, &qinfo);
if (rc < 0)
return rc;
dp->queue = qinfo.queue;
return 0;
@ -485,7 +486,8 @@ snd_seq_oss_system_info_read(struct snd_info_buffer *buf)
snd_iprintf(buf, "\nNumber of applications: %d\n", num_clients);
for (i = 0; i < num_clients; i++) {
snd_iprintf(buf, "\nApplication %d: ", i);
if ((dp = client_table[i]) == NULL) {
dp = client_table[i];
if (!dp) {
snd_iprintf(buf, "*empty*\n");
continue;
}

View File

@ -152,7 +152,8 @@ snd_seq_oss_midi_check_new_port(struct snd_seq_port_info *pinfo)
/*
* look for the identical slot
*/
if ((mdev = find_slot(pinfo->addr.client, pinfo->addr.port)) != NULL) {
mdev = find_slot(pinfo->addr.client, pinfo->addr.port);
if (mdev) {
/* already exists */
snd_use_lock_free(&mdev->use_lock);
return 0;
@ -218,7 +219,8 @@ snd_seq_oss_midi_check_exit_port(int client, int port)
unsigned long flags;
int index;
if ((mdev = find_slot(client, port)) != NULL) {
mdev = find_slot(client, port);
if (mdev) {
spin_lock_irqsave(&register_lock, flags);
midi_devs[mdev->seq_device] = NULL;
spin_unlock_irqrestore(&register_lock, flags);
@ -250,7 +252,8 @@ snd_seq_oss_midi_clear_all(void)
spin_lock_irqsave(&register_lock, flags);
for (i = 0; i < max_midi_devs; i++) {
if ((mdev = midi_devs[i]) != NULL) {
mdev = midi_devs[i];
if (mdev) {
snd_midi_event_free(mdev->coder);
kfree(mdev);
midi_devs[i] = NULL;
@ -318,7 +321,8 @@ snd_seq_oss_midi_open(struct seq_oss_devinfo *dp, int dev, int fmode)
struct seq_oss_midi *mdev;
struct snd_seq_port_subscribe subs;
if ((mdev = get_mididev(dp, dev)) == NULL)
mdev = get_mididev(dp, dev);
if (!mdev)
return -ENODEV;
/* already used? */
@ -384,7 +388,8 @@ snd_seq_oss_midi_close(struct seq_oss_devinfo *dp, int dev)
struct seq_oss_midi *mdev;
struct snd_seq_port_subscribe subs;
if ((mdev = get_mididev(dp, dev)) == NULL)
mdev = get_mididev(dp, dev);
if (!mdev)
return -ENODEV;
if (! mdev->opened || mdev->devinfo != dp) {
snd_use_lock_free(&mdev->use_lock);
@ -421,7 +426,8 @@ snd_seq_oss_midi_filemode(struct seq_oss_devinfo *dp, int dev)
struct seq_oss_midi *mdev;
int mode;
if ((mdev = get_mididev(dp, dev)) == NULL)
mdev = get_mididev(dp, dev);
if (!mdev)
return 0;
mode = 0;
@ -443,7 +449,8 @@ snd_seq_oss_midi_reset(struct seq_oss_devinfo *dp, int dev)
{
struct seq_oss_midi *mdev;
if ((mdev = get_mididev(dp, dev)) == NULL)
mdev = get_mididev(dp, dev);
if (!mdev)
return;
if (! mdev->opened) {
snd_use_lock_free(&mdev->use_lock);
@ -491,7 +498,8 @@ snd_seq_oss_midi_get_addr(struct seq_oss_devinfo *dp, int dev, struct snd_seq_ad
{
struct seq_oss_midi *mdev;
if ((mdev = get_mididev(dp, dev)) == NULL)
mdev = get_mididev(dp, dev);
if (!mdev)
return;
addr->client = mdev->client;
addr->port = mdev->port;
@ -511,7 +519,8 @@ snd_seq_oss_midi_input(struct snd_seq_event *ev, int direct, void *private_data)
if (dp->readq == NULL)
return 0;
if ((mdev = find_slot(ev->source.client, ev->source.port)) == NULL)
mdev = find_slot(ev->source.client, ev->source.port);
if (!mdev)
return 0;
if (! (mdev->opened & PERM_READ)) {
snd_use_lock_free(&mdev->use_lock);
@ -623,7 +632,8 @@ snd_seq_oss_midi_putc(struct seq_oss_devinfo *dp, int dev, unsigned char c, stru
{
struct seq_oss_midi *mdev;
if ((mdev = get_mididev(dp, dev)) == NULL)
mdev = get_mididev(dp, dev);
if (!mdev)
return -ENODEV;
if (snd_midi_event_encode_byte(mdev->coder, c, ev)) {
snd_seq_oss_fill_addr(dp, ev, mdev->client, mdev->port);
@ -642,7 +652,8 @@ snd_seq_oss_midi_make_info(struct seq_oss_devinfo *dp, int dev, struct midi_info
{
struct seq_oss_midi *mdev;
if ((mdev = get_mididev(dp, dev)) == NULL)
mdev = get_mididev(dp, dev);
if (!mdev)
return -ENXIO;
inf->device = dev;
inf->dev_type = 0; /* FIXME: ?? */

View File

@ -132,7 +132,8 @@ snd_seq_oss_write(struct seq_oss_devinfo *dp, const char __user *buf, int count,
}
/* insert queue */
if ((err = insert_queue(dp, &rec, opt)) < 0)
err = insert_queue(dp, &rec, opt);
if (err < 0)
break;
result += ev_size;

View File

@ -451,7 +451,8 @@ snd_seq_oss_synth_load_patch(struct seq_oss_devinfo *dp, int dev, int fmt,
if (info->is_midi)
return 0;
if ((rec = get_synthdev(dp, dev)) == NULL)
rec = get_synthdev(dp, dev);
if (!rec)
return -ENXIO;
if (rec->oper.load_patch == NULL)
@ -569,7 +570,8 @@ snd_seq_oss_synth_ioctl(struct seq_oss_devinfo *dp, int dev, unsigned int cmd, u
info = get_synthinfo_nospec(dp, dev);
if (!info || info->is_midi)
return -ENXIO;
if ((rec = get_synthdev(dp, dev)) == NULL)
rec = get_synthdev(dp, dev);
if (!rec)
return -ENXIO;
if (rec->oper.ioctl == NULL)
rc = -ENXIO;
@ -619,7 +621,8 @@ snd_seq_oss_synth_make_info(struct seq_oss_devinfo *dp, int dev, struct synth_in
inf->device = dev;
strscpy(inf->name, minf.name, sizeof(inf->name));
} else {
if ((rec = get_synthdev(dp, dev)) == NULL)
rec = get_synthdev(dp, dev);
if (!rec)
return -ENXIO;
inf->synth_type = rec->synth_type;
inf->synth_subtype = rec->synth_subtype;

View File

@ -27,7 +27,8 @@ snd_seq_oss_writeq_new(struct seq_oss_devinfo *dp, int maxlen)
struct seq_oss_writeq *q;
struct snd_seq_client_pool pool;
if ((q = kzalloc(sizeof(*q), GFP_KERNEL)) == NULL)
q = kzalloc(sizeof(*q), GFP_KERNEL);
if (!q)
return NULL;
q->dp = dp;
q->maxlen = maxlen;

View File

@ -416,7 +416,10 @@ static ssize_t snd_seq_read(struct file *file, char __user *buf, size_t count,
if (snd_BUG_ON(!client))
return -ENXIO;
if (!client->accept_input || (fifo = client->data.user.fifo) == NULL)
if (!client->accept_input)
return -ENXIO;
fifo = client->data.user.fifo;
if (!fifo)
return -ENXIO;
if (atomic_read(&fifo->overflow) > 0) {
@ -435,9 +438,9 @@ static ssize_t snd_seq_read(struct file *file, char __user *buf, size_t count,
int nonblock;
nonblock = (file->f_flags & O_NONBLOCK) || result > 0;
if ((err = snd_seq_fifo_cell_out(fifo, &cell, nonblock)) < 0) {
err = snd_seq_fifo_cell_out(fifo, &cell, nonblock);
if (err < 0)
break;
}
if (snd_seq_ev_is_variable(&cell->event)) {
struct snd_seq_event tmpev;
tmpev = cell->event;
@ -970,7 +973,8 @@ static int snd_seq_client_enqueue_event(struct snd_seq_client *client,
return err;
/* we got a cell. enqueue it. */
if ((err = snd_seq_enqueue_event(cell, atomic, hop)) < 0) {
err = snd_seq_enqueue_event(cell, atomic, hop);
if (err < 0) {
snd_seq_cell_free(cell);
return err;
}
@ -1312,7 +1316,8 @@ static int snd_seq_ioctl_create_port(struct snd_seq_client *client, void *arg)
return -EINVAL;
}
if (client->type == KERNEL_CLIENT) {
if ((callback = info->kernel) != NULL) {
callback = info->kernel;
if (callback) {
if (callback->owner)
port->owner = callback->owner;
port->private_data = callback->private_data;
@ -1466,13 +1471,17 @@ static int snd_seq_ioctl_subscribe_port(struct snd_seq_client *client,
struct snd_seq_client *receiver = NULL, *sender = NULL;
struct snd_seq_client_port *sport = NULL, *dport = NULL;
if ((receiver = snd_seq_client_use_ptr(subs->dest.client)) == NULL)
receiver = snd_seq_client_use_ptr(subs->dest.client);
if (!receiver)
goto __end;
if ((sender = snd_seq_client_use_ptr(subs->sender.client)) == NULL)
sender = snd_seq_client_use_ptr(subs->sender.client);
if (!sender)
goto __end;
if ((sport = snd_seq_port_use_ptr(sender, subs->sender.port)) == NULL)
sport = snd_seq_port_use_ptr(sender, subs->sender.port);
if (!sport)
goto __end;
if ((dport = snd_seq_port_use_ptr(receiver, subs->dest.port)) == NULL)
dport = snd_seq_port_use_ptr(receiver, subs->dest.port);
if (!dport)
goto __end;
result = check_subscription_permission(client, sport, dport, subs);
@ -1508,13 +1517,17 @@ static int snd_seq_ioctl_unsubscribe_port(struct snd_seq_client *client,
struct snd_seq_client *receiver = NULL, *sender = NULL;
struct snd_seq_client_port *sport = NULL, *dport = NULL;
if ((receiver = snd_seq_client_use_ptr(subs->dest.client)) == NULL)
receiver = snd_seq_client_use_ptr(subs->dest.client);
if (!receiver)
goto __end;
if ((sender = snd_seq_client_use_ptr(subs->sender.client)) == NULL)
sender = snd_seq_client_use_ptr(subs->sender.client);
if (!sender)
goto __end;
if ((sport = snd_seq_port_use_ptr(sender, subs->sender.port)) == NULL)
sport = snd_seq_port_use_ptr(sender, subs->sender.port);
if (!sport)
goto __end;
if ((dport = snd_seq_port_use_ptr(receiver, subs->dest.port)) == NULL)
dport = snd_seq_port_use_ptr(receiver, subs->dest.port);
if (!dport)
goto __end;
result = check_subscription_permission(client, sport, dport, subs);
@ -1926,9 +1939,11 @@ static int snd_seq_ioctl_get_subscription(struct snd_seq_client *client,
struct snd_seq_client_port *sport = NULL;
result = -EINVAL;
if ((sender = snd_seq_client_use_ptr(subs->sender.client)) == NULL)
sender = snd_seq_client_use_ptr(subs->sender.client);
if (!sender)
goto __end;
if ((sport = snd_seq_port_use_ptr(sender, subs->sender.port)) == NULL)
sport = snd_seq_port_use_ptr(sender, subs->sender.port);
if (!sport)
goto __end;
result = snd_seq_port_get_subscription(&sport->c_src, &subs->dest,
subs);
@ -1955,9 +1970,11 @@ static int snd_seq_ioctl_query_subs(struct snd_seq_client *client, void *arg)
struct list_head *p;
int i;
if ((cptr = snd_seq_client_use_ptr(subs->root.client)) == NULL)
cptr = snd_seq_client_use_ptr(subs->root.client);
if (!cptr)
goto __end;
if ((port = snd_seq_port_use_ptr(cptr, subs->root.port)) == NULL)
port = snd_seq_port_use_ptr(cptr, subs->root.port);
if (!port)
goto __end;
switch (subs->type) {

View File

@ -109,7 +109,8 @@ create_port(int idx, int type)
struct snd_seq_port_callback pcb;
struct snd_seq_dummy_port *rec;
if ((rec = kzalloc(sizeof(*rec), GFP_KERNEL)) == NULL)
rec = kzalloc(sizeof(*rec), GFP_KERNEL);
if (!rec)
return NULL;
rec->client = my_client;

View File

@ -143,7 +143,8 @@ static struct snd_seq_event_cell *fifo_cell_out(struct snd_seq_fifo *f)
{
struct snd_seq_event_cell *cell;
if ((cell = f->head) != NULL) {
cell = f->head;
if (cell) {
f->head = cell->next;
/* reset tail if this was the last element */

View File

@ -69,7 +69,8 @@ int snd_seq_dump_var_event(const struct snd_seq_event *event,
int len, err;
struct snd_seq_event_cell *cell;
if ((len = get_var_len(event)) <= 0)
len = get_var_len(event);
if (len <= 0)
return len;
if (event->data.ext.len & SNDRV_SEQ_EXT_USRPTR) {
@ -133,7 +134,8 @@ int snd_seq_expand_var_event(const struct snd_seq_event *event, int count, char
int len, newlen;
int err;
if ((len = get_var_len(event)) < 0)
len = get_var_len(event);
if (len < 0)
return len;
newlen = len;
if (size_aligned > 0)

View File

@ -101,7 +101,8 @@ static int dump_midi(struct snd_rawmidi_substream *substream, const char *buf, i
if (snd_BUG_ON(!substream || !buf))
return -EINVAL;
runtime = substream->runtime;
if ((tmp = runtime->avail) < count) {
tmp = runtime->avail;
if (tmp < count) {
if (printk_ratelimit())
pr_err("ALSA: seq_midi: MIDI output buffer overrun\n");
return -ENOMEM;
@ -167,10 +168,11 @@ static int midisynth_subscribe(void *private_data, struct snd_seq_port_subscribe
struct snd_rawmidi_params params;
/* open midi port */
if ((err = snd_rawmidi_kernel_open(msynth->card, msynth->device,
msynth->subdevice,
SNDRV_RAWMIDI_LFLG_INPUT,
&msynth->input_rfile)) < 0) {
err = snd_rawmidi_kernel_open(msynth->card, msynth->device,
msynth->subdevice,
SNDRV_RAWMIDI_LFLG_INPUT,
&msynth->input_rfile);
if (err < 0) {
pr_debug("ALSA: seq_midi: midi input open failed!!!\n");
return err;
}
@ -178,7 +180,8 @@ static int midisynth_subscribe(void *private_data, struct snd_seq_port_subscribe
memset(&params, 0, sizeof(params));
params.avail_min = 1;
params.buffer_size = input_buffer_size;
if ((err = snd_rawmidi_input_params(msynth->input_rfile.input, &params)) < 0) {
err = snd_rawmidi_input_params(msynth->input_rfile.input, &params);
if (err < 0) {
snd_rawmidi_kernel_release(&msynth->input_rfile);
return err;
}
@ -209,10 +212,11 @@ static int midisynth_use(void *private_data, struct snd_seq_port_subscribe *info
struct snd_rawmidi_params params;
/* open midi port */
if ((err = snd_rawmidi_kernel_open(msynth->card, msynth->device,
msynth->subdevice,
SNDRV_RAWMIDI_LFLG_OUTPUT,
&msynth->output_rfile)) < 0) {
err = snd_rawmidi_kernel_open(msynth->card, msynth->device,
msynth->subdevice,
SNDRV_RAWMIDI_LFLG_OUTPUT,
&msynth->output_rfile);
if (err < 0) {
pr_debug("ALSA: seq_midi: midi output open failed!!!\n");
return err;
}
@ -220,7 +224,8 @@ static int midisynth_use(void *private_data, struct snd_seq_port_subscribe *info
params.avail_min = 1;
params.buffer_size = output_buffer_size;
params.no_active_sensing = 1;
if ((err = snd_rawmidi_output_params(msynth->output_rfile.output, &params)) < 0) {
err = snd_rawmidi_output_params(msynth->output_rfile.output, &params);
if (err < 0) {
snd_rawmidi_kernel_release(&msynth->output_rfile);
return err;
}

View File

@ -222,7 +222,8 @@ struct snd_seq_queue *snd_seq_queue_find_name(char *name)
struct snd_seq_queue *q;
for (i = 0; i < SNDRV_SEQ_MAX_QUEUES; i++) {
if ((q = queueptr(i)) != NULL) {
q = queueptr(i);
if (q) {
if (strncmp(q->name, name, sizeof(q->name)) == 0)
return q;
queuefree(q);
@ -432,7 +433,8 @@ int snd_seq_queue_timer_open(int queueid)
if (queue == NULL)
return -EINVAL;
tmr = queue->timer;
if ((result = snd_seq_timer_open(queue)) < 0) {
result = snd_seq_timer_open(queue);
if (result < 0) {
snd_seq_timer_defaults(tmr);
result = snd_seq_timer_open(queue);
}
@ -548,7 +550,8 @@ void snd_seq_queue_client_leave(int client)
/* delete own queues from queue list */
for (i = 0; i < SNDRV_SEQ_MAX_QUEUES; i++) {
if ((q = queue_list_remove(i, client)) != NULL)
q = queue_list_remove(i, client);
if (q)
queue_delete(q);
}
@ -556,7 +559,8 @@ void snd_seq_queue_client_leave(int client)
* they are not owned by this client
*/
for (i = 0; i < SNDRV_SEQ_MAX_QUEUES; i++) {
if ((q = queueptr(i)) == NULL)
q = queueptr(i);
if (!q)
continue;
if (test_bit(client, q->clients_bitmap)) {
snd_seq_prioq_leave(q->tickq, client, 0);
@ -578,7 +582,8 @@ void snd_seq_queue_client_leave_cells(int client)
struct snd_seq_queue *q;
for (i = 0; i < SNDRV_SEQ_MAX_QUEUES; i++) {
if ((q = queueptr(i)) == NULL)
q = queueptr(i);
if (!q)
continue;
snd_seq_prioq_leave(q->tickq, client, 0);
snd_seq_prioq_leave(q->timeq, client, 0);
@ -593,7 +598,8 @@ void snd_seq_queue_remove_cells(int client, struct snd_seq_remove_events *info)
struct snd_seq_queue *q;
for (i = 0; i < SNDRV_SEQ_MAX_QUEUES; i++) {
if ((q = queueptr(i)) == NULL)
q = queueptr(i);
if (!q)
continue;
if (test_bit(client, q->clients_bitmap) &&
(! (info->remove_mode & SNDRV_SEQ_REMOVE_DEST) ||
@ -724,7 +730,8 @@ void snd_seq_info_queues_read(struct snd_info_entry *entry,
int owner;
for (i = 0; i < SNDRV_SEQ_MAX_QUEUES; i++) {
if ((q = queueptr(i)) == NULL)
q = queueptr(i);
if (!q)
continue;
tmr = q->timer;

View File

@ -482,10 +482,11 @@ int snd_virmidi_new(struct snd_card *card, int device, struct snd_rawmidi **rrmi
int err;
*rrmidi = NULL;
if ((err = snd_rawmidi_new(card, "VirMidi", device,
16, /* may be configurable */
16, /* may be configurable */
&rmidi)) < 0)
err = snd_rawmidi_new(card, "VirMidi", device,
16, /* may be configurable */
16, /* may be configurable */
&rmidi);
if (err < 0)
return err;
strcpy(rmidi->name, rmidi->id);
rdev = kzalloc(sizeof(*rdev), GFP_KERNEL);

View File

@ -10,20 +10,34 @@
#include <linux/vmalloc.h>
#include <linux/export.h>
#include <sound/memalloc.h>
#include "memalloc_local.h"
struct snd_sg_page {
void *buf;
dma_addr_t addr;
};
struct snd_sg_buf {
int size; /* allocated byte size */
int pages; /* allocated pages */
int tblsize; /* allocated table size */
struct snd_sg_page *table; /* address table */
struct page **page_table; /* page table (for vmap/vunmap) */
struct device *dev;
};
/* table entries are align to 32 */
#define SGBUF_TBL_ALIGN 32
#define sgbuf_align_table(tbl) ALIGN((tbl), SGBUF_TBL_ALIGN)
int snd_free_sgbuf_pages(struct snd_dma_buffer *dmab)
static void snd_dma_sg_free(struct snd_dma_buffer *dmab)
{
struct snd_sg_buf *sgbuf = dmab->private_data;
struct snd_dma_buffer tmpb;
int i;
if (! sgbuf)
return -EINVAL;
if (!sgbuf)
return;
vunmap(dmab->area);
dmab->area = NULL;
@ -45,15 +59,11 @@ int snd_free_sgbuf_pages(struct snd_dma_buffer *dmab)
kfree(sgbuf->page_table);
kfree(sgbuf);
dmab->private_data = NULL;
return 0;
}
#define MAX_ALLOC_PAGES 32
void *snd_malloc_sgbuf_pages(struct device *device,
size_t size, struct snd_dma_buffer *dmab,
size_t *res_size)
static int snd_dma_sg_alloc(struct snd_dma_buffer *dmab, size_t size)
{
struct snd_sg_buf *sgbuf;
unsigned int i, pages, chunk, maxpages;
@ -63,18 +73,16 @@ void *snd_malloc_sgbuf_pages(struct device *device,
int type = SNDRV_DMA_TYPE_DEV;
pgprot_t prot = PAGE_KERNEL;
dmab->area = NULL;
dmab->addr = 0;
dmab->private_data = sgbuf = kzalloc(sizeof(*sgbuf), GFP_KERNEL);
if (! sgbuf)
return NULL;
if (!sgbuf)
return -ENOMEM;
if (dmab->dev.type == SNDRV_DMA_TYPE_DEV_UC_SG) {
type = SNDRV_DMA_TYPE_DEV_UC;
#ifdef pgprot_noncached
prot = pgprot_noncached(PAGE_KERNEL);
#endif
}
sgbuf->dev = device;
sgbuf->dev = dmab->dev.dev;
pages = snd_sgbuf_aligned_pages(size);
sgbuf->tblsize = sgbuf_align_table(pages);
table = kcalloc(sgbuf->tblsize, sizeof(*table), GFP_KERNEL);
@ -94,12 +102,10 @@ void *snd_malloc_sgbuf_pages(struct device *device,
if (chunk > maxpages)
chunk = maxpages;
chunk <<= PAGE_SHIFT;
if (snd_dma_alloc_pages_fallback(type, device,
if (snd_dma_alloc_pages_fallback(type, dmab->dev.dev,
chunk, &tmpb) < 0) {
if (!sgbuf->pages)
goto _failed;
if (!res_size)
goto _failed;
size = sgbuf->pages * PAGE_SIZE;
break;
}
@ -124,27 +130,42 @@ void *snd_malloc_sgbuf_pages(struct device *device,
dmab->area = vmap(sgbuf->page_table, sgbuf->pages, VM_MAP, prot);
if (! dmab->area)
goto _failed;
if (res_size)
*res_size = sgbuf->size;
return dmab->area;
return 0;
_failed:
snd_free_sgbuf_pages(dmab); /* free the table */
return NULL;
snd_dma_sg_free(dmab); /* free the table */
return -ENOMEM;
}
/*
* compute the max chunk size with continuous pages on sg-buffer
*/
unsigned int snd_sgbuf_get_chunk_size(struct snd_dma_buffer *dmab,
unsigned int ofs, unsigned int size)
static dma_addr_t snd_dma_sg_get_addr(struct snd_dma_buffer *dmab,
size_t offset)
{
struct snd_sg_buf *sgbuf = dmab->private_data;
dma_addr_t addr;
addr = sgbuf->table[offset >> PAGE_SHIFT].addr;
addr &= ~((dma_addr_t)PAGE_SIZE - 1);
return addr + offset % PAGE_SIZE;
}
static struct page *snd_dma_sg_get_page(struct snd_dma_buffer *dmab,
size_t offset)
{
struct snd_sg_buf *sgbuf = dmab->private_data;
unsigned int idx = offset >> PAGE_SHIFT;
if (idx >= (unsigned int)sgbuf->pages)
return NULL;
return sgbuf->page_table[idx];
}
static unsigned int snd_dma_sg_get_chunk_size(struct snd_dma_buffer *dmab,
unsigned int ofs,
unsigned int size)
{
struct snd_sg_buf *sg = dmab->private_data;
unsigned int start, end, pg;
if (!sg)
return size;
start = ofs >> PAGE_SHIFT;
end = (ofs + size - 1) >> PAGE_SHIFT;
/* check page continuity */
@ -160,4 +181,11 @@ unsigned int snd_sgbuf_get_chunk_size(struct snd_dma_buffer *dmab,
/* ok, all on continuous pages */
return size;
}
EXPORT_SYMBOL(snd_sgbuf_get_chunk_size);
const struct snd_malloc_ops snd_dma_sg_ops = {
.alloc = snd_dma_sg_alloc,
.free = snd_dma_sg_free,
.get_addr = snd_dma_sg_get_addr,
.get_page = snd_dma_sg_get_page,
.get_chunk_size = snd_dma_sg_get_chunk_size,
};

View File

@ -357,7 +357,8 @@ static void snd_minor_info_read(struct snd_info_entry *entry, struct snd_info_bu
mutex_lock(&sound_mutex);
for (minor = 0; minor < SNDRV_OS_MINORS; ++minor) {
if (!(mptr = snd_minors[minor]))
mptr = snd_minors[minor];
if (!mptr)
continue;
if (mptr->card >= 0) {
if (mptr->device >= 0)

View File

@ -217,7 +217,8 @@ static void snd_minor_info_oss_read(struct snd_info_entry *entry,
mutex_lock(&sound_oss_mutex);
for (minor = 0; minor < SNDRV_OSS_MINORS; ++minor) {
if (!(mptr = snd_oss_minors[minor]))
mptr = snd_oss_minors[minor];
if (!mptr)
continue;
if (mptr->card >= 0)
snd_iprintf(buffer, "%3i: [%i-%2i]: %s\n", minor,

View File

@ -104,7 +104,8 @@ static int snd_mpu401_probe(struct platform_device *devptr)
err = snd_mpu401_create(&devptr->dev, dev, &card);
if (err < 0)
return err;
if ((err = snd_card_register(card)) < 0) {
err = snd_card_register(card);
if (err < 0) {
snd_card_free(card);
return err;
}
@ -182,7 +183,8 @@ static int snd_mpu401_pnp_probe(struct pnp_dev *pnp_dev,
err = snd_mpu401_create(&pnp_dev->dev, dev, &card);
if (err < 0)
return err;
if ((err = snd_card_register(card)) < 0) {
err = snd_card_register(card);
if (err < 0) {
snd_card_free(card);
return err;
}
@ -227,7 +229,8 @@ static int __init alsa_card_mpu401_init(void)
{
int i, err;
if ((err = platform_driver_register(&snd_mpu401_driver)) < 0)
err = platform_driver_register(&snd_mpu401_driver);
if (err < 0)
return err;
for (i = 0; i < SNDRV_CARDS; i++) {

View File

@ -271,8 +271,11 @@ static int snd_mpu401_uart_input_open(struct snd_rawmidi_substream *substream)
int err;
mpu = substream->rmidi->private_data;
if (mpu->open_input && (err = mpu->open_input(mpu)) < 0)
return err;
if (mpu->open_input) {
err = mpu->open_input(mpu);
if (err < 0)
return err;
}
if (! test_bit(MPU401_MODE_BIT_OUTPUT, &mpu->mode)) {
if (snd_mpu401_do_reset(mpu) < 0)
goto error_out;
@ -293,8 +296,11 @@ static int snd_mpu401_uart_output_open(struct snd_rawmidi_substream *substream)
int err;
mpu = substream->rmidi->private_data;
if (mpu->open_output && (err = mpu->open_output(mpu)) < 0)
return err;
if (mpu->open_output) {
err = mpu->open_output(mpu);
if (err < 0)
return err;
}
if (! test_bit(MPU401_MODE_BIT_INPUT, &mpu->mode)) {
if (snd_mpu401_do_reset(mpu) < 0)
goto error_out;
@ -524,8 +530,9 @@ int snd_mpu401_uart_new(struct snd_card *card, int device,
info_flags |= MPU401_INFO_INPUT | MPU401_INFO_OUTPUT;
in_enable = (info_flags & MPU401_INFO_INPUT) ? 1 : 0;
out_enable = (info_flags & MPU401_INFO_OUTPUT) ? 1 : 0;
if ((err = snd_rawmidi_new(card, "MPU-401U", device,
out_enable, in_enable, &rmidi)) < 0)
err = snd_rawmidi_new(card, "MPU-401U", device,
out_enable, in_enable, &rmidi);
if (err < 0)
return err;
mpu = kzalloc(sizeof(*mpu), GFP_KERNEL);
if (!mpu) {

View File

@ -566,7 +566,8 @@ static irqreturn_t snd_mtpav_irqh(int irq, void *dev_id)
*/
static int snd_mtpav_get_ISA(struct mtpav *mcard)
{
if ((mcard->res_port = request_region(port, 3, "MotuMTPAV MIDI")) == NULL) {
mcard->res_port = request_region(port, 3, "MotuMTPAV MIDI");
if (!mcard->res_port) {
snd_printk(KERN_ERR "MTVAP port 0x%lx is busy\n", port);
return -EBUSY;
}
@ -628,10 +629,11 @@ static int snd_mtpav_get_RAWMIDI(struct mtpav *mcard)
hwports = 8;
mcard->num_ports = hwports;
if ((rval = snd_rawmidi_new(mcard->card, "MotuMIDI", 0,
mcard->num_ports * 2 + MTPAV_PIDX_BROADCAST + 1,
mcard->num_ports * 2 + MTPAV_PIDX_BROADCAST + 1,
&mcard->rmidi)) < 0)
rval = snd_rawmidi_new(mcard->card, "MotuMIDI", 0,
mcard->num_ports * 2 + MTPAV_PIDX_BROADCAST + 1,
mcard->num_ports * 2 + MTPAV_PIDX_BROADCAST + 1,
&mcard->rmidi);
if (rval < 0)
return rval;
rawmidi = mcard->rmidi;
rawmidi->private_data = mcard;
@ -744,7 +746,8 @@ static int __init alsa_card_mtpav_init(void)
{
int err;
if ((err = platform_driver_register(&snd_mtpav_driver)) < 0)
err = platform_driver_register(&snd_mtpav_driver);
if (err < 0)
return err;
device = platform_device_register_simple(SND_MTPAV_DRIVER, -1, NULL, 0);

View File

@ -950,7 +950,8 @@ static int snd_mts64_probe(struct platform_device *pdev)
goto free_pardev;
}
if ((err = snd_mts64_create(card, pardev, &mts)) < 0) {
err = snd_mts64_create(card, pardev, &mts);
if (err < 0) {
snd_printd("Cannot create main component\n");
goto release_pardev;
}
@ -963,19 +964,22 @@ static int snd_mts64_probe(struct platform_device *pdev)
goto __err;
}
if ((err = snd_mts64_rawmidi_create(card)) < 0) {
err = snd_mts64_rawmidi_create(card);
if (err < 0) {
snd_printd("Creating Rawmidi component failed\n");
goto __err;
}
/* init device */
if ((err = mts64_device_init(p)) < 0)
err = mts64_device_init(p);
if (err < 0)
goto __err;
platform_set_drvdata(pdev, card);
/* At this point card will be usable */
if ((err = snd_card_register(card)) < 0) {
err = snd_card_register(card);
if (err < 0) {
snd_printd("Cannot register card\n");
goto __err;
}
@ -1031,7 +1035,8 @@ static int __init snd_mts64_module_init(void)
{
int err;
if ((err = platform_driver_register(&snd_mts64_driver)) < 0)
err = platform_driver_register(&snd_mts64_driver);
if (err < 0)
return err;
if (parport_register_driver(&mts64_parport_driver) != 0) {

View File

@ -243,7 +243,8 @@ static int snd_opl3_timer1_init(struct snd_opl3 * opl3, int timer_no)
tid.card = opl3->card->number;
tid.device = timer_no;
tid.subdevice = 0;
if ((err = snd_timer_new(opl3->card, "AdLib timer #1", &tid, &timer)) >= 0) {
err = snd_timer_new(opl3->card, "AdLib timer #1", &tid, &timer);
if (err >= 0) {
strcpy(timer->name, "AdLib timer #1");
timer->private_data = opl3;
timer->hw = snd_opl3_timer1;
@ -263,7 +264,8 @@ static int snd_opl3_timer2_init(struct snd_opl3 * opl3, int timer_no)
tid.card = opl3->card->number;
tid.device = timer_no;
tid.subdevice = 0;
if ((err = snd_timer_new(opl3->card, "AdLib timer #2", &tid, &timer)) >= 0) {
err = snd_timer_new(opl3->card, "AdLib timer #2", &tid, &timer);
if (err >= 0) {
strcpy(timer->name, "AdLib timer #2");
timer->private_data = opl3;
timer->hw = snd_opl3_timer2;
@ -348,7 +350,8 @@ int snd_opl3_new(struct snd_card *card,
spin_lock_init(&opl3->reg_lock);
spin_lock_init(&opl3->timer_lock);
if ((err = snd_device_new(card, SNDRV_DEV_CODEC, opl3, &ops)) < 0) {
err = snd_device_new(card, SNDRV_DEV_CODEC, opl3, &ops);
if (err < 0) {
snd_opl3_free(opl3);
return err;
}
@ -396,19 +399,23 @@ int snd_opl3_create(struct snd_card *card,
int err;
*ropl3 = NULL;
if ((err = snd_opl3_new(card, hardware, &opl3)) < 0)
err = snd_opl3_new(card, hardware, &opl3);
if (err < 0)
return err;
if (! integrated) {
if ((opl3->res_l_port = request_region(l_port, 2, "OPL2/3 (left)")) == NULL) {
opl3->res_l_port = request_region(l_port, 2, "OPL2/3 (left)");
if (!opl3->res_l_port) {
snd_printk(KERN_ERR "opl3: can't grab left port 0x%lx\n", l_port);
snd_device_free(card, opl3);
return -EBUSY;
}
if (r_port != 0 &&
(opl3->res_r_port = request_region(r_port, 2, "OPL2/3 (right)")) == NULL) {
snd_printk(KERN_ERR "opl3: can't grab right port 0x%lx\n", r_port);
snd_device_free(card, opl3);
return -EBUSY;
if (r_port != 0) {
opl3->res_r_port = request_region(r_port, 2, "OPL2/3 (right)");
if (!opl3->res_r_port) {
snd_printk(KERN_ERR "opl3: can't grab right port 0x%lx\n", r_port);
snd_device_free(card, opl3);
return -EBUSY;
}
}
}
opl3->l_port = l_port;
@ -423,7 +430,8 @@ int snd_opl3_create(struct snd_card *card,
break;
default:
opl3->command = &snd_opl2_command;
if ((err = snd_opl3_detect(opl3)) < 0) {
err = snd_opl3_detect(opl3);
if (err < 0) {
snd_printd("OPL2/3 chip not detected at 0x%lx/0x%lx\n",
opl3->l_port, opl3->r_port);
snd_device_free(card, opl3);
@ -449,11 +457,14 @@ int snd_opl3_timer_new(struct snd_opl3 * opl3, int timer1_dev, int timer2_dev)
{
int err;
if (timer1_dev >= 0)
if ((err = snd_opl3_timer1_init(opl3, timer1_dev)) < 0)
if (timer1_dev >= 0) {
err = snd_opl3_timer1_init(opl3, timer1_dev);
if (err < 0)
return err;
}
if (timer2_dev >= 0) {
if ((err = snd_opl3_timer2_init(opl3, timer2_dev)) < 0) {
err = snd_opl3_timer2_init(opl3, timer2_dev);
if (err < 0) {
snd_device_free(opl3->card, opl3->timer1);
opl3->timer1 = NULL;
return err;
@ -477,7 +488,8 @@ int snd_opl3_hwdep_new(struct snd_opl3 * opl3,
/* create hardware dependent device (direct FM) */
if ((err = snd_hwdep_new(card, "OPL2/OPL3", device, &hw)) < 0) {
err = snd_hwdep_new(card, "OPL2/OPL3", device, &hw);
if (err < 0) {
snd_device_free(card, opl3);
return err;
}

View File

@ -180,8 +180,7 @@ static int opl3_get_voice(struct snd_opl3 *opl3, int instr_4op,
if (vp2->state == SNDRV_OPL3_ST_ON_2OP) {
/* kill two voices, EXPENSIVE */
bp++;
voice_time = (voice_time > vp->time) ?
voice_time : vp->time;
voice_time = max(voice_time, vp2->time);
}
} else {
/* allocate 2op voice */

View File

@ -136,7 +136,8 @@ static int snd_opl3_open_seq_oss(struct snd_seq_oss_arg *arg, void *closure)
if (snd_BUG_ON(!arg))
return -ENXIO;
if ((err = snd_opl3_synth_setup(opl3)) < 0)
err = snd_opl3_synth_setup(opl3);
if (err < 0)
return err;
/* fill the argument data */
@ -144,7 +145,8 @@ static int snd_opl3_open_seq_oss(struct snd_seq_oss_arg *arg, void *closure)
arg->addr.client = opl3->oss_chset->client;
arg->addr.port = opl3->oss_chset->port;
if ((err = snd_opl3_synth_use_inc(opl3)) < 0)
err = snd_opl3_synth_use_inc(opl3);
if (err < 0)
return err;
opl3->synth_mode = SNDRV_OPL3_MODE_SYNTH;

View File

@ -92,7 +92,8 @@ static int snd_opl3_synth_use(void *private_data, struct snd_seq_port_subscribe
struct snd_opl3 *opl3 = private_data;
int err;
if ((err = snd_opl3_synth_setup(opl3)) < 0)
err = snd_opl3_synth_setup(opl3);
if (err < 0)
return err;
if (use_internal_drums) {
@ -107,7 +108,8 @@ static int snd_opl3_synth_use(void *private_data, struct snd_seq_port_subscribe
}
if (info->sender.client != SNDRV_SEQ_CLIENT_SYSTEM) {
if ((err = snd_opl3_synth_use_inc(opl3)) < 0)
err = snd_opl3_synth_use_inc(opl3);
if (err < 0)
return err;
}
opl3->synth_mode = SNDRV_OPL3_MODE_SEQ;
@ -227,7 +229,8 @@ static int snd_opl3_seq_probe(struct device *_dev)
if (client < 0)
return client;
if ((err = snd_opl3_synth_create_port(opl3)) < 0) {
err = snd_opl3_synth_create_port(opl3);
if (err < 0) {
snd_seq_delete_kernel_client(client);
opl3->seq_client = -1;
return err;

View File

@ -749,7 +749,8 @@ static int snd_portman_probe(struct platform_device *pdev)
goto free_pardev;
}
if ((err = portman_create(card, pardev, &pm)) < 0) {
err = portman_create(card, pardev, &pm);
if (err < 0) {
snd_printd("Cannot create main component\n");
goto release_pardev;
}
@ -762,19 +763,22 @@ static int snd_portman_probe(struct platform_device *pdev)
goto __err;
}
if ((err = snd_portman_rawmidi_create(card)) < 0) {
err = snd_portman_rawmidi_create(card);
if (err < 0) {
snd_printd("Creating Rawmidi component failed\n");
goto __err;
}
/* init device */
if ((err = portman_device_init(pm)) < 0)
err = portman_device_init(pm);
if (err < 0)
goto __err;
platform_set_drvdata(pdev, card);
/* At this point card will be usable */
if ((err = snd_card_register(card)) < 0) {
err = snd_card_register(card);
if (err < 0) {
snd_printd("Cannot register card\n");
goto __err;
}
@ -831,7 +835,8 @@ static int __init snd_portman_module_init(void)
{
int err;
if ((err = platform_driver_register(&snd_portman_driver)) < 0)
err = platform_driver_register(&snd_portman_driver);
if (err < 0)
return err;
if (parport_register_driver(&portman_parport_driver) != 0) {

View File

@ -783,7 +783,8 @@ static int snd_uart16550_create(struct snd_card *card,
int err;
if ((uart = kzalloc(sizeof(*uart), GFP_KERNEL)) == NULL)
uart = kzalloc(sizeof(*uart), GFP_KERNEL);
if (!uart)
return -ENOMEM;
uart->adaptor = adaptor;
uart->card = card;
@ -792,7 +793,8 @@ static int snd_uart16550_create(struct snd_card *card,
uart->base = iobase;
uart->drop_on_full = droponfull;
if ((err = snd_uart16550_detect(uart)) <= 0) {
err = snd_uart16550_detect(uart);
if (err <= 0) {
printk(KERN_ERR "no UART detected at 0x%lx\n", iobase);
snd_uart16550_free(uart);
return -ENODEV;
@ -818,7 +820,8 @@ static int snd_uart16550_create(struct snd_card *card,
uart->timer_running = 0;
/* Register device */
if ((err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, uart, &ops)) < 0) {
err = snd_device_new(card, SNDRV_DEV_LOWLEVEL, uart, &ops);
if (err < 0) {
snd_uart16550_free(uart);
return err;
}
@ -932,14 +935,10 @@ static int snd_serial_probe(struct platform_device *devptr)
strcpy(card->driver, "Serial");
strcpy(card->shortname, "Serial MIDI (UART16550A)");
if ((err = snd_uart16550_create(card,
port[dev],
irq[dev],
speed[dev],
base[dev],
adaptor[dev],
droponfull[dev],
&uart)) < 0)
err = snd_uart16550_create(card, port[dev], irq[dev], speed[dev],
base[dev], adaptor[dev], droponfull[dev],
&uart);
if (err < 0)
goto _err;
err = snd_uart16550_rmidi(uart, 0, outs[dev], ins[dev], &uart->rmidi);
@ -952,7 +951,8 @@ static int snd_serial_probe(struct platform_device *devptr)
uart->base,
uart->irq);
if ((err = snd_card_register(card)) < 0)
err = snd_card_register(card);
if (err < 0)
goto _err;
platform_set_drvdata(devptr, card);
@ -992,7 +992,8 @@ static int __init alsa_card_serial_init(void)
{
int i, cards, err;
if ((err = platform_driver_register(&snd_serial_driver)) < 0)
err = platform_driver_register(&snd_serial_driver);
if (err < 0)
return err;
cards = 0;

View File

@ -110,20 +110,25 @@ static int vx_transfer_end(struct vx_core *chip, int cmd)
{
int err;
if ((err = vx_reset_chk(chip)) < 0)
err = vx_reset_chk(chip);
if (err < 0)
return err;
/* irq MESS_READ/WRITE_END */
if ((err = vx_send_irq_dsp(chip, cmd)) < 0)
err = vx_send_irq_dsp(chip, cmd);
if (err < 0)
return err;
/* Wait CHK = 1 */
if ((err = vx_wait_isr_bit(chip, ISR_CHK)) < 0)
err = vx_wait_isr_bit(chip, ISR_CHK);
if (err < 0)
return err;
/* If error, Read RX */
if ((err = vx_inb(chip, ISR)) & ISR_ERR) {
if ((err = vx_wait_for_rx_full(chip)) < 0) {
err = vx_inb(chip, ISR);
if (err & ISR_ERR) {
err = vx_wait_for_rx_full(chip);
if (err < 0) {
snd_printd(KERN_DEBUG "transfer_end: error in rx_full\n");
return err;
}
@ -232,7 +237,8 @@ int vx_send_msg_nolock(struct vx_core *chip, struct vx_rmh *rmh)
if (chip->chip_status & VX_STAT_IS_STALE)
return -EBUSY;
if ((err = vx_reset_chk(chip)) < 0) {
err = vx_reset_chk(chip);
if (err < 0) {
snd_printd(KERN_DEBUG "vx_send_msg: vx_reset_chk error\n");
return err;
}
@ -254,7 +260,8 @@ int vx_send_msg_nolock(struct vx_core *chip, struct vx_rmh *rmh)
rmh->Cmd[0] &= MASK_1_WORD_COMMAND;
/* Wait for TX empty */
if ((err = vx_wait_isr_bit(chip, ISR_TX_EMPTY)) < 0) {
err = vx_wait_isr_bit(chip, ISR_TX_EMPTY);
if (err < 0) {
snd_printd(KERN_DEBUG "vx_send_msg: wait tx empty error\n");
return err;
}
@ -265,18 +272,21 @@ int vx_send_msg_nolock(struct vx_core *chip, struct vx_rmh *rmh)
vx_outb(chip, TXL, rmh->Cmd[0] & 0xff);
/* Trigger irq MESSAGE */
if ((err = vx_send_irq_dsp(chip, IRQ_MESSAGE)) < 0) {
err = vx_send_irq_dsp(chip, IRQ_MESSAGE);
if (err < 0) {
snd_printd(KERN_DEBUG "vx_send_msg: send IRQ_MESSAGE error\n");
return err;
}
/* Wait for CHK = 1 */
if ((err = vx_wait_isr_bit(chip, ISR_CHK)) < 0)
err = vx_wait_isr_bit(chip, ISR_CHK);
if (err < 0)
return err;
/* If error, get error value from RX */
if (vx_inb(chip, ISR) & ISR_ERR) {
if ((err = vx_wait_for_rx_full(chip)) < 0) {
err = vx_wait_for_rx_full(chip);
if (err < 0) {
snd_printd(KERN_DEBUG "vx_send_msg: rx_full read error\n");
return err;
}
@ -292,7 +302,8 @@ int vx_send_msg_nolock(struct vx_core *chip, struct vx_rmh *rmh)
if (rmh->LgCmd > 1) {
for (i = 1; i < rmh->LgCmd; i++) {
/* Wait for TX ready */
if ((err = vx_wait_isr_bit(chip, ISR_TX_READY)) < 0) {
err = vx_wait_isr_bit(chip, ISR_TX_READY);
if (err < 0) {
snd_printd(KERN_DEBUG "vx_send_msg: tx_ready error\n");
return err;
}
@ -303,13 +314,15 @@ int vx_send_msg_nolock(struct vx_core *chip, struct vx_rmh *rmh)
vx_outb(chip, TXL, rmh->Cmd[i] & 0xff);
/* Trigger irq MESS_READ_NEXT */
if ((err = vx_send_irq_dsp(chip, IRQ_MESS_READ_NEXT)) < 0) {
err = vx_send_irq_dsp(chip, IRQ_MESS_READ_NEXT);
if (err < 0) {
snd_printd(KERN_DEBUG "vx_send_msg: IRQ_READ_NEXT error\n");
return err;
}
}
/* Wait for TX empty */
if ((err = vx_wait_isr_bit(chip, ISR_TX_READY)) < 0) {
err = vx_wait_isr_bit(chip, ISR_TX_READY);
if (err < 0) {
snd_printd(KERN_DEBUG "vx_send_msg: TX_READY error\n");
return err;
}
@ -362,17 +375,21 @@ int vx_send_rih_nolock(struct vx_core *chip, int cmd)
#if 0
printk(KERN_DEBUG "send_rih: cmd = 0x%x\n", cmd);
#endif
if ((err = vx_reset_chk(chip)) < 0)
err = vx_reset_chk(chip);
if (err < 0)
return err;
/* send the IRQ */
if ((err = vx_send_irq_dsp(chip, cmd)) < 0)
err = vx_send_irq_dsp(chip, cmd);
if (err < 0)
return err;
/* Wait CHK = 1 */
if ((err = vx_wait_isr_bit(chip, ISR_CHK)) < 0)
err = vx_wait_isr_bit(chip, ISR_CHK);
if (err < 0)
return err;
/* If error, read RX */
if (vx_inb(chip, ISR) & ISR_ERR) {
if ((err = vx_wait_for_rx_full(chip)) < 0)
err = vx_wait_for_rx_full(chip);
if (err < 0)
return err;
err = vx_inb(chip, RXH) << 16;
err |= vx_inb(chip, RXM) << 8;
@ -648,7 +665,8 @@ int snd_vx_dsp_boot(struct vx_core *chip, const struct firmware *boot)
vx_reset_board(chip, cold_reset);
vx_validate_irq(chip, 0);
if ((err = snd_vx_load_boot_image(chip, boot)) < 0)
err = snd_vx_load_boot_image(chip, boot);
if (err < 0)
return err;
msleep(10);
@ -678,7 +696,8 @@ int snd_vx_dsp_load(struct vx_core *chip, const struct firmware *dsp)
for (i = 0; i < dsp->size; i += 3) {
image = dsp->data + i;
/* Wait DSP ready for a new read */
if ((err = vx_wait_isr_bit(chip, ISR_TX_EMPTY)) < 0) {
err = vx_wait_isr_bit(chip, ISR_TX_EMPTY);
if (err < 0) {
printk(KERN_ERR
"dsp loading error at position %d\n", i);
return err;
@ -698,7 +717,8 @@ int snd_vx_dsp_load(struct vx_core *chip, const struct firmware *dsp)
msleep(200);
if ((err = vx_wait_isr_bit(chip, ISR_CHK)) < 0)
err = vx_wait_isr_bit(chip, ISR_CHK);
if (err < 0)
return err;
vx_toggle_dac_mute(chip, 0);

View File

@ -78,15 +78,19 @@ int snd_vx_setup_firmware(struct vx_core *chip)
/* ok, we reached to the last one */
/* create the devices if not built yet */
if ((err = snd_vx_pcm_new(chip)) < 0)
err = snd_vx_pcm_new(chip);
if (err < 0)
return err;
if ((err = snd_vx_mixer_new(chip)) < 0)
err = snd_vx_mixer_new(chip);
if (err < 0)
return err;
if (chip->ops->add_controls)
if ((err = chip->ops->add_controls(chip)) < 0)
if (chip->ops->add_controls) {
err = chip->ops->add_controls(chip);
if (err < 0)
return err;
}
chip->chip_status |= VX_STAT_DEVICE_INIT;
chip->chip_status |= VX_STAT_CHIP_INIT;

View File

@ -910,7 +910,8 @@ int snd_vx_mixer_new(struct vx_core *chip)
temp = vx_control_output_level;
temp.index = i;
temp.tlv.p = chip->hw->output_level_db_scale;
if ((err = snd_ctl_add(card, snd_ctl_new1(&temp, chip))) < 0)
err = snd_ctl_add(card, snd_ctl_new1(&temp, chip));
if (err < 0)
return err;
}
@ -921,22 +922,26 @@ int snd_vx_mixer_new(struct vx_core *chip)
temp.index = i;
temp.name = "PCM Playback Volume";
temp.private_value = val;
if ((err = snd_ctl_add(card, snd_ctl_new1(&temp, chip))) < 0)
err = snd_ctl_add(card, snd_ctl_new1(&temp, chip));
if (err < 0)
return err;
temp = vx_control_output_switch;
temp.index = i;
temp.private_value = val;
if ((err = snd_ctl_add(card, snd_ctl_new1(&temp, chip))) < 0)
err = snd_ctl_add(card, snd_ctl_new1(&temp, chip));
if (err < 0)
return err;
temp = vx_control_monitor_gain;
temp.index = i;
temp.private_value = val;
if ((err = snd_ctl_add(card, snd_ctl_new1(&temp, chip))) < 0)
err = snd_ctl_add(card, snd_ctl_new1(&temp, chip));
if (err < 0)
return err;
temp = vx_control_monitor_switch;
temp.index = i;
temp.private_value = val;
if ((err = snd_ctl_add(card, snd_ctl_new1(&temp, chip))) < 0)
err = snd_ctl_add(card, snd_ctl_new1(&temp, chip));
if (err < 0)
return err;
}
for (i = 0; i < chip->hw->num_outs; i++) {
@ -944,20 +949,25 @@ int snd_vx_mixer_new(struct vx_core *chip)
temp.index = i;
temp.name = "PCM Capture Volume";
temp.private_value = (i * 2) | (1 << 8);
if ((err = snd_ctl_add(card, snd_ctl_new1(&temp, chip))) < 0)
err = snd_ctl_add(card, snd_ctl_new1(&temp, chip));
if (err < 0)
return err;
}
/* Audio source */
if ((err = snd_ctl_add(card, snd_ctl_new1(&vx_control_audio_src, chip))) < 0)
err = snd_ctl_add(card, snd_ctl_new1(&vx_control_audio_src, chip));
if (err < 0)
return err;
/* clock mode */
if ((err = snd_ctl_add(card, snd_ctl_new1(&vx_control_clock_mode, chip))) < 0)
err = snd_ctl_add(card, snd_ctl_new1(&vx_control_clock_mode, chip));
if (err < 0)
return err;
/* IEC958 controls */
if ((err = snd_ctl_add(card, snd_ctl_new1(&vx_control_iec958_mask, chip))) < 0)
err = snd_ctl_add(card, snd_ctl_new1(&vx_control_iec958_mask, chip));
if (err < 0)
return err;
if ((err = snd_ctl_add(card, snd_ctl_new1(&vx_control_iec958, chip))) < 0)
err = snd_ctl_add(card, snd_ctl_new1(&vx_control_iec958, chip));
if (err < 0)
return err;
/* VU, peak, saturation meters */
for (c = 0; c < 2; c++) {
@ -968,7 +978,8 @@ int snd_vx_mixer_new(struct vx_core *chip)
temp = vx_control_saturation;
temp.index = i;
temp.private_value = val;
if ((err = snd_ctl_add(card, snd_ctl_new1(&temp, chip))) < 0)
err = snd_ctl_add(card, snd_ctl_new1(&temp, chip));
if (err < 0)
return err;
}
sprintf(name, "%s VU Meter", dir[c]);
@ -976,14 +987,16 @@ int snd_vx_mixer_new(struct vx_core *chip)
temp.index = i;
temp.name = name;
temp.private_value = val;
if ((err = snd_ctl_add(card, snd_ctl_new1(&temp, chip))) < 0)
err = snd_ctl_add(card, snd_ctl_new1(&temp, chip));
if (err < 0)
return err;
sprintf(name, "%s Peak Meter", dir[c]);
temp = vx_control_peak_meter;
temp.index = i;
temp.name = name;
temp.private_value = val;
if ((err = snd_ctl_add(card, snd_ctl_new1(&temp, chip))) < 0)
err = snd_ctl_add(card, snd_ctl_new1(&temp, chip));
if (err < 0)
return err;
}
}

View File

@ -341,10 +341,12 @@ static int vx_toggle_pipe(struct vx_core *chip, struct vx_pipe *pipe, int state)
}
}
if ((err = vx_conf_pipe(chip, pipe)) < 0)
err = vx_conf_pipe(chip, pipe);
if (err < 0)
return err;
if ((err = vx_send_irqa(chip)) < 0)
err = vx_send_irqa(chip);
if (err < 0)
return err;
/* If it completes successfully, wait for the pipes
@ -680,8 +682,9 @@ static void vx_pcm_playback_transfer(struct vx_core *chip,
if (! pipe->prepared || (chip->chip_status & VX_STAT_IS_STALE))
return;
for (i = 0; i < nchunks; i++) {
if ((err = vx_pcm_playback_transfer_chunk(chip, runtime, pipe,
chip->ibl.size)) < 0)
err = vx_pcm_playback_transfer_chunk(chip, runtime, pipe,
chip->ibl.size);
if (err < 0)
return;
}
}
@ -698,7 +701,8 @@ static void vx_pcm_playback_update(struct vx_core *chip,
struct snd_pcm_runtime *runtime = subs->runtime;
if (pipe->running && ! (chip->chip_status & VX_STAT_IS_STALE)) {
if ((err = vx_update_pipe_position(chip, runtime, pipe)) < 0)
err = vx_update_pipe_position(chip, runtime, pipe);
if (err < 0)
return;
if (pipe->transferred >= (int)runtime->period_size) {
pipe->transferred %= runtime->period_size;
@ -747,11 +751,13 @@ static int vx_pcm_trigger(struct snd_pcm_substream *subs, int cmd)
pipe->running = 0;
break;
case SNDRV_PCM_TRIGGER_PAUSE_PUSH:
if ((err = vx_toggle_pipe(chip, pipe, 0)) < 0)
err = vx_toggle_pipe(chip, pipe, 0);
if (err < 0)
return err;
break;
case SNDRV_PCM_TRIGGER_PAUSE_RELEASE:
if ((err = vx_toggle_pipe(chip, pipe, 1)) < 0)
err = vx_toggle_pipe(chip, pipe, 1);
if (err < 0)
return err;
break;
default:
@ -792,13 +798,15 @@ static int vx_pcm_prepare(struct snd_pcm_substream *subs)
snd_printdd(KERN_DEBUG "reopen the pipe with data_mode = %d\n", data_mode);
vx_init_rmh(&rmh, CMD_FREE_PIPE);
vx_set_pipe_cmd_params(&rmh, 0, pipe->number, 0);
if ((err = vx_send_msg(chip, &rmh)) < 0)
err = vx_send_msg(chip, &rmh);
if (err < 0)
return err;
vx_init_rmh(&rmh, CMD_RES_PIPE);
vx_set_pipe_cmd_params(&rmh, 0, pipe->number, pipe->channels);
if (data_mode)
rmh.Cmd[0] |= BIT_DATA_MODE;
if ((err = vx_send_msg(chip, &rmh)) < 0)
err = vx_send_msg(chip, &rmh);
if (err < 0)
return err;
pipe->data_mode = data_mode;
}
@ -810,7 +818,8 @@ static int vx_pcm_prepare(struct snd_pcm_substream *subs)
}
vx_set_clock(chip, runtime->rate);
if ((err = vx_set_format(chip, pipe, runtime)) < 0)
err = vx_set_format(chip, pipe, runtime);
if (err < 0)
return err;
if (vx_is_pcmcia(chip)) {
@ -1187,7 +1196,8 @@ int snd_vx_pcm_new(struct vx_core *chip)
unsigned int i;
int err;
if ((err = vx_init_audio_io(chip)) < 0)
err = vx_init_audio_io(chip);
if (err < 0)
return err;
for (i = 0; i < chip->hw->num_codecs; i++) {

View File

@ -18,8 +18,25 @@ config SND_DICE
select SND_HWDEP
select SND_FIREWIRE_LIB
help
Say Y here to include support for many DACs based on the DICE
chip family (DICE-II/Jr/Mini) which TC Applied Technologies produces.
Say Y here to include support for devices based on the DICE chip family
(DICE-II/TCD2210(Mini)/TCD2220(Jr.)) which TC Applied Technologies (TCAT) produced.
* Allen and Heath Zed R16
* Alesis iO 14/26 FireWire, MasterControl, MultiMix 8/12/16 FireWire
* Avid Mbox 3 Pro
* FlexRadio Systems FLEX-3000, FLEX-5000
* Focusrite Liquid Saffire 56
* Focusrite Saffire Pro 14, Pro 24, Pro 24 DSP, Pro 26, Pro 40(TCD2220)
* Harman Music Group Lexicon I-ONIX FW810S
* Loud Technologies Mackie Onyx Blackbird, Onyx 820i/1220i/1620i/1640i (latter models)
* M-Audio ProFire 610/2626
* Mytek Stereo192-DSD DAC
* Midas Klark Teknik VeniceF series
* PreSonus FireStudio, FireStudio Mobile, FireStudio Project, FireStudio Tube
* PreSonus StudioLive 16.4.2, 16.0.2, 24.4.2, 32.4.2
* Solid State Logic Duende Classic, Duende Mini
* TC Electronic Studio Konnekt 48, Konnekt 24D, Konnekt Live, Impact Twin
* TC Electronic Digital Konnekt x32, Desktop Konnekt 6
* Weiss Engineering ADC2, Vesta, Minerva, AFI1, DAC1, INT202, DAC202
To compile this driver as a module, choose M here: the module
will be called snd-dice.
@ -38,7 +55,7 @@ config SND_OXFW
* Mackie(Loud) Onyx 1640i (former model)
* Mackie(Loud) Onyx Satellite
* Mackie(Loud) Tapco Link.Firewire
* Mackie(Loud) d.4 pro
* Mackie(Loud) d.2 pro/d.4 pro (built-in FireWire card with OXFW971 ASIC)
* Mackie(Loud) U.420/U.420d
* TASCAM FireOne
* Stanton Controllers & Systems 1 Deck/Mixer
@ -84,7 +101,7 @@ config SND_BEBOB
* PreSonus FIREBOX/FIREPOD/FP10/Inspire1394
* BridgeCo RDAudio1/Audio5
* Mackie Onyx 1220/1620/1640 (FireWire I/O Card)
* Mackie d.2 (FireWire Option) and d.2 Pro
* Mackie d.2 (optional FireWire card with DM1000 ASIC)
* Stanton FinalScratch 2 (ScratchAmp)
* Tascam IF-FW/DM
* Behringer XENIX UFX 1204/1604
@ -110,6 +127,7 @@ config SND_BEBOB
* M-Audio Ozonic/NRV10/ProfireLightBridge
* M-Audio FireWire 1814/ProjectMix IO
* Digidesign Mbox 2 Pro
* ToneWeal FW66
To compile this driver as a module, choose M here: the module
will be called snd-bebob.
@ -148,12 +166,16 @@ config SND_FIREWIRE_MOTU
select SND_HWDEP
help
Say Y here to enable support for FireWire devices which MOTU produced:
* 828
* 896
* 828mk2
* Traveler
* Ultralite
* 8pre
* 828mk3 (FireWire only)
* 828mk3 (Hybrid)
* Ultralite mk3 (FireWire only)
* Ultralite mk3 (Hybrid)
* Audio Express
* 4pre

View File

@ -410,10 +410,10 @@ static unsigned int process_ir_ctx_payloads(struct amdtp_stream *s,
* @s: the AMDTP stream to initialize
* @unit: the target of the stream
* @dir: the direction of stream
* @flags: the packet transmission method to use
* @flags: the details of the streaming protocol consist of cip_flags enumeration-constants.
*/
int amdtp_am824_init(struct amdtp_stream *s, struct fw_unit *unit,
enum amdtp_stream_direction dir, enum cip_flags flags)
enum amdtp_stream_direction dir, unsigned int flags)
{
amdtp_stream_process_ctx_payloads_t process_ctx_payloads;

View File

@ -45,5 +45,5 @@ void amdtp_am824_midi_trigger(struct amdtp_stream *s, unsigned int port,
struct snd_rawmidi_substream *midi);
int amdtp_am824_init(struct amdtp_stream *s, struct fw_unit *unit,
enum amdtp_stream_direction dir, enum cip_flags flags);
enum amdtp_stream_direction dir, unsigned int flags);
#endif

View File

@ -49,7 +49,7 @@ TRACE_EVENT(amdtp_packet,
__entry->data_blocks = data_blocks;
__entry->data_block_counter = data_block_counter,
__entry->packet_index = packet_index;
__entry->irq = !!in_interrupt();
__entry->irq = !!in_softirq();
__entry->index = index;
),
TP_printk(

File diff suppressed because it is too large Load Diff

View File

@ -35,6 +35,8 @@
* @CIP_NO_HEADERS: a lack of headers in packets
* @CIP_UNALIGHED_DBC: Only for in-stream. The value of dbc is not alighed to
* the value of current SYT_INTERVAL; e.g. initial value is not zero.
* @CIP_UNAWARE_SYT: For outgoing packet, the value in SYT field of CIP is 0xffff.
* For incoming packet, the value in SYT field of CIP is not handled.
*/
enum cip_flags {
CIP_NONBLOCKING = 0x00,
@ -48,6 +50,7 @@ enum cip_flags {
CIP_HEADER_WITHOUT_EOH = 0x80,
CIP_NO_HEADER = 0x100,
CIP_UNALIGHED_DBC = 0x200,
CIP_UNAWARE_SYT = 0x400,
};
/**
@ -112,7 +115,8 @@ typedef unsigned int (*amdtp_stream_process_ctx_payloads_t)(
struct amdtp_domain;
struct amdtp_stream {
struct fw_unit *unit;
enum cip_flags flags;
// The combination of cip_flags enumeration-constants.
unsigned int flags;
enum amdtp_stream_direction direction;
struct mutex mutex;
@ -134,19 +138,37 @@ struct amdtp_stream {
// Fixed interval of dbc between previos/current
// packets.
unsigned int dbc_interval;
// The device starts multiplexing events to the packet.
bool event_starts;
struct {
struct seq_desc *descs;
unsigned int size;
unsigned int tail;
} cache;
} tx;
struct {
// To calculate CIP data blocks and tstamp.
unsigned int transfer_delay;
unsigned int seq_index;
// To generate CIP header.
unsigned int fdf;
int syt_override;
// To generate constant hardware IRQ.
unsigned int event_count;
unsigned int events_per_period;
// To calculate CIP data blocks and tstamp.
struct {
struct seq_desc *descs;
unsigned int size;
unsigned int tail;
unsigned int head;
} seq;
unsigned int data_block_state;
unsigned int syt_offset_state;
unsigned int last_syt_offset;
struct amdtp_stream *replay_target;
unsigned int cache_head;
} rx;
} ctx_data;
@ -157,20 +179,21 @@ struct amdtp_stream {
unsigned int sph;
unsigned int fmt;
/* Internal flags. */
// Internal flags.
unsigned int transfer_delay;
enum cip_sfc sfc;
unsigned int syt_interval;
/* For a PCM substream processing. */
struct snd_pcm_substream *pcm;
struct work_struct period_work;
snd_pcm_uframes_t pcm_buffer_pointer;
unsigned int pcm_period_pointer;
/* To wait for first packet. */
bool callbacked;
wait_queue_head_t callback_wait;
u32 start_cycle;
// To start processing content of packets at the same cycle in several contexts for
// each direction.
bool ready_processing;
wait_queue_head_t ready_wait;
unsigned int next_cycle;
/* For backends to process data blocks. */
void *protocol;
@ -184,7 +207,7 @@ struct amdtp_stream {
};
int amdtp_stream_init(struct amdtp_stream *s, struct fw_unit *unit,
enum amdtp_stream_direction dir, enum cip_flags flags,
enum amdtp_stream_direction dir, unsigned int flags,
unsigned int fmt,
amdtp_stream_process_ctx_payloads_t process_ctx_payloads,
unsigned int protocol_size);
@ -259,21 +282,6 @@ static inline bool cip_sfc_is_base_44100(enum cip_sfc sfc)
return sfc & 1;
}
/**
* amdtp_stream_wait_callback - sleep till callbacked or timeout
* @s: the AMDTP stream
* @timeout: msec till timeout
*
* If this function return false, the AMDTP stream should be stopped.
*/
static inline bool amdtp_stream_wait_callback(struct amdtp_stream *s,
unsigned int timeout)
{
return wait_event_timeout(s->callback_wait,
s->callbacked,
msecs_to_jiffies(timeout)) > 0;
}
struct seq_desc {
unsigned int syt_offset;
unsigned int data_blocks;
@ -287,13 +295,16 @@ struct amdtp_domain {
struct amdtp_stream *irq_target;
struct seq_desc *seq_descs;
unsigned int seq_size;
unsigned int seq_tail;
struct {
unsigned int tx_init_skip;
unsigned int tx_start;
unsigned int rx_start;
} processing_cycle;
unsigned int data_block_state;
unsigned int syt_offset_state;
unsigned int last_syt_offset;
struct {
bool enable:1;
bool on_the_fly:1;
} replay;
};
int amdtp_domain_init(struct amdtp_domain *d);
@ -302,7 +313,8 @@ void amdtp_domain_destroy(struct amdtp_domain *d);
int amdtp_domain_add_stream(struct amdtp_domain *d, struct amdtp_stream *s,
int channel, int speed);
int amdtp_domain_start(struct amdtp_domain *d, unsigned int ir_delay_cycle);
int amdtp_domain_start(struct amdtp_domain *d, unsigned int tx_init_skip_cycles, bool replay_seq,
bool replay_on_the_fly);
void amdtp_domain_stop(struct amdtp_domain *d);
static inline int amdtp_domain_set_events_per_period(struct amdtp_domain *d,
@ -319,4 +331,25 @@ unsigned long amdtp_domain_stream_pcm_pointer(struct amdtp_domain *d,
struct amdtp_stream *s);
int amdtp_domain_stream_pcm_ack(struct amdtp_domain *d, struct amdtp_stream *s);
/**
* amdtp_domain_wait_ready - sleep till being ready to process packets or timeout
* @d: the AMDTP domain
* @timeout_ms: msec till timeout
*
* If this function return false, the AMDTP domain should be stopped.
*/
static inline bool amdtp_domain_wait_ready(struct amdtp_domain *d, unsigned int timeout_ms)
{
struct amdtp_stream *s;
list_for_each_entry(s, &d->streams, list) {
unsigned int j = msecs_to_jiffies(timeout_ms);
if (wait_event_interruptible_timeout(s->ready_wait, s->ready_processing, j) <= 0)
return false;
}
return true;
}
#endif

View File

@ -40,14 +40,12 @@ static DECLARE_BITMAP(devices_used, SNDRV_CARDS);
#define VEN_EDIROL 0x000040ab
#define VEN_PRESONUS 0x00000a92
#define VEN_BRIDGECO 0x000007f5
#define VEN_MACKIE1 0x0000000f
#define VEN_MACKIE2 0x00000ff2
#define VEN_MACKIE 0x00000ff2
#define VEN_STANTON 0x00001260
#define VEN_TASCAM 0x0000022e
#define VEN_BEHRINGER 0x00001564
#define VEN_APOGEE 0x000003db
#define VEN_ESI 0x00000f1b
#define VEN_ACOUSTIC 0x00000002
#define VEN_CME 0x0000000a
#define VEN_PHONIC 0x00001496
#define VEN_LYNX 0x000019e5
@ -56,14 +54,15 @@ static DECLARE_BITMAP(devices_used, SNDRV_CARDS);
#define VEN_TERRATEC 0x00000aac
#define VEN_YAMAHA 0x0000a0de
#define VEN_FOCUSRITE 0x0000130e
#define VEN_MAUDIO1 0x00000d6c
#define VEN_MAUDIO2 0x000007f5
#define VEN_MAUDIO 0x00000d6c
#define VEN_DIGIDESIGN 0x00a07e
#define OUI_SHOUYO 0x002327
#define MODEL_FOCUSRITE_SAFFIRE_BOTH 0x00000000
#define MODEL_MAUDIO_AUDIOPHILE_BOTH 0x00010060
#define MODEL_MAUDIO_FW1814 0x00010071
#define MODEL_MAUDIO_PROJECTMIX 0x00010091
#define MODEL_MAUDIO_PROFIRELIGHTBRIDGE 0x000100a1
static int
name_device(struct snd_bebob *bebob)
@ -74,7 +73,6 @@ name_device(struct snd_bebob *bebob)
u32 hw_id;
u32 data[2] = {0};
u32 revision;
u32 version;
int err;
/* get vendor name from root directory */
@ -107,12 +105,6 @@ name_device(struct snd_bebob *bebob)
if (err < 0)
goto end;
err = snd_bebob_read_quad(bebob->unit, INFO_OFFSET_BEBOB_VERSION,
&version);
if (err < 0)
goto end;
bebob->version = version;
strcpy(bebob->card->driver, "BeBoB");
strcpy(bebob->card->shortname, model);
strcpy(bebob->card->mixername, model);
@ -135,6 +127,9 @@ bebob_card_free(struct snd_card *card)
mutex_unlock(&devices_mutex);
snd_bebob_stream_destroy_duplex(bebob);
mutex_destroy(&bebob->mutex);
fw_unit_put(bebob->unit);
}
static const struct snd_bebob_spec *
@ -162,16 +157,55 @@ check_audiophile_booted(struct fw_unit *unit)
return strncmp(name, "FW Audiophile Bootloader", 24) != 0;
}
static void
do_registration(struct work_struct *work)
static int detect_quirks(struct snd_bebob *bebob, const struct ieee1394_device_id *entry)
{
if (entry->vendor_id == VEN_MAUDIO) {
switch (entry->model_id) {
case MODEL_MAUDIO_PROFIRELIGHTBRIDGE:
// M-Audio ProFire Lightbridge has a quirk to transfer packets with
// discontinuous cycle or data block counter in early stage of packet
// streaming. The cycle span from the first packet with event is variable.
bebob->quirks |= SND_BEBOB_QUIRK_INITIAL_DISCONTINUOUS_DBC;
break;
case MODEL_MAUDIO_FW1814:
case MODEL_MAUDIO_PROJECTMIX:
// At high sampling rate, M-Audio special firmware transmits empty packet
// with the value of dbc incremented by 8.
bebob->quirks |= SND_BEBOB_QUIRK_WRONG_DBC;
break;
default:
break;
}
}
return 0;
}
static int bebob_probe(struct fw_unit *unit, const struct ieee1394_device_id *entry)
{
struct snd_bebob *bebob =
container_of(work, struct snd_bebob, dwork.work);
unsigned int card_index;
struct snd_card *card;
struct snd_bebob *bebob;
const struct snd_bebob_spec *spec;
int err;
if (bebob->registered)
return;
if (entry->vendor_id == VEN_FOCUSRITE &&
entry->model_id == MODEL_FOCUSRITE_SAFFIRE_BOTH)
spec = get_saffire_spec(unit);
else if (entry->vendor_id == VEN_MAUDIO &&
entry->model_id == MODEL_MAUDIO_AUDIOPHILE_BOTH &&
!check_audiophile_booted(unit))
spec = NULL;
else
spec = (const struct snd_bebob_spec *)entry->driver_data;
if (spec == NULL) {
// To boot up M-Audio models.
if (entry->vendor_id == VEN_MAUDIO || entry->vendor_id == VEN_BRIDGECO)
return snd_bebob_maudio_load_firmware(unit);
else
return -ENODEV;
}
mutex_lock(&devices_mutex);
for (card_index = 0; card_index < SNDRV_CARDS; card_index++) {
@ -180,27 +214,40 @@ do_registration(struct work_struct *work)
}
if (card_index >= SNDRV_CARDS) {
mutex_unlock(&devices_mutex);
return;
return -ENOENT;
}
err = snd_card_new(&bebob->unit->device, index[card_index],
id[card_index], THIS_MODULE, 0, &bebob->card);
err = snd_card_new(&unit->device, index[card_index], id[card_index], THIS_MODULE,
sizeof(*bebob), &card);
if (err < 0) {
mutex_unlock(&devices_mutex);
return;
return err;
}
card->private_free = bebob_card_free;
set_bit(card_index, devices_used);
mutex_unlock(&devices_mutex);
bebob->card->private_free = bebob_card_free;
bebob->card->private_data = bebob;
bebob = card->private_data;
bebob->unit = fw_unit_get(unit);
dev_set_drvdata(&unit->device, bebob);
bebob->card = card;
bebob->card_index = card_index;
bebob->spec = spec;
mutex_init(&bebob->mutex);
spin_lock_init(&bebob->lock);
init_waitqueue_head(&bebob->hwdep_wait);
err = name_device(bebob);
if (err < 0)
goto error;
err = detect_quirks(bebob, entry);
if (err < 0)
goto error;
if (bebob->spec == &maudio_special_spec) {
if (bebob->entry->model_id == MODEL_MAUDIO_FW1814)
if (entry->model_id == MODEL_MAUDIO_FW1814)
err = snd_bebob_maudio_special_discover(bebob, true);
else
err = snd_bebob_maudio_special_discover(bebob, false);
@ -230,80 +277,26 @@ do_registration(struct work_struct *work)
if (err < 0)
goto error;
err = snd_card_register(bebob->card);
err = snd_card_register(card);
if (err < 0)
goto error;
bebob->registered = true;
return;
error:
snd_card_free(bebob->card);
dev_info(&bebob->unit->device,
"Sound card registration failed: %d\n", err);
}
static int
bebob_probe(struct fw_unit *unit, const struct ieee1394_device_id *entry)
{
struct snd_bebob *bebob;
const struct snd_bebob_spec *spec;
if (entry->vendor_id == VEN_FOCUSRITE &&
entry->model_id == MODEL_FOCUSRITE_SAFFIRE_BOTH)
spec = get_saffire_spec(unit);
else if (entry->vendor_id == VEN_MAUDIO1 &&
entry->model_id == MODEL_MAUDIO_AUDIOPHILE_BOTH &&
!check_audiophile_booted(unit))
spec = NULL;
else
spec = (const struct snd_bebob_spec *)entry->driver_data;
if (spec == NULL) {
if (entry->vendor_id == VEN_MAUDIO1 ||
entry->vendor_id == VEN_MAUDIO2)
return snd_bebob_maudio_load_firmware(unit);
else
return -ENODEV;
}
/* Allocate this independent of sound card instance. */
bebob = devm_kzalloc(&unit->device, sizeof(struct snd_bebob),
GFP_KERNEL);
if (!bebob)
return -ENOMEM;
bebob->unit = fw_unit_get(unit);
dev_set_drvdata(&unit->device, bebob);
bebob->entry = entry;
bebob->spec = spec;
mutex_init(&bebob->mutex);
spin_lock_init(&bebob->lock);
init_waitqueue_head(&bebob->hwdep_wait);
/* Allocate and register this sound card later. */
INIT_DEFERRABLE_WORK(&bebob->dwork, do_registration);
if (entry->vendor_id != VEN_MAUDIO1 ||
(entry->model_id != MODEL_MAUDIO_FW1814 &&
entry->model_id != MODEL_MAUDIO_PROJECTMIX)) {
snd_fw_schedule_registration(unit, &bebob->dwork);
} else {
/*
* This is a workaround. This bus reset seems to have an effect
* to make devices correctly handling transactions. Without
* this, the devices have gap_count mismatch. This causes much
* failure of transaction.
*
* Just after registration, user-land application receive
* signals from dbus and starts I/Os. To avoid I/Os till the
* future bus reset, registration is done in next update().
*/
fw_schedule_bus_reset(fw_parent_device(bebob->unit)->card,
false, true);
if (entry->vendor_id == VEN_MAUDIO &&
(entry->model_id == MODEL_MAUDIO_FW1814 || entry->model_id == MODEL_MAUDIO_PROJECTMIX)) {
// This is a workaround. This bus reset seems to have an effect to make devices
// correctly handling transactions. Without this, the devices have gap_count
// mismatch. This causes much failure of transaction.
//
// Just after registration, user-land application receive signals from dbus and
// starts I/Os. To avoid I/Os till the future bus reset, registration is done in
// next update().
fw_schedule_bus_reset(fw_parent_device(bebob->unit)->card, false, true);
}
return 0;
error:
snd_card_free(card);
return err;
}
/*
@ -330,11 +323,7 @@ bebob_update(struct fw_unit *unit)
if (bebob == NULL)
return;
/* Postpone a workqueue for deferred registration. */
if (!bebob->registered)
snd_fw_schedule_registration(unit, &bebob->dwork);
else
fcp_bus_reset(bebob->unit);
fcp_bus_reset(bebob->unit);
}
static void bebob_remove(struct fw_unit *unit)
@ -344,20 +333,8 @@ static void bebob_remove(struct fw_unit *unit)
if (bebob == NULL)
return;
/*
* Confirm to stop the work for registration before the sound card is
* going to be released. The work is not scheduled again because bus
* reset handler is not called anymore.
*/
cancel_delayed_work_sync(&bebob->dwork);
if (bebob->registered) {
// Block till all of ALSA character devices are released.
snd_card_free(bebob->card);
}
mutex_destroy(&bebob->mutex);
fw_unit_put(bebob->unit);
// Block till all of ALSA character devices are released.
snd_card_free(bebob->card);
}
static const struct snd_bebob_rate_spec normal_rate_spec = {
@ -370,6 +347,22 @@ static const struct snd_bebob_spec spec_normal = {
.meter = NULL
};
#define SPECIFIER_1394TA 0x00a02d
// The immediate entry for version in unit directory differs depending on models:
// * 0x010001
// * 0x014001
#define SND_BEBOB_DEV_ENTRY(vendor, model, data) \
{ \
.match_flags = IEEE1394_MATCH_VENDOR_ID | \
IEEE1394_MATCH_MODEL_ID | \
IEEE1394_MATCH_SPECIFIER_ID, \
.vendor_id = vendor, \
.model_id = model, \
.specifier_id = SPECIFIER_1394TA, \
.driver_data = (kernel_ulong_t)data \
}
static const struct ieee1394_device_id bebob_id_table[] = {
/* Edirol, FA-66 */
SND_BEBOB_DEV_ENTRY(VEN_EDIROL, 0x00010049, &spec_normal),
@ -386,9 +379,9 @@ static const struct ieee1394_device_id bebob_id_table[] = {
/* BridgeCo, Audio5 */
SND_BEBOB_DEV_ENTRY(VEN_BRIDGECO, 0x00010049, &spec_normal),
/* Mackie, Onyx 1220/1620/1640 (Firewire I/O Card) */
SND_BEBOB_DEV_ENTRY(VEN_MACKIE2, 0x00010065, &spec_normal),
// Mackie, d.2 (Firewire option card) and d.2 Pro (the card is built-in).
SND_BEBOB_DEV_ENTRY(VEN_MACKIE1, 0x00010067, &spec_normal),
SND_BEBOB_DEV_ENTRY(VEN_MACKIE, 0x00010065, &spec_normal),
// Mackie, d.2 (optional Firewire card with DM1000).
SND_BEBOB_DEV_ENTRY(VEN_MACKIE, 0x00010067, &spec_normal),
/* Stanton, ScratchAmp */
SND_BEBOB_DEV_ENTRY(VEN_STANTON, 0x00000001, &spec_normal),
/* Tascam, IF-FW DM */
@ -410,17 +403,20 @@ static const struct ieee1394_device_id bebob_id_table[] = {
SND_BEBOB_DEV_ENTRY(VEN_APOGEE, 0x01eeee, &spec_normal),
/* ESI, Quatafire610 */
SND_BEBOB_DEV_ENTRY(VEN_ESI, 0x00010064, &spec_normal),
/* AcousticReality, eARMasterOne */
SND_BEBOB_DEV_ENTRY(VEN_ACOUSTIC, 0x00000002, &spec_normal),
// AcousticReality, eARMasterOne. Terratec OEM.
SND_BEBOB_DEV_ENTRY(VEN_TERRATEC, 0x00000002, &spec_normal),
/* CME, MatrixKFW */
SND_BEBOB_DEV_ENTRY(VEN_CME, 0x00030000, &spec_normal),
/* Phonic, Helix Board 12 MkII */
// Phonic Helix Board 12 FireWire MkII.
SND_BEBOB_DEV_ENTRY(VEN_PHONIC, 0x00050000, &spec_normal),
/* Phonic, Helix Board 18 MkII */
// Phonic Helix Board 18 FireWire MkII.
SND_BEBOB_DEV_ENTRY(VEN_PHONIC, 0x00060000, &spec_normal),
/* Phonic, Helix Board 24 MkII */
// Phonic Helix Board 24 FireWire MkII.
SND_BEBOB_DEV_ENTRY(VEN_PHONIC, 0x00070000, &spec_normal),
/* Phonic, Helix Board 12 Universal/18 Universal/24 Universal */
// Phonic FireFly 808 FireWire.
SND_BEBOB_DEV_ENTRY(VEN_PHONIC, 0x00080000, &spec_normal),
// Phonic FireFly 202, 302, 808 Universal.
// Phinic Helix Board 12/18/24 FireWire, 12/18/24 Universal
SND_BEBOB_DEV_ENTRY(VEN_PHONIC, 0x00000000, &spec_normal),
/* Lynx, Aurora 8/16 (LT-FW) */
SND_BEBOB_DEV_ENTRY(VEN_LYNX, 0x00000001, &spec_normal),
@ -447,45 +443,35 @@ static const struct ieee1394_device_id bebob_id_table[] = {
/* Focusrite, SaffirePro 26 I/O */
SND_BEBOB_DEV_ENTRY(VEN_FOCUSRITE, 0x00000003, &saffirepro_26_spec),
/* Focusrite, SaffirePro 10 I/O */
{
// The combination of vendor_id and model_id is the same as the
// same as the one of Liquid Saffire 56.
.match_flags = IEEE1394_MATCH_VENDOR_ID |
IEEE1394_MATCH_MODEL_ID |
IEEE1394_MATCH_SPECIFIER_ID |
IEEE1394_MATCH_VERSION,
.vendor_id = VEN_FOCUSRITE,
.model_id = 0x000006,
.specifier_id = 0x00a02d,
.version = 0x010001,
.driver_data = (kernel_ulong_t)&saffirepro_10_spec,
},
SND_BEBOB_DEV_ENTRY(VEN_FOCUSRITE, 0x000006, &saffirepro_10_spec),
/* Focusrite, Saffire(no label and LE) */
SND_BEBOB_DEV_ENTRY(VEN_FOCUSRITE, MODEL_FOCUSRITE_SAFFIRE_BOTH,
&saffire_spec),
/* M-Audio, Firewire 410 */
SND_BEBOB_DEV_ENTRY(VEN_MAUDIO2, 0x00010058, NULL), /* bootloader */
SND_BEBOB_DEV_ENTRY(VEN_MAUDIO2, 0x00010046, &maudio_fw410_spec),
// M-Audio, Firewire 410. The vendor field is left as BridgeCo. AG.
SND_BEBOB_DEV_ENTRY(VEN_BRIDGECO, 0x00010058, NULL),
SND_BEBOB_DEV_ENTRY(VEN_BRIDGECO, 0x00010046, &maudio_fw410_spec),
/* M-Audio, Firewire Audiophile */
SND_BEBOB_DEV_ENTRY(VEN_MAUDIO1, MODEL_MAUDIO_AUDIOPHILE_BOTH,
SND_BEBOB_DEV_ENTRY(VEN_MAUDIO, MODEL_MAUDIO_AUDIOPHILE_BOTH,
&maudio_audiophile_spec),
/* M-Audio, Firewire Solo */
SND_BEBOB_DEV_ENTRY(VEN_MAUDIO1, 0x00010062, &maudio_solo_spec),
SND_BEBOB_DEV_ENTRY(VEN_MAUDIO, 0x00010062, &maudio_solo_spec),
/* M-Audio, Ozonic */
SND_BEBOB_DEV_ENTRY(VEN_MAUDIO1, 0x0000000a, &maudio_ozonic_spec),
SND_BEBOB_DEV_ENTRY(VEN_MAUDIO, 0x0000000a, &maudio_ozonic_spec),
/* M-Audio NRV10 */
SND_BEBOB_DEV_ENTRY(VEN_MAUDIO1, 0x00010081, &maudio_nrv10_spec),
SND_BEBOB_DEV_ENTRY(VEN_MAUDIO, 0x00010081, &maudio_nrv10_spec),
/* M-Audio, ProFireLightbridge */
SND_BEBOB_DEV_ENTRY(VEN_MAUDIO1, 0x000100a1, &spec_normal),
SND_BEBOB_DEV_ENTRY(VEN_MAUDIO, MODEL_MAUDIO_PROFIRELIGHTBRIDGE, &spec_normal),
/* Firewire 1814 */
SND_BEBOB_DEV_ENTRY(VEN_MAUDIO1, 0x00010070, NULL), /* bootloader */
SND_BEBOB_DEV_ENTRY(VEN_MAUDIO1, MODEL_MAUDIO_FW1814,
SND_BEBOB_DEV_ENTRY(VEN_MAUDIO, 0x00010070, NULL), /* bootloader */
SND_BEBOB_DEV_ENTRY(VEN_MAUDIO, MODEL_MAUDIO_FW1814,
&maudio_special_spec),
/* M-Audio ProjectMix */
SND_BEBOB_DEV_ENTRY(VEN_MAUDIO1, MODEL_MAUDIO_PROJECTMIX,
SND_BEBOB_DEV_ENTRY(VEN_MAUDIO, MODEL_MAUDIO_PROJECTMIX,
&maudio_special_spec),
/* Digidesign Mbox 2 Pro */
SND_BEBOB_DEV_ENTRY(VEN_DIGIDESIGN, 0x0000a9, &spec_normal),
// Toneweal FW66.
SND_BEBOB_DEV_ENTRY(OUI_SHOUYO, 0x020002, &spec_normal),
/* IDs are unknown but able to be supported */
/* Apogee, Mini-ME Firewire */
/* Apogee, Mini-DAC Firewire */
@ -496,11 +482,6 @@ static const struct ieee1394_device_id bebob_id_table[] = {
/* Infrasonic, Windy6 */
/* Mackie, Digital X Bus x.200 */
/* Mackie, Digital X Bus x.400 */
/* Phonic, HB 12 */
/* Phonic, HB 24 */
/* Phonic, HB 18 */
/* Phonic, FireFly 202 */
/* Phonic, FireFly 302 */
/* Rolf Spuler, Firewire Guitar */
{}
};

View File

@ -75,6 +75,11 @@ struct snd_bebob_spec {
const struct snd_bebob_meter_spec *meter;
};
enum snd_bebob_quirk {
SND_BEBOB_QUIRK_INITIAL_DISCONTINUOUS_DBC = (1 << 0),
SND_BEBOB_QUIRK_WRONG_DBC = (1 << 1),
};
struct snd_bebob {
struct snd_card *card;
struct fw_unit *unit;
@ -83,11 +88,8 @@ struct snd_bebob {
struct mutex mutex;
spinlock_t lock;
bool registered;
struct delayed_work dwork;
const struct ieee1394_device_id *entry;
const struct snd_bebob_spec *spec;
unsigned int quirks; // Combination of snd_bebob_quirk enumerations.
unsigned int midi_input_ports;
unsigned int midi_output_ports;
@ -113,9 +115,6 @@ struct snd_bebob {
/* for M-Audio special devices */
void *maudio_special_quirk;
/* For BeBoB version quirk. */
unsigned int version;
struct amdtp_domain domain;
};
@ -254,13 +253,4 @@ extern const struct snd_bebob_spec maudio_special_spec;
int snd_bebob_maudio_special_discover(struct snd_bebob *bebob, bool is1814);
int snd_bebob_maudio_load_firmware(struct fw_unit *unit);
#define SND_BEBOB_DEV_ENTRY(vendor, model, data) \
{ \
.match_flags = IEEE1394_MATCH_VENDOR_ID | \
IEEE1394_MATCH_MODEL_ID, \
.vendor_id = vendor, \
.model_id = model, \
.driver_data = (kernel_ulong_t)data \
}
#endif

View File

@ -7,8 +7,7 @@
#include "./bebob.h"
#define CALLBACK_TIMEOUT 2500
#define FW_ISO_RESOURCE_DELAY 1000
#define READY_TIMEOUT_MS 4000
/*
* NOTE;
@ -402,12 +401,6 @@ static void break_both_connections(struct snd_bebob *bebob)
{
cmp_connection_break(&bebob->in_conn);
cmp_connection_break(&bebob->out_conn);
// These models seem to be in transition state for a longer time. When
// accessing in the state, any transactions is corrupted. In the worst
// case, the device is going to reboot.
if (bebob->version < 2)
msleep(600);
}
static int start_stream(struct snd_bebob *bebob, struct amdtp_stream *stream)
@ -437,6 +430,7 @@ static int start_stream(struct snd_bebob *bebob, struct amdtp_stream *stream)
static int init_stream(struct snd_bebob *bebob, struct amdtp_stream *stream)
{
unsigned int flags = CIP_BLOCKING;
enum amdtp_stream_direction dir_stream;
struct cmp_connection *conn;
enum cmp_direction dir_conn;
@ -452,32 +446,21 @@ static int init_stream(struct snd_bebob *bebob, struct amdtp_stream *stream)
dir_conn = CMP_INPUT;
}
if (stream == &bebob->tx_stream) {
if (bebob->quirks & SND_BEBOB_QUIRK_WRONG_DBC)
flags |= CIP_EMPTY_HAS_WRONG_DBC;
}
err = cmp_connection_init(conn, bebob->unit, dir_conn, 0);
if (err < 0)
return err;
err = amdtp_am824_init(stream, bebob->unit, dir_stream, CIP_BLOCKING);
err = amdtp_am824_init(stream, bebob->unit, dir_stream, flags);
if (err < 0) {
cmp_connection_destroy(conn);
return err;
}
if (stream == &bebob->tx_stream) {
// BeBoB v3 transfers packets with these qurks:
// - In the beginning of streaming, the value of dbc is
// incremented even if no data blocks are transferred.
// - The value of dbc is reset suddenly.
if (bebob->version > 2)
bebob->tx_stream.flags |= CIP_EMPTY_HAS_WRONG_DBC |
CIP_SKIP_DBC_ZERO_CHECK;
// At high sampling rate, M-Audio special firmware transmits
// empty packet with the value of dbc incremented by 8 but the
// others are valid to IEC 61883-1.
if (bebob->maudio_special_quirk)
bebob->tx_stream.flags |= CIP_EMPTY_HAS_WRONG_DBC;
}
return 0;
}
@ -624,9 +607,8 @@ int snd_bebob_stream_start_duplex(struct snd_bebob *bebob)
if (!amdtp_stream_running(&bebob->rx_stream)) {
enum snd_bebob_clock_type src;
struct amdtp_stream *master, *slave;
unsigned int curr_rate;
unsigned int ir_delay_cycle;
unsigned int tx_init_skip_cycles;
if (bebob->maudio_special_quirk) {
err = bebob->spec->rate->get(bebob, &curr_rate);
@ -638,36 +620,28 @@ int snd_bebob_stream_start_duplex(struct snd_bebob *bebob)
if (err < 0)
return err;
if (src != SND_BEBOB_CLOCK_TYPE_SYT) {
master = &bebob->tx_stream;
slave = &bebob->rx_stream;
} else {
master = &bebob->rx_stream;
slave = &bebob->tx_stream;
}
err = start_stream(bebob, master);
err = start_stream(bebob, &bebob->rx_stream);
if (err < 0)
goto error;
err = start_stream(bebob, slave);
err = start_stream(bebob, &bebob->tx_stream);
if (err < 0)
goto error;
// The device postpones start of transmission mostly for 1 sec
// after receives packets firstly. For safe, IR context starts
// 0.4 sec (=3200 cycles) later to version 1 or 2 firmware,
// 2.0 sec (=16000 cycles) for version 3 firmware. This is
// within 2.5 sec (=CALLBACK_TIMEOUT).
// Furthermore, some devices transfer isoc packets with
// discontinuous counter in the beginning of packet streaming.
// The delay has an effect to avoid detection of this
// discontinuity.
if (bebob->version < 2)
ir_delay_cycle = 3200;
if (!(bebob->quirks & SND_BEBOB_QUIRK_INITIAL_DISCONTINUOUS_DBC))
tx_init_skip_cycles = 0;
else
ir_delay_cycle = 16000;
err = amdtp_domain_start(&bebob->domain, ir_delay_cycle);
tx_init_skip_cycles = 16000;
// MEMO: Some devices start packet transmission long enough after establishment of
// CMP connection. In the early stage of packet streaming, any device transfers
// NODATA packets. After several hundred cycles, it begins to multiplex event into
// the packet with adequate value of syt field in CIP header. Some devices are
// strictly to generate any discontinuity in the sequence of tx packet when they
// receives inadequate sequence of value in syt field of CIP header. In the case,
// the request to break CMP connection is often corrupted, then any transaction
// results in unrecoverable error, sometimes generate bus-reset.
err = amdtp_domain_start(&bebob->domain, tx_init_skip_cycles, true, false);
if (err < 0)
goto error;
@ -684,10 +658,9 @@ int snd_bebob_stream_start_duplex(struct snd_bebob *bebob)
}
}
if (!amdtp_stream_wait_callback(&bebob->rx_stream,
CALLBACK_TIMEOUT) ||
!amdtp_stream_wait_callback(&bebob->tx_stream,
CALLBACK_TIMEOUT)) {
// Some devices postpone start of transmission mostly for 1 sec after receives
// packets firstly.
if (!amdtp_domain_wait_ready(&bebob->domain, READY_TIMEOUT_MS)) {
err = -ETIMEDOUT;
goto error;
}
@ -883,6 +856,11 @@ static int detect_midi_ports(struct snd_bebob *bebob,
err = avc_bridgeco_get_plug_ch_count(bebob->unit, addr, &ch_count);
if (err < 0)
break;
// Yamaha GO44, GO46, Terratec Phase 24, Phase x24 reports 0 for the number of
// channels in external output plug 3 (MIDI type) even if it has a pair of physical
// MIDI jacks. As a workaround, assume it as one.
if (ch_count == 0)
ch_count = 1;
*midi_ports += ch_count;
}
@ -961,12 +939,12 @@ int snd_bebob_stream_discover(struct snd_bebob *bebob)
if (err < 0)
goto end;
err = detect_midi_ports(bebob, bebob->rx_stream_formations, addr, AVC_BRIDGECO_PLUG_DIR_IN,
err = detect_midi_ports(bebob, bebob->tx_stream_formations, addr, AVC_BRIDGECO_PLUG_DIR_IN,
plugs[2], &bebob->midi_input_ports);
if (err < 0)
goto end;
err = detect_midi_ports(bebob, bebob->tx_stream_formations, addr, AVC_BRIDGECO_PLUG_DIR_OUT,
err = detect_midi_ports(bebob, bebob->rx_stream_formations, addr, AVC_BRIDGECO_PLUG_DIR_OUT,
plugs[3], &bebob->midi_output_ports);
if (err < 0)
goto end;

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